使用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);//播放 } }