本文主要介绍如何使用混音器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。具体方法如下:

 #include <mmsystem.h>                        //包含音频操作头文件mmsystem.h
#pragma comment(lib, "Winmm.lib") //添加动态链接库Winmm.lib

3.2获取混合器设备的数量

  通过使用Mixer API函数mixerGetNumDevs(),我们可以获取系统中混合器设备的数量。具体方法如下:

 /*
* 函数功能 : 获取混合器设备的数量
* 备 注 :
* 作 者 : 博客园 依旧淡然
*/
bool CMixerDAO::GetMixerDevsNumber()
{
m_nMixerDevsNumber = ::mixerGetNumDevs();
if(m_nMixerDevsNumber == )
{
return false;
}
return true;
}

  其中,成员变量m_nMixerDevsNumber用于存储获取到的系统中混合器设备的数量,若不存在混合器设备,后续对混合器的操作均不可进行。

3.3打开混合器设备

  通过使用Mixer API函数mixerOpen (),我们可以打开指定的混合器设备。具体方法如下:

 /*
* 函数功能 : 打开混合器设备
* 备 注 : 参数hWnd表示窗口句柄
* 参数nMixerID表示混合器标识号(取值范围0到混合器设备总个数-1)
* 作 者 : 博客园 依旧淡然
*/
bool CMixerDAO::OpenMixer(HWND hWnd, UINT nMixerID)
{
ASSERT(nMixerID < m_nMixerDevsNumber-);
MMRESULT mmResult = ::mixerOpen(&m_hMixer, nMixerID, (DWORD)hWnd, NULL,
MIXER_OBJECTF_MIXER | CALLBACK_WINDOW);
if(mmResult != MMSYSERR_NOERROR)
{
return false;
}
return true;
}

  其中,成员变量m_hMixer用于存储混合器设备句柄。

3.4获取混合器设备指定音频线路的信息

  通过使用Mixer API函数mixerGetLineInfo (),我们可以获取混合器设备指定音频线路的信息。具体方法如下:

 /*
* 函数功能 : 获取混合器音频线路信息
* 备 注 :
* 作 者 : 博客园 依旧淡然
*/
bool CMixerDAO::GetMixerLineInfo()
{
ASSERT(m_hMixer != NULL);
m_tMixerLine.cbStruct = sizeof(MIXERLINE);
m_tMixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
MMRESULT mmResult = ::mixerGetLineInfo((HMIXEROBJ)m_hMixer, &m_tMixerLine,
MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE); //指定线路类型
if(mmResult != MMSYSERR_NOERROR)
{
return false;
}
return true;
}

3.5获取与音频线路相关的控制

  通过使用Mixer API函数mixerGetLineControls (),我们可以获取与音频线路相关的控制。例如要获得音量控制器,可以采用如下方法:

 /*
* 函数功能 : 获取混合器音频线路控件(音量)
* 备 注 :
* 作 者 : 博客园 依旧淡然
*/
bool CMixerDAO::GetMixerLineControlsOfVolume()
{
ASSERT(m_hMixer != NULL);
m_tMixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
m_tMixerLineControls.dwLineID = m_tMixerLine.dwLineID;
m_tMixerLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; //音量
m_tMixerLineControls.cControls = ;
m_tMixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
m_tMixerLineControls.pamxctrl = &m_tMixerControlOfVolume;
MMRESULT mmResult = ::mixerGetLineControls((HMIXEROBJ)m_hMixer, &m_tMixerLineControls,
MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE);
if(mmResult != MMSYSERR_NOERROR)
{
return false;
}
return true;
}

  其中,m_tMixerLineControls.dwControlType用于指定要获取哪种控制器,若为MIXERCONTROL_CONTROLTYPE_VOLUME,则表明是音量控制器m_tMixerControlOfVolume;若为MIXERCONTROL_CONTROLTYPE_MUTE,则表明是静音控制器m_tMixerControlOfMute。

3.6获取指定控制器的详细信息

  通过使用Mixer API函数mixerGetControlDetails (),我们可以获取指定控制器的详细信息。例如要获取当前的音量值,可以采用如下方法:

 /*
* 函数功能 : 获取混合器控件详细信息(音量)
* 备 注 : 参数nCurrentVolume表示当前的音量值
* 作 者 : 博客园 依旧淡然
*/
bool CMixerDAO::GetMixerControlDetails(DWORD& nCurrentVolume)
{
ASSERT(m_hMixer != NULL);
MIXERCONTROLDETAILS_UNSIGNED tMixerControlDetailsUnsigned;
m_tMixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
m_tMixerControlDetails.dwControlID = m_tMixerControlOfVolume.dwControlID;
m_tMixerControlDetails.cChannels = ;
m_tMixerControlDetails.cMultipleItems = ;
m_tMixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
m_tMixerControlDetails.paDetails = &tMixerControlDetailsUnsigned;
MMRESULT mmResult = ::mixerGetControlDetails((HMIXEROBJ)m_hMixer, &m_tMixerControlDetails,
MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE);
if(mmResult != MMSYSERR_NOERROR)
{
return false;
}
nCurrentVolume = tMixerControlDetailsUnsigned.dwValue; //获取当前的音量值
return true;
}

  获取系统静音状态的方法与上述获取当前系统音量值的方法类似,但是需要将m_tMixerControlDetails.dwControlID指定为m_tMixerControlOfMute.dwControlID。

3.7设置指定控制器的详细信息

  通过使用Mixer API函数mixerSetControlDetails (),我们可以设置指定控制器的详细信息。例如要设置音量值,可以采用如下方法:

 /*
* 函数功能 : 设置混合器控件详细信息(音量)
* 备 注 : 参数nNewVolume表示新的音量值
* 作 者 : 博客园 依旧淡然
*/
bool CMixerDAO::SetMixerControlDetails(DWORD nNewVolume)
{
ASSERT(m_hMixer != NULL);
ASSERT(nNewVolume >= m_tMixerControlOfVolume.Bounds.dwMinimum); //输入参数范围验证
ASSERT(nNewVolume <= m_tMixerControlOfVolume.Bounds.dwMaximum);
MIXERCONTROLDETAILS_UNSIGNED tMixerControlDetailsUnsigned = {nNewVolume};
m_tMixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
m_tMixerControlDetails.dwControlID = m_tMixerControlOfVolume.dwControlID;
m_tMixerControlDetails.cChannels = ;
m_tMixerControlDetails.cMultipleItems = ;
m_tMixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
m_tMixerControlDetails.paDetails = &tMixerControlDetailsUnsigned;
MMRESULT mmResult = ::mixerSetControlDetails((HMIXEROBJ)m_hMixer, &m_tMixerControlDetails,
MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
if(mmResult != MMSYSERR_NOERROR)
{
return false;
}
return true;
}

  设置系统静音状态的方法与上述设置当前系统音量值的方法类似,但是需要将m_tMixerControlDetails.dwControlID指定为m_tMixerControlOfMute.dwControlID。

3.8关闭混合器设备

  通过使用Mixer API函数mixerClose (),可以关闭混合器设备。具体方法如下:

 /*
* 函数功能 : 关闭混合器设备
* 备 注 :
* 作 者 : 博客园 依旧淡然
*/
bool CMixerDAO::CloseMixer()
{
ASSERT(m_hMixer != NULL);
MMRESULT mmResult = ::mixerClose(m_hMixer);
if(mmResult != MMSYSERR_NOERROR)
{
return false;
}
m_hMixer = NULL;
return true;
}

  至此,我们已经在CMixerDAO类中封装好了进行混合器操作的一些常用方法,通过调用这些方法,就可以实现调节音量、设置静音功能了。但是,要实现在调节系统音量、设置静音时,我们的程序也能够同步进行响应,就得在我们的程序中对MM_MIXM_CONTROL_CHANGE消息进行监听并响应了。

3.9监听响应MM_MIXM_CONTROL_CHANGE消息

  当混合器控制器改变时会发送MM_MIXM_CONTROL_CHANGE消息,我们对该消息进行监听,并进行相应的消息事件处理,就可以让我们的程序在调节系统音量、设置静音时,进行同步响应了。具体的实现代码如下:

 /*
* 函数功能 : 系统音量(静音)调节消息MM_MIXM_CONTROL_CHANGE的消息处理函数
* 备 注 :
* 作 者 : 博客园 依旧淡然
*/
LONG CFrequencyVoiceDlg::OnMixerCtrlChange(UINT wParam, LONG lParam)
{
//静音
if((wParam == (UINT)(HMIXEROBJ)m_MixerDAO.m_hMixer) &&
(lParam == m_MixerDAO.m_tMixerControlOfMute.dwControlID))
{
//获取混合器控件详细信息(静音)
if(!m_MixerDAO.GetMixerControlDetails(m_isMixerMute))
{
MessageBox("获取混合器控件详细信息(静音)失败!", "提示", MB_OK|MB_ICONWARNING);
return ;
} //更新静音复选框的勾选状态
((CButton*)GetDlgItem(IDC_CHECK_MUTE))->SetCheck((int)m_isMixerMute);
} //音量
if((wParam == (UINT)(HMIXEROBJ)m_MixerDAO.m_hMixer) &&
(lParam == m_MixerDAO.m_tMixerControlOfVolume.dwControlID))
{
//获取混合器控件详细信息(音量)
if(!m_MixerDAO.GetMixerControlDetails(m_nCurrentVolume))
{
MessageBox("获取混合器控件详细信息(音量)失败!", "提示", MB_OK|MB_ICONWARNING);
return ;
} //更新音量控件信息
m_nCurrentVolumePos = - m_nCurrentVolume;
UpdateDataVolumeCtrlInfo();
} return ;
}

  备注:由于接口函数变更,在Win7以上的系统中,调节音量或设置静音,需要使用IAudioEndpointVolume,具体请参阅MSDN:

http://msdn.microsoft.com/en-us/library/dd370839(v=VS.85).aspx

最新文章

  1. Makefile使用库
  2. [转]浏览器渲染机制——一定要放在body底部的js引用
  3. Selenium自动化测试实践 公开班(广州)
  4. (实用篇)php处理单文件、多文件上传代码分享
  5. Linux命令(17)du 查看文件和目录磁盘使用情况
  6. 【EF 4】ORM框架及其流行产品之一EF介绍
  7. TableView 中cell间的分割线(及其他控件间(内)的分割线)设置
  8. SQL学习中(一)序列
  9. (转)ASP.NET版本的Kindeditor插件的使用(同步)
  10. ASP.NET Web Service应用发布到IIs怎么做
  11. UIViewAdditions(一个非常方便的工具类用它)
  12. javascript 拖放效果
  13. Django 模版中如何对主菜单进行选中?
  14. DAY10、函数的参数
  15. hadoop配置笔记
  16. Django restful
  17. 清理tomcat服务器缓存
  18. pta习题集 5-10 切分表达式——写个tokenizer吧
  19. Python处理文本换行符
  20. 在 CentOS 7.0 上安装配置 Ceph 存储

热门文章

  1. 追踪记录每笔业务操作数据改变的利器——SQLCDC
  2. 数据结构0103汉诺塔&amp;八皇后
  3. java提升路线书单(原文自知乎刘欣)
  4. Python爬虫学习(7):浙大软院网号嗅探
  5. js闭包
  6. Java throws Exception、try、catch
  7. BestCoder Round 69 Div 2 1001&amp;&amp; 1002 || HDU 5610 &amp;&amp; 5611
  8. view的滑动冲突解决方案
  9. CICS的几个常用命令
  10. @autowired和@resource的区别