实时录音并显示波形、频谱
本文讲述如何实时录音,以及将录音波形频谱实时显示的方法。Windows提供了一个多媒体控制接口(MCI),用它可以录音,很方便。但是这种方法不能实时给出录音的原始数据,因此要显示波形和频谱都是不可能实现的。要达到实时的效果,就要使用Windows提供的另一套函数,即低级音频函数。其中和录音有关的是以waveIn开头的一组函数。
低级音频函数的使用比较繁琐,大致要有以下几个步骤。
上面就是实时录音的一个基本流程,产生回调时,其lParam就是一个指向WAVEHDR结构的指针,通过这个指针就可以得到原始数据(注意了:我这个程序只是单声道8位的PCM格式,因此正好一个字节就是一个采样点的值,对于其他格式的我就不知道了)。有了原始数据就可以很容易的画出波形了,而频谱也就是多一次FFT变换而已,没什么太难的。
这里是我用LCC写的例子,非常简单,而且相信大家都可以很容易的移植到BCB上来。另外,我偷了一下懒,FFT用了我以前封装到DLL中的函数(现在已经忘了怎么写了^_^),可以在此下载 (不要觉得奇怪,就是这个时钟,将其中的DEMO.DLL拿来用就是了)。当然你也可以自己写一个FFT放到程序里去。
-*-*-PATCH-*-*-2002-06-11
上次那个程序还不好,原因是双缓冲还不能满足实时的要求,因此这次用了8缓冲循环技术。新的程序也是用LCC写的。
开始时依次将0-6号缓冲区关联到设备上,而7号缓冲区不关联,然后开始录音,这是驱动程序开始向0号缓冲区输出数据,当0号缓冲区数据满时产生回调,这时驱动程序会自动向1号缓冲区输出数据,但这时应将7号缓冲区关联到设备上去,然后处理0号缓冲区的数据。然后当1号缓冲区数据满时又会产生回调,这时驱动程序会自动向2号缓冲区输出数据,而将0号缓冲区关联到设备上去。这样如此反复,始终保持1个缓冲区用于驱动输出数据,1个缓冲区用于处理数据,6个缓冲区处于等待状态。
而如果只有两个缓冲区,就只能一个用于驱动输出,一个用于处理数据。这样在产生回调的时候就会出现没有处于等待状态的缓冲区的情况,这样驱动程序就不能自动向缓冲区输出数据。而要等waveInPrepareBuffer、waveInAddBuffer调用之后,这样就会出现一个小小的间隙,而导致录音不连续。
-*-*-PATCH-*-*-2002-06-11
只是我的个人观点,有什么不对的地方,还望指教。
-*-*-PATCH-*-*-2003-04-07
程序中有一个错误,在WIM_DATA的处理过程里。
case WIM_DATA:当0号缓冲区数据满时,应该释放0号句柄。这第一次是对的,但是第二次当1号缓冲满的时候,程序却释放了7号句柄。这里是错的,解决方法就是计算正确的句柄号。
或者,waveInUnprepareHeader(hwi,LPWAVEHDR(lParam),sizeof(WAVEHDR));
这样就可以了,感谢flinming发现这个问题。
另外,《网络语音传输》中的程序也有这个问题,请大家自己改吧。
-*-*-PATCH-*-*-2003-04-07