转载——用Mixer API函数调节控制面板的音频设置
关键词:Mixer函数,控制面板,音频设备调节
如果你用过windows的音频设备,比如播放音乐或者录音,聊天,调节麦克或者声音的大小,以及设置静音,都可以通过控制面板中的音频设置面板来调节,你对于下面的两个设置面板肯定不陌生。
播放时调节音量大小和左右声道的控制板,还可以通过它将某个设备设置为静音。
![]() 图1 |
另一个就是录音时控制面板,在这里我们可以选择声音输入设备,以及调节录音时左右声道音量大小
![]() 图2 |
这两个控制板是windows提供给我们的,这两个控制板是让windows用户在播放声音或者录音时莱调节音频设备的,通过这两个控制板,我们可以选择播放或者录音的音频设备,设置音量的大小,调整左右声道。但是如果我们自己开发的程序中也要用到这个功能该怎么办,比如你开发的程序想给用户提供一个调节音频设备的界面,可以让用户很方便的通过你的程序提供的功能来调节和选择相应的音频设备,而不是每次都要转到系统的控制面板中来调节它们,当用户通过我们提供的接口对设备进行的调整,在系统的控制面板中的音频设备设置要相应的发生改变,并且当用户通过系统控制面板调整音频设置后,在我们程序的界面上也会发生相应的改变。我最近在开发过程中就遇到这个问题,通过仔细的查阅msdn以及其他的资料,终于解决了这个问题,下面我将我的经验总结一下,如果你也遇到相类似的问题,希望能对你有所帮助。
如何来控制系统中任何的音频输出和输入,比如波形音频,MIDI ,CD音频,合成语音等音频输出以及Line in ,麦克等输入,windows给我们提供了一组API接口函数,称为Mixer系列的函数,mixer也称为混音器,通过混音器可以实现混音和音量控制。最基本的混音器结构单元是音频线路,比如microphone ,line in ,cd,midi等都是一个音频线路。音频线路包含一个或者多个发源于单一音源或系统资源的声道,例如,一个立体声音频线路有两个声道,但仍然被看成是一个音频线路,因为它发源于一个音源。
下面我要先简单的介绍一下Mixer函数,其实反正总共也没有几个,使用起来很简单的。
mixerOpen
mixerClose
mixerGetDevCaps
mixerGetLineControls
mixerGetLineInfo
mixerGetControlDetails
mixerSetControlDetails
mixerGetID
mixerGetNumDevs
看到了吧,就这么简单的几个函数,通过这9个API,我们就可以来控制音频的输入和输出设备了,其实有关这几个函数的定义你可以在C:\Program Files\Microsoft Visual Studio\VC98\Include\mmsystem.h文件中找到。下面我简单介绍一下这几个函数,详细地介绍你可以参见msdn。
mixerOpen和mixerClose函数用来打开和关闭混音器设备
mixerGetNumDevs可以确定系统中有多少混音器设备
mixerGetDevCaps函数可以确定混音器设备的能力
mixerGetLineInfo可以检索指定音频线路的信息
mixerGetLineControls用于检索一个或者多个与音频线路相关的控制的通用信息
mixerGetControlDetails用于检索与某个音频线路相关的一个控制的属性
mixerSetControlDetails用于设置制定控制的属性。
其实我们主要用到的就是后面的四个函数,希望大家重点研究一下。混音器还提供了窗口回调服务,用户在调用mixeropen的时候,可以将一个窗口句柄作为参数传递给mixer,这样,当mixer设备发生变化时就会给回调窗口发送消息通知,比如用户通过控制面板调整了音量的大小,或者选择了某个录音设备。消息的类型就两个MM_MIXM_LINE_CHANGE和MM_MIXM_CONTROL_CHANGE。
下面就不多说了,我用一个例子告诉你如何在程序中对音频设备进行设置,先看看我提供的例子的界面
![]() 图3 |
这里播放和录音我都只是选择了几个常用的设备,当然系统提供的设备比我这里的举例用到的设备要多,你可以根据我提供的方法来对其他的设备进行控制。还有说明一下,具有两个滑动条的表示左右声道。但是像麦克风只有一个声道。
通过我们的程序界面我们就可以像在控制面板里一样可以调节左右声道的音量,以及选择某个设备进行录音,或者对某个音频线路进行静音,相应的系统的设置也会被改变,如果你通过系统的控制面板进行设置,在我们的程序界面也上同步的可以反映出来变化。
关于工程的建立我就不多少了,很简单的,就是一个基于对话框的工程,上面放了一些控件。下面我主要讲一下每个功能是如何实现的。主要有三个功能1 如何调整左右声道音量的大小,2 如何将某个设备静音,3 如何选择录音设备。
这里关于mixer函数的用法还要先唠叨几句。一般来说,对音频线路的操作流程如下:
1、通过GetLineInfo获取指定音频线路的信息,返回一个MIXERLINE结构
2、然后通过GetLineControl获取音频线路相关的控制的通用信息,通过MIXERCONTROL结构返回。
3、通过GetConrolDetails获取指定控制的属性值
4、通过SetControlDetails设置指定控制的属性值,
对于每个线路设备,mixer都用一个类型值来标示,比如:
Volume对应的值 MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
CD 对于的值 MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC
Midi对应的值为 MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER
Wave对应的值为 MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT
Line in对应的值为 MIXERLINE_COMPONENTTYPE_SRC_LINE
Microphone对应的值为 MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
我们可以通过音频线路的类型值获得相应的线路的信息,也可以通过音频线路的设备ID来获取相应的线路的信息。
下面开始我们编程吧。
首先定义三个变量
UINT m_uMxId; //mixer的ID HWND m_hWnd; //回调窗口句柄 HMIXER m_hmx; // |
然后就是要打开mixer,可以在对话的初始化中作这些工作。
#define MAX_VOL_VALUE 65535 if (MMSYSERR_NOERROR != mixerOpen(&m_hmx, m_uMxId,(DWORD)m_hWnd, 0, CALLBACK_WINDOW)) { return FALSE; } if (MMSYSERR_NOERROR == mixerGetID((HMIXEROBJ)m_hmx, &m_uMxId, MIXER_OBJECTF_HMIXER)) { return m_uMxId; } //设置Volume的滑动条的范围这里只以Volume为例。 m_SliderWaveL.SetRange(0, MAX_VOL_VALUE, TRUE); m_SliderWaveR.SetRange(0, MAX_VOL_VALUE, TRUE); |
接着我先演示一下如何获取和设置录音设备的左右声道的音量值,以及如何静音放音设备,这里以Volume为例,其他的设备类似,你可以照着我的代码,套用即可。
1、如何获取Volume设备的音量大小
DWORD dwLValue; DWORD dwRValue; GetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, &dwLValue,&dwRValue); //GetVolume函数的定义见下面,然后根据返回的值调整滑动条的位置 m_SliderVolR.SetPos(MAX_VOL_VALUE - dwLValue); m_SliderVolL.SetPos(MAX_VOL_VALUE - dwRValue); |
2、如何根据滑动条的位置来调整系统音量的大小
void CMixerControlDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // m_dwSpkR和m_dwSpkL是用来记录Volume左右声道的音量值,0~~65535 CSliderCtrl *pSlider = (CSliderCtrl *)pScrollBar; int nValue = MAX_VOL_VALUE - pSlider->GetPos(); //获取滑动条的位置pos else if (m_SliderVolR.m_hWnd == pSlider->m_hWnd) { //如果拖动的是Volume的左声道 m_dwSpkR = nValue; // 设置Volume的音量值 SetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, m_dwSpkL, m_dwSpkR); } else if (m_SliderVolL.m_hWnd == pSlider->m_hWnd) { //Volume右声道 m_dwSpkL = nValue; // 设置Volume的音量值 SetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, m_dwSpkL, m_dwSpkR); } //其他音频线路可以依次类推在下面添加 } |
GetVolume和SetVolume函数的定义下面给出
BOOL CMixer::SetVolume(DWORD dwSrcType, DWORD dwLValue, DWORD dwRValue, BOOL bMono) { MIXERLINE mxl; if (! GetLineInfo(&mxl, MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, dwSrcType)) return FALSE; MIXERCONTROL mxc; MIXERCONTROLDETAILS mxcd; mxcd.cbStruct = sizeof(mxcd); if (bMono) if (! SetControlDetails(&mxcd, MIXER_OBJECTF_MIXER)) return TRUE; BOOL CMixer::GetVolume(DWORD dwSrcType, DWORD* pdwLValue, DWORD* pdwRValue, BOOL bMono) MIXERCONTROL mxc; MIXERCONTROLDETAILS mxcd; mxcd.cbStruct = sizeof(mxcd); if (bMono) if (! GetControlDetails(&mxcd, MIXER_GETCONTROLDETAILSF_VALUE)) *pdwLValue = mxcd_u1.dwValue; if (! GetControlDetails(&mxcd, MIXER_GETCONTROLDETAILSF_VALUE)) *pdwLValue = mxcd_u[0].dwValue; BOOL GetLineInfo(LPMIXERLINE pmxl, DWORD dwDstType, DWORD dwSrcType) UINT u=0; } while ((u < mxcaps.cDestinations) && (pmxl->dwComponentType != dwDstType)); if (u > mxcaps.cDestinations) if (dwDstType == dwSrcType) pmxl->dwDestination = u; UINT v=0; if (MMSYSERR_NOERROR != mixerGetLineControls((HMIXEROBJ)m_uMxId, pmxl, MIXER_GETLINEINFOF_SOURCE)) if((v > cConnections) || (pmxl->dwComponentType !=dwSrcType)) return TRUE; BOOL GetLineControl(LPMIXERCONTROL pmxc, LPMIXERLINE pmxl, DWORD dwType) MIXERLINECONTROLS mxlc; if (MMSYSERR_NOERROR != mixerGetControlDetails((HMIXEROBJ)m_uMxId, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE)) |
3、下面演示一下如何设置Volume设备的静音
这里提供了两个函数,GetMute用来获取系统设置中是否对某个音频线路进行了静音操作,SetMute是用来对系统的某个音频线路进行静音操作。
BOOL CMixer::SetMute(DWORD dwSrcType, BOOL bValue) { MIXERLINE mxl; if (! GetLineInfo(&mxl, MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, dwSrcType)) return FALSE; MIXERCONTROL mxc; MIXERCONTROLDETAILS mxcd; mxcd.cbStruct = sizeof(mxcd); if (! SetControlDetails(&mxcd, MIXER_OBJECTF_MIXER)) return TRUE; BOOL CMixer::GetMute(DWORD dwSrcType, BOOL* pbValue) MIXERCONTROL mxc; MIXERCONTROLDETAILS mxcd; mxcd.cbStruct = sizeof(mxcd); if (! GetControlDetails(&mxcd, MIXER_GETCONTROLDETAILSF_VALUE)) *pbValue = mxcd_f.fValue; return TRUE; |
如果用这两个函数呢,下面我演示了如何设置和获取Volume音频线路的静音操作。
BOOL bValue = TRUE; SetMute(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, bValue); GetMute(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, &bValue); |
4、下面看看当系统的设置改变时,mixer是如何通知我们的吧。
还记得我前面讲过的,当我们调用mixeropen时可以传递一个窗口的句柄作为回调窗口,当系统的设置改变,比如音量改变,某个音频线路被静音时,mixer都会给我们的回调窗口发送消息的。
一般只有两个消息,如下
afx_msg void OnMLChange(WPARAM wParam, LPARAM lParam); afx_msg void OnMCChange(WPARAM wParam, LPARAM lParam); ON_MESSAGE(MM_MIXM_LINE_CHANGE, OnMLChange) |
其中MM_MIXM_CONTROL_CHANGE 消息中,发送消息的两个参数代表的意思如下
wParam = (WPARAM) hMixer lParam = (LPARAM) dwControlID |
在MM_MIXM_LINE_CHANGE 消息中,发送消息的参数代表的意思如下
wParam = (WPARAM) hMixer lParam = (LPARAM) dwLineID |
在我们的应用程序中,我们可以在这两个消息处理函数中调整我们的设置,以对应于系统的改变,比如你的代码可以这样写:
void CMixerControlDlg::OnMCChange(WPARAM wParam, LPARAM lParam) { DWORD dwLValue; DWORD dwRValue; GetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, &dwLValue,&dwRValue); //GetVolume函数的定义见下面,然后根据返回的值调整滑动条的位置 m_SliderVolR.SetPos(MAX_VOL_VALUE - dwLValue); m_SliderVolL.SetPos(MAX_VOL_VALUE - dwRValue); //你也可以在这里调用GetMute查看Volume是否被静音, } |
如此你的程序就可以自动的响应系统设置的改变了。
关于mixer API的应用开发就介绍到这里,记着最后要关闭mixer如此:mixerClose(m_hmx);
转载——用Mixer API函数调节控制面板的音频设置的更多相关文章
- Windows文件操作的API函数[转载]
在VC中,大多数情况对文件的操作都使用系统提供的 API 函数,但有的函数我们不是很熟悉,以下提供一些文件操作 API 函数介绍: 一般文件操作 API CreateFile 打开文件 要对文件进行读 ...
- Zigbee协议栈OSAL层API函数【转载】
OSAL层提供了很多的API来对整个的协议栈进行管理.主要有下面的几类:信息管理.任务同步.时间管理.中断管理.任务管理.内存管理.电源管理以及非易失存储管理.看到这些管理是不是感 ...
- C#调用Win32 的API函数--User32.dll ----转载
Win32的API函数是微软自己的东西,可以直接在C#中直接调用,在做WinForm时还是很有帮助的.有时候我们之直接调用Win32 的API,可以很高效的实现想要的效果. using System; ...
- Windows API 函数列表 附帮助手册
所有Windows API函数列表,为了方便查询,也为了大家查找,所以整理一下贡献出来了. 帮助手册:700多个Windows API的函数手册 免费下载 API之网络函数 API之消息函数 API之 ...
- API函数
1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WNetAddConnection2 创建同一个网络资源的连接 WNetAddConnection3 创建同 ...
- Detours简介 (拦截x86机器上的任意的win32 API函数)
Detours 当然是用detours,微软明显高腾讯一筹,同上,至今没失败过.写这种HOOK一定要再写个测试程序,不要直接HOOK你的目的程序,例如QQ,因为这样不方面更灵活的测试.说明一下:Det ...
- WINDOWS API 函数(超长,值得学习)
一.隐藏和显示光标 函数: int ShowCursor ( BOOL bShow ); 参数 bshow,为布尔型,bShow的值为False时隐藏光标,为True时显示光标:该函数的返回值为整型 ...
- Delphi 常用API 函数(好多都没见过)
AdjustWindowRect 给定一种窗口样式,计算获得目标客户区矩形所需的窗口大小AnyPopup 判断屏幕上是否存在任何弹出式窗口ArrangeIconicWindows 排列一个父窗口的最小 ...
- Delphi 常用API 函数
Delphi 常用API 函数 AdjustWindowRect 给定一种窗口样式,计算获得目标客户区矩形所需的窗口大小 AnyPopup 判断屏幕上是否存在任何弹出式窗口 ArrangeIconic ...
随机推荐
- [Asp.net Mvc]通过UrlHelper扩展为js,css静态文件添加版本号
写在前面 在app中嵌入h5应用,最头疼的就是缓存的问题,比如你修改了一个样式,或者在js中添加了一个方法,发布之后,并没有更新,加载的仍是缓存里面的内容.这个时候就需要清理缓存才能解决.但又不想让w ...
- 利用sourcemap来调试sass
最近项目用上了sass,作为css的预处理器,它可以让我们用程序化的思维书写样式,极大的简化了css的开发,实在是前端居家旅行必备的利器. 我们都知道,在项目中,样式的频繁调试是不可避免的,用上sas ...
- 解读JSP的解析过程
解读JSP的解析过程 互联网上,这方面的资料实在太少了,故把自己研究的一些结果公布出来. 首先,问大家几个问题,看大家能不能回答出来,或者在网上能不能找到答案: 1.page.include.tagl ...
- [Effective JavaScript 笔记]第35条:使用闭包存储私有数据
js的对象系统并没有特别鼓励或强制信息隐藏.所有的属性名都是一个字符串,任意一个程序都可以简单地通过访问属性名来获取相应的对象属性.例如,for...in循环.ES5的Object.keys()和Ob ...
- Xen虚拟机克隆实战
导读 在我们使用Xen虚拟化的时候,会经常创建虚拟机(VM),每次安装创建步骤比较繁琐,本文介绍通过virt-clone命令克隆xen虚拟机实战. 查看virt-clone命令是否存在 rpm -qa ...
- MySQL的分页
有朋友问: MySQL的分页似乎一直是个问题,有什么优化方法吗?网上看到网上推荐了一些分页方法,但似乎不太可行,你能点评一下吗? 方法1: 直接使用数据库提供的SQL语句 ---语句样式: MySQL ...
- Linux netstat +awk 看攻击IP
netstat -n | awk '/^tcp/ {n=split($(NF-1),array,":");if(n<=2)++S[array[(1)]];else++S[a ...
- qq空间答案
2073693795 懂得人自然会懂
- 用VMware安装虚拟系统时出现Invalid system disk,Replace the disk and then press any key
VMware 默认是第一次从光盘启动,第二次从硬盘启动,你刚分区,里面还没有系统,当然报这个错,再次从光盘启动需要设置 VMware 的 BIOS,重新启动虚拟系统,当出现 VMware 的图标时用鼠 ...
- 《ASP.NET1200例》<asp:DataList>分页显示图片
aspx页面代码 <asp:DataList ID="dlPhoto" runat="server" Height="137px" W ...