MFC音频API.docx
《MFC音频API.docx》由会员分享,可在线阅读,更多相关《MFC音频API.docx(10页珍藏版)》请在冰豆网上搜索。
MFC音频API
如何来控制系统中任何的音频输出和输入,比如波形音频,MIDI,CD音频,合成语音等音频输出以及Linein,麦克等输入,windows给我们提供了一组API接口函数,称为Mixer系列的函数,mixer也称为混音器,通过混音器可以实现混音和音量控制。
最基本的混音器结构单元是音频线路,比如microphone,linein,cd,midi等都是一个音频线路。
音频线路包含一个或者多个发源于单一音源或系统资源的声道,例如,一个立体声音频线路有两个声道,但仍然被看成是一个音频线路,因为它发源于一个音源。
下面我要先简单的介绍一下Mixer函数,其实反正总共也没有几个,使用起来很简单的。
mixerOpen
mixerClose
mixerGetDevCaps
mixerGetLineControls
mixerGetLineInfo
mixerGetControlDetails
mixerSetControlDetails
mixerGetID
mixerGetNumDevs
看到了吧,就这么简单的几个函数,通过这9个API,我们就可以来控制音频的输入和输出设备了,其实有关这几个函数的定义你可以在C:
\ProgramFiles\MicrosoftVisualStudio\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
Linein对应的值为MIXERLINE_COMPONENTTYPE_SRC_LINE
Microphone对应的值为MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE
我们可以通过音频线路的类型值获得相应的线路的信息,也可以通过音频线路的设备ID来获取相应的线路的信息。
下面开始我们编程吧。
首先定义三个变量
UINTm_uMxId;//mixer的ID
HWNDm_hWnd;//回调窗口句柄
HMIXERm_hmx;//
然后就是要打开mixer,可以在对话的初始化中作这些工作。
#defineMAX_VOL_VALUE65535
if(MMSYSERR_NOERROR!
=mixerOpen(&m_hmx,m_uMxId,(DWORD)m_hWnd,0,CALLBACK_WINDOW))
{
returnFALSE;
}
if(MMSYSERR_NOERROR==mixerGetID((HMIXEROBJ)m_hmx,&m_uMxId,MIXER_OBJECTF_HMIXER))
{
returnm_uMxId;
}
//设置Volume的滑动条的范围这里只以Volume为例。
m_SliderWaveL.SetRange(0,MAX_VOL_VALUE,TRUE);
m_SliderWaveR.SetRange(0,MAX_VOL_VALUE,TRUE);
接着我先演示一下如何获取和设置录音设备的左右声道的音量值,以及如何静音放音设备,这里以Volume为例,其他的设备类似,你可以照着我的代码,套用即可。
1、如何获取Volume设备的音量大小
DWORDdwLValue;
DWORDdwRValue;
GetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,&dwLValue,&dwRValue);
//GetVolume函数的定义见下面,然后根据返回的值调整滑动条的位置
m_SliderVolR.SetPos(MAX_VOL_VALUE-dwLValue);
m_SliderVolL.SetPos(MAX_VOL_VALUE-dwRValue);
2、如何根据滑动条的位置来调整系统音量的大小
voidCMixerControlDlg:
:
OnVScroll(UINTnSBCode,UINTnPos,CScrollBar*pScrollBar)
{
//m_dwSpkR和m_dwSpkL是用来记录Volume左右声道的音量值,0~~65535
CSliderCtrl*pSlider=(CSliderCtrl*)pScrollBar;
intnValue=MAX_VOL_VALUE-pSlider->GetPos();//获取滑动条的位置pos
elseif(m_SliderVolR.m_hWnd==pSlider->m_hWnd)
{
//如果拖动的是Volume的左声道
m_dwSpkR=nValue;
//设置Volume的音量值
SetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,m_dwSpkL,m_dwSpkR);
}
elseif(m_SliderVolL.m_hWnd==pSlider->m_hWnd)
{
//Volume右声道
m_dwSpkL=nValue;
//设置Volume的音量值
SetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,m_dwSpkL,m_dwSpkR);
}
//其他音频线路可以依次类推在下面添加
}
GetVolume和SetVolume函数的定义下面给出
BOOLCMixer:
:
SetVolume(DWORDdwSrcType,DWORDdwLValue,DWORDdwRValue,BOOLbMono)
{
MIXERLINEmxl;
if(!
GetLineInfo(&mxl,MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,dwSrcType))
returnFALSE;
MIXERCONTROLmxc;
if(!
GetLineControl(&mxc,&mxl,MIXERCONTROL_CONTROLTYPE_VOLUME))
returnFALSE;
MIXERCONTROLDETAILSmxcd;
MIXERCONTROLDETAILS_UNSIGNEDmxcd_u1;
MIXERCONTROLDETAILS_UNSIGNEDmxcd_u[2];
mxcd.cbStruct=sizeof(mxcd);
mxcd.dwControlID=mxc.dwControlID;
mxcd.cMultipleItems=0;
if(bMono)
{
mxcd.cChannels=1;
mxcd.cbDetails=sizeof(mxcd_u1);
mxcd.paDetails=&mxcd_u1;
mxcd_u1.dwValue=dwLValue;
}
else
{
mxcd.cChannels=mxl.cChannels;
mxcd.cbDetails=sizeof(*mxcd_u);
mxcd.paDetails=mxcd_u;
mxcd_u[0].dwValue=dwLValue;
mxcd_u[1].dwValue=dwRValue;
}
if(!
SetControlDetails(&mxcd,MIXER_OBJECTF_MIXER))
returnFALSE;
returnTRUE;
}
BOOLCMixer:
:
GetVolume(DWORDdwSrcType,DWORD*pdwLValue,DWORD*pdwRValue,BOOLbMono)
{
MIXERLINEmxl;
if(!
GetLineInfo(&mxl,MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,dwSrcType))
returnFALSE;
MIXERCONTROLmxc;
if(!
GetLineControl(&mxc,&mxl,MIXERCONTROL_CONTROLTYPE_VOLUME))
returnFALSE;
MIXERCONTROLDETAILSmxcd;
MIXERCONTROLDETAILS_UNSIGNEDmxcd_u1;
MIXERCONTROLDETAILS_UNSIGNEDmxcd_u[2];
mxcd.cbStruct=sizeof(mxcd);
mxcd.dwControlID=mxc.dwControlID;
mxcd.cMultipleItems=0;
if(bMono)
{
mxcd.cChannels=1;
mxcd.cbDetails=sizeof(mxcd_u1);
mxcd.paDetails=&mxcd_u1;
if(!
GetControlDetails(&mxcd,MIXER_GETCONTROLDETAILSF_VALUE))
returnFALSE;
*pdwLValue=mxcd_u1.dwValue;
}
else
{
mxcd.cChannels=mxl.cChannels;
mxcd.cbDetails=sizeof(*mxcd_u);
mxcd.paDetails=mxcd_u;
if(!
GetControlDetails(&mxcd,MIXER_GETCONTROLDETAILSF_VALUE))
returnFALSE;
*pdwLValue=mxcd_u[0].dwValue;
*pdwRValue=mxcd_u[1].dwValue;
}
returnTRUE;
}
BOOLGetLineInfo(LPMIXERLINEpmxl,DWORDdwDstType,DWORDdwSrcType)
{
MIXERCAPSmxcaps;
if(!
GetDevCaps(&mxcaps))
returnFALSE;
UINTu=0;
do
{
pmxl->cbStruct=sizeof(*pmxl);
pmxl->dwDestination=u;
u++;
if(MMSYSERR_NOERROR!
=mixerGetLineControls((HMIXEROBJ)m_uMxId,pmxl,MIXER_GETLINEINFOF_DESTINATION))
{
returnFALSE;
}
}while((udwComponentType!
=dwDstType));
if(u>mxcaps.cDestinations)
returnFALSE;
if(dwDstType==dwSrcType)
returnTRUE;
pmxl->dwDestination=u;
UINTcConnections=(UINT)pmxl->cConnections;
UINTv=0;
u--;
do
{
pmxl->cbStruct=sizeof(*pmxl);
pmxl->dwDestination=u;
pmxl->dwSource=v;
v++;
if(MMSYSERR_NOERROR!
=mixerGetLineControls((HMIXEROBJ)m_uMxId,pmxl,MIXER_GETLINEINFOF_SOURCE))
{
returnFALSE;
}
}while((vdwComponentType!
=dwSrcType));
if((v>cConnections)||(pmxl->dwComponentType!
=dwSrcType))
returnFALSE;
returnTRUE;
}
BOOLGetLineControl(LPMIXERCONTROLpmxc,LPMIXERLINEpmxl,DWORDdwType)
{
LPMIXERCONTROLpamxctrl;
DWORDcbmxctrls=sizeof(*pamxctrl)*(UINT)pmxl->cControls;
pamxctrl=(LPMIXERCONTROL)LocalAlloc(LPTR,cbmxctrls);
MIXERLINECONTROLSmxlc;
mxlc.cbStruct=sizeof(mxlc);
mxlc.dwLineID=pmxl->dwLineID;
mxlc.dwControlType=dwType;
mxlc.cControls=pmxl->cControls;
mxlc.cbmxctrl=sizeof(*pamxctrl);
mxlc.pamxctrl=pamxctrl;
if(MMSYSERR_NOERROR!
=mixerGetControlDetails((HMIXEROBJ)m_uMxId,&mxlc,MIXER_GETLINECONTROLSF_ONEBYTYPE))
{
returnFALSE;
}
memcpy(pmxc,pamxctrl,sizeof(*pamxctrl));
LocalFree(pamxctrl);
returnTRUE;
}
进入讨论组讨论。
3、下面演示一下如何设置Volume设备的静音
这里提供了两个函数,GetMute用来获取系统设置中是否对某个音频线路进行了静音操作,SetMute是用来对系统的某个音频线路进行静音操作。
BOOLCMixer:
:
SetMute(DWORDdwSrcType,BOOLbValue)
{
MIXERLINEmxl;
if(!
GetLineInfo(&mxl,MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,dwSrcType))
returnFALSE;
MIXERCONTROLmxc;
if(!
GetLineControl(&mxc,&mxl,MIXERCONTROL_CONTROLTYPE_MUTE))
returnFALSE;
MIXERCONTROLDETAILSmxcd;
MIXERCONTROLDETAILS_BOOLEANmxcd_f;
mxcd.cbStruct=sizeof(mxcd);
mxcd.dwControlID=mxc.dwControlID;
mxcd.cChannels=1;
mxcd.cMultipleItems=0;
mxcd.cbDetails=sizeof(mxcd_f);
mxcd.paDetails=&mxcd_f;
mxcd_f.fValue=bValue;
if(!
SetControlDetails(&mxcd,MIXER_OBJECTF_MIXER))
returnFALSE;
returnTRUE;
}
BOOLCMixer:
:
GetMute(DWORDdwSrcType,BOOL*pbValue)
{
MIXERLINEmxl;
if(!
GetLineInfo(&mxl,MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,dwSrcType))
returnFALSE;
MIXERCONTROLmxc;
if(!
GetLineControl(&mxc,&mxl,MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT))
returnFALSE;
MIXERCONTROLDETAILSmxcd;
MIXERCONTROLDETAILS_BOOLEANmxcd_f;
mxcd.cbStruct=sizeof(mxcd);
mxcd.dwControlID=mxc.dwControlID;
mxcd.cChannels=1;
mxcd.cMultipleItems=0;
mxcd.cbDetails=sizeof(mxcd_f);
mxcd.paDetails=&mxcd_f;
if(!
GetControlDetails(&mxcd,MIXER_GETCONTROLDETAILSF_VALUE))
returnFALSE;
*pbValue=mxcd_f.fValue;
returnTRUE;
}
如果用这两个函数呢,下面我演示了如何设置和获取Volume音频线路的静音操作。
BOOLbValue=TRUE;
SetMute(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,bValue);
GetMute(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,&bValue);
4、下面看看当系统的设置改变时,mixer是如何通知我们的吧。
还记得我前面讲过的,当我们调用mixeropen时可以传递一个窗口的句柄作为回调窗口,当系统的设置改变,比如音量改变,某个音频线路被静音时,mixer都会给我们的回调窗口发送消息的。
一般只有两个消息,如下
afx_msgvoidOnMLChange(WPARAMwParam,LPARAMlParam);
afx_msgvoidOnMCChange(WPARAMwParam,LPARAMlParam);
ON_MESSAGE(MM_MIXM_LINE_CHANGE,OnMLChange)
ON_MESSAGE(MM_MIXM_CONTROL_CHANGE,OnMCChange)
其中MM_MIXM_CONTROL_CHANGE消息中,发送消息的两个参数代表的意思如下
wParam=(WPARAM)hMixer
lParam=(LPARAM)dwControlID
在MM_MIXM_LINE_CHANGE消息中,发送消息的参数代表的意思如下
wParam=(WPARAM)hMixer
lParam=(LPARAM)dwLineID
在我们的应用程序中,我们可以在这两个消息处理函数中调整我们的设置,以对应于系统的改变,比如你的代码可以这样写:
voidCMixerControlDlg:
:
OnMCChange(WPARAMwParam,LPARAMlParam)
{
DWORDdwLValue;
DWORDdwRValue;
GetVolume(MIXERLINE_COMPONENTTYPE_DST_SPEAKERS,&dwLValue,&dwRValue);
//GetVolume函数的定义见下面,然后根据返回的值调整滑动条的位置
m_SliderVolR.SetPos(MAX_VOL_VALUE-dwLValue);
m_SliderVolL.SetPos(MAX_VOL_VALUE-dwRValue);
//你也可以在这里调用GetM