《2022年2022年录音小程序 .pdf》由会员分享,可在线阅读,更多相关《2022年2022年录音小程序 .pdf(12页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、EVC 录音详解语音采集默认分类2007-10-02 23:11:24 阅读 20 评论 0字号: 大中小= /TITLE: / EVC 录音详解/AUTHOR: / norains /DATE: / Friday 9-June-2006 /= 借助 evc 在 wince 下实现录音不是一件难事.恩,的确不是一件难事.本文主要解释如何使用wavein, 并且把声音以wave 文件形式保存到储存器中. 最先 ,我们要分配两个缓冲区.因为数据首先要保存到内存中,两个内存缓存区间可以较快进行切换 ,可以避免录音有断断续续的现象.#define INP_BUFFER_SIZE 16*1024 /输入
2、的缓冲区长度PBYTE pBuffer1,pBuffer2; /保存输入数据的两个缓冲区pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE); pBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE); if (!pBuffer1 | !pBuffer2) if (pBuffer1) free(pBuffer1); if (pBuffer2) free(pBuffer2); AfxMessageBox(LMemory erro!); return ; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - -
3、 - - - - 名师精心整理 - - - - - - - 第 1 页,共 12 页 - - - - - - - - - 接下来需要设置录音的方式,需要用到 WAVEFORMATEX结构 .声道数 ,采样位和采样率都可以在这结构中设置.WAVEFORMATEX waveform; waveform.wFormatTag=WAVE_FORMAT_PCM; /录音的格式waveform.cbSize=0; /方式为 WAVE_FORMAT_PCM时此参数可以忽略waveform.nChannels=1; /声道数 ,数值可为 1或2 waveform.nSamplesPerSec=11025; /
4、采样率 ,数值有 :11025,22050,44100 waveform.wBitsPerSample=8; /采样位 ,数值有 :8,16 waveform.nBlockAlign=waveform.nChannels * waveform.wBitsPerSample / 8; waveform.nAvgBytesPerSec=waveform.nBlockAlign * waveform.nSamplesPerSec; 设置完毕之后,就可以用waveInOpen函数打开输入设备.HWAVEIN hWaveIn; /输入设备句柄if (waveInOpen(&hWaveIn,WAVE_MA
5、PPER,&waveform,(DWORD)this-m_hWnd,NULL,CALLBACK_WINDOW) free(pBuffer1); free(pBuffer2); AfxMessageBox(L无法打开录音设备); return; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 12 页 - - - - - - - - - 设备可以打开后,就需要 初始化两个输入缓存区的声音文件头了.声音文件头主要是在录音时 ,记录相关的数据,以方便后期的处理.PWAVEHDR
6、 pWaveHdr1,pWaveHdr2; pWaveHdr1-lpData=(LPSTR)pBuffer1; /缓冲区地址pWaveHdr1-dwBufferLength=INP_BUFFER_SIZE; /缓冲区长度pWaveHdr1-dwBytesRecorded=0; pWaveHdr1-dwUser=0; pWaveHdr1-dwFlags=0; pWaveHdr1-dwLoops=1; pWaveHdr1-lpNext=NULL; pWaveHdr1-reserved=0; waveInPrepareHeader(hWaveIn,pWaveHdr1,sizeof(WAVEHDR);
7、 /将缓冲区信息和输入设备相关联waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR) ; /将缓冲区地址和输入设备相关联在对 PWAVEHDR进行赋值时 ,本程序中需要设置的其实只有lpData 和 dwBufferLength.接下来将pWaveHdr2 同 pWaveHdr1 进行相关处理 (略). 由于我们是要将录音数据以文件形式保存到非易失性存储器上,所以在开始录音之前我们需要先建立文件,并且把相关的文件头信息写入(WriteWaveFileHeader是自写函数 ,代码附在文章最后 ). /先写文件头MMRESULT mr; mr
8、=WriteWaveFileHeader(strSavePath,&waveform,0,TRUE); if(mr != MMSYSERR_NOERROR) AfxMessageBox(L文件保存失败 !); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 12 页 - - - - - - - - - /停止录音 ,关闭设备waveInReset(hWaveIn); return; /获取文件句柄,方便之后对其添加数据. m_fh = CreateFile(strSave
9、Path, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if( m_fh = INVALID_HANDLE_VALUE ) AfxMessageBox(L添加数据音频数据错误); return ; 一切准备就绪之后,就可以调用函数waveInStart() 来进行真正的录音了:waveInStart(hWaveIn); 在录音过程中,有三个回调函数系统会自动调用,分别是:OnMM_WIM_OPEN(),OnMM_WIM_DATA()和 OnMM_WIM_CLOSE().顾名思义 ,这三个函数分别在这三种情况下调用
10、:开始录音时 ;缓冲区用完时;录音关闭时 .其中OnMM_WIM_OPEN()和 OnMM_WIM_CLOSE()只调用一次 . 本程序最重要是对OnMM_WIM_DATA()函数进行处理 . 相关代码如下: void OnMM_WIM_DATA(UINT wParam, LONG lParam) /bEnding是一个外部定义的BOOL 变量 ,用来判断外部是否按下停止 按钮 ;是则不分配内存 ,直接返回 . if (bEnding) 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第
11、 4 页,共 12 页 - - - - - - - - - /关闭录音waveInClose (hWaveIn) ; return ; /dwDataLength是一个外部定义的DWORD变量 ,用来记录录音数据的长度. dwDataLength += (PWAVEHDR) lParam)-dwBytesRecorded ; /将内存数据写到文件中/pSaveBuffer是外部定义的一个临时缓存pSaveBuffer=(PBYTE)realloc (pSaveBuffer, (PWAVEHDR) lParam)-dwBytesRecorded); CopyMemory (pSaveBuffer
12、, (PWAVEHDR) lParam)-lpData,(PWAVEHDR) lParam)-dwBytesRecorded) ; m_bAddSuc=AddWaveFileDate(m_fh,pSaveBuffer,(PWAVEHDR) lParam)-dwBytesRecorded); if(m_bAddSuc=FALSE) /加入不成功waveInClose (hWaveIn) ; return ; /加入新的内存waveInAddBuffer (hWaveIn, (PWAVEHDR) lParam, sizeof (WAVEHDR) ; 录音完毕则调用OnMM_WIM_CLOSE(),
13、我们在此函数体里进行相关的收尾清除工作名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 12 页 - - - - - - - - - void CRecordDlg:OnMM_WIM_CLOSE(UINT wParam, LONG lParam) /关闭文件句柄CloseHandle(m_fh); if (0=dwDataLength) /长度为 0,可能录音失败return; /重写一次文件头,将文件长度写入文件中MMRESULT mr; mr=WriteWaveFile
14、Header(strSavePath,&waveform,dwDataLength,FALSE); if(mr != MMSYSERR_NOERROR) AfxMessageBox(L重写文件头失败!); return; waveInUnprepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR) ; waveInUnprepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR) ; free (pBuffer1) ; free (pBuffer2) ; 至此 ,整个录音程序结束. 附录 :相关文件函数/* 名师
15、资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 12 页 - - - - - - - - - /写 wav 文件头/- /pszFilename:保存的路径/pWFX: 保存的格式信息/dwBufferSize:保存 WAV 的长度/bCover: 创建文件时如果原文件存在,是否截断 (在此函数意义是:是新建文件写文件头,还是改写文件头 ) /* /- MMRESULT CRecordDlg:WriteWaveFileHeader(LPCTSTR pszFilename, P
16、WAVEFORMATEX pWFX, DWORD dwBufferSize,BOOL bCover) RIFF_FILEHEADER FileHeader; RIFF_CHUNKHEADER WaveHeader; RIFF_CHUNKHEADER DataHeader; DWORD dwBytesWritten; HANDLE fh; MMRESULT mmRet = MMSYSERR_ERROR; / Fill in the file, wave and data headers WaveHeader.dwCKID = RIFF_FORMAT; WaveHeader.dwSize = si
17、zeof(WAVEFORMATEX) + pWFX-cbSize; / the DataHeader chunk contains the audio data DataHeader.dwCKID = RIFF_CHANNEL; DataHeader.dwSize = dwBufferSize; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 12 页 - - - - - - - - - / The FileHeader FileHeader.dwRiff = RIFF_
18、FILE; FileHeader.dwSize = sizeof(WaveHeader) + WaveHeader.dwSize + sizeof(DataHeader) + DataHeader.dwSize; FileHeader.dwWave = RIFF_WAVE; /- /追踪一下DWORD i=sizeof(WaveHeader); i=sizeof(WaveHeader) + WaveHeader.dwSize; i=sizeof(WaveHeader) + WaveHeader.dwSize + sizeof(DataHeader); i=sizeof(WaveHeader)
19、+ WaveHeader.dwSize + sizeof(DataHeader) + DataHeader.dwSize; /- / Open wave file if(bCover=TRUE) /如果原文件已存在,则把原文件截断(覆盖 ) fh = CreateFile(pszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, Create_ALWAYS, 0, NULL); else /打开已存在的原文件fh = CreateFile(pszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_
20、EXISTING, 0, NULL); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 12 页 - - - - - - - - - /将文件指针移到文件头SetFilePointer(fh,0,NULL,FILE_BEGIN); if( fh = INVALID_HANDLE_VALUE ) RETAILMSG(1, (TEXT(Error opening %s. Error code = 0 x%08xn), pszFilename, GetLastError();
21、/AfxMessageBox(Lerror open file in writing header); return mmRet; / write the riff file if (! WriteFile(fh, &FileHeader, sizeof(FileHeader), &dwBytesWritten, NULL) RETAILMSG(1, (TEXT(Error writing file headerrn); /AfxMessageBox(Lerro writing file header); goto ERROR_EXIT; / write the wave header if
22、(! WriteFile(fh, &WaveHeader, sizeof(WaveHeader), &dwBytesWritten, NULL) RETAILMSG(1, (TEXT(Error writing wave headerrn); /AfxMessageBox(Lerroer writing wave header); goto ERROR_EXIT; / write the wave format if (! WriteFile(fh, pWFX, WaveHeader.dwSize, &dwBytesWritten, NULL) RETAILMSG(1, (TEXT(Error
23、 writing wave formatrn); /AfxMessageBox(Lerror writing wave formate); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 12 页 - - - - - - - - - goto ERROR_EXIT; / write the data header if (! WriteFile(fh, &DataHeader, sizeof(DataHeader), &dwBytesWritten, NULL) RETA
24、ILMSG(1, (TEXT(Error writing PCM data headerrn); /AfxMessageBox(Lerror wrting pcm data header); goto ERROR_EXIT; /*- /此函数只是为了写文件头,不写录音数据/ write the PCM data if (! WriteFile(fh, pBufferBits, DataHeader.dwSize, &dwBytesWritten, NULL) RETAILMSG(1, (TEXT(Error writing PCM datarn); AfxMessageBox(Lerror w
25、rting pcm data); goto ERROR_EXIT; -*/ / Success mmRet = MMSYSERR_NOERROR; ERROR_EXIT: CloseHandle(fh); return mmRet; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 12 页 - - - - - - - - - /* /将 wav 的数据加到现存的一个文件中/- /LPCTSTR pszFilename 要追加的文件名/PBYTE pBufferBits
26、要写入的数据/DWORD dwBufferSize 要写入数据的长度/- /* BOOL CRecordDlg:AddWaveFileDate(HANDLE fh, PBYTE pBufferBits, DWORD dwBufferSize) /HANDLE fh; DWORD dwBytesWritten; /* / Open the existing wave file fh = CreateFile(pszFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if( fh = INVALID_HA
27、NDLE_VALUE ) RETAILMSG(1, (TEXT(Error opening %s. Error code = 0 x%08xn), pszFilename, GetLastError(); AfxMessageBox(Lerror open file in the adding); return FALSE; /将文件指针移到文件尾SetFilePointer(fh,0,NULL,FILE_END); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 12
28、 页 - - - - - - - - - */ / write the PCM data if (! WriteFile(fh, pBufferBits, dwBufferSize, &dwBytesWritten, NULL) RETAILMSG(1, (TEXT(Error writing PCM datarn); /AfxMessageBox(L当前存储器已满); goto ERROR_EXIT; /CloseHandle(fh); return TRUE; ERROR_EXIT: /CloseHandle(fh); return FALSE; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 12 页 - - - - - - - - -