录音小程序

更新时间:2024-03-01 18:41:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

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 //输入的缓冲区长度 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(L\ return ;

}

接下来需要设置录音的方式,需要用到WAVEFORMATEX结构.声道数,采样位和采样率都可以在这结构中设置.

WAVEFORMATEX waveform;

waveform.wFormatTag=WAVE_FORMAT_PCM; //录音的格式

waveform.cbSize=0; //方式为WAVE_FORMAT_PCM时此参数可以忽略 waveform.nChannels=1; //声道数,数值可为1或2

waveform.nSamplesPerSec=11025; //采样率,数值有: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_MAPPER,&waveform,(DWORD)this->m_hWnd,NULL,CALLBACK_WINDOW)) {

free(pBuffer1); free(pBuffer2);

AfxMessageBox(L\无法打开录音设备\ return; }

设备可以打开后,就需要初始化两个输入缓存区的声音文件头了.声音文件头主要是在录音时,记录相关的数据,以方便后期的处理. PWAVEHDR 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)); //将缓冲区信息和输入设备相关联

waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ; //将缓冲区地址和输入设备相关联

在对PWAVEHDR进行赋值时,本程序中需要设置的其实只有lpData和dwBufferLength.接下来将pWaveHdr2同pWaveHdr1进行相关处理(略).

由于我们是要将录音数据以文件形式保存到非易失性存储器上,所以在开始录音之前我们需要先建立文件,并且把相关的文件头信息写入(WriteWaveFileHeader是自写函数,代码附在文章最后). //先写文件头 MMRESULT mr;

mr=WriteWaveFileHeader(strSavePath,&waveform,0,TRUE); if(mr != MMSYSERR_NOERROR) {

AfxMessageBox(L\文件保存失败!\

//停止录音,关闭设备 waveInReset(hWaveIn); return; }

//获取文件句柄,方便之后对其添加数据.

m_fh = CreateFile(strSavePath, 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().顾名思义,这三个函数分别在这三种情况下调用:开始录音时;缓冲区用完时;录音关闭时.其中OnMM_WIM_OPEN()和OnMM_WIM_CLOSE()只调用一次.

本程序最重要是对OnMM_WIM_DATA()函数进行处理. 相关代码如下:

void OnMM_WIM_DATA(UINT wParam, LONG lParam) {

//bEnding是一个外部定义的BOOL变量,用来判断外部是否按下\停止\按钮;是则不分配内存,直接返回. if (bEnding)

{

//关闭录音

waveInClose (hWaveIn) ; return ; }

//dwDataLength是一个外部定义的DWORD变量,用来记录录音数据的长度. dwDataLength += ((PWAVEHDR) lParam)->dwBytesRecorded ; //将内存数据写到文件中

//pSaveBuffer是外部定义的一个临时缓存

pSaveBuffer=(PBYTE)realloc (pSaveBuffer, ((PWAVEHDR) lParam)->dwBytesRecorded);

CopyMemory (pSaveBuffer, ((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(),我们在此函数体里进行相关的收尾清除工作

void CRecordDlg::OnMM_WIM_CLOSE(UINT wParam, LONG lParam) {

//关闭文件句柄 CloseHandle(m_fh); if (0==dwDataLength) {

//长度为0,可能录音失败 return; }

//重写一次文件头,将文件长度写入文件中 MMRESULT mr;

mr=WriteWaveFileHeader(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) ; }

至此,整个录音程序结束.

附录:相关文件函数

//******************************************************************************************

//写wav文件头

//--------------------------------------------------------------- //pszFilename:保存的路径 //pWFX:保存的格式信息 //dwBufferSize:保存WAV的长度

//bCover:创建文件时如果原文件存在,是否截断(在此函数意义是:是新建文件写文件头,还是改写文件头)

//******************************************************************************************* //----------------------------------------------------------------

MMRESULT CRecordDlg::WriteWaveFileHeader(LPCTSTR pszFilename, PWAVEFORMATEX 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 = sizeof(WAVEFORMATEX) + pWFX->cbSize;

// the DataHeader chunk contains the audio data DataHeader.dwCKID = RIFF_CHANNEL; DataHeader.dwSize = dwBufferSize;

// The FileHeader

FileHeader.dwRiff = RIFF_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) + 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_EXISTING, 0, NULL);

//将文件指针移到文件头

SetFilePointer(fh,0,NULL,FILE_BEGIN); }

if( fh == INVALID_HANDLE_VALUE ) {

RETAILMSG(1, (TEXT(\pszFilename, GetLastError()));

//AfxMessageBox(L\ return mmRet; }

// write the riff file

if (! WriteFile(fh, &FileHeader, sizeof(FileHeader), &dwBytesWritten, NULL)) { RETAILMSG(1, (TEXT(\ //AfxMessageBox(L\ goto ERROR_EXIT; }

// write the wave header

if (! WriteFile(fh, &WaveHeader, sizeof(WaveHeader), &dwBytesWritten, NULL)) { RETAILMSG(1, (TEXT(\ //AfxMessageBox(L\ goto ERROR_EXIT; }

// write the wave format

if (! WriteFile(fh, pWFX, WaveHeader.dwSize, &dwBytesWritten, NULL)) { RETAILMSG(1, (TEXT(\ //AfxMessageBox(L\

goto ERROR_EXIT; }

// write the data header

if (! WriteFile(fh, &DataHeader, sizeof(DataHeader), &dwBytesWritten, NULL)) { RETAILMSG(1, (TEXT(\ //AfxMessageBox(L\ goto ERROR_EXIT; }

/*----------------------------------------------------------------------------- //此函数只是为了写文件头,不写录音数据 // write the PCM data

if (! WriteFile(fh, pBufferBits, DataHeader.dwSize, &dwBytesWritten, NULL)) { RETAILMSG(1, (TEXT(\ AfxMessageBox(L\ goto ERROR_EXIT; }

---------------------------------------------------------------------------------*/

// Success

mmRet = MMSYSERR_NOERROR;

ERROR_EXIT: CloseHandle(fh); return mmRet; }

//****************************************************************************************

//将wav的数据加到现存的一个文件中 //-----------------------------------------------------------------

//LPCTSTR pszFilename 要追加的文件名

//PBYTE pBufferBits 要写入的数据

//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_HANDLE_VALUE ) { RETAILMSG(1, (TEXT(\pszFilename, GetLastError()));

AfxMessageBox(L\ return FALSE; }

//将文件指针移到文件尾 SetFilePointer(fh,0,NULL,FILE_END);

*/

// write the PCM data if (! WriteFile(fh, pBufferBits, dwBufferSize, &dwBytesWritten, NULL)) {

RETAILMSG(1, (TEXT(\

//AfxMessageBox(L\当前存储器已满\ goto ERROR_EXIT; }

//CloseHandle(fh); return TRUE;

ERROR_EXIT:

//CloseHandle(fh); return FALSE; }

本文来源:https://www.bwwdw.com/article/92ha.html

Top