使用WindowsAPI获取录音音频的方法
本文实例介绍了使用winmm.h进行音频流的获取的方法,具体步骤如下:
一、首先需要包含以下引用对象
#include<Windows.h> #include"mmsystem.h" #pragmacomment(lib,"winmm.lib")
二、音频的获取需要调用7个函数
1.waveInGetNumDevs:返回系统中就绪的波形声音输入设备的数量
UINTwaveInGetNumDevs(VOID);
2.waveInGetDevCaps:检查指定波形输入设备的特性
MMRESULTwaveInGetDevCaps( UINT_PTRuDeviceID, LPWAVEINCAPSpwic, UINTcbwic ); //uDeviceID音频输入设备标识,也可以为一个打开的音频输入设备的句柄. //个人认为如果上一步获得了多个设备,可以用索引标识每一个设备. // //pwic对WAVEINCAPS结构体的一个指针,包含设备的音频特性. // //cbwicWAVEINCAPS结构体的大小,使用sizeof即可. // //MMRESULT函数执行的结果 //MMSYSERR_NOERROR表示执行成功 //MMSYSERR_BADDEVICEID索引越界 //MMSYSERR_NODRIVER没有就绪的设备 //MMSYSERR_NOMEM不能分配或者锁定内存
介绍WAVEINCAPS结构体的含义:
typedefstruct{
WORDwMid;//音频设备制造商定义的驱动程序标识
WORDwPid;//音频输入设备的产品标识
MMVERSIONvDriverVersion;//驱动程序版本号
TCHARszPname[MAXPNAMELEN];//制造商名称
DWORDdwFormats;//支持的格式,参见MSDN
WORDwChannels;//支持的声道数
WORDwReserved1;//保留参数
}WAVEINCAPS;
3.waveInOpen:打开指定的音频输入设备,进行录音
MMRESULTwaveInOpen( LPHWAVEINphwi,//接收打开的音频输入设备标识的HWAVEIN结构的指针 UINT_PTRuDeviceID,//指定一个需要打开的设备标识.可以使用WAVE_MAPPER选择一个按指定录音格式录音的设备 LPWAVEFORMATEXpwfx,//一个所需的格式进行录音的WAVEFORMATEX结构的指针 DWORD_PTRdwCallback,//指向一个回调函数、事件句柄、窗口句柄、线程标识,对录音事件进行处理. DWORD_PTRdwCallbackInstance,//传给回调机制的参数 DWORDfdwOpen//打开设备的方法标识,指定回调的类型.参见CSDN );
介绍WAVEFORMATEX结构体的含义:
typedefstruct{
WORDwFormatTag;//波形声音的格式,单声道双声道使用WAVE_FORMAT_PCM.当包含在WAVEFORMATEXTENSIBLE结构中时,使用WAVE_FORMAT_EXTENSIBLE.
WORDnChannels;//声道数量
DWORDnSamplesPerSec;//采样率.wFormatTag为WAVE_FORMAT_PCM时,有8.0kHz,11.025kHz,22.05kHz,和44.1kHz.
DWORDnAvgBytesPerSec;//每秒的采样字节数.通过nSamplesPerSec*nChannels*wBitsPerSample/8计算
WORDnBlockAlign;//每次采样的字节数.通过nChannels*wBitsPerSample/8计算
WORDwBitsPerSample;//采样位数.wFormatTag为WAVE_FORMAT_PCM时,为8或者16
WORDcbSize;//wFormatTag为WAVE_FORMAT_PCM时,忽略此参数
}WAVEFORMATEX;
介绍dwCallback回调函数格式:
voidCALLBACKwaveInProc( HWAVEINhwi,//回调此函数的设备句柄 UINTuMsg,//波形声音输入信息,标识关闭(WIM_CLOSE)、缓冲区满(WIM_DATA)、打开(WIM_OPEN). DWORD_PTRdwInstance,//用户在waveInOpen指定的数据 DWORD_PTRdwParam1,//(LPWAVEHDR)dwParam1,用户指定的缓冲区 DWORD_PTRdwParam2 );
4.waveInPrepareHeader:为音频输入设备准备一个缓冲区
MMRESULTwaveInPrepareHeader( HWAVEINhwi,//音频输入设备句柄 LPWAVEHDRpwh,//指向WAVEHDR结构的指针,标识准备的缓冲区 UINTcbwh//WAVEHDR结构的大小,使用sizeof即可 );
介绍WAVEHDR结构:
typedefstructwavehdr_tag{
LPSTRlpData;//指向波形格式的缓冲区
DWORDdwBufferLength;//缓冲区的大小
DWORDdwBytesRecorded;//当前存储了多少数据
DWORD_PTRdwUser;//用户数据
DWORDdwFlags;//为缓冲区提供的信息,在waveInPrepareHeader函数中使用WHDR_PREPARED
DWORDdwLoops;//输出时使用,标识播放次数
structwavehdr_tag*lpNext;//reserved
DWORD_PTRreserved;//reserved
}WAVEHDR,*LPWAVEHDR;
5.waveInAddBuffer:将缓冲区发送给设备,若缓冲区填满,则不起作用。(参数同上)
MMRESULTwaveInAddBuffer( HWAVEINhwi, LPWAVEHDRpwh, UINTcbwh );
6.waveInStart:开始进行录制
MMRESULTwaveInStart( HWAVEINhwi//设备句柄 );
7.waveInClose:关闭设备
MRESULTwaveInClose( HWAVEINhwi//设备句柄 );
三、完整实例代码如下:
//Run.c文件
#include<Windows.h>
#include<stdio.h>
#include"mmsystem.h"
#pragmacomment(lib,"winmm.lib")
voidPlayMusi();
voidWaveInitFormat(LPWAVEFORMATEXm_WaveFormat,WORDnCh,DWORDnSampleRate,WORDBitsPerSample);
DWORDCALLBACKMicCallback(HWAVEINhwavein,UINTuMsg,DWORDdwInstance,DWORDdwParam1,DWORDdwParam2);
voidRecordWave();
voidmain()
{
//PlayMusi();
RecordWave();
while(1);
}
voidRecordWave()
{
intcount=waveInGetNumDevs();//1
printf("\n音频输入数量:%d\n",count);
WAVEINCAPSwaveIncaps;
MMRESULTmmResult=waveInGetDevCaps(0,&waveIncaps,sizeof(WAVEINCAPS));//2
printf("\n音频输入设备:%s\n",waveIncaps.szPname);
if(MMSYSERR_NOERROR==mmResult)
{
HWAVEINphwi;
WAVEFORMATEXpwfx;
WaveInitFormat(&pwfx,1,8000,8);
printf("\n请求打开音频输入设备");
printf("\n采样参数:单声道8kHz8bit\n");
mmResult=waveInOpen(&phwi,WAVE_MAPPER,&pwfx,(DWORD)(MicCallback),NULL,CALLBACK_FUNCTION);//3
if(MMSYSERR_NOERROR==mmResult)
{
WAVEHDRpwh1;
charbuffer1[10240];
pwh1.lpData=buffer1;
pwh1.dwBufferLength=10240;
pwh1.dwUser=1;
pwh1.dwFlags=0;
mmResult=waveInPrepareHeader(phwi,&pwh1,sizeof(WAVEHDR));//4
printf("\n准备缓冲区1");
WAVEHDRpwh2;
charbuffer2[10240];
pwh2.lpData=buffer2;
pwh2.dwBufferLength=10240;
pwh2.dwUser=2;
pwh2.dwFlags=0;
mmResult=waveInPrepareHeader(phwi,&pwh2,sizeof(WAVEHDR));//4
printf("\n准备缓冲区2\n");
if(MMSYSERR_NOERROR==mmResult)
{
mmResult=waveInAddBuffer(phwi,&pwh1,sizeof(WAVEHDR));//5
printf("\n将缓冲区1加入音频输入设备");
mmResult=waveInAddBuffer(phwi,&pwh2,sizeof(WAVEHDR));//5
printf("\n将缓冲区2加入音频输入设备\n");
if(MMSYSERR_NOERROR==mmResult)
{
mmResult=waveInStart(phwi);//6
printf("\n请求开始录音\n");
}
}
}
}
}
DWORDCALLBACKMicCallback(HWAVEINhwavein,UINTuMsg,DWORDdwInstance,DWORDdwParam1,DWORDdwParam2)
{
switch(uMsg)
{
caseWIM_OPEN:
printf("\n设备已经打开...\n");
break;
caseWIM_DATA:
printf("\n缓冲区%d存满...\n",((LPWAVEHDR)dwParam1)->dwUser);
waveInAddBuffer(hwavein,(LPWAVEHDR)dwParam1,sizeof(WAVEHDR));
break;
caseWIM_CLOSE:
printf("\n设备已经关闭...\n");
break;
default:
break;
}
return0;
}
voidWaveInitFormat(LPWAVEFORMATEXm_WaveFormat,WORDnCh,DWORDnSampleRate,WORDBitsPerSample)
{
m_WaveFormat->wFormatTag=WAVE_FORMAT_PCM;
m_WaveFormat->nChannels=nCh;
m_WaveFormat->nSamplesPerSec=nSampleRate;
m_WaveFormat->nAvgBytesPerSec=nSampleRate*nCh*BitsPerSample/8;
m_WaveFormat->nBlockAlign=m_WaveFormat->nChannels*BitsPerSample/8;
m_WaveFormat->wBitsPerSample=BitsPerSample;
m_WaveFormat->cbSize=0;
}
voidPlayMusi()
{
interror=mciSendString("openC:\\Users\\Angel\\Desktop\\有多少爱可以重来.mp3aliasmyDivece",NULL,0,NULL);
if(error==0)
{
mciSendString("playmyDivece",NULL,0,NULL);//播放
}
}