// File: calib.cpp #include "precomp.h" #include "resource.h" #include "WaveDev.h" #include "dstest.h" #include "avdefs.h" #include #include #include #include #include // 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; iGetAGC(&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; }