C语言-从声卡录音的一个demo
/* http://sdr-reu.wikispaces.com/file/view/SoundIn.c File to read sound from sound card and record it to a file in PCM format. */ #include <windows.h> #include <mmsystem.h> #include <stdio.h> #include <conio.h> #pragma comment(lib, "winmm.lib") #define IN_BUFFERS_NUMBER 4 //开辟三个数据缓冲区 #define REC_STATUS_STARTING_RECORD 1 #define REC_STATUS_RECORDING 2 #define REC_STATUS_ALL_DONE -2 //录音完成 #define REC_STATUS_FINISHING -1 //即将完成 #define REC_STATUS_FAIL -3 #define SIZE_OF_WAVEHDR 32 //wave头大小 //函数 void FreeBuffers(WAVEHDR * buffers); DWORD WINAPI waveInProc(LPVOID threadControls); typedef struct soundInDataAndControls { WAVEHDR buffers[IN_BUFFERS_NUMBER]; //开辟三个数据缓冲区 int recordingStatus; //录音状态 HWAVEIN inWaveDevice; int buffers_left; //可用内存数目 }SoundThreadInfo; WAVEFORMATEX sampleFormat; //全局变量 char * outfilename; HMMIO m_hFile; MMCKINFO m_MMCKInfoData; MMCKINFO m_MMCKInfoParent; MMCKINFO m_MMCKInfoChild; int main() { MMRESULT errorResult = 0 ; SoundThreadInfo soundIn; HANDLE inWaveThreadHandle; //线程 int x = 0; //计数器 soundIn.recordingStatus = 0; //设置录音状态 soundIn.buffers_left = IN_BUFFERS_NUMBER; //设置预期缓冲数量 outfilename = ".\\1.wav"; inWaveThreadHandle = CreateThread(0 ,0,(LPTHREAD_START_ROUTINE)waveInProc,/*参数*/ &soundIn, 0, &errorResult); //创建线程 if(!inWaveThreadHandle) { printf("Can't create sound in thread! -- %08X\n",GetLastError()); return 0; } CloseHandle(inWaveThreadHandle); //关闭线程 for (x = 0; x<IN_BUFFERS_NUMBER; x++) //清空缓存 { ZeroMemory(&soundIn.buffers[x], SIZE_OF_WAVEHDR); } //设置 waveFormat sampleFormat.wFormatTag = WAVE_FORMAT_PCM; sampleFormat.nChannels = 2; //声道 sampleFormat.nSamplesPerSec = 44100; sampleFormat.wBitsPerSample = 16; sampleFormat.nBlockAlign = sampleFormat.nChannels * (sampleFormat.wBitsPerSample >> 3); sampleFormat.nAvgBytesPerSec = sampleFormat.nSamplesPerSec * sampleFormat.nBlockAlign; if(!CreateWaveFile()) { return getchar(); } //分配 memory sound in buffers. for(x = 0; x < IN_BUFFERS_NUMBER; x++) //this loop is not need after testing { //can be replaced with hard coded buffer allocation //clear waveheaders ZeroMemory(&soundIn.buffers[x],SIZE_OF_WAVEHDR); soundIn.buffers[x].dwBufferLength = sampleFormat.nAvgBytesPerSec << 2; //内存大小估计一块 soundIn.buffers[x].dwFlags = 0; soundIn.buffers[x].lpData = (char *) VirtualAlloc(NULL, soundIn.buffers[0].dwBufferLength, MEM_COMMIT, PAGE_READWRITE); //申请内存 if(soundIn.buffers[x].lpData == NULL) { printf("Sound In Buffer number %d failed to get allocate memory.\n",x); for(--x;x;x--) // start 1 down, and while x!=0 x-- { VirtualFree(soundIn.buffers[x].lpData, 0, MEM_RELEASE); //释放内存 } return 0; } else { printf(" %d Buffer Application sucsess\n",x); } } //open wave device errorResult = waveInOpen(&soundIn.inWaveDevice, WAVE_MAPPER, &sampleFormat, (DWORD)errorResult, 0, CALLBACK_THREAD); if(errorResult != MMSYSERR_NOERROR) { FreeBuffers(soundIn.buffers); return getchar(); } // buffers and queue them for(x=0;x<IN_BUFFERS_NUMBER;x++) { errorResult = waveInPrepareHeader(soundIn.inWaveDevice, &soundIn.buffers[x],SIZE_OF_WAVEHDR); if(errorResult != MMSYSERR_NOERROR) { printf("Failed to prepare header %d. Error %d\n",x,errorResult); //fprintf(std,"Last was %s FreeBuffers(soundIn.buffers); errorResult= waveInClose(soundIn.inWaveDevice); if(errorResult) { printf("Can't Close Wave Device!\n"); getchar(); } return 0; } errorResult = waveInAddBuffer(soundIn.inWaveDevice, &soundIn.buffers[x],SIZE_OF_WAVEHDR); if(errorResult != MMSYSERR_NOERROR ) { printf("Failed to queue wave buffer %d.\n",x); soundIn.buffers_left--; if(soundIn.buffers_left < 2) { FreeBuffers(soundIn.buffers); errorResult= waveInClose(soundIn.inWaveDevice); if(errorResult) { printf("Can't Close Wave Device!\n"); getchar(); } return 0; } } } //set record flag printf("Hit any key to begin recording.\n"); getchar(); soundIn.recordingStatus = 1; //1 == starting recording //start recording errorResult = waveInStart(soundIn.inWaveDevice); if(errorResult == MMSYSERR_NOERROR) { //wait for user to stop recording printf("Hit any key to stop recording.\n"); getchar(); soundIn.recordingStatus = REC_STATUS_FINISHING; } else { //Recording never started. soundIn.recordingStatus = REC_STATUS_ALL_DONE; } //reset headers waveInReset(soundIn.inWaveDevice); //this should send a MM_WIM_DONE for each of the buffers/headers //wait thread while( (soundIn.recordingStatus != REC_STATUS_ALL_DONE) ) //status -2 is finished { Sleep(100); //tenth of a second printf("Waiting for all done.\n"); printf("Recording status = %d\n",soundIn.recordingStatus); } //un prepare the buffers for(x=0;x<IN_BUFFERS_NUMBER;x++) { errorResult = waveInUnprepareHeader(soundIn.inWaveDevice, &soundIn.buffers[x], SIZE_OF_WAVEHDR); if(errorResult != 0) { printf("Failed to unprepare wave header.\n"); } } //deallocate memory FreeBuffers(soundIn.buffers); mmioAscend(m_hFile, &m_MMCKInfoChild, 0); mmioAscend(m_hFile, &m_MMCKInfoParent, 0); //close wave device errorResult= waveInClose(soundIn.inWaveDevice); if(errorResult) { printf("Can't Close Wave Device!\n"); getchar(); } return getchar(); } void FreeBuffers(WAVEHDR * buffers) { int x; for(x=0;x<IN_BUFFERS_NUMBER;x++) { VirtualFree(buffers[x].lpData, 0, MEM_RELEASE); //zero meams all memory } } int CreateWaveFile() { MMRESULT mmResult = 0; ZeroMemory(&m_MMCKInfoParent,sizeof(MMCKINFO)); ZeroMemory(&m_MMCKInfoChild,sizeof(MMCKINFO)); ZeroMemory(&m_MMCKInfoData,sizeof(MMCKINFO)); m_hFile = mmioOpen(outfilename,NULL, MMIO_CREATE|MMIO_WRITE|MMIO_EXCLUSIVE | MMIO_ALLOCBUF); if(m_hFile == NULL) { return getchar(); } m_MMCKInfoParent.fccType = mmioFOURCC('W','A','V','E'); mmResult = mmioCreateChunk( m_hFile,&m_MMCKInfoParent, MMIO_CREATERIFF); m_MMCKInfoChild.ckid = mmioFOURCC('f','m','t',' '); m_MMCKInfoChild.cksize = sizeof(WAVEFORMATEX) + sampleFormat.cbSize; mmResult = mmioCreateChunk(m_hFile, &m_MMCKInfoChild, 0); mmResult = mmioWrite(m_hFile, (char*)&sampleFormat, sizeof(WAVEFORMATEX) + sampleFormat.cbSize); mmResult = mmioAscend(m_hFile, &m_MMCKInfoChild, 0); m_MMCKInfoChild.ckid = mmioFOURCC('d', 'a', 't', 'a'); mmResult = mmioCreateChunk(m_hFile, &m_MMCKInfoChild, 0); return 1; } DWORD WINAPI waveInProc(void *threadControls) { MSG msg; SoundThreadInfo *inFORMATION = (SoundThreadInfo *) threadControls; MMRESULT errorResult; int outputlenth = 0; while(GetMessage(&msg,0,0,0)== 1) //得到一消息 { if (msg.message == MM_WIM_DATA ) { printf("Data amount %d\n",((WAVEHDR *)msg.lParam)->dwBytesRecorded); //collect data if(inFORMATION->recordingStatus != 0) //recording not began or stopped只有0 ,-1 -2 三个值 { if(inFORMATION->recordingStatus == REC_STATUS_ALL_DONE) { printf("Possible error recieving WIM_DATA during condition ALL_DONE\n"); break; //time for thread to end } outputlenth = mmioWrite(m_hFile, ((WAVEHDR *) msg.lParam)->lpData,((WAVEHDR *)msg.lParam)->dwBytesRecorded); if(outputlenth == ((WAVEHDR *)msg.lParam)->dwBytesRecorded) { printf("sucsess save data_dwBytesRecorded %d\n",outputlenth); printf("sucsess save data_dwBufferLength %d\n",((WAVEHDR *)msg.lParam)->dwBufferLength); } //was this that last block the user wanted. if(inFORMATION->recordingStatus == REC_STATUS_FINISHING) { //the buffers are each sent back, but not requeue if(--inFORMATION->buffers_left == 0) { inFORMATION->recordingStatus = REC_STATUS_ALL_DONE; } printf("Buffer finished.\n"); continue; } } //if stopped it only requeue s the buffer and continues. //requeue buffer if(!waveInAddBuffer(inFORMATION->inWaveDevice, (WAVEHDR *) msg.lParam, SIZE_OF_WAVEHDR)) { if(!waveInAddBuffer(inFORMATION->inWaveDevice, (WAVEHDR *) msg.lParam, SIZE_OF_WAVEHDR)) { printf("Buffer requeue error.\n"); if(--inFORMATION->buffers_left < 2) { FreeBuffers(inFORMATION->buffers); printf("in requeue error device."); errorResult = waveInClose(inFORMATION->inWaveDevice); if(errorResult) { printf("Can't Close Wave Device!\n"); getchar(); } return 0; inFORMATION->recordingStatus = REC_STATUS_FINISHING; //finishing means takes the queued blocks and no more //in thoery the next block (the last one) that was queue //previously mmioAscend(m_hFile, &m_MMCKInfoChild, 0); mmioAscend(m_hFile, &m_MMCKInfoParent, 0); return -1; } } } } } return 1; }