在windows 下有一個 winAPI library 可以實現錄音的功能
API 說明可以參考 MSDN 網站:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd743833(v=vs.85).aspx
這裡主要是介紹如何將電腦麥克風的聲音錄起來,
並存成 wav 檔
1.Audio 結構
在聲音的格式中,定義在 WAVEFORMATEX 這個結構中:
typedef struct { WORD wFormatTag; //audio format,這裡使用WAVE_FORMAT_PCM WORD nChannels; //1為單聲道,2為雙聲道 DWORD nSamplesPerSec; //每秒採集的聲音sample數量 DWORD nAvgBytesPerSec; //每秒傳送byte數量 WORD nBlockAlign; //nBlockAlign = (nChannels*wBitsPerSample)/8; WORD wBitsPerSample; //每個sample儲存多少bit的資料,一般為8bit or 16bit WORD cbSize; //額外資訊的大小,通常是non-PCM時,才會用到,這裡設0 } WAVEFORMATEX;
聲音的採集資料,定義在 WAVEHDR 這個結構中:
typedef struct { LPSTR lpData; //buffer的資料 DWORD dwBufferLength; //buffer的長度 DWORD dwBytesRecorded; //buffer的資料大小(bytes) DWORD dwUser; //通常為0 DWORD dwFlags; //描述額外的資料 DWORD dwLoops; //在播放的時候使用 struct wavehdr_tag* lpNext;//應該給link list用 DWORD reserved; //保留 } WAVEHDR;
2.使用API
使用windows API錄音 主要利用到下面函式:
waveInOpen() //開啟錄音裝置 waveInPrepareHeader() //buffer header 準備 waveInAddBuffer() //輸入buffer waveInStart() //開始錄音 waveInStop() //停止錄音 waveInUnprepareHeader() //buffer header 清空 waveInClose() //關閉錄音裝置
3.code ( 含儲存成wav檔 )
#include "stdafx.h" #include "windows.h" #pragma comment(lib, "winmm.lib") //windows API library for wave #define DATASIZE 22050*2*5 //SamplesPerSec * byte per sample * duration time int _tmain(int argc, _TCHAR* argv[]) { HWAVEIN audio_in; WAVEFORMATEX audio_format; //structure of wave format WAVEHDR audio_header; int log; char* soundBuffer[DATASIZE]; audio_format.wFormatTag=WAVE_FORMAT_PCM; audio_format.nChannels=1; audio_format.nSamplesPerSec=22050; audio_format.wBitsPerSample=16; audio_format.cbSize=0; audio_format.nBlockAlign = (audio_format.nChannels * audio_format.wBitsPerSample)/8; audio_format.nAvgBytesPerSec = (audio_format.nSamplesPerSec*audio_format.nBlockAlign); log = waveInOpen(&audio_in,WAVE_MAPPER,&audio_format,NULL,NULL,NULL); //open input device if (log == MMSYSERR_NOERROR) printf("waveInOpen success\n"); else printf("waveInOpen fail\n"); audio_header.dwFlags=0; audio_header.dwUser=0; audio_header.dwLoops=0; audio_header.dwBytesRecorded=0; audio_header.lpData = (LPSTR)soundBuffer; audio_header.dwBufferLength = DATASIZE; //prepare buffer header log = waveInPrepareHeader( audio_in, &audio_header, sizeof(WAVEHDR) ); if (log == MMSYSERR_NOERROR) printf("waveInPrepareHeader success\n"); else printf("waveInPrepareHeader fail\n"); //send buffer to input device log = waveInAddBuffer( audio_in, &audio_header, sizeof(WAVEHDR) ); if (log == MMSYSERR_NOERROR) printf("waveInAddBuffer success\n"); else printf("waveInAddBuffer fail\n"); if (! waveInStart(audio_in) ) //start recording printf("recording start for 5 sec...\nenter any char to stop\n"); else printf("recording fail...\n"); getchar(); if (! waveInStop(audio_in) ) //stop recording printf("recording stop\n"); else printf("recording stop fail\n"); //clean buffer header if(waveInUnprepareHeader(audio_in, &audio_header, sizeof(WAVEHDR))) printf("UnPrepare Header fail\n"); else printf("UnPrepare Header success\n"); Sleep(500); if (waveInClose(audio_in)==MMSYSERR_NOERROR) printf("waveInClose success\n"); else printf("waveInClose fail\n"); //saving as wave file MMCKINFO wav_file_header1; MMCKINFO wav_file_header2; HMMIO wav_file; MMRESULT result; long wav_log; //create wav file wav_file = mmioOpen(L"wavfile.wav",NULL,MMIO_CREATE|MMIO_WRITE|MMIO_EXCLUSIVE | MMIO_ALLOCBUF); if(wav_file == NULL) printf("mmioOpen fail\n"); ZeroMemory(&wav_file_header1, sizeof(MMCKINFO)); wav_file_header1.fccType=mmioFOURCC('W', 'A', 'V', 'E'); result = mmioCreateChunk(wav_file ,&wav_file_header1, MMIO_CREATERIFF); //create RIFF chunk if (result==MMSYSERR_NOERROR) printf("mmioCreateChunk: wav_file_header1 %s ok\n",result); else printf("mmioCreateChunk: wav_file_header1 fail\n"); ZeroMemory(&wav_file_header2, sizeof(MMCKINFO)); wav_file_header2.ckid=mmioFOURCC('f', 'm', 't', ' '); wav_file_header2.cksize=sizeof(WAVEFORMATEX)+audio_format.cbSize; //create fmt chunk result = mmioCreateChunk(wav_file ,&wav_file_header2, 0); if (result==MMSYSERR_NOERROR) printf("mmioCreateChunk wav_file_header2 %s ok\n",result); else printf("mmioCreateChunk wav_file_header2 fail\n"); //輸入fmt chunk的data wav_log = mmioWrite(wav_file ,(char*)&audio_format,sizeof(WAVEFORMATEX)+audio_format.cbSize); if(wav_log==-1) printf( "mmioWrite audio_format fail\n"); else printf( "mmioWrite write %d bytes\n",wav_log); //跳出fmt chunk result = mmioAscend(wav_file,&wav_file_header2,0); if (result==MMSYSERR_NOERROR ) printf( "mmioAscend wav_file_header2 %s ok\n",result); else printf( "mmioAscend wav_file_header2 %s fail\n",result); wav_file_header2.ckid=mmioFOURCC('d', 'a', 't', 'a'); //create data Chunk result = mmioCreateChunk(wav_file ,&wav_file_header2,0); if (result==MMSYSERR_NOERROR) printf( "mmioCreateChunk wav_file_header2 %s ok\n",result); else printf( "mmioCreateChunk wav_file_header2 %s fail\n",result); printf("audio_header %d BytesRecorded\n",audio_header.dwBytesRecorded); //輸入audio data wav_log = mmioWrite(wav_file,(char*)audio_header.lpData,DATASIZE); if(wav_log==-1) printf( "mmioWrite audio data fail\n"); else printf( "mmioWrite success : write %d bytes\n",wav_log); //跳出data chunk result = mmioAscend(wav_file,&wav_file_header2,0); if (result==MMSYSERR_NOERROR) printf( "mmioAscend wav_file_header2 %s ok\n",result); else printf( "mmioAscend wav_file_header2 %s fail\n",result); //跳出RIFF chunk result = mmioAscend(wav_file,&wav_file_header1,0); if (result==MMSYSERR_NOERROR) printf( "mmioAscend wav_file_header1 %s ok\n",result); else printf( "mmioAscend wav_file_header1 %s fail\n",result); result = mmioClose(wav_file,0); //close the wav file if (result==MMIOERR_CANNOTWRITE){ printf( "mmioClose fail\n"); } return 0; }可以看到儲存下來的wav檔
作者已經移除這則留言。
回覆刪除