【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。具体方法如下:
#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
【VC++技术杂谈001】音频技术之调节音量及设置静音的更多相关文章
- 【VC++技术杂谈003】打印技术之打印机状态监控
在上一篇博文中我主要介绍了如何获取以及设置系统的默认打印机,本文将介绍如何对打印机状态进行实时监控,记录下所打印的文档.打印的份数以及打印时间等打印信息. 1.打印机虚脱机技术 在正式介绍如何对打印机 ...
- 游戏音频技术备忘 (五)Wwise Unreal Engine 集成代码浅析 二
AkAmbientSound类的实现 Unreal Engine提供了一个基本对象的构造器ObjectInitializer,一般来说用户创建的类总是拥有很多变量,因此 AkAmbientSound ...
- Fraunhofer音频技术为MPEG未来高品质3D音频内容传输的标准依据
OFweek电子工程网讯:世界着名的音频和多媒体技术研究机构Fraunhofer IIS的基于信道/对象的方案获选成为未来MPEG-H 3D音频标准的依据,此项标准旨在传输高品质的3D音频内容.MPE ...
- 内行看门道:看似“佛系”的《QQ炫舞手游》,背后的音频技术一点都不简单
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯游戏云发表于云+社区专栏 3月14日,腾讯旗下知名手游<QQ炫舞>正式上线各大应用商店,并迅速登上App Store免 ...
- 后端技术杂谈11:十分钟理解Kubernetes核心概念
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 本文转自 https://github.com/h2pl/Java-Tutorial 喜欢的 ...
- 后端技术杂谈10:Docker 核心技术与实现原理
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- 后端技术杂谈9:先搞懂Docker核心概念吧
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- 后端技术杂谈8:OpenStack架构设计
本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...
- 后端技术杂谈7:OpenStack的基石KVM
Qemu,KVM,Virsh傻傻的分不清 本文转载自Itweet的博客 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://gi ...
随机推荐
- 优化Web中的性能
优化Web中的性能 简介 web的优化就是一场阻止http请求最终访问到数据库的战争. 优化的方式就是加缓存,在各个节点加缓存. web请求的流程及节点 熟悉流程及节点,才能定位性能的问题.而且优化的 ...
- Python3的tkinter写一个简单的小程序
一.这个学期开始学习python,但是看了python2和python3,最后还是选择了python3 本着熟悉python的原因,并且也想做一些小程序来增加自己对python的熟练度.所以写了一个简 ...
- 【转载】给那些想多学习,多进步的Domino初学者
在这个社区里面,包括QQ技术群里面混了很久了.遇到了很多Domino初学者,也认识了很多致力于Domino这个技术领域的朋友,很开心.很久没有写长篇大论给大家了.我要把一些想法写出来,共大家参考.讨论 ...
- C++-Qt【1】-退出程序&静态调试
目前还没有发现很好的调试qt代码的方法,权且记录一下: #include "mainwindow.h" #include "ui_mainwindow.h" # ...
- 关于ADO.NET连接ORACLE,使用ODAC连接中的一些问题
ADO.NET连接ORACLE时,用到ODAC组件时,有几点注意的. 1.安装的具体方法见:http://jingyan.baidu.com/article/e4511cf336ce872b845ea ...
- 未能添加对***.dll的引用 问题解决方法
这个不是什么新问题了,这里说一下我遇到的这个操蛋事. 转载请注明出处 http://www.cnblogs.com/zaiyuzhong/p/6236263.html 我做的和往常一样,找到SDK开发 ...
- 有关iOS系统中调用相机设备实现二维码扫描功能的注意点(3/3)
今天我们接着聊聊iOS系统实现二维码扫描的其他注意点. 大家还记得前面我们用到的输出数据的类对象吗?AVCaptureMetadataOutput,就是它!如果我们需要实现目前主流APP扫描二维码的功 ...
- c++书
http://www.enet.com.cn/eschool/video/c++/ 视频 http://www.runoob.com/cplusplus/cpp-inheritance.html ...
- _MSC_VER详细介绍
_MSC_VER详细介绍 转自:http://www.cnblogs.com/braver/articles/2064817.html _MSC_VER是微软的预编译控制. _MSC_VER可以分解为 ...
- Windows7-USB-DVD-tool提示不能拷贝文件的处理
打开 Windows7-USB-DVD-tool所在目录的log/日志 01/28/2016 02:21:02: Drive selected, H:\; Ready01/28/2016 02:21 ...