本文主要介绍如何使用混音器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();
     )
     {
         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);
             ;
         }

         //更新静音复选框的勾选状态
         ((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);
             ;
         }

         //更新音量控件信息
         m_nCurrentVolumePos =  - m_nCurrentVolume;
         UpdateDataVolumeCtrlInfo();
     }

     ;
 }

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

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

【VC++技术杂谈001】音频技术之调节音量及设置静音的更多相关文章

  1. 【VC++技术杂谈003】打印技术之打印机状态监控

    在上一篇博文中我主要介绍了如何获取以及设置系统的默认打印机,本文将介绍如何对打印机状态进行实时监控,记录下所打印的文档.打印的份数以及打印时间等打印信息. 1.打印机虚脱机技术 在正式介绍如何对打印机 ...

  2. 游戏音频技术备忘 (五)Wwise Unreal Engine 集成代码浅析 二

    AkAmbientSound类的实现 Unreal Engine提供了一个基本对象的构造器ObjectInitializer,一般来说用户创建的类总是拥有很多变量,因此 AkAmbientSound  ...

  3. 解决Eclipse中文乱码 - 技术博客 - 51CTO技术博客 http://hsj69106.blog.51cto.com/1017401/595598/

    解决Eclipse中文乱码 - 技术博客 - 51CTO技术博客  http://hsj69106.blog.51cto.com/1017401/595598/

  4. 从ThoughtWorks 2017技术雷达看微软技术

    ThoughtWorks在每年都会出品两期技术雷达,这是一份关于技术趋势的报告,它比起一些我们能在市面上见到的其他各种技术行情和预测报告,更加具体,更具可操作性,因为它不仅涉及到新技术大趋势,比如云平 ...

  5. android 滑动滚动条调节音量

    利用滚动条滑动控制音量: 定义: private SeekBar mseekBarvolume: 以下实现代码: //调节音量--begin------------------------- //音量 ...

  6. 【VC++技术杂谈004】使用微软TTS语音引擎实现文本朗读

    本文主要介绍如何使用微软TTS语音引擎实现文本朗读,以及生成wav格式的声音文件. 1.语音引擎及语音库的安装 TTS(Text-To-Speech)是指文本语音的简称,即通过TTS引擎把文本转化为语 ...

  7. 【VC++技术杂谈008】使用zlib解压zip压缩文件

    最近因为项目的需要,要对zip压缩文件进行批量解压.在网上查阅了相关的资料后,最终使用zlib开源库实现了该功能.本文将对zlib开源库进行简单介绍,并给出一个使用zlib开源库对zip压缩文件进行解 ...

  8. 【VC++技术杂谈007】使用GDI+进行图片格式转换

    本文主要介绍如何使用GDI+对图片进行格式转换,可以转换的图片格式为bmp.jpg.png. 1.加载GDI+库 GDI+是GDI图形库的一个增强版本,提供了一系列Visual C++ API.为了使 ...

  9. 【VC++技术杂谈006】截取电脑桌面并将其保存为bmp图片

    本文主要介绍如何截取电脑桌面并将其保存为bmp图片. 1. Bmp图像文件组成 Bmp是Windows操作系统中的标准图像文件格式. Bmp图像文件由四部分组成: (1)位图头文件数据结构,包含Bmp ...

随机推荐

  1. 如何利用 Visual Studio 自定义项目或工程模板

    在开发项目的时候,由其是商业性质的大型项目时,往往需要在每个代码文件上都加上一段关于版权.开发人员的信息,并且名称空间上都需要带有公司的标志.这个时候,是选择在开发的时候手动添加还是自动生成呢? 我们 ...

  2. MongoDB 优化器MongoDB Database Profiler(12)

    优化器profile 在MySQL 中,慢查询日志是经常作为我们优化数据库的依据,那在MongoDB 中是否有类似的功能呢?答案是肯定的,那就是MongoDB Database Profiler. 1 ...

  3. perl学习之路2

    这些主要是从 "小骆驼" 书上粘贴或者摘抄出来的, 个人认为需要记的语法知识 "在某些情况下, 你可能需要在一台机器上写程序, 再传送到另一台机器上运行.这时候, 请使用 ...

  4. javascript设计模式实践之迭代器--具有百叶窗切换图片效果的JQuery插件(一)

    类似于幻灯片的切换效果,有时需要在网页中完成一些图片的自动切换效果,比如广告,宣传,产品介绍之类的,那么单纯的切就没意思了,需要在切换的时候通过一些效果使得切换生动些. 比较常用之一的就是窗帘切换了. ...

  5. codeforces#271 (Div. 2)预处理

    B. Worms time limit per test 1 second memory limit per test 256 megabytes input standard input outpu ...

  6. Lunix 命令

    awk '{a[$1]+=1;if(a[$1]==1){print $0}}' awk -F ','  '{print $1, $6}'  IS.csv | sort -k1n -k2n | awk ...

  7. Android长时间后台运行Service

         项目需要在后台获取GPS经纬度.当用户对手机有一段时间没有操作后,屏幕(Screen)将从高亮(Bright)变为暗淡(Dim),如果再过段时间没操作, 屏幕(Screen)将又由暗淡(Di ...

  8. LoadRunner中文乱码问题解决方案

    一下内容纯属网上方法集合: 我用loadrunner录制,脚本里的乱码一直没有解决.看到网上很多贴子.采用的方法:1.第一步:去lr 的vugen的Tools -> Recoding Optio ...

  9. HealthKit开发教程之HealthKit的复合数据

    HealthKit开发教程之HealthKit的复合数据 复合数据就是复合单位和值构成的数据.所谓复合单位就是由单位进行乘法.除法等得到的单位,如m/s.lb·ft等就是复合单位.本节将针对这些复合数 ...

  10. Android高级之Dalvik初识

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 研究安卓已多年,一直在应用层做开发,Framework层只是看过,也就是大家常说的"底层& ...