【VC++技术杂谈001】音频技术之调节音量及设置静音

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

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

3.2获取混合器设备的数量

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

 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 (),我们可以打开指定的混合器设备。具体方法如下:

 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 (),我们可以获取混合器设备指定音频线路的信息。具体方法如下:

 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 (),我们可以获取与音频线路相关的控制。例如要获得音量控制器,可以采用如下方法:

 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 (),我们可以获取指定控制器的详细信息。例如要获取当前的音量值,可以采用如下方法:

 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 (),我们可以设置指定控制器的详细信息。例如要设置音量值,可以采用如下方法:

 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 (),可以关闭混合器设备。具体方法如下:

 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消息,我们对该消息进行监听,并进行相应的消息事件处理,就可以让我们的程序在调节系统音量、设置静音时,进行同步响应了。具体的实现代码如下:

 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

时间: 2024-11-04 19:10:12

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

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

在上一篇博文中我主要介绍了如何获取以及设置系统的默认打印机,本文将介绍如何对打印机状态进行实时监控,记录下所打印的文档.打印的份数以及打印时间等打印信息. 1.打印机虚脱机技术 在正式介绍如何对打印机状态进行实时监控之前,我们有必要先了解一下打印机虚脱机技术. 独占设备是指在一个程序(作业.用户)的整个运行期间独占设备,直到该程序(作业.用户)完成.系统的独占设备是有限的(比如,一台计算机只能够连接一台打印机),往往不能够满足多进程的要求,会引起大量进程由于等待某些独占设备而阻塞.另一方面,申请

游戏音频技术备忘 (二) 关于游戏开发

千里之行始于足下,一款游戏如何从无到有?诗人构思许久后动笔写作,音乐家在乐谱与乐器间来回修改,画家调节颜料比例涂抹在画布上,文学音乐绘画都要经历如上所述大致相同的创作流程.游戏不同与往,游戏杂糅了几乎所有艺术形式的特征,一方面我们还要进行传统的 文学音乐绘画创作,另一方面我们要额外考虑如何把这些各自分隔的内容糅合在一起,并且提供一套交互系统用以产生变化,这时候我们就需要一个工程师来实现这一目标. 作为电子游戏,建构虚拟世界的根基是各类的计算机硬件,我们需要一块屏幕用以显示图像,一只喇叭用以播放声

视音频技术学习的视频资源

这两天开始带广播电视工程大二的暑假小学期的课程设计了.本次小学期课程内容为<基于 FFmpeg + SDL 的视频播放器的制作>,其中主要讲述了视音频开发的入门知识.由于课程的内容比较适合没有视音频基础的开发者入门使用,所以在讲课的同时也录制了一部分内容并上传到了网上,方便新手学习FFmpeg的开发. 这是自己第一次讲课,很多地方还没有经验.希望以后多加油,争取能够讲得更好. O(∩_∩)O <基于 FFmpeg + SDL 的视频播放器的制作>课程视频 本课程是使用FFmpeg进

游戏音频技术备忘 (一) 关于游戏

大家好,随着游戏工业的发展,游戏音频相关技术变得越来越复杂,然而中文世界里相关的学习资料与文档始终难以找寻,游戏音频相关技术相较图形编程渲染领域在游戏开发技术中处于比较次要的位置,同时深耕声学音乐学与计算机相关学科难以实现兼顾平衡导致音效师,作曲家与程序员之间存在较为明显的分野,在个人的学习过程中也时常感到路途陡峭.在此整理分享一些过去积累的相关技术内容,如有疏漏不妥之处,尽请匡正. 暂且不考虑艺术和社会学范畴对游戏的定义,电子游戏作为一种特殊的计算机软件能够产生的交互,本质上与我们在电视机空调

WebGIS开发技术杂谈

WebGIS项目的开发主要是B/S架构.最流行的是客户端javascript,服务器端java. 另外还有flex客户端. 客户端主要完成用户交互.向服务器端发送请求并传参以及组织显示服务器端返回的结果等.  服务器端则完成数据库增删查改.业务功能等. 服务器端最底层是数据层,完成对数据的增删查改.常用的数据库有oracle.mysql等.最基本的方法是, java语言使用jdbc,组织相应的sql语句实现数据库操作.   更便捷的方法是使用第三方框架,如hibernate. hibernate

[总结]视音频技术零基础学习方法

一直想把视音频编解码技术做一个简单的总结,可是苦于时间不充裕,一直没能完成.今天有着很大的空闲,终于可以总结一个有关视音频技术的入门教程,可以方便更多的人学习从零开始学习视音频技术.需要注意的是,本文所说的视音频技术,指的是理论层面的视音频技术,并不涉及到编程相关的东西. 0.     生活中的视音频技术 平时我们打开电脑中自己存电影的目录的话,一般都会如下图所示,一大堆五花八门的电影.(其实专业的影视爱好者一概会把影视文件分门别类的,但我比较懒,一股脑把电影放在了一起) 因为下载的来源不同,这

iPhone OS的音频技术简介

iPhone OS的音频技术为用户提供了丰富的音频体验.它包括音频回放,高质量的录音和触发设备的振动功能等. iPhone OS的音频技术支持如下音频格式:AAC.Apple Lossless(ALAC).A-law.IMA/ADPCM(IMA4).Linear PCM.μ-law和Core Audio等. ① 核心音频(Core Audio Family)      ▇     ▇     ▇     ▇     ▇     ▇     ▇     ▇     ▇     ▇     ▇   

语音、音频技术的一点思考

语音和图像.视频一样,是人与人之间沟通的交流方式. 语音信号处理是一门综合性的学科,它与语音学.心理学.数字信号处理.计算机科学.模式识别等有着密切联系. 语音技术一般可以分为三大类: 1.人与人之间的通信:语音增强.语音编码.语音通信.VOIP等 简单的说,以网络为载体,实现人与人之间的语音通信,涉及到语音前端去噪,增强,语音压缩编码等. 语音增强.语音去噪等, 主要解决的是前端问题,单纯的语音.音频处理技术主要应用在嵌入式方向. 开源的像Webrtc.Speex之类. VOIP.语音通信主要

《技术垄断:文明向技术投降》

<技术垄断:文明向技术投降>是著名的“媒介批评三部曲”之一,系统讲解了技术垄断对人类社会的文化.宗教.传统和心理造成的影响和破坏,深刻地指出了技术的发展不受控制所带来的恶果:技术所创造的文化缺乏道德根基,它破坏了某些心理过程和社会关系,破坏了人类生存的价值所在. 内容简介 <技术垄断(文明向技术投降)>曾经是<纽约时报>TOP100的畅销书,颇得广大读者认同.世界著名媒介理论家和批评家Neil Postman(即波兹曼)从社会现状出发,以独特的视角揭示了技术的发展和变化