录音小程序
更新时间: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; }
正在阅读:
录音小程序03-01
强国复兴有我演讲稿5篇04-03
衣鱼、蜻蜓与豆娘、螳螂对蜜蜂有哪些危害05-17
学校的经典座右铭11-20
危险化学品清单及MSDS资料05-14
领馆公证认证申请表06-02
夏季施工安全生产的注意事项05-06
sj习题集11-14
- 《江苏省环境水质(地表水)自动监测预警系统运行管理办法(试行)》
- 安乐死合法化辩论赛立论稿(浙大新生赛)
- 公共科目模拟试卷公务员考试资料
- 我国固定资产投资FAI对GDP的影响
- 大学生创新创业训练计划项目申请书大创项目申报表
- 完美版—单片机控制步进电机
- 2013资阳中考化学试题
- 18.两位数减一位数退位(397道)
- 工程量计算规则
- 二年级操行评语(下)
- 第3章 流程控制语句
- 浅基桥墩加固技术
- 课题研究的主要方法
- 5100软件说明书 - 图文
- 车间技术员年终总结
- 关于印发《中铁建工集团开展项目管理实验室活动方案》的通知
- 经典诵读结题报告
- 地下水动力学习题答案
- 2018年全国各地高考数学模拟试题平面解析几何试题汇编(含答案解
- 街道办事处主任2018年度述职述廉报告
- 录音
- 程序
- 2017届浙江省瑞安中学高三月考生物试题及答案
- 高考作文的应试策略
- 学车(考驾照)知识入门
- 《Linux服务器配置与管理》教学大纲
- 临沂市2018年中考英语真题试题(含答案)
- 初中地理活动记录
- 实验二 发动机负荷特性试验
- 《数学分析》 教学大纲(2013版)
- 毛概(2016年春)
- 安全工程师《安全生产法及法律知识》练习试题
- 班主任总结
- 生理学试题及答案第四章-血液循环题库
- 小学数学三年级长方形和正方形面积的计算说课稿
- 2017年秋六年级上册语文期末试卷二及答案
- 沈阳市信访局政府信息公开新闻发布会、听证会和论证会
- 渔父公开课教案
- 浅谈对幼儿情感教育的探索
- 油葵栽培技术及病虫草害防治
- 2010年特岗教师招聘考试中学英语模拟试题及答案五 - 词汇和结构
- 儒家恕道思想三段式论文