DSP

音频混音接口调节音量及设置静音

2019-07-13 17:32发布

本文主要介绍如何使用混音器Mixer API函数实现系统音量调节,以及设置静音。 1.混音器的作用及结构 1.1混音器的作用   声卡(音频卡)是计算机进行声音处理的适配器,具有三个基本功能:   (1)音乐合成发音功能   (2)混音器(Mixer)功能和数字声音效果处理器(DSP)功能   (3)模拟声音信号的输入和输出功能   混音器的作用是将来自音乐合成器、CD-ROM、话筒输入(MIC)等不同来源的声音组合在一起再输出。 1.2混音器的结构   混音器由多个目的单元(Destination)组成,如回放(Playback)、录音(Recording)、语音命令(Voice Command)等等。   目的单元(Destination)又由多个连接设备(Connections)组成,如回放下有CD Audio、MIDI、Wave等等。   而每条连接设备又联系着一个或多个控制器(Control。   控制器是混音器的关键,如音量控制器(Volume Control)、静音控制器(Mute Control、仪表控制器(Meter Control)等等。   2. Mixer API函数 2.1获取混合器设备的数量 函数原型: WINMMAPI UINT WINAPI mixerGetNumDevs(void); 函数说明:该函数用于获取系统中混合器设备的数量。 2.2打开混合器设备 函数原型: WINMMAPI MMRESULT WINAPI mixerOpen(LPHMIXER phmx, UINT uMxId, DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen); 函数说明:该函数用于打开混合器设备。 参数说明: 参数phmx是一个指向设备句柄的指针,当该函数调用成功,该指针就指向所打开的混合器设备句柄。 参数uMxId是混合器的标识号,用于指定要打开的混合器设备。 参数dwCallback是在混合器设备发生变化时,接收通知消息的窗口句柄。 参数dwInstance是传给回调函数的用户实例数据。 参数fdwOpen表示打开设备的标志。 2.3获取混合器设备指定音频线路的信息 函数原型: WINMMAPI MMRESULT WINAPI mixerGetLineInfo(HMIXEROBJ hmxobj, LPMIXERLINE pmxl, DWORD fdwInfo); 函数说明:该函数用于获取混合器设备指定音频线路的信息。 参数说明: 参数hmxobj表示混合器设备对象句柄。 参数pmxl是MIXERLINE结构体对象,用于填充指定音频线路的相关信息。 参数fdwInfo用于指定得到哪些音频线路信息。 2.4获取与音频线路相关的控制 函数原型: WINMMAPI MMRESULT WINAPI mixerGetLineControls(HMIXEROBJ hmxobj, LPMIXERLINECONTROLS pmxlc, DWORD fdwControls); 函数说明:该函数用于获取与音频线路相关的控制。 参数说明: 参数hmxobj表示混合器设备对象句柄。 参数pmxlc是MIXERLINECONTROLS结构体对象,用于填充控制信息。 参数fdwControls用于指定得到哪些线路的控制。 2.5获取指定控制器的详细信息 函数原型: WINMMAPI MMRESULT WINAPI mixerGetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails); 函数说明:该函数用于获取指定控制器的详细信息 参数说明: 参数hmxobj表示混合器设备对象句柄。 参数pmxcd是MIXERCONTROLDETAILS结构体对象,包含具体控制信息。 参数fdwDetails用于指定要获取的信息。 2.6设置指定控制器的详细信息 函数原型: WINMMAPI MMRESULT WINAPI mixerSetControlDetails(HMIXEROBJ hmxobj, LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails); 函数说明:该函数用于设置指定控制器的详细信息 参数说明: 参数hmxobj表示混合器设备对象句柄。 参数pmxcd是MIXERCONTROLDETAILS结构体对象,包含具体控制信息。 参数fdwDetails用于指定要设置的信息。 2.7关闭混合器设备 函数原型: WINMMAPI MMRESULT WINAPI mixerClose(HMIXER hmx); 函数说明:该函数用于关闭混合器设备 参数说明: 参数hmx表示混合器设备对象句柄。   3.使用实例   下面通过一个简单的实例来演示如何使用上述的Mixer API函数实现系统音量调节,以及设置静音。实例运行效果如图1所示。  图1 FV扫频软件_V1.0主界面   该实例是我正在做的一个扫频软件,其中的音量调节部分实现了以下功能:   (1)通过拖动滑块,能够调节系统音量的大小,并实时显示当前音量值。   (2)通过勾选/取消勾选“静音”复选框,能够设置系统是/否静音。   (3)调节系统音量或设置静音时,程序也能够同步进行响应。 3.1加载头文件和动态链接库   在使用Mixer API函数编程时,我们需要在工程中包含头文件mmsystem.h,并加载动态链接库Winmm.lib。具体方法如下:   [cpp] view plain copy
  1. #include                         //包含音频操作头文件mmsystem.h  
  2. #pragma comment(lib, "Winmm.lib")            //添加动态链接库Winmm.lib  
3.2获取混合器设备的数量   通过使用Mixer API函数mixerGetNumDevs(),我们可以获取系统中混合器设备的数量。具体方法如下:   [cpp] view plain copy
  1. /* 
  2.  * 函数功能 : 获取混合器设备的数量 
  3.  * 备    注 :  
  4.  * 作    者 : 博客园 依旧淡然 
  5.  */  
  6. bool CMixerDAO::GetMixerDevsNumber()  
  7. {  
  8.     m_nMixerDevsNumber = ::mixerGetNumDevs();  
  9.     if(m_nMixerDevsNumber == 0)  
  10.     {  
  11.         return false;  
  12.     }  
  13.     return true;  
  14. }  
  其中,成员变量m_nMixerDevsNumber用于存储获取到的系统中混合器设备的数量,若不存在混合器设备,后续对混合器的操作均不可进行。 3.3打开混合器设备   通过使用Mixer API函数mixerOpen (),我们可以打开指定的混合器设备。具体方法如下:   [cpp] view plain copy
  1. /* 
  2.  * 函数功能 : 打开混合器设备 
  3.  * 备    注 : 参数hWnd表示窗口句柄 
  4.  *              参数nMixerID表示混合器标识号(取值范围0到混合器设备总个数-1) 
  5.  * 作    者 : 博客园 依旧淡然 
  6.  */  
  7. bool CMixerDAO::OpenMixer(HWND hWnd, UINT nMixerID)  
  8. {  
  9.     ASSERT(nMixerID < m_nMixerDevsNumber-1);  
  10.     MMRESULT mmResult = ::mixerOpen(&m_hMixer, nMixerID, (DWORD)hWnd, NULL,  
  11.         MIXER_OBJECTF_MIXER | CALLBACK_WINDOW);  
  12.     if(mmResult != MMSYSERR_NOERROR)  
  13.     {  
  14.         return false;  
  15.     }  
  16.     return true;  
  17. }  
  其中,成员变量m_hMixer用于存储混合器设备句柄。 3.4获取混合器设备指定音频线路的信息   通过使用Mixer API函数mixerGetLineInfo (),我们可以获取混合器设备指定音频线路的信息。具体方法如下:   [cpp] view plain copy
  1. /* 
  2.  * 函数功能 : 获取混合器音频线路信息 
  3.  * 备    注 :  
  4.  * 作    者 : 博客园 依旧淡然 
  5.  */  
  6. bool CMixerDAO::GetMixerLineInfo()  
  7. {  
  8.     ASSERT(m_hMixer != NULL);  
  9.     m_tMixerLine.cbStruct = sizeof(MIXERLINE);  
  10.     m_tMixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;  
  11.     MMRESULT mmResult = ::mixerGetLineInfo((HMIXEROBJ)m_hMixer, &m_tMixerLine,   
  12.         MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE);        //指定线路类型  
  13.     if(mmResult != MMSYSERR_NOERROR)  
  14.     {  
  15.         return false;  
  16.     }  
  17.     return true;  
  18. }  
3.5获取与音频线路相关的控制   通过使用Mixer API函数mixerGetLineControls (),我们可以获取与音频线路相关的控制。例如要获得音量控制器,可以采用如下方法:   [cpp] view plain copy
  1. /* 
  2.  * 函数功能 : 获取混合器音频线路控件(音量) 
  3.  * 备    注 :  
  4.  * 作    者 : 博客园 依旧淡然 
  5.  */  
  6. bool CMixerDAO::GetMixerLineControlsOfVolume()  
  7. {  
  8.     ASSERT(m_hMixer != NULL);  
  9.     m_tMixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);  
  10.     m_tMixerLineControls.dwLineID = m_tMixerLine.dwLineID;  
  11.     m_tMixerLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;        //音量  
  12.     m_tMixerLineControls.cControls = 1;  
  13.     m_tMixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);  
  14.     m_tMixerLineControls.pamxctrl = &m_tMixerControlOfVolume;  
  15.     MMRESULT mmResult = ::mixerGetLineControls((HMIXEROBJ)m_hMixer, &m_tMixerLineControls,  
  16.         MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE);  
  17.     if(mmResult != MMSYSERR_NOERROR)  
  18.     {  
  19.         return false;  
  20.     }  
  21.     return true;  
  22. }  
  其中,m_tMixerLineControls.dwControlType用于指定要获取哪种控制器,若为MIXERCONTROL_CONTROLTYPE_VOLUME,则表明是音量控制器m_tMixerControlOfVolume;若为MIXERCONTROL_CONTROLTYPE_MUTE,则表明是静音控制器m_tMixerControlOfMute。 3.6获取指定控制器的详细信息   通过使用Mixer API函数mixerGetControlDetails (),我们可以获取指定控制器的详细信息。例如要获取当前的音量值,可以采用如下方法:   [cpp] view plain copy
  1. /* 
  2.  * 函数功能 : 获取混合器控件详细信息(音量) 
  3.  * 备    注 : 参数nCurrentVolume表示当前的音量值 
  4.  * 作    者 : 博客园 依旧淡然 
  5.  */  
  6. bool CMixerDAO::GetMixerControlDetails(DWORD& nCurrentVolume)  
  7. {  
  8.     ASSERT(m_hMixer != NULL);  
  9.     MIXERCONTROLDETAILS_UNSIGNED tMixerControlDetailsUnsigned;  
  10.     m_tMixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);  
  11.     m_tMixerControlDetails.dwControlID = m_tMixerControlOfVolume.dwControlID;  
  12.     m_tMixerControlDetails.cChannels = 1;  
  13.     m_tMixerControlDetails.cMultipleItems = 0;  
  14.     m_tMixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);  
  15.     m_tMixerControlDetails.paDetails = &tMixerControlDetailsUnsigned;  
  16.     MMRESULT mmResult = ::mixerGetControlDetails((HMIXEROBJ)m_hMixer, &m_tMixerControlDetails,  
  17.         MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE);  
  18.     if(mmResult != MMSYSERR_NOERROR)  
  19.     {  
  20.         return false;  
  21.     }  
  22.     nCurrentVolume = tMixerControlDetailsUnsigned.dwValue;            //获取当前的音量值  
  23.     return true;  
  24. }  
  获取系统静音状态的方法与上述获取当前系统音量值的方法类似,但是需要将m_tMixerControlDetails.dwControlID指定为m_tMixerControlOfMute.dwControlID。   3.7设置指定控制器的详细信息     通过使用Mixer API函数mixerSetControlDetails (),我们可以设置指定控制器的详细信息。例如要设置音量值,可以采用如下方法:   [cpp] view plain copy
  1. /* 
  2.  * 函数功能 : 设置混合器控件详细信息(音量) 
  3.  * 备    注 : 参数nNewVolume表示新的音量值 
  4.  * 作    者 : 博客园 依旧淡然 
  5.  */  
  6. bool CMixerDAO::SetMixerControlDetails(DWORD nNewVolume)  
  7. {  
  8.     ASSERT(m_hMixer != NULL);  
  9.     ASSERT(nNewVolume >= m_tMixerControlOfVolume.Bounds.dwMinimum);            //输入参数范围验证  
  10.     ASSERT(nNewVolume <= m_tMixerControlOfVolume.Bounds.dwMaximum);  
  11.     MIXERCONTROLDETAILS_UNSIGNED tMixerControlDetailsUnsigned = {nNewVolume};  
  12.     m_tMixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);  
  13.     m_tMixerControlDetails.dwControlID = m_tMixerControlOfVolume.dwControlID;  
  14.     m_tMixerControlDetails.cChannels = 1;  
  15.     m_tMixerControlDetails.cMultipleItems = 0;  
  16.     m_tMixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);  
  17.     m_tMixerControlDetails.paDetails = &tMixerControlDetailsUnsigned;  
  18.     MMRESULT mmResult = ::mixerSetControlDetails((HMIXEROBJ)m_hMixer, &m_tMixerControlDetails,  
  19.         MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);  
  20.     if(mmResult != MMSYSERR_NOERROR)  
  21.     {  
  22.         return false;  
  23.     }  
  24.     return true;  
  25. }  
  设置系统静音状态的方法与上述设置当前系统音量值的方法类似,但是需要将m_tMixerControlDetails.dwControlID指定为m_tMixerControlOfMute.dwControlID。 3.8关闭混合器设备   通过使用Mixer API函数mixerClose (),可以关闭混合器设备。具体方法如下:   [cpp] view plain copy
  1. /* 
  2.  * 函数功能 : 关闭混合器设备 
  3.  * 备    注 :  
  4.  * 作    者 : 博客园 依旧淡然 
  5.  */  
  6. bool CMixerDAO::CloseMixer()  
  7. {  
  8.     ASSERT(m_hMixer != NULL);  
  9.     MMRESULT mmResult = ::mixerClose(m_hMixer);  
  10.     if(mmResult != MMSYSERR_NOERROR)  
  11.     {  
  12.         return false;  
  13.     }  
  14.     m_hMixer = NULL;  
  15.     return true;  
  16. }  
  至此,我们已经在CMixerDAO类中封装好了进行混合器操作的一些常用方法,通过调用这些方法,就可以实现调节音量、设置静音功能了。但是,要实现在调节系统音量、设置静音时,我们的程序也能够同步进行响应,就得在我们的程序中对MM_MIXM_CONTROL_CHANGE消息进行监听并响应了。 3.9监听响应MM_MIXM_CONTROL_CHANGE消息   当混合器控制器改变时会发送MM_MIXM_CONTROL_CHANGE消息,我们对该消息进行监听,并进行相应的消息事件处理,就可以让我们的程序在调节系统音量、设置静音时,进行同步响应了。具体的实现代码如下:   [cpp] view plain copy
  1. /* 
  2.  * 函数功能 : 系统音量(静音)调节消息MM_MIXM_CONTROL_CHANGE的消息处理函数 
  3.  * 备    注 :  
  4.  * 作    者 : 博客园 依旧淡然 
  5.  */  
  6. LONG CFrequencyVoiceDlg::OnMixerCtrlChange(UINT wParam, LONG lParam)  
  7. {  
  8.     //静音  
  9.     if((wParam == (UINT)(HMIXEROBJ)m_MixerDAO.m_hMixer) &&  
  10.         (lParam == m_MixerDAO.m_tMixerControlOfMute.dwControlID))  
  11.     {  
  12.         //获取混合器控件详细信息(静音)  
  13.         if(!m_MixerDAO.GetMixerControlDetails(m_isMixerMute))  
  14.         {  
  15.             MessageBox("获取混合器控件详细信息(静音)失败!", "提示", MB_OK|MB_ICONWARNING);  
  16.             return 0;  
  17.         }  
  18.       
  19.         //更新静音复选框的勾选状态  
  20.         ((CButton*)GetDlgItem(IDC_CHECK_MUTE))->SetCheck((int)m_isMixerMute);      
  21.     }  
  22.   
  23.     //音量  
  24.     if((wParam == (UINT)(HMIXEROBJ)m_MixerDAO.m_hMixer) &&  
  25.         (lParam == m_MixerDAO.m_tMixerControlOfVolume.dwControlID))  
  26.     {  
  27.         //获取混合器控件详细信息(音量)  
  28.         if(!m_MixerDAO.GetMixerControlDetails(m_nCurrentVolume))  
  29.         {  
  30.             MessageBox("获取混合器控件详细信息(音量)失败!", "提示", MB_OK|MB_ICONWARNING);  
  31.             return 0;  
  32.         }  
  33.           
  34.         //更新音量控件信息  
  35.         m_nCurrentVolumePos = 65535 - m_nCurrentVolume;  
  36.         UpdateDataVolumeCtrlInfo();  
  37.     }  
  38.   
  39.     return 0;  
  40. }  
          备注:由于接口函数变更,在Win7以上的系统中,调节音量或设置静音,需要使用IAudioEndpointVolume,具体请参阅MSDN: http://msdn.microsoft.com/en-us/library/dd370839(v=VS.85).aspx   转自:http://www.cnblogs.com/menlsh/p/4168195.html