语音输入的音量控制比较麻烦,写此文章以增强记忆。
// 打开mixer MMRESULT rc; HMIXER hMixer; UINT mixerID; rc = mixerGetID((HMIXEROBJ)hWaveIn,&mixerID,MIXER_OBJECTF_HWAVEIN); rc = mixerOpen(&hMixer,mixerID,(DWORD)this->m_hWnd,0,CALLBACK_WINDOW); if (rc != MMSYSERR_NOERROR) { MessageBox(_T("mixerOpen Error!")); return; } // mixerGetLineInfo MIXERLINE mixerLine; ZeroMemory(&mixerLine,sizeof(MIXERLINE)); mixerLine.cbStruct = sizeof(MIXERLINE); mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN; rc = mixerGetLineInfo((HMIXEROBJ)hMixer, &mixerLine,MIXER_GETLINEINFOF_COMPONENTTYPE); if (rc != MMSYSERR_NOERROR) { MessageBox(_T("mixerGetLineInfo Error!")); return; } // 获取麦克风的LineID DWORD dwConnections = mixerLine.cConnections; DWORD dwLineID = -1; for (DWORD i=0; i<dwConnections; i++) { mixerLine.dwSource = i; rc = mixerGetLineInfo((HMIXEROBJ)hMixer,&mixerLine,MIXER_OBJECTF_HMIXER|MIXER_GETLINEINFOF_SOURCE); if ( rc == MMSYSERR_NOERROR ) { if (mixerLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) { dwLineID = mixerLine.dwLineID; break; } } } if (dwLineID == -1) { return; } // mixerGetLineControls MIXERCONTROL mxControl; MIXERLINECONTROLS mxLineControls; ZeroMemory(&mxLineControls,sizeof(mxLineControls)); mxLineControls.cbStruct = sizeof(mxLineControls); mxLineControls.dwLineID = dwLineID; mxLineControls.dwControlType= MIXERCONTROL_CONTROLTYPE_VOLUME; mxLineControls.cControls = 1; mxLineControls.cbmxctrl = sizeof(mxControl); mxLineControls.pamxctrl = &mxControl; ZeroMemory(&mxControl,sizeof(mxControl)); mxControl.cbStruct = sizeof(mxControl); rc = mixerGetLineControls((HMIXEROBJ)hMixer,&mxLineControls,MIXER_GETLINECONTROLSF_ONEBYTYPE); if (rc != MMSYSERR_NOERROR) { MessageBox(_T("mixerGetLineControls Error!")); return; } // get volume MIXERCONTROLDETAILS mxControlDetails; MIXERCONTROLDETAILS_SIGNED volStruct; ZeroMemory(&mxControlDetails,sizeof(mxControlDetails)); mxControlDetails.cbStruct = sizeof(mxControlDetails); mxControlDetails.dwControlID= mxControl.dwControlID; mxControlDetails.cChannels = 1; mxControlDetails.cbDetails = sizeof(volStruct); mxControlDetails.paDetails = &volStruct; rc = mixerGetControlDetails((HMIXEROBJ)hMixer,&mxControlDetails,MIXER_GETCONTROLDETAILSF_VALUE); if (rc != MMSYSERR_NOERROR) { MessageBox(_T("mixerGetControlDetails Error!")); return; } long step = (mxControl.Bounds.lMaximum - mxControl.Bounds.lMinimum) / 100; int index = (volStruct.lValue - mxControl.Bounds.lMinimum) / step; //set volume volStruct.lValue = 65535; ZeroMemory(&mxControlDetails,sizeof(mxControlDetails)); mxControlDetails.cbStruct = sizeof(mxControlDetails); mxControlDetails.dwControlID= mxControl.dwControlID; mxControlDetails.cChannels = 1; mxControlDetails.cbDetails = sizeof(volStruct); mxControlDetails.paDetails = &volStruct; rc = mixerSetControlDetails((HMIXEROBJ)hMixer,&mxControlDetails,MIXER_GETCONTROLDETAILSF_VALUE); if (rc != MMSYSERR_NOERROR) { MessageBox(_T("mixerGetControlDetails Error!")); return; }
第四行,获取hWaveIn句柄的代码如下:
// 检查设备 if ( ! waveInGetNumDevs() ) { MessageBeep(MB_ICONEXCLAMATION); MessageBox(_T("找不到语音输入设备!")); return FALSE; } // format of voice: 16 bits,11.025KHz,Mono audio WAVEFORMATEX format; format.cbSize = 0; format.nAvgBytesPerSec = 11025; //数据率 format.nBlockAlign = 1; //每样点的字节数 format.nChannels = 1; //单声道,Mono/立体声 format.nSamplesPerSec = 11025; //采样率 format.wBitsPerSample = 8; //采样精度 format.wFormatTag = WAVE_FORMAT_PCM; // 打开语音输入设备 if ( (result=waveInOpen(&hWaveIn, WAVE_MAPPER,&format,(DWORD)hwnd, 0, CALLBACK_WINDOW)) != MMSYSERR_NOERROR ) { TCHAR szErrorText[100] = {0}; if (waveInGetErrorText(result,szErrorText,sizeof(szErrorText)) == MMSYSERR_NOERROR) { MessageBeep(MB_ICONEXCLAMATION); MessageBox(szErrorText,_T("WaveIn Open Error!"),MB_ICONEXCLAMATION|MB_OK); } else { MessageBeep(MB_ICONEXCLAMATION); MessageBox(_T("Unknown Error"),_T("WaveIn Open Error!"),MB_ICONEXCLAMATION|MB_OK); } hWaveIn = NULL; return; }
当然使用完了别忘了关闭:
waveInReset(hWaveIn); waveInClose(hWaveIn); hWaveIn = NULL;
当然,一般情况下,语音输入设备的ID号是0,所以也可以直接用以下代码打开mixer设备:
rc = mixerOpen(&hmx,0,(DWORD)this->m_hWnd,0,CALLBACK_WINDOW);
mixerOpen函数中使用CALLBACK_WINDOW的目的是在改变了系统输入音量后能够及时的在窗口中更新。其对应的Windows消息是MM_MIXM_CONTROL_CHANGE.
//添加响应消息宏 ON_MESSAGE(MM_MIXM_CONTROL_CHANGE,OnVolumeChanged) LRESULT CSendVoiceDlg::OnVolumeChanged(WPARAM wParam, LPARAM lParam) { // 此消息有两个参数 // 第一个参数WPARAM, 表示MIXER设备句柄,即上面代码中的hMixer // 第二个参数LPARAM, 表示MIXERCONTROL结构中的dwControlID成员。 return 0; } //下面是一个例子 LRESULT CSendVoiceDlg::OnVolumeChanged(WPARAM wParam, LPARAM lParam) { CSliderCtrl* pSlider = (CSliderCtrl*)GetDlgItem(IDC_SLIDER1); HMIXER hMixer = (HMIXER)wParam; DWORD dwControlID = (DWORD)lParam; MIXERCONTROLDETAILS mxControlDetails; MIXERCONTROLDETAILS_SIGNED volStruct; ZeroMemory(&mxControlDetails,sizeof(mxControlDetails)); mxControlDetails.cbStruct = sizeof(mxControlDetails); mxControlDetails.dwControlID= dwControlID; mxControlDetails.cChannels = 1; mxControlDetails.cbDetails = sizeof(volStruct); mxControlDetails.paDetails = &volStruct; MMRESULT rc = mixerGetControlDetails((HMIXEROBJ)hMixer,&mxControlDetails,MIXER_GETCONTROLDETAILSF_VALUE); if (rc != MMSYSERR_NOERROR) { MessageBox(_T("mixerGetControlDetails Error!")); return 0; } // long step = (mxControl.Bounds.lMaximum - mxControl.Bounds.lMinimum) / 100; // int index = (volStruct.lValue - mxControl.Bounds.lMinimum) / step; pSlider->SetPos(volStruct.lValue); return 0; }