语音输入的音量控制比较麻烦,写此文章以增强记忆。
// 打开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;
}