windows录音教程

来源:互联网 发布:js实现word预览 编辑:程序博客网 时间:2024/06/07 02:28

一、录音的基本流程:


这个流程图可能不太准确,具体的看下面的分析吧

二、具体步骤

1.使用waveInOpen()函数打开一个音频设备:

HWAVEIN hWavein;WAVEFORMATEX waveFormat;  //音频格式waveFormat.wFormatTag = WAVE_FORMAT_PCM;waveFormat.nChannels = 1;  //单声道waveFormat.nSamplesPerSec = SAMPLESPERSEC;  //采样率waveFormat.nAvgBytesPerSec = SAMPLESPERSEC * 2;waveFormat.nBlockAlign = 2;  //最小的块大小waveFormat.wBitsPerSample = BITSPERSAMPLE;  //采样精度DWORD nThreadID;HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)waveInProc, NULL, 0, &nThreadID);if (hThread == INVALID_HANDLE_VALUE){printf("创建线程失败!\n");longjmp(jmpBuf, GetLastError());}MMRESULT ret = waveInOpen(&hWavein, 0, &waveFormat, nThreadID, 0, CALLBACK_THREAD);  //这里我们采用线程回调的方式

我们需要在waveInOpen()函数的第二个参数中指定设备的ID,这里我们给了0表示打开系统中第一个麦克风

2.使用waveInPrepareHeader()和waveInAddBuffer()添加缓冲区:

for (int i = 0; i < 4; ++i)  //这里我们初始化4块缓冲区{WAVEHDR* pWaveHdr = malloc(sizeof(WAVEHDR));RtlZeroMemory(pWaveHdr, sizeof(WAVEHDR));pWaveHdr->lpData = malloc(DATASIZE);pWaveHdr->dwBufferLength = DATASIZE;pWaveHdr->dwFlags = 0;ret = waveInPrepareHeader(hWavein, pWaveHdr, sizeof(WAVEHDR));if (ret != MMSYSERR_NOERROR){printf("准备缓冲区失败!\n");longjmp(jmpBuf, GetLastError());}ret = waveInAddBuffer(hWavein, pWaveHdr, sizeof(WAVEHDR));if (ret != MMSYSERR_NOERROR){printf("加入缓冲区失败!\n");longjmp(jmpBuf, GetLastError());}}

建议在这里至少添加4块缓冲区,注意结构体WAVEHDR中有三个参数是需要我们进行初始化的,lpData表示存放音频块的大小,这里我们给的是6400个字节,dwBufferLength表示lpData的大小,dwFlags给0即可,之后即可将该结构体添加进去。注意:这里的结构体需要在堆上申请内存,不要在这里使用局部变量。

3.使用waveInStart()
waveInStart()之后,程序就开始录音了,当一块音频区满后,会产生MM_WIM_DATA消息(如果你在waveInOpen那里使用的是回调函数,这个消息是WIM_DATA),在这个消息中我们将音频块的内容取出,并重新将这个音频块加入到设备中。
case MM_WIM_DATA:  //缓冲区录满的消息,在这里取数据,并重新添加缓冲区hWavein = (HWAVEIN)msg.wParam;pWavehdr = (WAVEHDR*)msg.lParam;int nWrite = fwrite(pWavehdr->lpData, 1,pWavehdr->dwBytesRecorded, g_pFile);printf("dwBytesRecorded:%d, dwBufferLength: %d\n", pWavehdr->dwBytesRecorded, pWavehdr->dwBufferLength);if (g_bWaveStatus){ret = waveInAddBuffer(hWavein, pWavehdr, sizeof(WAVEHDR));if (ret != MMSYSERR_NOERROR){printf("再次加入缓冲区失败!\n");longjmp(callBackJmp, GetLastError());}}

这样我们就可以源源不断的一直在录音了,那么如何结束录音并释放缓冲区昵,下面开始进行结束录音:

4.使用waveInStop()、waveInReset()和waveInUnprepareHeader()

先使用waveInStop(),它会立即停止录音,停止录音的同时,肯定有一块缓冲区正在被使用,它不管这块缓冲区有没有满,直接将这块缓冲区发送给相应的接收程序(就是我们可以在MM_WIM_DATA中收到这块缓冲区),那么我们如何知道这块缓冲区到底被使用了多少昵?在WAVEHDR结构体中,有一个dwBytesRecorded变量会指示这块缓冲区被使用了多少,一般这个值是等于dwBufferLength的,但是当我们使用waveInStop()后,我们可以通过dwBytesRecorded了解缓冲区被使用的大小,所以我们应该尽量以dwBytesRecorded为准。之后我们就可以使用waveInUnprepareHeader()来释放掉这块缓冲区,也不要在把这块缓冲区加入进去了。

这样我们就释放掉一块缓冲区了,但是我们在开始的时候一共申请了4块缓冲区,还有3块怎么办昵?

这时我们需要使用waveInReset()将其他没有被使用的缓冲区直接发送给接收程序(就是我们可以在MM_WIM_DATA中收到这些缓冲区),之后在调用waveInUnprepareHeader()。
下面这张图充分的说明了这一切:


5.使用waveInClose()结束一切。


0 0