三度网教程:是一个免费提供流行视频软件教程、在线学习分享的学习平台!

API层完成语音录制

时间:2024/6/13作者:未知来源:三度网教程人气:


     我从前出于需要,上网寻找了关于录音部分的源代码,收获不大,现在把自己摸索的部分源代码公开出来吧,希望对部分人有用。

     其实要实现声音的录制,可以用多种的方式(例如 mci ),我这里介绍的是在 API 的层面来实现,你可以对其中进行更多的控制。比方说,要音频裸数据存到你指定的内存中去。

     先说一下要用到的 API , 录音通常都是使用 waveInXXX 一类 API 的,最主要的是 waveInStart (顾名思义就是开始录音),然后是 waveInStop(它能够在你指定的缓冲满的时候返回) ; 如果不用 waveInStop 可以使用 waveInReset(不同于Stop的是该函数不等缓冲满就马上返回那样你才可以终止录音),不过最好跟 waveInGetPosition 配合使用。

    说完这些函数,不得不提的是为以上几个函数做准备工作的函数(注意配对使用), waveInOpen 和 waveInClose 配对( waveInOpen 里面指定音频的格式,比方说立体声 和16位音质等); waveInPrepareHeader 和 waveInUndivpareHeader 配对( waveInPrepareHeader 里面指定用来录音缓冲的大小和首地址),紧跟着 waveInPrepareHeader要例行公事调用 waveInAddBuffer( 作用未详,不多说了)。

    详细调用过程可以看下面



(之前最好调用 waveInGetNumDevs 看看有没有可用的设备)

waveInOpen (该处用 WAVEFORMATEX 结构指定音频格式)



     waveInPrepareHeader (该处用 WAVEHDR 结构的 lpData 成员指定缓冲首地址)

     waveInAddBuffer



        waveInStart

         (录制中....)

        waveInStop (warning:一定要缓冲满了才返回)



     waveInUndivpareHeader



waveInClose







    需要指出的是,上面的代码你不能随心所欲的停止录音过程(如果你指定的缓冲非常大,比方说足够录音一个小时,那么你就要乖乖的等上一个小时),如果希望马上停止,请使用下面的方法。





        waveInStart

        (录制中....)

        (n 时间后,用户提出停止请求)

        waveInGetPosition (保留该值,用来设置 WAVEHDR 结构的 dwBytesRecorded 成员)

        waveInReset

        (重新设置 WAVEHDR 结构的 dwBytesRecorded 成员)







    整个过程就是如此的几句,下面将给出源程序以验证。





    需要说明一下,正常情况下录音以后,总共耗费的内存(以字节算) 会保存在WAVEHDR 结构的 dwBytesRecorded 成员中,可用的音频裸数据当然就放进你指定的内存缓冲中去了,你大可不必等 waveInUndivpareHeader 就可以马上拿来用了。





   ( 补充一个内容,粗略讲解一下 .wav 文件的文件头格式 )

    看下面的结构,一开始的八个字节是一个结构, 第一个 四字节 是标志,刚好等于 ascii 的 "RIFF" ,第二个四字节是总的文件长度减去8。你可以验证一下。(参照16进制阅读数字的方法)

    跟着是第二个数据结构,占12个字节。如果你是标准的 wave 格式的文件,那么就是紧接着两个标志,第一个四字节的标志是 ascii 的 "WAVE" ,第二个 四字节的标志就是 ascii 的 "fmt "(注意,有一个空格),然后剩下的四字节里面藏的是 WAVEFORMATEX 结构的大小(参照MSDN),应该是18个字节。

    然后,当然就是 18个字节的 WAVEFORMATEX 结构里面的值。详细的就不说了,自己查一下 MSDN。 (需要注意的是,这个 WAVEFORMATEXEX 的末一个成员,讲了可能的长度扩充)

    在这 18 个字节后面 (按照旧时候的方法),应该是跟着一个8字节的结构的,然后就是 "裸数据" 的开始地址了,这八字节结构的开始四字节是标志,应该等于 ascii 的 "data",然后紧跟着的四字节就是裸数据的大小了,也就是最重要的部分。

    好了,如此一来,你就可以得到音频裸数据的起始位置(紧紧跟在含"data"标志的数据结构的后面),还有就是音频数据的长度了。应该是所有的问题都很容易解决的。

    

    不过,还要注意,就是现在的很多 .wav 文件都会外加一个数据结构(12字节),就插在 WAVEFORMATEX 的后面和 含 "data" 的数据结构前面。  这个外加的结构 第一个四字节是标志,等于 ascii 码的 "fact",然后第二个四字节的值在大部分情况下都等于 4, 第三个四字节的值也是等于 音频裸数据的长度。  基本上就是这样了。





      下面给出的源程序文件只要加进新建的 VC win32工程中,编译即可,执行效果是录音三秒后自动生成 mytest.wav 文件供播放测试(记得选好默认录音通道)。

    废话不多说,给出源程序(该源程序中要包含 RunTimeLog.cpp,见http://www.csdn.net/develop/Read_Article.asp?Id=17477) 希望对大家有用。(全文完)

      (全文完 - 2003年03月27日_am: 11时27分)







// *******************  FileName: WinMain.cpp  *****************************



// 该源程序需要加入到 VC6 的 Win32 Application 的 empty Project 中

// 请包含我自定义的调试类,见 #include "RunTimeLog.cpp"

// 对于工程的 Link 选项,至少要包含以下库:  msvcrt.lib kernel32.lib user32.lib Winmm.lib





#define WIN32_LEAN_AND_MEAN      // Say No to MFC !!



#include <windows.h>

#include <Mmsystem.h>



#include "RunTimeLog.cpp"



RunTimeLog log;





char lpTemp[256]="";





DWORD FCC(LPSTR lpStr)

{

   DWORD Number = lpStr[0] + lpStr[1] *0x100 + lpStr[2] *0x10000 + lpStr[3] *0x1000000 ;

   return Number;

}





int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,

                    LPSTR lpCmdLine, int nCmdShow )

{



  CreateMutex( NULL, false, "MyMutex");

   if ( GetLastError() == ERROR_ALREADY_EXISTS )

   { log.write("Exists and Exit"); log.last(); ExitProcess( NULL); }





    log.write("Program Start.");

    log.nobuff = true;



DWORD datasize = 48000;

    

    // 最常用法

WAVEFORMATEX waveformat;

waveformat.wFormatTag=WAVE_FORMAT_PCM;

waveformat.nChannels=1;

waveformat.nSamplesPerSec=8000;

waveformat.nAvgBytesPerSec=8000;

waveformat.nBlockAlign=1;

waveformat.wBitsPerSample=8; //指定录音格式

waveformat.cbSize=0;



  wsprintf( lpTemp, "WAVEFORMATEX size = %lu", sizeof(WAVEFORMATEX) );

  log.write(lpTemp);







HWAVEIN  m_hWaveIn;



if ( waveInGetNumDevs() ) log.write("有可以使用的 WaveIn 通道");  else log.write("没有可以使用的 waveIn 通道");



int res=waveInOpen(&m_hWaveIn,WAVE_MAPPER, &waveformat, (DWORD)NULL,0L,CALLBACK_WINDOW); //打开录音设备



if ( res == MMSYSERR_NOERROR ) log.write("打开 waveIn 成功");  // 验证创建是否成功

else  {

     wsprintf(lpTemp, "打开 waveIn 通道失败,Error_Code = 0x%x", res );

     log.write(lpTemp);

} // End of 验证创建是否成功







WAVEHDR m_pWaveHdr;

   

  m_pWaveHdr.lpData = (char *)GlobalLock( GlobalAlloc(GMEM_MOVEABLE

关键词:  API层完成语音录制





Copyright © 2012-2018 三度网教程(http://www.3du8.cn) .All Rights Reserved 网站地图 友情链接

免责声明:本站资源均来自互联网收集 如有侵犯到您利益的地方请及时联系管理删除,敬请见谅!

QQ:1006262270   邮箱:kfyvi376850063@126.com   手机版