windows-nt/Source/XPSP1/NT/enduser/netmeeting/ui/conf/calib.cpp
2020-09-26 16:20:57 +08:00

2479 lines
64 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// File: calib.cpp
#include "precomp.h"
#include "resource.h"
#include "WaveDev.h"
#include "dstest.h"
#include "avdefs.h"
#include <mmsystem.h>
#include <mixer.h>
#include <mperror.h>
#include <iacapapi.h>
#include <sehcall.h>
// Local includes
#include "ConfCpl.h"
#include "conf.h"
// Defined in wizard.cpp
extern UINT_PTR GetPageBeforeAudioWiz();
// move somewhere else
#define MAXNUMPAGES_INCALIBWIZ 7
#define WAVEDEVICE_OPENFAILED -1
#define MAXSTRINGSIZE 256
#define READFROM_REGISTRY -1
#define AUDIOWIZ_WARNING 1
#define AUDIOWIZ_ERROR 2
#define CALIB_CHECK 1
#define CALIB_PREPARE 2
#define CALIBERR_NO_MIXERS 1
#define CALIBERR_CANT_OPEN_WAVE_DEV 2
#define CALIBERR_CANT_SET_VOLUME 3
#define CALIBERR_USER_CANCEL 4
#define CALIBERR_MIXER_ERROR 6
#define CALIBERR_NO_MICROPHONE 7
#define CALIBERR_DEVICE_ERROR 8
#define ATW_PLAYFILE_SOUND TEXT("TestSnd.Wav")
#define CLIPPINGVOL 0x6000
#define DECREMENT_AMOUNT 0x800
#define DECREMENT_AMOUNT_LARGE 0x1200
#define SILENCE_THRESHOLD 0x800
// trackbar sets volume range from 0-65535, but only has 100 steps.
#define TB_VOL_INCREMENT 655
#define ATW_MSG_LENGTH 256
#define MIXER_VOLUME_MAX 0x0000ffff
#define MIXER_VOLUME_UNINITIALIZED 0xffffffff
#define WM_AUDIO_CLIPPING (WM_USER+21)
#define WM_AUDIOTHREAD_STOP (WM_USER+22)
#define WM_AUDIOTHREAD_ERROR (WM_USER+23)
#define WM_AUDIOTHREAD_SOUND (WM_USER+24)
// vu meter
#define RECTANGLE_WIDTH 10
#define RECTANGLE_LEADING 1
#define MAX_VOLUME 32768
#define MAX_VOLUME_NORMALIZED 256
#define SHABS(x) (((x) > 0) ? (x) : (WORD)(-(x)))
typedef struct _power_struct
{
DWORD dwMin;
DWORD dwMax;
DWORD dwAvg;
LONG lDcComponent;
} AUDIO_POWER;
#define SAMPLE_SIZE 2 // 16 bit samples
typedef struct _ERRWIZINFO{
UINT uType;
UINT uButtonOptions;
UINT uNextWizId;
UINT uBackWizId;
UINT uErrTitleId;
UINT uErrTextId;
}ERRWIZINFO, *PERRWIZINFO;
typedef struct _calib_wavein
{
HWND hVUMeter;
DWORD nErrorTextId;
HWND hDlg;
UINT uWaveInDevId;
HANDLE hEvent; // signal to parent after creating msg queue
} CALIB_DISPLAY, *PCALIBDISPLAY;
typedef struct _AUDIOWIZINFO{
UINT uFlags;
UINT uOptions;
UINT uWaveInDevId;
UINT uWaveOutDevId;
BOOL iSetAgc;
UINT uChanged; //set in the wizard.
UINT uCalibratedVol;
UINT uSpeakerVol;
UINT uSoundCardCaps;
UINT uTypBandWidth;
TCHAR szWaveInDevName[MAXPNAMELEN];
TCHAR szWaveOutDevName[MAXPNAMELEN];
MIXVOLUME uPreCalibMainVol; // record volume
MIXVOLUME uPreCalibSubVol; // microphone volume
MIXVOLUME uPreCalibSpkVol; // speaker/wave volume
UINT uOldWaveInDevId;
UINT uOldWaveOutDevId;
TCHAR szOldWaveInDevName[MAXPNAMELEN];
TCHAR szOldWaveOutDevName[MAXPNAMELEN];
ERRWIZINFO ErrWizInfo;
DWORD dwWizButtons;
}AUDIOWIZINFO, *PAUDIOWIZINFO;
class WaveBufferList
{
BYTE *m_aBytes;
DWORD m_dwBuffers;
DWORD m_dwSize;
public:
WaveBufferList(DWORD dwBuffers, DWORD dwSize);
~WaveBufferList();
BYTE *GetBuffer(DWORD dwIndex);
};
WaveBufferList::WaveBufferList(DWORD dwBuffers, DWORD dwSize) :
m_aBytes(NULL),
m_dwBuffers(dwBuffers),
m_dwSize(dwSize)
{
if ((m_dwBuffers > 0) && (m_dwSize > 0))
{
m_aBytes = new BYTE[m_dwBuffers*m_dwSize];
}
}
BYTE *WaveBufferList::GetBuffer(DWORD dwIndex)
{
if ((dwIndex < m_dwBuffers) && (m_aBytes))
{
return m_aBytes + dwIndex*m_dwSize;
}
return NULL;
}
WaveBufferList::~WaveBufferList()
{
if (m_aBytes)
delete [] m_aBytes;
}
//------------------------ Prototype Definitions -------------------------
BOOL GetAudioWizardPages(UINT uOptions, UINT uDevId,
LPPROPSHEETPAGE *plpPropSheetPages, LPUINT lpuNumPages);
void ReleaseAudioWizardPages(LPPROPSHEETPAGE lpPropSheetPages, PWIZCONFIG pWizConfig,
PAUDIOWIZOUTPUT pAudioWizOut);
INT_PTR CallAudioCalibWizard(HWND hwndOwner, UINT uOptions,
UINT uDevId,PAUDIOWIZOUTPUT pAudioWizOut,INT iSetAgc);
static INT_PTR IntCreateAudioCalibWizard(HWND hwndOwner, UINT uOptions, UINT uDevId,
PAUDIOWIZOUTPUT pAudioWizOut,INT iSetAgc);
INT_PTR APIENTRY DetSoundCardWiz( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR APIENTRY AudioCalibWiz0( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR APIENTRY AudioCalibWiz1( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR APIENTRY AudioCalibWiz2( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR APIENTRY AudioCalibWiz3( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR APIENTRY AudioCalibWiz4( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR APIENTRY AudioCalibErrWiz( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
static void SaveAudioWizChanges(PAUDIOWIZINFO pawInfo);
static UINT GetSoundCardCaps(UINT uWaveInDevId,UINT uWaveOutDevId, HWND hwnd);
static UINT CheckForFullDuplex(UINT uWaveInDevId,UINT uWaveOutDevId);
static UINT CheckForAgc(UINT uWaveInDevId);
static UINT GetWaveDeviceFromWaveMapper(UINT uNumWaveDevId, UINT uInOrOut);
static UINT CheckForWaveDeviceSupport(UINT uWaveDevId, UINT uInOrOut);
static void ProcessCalibError(UINT uCalibErr, PAUDIOWIZINFO pawInfo);
static DWORD ComputePower(SHORT *wBuffer, DWORD dwNumSamples, AUDIO_POWER *pAudioPower);
static BOOL StartAGC(CMixerDevice *pMixer, BOOL iSetAgc, UINT uSoundCardCaps);
static void PaintVUMeter (HWND hwnd, DWORD dwVolume);
static DWORD CALLBACK CalibrateTalking(PVOID);
BOOL IntGetAudioWizardPages(UINT uOptions, UINT uDevId,
LPPROPSHEETPAGE *plpPropSheetPages, PWIZCONFIG *plpWizConfig,
LPUINT lpuNumPages, INT iSetAgc);
///////////////////////
static const BYTE g_VUTable[] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 23, 30, 35, 39, 43, 46, 49,
52, 55, 57, 60, 62, 64, 66, 68,
70, 72, 74, 76, 78, 80, 81, 83,
85, 86, 88, 89, 91, 92, 94, 95,
97, 98, 99, 101, 102, 103, 105, 106,
107, 108, 110, 111, 112, 113, 114, 115,
117, 118, 119, 120, 121, 122, 123, 124,
125, 126, 127, 128, 129, 130, 132, 132,
133, 134, 135, 136, 137, 138, 139, 140,
141, 142, 143, 144, 145, 146, 147, 147,
148, 149, 150, 151, 152, 153, 154, 154,
155, 156, 157, 158, 159, 159, 160, 161,
162, 163, 163, 164, 165, 166, 167, 167,
168, 169, 170, 170, 171, 172, 173, 173,
174, 175, 176, 176, 177, 178, 179, 179,
180, 181, 181, 182, 183, 184, 184, 185,
186, 186, 187, 188, 188, 189, 190, 190,
191, 192, 192, 193, 194, 194, 195, 196,
196, 197, 198, 198, 199, 200, 200, 201,
202, 202, 203, 204, 204, 205, 205, 206,
207, 207, 208, 209, 209, 210, 210, 211,
212, 212, 213, 213, 214, 215, 215, 216,
216, 217, 218, 218, 219, 219, 220, 221,
221, 222, 222, 223, 223, 224, 225, 225,
226, 226, 227, 227, 228, 229, 229, 230,
230, 231, 231, 232, 232, 233, 234, 234,
235, 235, 236, 236, 237, 237, 238, 238,
239, 239, 240, 241, 241, 242, 242, 243,
243, 244, 244, 245, 245, 246, 246, 247,
247, 248, 248, 249, 249, 250, 250, 251,
251, 252, 252, 253, 253, 254, 254, 255
};
//functions
BOOL GetAudioWizardPages(UINT uOptions, UINT uDevId,
LPPROPSHEETPAGE *plpPropSheetPages, PWIZCONFIG *plpWizConfig, LPUINT lpuNumPages)
{
return IntGetAudioWizardPages(uOptions, uDevId,
plpPropSheetPages, plpWizConfig,
lpuNumPages, READFROM_REGISTRY);
}
BOOL IntGetAudioWizardPages(UINT uOptions, UINT uDevId,
LPPROPSHEETPAGE *plpPropSheetPages, PWIZCONFIG *plpWizConfig,
LPUINT lpuNumPages, INT iSetAgc)
{
LPPROPSHEETPAGE psp;
UINT uNumPages = 0;
PWIZCONFIG pWizConfig;
PAUDIOWIZINFO pawInfo;
LPSTR szTemp;
RegEntry re( AUDIO_KEY, HKEY_CURRENT_USER );
*plpPropSheetPages = NULL;
*plpWizConfig = NULL;
psp = (LPPROPSHEETPAGE) LocalAlloc(LPTR, MAXNUMPAGES_INCALIBWIZ * sizeof(PROPSHEETPAGE));
if (NULL == psp)
{
return FALSE;
}
pWizConfig = (PWIZCONFIG) LocalAlloc(LPTR, sizeof(AUDIOWIZINFO) + sizeof(WIZCONFIG));
if (NULL == pWizConfig)
{
LocalFree(psp);
return FALSE;
}
pWizConfig->fCancel = FALSE;
pWizConfig->uFlags = HIWORD(uOptions);
pWizConfig->dwCustomDataSize = sizeof(AUDIOWIZINFO);
pawInfo = (PAUDIOWIZINFO)pWizConfig->pCustomData;
pawInfo->uOptions = LOWORD(uOptions);
pawInfo->uWaveInDevId = uDevId;
pawInfo->uChanged = AUDIOWIZ_NOCHANGES;
pawInfo->iSetAgc = iSetAgc;
pawInfo->uOldWaveInDevId = re.GetNumber(REGVAL_WAVEINDEVICEID,WAVE_MAPPER);
szTemp = re.GetString(REGVAL_WAVEINDEVICENAME);
if (szTemp)
lstrcpy(pawInfo->szOldWaveInDevName, szTemp);
pawInfo->uOldWaveOutDevId = re.GetNumber(REGVAL_WAVEOUTDEVICEID,WAVE_MAPPER);
szTemp = re.GetString(REGVAL_WAVEOUTDEVICENAME);
if (szTemp)
lstrcpy(pawInfo->szOldWaveOutDevName, szTemp);
pawInfo->uCalibratedVol = re.GetNumber(REGVAL_LASTCALIBRATEDVOL, 0xFFFFFFFF);
pawInfo->uPreCalibSpkVol.leftVolume = MIXER_VOLUME_UNINITIALIZED; // playback
pawInfo->uPreCalibSpkVol.rightVolume = MIXER_VOLUME_UNINITIALIZED; // playback
pawInfo->uPreCalibMainVol.leftVolume = MIXER_VOLUME_UNINITIALIZED; // recording
pawInfo->uPreCalibMainVol.rightVolume = MIXER_VOLUME_UNINITIALIZED; // recording
pawInfo->uPreCalibSubVol.leftVolume = MIXER_VOLUME_UNINITIALIZED; // microphone
pawInfo->uPreCalibSubVol.rightVolume = MIXER_VOLUME_UNINITIALIZED; // microphone
if (!waveInGetNumDevs() || !waveOutGetNumDevs())
pawInfo->uSoundCardCaps = SOUNDCARD_NONE;
else
pawInfo->uSoundCardCaps = SOUNDCARD_PRESENT;
FillInPropertyPage(&psp[uNumPages++], IDD_DETSOUNDCARDWIZ,
DetSoundCardWiz,(LPARAM)pWizConfig);
FillInPropertyPage(&psp[uNumPages++], IDD_AUDIOCALIBWIZ0,
AudioCalibWiz0, (LPARAM)pWizConfig);
if ((RUNDUE_CARDCHANGE == pawInfo->uOptions) ||
(RUNDUE_NEVERBEFORE == pawInfo->uOptions) ||
(RUNDUE_USERINVOKED == pawInfo->uOptions))
{
FillInPropertyPage(&psp[uNumPages++], IDD_AUDIOCALIBWIZ1,
AudioCalibWiz1,(LPARAM)pWizConfig);
}
else
{
//the old wavein and wave out device will remain
pawInfo->uWaveInDevId = pawInfo->uOldWaveInDevId;
pawInfo->uWaveOutDevId = pawInfo->uOldWaveOutDevId;
lstrcpy(pawInfo->szWaveInDevName,pawInfo->szOldWaveOutDevName);
lstrcpy(pawInfo->szWaveOutDevName,pawInfo->szOldWaveOutDevName);
}
// For each of the pages that I need, fill in a PROPSHEETPAGE structure.
FillInPropertyPage(&psp[uNumPages++], IDD_AUDIOCALIBWIZ2,
AudioCalibWiz2, (LPARAM)pWizConfig);
FillInPropertyPage(&psp[uNumPages++], IDD_AUDIOCALIBWIZ3,
AudioCalibWiz3, (LPARAM)pWizConfig);
FillInPropertyPage(&psp[uNumPages++], IDD_AUDIOCALIBWIZ4,
AudioCalibWiz4, (LPARAM)pWizConfig);
FillInPropertyPage(&psp[uNumPages++], IDD_AUDIOCALIBERRWIZ,
AudioCalibErrWiz, (LPARAM)pWizConfig);
// The number of pages in this wizard.
*lpuNumPages = uNumPages;
*plpPropSheetPages = (LPPROPSHEETPAGE) psp;
*plpWizConfig = pWizConfig;
return TRUE;
}
void ReleaseAudioWizardPages(LPPROPSHEETPAGE lpPropSheetPages,
PWIZCONFIG pWizConfig, PAUDIOWIZOUTPUT pAudioWizOut)
{
PAUDIOWIZINFO pawInfo;
pawInfo = (PAUDIOWIZINFO)pWizConfig->pCustomData;
if (pAudioWizOut)
{
pAudioWizOut->uValid = pawInfo->uChanged;//whatever is set in the wizard is valid
pAudioWizOut->uSoundCardCaps = pawInfo->uSoundCardCaps;
pAudioWizOut->uCalibratedVol = pawInfo->uCalibratedVol;
pAudioWizOut->uTypBandWidth = pawInfo->uTypBandWidth;
pAudioWizOut->uWaveInDevId = pawInfo->uWaveInDevId;
pAudioWizOut->uWaveOutDevId = pawInfo->uWaveOutDevId;
lstrcpy(pAudioWizOut->szWaveInDevName,pawInfo->szWaveInDevName);
lstrcpy(pAudioWizOut->szWaveOutDevName,pawInfo->szWaveOutDevName);
//the ui needs to read the changed values and call nac methods for
//the changes below
pAudioWizOut->uChanged = AUDIOWIZ_NOCHANGES;
if ((pawInfo->uChanged & SOUNDCARD_CHANGED) &&
((pawInfo->uWaveInDevId != pawInfo->uOldWaveInDevId) ||
(pawInfo->uWaveOutDevId != pawInfo->uOldWaveOutDevId) ||
lstrcmp(pawInfo->szWaveInDevName,pawInfo->szOldWaveInDevName) ||
lstrcmp(pawInfo->szWaveOutDevName,pawInfo->szOldWaveOutDevName)))
{
pAudioWizOut->uChanged |= SOUNDCARD_CHANGED;
pAudioWizOut->uChanged |= SOUNDCARDCAPS_CHANGED;
}
}
LocalFree(pWizConfig);
LocalFree(lpPropSheetPages);
}
INT_PTR CallAudioCalibWizard(HWND hwndOwner, UINT uOptions,
UINT uDevId,PAUDIOWIZOUTPUT pAudioWizOut,INT iSetAgc)
{
//agc values are provided
return(IntCreateAudioCalibWizard(hwndOwner, uOptions, uDevId, pAudioWizOut, iSetAgc));
}
VOID CmdAudioCalibWizard(HWND hwnd)
{
AUDIOWIZOUTPUT awo;
INT_PTR nRet = IntCreateAudioCalibWizard(
hwnd,
RUNDUE_USERINVOKED,
WAVE_MAPPER,
&awo,
READFROM_REGISTRY);
if ((nRet > 0) && (awo.uChanged & SOUNDCARD_CHANGED))
{
::HandleConfSettingsChange(CSETTING_L_AUDIODEVICE);
}
}
INT_PTR IntCreateAudioCalibWizard(HWND hwndOwner, UINT uOptions,
UINT uDevId, PAUDIOWIZOUTPUT pAudioWizOut, INT iSetAgc)
{
LPPROPSHEETPAGE ppsp;
UINT uNumPages;
PWIZCONFIG pWizConfig;
if (!IntGetAudioWizardPages(uOptions, uDevId,
&ppsp, &pWizConfig, &uNumPages, iSetAgc))
{
return -1;
}
PROPSHEETHEADER psh;
InitStruct(&psh);
// Specify that this is a wizard property sheet with no Apply Now button.
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD | PSH_NOAPPLYNOW;
psh.hwndParent = hwndOwner;
// Use page captions.
ASSERT(NULL == psh.pszCaption);
ASSERT(0 == psh.nStartPage);
psh.nPages = uNumPages;
psh.ppsp = ppsp;
// Create and run the wizard.
INT_PTR iRet = PropertySheet(&psh);
ReleaseAudioWizardPages(ppsp, pWizConfig, pAudioWizOut);
return iRet;
}
void SaveAudioWizChanges(PAUDIOWIZINFO pawInfo)
{
RegEntry re( AUDIO_KEY, HKEY_CURRENT_USER );
if (pawInfo->uChanged & SOUNDCARDCAPS_CHANGED)
{
re.SetValue ( REGVAL_SOUNDCARDCAPS, pawInfo->uSoundCardCaps);
re.SetValue ( REGVAL_FULLDUPLEX, ISSOUNDCARDFULLDUPLEX(pawInfo->uSoundCardCaps) ? FULLDUPLEX_ENABLED : FULLDUPLEX_DISABLED);
if (!ISDIRECTSOUNDAVAILABLE(pawInfo->uSoundCardCaps))
{
re.SetValue(REGVAL_DIRECTSOUND, (ULONG)DSOUND_USER_DISABLED);
}
}
if (pawInfo->uChanged & CALIBVOL_CHANGED)
{
re.SetValue ( REGVAL_CALIBRATEDVOL, pawInfo->uCalibratedVol);
re.SetValue ( REGVAL_LASTCALIBRATEDVOL, pawInfo->uCalibratedVol);
}
if (pawInfo->uChanged & SOUNDCARD_CHANGED)
{
re.SetValue (REGVAL_WAVEINDEVICEID, pawInfo->uWaveInDevId);
re.SetValue (REGVAL_WAVEINDEVICENAME, pawInfo->szWaveInDevName);
re.SetValue (REGVAL_WAVEOUTDEVICEID, pawInfo->uWaveOutDevId);
re.SetValue (REGVAL_WAVEOUTDEVICENAME, pawInfo->szWaveOutDevName);
}
if (pawInfo->uChanged & SPEAKERVOL_CHANGED)
{
re.SetValue (REGVAL_SPEAKERVOL, pawInfo->uSpeakerVol);
}
}
INT_PTR APIENTRY DetSoundCardWiz( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
PROPSHEETPAGE * ps;
static PWIZCONFIG pWizConfig;
static PAUDIOWIZINFO pawInfo;
switch (message) {
case WM_INITDIALOG:
// Save the PROPSHEETPAGE information.
ps = (PROPSHEETPAGE *)lParam;
pWizConfig = (PWIZCONFIG)ps->lParam;
pawInfo = (PAUDIOWIZINFO)pWizConfig->pCustomData;
if (g_fSilentWizard)
{
HideWizard(GetParent(hDlg));
}
return (TRUE);
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code) {
case PSN_SETACTIVE:
{
if (pawInfo->uSoundCardCaps != SOUNDCARD_NONE)
{
// Skip this page; go to IDD_AUDIOCALIBWIZ0;
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
return TRUE;
}
// Initialize the controls.
DWORD dwWizButtons = PSWIZB_FINISH;
if (pWizConfig->uFlags & STARTWITH_BACK)
dwWizButtons |= PSWIZB_BACK;
PropSheet_SetWizButtons(GetParent(hDlg), dwWizButtons );
if (g_fSilentWizard)
{
PropSheet_PressButton(GetParent(hDlg), PSBTN_FINISH);
}
break;
}
case PSN_WIZNEXT:
// Due to bug in ComCtl32 don't allow next
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
return TRUE;
case PSN_WIZBACK:
// Due to bug in ComCtl32 check if button is enabled
if (!(pWizConfig->uFlags & STARTWITH_BACK))
{
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
return TRUE;
}
else
{
UINT_PTR iPrev = GetPageBeforeAudioWiz();
ASSERT( iPrev );
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, iPrev);
return TRUE;
}
break;
case PSN_WIZFINISH:
{
RegEntry re( AUDIO_KEY, HKEY_CURRENT_USER );
re.SetValue ( REGVAL_SOUNDCARDCAPS, pawInfo->uSoundCardCaps);
break;
}
case PSN_RESET:
pawInfo->uChanged = AUDIOWIZ_NOCHANGES;
break;
default:
break;
}
break;
default:
return FALSE;
}
return (FALSE);
}
INT_PTR APIENTRY AudioCalibWiz0( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
PROPSHEETPAGE * ps;
static PWIZCONFIG pWizConfig;
static PAUDIOWIZINFO pawInfo;
switch (message) {
case WM_INITDIALOG:
// Save the PROPSHEETPAGE information.
ps = (PROPSHEETPAGE *)lParam;
pWizConfig = (PWIZCONFIG)ps->lParam;
pawInfo = (PAUDIOWIZINFO)pWizConfig->pCustomData;
return TRUE;
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code) {
case PSN_SETACTIVE:
{
// Initialize the controls.
DWORD dwWizButtons = PSWIZB_NEXT;
if (pWizConfig->uFlags & STARTWITH_BACK)
dwWizButtons |= PSWIZB_BACK;
PropSheet_SetWizButtons(GetParent(hDlg), dwWizButtons );
if (g_fSilentWizard)
{
PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT);
}
break;
}
case PSN_WIZBACK:
// Due to bug in ComCtl32 check if button is enabled
if (!(pWizConfig->uFlags & STARTWITH_BACK))
{
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
return TRUE;
}
if (pawInfo->uSoundCardCaps != SOUNDCARD_NONE)
{
// don't go to the DetSoundCard page...
UINT_PTR iPrev = GetPageBeforeAudioWiz();
ASSERT( iPrev );
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, iPrev);
return TRUE;
}
break;
case PSN_RESET:
pawInfo->uChanged = AUDIOWIZ_NOCHANGES;
break;
default:
break;
}
break;
default:
return FALSE;
}
return (FALSE);
}
INT_PTR APIENTRY AudioCalibWiz1( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static PROPSHEETPAGE * ps;
static PWIZCONFIG pWizConfig;
static PAUDIOWIZINFO pawInfo;
UINT uSoundCardCaps;
int nIndex;
HWND hwndCB;
switch (message)
{
case WM_INITDIALOG:
{
WAVEINCAPS wiCaps;
WAVEOUTCAPS woCaps;
LPSTR lpszTemp;
UINT uWaveDevId;
UINT uWaveDevRealId;
UINT uDevCnt;
UINT uCnt;
UINT uDevID;
// Save the PROPSHEETPAGE information.
ps = (PROPSHEETPAGE *)lParam;
pWizConfig = (PWIZCONFIG)ps->lParam;
pawInfo = (PAUDIOWIZINFO)pWizConfig->pCustomData;
//we come to this page only if a sound card is present.
// If we end up with WAVE_MAPPER, this means that this is the first time we run this code
pawInfo->uWaveInDevId = uWaveDevRealId = uWaveDevId = pawInfo->uOldWaveInDevId;
uDevCnt = waveInGetNumDevs();
lstrcpy(pawInfo->szWaveInDevName, lpszTemp = pawInfo->szOldWaveInDevName);
//add the device to the drop down list
hwndCB = GetDlgItem(hDlg, IDC_WAVEIN);
for (uDevID = 0, uCnt = uDevCnt; 0 != uCnt; uDevID++, uCnt--)
{
if ((waveInGetDevCaps(uDevID, &wiCaps, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) &&
(CheckForWaveDeviceSupport(uDevID, 0)))
{
nIndex = ComboBox_AddString(hwndCB, wiCaps.szPname);
ComboBox_SetItemData(hwndCB, nIndex, uDevID);
//if a device hasnt been chosen previously, then set the default device to the
//zeroth one
if (uWaveDevId == WAVE_MAPPER)
{
if (uDevCnt <= 1)
uWaveDevRealId = uDevID;
else
if ((uWaveDevRealId == WAVE_MAPPER) && (uDevCnt == uCnt))
uWaveDevRealId = GetWaveDeviceFromWaveMapper(uCnt, 0);
if (uDevID == uWaveDevRealId)
{
ComboBox_SetCurSel(hwndCB, nIndex);
pawInfo->uWaveInDevId = uDevID;
lstrcpy(pawInfo->szWaveInDevName, wiCaps.szPname);
}
}
else
{
if ((0 == nIndex) || (!lstrcmp(wiCaps.szPname, lpszTemp)))
{
ComboBox_SetCurSel(hwndCB, nIndex);
pawInfo->uWaveInDevId = uDevID;
lstrcpy(pawInfo->szWaveInDevName, wiCaps.szPname);
}
}
}
}
// TEMPORARY 1.0 stuff because this would require too much rewrite:
// In case no device was added to the combo box, let's put the first one in
// even though we know it will never work.
if ((0 == ComboBox_GetCount(hwndCB)) || (uWaveDevRealId == WAVE_MAPPER))
{
waveInGetDevCaps(0,&wiCaps, sizeof(WAVEINCAPS));
if (0 == ComboBox_GetCount(hwndCB))
{
ComboBox_AddString(hwndCB, wiCaps.szPname);
ComboBox_SetItemData(hwndCB, 0, 0);
}
ComboBox_SetCurSel(hwndCB, 0);
pawInfo->uWaveInDevId = 0;
lstrcpy(pawInfo->szWaveInDevName, wiCaps.szPname);
}
// If we end up with WAVE_MAPPER, this means that this is the first time we run this code
pawInfo->uWaveOutDevId = uWaveDevRealId = uWaveDevId = pawInfo->uOldWaveOutDevId;
uDevCnt = waveOutGetNumDevs();
lstrcpy(pawInfo->szWaveOutDevName, lpszTemp = pawInfo->szOldWaveOutDevName);
//add the device to the drop down list
hwndCB = GetDlgItem(hDlg, IDC_WAVEOUT);
for (uDevID = 0, uCnt = uDevCnt; 0 != uCnt; uDevID++, uCnt--)
{
if ((waveOutGetDevCaps(uDevID, &woCaps, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) &&
(CheckForWaveDeviceSupport(uDevID, 1)))
{
nIndex = ComboBox_AddString(hwndCB, woCaps.szPname);
ComboBox_SetItemData(hwndCB, nIndex, uDevID);
//if a device hasnt been chosen previously, then set the default device to the
//zeroth one
if (uWaveDevId == WAVE_MAPPER)
{
if (uDevCnt <= 1)
uWaveDevRealId = uDevID;
else
if ((uWaveDevRealId == WAVE_MAPPER) && (uDevCnt == uCnt))
uWaveDevRealId = GetWaveDeviceFromWaveMapper(uCnt, 1);
if (uDevID == uWaveDevRealId)
{
ComboBox_SetCurSel(hwndCB, nIndex);
pawInfo->uWaveOutDevId = uDevID;
lstrcpy(pawInfo->szWaveOutDevName, woCaps.szPname);
}
}
else
{
if ((0 == nIndex) || (!lstrcmp(woCaps.szPname, lpszTemp)))
{
ComboBox_SetCurSel(hwndCB, nIndex);
pawInfo->uWaveOutDevId = uDevID;
lstrcpy(pawInfo->szWaveOutDevName, woCaps.szPname);
}
}
}
}
// TEMPORARY 1.0 stuff because this would require too much rewrite:
// In case no device was added to the combo box, let's put the first one in
// even though we know it will never work.
if ((0 == ComboBox_GetCount(hwndCB)) || (uWaveDevRealId == WAVE_MAPPER))
{
waveOutGetDevCaps(0,&woCaps, sizeof(WAVEOUTCAPS));
if (0 == ComboBox_GetCount(hwndCB))
{
ComboBox_AddString(hwndCB, (LPARAM)woCaps.szPname);
ComboBox_SetItemData(hwndCB, 0, 0);
}
ComboBox_SetCurSel(hwndCB, 0);
pawInfo->uWaveOutDevId = 0;
lstrcpy(pawInfo->szWaveOutDevName, woCaps.szPname);
}
return (TRUE);
}
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code) {
case PSN_SETACTIVE:
// Initialize the controls.
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_NEXT);
if (g_fSilentWizard)
{
PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT);
break;
}
else
{
if ((1 != ComboBox_GetCount(GetDlgItem(hDlg, IDC_WAVEIN))) ||
(1 != ComboBox_GetCount(GetDlgItem(hDlg, IDC_WAVEOUT))))
{
break;
}
// else fall through to next
}
case PSN_WIZNEXT:
// set settings in registry
//check the device
//get the new wavein device and its info
hwndCB = GetDlgItem(hDlg, IDC_WAVEIN);
nIndex = ComboBox_GetCurSel(hwndCB);
pawInfo->uWaveInDevId = (UINT)ComboBox_GetItemData(hwndCB, nIndex);
ComboBox_GetLBText(hwndCB, nIndex, pawInfo->szWaveInDevName);
//get the new waveout device and its info
hwndCB = GetDlgItem(hDlg, IDC_WAVEOUT);
nIndex = ComboBox_GetCurSel(hwndCB);
pawInfo->uWaveOutDevId = (UINT)ComboBox_GetItemData(hwndCB, nIndex);
ComboBox_GetLBText(hwndCB, nIndex, pawInfo->szWaveOutDevName);
uSoundCardCaps = GetSoundCardCaps(pawInfo->uWaveInDevId,pawInfo->uWaveOutDevId, hDlg);
//save it in the wizinfo struct for writing to registry
pawInfo->uSoundCardCaps = uSoundCardCaps;
pawInfo->uChanged |= SOUNDCARDCAPS_CHANGED;
pawInfo->uChanged |= SOUNDCARD_CHANGED;
if (PSN_SETACTIVE == ((NMHDR FAR *) lParam)->code)
{
// Skip this page;
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
return TRUE;
}
break;
case PSN_RESET:
{
pawInfo->uChanged = AUDIOWIZ_NOCHANGES;
break;
}
default:
break;
}
break;
default:
return FALSE;
}
return (FALSE);
}
// The WaveOut test page
INT_PTR WINAPI AudioCalibWiz2(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static CMixerDevice *pMixer = NULL;
static HWND hTrackBar;
DWORD dwTBPos;
MIXVOLUME dwNewVol;
static MIXVOLUME dwVol; // last set volume
BOOL fRet;
static BOOL fCanSetVolume = FALSE;
static waveOutDev *pWaveOut= NULL;
UINT uWaveOutDevId;
static PROPSHEETPAGE * ps;
static PWIZCONFIG pWizConfig;
static PAUDIOWIZINFO pawInfo;
TCHAR szText[ATW_MSG_LENGTH];
MMRESULT mmr;
static fIsPlaying;
switch (msg)
{
case (WM_INITDIALOG):
{
pMixer = NULL;
hTrackBar = GetDlgItem(hDlg, IDC_ATW_SLIDER1);
ps = (PROPSHEETPAGE *)lParam;
pWizConfig = (PWIZCONFIG)ps->lParam;
pawInfo = (PAUDIOWIZINFO)pWizConfig->pCustomData;
break;
}
case (WM_NOTIFY):
{
switch (((NMHDR *)lParam)->code)
{
case PSN_SETACTIVE:
fIsPlaying = FALSE;
uWaveOutDevId = pawInfo->uWaveOutDevId;
pMixer = CMixerDevice::GetMixerForWaveDevice(hDlg, uWaveOutDevId, MIXER_OBJECTF_WAVEOUT);
if (pMixer)
{
SendMessage(hTrackBar, TBM_SETRANGE, TRUE, (LPARAM)MAKELONG(0, 100));
SendMessage(hTrackBar, TBM_SETTICFREQ, 10, 0);
SendMessage(hTrackBar, TBM_SETPAGESIZE, 0, 20);
SendMessage(hTrackBar, TBM_SETLINESIZE, 0, 10);
pMixer->GetVolume(&dwVol);
fCanSetVolume = pMixer->SetVolume(&dwVol);
pMixer->UnMuteVolume();
// preserve the speaker volume so that it can be restored
// if the user presses cancel
if (pawInfo->uPreCalibSpkVol.leftVolume == MIXER_VOLUME_UNINITIALIZED)
{
pawInfo->uPreCalibSpkVol.leftVolume = dwVol.leftVolume;
}
if (pawInfo->uPreCalibSpkVol.rightVolume == MIXER_VOLUME_UNINITIALIZED)
{
pawInfo->uPreCalibSpkVol.rightVolume = dwVol.rightVolume;
}
}
else
fCanSetVolume = FALSE;
EnableWindow(GetDlgItem(hDlg, IDC_GROUP_VOLUME), fCanSetVolume);
EnableWindow(GetDlgItem(hDlg, IDC_ATW_SLIDER1), fCanSetVolume);
EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_ATW_TEST), TRUE);
if (fCanSetVolume)
{
FLoadString(IDS_ATW_PLAYBACK, szText, CCHMAX(szText));
SendMessage(hTrackBar, TBM_SETPOS, TRUE, max(dwVol.leftVolume , dwVol.rightVolume)/TB_VOL_INCREMENT);
}
// if we can't get a mixer, then center the trackbar and disable
else
{
FLoadString(IDS_ATW_PLAYBACK_NOMIX, szText, CCHMAX(szText));
SendMessage(hTrackBar, TBM_SETPOS, TRUE, 50);
}
SetDlgItemText(hDlg, IDC_ATW_PLAYTEXT, szText);
SetDlgItemText(hDlg, IDC_ATW_PLAYBACK_ERROR, TEXT(""));
FLoadString(IDS_TESTBUTTON_TEXT, szText, CCHMAX(szText));
SetDlgItemText(hDlg, IDC_BUTTON_ATW_TEST, szText);
pWaveOut = new waveOutDev(uWaveOutDevId, hDlg);
if (pWaveOut == NULL)
{
ERROR_OUT(("AudioWiz2: Unable to create waveOutDev object"));
}
PropSheet_SetWizButtons(GetParent(hDlg),PSWIZB_BACK|PSWIZB_NEXT);
if (g_fSilentWizard)
{
PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT);
return TRUE;
}
break;
case PSN_WIZNEXT:
case PSN_WIZBACK:
case PSN_WIZFINISH:
case PSN_KILLACTIVE:
if ((fCanSetVolume) && (pMixer))
{
pMixer->GetVolume(&dwNewVol);
pawInfo->uSpeakerVol = max(dwNewVol.leftVolume , dwNewVol.rightVolume);
pawInfo->uChanged |= SPEAKERVOL_CHANGED;
}
if (pMixer)
{
delete pMixer;
pMixer = NULL;
}
if (pWaveOut)
{
delete pWaveOut;
pWaveOut = NULL;
}
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
break;
case PSN_RESET:
// psn_reset get's received even if user presses
// cancel on another dialog.
// restore speaker volume to what it was before the tuning wizard was launched
if (pawInfo->uPreCalibSpkVol.leftVolume <= MIXER_VOLUME_MAX || pawInfo->uPreCalibSpkVol.rightVolume <= MIXER_VOLUME_MAX)
{
if (pMixer == NULL)
{
pMixer = CMixerDevice::GetMixerForWaveDevice(hDlg, pawInfo->uWaveOutDevId, MIXER_OBJECTF_WAVEOUT);
}
if (pMixer)
{
pMixer->SetVolume(&pawInfo->uPreCalibSpkVol);
}
}
if (pMixer)
{
delete pMixer;
pMixer = NULL;
}
if (pWaveOut)
{
delete pWaveOut;
pWaveOut = NULL;
}
break;
default:
return FALSE;
}
return TRUE;
}
case (WM_HSCROLL): // trackbar notification
{
dwTBPos = (DWORD)SendMessage(hTrackBar, TBM_GETPOS, 0, 0);
if (pMixer)
{
pMixer->GetVolume(&dwVol);
NewMixVolume(&dwNewVol, dwVol, (dwTBPos * TB_VOL_INCREMENT));
pMixer->SetVolume(&dwNewVol);
}
break;
}
// mixer notifications
case MM_MIXM_CONTROL_CHANGE:
case MM_MIXM_LINE_CHANGE:
{
if (pMixer)
{
fRet = pMixer->GetVolume(&dwNewVol);
if ((fRet) && (dwNewVol.leftVolume != dwVol.leftVolume || dwNewVol.rightVolume != dwVol.rightVolume))
{
dwVol = dwNewVol;
SendMessage(hTrackBar, TBM_SETPOS, TRUE, max(dwVol.leftVolume , dwVol.rightVolume)/TB_VOL_INCREMENT);
break;
}
}
break;
}
// when the PlayFile is done playing
case WOM_DONE:
{
if ((pWaveOut) && (fIsPlaying))
{
pWaveOut->PlayFile(ATW_PLAYFILE_SOUND);
}
break;
}
case WM_COMMAND:
{
// if the device fails to open, then we
// display the error text
// if the WAV file fails to load, we simply disable the button
if (LOWORD(wParam) == IDC_BUTTON_ATW_TEST)
{
if (fIsPlaying == TRUE)
{
fIsPlaying = FALSE;
pWaveOut->Close();
FLoadString(IDS_TESTBUTTON_TEXT, szText, CCHMAX(szText));
SetDlgItemText(hDlg, IDC_BUTTON_ATW_TEST, szText);
break;
}
mmr = pWaveOut->PlayFile(ATW_PLAYFILE_SOUND);
if (mmr == MMSYSERR_ALLOCATED )
{
FLoadString(IDS_PLAYBACK_ERROR, szText, CCHMAX(szText));
SetDlgItemText(hDlg, IDC_ATW_PLAYBACK_ERROR, szText);
}
else if (mmr != MMSYSERR_NOERROR)
{
EnableWindow(GetDlgItem(hDlg, IDC_BUTTON_ATW_TEST), FALSE);
FLoadString(IDS_PLAYBACK_ERROR2, szText, CCHMAX(szText));
SetDlgItemText(hDlg, IDC_ATW_PLAYBACK_ERROR, szText);
}
else // mmr == MMSYSERR_NOERROR
{
SetDlgItemText(hDlg, IDC_ATW_PLAYBACK_ERROR, TEXT(""));
FLoadString(IDS_STOPBUTTON_TEXT, szText, CCHMAX(szText));
SetDlgItemText(hDlg, IDC_BUTTON_ATW_TEST, szText);
fIsPlaying = TRUE;
}
}
break;
}
default:
return FALSE;
}
return TRUE;
}
// Microphone test page
INT_PTR WINAPI AudioCalibWiz3(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HANDLE hThread = NULL;
static DWORD dwThreadID = 0;
static HANDLE hEvent = NULL;
static CMixerDevice *pMixer = NULL;
static HWND hTrackBar;
static DWORD dwMainVol;
static DWORD dwSubVol;
DWORD dwTBPos, dwNewMainVol, dwNewSubVol;
MIXVOLUME dwVol, dwNewVol;
BOOL fRet;
static BOOL fCanSetVolume=FALSE;
static CALIB_DISPLAY CalibDisplay;
static PROPSHEETPAGE * ps;
static PWIZCONFIG pWizConfig;
static PAUDIOWIZINFO pawInfo;
static BOOL fSoundDetected;
const TCHAR *szEventName = _TEXT("CONF.EXE ATW Event Handle");
switch (msg)
{
case (WM_INITDIALOG):
{
hThread = NULL;
dwThreadID = NULL;
hTrackBar = GetDlgItem(hDlg, IDC_ATW_SLIDER2);
ps = (PROPSHEETPAGE *)lParam;
pWizConfig = (PWIZCONFIG)ps->lParam;
pawInfo = (PAUDIOWIZINFO)pWizConfig->pCustomData;
break;
}
case (WM_NOTIFY):
{
switch (((NMHDR *)lParam)->code)
{
case PSN_SETACTIVE:
if (g_fSilentWizard)
{
PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT);
return TRUE;
}
fCanSetVolume = TRUE;
fSoundDetected = FALSE;
pMixer = CMixerDevice::GetMixerForWaveDevice(hDlg, pawInfo->uWaveInDevId, MIXER_OBJECTF_WAVEIN);
if (pMixer)
{
SendMessage(hTrackBar, TBM_SETRANGE, TRUE, (LPARAM)MAKELONG(0, 100));
SendMessage(hTrackBar, TBM_SETTICFREQ, 10, 0);
SendMessage(hTrackBar, TBM_SETPAGESIZE, 0, 20);
SendMessage(hTrackBar, TBM_SETLINESIZE, 0, 10);
// remember the volume in case the user presses cancel
if (pawInfo->uPreCalibMainVol.leftVolume == MIXER_VOLUME_UNINITIALIZED ||
pawInfo->uPreCalibMainVol.rightVolume == MIXER_VOLUME_UNINITIALIZED)
{
pMixer->GetMainVolume(&(pawInfo->uPreCalibMainVol));
}
if (pawInfo->uPreCalibSubVol.leftVolume == MIXER_VOLUME_UNINITIALIZED ||
pawInfo->uPreCalibSubVol.rightVolume == MIXER_VOLUME_UNINITIALIZED)
{
pMixer->GetSubVolume(&(pawInfo->uPreCalibSubVol));
}
MIXVOLUME mixVol = {-1, -1};
pMixer->GetVolume(&mixVol);
fCanSetVolume = pMixer->SetVolume(&mixVol);
dwSubVol = dwMainVol= 0xffff;
SendMessage(hTrackBar, TBM_SETPOS, TRUE, dwMainVol/TB_VOL_INCREMENT);
pMixer->EnableMicrophone();
pMixer->UnMuteVolume();
StartAGC(pMixer, pawInfo->iSetAgc, pawInfo->uSoundCardCaps);
}
// no mixer!
if (pMixer == NULL)
{
ProcessCalibError(CALIBERR_MIXER_ERROR, pawInfo);
}
// no microphone!
else if (fCanSetVolume == FALSE)
{
delete pMixer;
pMixer = NULL;
ProcessCalibError(CALIBERR_CANT_SET_VOLUME, pawInfo);
}
// process error
if ((pMixer == NULL) || (fCanSetVolume == FALSE))
{
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_AUDIOCALIBERRWIZ);
return TRUE;
}
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK|PSWIZB_NEXT);
CalibDisplay.hDlg = hDlg;
CalibDisplay.hVUMeter = GetDlgItem(hDlg, IDC_VUMETER);
CalibDisplay.uWaveInDevId = pawInfo->uWaveInDevId;
ASSERT(hEvent == NULL);
// just create the same event twice (easier than using DuplicateHandle)
hEvent = CreateEvent(NULL, FALSE, FALSE, szEventName);
CalibDisplay.hEvent = CreateEvent(NULL, FALSE, FALSE, szEventName);
ASSERT(hThread == NULL);
hThread = NULL;
if (hEvent && (CalibDisplay.hEvent))
{
hThread = CreateThread(NULL, 0, CalibrateTalking, (LPVOID)(&CalibDisplay), 0, &dwThreadID);
}
#ifdef DEBUG
if ((hEvent == NULL) || (CalibDisplay.hEvent == NULL))
{
ERROR_OUT(("ATW: Unable to create events for thread control!\r\n"));
}
else if (hThread == NULL)
{
ERROR_OUT(("ATW: Unable to create thread for recording loop!\r\n"));
}
#endif
break;
case PSN_WIZNEXT:
case PSN_WIZBACK:
case PSN_WIZFINISH:
case PSN_KILLACTIVE:
if (hThread)
{
SetEvent(hEvent); // signal the thread to exit, thread will CloseHandle(hEvent)
// wait for the thread to exit, but
// but keep processing window messages
AtlWaitWithMessageLoop(hThread);
CloseHandle(hEvent);
CloseHandle(hThread);
hThread = NULL;
hEvent = NULL;
dwThreadID = 0;
}
// silent wizard get's set to max
if (g_fSilentWizard)
{
pawInfo->uChanged |= CALIBVOL_CHANGED;
pawInfo->uChanged = 0xffff;
}
else if ((fCanSetVolume) && (pMixer))
{
pawInfo->uChanged |= CALIBVOL_CHANGED;
pMixer->GetVolume(&dwVol);
pawInfo->uCalibratedVol = max (dwVol.leftVolume , dwVol.rightVolume);
}
if (pMixer)
{
delete pMixer;
pMixer = NULL;
}
// if we never got an indication back from the sound thread
// then the next page to be displayed is the "microphone" error page
// note the check for the silent wizard
if ((!g_fSilentWizard) && (fSoundDetected == FALSE) && (((NMHDR *)lParam)->code == PSN_WIZNEXT))
{
ProcessCalibError(CALIBERR_NO_MICROPHONE, pawInfo);
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, IDD_AUDIOCALIBERRWIZ);
}
else
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
break;
case PSN_RESET:
// psn_reset get's received even if user presses
// cancel on another dialog.
if (hThread)
{
SetEvent(hEvent); // signal thread to exit
AtlWaitWithMessageLoop(hThread);
CloseHandle(hEvent);
hEvent = NULL;
CloseHandle(hThread);
hThread = NULL;
dwThreadID = 0;
}
// restore recording/microphone volume to what it was before the tuning wizard was launched
if ( (pawInfo->uPreCalibMainVol.leftVolume <= MIXER_VOLUME_MAX && pawInfo->uPreCalibMainVol.rightVolume <= MIXER_VOLUME_MAX) ||
(pawInfo->uPreCalibSubVol.leftVolume <= MIXER_VOLUME_MAX && pawInfo->uPreCalibSubVol.rightVolume <= MIXER_VOLUME_MAX))
{
if (pMixer == NULL)
{
pMixer = CMixerDevice::GetMixerForWaveDevice(hDlg, pawInfo->uWaveInDevId, MIXER_OBJECTF_WAVEIN);
}
if (pMixer)
{
if (pawInfo->uPreCalibMainVol.leftVolume < MIXER_VOLUME_MAX || pawInfo->uPreCalibMainVol.rightVolume < MIXER_VOLUME_MAX)
{
pMixer->SetMainVolume(&pawInfo->uPreCalibMainVol);
}
if (pawInfo->uPreCalibSubVol.leftVolume < MIXER_VOLUME_MAX || pawInfo->uPreCalibSubVol.rightVolume < MIXER_VOLUME_MAX)
{
pMixer->SetSubVolume(&pawInfo->uPreCalibSubVol);
}
}
}
if (pMixer)
{
delete pMixer;
pMixer = NULL;
}
break;
default:
return FALSE;
}
return TRUE;
}
case (WM_HSCROLL): // trackbar notification
{
dwTBPos = (DWORD)SendMessage(hTrackBar, TBM_GETPOS, 0, 0);
if (pMixer)
{
pMixer->GetVolume(&dwVol);
NewMixVolume(&dwNewVol, dwVol, (dwTBPos * TB_VOL_INCREMENT));
pMixer->SetVolume(&dwNewVol);
}
break;
}
// notifications from the mixer
case MM_MIXM_CONTROL_CHANGE:
case MM_MIXM_LINE_CHANGE:
{
if (pMixer)
{
fRet = pMixer->GetMainVolume(&dwVol);
if ((fRet) && (dwVol.leftVolume != dwMainVol || dwVol.rightVolume != dwMainVol))
{
pMixer->SetSubVolume(&dwVol);
SendMessage(hTrackBar, TBM_SETPOS, TRUE, max(dwVol.leftVolume , dwVol.rightVolume)/TB_VOL_INCREMENT);
break;
}
MIXVOLUME subvol;
fRet = pMixer->GetSubVolume(&subvol);
if ((fRet) && (dwVol.leftVolume != subvol.leftVolume || dwVol.rightVolume !=subvol.rightVolume))
{
pMixer->SetMainVolume(&subvol);
SendMessage(hTrackBar, TBM_SETPOS, TRUE, max(subvol.leftVolume , subvol.rightVolume)/TB_VOL_INCREMENT);
break;
}
}
break;
}
// calibration thread sends this message to indicate that the
// volume is too loud
case WM_AUDIO_CLIPPING:
{
if (pMixer)
{
pMixer->GetVolume(&dwVol);
if (dwVol.leftVolume > DECREMENT_AMOUNT || dwVol.rightVolume > DECREMENT_AMOUNT)
{
dwVol.leftVolume -=DECREMENT_AMOUNT;
dwVol.rightVolume -=DECREMENT_AMOUNT;
pMixer->SetVolume(&dwVol);
// fix for Videum driver
// check to see if the volume actually got lowered
// if it didn't, try a larger decrement
pMixer->GetVolume(&dwNewVol);
if ((dwNewVol.leftVolume == dwVol.leftVolume) && (dwVol.leftVolume >= DECREMENT_AMOUNT_LARGE) ||
(dwNewVol.rightVolume == dwVol.rightVolume) && (dwVol.rightVolume >= DECREMENT_AMOUNT_LARGE))
{
dwVol.leftVolume -=DECREMENT_AMOUNT_LARGE;
dwVol.rightVolume -=DECREMENT_AMOUNT_LARGE;
pMixer->SetVolume(&dwVol);
}
}
}
break;
}
// the recording thread is signaling back to us that there is
// a severe error. Assume the thread has exited
case WM_AUDIOTHREAD_ERROR:
{
ProcessCalibError(CALIBERR_DEVICE_ERROR, pawInfo);
PropSheet_SetCurSelByID(GetParent(hDlg), IDD_AUDIOCALIBERRWIZ);
break;
}
// The recording thread will send this message back to us
// at least once to indicate that the silence threshold was
// broken. Thus, the microphone is functional.
case WM_AUDIOTHREAD_SOUND:
{
fSoundDetected = TRUE;
break;
}
default:
return FALSE;
}
return TRUE;
}
INT_PTR APIENTRY AudioCalibWiz4( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static PROPSHEETPAGE * ps;
static PWIZCONFIG pWizConfig;
static PAUDIOWIZINFO pawInfo;
switch (message) {
case WM_INITDIALOG:
{
// Save the PROPSHEETPAGE information.
ps = (PROPSHEETPAGE *)lParam;
pWizConfig = (PWIZCONFIG)ps->lParam;
pawInfo = (PAUDIOWIZINFO)pWizConfig->pCustomData;
return (TRUE);
}
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code) {
case PSN_SETACTIVE:
{
// Initialize the controls.
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_BACK | PSWIZB_FINISH);
if (g_fSilentWizard)
{
PropSheet_PressButton(GetParent(hDlg), PSBTN_FINISH);
}
break;
}
case PSN_WIZNEXT:
// Due to bug in ComCtl32 don't allow next
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
return TRUE;
case PSN_WIZFINISH:
SaveAudioWizChanges(pawInfo);
break;
}
break;
}
return (FALSE);
}
INT_PTR APIENTRY AudioCalibErrWiz( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
PROPSHEETPAGE * ps;
PWIZCONFIG pWizConfig;
static PAUDIOWIZINFO pawInfo;
TCHAR szTemp[MAXSTRINGSIZE];
LPTSTR pszIcon;
//WORD wCmdId;
switch (message) {
case WM_INITDIALOG:
{
// Save the PROPSHEETPAGE information.
ps = (PROPSHEETPAGE *)lParam;
pWizConfig = (PWIZCONFIG)ps->lParam;
pawInfo = (PAUDIOWIZINFO)pWizConfig->pCustomData;
return (TRUE);
}
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code) {
case PSN_SETACTIVE:
// initialize the controls.
// Show the error or warning icon
pszIcon = (((pawInfo->ErrWizInfo).uType == AUDIOWIZ_WARNING) ?
IDI_ASTERISK : IDI_EXCLAMATION);
// Set the wizard bitmap to the static control
::SendDlgItemMessage( hDlg,
IDC_ERRWIZICON,
STM_SETIMAGE,
IMAGE_ICON,
(LPARAM) ::LoadIcon(NULL, pszIcon));
//set the error title
if ((pawInfo->ErrWizInfo).uErrTitleId)
{
LoadString(GetInstanceHandle(),(pawInfo->ErrWizInfo).uErrTitleId,
szTemp, MAXSTRINGSIZE);
SetDlgItemText(hDlg, IDC_ERRTITLE, szTemp);
}
if ((pawInfo->ErrWizInfo).uErrTextId)
{
//show the error text
LoadString(GetInstanceHandle(),(pawInfo->ErrWizInfo).uErrTextId,
szTemp, MAXSTRINGSIZE);
SetDlgItemText(hDlg, IDC_ERRTEXT, szTemp);
}
PropSheet_SetWizButtons(GetParent(hDlg),
(pawInfo->ErrWizInfo).uButtonOptions );
if (g_fSilentWizard)
{
// Due to bug in ComCtl32 check if button is enabled
if (!((pawInfo->ErrWizInfo).uButtonOptions & PSWIZB_FINISH))
{
PropSheet_PressButton(GetParent(hDlg), PSBTN_FINISH);
}
else
{
PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT);
}
}
break;
case PSN_WIZNEXT:
// Due to bug in ComCtl32 check if button is enabled
if (!((pawInfo->ErrWizInfo).uButtonOptions & PSWIZB_NEXT))
{
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
return TRUE;
}
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (pawInfo->ErrWizInfo).uNextWizId);
return TRUE;
case PSN_RESET:
pawInfo->uChanged = AUDIOWIZ_NOCHANGES;
break;
case PSN_WIZFINISH:
// Due to bug in ComCtl32 check if button is enabled
if (!((pawInfo->ErrWizInfo).uButtonOptions & PSWIZB_FINISH))
{
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
return TRUE;
}
SaveAudioWizChanges(pawInfo);
break;
case PSN_WIZBACK:
// Due to bug in ComCtl32 check if button is enabled
if (!((pawInfo->ErrWizInfo).uButtonOptions & PSWIZB_BACK))
{
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, -1);
return TRUE;
}
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (pawInfo->ErrWizInfo).uBackWizId);
return TRUE;
}
break;
}
return (FALSE);
}
void ProcessCalibError(UINT uCalibErr, PAUDIOWIZINFO pawInfo)
{
switch (uCalibErr)
{
case CALIBERR_CANT_SET_VOLUME:
pawInfo->ErrWizInfo.uType = AUDIOWIZ_WARNING;
pawInfo->ErrWizInfo.uErrTitleId = IDS_UNSUPPORTEDCARD;
pawInfo->ErrWizInfo.uErrTextId = IDS_NORECVOLCNTRL;
pawInfo->ErrWizInfo.uButtonOptions = PSWIZB_FINISH|PSWIZB_BACK;
pawInfo->ErrWizInfo.uNextWizId = 0;
pawInfo->ErrWizInfo.uBackWizId = IDD_AUDIOCALIBWIZ2;
break;
case CALIBERR_NO_MIXERS:
pawInfo->ErrWizInfo.uType = AUDIOWIZ_ERROR;
pawInfo->ErrWizInfo.uErrTitleId = IDS_UNSUPPORTEDCARD;
pawInfo->ErrWizInfo.uErrTextId = IDS_AUDIO_ERROR;
pawInfo->ErrWizInfo.uButtonOptions = PSWIZB_FINISH|PSWIZB_BACK;
pawInfo->ErrWizInfo.uNextWizId = 0;
pawInfo->ErrWizInfo.uBackWizId = IDD_AUDIOCALIBWIZ1;
break;
case CALIBERR_MIXER_ERROR:
pawInfo->ErrWizInfo.uType = AUDIOWIZ_ERROR;
pawInfo->ErrWizInfo.uErrTitleId = IDS_UNSUPPORTEDCARD;
pawInfo->ErrWizInfo.uErrTextId = IDS_AUDIO_ERROR;
pawInfo->ErrWizInfo.uButtonOptions = PSWIZB_FINISH|PSWIZB_BACK;
pawInfo->ErrWizInfo.uNextWizId = 0;
pawInfo->ErrWizInfo.uBackWizId = IDD_AUDIOCALIBWIZ2;
break;
case CALIBERR_CANT_OPEN_WAVE_DEV:
pawInfo->ErrWizInfo.uType = AUDIOWIZ_ERROR;
pawInfo->ErrWizInfo.uErrTitleId = IDS_CANTOPENWAVE;
pawInfo->ErrWizInfo.uErrTextId = IDS_QUITPROGRAM;
pawInfo->ErrWizInfo.uButtonOptions = PSWIZB_NEXT|PSWIZB_BACK;
pawInfo->ErrWizInfo.uNextWizId = IDD_AUDIOCALIBWIZ3;
pawInfo->ErrWizInfo.uBackWizId = IDD_AUDIOCALIBWIZ1;
break;
case CALIBERR_NO_MICROPHONE:
pawInfo->ErrWizInfo.uType = AUDIOWIZ_WARNING;
pawInfo->ErrWizInfo.uErrTitleId = IDS_NO_MICROPHONE;
pawInfo->ErrWizInfo.uErrTextId = IDS_NO_MICWARNING;
pawInfo->ErrWizInfo.uButtonOptions = PSWIZB_NEXT|PSWIZB_BACK;
pawInfo->ErrWizInfo.uNextWizId = IDD_AUDIOCALIBWIZ4;
pawInfo->ErrWizInfo.uBackWizId = IDD_AUDIOCALIBWIZ3;
break;
default:
case CALIBERR_DEVICE_ERROR:
pawInfo->ErrWizInfo.uType = AUDIOWIZ_ERROR;
pawInfo->ErrWizInfo.uErrTitleId = IDS_UNSUPPORTEDCARD;
pawInfo->ErrWizInfo.uErrTextId = IDS_AUDIO_ERROR;
pawInfo->ErrWizInfo.uButtonOptions = PSWIZB_FINISH|PSWIZB_BACK;
pawInfo->ErrWizInfo.uNextWizId = 0;
pawInfo->ErrWizInfo.uBackWizId = IDD_AUDIOCALIBWIZ2;
break;
}
}
UINT GetSoundCardCaps(UINT uWaveInDevId, UINT uWaveOutDevId, HWND hwnd)
{
UINT uSoundCardCaps;
UINT uRet;
bool bFD = false;
UINT uDSCheck;
uSoundCardCaps = SOUNDCARD_PRESENT;
if ((uRet = CheckForFullDuplex(uWaveInDevId,uWaveOutDevId)) == SOUNDCARD_NONE)
{
//failed to open wave device
//SS:Error message ??
//all applications using the wave device should be closed
}
else if (uRet == SOUNDCARD_FULLDUPLEX)
{
uSoundCardCaps = uSoundCardCaps | SOUNDCARD_FULLDUPLEX;
bFD = true;
}
if ((uRet = CheckForAgc(uWaveInDevId)) == SOUNDCARD_NONE)
{
//mixer initialization failed
//SS: Error message
}
else if (uRet == SOUNDCARD_HAVEAGC)
uSoundCardCaps = uSoundCardCaps | SOUNDCARD_HAVEAGC;
uDSCheck = DirectSoundCheck(uWaveInDevId, uWaveOutDevId, hwnd);
if (uDSCheck & DS_FULLDUPLEX)
{
uSoundCardCaps = uSoundCardCaps | SOUNDCARD_DIRECTSOUND;
}
return(uSoundCardCaps);
}
UINT CheckForFullDuplex(UINT uWaveInDevId,UINT uWaveOutDevId)
{
HWAVEIN hWaveIn=NULL;
HWAVEOUT hWaveOut=NULL;
MMRESULT mmr;
UINT uRet = SOUNDCARD_NONE;
waveInDev waveIn(uWaveInDevId);
waveOutDev waveOut(uWaveOutDevId);
mmr = waveOut.Open();
if (mmr != MMSYSERR_NOERROR)
{
return SOUNDCARD_NONE;
}
mmr = waveIn.Open();
if (mmr != MMSYSERR_NOERROR)
{
return SOUNDCARD_PRESENT;
}
return SOUNDCARD_FULLDUPLEX;
// object destructors will close devices
}
UINT GetWaveDeviceFromWaveMapper(UINT uNumWaveDevId, UINT uInOrOut)
{
HWAVE hWave=NULL;
HWAVE hWaveMapper=NULL;
WAVEFORMATEX WaveFormatEx;
MMRESULT mmr;
UINT uDeviceId = (UINT)-1;
UINT i;
WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
WaveFormatEx.nChannels = 1;
WaveFormatEx.nSamplesPerSec = 8000;
WaveFormatEx.nAvgBytesPerSec = 8000*SAMPLE_SIZE;
WaveFormatEx.nBlockAlign = SAMPLE_SIZE;
WaveFormatEx.wBitsPerSample = SAMPLE_SIZE*8;
WaveFormatEx.cbSize = 0;
if (!uInOrOut)
{
#if 0
// First, make sure that none of the devices are already open
for (i=0; i<uNumWaveDevId; i++, hWave=NULL)
{
if ((mmr = waveInOpen ((HWAVEIN *) &hWave, i, (WAVEFORMATEX *) &WaveFormatEx, 0, 0, CALLBACK_NULL)) == MMSYSERR_ALLOCATED)
goto MyExit;
else
if (mmr == WAVERR_BADFORMAT)
{
// This is probably an 8 bit board. Try again using 8 bit format
WaveFormatEx.nAvgBytesPerSec = 8000;
WaveFormatEx.nBlockAlign = 1;
WaveFormatEx.wBitsPerSample = 8;
if ((mmr = waveInOpen ((HWAVEIN *) &hWave, i, (WAVEFORMATEX *) &WaveFormatEx, 0, 0, CALLBACK_NULL)) == MMSYSERR_ALLOCATED)
goto MyExit;
}
if (hWave)
{
waveInClose((HWAVEIN)hWave);
hWave = (HWAVE)NULL;
}
}
WaveFormatEx.nAvgBytesPerSec = 8000*SAMPLE_SIZE;
WaveFormatEx.nBlockAlign = SAMPLE_SIZE;
WaveFormatEx.wBitsPerSample = SAMPLE_SIZE*8;
#endif
// Open the wave in device using wave mapper
if (mmr = waveInOpen ((HWAVEIN *) &hWaveMapper, WAVE_MAPPER, (WAVEFORMATEX *) &WaveFormatEx, 0, 0, CALLBACK_NULL))
{
if (mmr == WAVERR_BADFORMAT)
{
// This is probably an 8 bit board. Try again using 8 bit format
WaveFormatEx.nAvgBytesPerSec = 8000;
WaveFormatEx.nBlockAlign = 1;
WaveFormatEx.wBitsPerSample = 8;
if (mmr = waveInOpen ((HWAVEIN *) &hWaveMapper, WAVE_MAPPER, (WAVEFORMATEX *) &WaveFormatEx, 0, 0, CALLBACK_NULL))
goto MyExit;
}
else
goto MyExit;
}
// Now, look for the wave device that is already open
// that's the one wave mapper picked up
for (i=0; i<uNumWaveDevId; i++, hWave=NULL)
{
if ((mmr = waveInOpen ((HWAVEIN *) &hWave, i, (WAVEFORMATEX *) &WaveFormatEx, 0, 0, CALLBACK_NULL)) == MMSYSERR_ALLOCATED)
{
uDeviceId = i;
goto MyExit;
}
else
if (hWave)
{
waveInClose((HWAVEIN)hWave);
hWave = (HWAVE)NULL;
}
}
}
else
{
#if 0
// First, make sure that none of the devices are already open
for (i=0; i<uNumWaveDevId; i++, hWave=NULL)
{
if ((mmr = waveOutOpen ((HWAVEOUT *) &hWave, i, (WAVEFORMATEX *) &WaveFormatEx, 0, 0, CALLBACK_NULL)) == MMSYSERR_ALLOCATED)
goto MyExit;
else
if (mmr == WAVERR_BADFORMAT)
{
// This is probably an 8 bit board. Try again using 8 bit format
WaveFormatEx.nAvgBytesPerSec = 8000;
WaveFormatEx.nBlockAlign = 1;
WaveFormatEx.wBitsPerSample = 8;
if ((mmr = waveOutOpen ((HWAVEOUT *) &hWave, i, (WAVEFORMATEX *) &WaveFormatEx, 0, 0, CALLBACK_NULL)) == MMSYSERR_ALLOCATED)
goto MyExit;
}
if (hWave)
{
waveOutClose((HWAVEOUT)hWave);
hWave = (HWAVE)NULL;
}
}
WaveFormatEx.nAvgBytesPerSec = 8000*SAMPLE_SIZE;
WaveFormatEx.nBlockAlign = SAMPLE_SIZE;
WaveFormatEx.wBitsPerSample = SAMPLE_SIZE*8;
#endif
// Open the wave in device using wave mapper
if (mmr = waveOutOpen ((HWAVEOUT *) &hWaveMapper, WAVE_MAPPER, (WAVEFORMATEX *) &WaveFormatEx, 0, 0, CALLBACK_NULL))
{
if (mmr == WAVERR_BADFORMAT)
{
// This is probably an 8 bit board. Try again using 8 bit format
WaveFormatEx.nAvgBytesPerSec = 8000;
WaveFormatEx.nBlockAlign = 1;
WaveFormatEx.wBitsPerSample = 8;
if (mmr = waveOutOpen ((HWAVEOUT *) &hWaveMapper, WAVE_MAPPER, (WAVEFORMATEX *) &WaveFormatEx, 0, 0, CALLBACK_NULL))
goto MyExit;
}
else
goto MyExit;
}
// Now, look for the wave device that is already open
// that's the one wave mapper picked up
for (i=0; i<uNumWaveDevId; i++, hWave=NULL)
{
if ((mmr = waveOutOpen ((HWAVEOUT *) &hWave, i, (WAVEFORMATEX *) &WaveFormatEx, 0, 0, CALLBACK_NULL)) == MMSYSERR_ALLOCATED)
{
uDeviceId = i;
goto MyExit;
}
else
if (hWave)
{
waveOutClose((HWAVEOUT)hWave);
hWave = (HWAVE)NULL;
}
}
}
MyExit:
if (!uInOrOut)
{
if (hWave) waveInClose((HWAVEIN)hWave);
if (hWaveMapper) waveInClose((HWAVEIN)hWaveMapper);
}
else
{
if (hWave) waveOutClose((HWAVEOUT)hWave);
if (hWaveMapper) waveOutClose((HWAVEOUT)hWaveMapper);
}
return(uDeviceId);
}
UINT CheckForWaveDeviceSupport(UINT uWaveDevId, UINT uInOrOut)
{
MMRESULT mmr;
// querying isn't good enough, always directly open the device
// to see if it supports a given format
if (!uInOrOut)
{
waveInDev WaveIn(uWaveDevId);
if (uWaveDevId != WAVE_MAPPER)
WaveIn.AllowMapper(FALSE);
mmr = WaveIn.Open(8000,16);
if (mmr == WAVERR_BADFORMAT)
{
mmr = WaveIn.Open(8000,8);
if (mmr == WAVERR_BADFORMAT)
{
mmr = WaveIn.Open(11025, 16);
if (mmr == WAVERR_BADFORMAT)
{
mmr = WaveIn.Open(22050, 16);
if (mmr == WAVERR_BADFORMAT)
{
mmr = WaveIn.Open(44100, 16);
}
}
}
}
}
else // waveOut
{
waveOutDev WaveOut(uWaveDevId);
if (uWaveDevId != WAVE_MAPPER)
WaveOut.AllowMapper(FALSE);
mmr = WaveOut.Open(8000,16);
if (mmr == WAVERR_BADFORMAT)
{
mmr = WaveOut.Open(8000,8);
if (mmr == WAVERR_BADFORMAT)
{
mmr = WaveOut.Open(11025, 16);
if (mmr == WAVERR_BADFORMAT)
{
mmr = WaveOut.Open(22050, 16);
if (mmr == WAVERR_BADFORMAT)
{
mmr = WaveOut.Open(44100, 16);
}
}
}
}
}
// go ahead and allow the device to pass if it's in use
if ((mmr == MMSYSERR_ALLOCATED) || (mmr == MMSYSERR_NOERROR))
return TRUE;
else
return FALSE;
// destructors for waveOut and waveIn will call Close()
}
UINT CheckForAgc(UINT uWaveInDevId)
{
CMixerDevice *pMixDev;
UINT uRet = SOUNDCARD_NONE;
BOOL fAgc;
pMixDev = CMixerDevice::GetMixerForWaveDevice(
NULL,
uWaveInDevId,
MIXER_OBJECTF_WAVEIN);
//SS: we need to correlate the uDevId to mixer id
if (pMixDev)
{
uRet = SOUNDCARD_PRESENT;
if (pMixDev->GetAGC(&fAgc))
uRet = SOUNDCARD_HAVEAGC;
delete pMixDev;
}
return (uRet);
}
// This function is here to allow the help system to invoke
// the wizard via rundll32
void WINAPI RunAudioWiz(HWND hwndStub, HINSTANCE hInst, LPSTR lpszCmdLine, int CmdShow )
{
IntCreateAudioCalibWizard(hwndStub, RUNDUE_USERINVOKED, WAVE_MAPPER,
NULL, READFROM_REGISTRY);
}
static void PaintVUMeter (HWND hwnd, DWORD dwVolume)
{
COLORREF RedColor = RGB(255,0,0);
COLORREF YellowColor = RGB(255,255,0);
COLORREF GreenColor = RGB(0,255,0);
static DWORD dwPrevVolume=0;
HBRUSH hRedBrush, hOldBrush, hYellowBrush, hGreenBrush;
HBRUSH hBlackBrush, hCurrentBrush;
HDC hdc;
RECT rect, rectDraw, invalidRect;
DWORD width, boxwidth, startPos=0;
DWORD nRect=0, yellowPos, redPos;
LONG lDiff, lDiffTrunc = (MAX_VOLUME_NORMALIZED/2);
// rect gets filled with the dimensions we are drawing into
if (FALSE == GetClientRect (hwnd, &rect))
{
return;
}
// we expect volume to be between 0-32768
if (dwVolume > MAX_VOLUME)
dwVolume = MAX_VOLUME;
// reduce from 15 bits to 8 // 0 <= dwVolume <= 256
dwVolume = dwVolume / 128;
// run it through the "normalizing" table. Special case: F(256)==256
if (dwVolume < MAX_VOLUME_NORMALIZED)
dwVolume = g_VUTable[dwVolume];
// visual aesthetic #1 - get rid of VU jerkiness
// if the volume changed by more than 1/2 since the last update
// only move the meter up half way
// exception: if volume is explicitly 0, then skip
lDiff = (LONG)dwVolume - (LONG)dwPrevVolume;
if ((dwVolume != 0) && ( (lDiff > (MAX_VOLUME_NORMALIZED/2))
|| (lDiff < -(MAX_VOLUME_NORMALIZED/2)) ))
dwVolume = dwVolume - (lDiff/2);
// minus 2 for the ending borders
// if Framed rectangles are used, drop the -2
boxwidth = rect.right - rect.left - 2;
width = (boxwidth * dwVolume)/ MAX_VOLUME_NORMALIZED;
// visual aesthetic #2 - to get rid of flicker
// if volume has increased since last time
// then there is no need to invalidate/update anything
// otherwise only clear everything to the right of the
// calculated "width". +/- 1 so the border doesn't get erased
if ((dwVolume < dwPrevVolume) || (dwVolume == 0))
{
invalidRect.left = rect.left + width - RECTANGLE_WIDTH;
if (invalidRect.left < rect.left)
invalidRect.left = rect.left;
invalidRect.right = rect.right - 1;
invalidRect.top = rect.top + 1;
invalidRect.bottom = rect.bottom - 1;
// these calls together erase the invalid region
InvalidateRect (hwnd, &invalidRect, TRUE);
UpdateWindow (hwnd);
}
hdc = GetDC (hwnd) ;
hRedBrush = CreateSolidBrush (RedColor) ;
hGreenBrush = CreateSolidBrush(GreenColor);
hYellowBrush = CreateSolidBrush(YellowColor);
hBlackBrush = (HBRUSH)GetStockObject(BLACK_BRUSH);
hOldBrush = (HBRUSH) SelectObject (hdc, hBlackBrush);
// draw the main
FrameRect(hdc, &rect, hBlackBrush);
yellowPos = boxwidth/2;
redPos = (boxwidth*3)/4;
SelectObject(hdc, hGreenBrush);
hCurrentBrush = hGreenBrush;
rectDraw.top = rect.top +1;
rectDraw.bottom = rect.bottom -1;
while ((startPos+RECTANGLE_WIDTH) < width)
{
rectDraw.left = rect.left + (RECTANGLE_WIDTH+RECTANGLE_LEADING)*nRect + 1;
rectDraw.right = rectDraw.left + RECTANGLE_WIDTH;
nRect++;
FillRect(hdc, &rectDraw, hCurrentBrush);
startPos += RECTANGLE_WIDTH+RECTANGLE_LEADING;
if (startPos > redPos)
hCurrentBrush = hRedBrush;
else if (startPos > yellowPos)
hCurrentBrush = hYellowBrush;
}
SelectObject (hdc, hOldBrush);
DeleteObject(hRedBrush);
DeleteObject(hYellowBrush);
DeleteObject(hGreenBrush);
ReleaseDC (hwnd, hdc) ;
dwPrevVolume = dwVolume;
return;
}
static DWORD ComputePower(SHORT *wBuffer, DWORD dwNumSamples, AUDIO_POWER *pAudioPower)
{
DWORD dwIndex, dwTotal;
LONG dcComponent;
SHORT val;
DWORD dwVal;
ZeroMemory(pAudioPower, sizeof(AUDIO_POWER));
pAudioPower->dwMin = MAX_VOLUME; // 32768
dwTotal = 0;
dcComponent = 0;
for (dwIndex = 0; dwIndex < dwNumSamples; dwIndex++)
{
val = wBuffer[dwIndex];
dwVal = SHABS(val);
dwTotal += dwVal;
dcComponent += val;
if (dwVal > pAudioPower->dwMax)
pAudioPower->dwMax = dwVal;
if (dwVal < pAudioPower->dwMin)
pAudioPower->dwMin = dwVal;
}
pAudioPower->lDcComponent = dcComponent / (LONG)dwNumSamples;
pAudioPower->dwAvg = dwTotal / dwNumSamples;
return pAudioPower->dwAvg;
}
// given a pointer to a wave In device, and a list of WAVEHDR structs
// each wave header is prepared (if needed) and fed to wavein
MMRESULT PostFreeBuffers(waveInDev *pWaveInDev, WAVEHDR *aWaveHdrs, int numBuffers, DWORD *pdwCount)
{
int nIndex;
MMRESULT mmr=MMSYSERR_NOERROR;
bool bNeedToPrepare;
// first time through - the dwUser field of all wave headers
// will be zero. Just look a the first header in the list
// to figure this out.
if (numBuffers < 1)
{
ASSERT(false);
return MMSYSERR_ERROR;
}
bNeedToPrepare = (aWaveHdrs[0].dwUser == 0);
if (bNeedToPrepare)
{
for (nIndex = 0; nIndex < numBuffers; nIndex++)
{
mmr = pWaveInDev->PrepareHeader(&aWaveHdrs[nIndex]);
if (mmr != MMSYSERR_NOERROR)
{
return mmr;
}
// so that the code below works ok, just mark the done
// bit on the wave headers
aWaveHdrs[nIndex].dwFlags |= WHDR_DONE;
}
}
// for each wave header passed in that has the "done" bit set
// repost to wavein
for (nIndex = 0; nIndex < numBuffers; nIndex++)
{
if (aWaveHdrs[nIndex].dwFlags & WHDR_DONE)
{
aWaveHdrs[nIndex].dwFlags &= ~(WHDR_DONE | WHDR_INQUEUE);
aWaveHdrs[nIndex].dwFlags |= WHDR_PREPARED;
*pdwCount = (*pdwCount) + 1;
if (*pdwCount == 0)
*pdwCount++;
aWaveHdrs[nIndex].dwUser = *pdwCount;
mmr = pWaveInDev->Record(&aWaveHdrs[nIndex]);
}
}
return mmr;
}
// scan the array of wave headers for "done" buffers
// return the most recently posted buffer (if any)
BYTE *GetLatestBuffer(WAVEHDR *aWaveHdrs, int numBuffers)
{
DWORD_PTR dwUserHigh=0;
int nIndexHigh=0;
int nIndex;
for (nIndex = 0; nIndex < numBuffers; nIndex++)
{
if (aWaveHdrs[nIndex].dwFlags & WHDR_DONE)
{
if (aWaveHdrs[nIndex].dwUser > dwUserHigh)
{
dwUserHigh = aWaveHdrs[nIndex].dwUser;
nIndexHigh = nIndex;
}
}
}
if (dwUserHigh > 0)
{
return (BYTE*)(aWaveHdrs[nIndexHigh].lpData);
}
return NULL;
}
static DWORD CALLBACK CalibrateTalking(PVOID pVoid)
{
const int SIZE_WAVEIN_BUFFER = 1600; // 100ms @ 8khz, 16-bit
const int NUM_WAVEIN_BUFFERS = 5;
WaveBufferList waveList(NUM_WAVEIN_BUFFERS, SIZE_WAVEIN_BUFFER);
WAVEHDR aWaveHdrs[NUM_WAVEIN_BUFFERS];
HWND hVUMeter, hDlg;
HANDLE hEvent;
MMRESULT mmr;
DWORD dwPow, dwRet, dwExitCode=0;
AUDIO_POWER audioPower;
CALIB_DISPLAY *pCalibDisplay;
TCHAR szText[ATW_MSG_LENGTH];
BOOL fOpened = TRUE;
BOOL fSoundDetected = FALSE;
int nRecordCount = 0, nIndex;
DWORD dwBufferIndex = 1;
SHORT *buffer;
HANDLE hEventRecord = CreateEvent(NULL, TRUE, FALSE, NULL);
waveInDev waveIn(((CALIB_DISPLAY *)pVoid)->uWaveInDevId, hEventRecord);
pCalibDisplay = (CALIB_DISPLAY *)pVoid;
hVUMeter = pCalibDisplay->hVUMeter;
hDlg = pCalibDisplay->hDlg;
hEvent = pCalibDisplay->hEvent;
ASSERT(hEvent);
mmr = waveIn.Open(8000,16);
if (mmr == MMSYSERR_ALLOCATED)
{
FLoadString(IDS_RECORD_ERROR, szText, CCHMAX(szText));
SetDlgItemText(hDlg, IDC_ATW_RECORD_ERROR, szText);
fOpened = FALSE;
}
else if (mmr != MMSYSERR_NOERROR)
{
PostMessage(hDlg, WM_AUDIOTHREAD_ERROR, 0, 0);
CloseHandle(hEvent);
CloseHandle(hEventRecord);
return -1;
}
else
{
SetDlgItemText(hDlg, IDC_ATW_RECORD_ERROR, "");
ResetEvent(hEventRecord);
}
// initialize the array of wavehdrs
for (nIndex=0; nIndex < NUM_WAVEIN_BUFFERS; nIndex++)
{
ZeroMemory(&aWaveHdrs[nIndex], sizeof(WAVEHDR));
aWaveHdrs[nIndex].lpData = (LPSTR)(waveList.GetBuffer(nIndex));
aWaveHdrs[nIndex].dwBufferLength = SIZE_WAVEIN_BUFFER;
}
while (1)
{
// is it time to exit ?
dwRet = WaitForSingleObject(hEvent, 0);
if (dwRet == WAIT_OBJECT_0)
{
dwExitCode = 0;
break;
}
// if we still haven't opened the device
// keep trying
if (fOpened == FALSE)
{
mmr = waveIn.Open(8000,16);
if (mmr == MMSYSERR_ALLOCATED)
{
PaintVUMeter(hVUMeter, 0); // draw a blank rectangle
Sleep(500);
continue;
}
if (mmr != MMSYSERR_NOERROR)
{
PostMessage(hDlg, WM_AUDIOTHREAD_ERROR, 0, 0);
dwExitCode = (DWORD)(-1);
break;
}
// mmr == noerror
SetDlgItemText(hDlg, IDC_ATW_RECORD_ERROR, TEXT(""));
fOpened = TRUE;
ResetEvent(hEventRecord);
}
// wave device is open at this point
mmr = PostFreeBuffers(&waveIn, aWaveHdrs, NUM_WAVEIN_BUFFERS, &dwBufferIndex);
if (mmr != MMSYSERR_NOERROR)
{
PostMessage(hDlg, WM_AUDIOTHREAD_ERROR, 0, 0);
dwExitCode = (DWORD) -1;
break;
}
WaitForSingleObject(hEventRecord, 5000);
ResetEvent(hEventRecord);
buffer = (SHORT*)GetLatestBuffer(aWaveHdrs, NUM_WAVEIN_BUFFERS);
if (buffer)
{
nRecordCount++;
dwPow = ComputePower(buffer, SIZE_WAVEIN_BUFFER/2, &audioPower);
// don't update the meter for the first 200ms.
// "noise" from opening the soundcard tends to show up
if (nRecordCount > 2)
{
PaintVUMeter(hVUMeter, audioPower.dwMax);
// signal back to the calling window (if it hasn't already),
// that the silence threshold was broken
if ((fSoundDetected == FALSE) && (audioPower.dwMax > SILENCE_THRESHOLD))
{
PostMessage(hDlg, WM_AUDIOTHREAD_SOUND, 0,0);
fSoundDetected = TRUE;
}
// check for clipping, post message back to parent thread/window
// so that it will adjust the volume
if (audioPower.dwMax > CLIPPINGVOL)
{
// should we use send message instead ?
PostMessage(hDlg, WM_AUDIO_CLIPPING,0,0);
}
}
else
PaintVUMeter(hVUMeter, 0);
}
}
waveIn.Reset();
for (nIndex = 0; nIndex < NUM_WAVEIN_BUFFERS; nIndex++)
{
waveIn.UnPrepareHeader(&aWaveHdrs[nIndex]);
}
waveIn.Close();
CloseHandle(hEvent);
CloseHandle(hEventRecord);
TRACE_OUT(("ATW: Recording Thread Exit\r\n"));
return dwExitCode;
}
// Turns on AGC if needed
// parameter is whatever pawInfo->iSetAgc is.
// but it's probably been hardcoded to be READFROM_REGISTRY
static BOOL StartAGC(CMixerDevice *pMixer, BOOL iSetAgc, UINT uSoundCardCaps)
{
BOOL bSet, bRet;
if (iSetAgc == READFROM_REGISTRY)
{
if (DOESSOUNDCARDHAVEAGC(uSoundCardCaps))
{
RegEntry re(AUDIO_KEY, HKEY_CURRENT_USER);
bSet = (BOOL)( re.GetNumber(REGVAL_AUTOGAIN,AUTOGAIN_ENABLED) == AUTOGAIN_ENABLED );
}
else
{
bSet = FALSE;
}
}
else
{
bSet = (iSetAgc != 0);
}
bRet = pMixer->SetAGC(bSet);
if (bSet == FALSE)
return FALSE;
return bRet;
}