上一次要用到音频已经是好几年前的事情了(毕竟本人是搞图象处理的)。当时写了一篇总结博客,没想到很多人看了,其中还有些在下载的地方和博客中问了些问题,虽然很想作答,但因为实在是忘了所以就没说什么。
最近又有项目要用到录制音频的功能,索性就把之前留下的双缓存坑填了。其实原理跟之前的差不多,最大的不同在于用到了回调函数。另外,本篇的代码基本上是参考这篇博客的,本人只修改了一部分,如有雷同,绝非偶然。
下面直接上代码,然后最后有整个工程的下载。
头文件和链接库如下:
#include
#include
#pragma comment(lib, "winmm.lib")
变量和函数声明如下:
bool win;
FILE *f;
HWAVEIN hWaveIn;
WAVEFORMATEX waveform;
BYTE *pBuffer1, *pBuffer2;
WAVEHDR wHdr1, wHdr2;
static DWORD CALLBACK MicCallback(HWAVEIN hWaveIn,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2);
初始化并开始录音的代码如下:
fopen_s(&f, "录音测试.pcm", "wb");
win = true;
waveform.wFormatTag = WAVE_FORMAT_PCM;
waveform.nSamplesPerSec = 8000;
waveform.wBitsPerSample = 16;
waveform.nChannels = 1;
waveform.nAvgBytesPerSec = 16000 * 4;
waveform.nBlockAlign = 2;
waveform.cbSize = 0;
MMRESULT mmr = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform,
(DWORD)(MicCallback), DWORD(this), CALLBACK_FUNCTION);
if (mmr != MMSYSERR_NOERROR)
return;
DWORD bufsize = 8 * 1024;
pBuffer1 = new BYTE[bufsize];
pBuffer2 = new BYTE[bufsize];
wHdr1.lpData = (LPSTR)pBuffer1;
wHdr1.dwBufferLength = bufsize;
wHdr1.dwBytesRecorded = 0;
wHdr1.dwUser = 0;
wHdr1.dwFlags = 0;
wHdr1.dwLoops = 1;
wHdr1.lpNext = NULL;
wHdr1.reserved = 0;
waveInPrepareHeader(hWaveIn, &wHdr1, sizeof(WAVEHDR));
wHdr2.lpData = (LPSTR)pBuffer2;
wHdr2.dwBufferLength = bufsize;
wHdr2.dwBytesRecorded = 0;
wHdr2.dwUser = 0;
wHdr2.dwFlags = 0;
wHdr2.dwLoops = 1;
wHdr2.lpNext = NULL;
wHdr2.reserved = 0;
waveInPrepareHeader(hWaveIn, &wHdr2, sizeof(WAVEHDR));
waveInAddBuffer(hWaveIn, &wHdr1, sizeof(WAVEHDR));
waveInAddBuffer(hWaveIn, &wHdr2, sizeof(WAVEHDR));
waveInStart(hWaveIn);
回调函数如下:
DWORD CALLBACK CPCMCollectProgramDouBufDlg::MicCallback(HWAVEIN hwavein, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
//这个CIMAADPCMDlg就是你的音频采集类
CPCMCollectProgramDouBufDlg*pWnd = (CPCMCollectProgramDouBufDlg*)dwInstance;
switch (uMsg)
{
case WIM_OPEN:
TRACE("WIM_OPEN\n");
break;
case WIM_DATA:
TRACE("WIM_DATA\n");
//采集到的数据做处理
//((PWAVEHDR)dwParam1)->lpData是采集到的数据指针
//((PWAVEHDR)dwParam1)->dwBytesRecorded是采集到的数据长度
//将采集到的数据写入文件中
fwrite(((PWAVEHDR)dwParam1)->lpData, ((PWAVEHDR)dwParam1)->dwBytesRecorded, 1, pWnd->f);
//处理完了之后还要再把这个缓冲数组加回去
//pWnd->win代表是否继续采集,因为当停止采集的时候,只有当所有的
//缓冲数组都腾出来之后才能close,所以需要停止采集时就不要再waveInAddBuffer了
if (pWnd->win)
waveInAddBuffer(hwavein, (PWAVEHDR)dwParam1, sizeof(WAVEHDR));
break;
case WIM_CLOSE:
TRACE("WIM_CLOSE\n");
break;
default:
break;
}
return 0;
}
关闭代码如下:
win = false;
Sleep(2000);
waveInClose(hWaveIn);
fclose(f);
如果是初学者看不懂,可以直接下载整个工程慢慢研究。
地址在这
录制出来的PCM文件如果不知道怎么播放出来,请移步这里。