录音小程序
更新时间: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
《乡下老鼠进城》社会05-18
一年级看图写话图片及范文最新版实用版04-01
计算机技术辅助审计的风险分析及规避策略08-13
习题六样本及抽样分布解答04-18
软考网络工程师资料-网工英语10套练12-19
环保知识竞赛题库一、选择题08-31
变频恒压供水毕业设计(开题报告)07-26
晚秋作文800字07-07
CMOS设置05-19
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 录音
- 程序
- 2017届浙江省瑞安中学高三月考生物试题及答案
- 高考作文的应试策略
- 学车(考驾照)知识入门
- 《Linux服务器配置与管理》教学大纲
- 临沂市2018年中考英语真题试题(含答案)
- 初中地理活动记录
- 实验二 发动机负荷特性试验
- 《数学分析》 教学大纲(2013版)
- 毛概(2016年春)
- 安全工程师《安全生产法及法律知识》练习试题
- 班主任总结
- 生理学试题及答案第四章-血液循环题库
- 小学数学三年级长方形和正方形面积的计算说课稿
- 2017年秋六年级上册语文期末试卷二及答案
- 沈阳市信访局政府信息公开新闻发布会、听证会和论证会
- 渔父公开课教案
- 浅谈对幼儿情感教育的探索
- 油葵栽培技术及病虫草害防治
- 2010年特岗教师招聘考试中学英语模拟试题及答案五 - 词汇和结构
- 儒家恕道思想三段式论文