天天看点

Windows基础-实时录音程序(WaveXXX)写在前面 使用MMAPI(WaveXxxAPI) 使用MCI(字符串命令)

录音无非两种需求: 

       1. 非实时获得音频,也就是停止录音了你才需要处理它; 

       2. 实时获取音频,比如QQ电话这种这边讲话那边马上就听到的。 

       后者实现起来比较啰嗦,但也很定式。既然啰嗦那就乖乖地写成类吧,管别的大仙怎么说你low呢 ( ͡° ͜ʖ ͡°) 。 

Windows基础-实时录音程序(WaveXXX)写在前面 使用MMAPI(WaveXxxAPI) 使用MCI(字符串命令)

Windows API 可用的实现方式

用处

Windows Multimedia API(WaveXxxAPI)

定式且啰嗦地实现音频流的实时获取。

Media Control Interface (MCI)

让你简单地用字符串命令实现录音和放音

——MMAPI可以让你访问音频设备的缓冲区,发挥比较自由,接近系统底层。 

——MCI是发送字符串指令给这个界面,内部的无法干涉,记得《少年电脑世界》之类的杂志教你打开关闭光驱什么的就是用写一行 

          <code>mciSendString("set cdaudio door open",NULL,0,NULL);//关闭把open改为close</code>。 

          注意:MCI简称媒体控制接口,较为高层,为的是让你不用关心设备的具体操作,快速上手,简单地操作多媒体设备。WaveXxxAPI是接近底层的应用程序接口,为的是灵活地控制设备,但设备的操作还是比较定式的,灵活在于设备状态配置和数据处理的时机,所以M$给你了两个控制方式。

       用MMAPI的估计都是想实时获得音频数据的,MMAPI可以把音频流缓冲起来并一块一块地发送给你,在这里我们暂把这种固定大小的音频裸数据简称为AudioFrame(数据块,代码中别名叫ChunkData)。这一块数据需要你一次性处理完(你甚至需要转移这个数据到另一个线程以保证缓冲区读写的稳定性),数据有多少字节可以根据实际情况来设定。在性能和延迟之间均衡考虑一下,200ms的数据可以应付大多数情况。 

       PS:用过Kinect V2麦克风的同学对此应该比有印象,AudioFrame顾名思义,音频帧。

       MMAPI的操作十分定式: 

       开始录音的流程为:以一种格式打开波形输入设备,发送WIM_OPEN消息给回调函数,准备缓冲区,添加缓冲区到设备,告诉设备录音开始; 

       录音期间循环发送WIM_DATA给回调函数; 

       结束录音的流程为:告诉设备录音结束并发送WIM_DATA给回调函数让它处理最后的数据,重置录音设备,释放缓冲区,至此可以重新设置缓冲区到设备并开始新的录音,关闭设备并发送WIM_CLOSE给回调函数。 

       关于MMAPI的回调函数: 

       这个回调函数是来处理消息的,一开始收到WIM_OPEN,最后收到WIM_CLOSE唯一频繁收到的消息是WIM_DATA,得到这个消息时我们需要转移缓冲区里的数据并把缓冲区压入到设备缓冲队列中,你可以理解为自动pop手动push。 

       我写的类里面的回调函数是属于这个回调函数的,阻塞的话还是会直接影响MMAPI的回调函数 

       这里用到双缓冲乃至多缓冲技术: 

       假设一个实时接水的任务,听起来奇怪但与MMAPI的处理流程相似,这里需要你用杯子连续接水,杯子相当于你开辟的缓冲区: 

       根据上面的​流程,你的身份是MMAPI的回调函数,在饮水机面前要拿着杯子执行这个任务:任务的基本指标是滴水不漏地连续用杯子把水接到一个存储区域里,你要接指定量的水,还要负责转移走这杯水。为了能腾出时间把水倒在存储区域里,你肯定需要用不止一个杯子轮流接水。饮水机有一个功能:每当杯子灌满后,饮水机会通知你,并自动去接下一个杯子,如果后面没有杯子则终止任务。(不会讲故事的我啊TT,这个奇葩例子能看懂就行)可以见得:1.你会被及时地通知去转移数据2.缓冲区用完了要及时放回缓冲区队列后端以保证任务能够继续3.如果转移并处理数据的时间不是很稳定,你可能需要准备多个缓冲区而不是单纯增加缓冲区容量,为的是确保任务中能够预留足够多的容忍时间供你使用。 

       这里的多缓冲技术浅显地解释就是多个缓冲区排成一个队列(或者理解为放成一摞)来抵消这个任务中那些耗时不稳定的处理过程对整个实时处理任务的连续性带来的负面影响。其实生活中有很多事情也是用到多缓冲这个概念。

    这一部分我把自己写的类里面的函数拿了出来,完整代码请见链接,免下载积分。

    需要添加:

    检查一下是否有音频输入设备:

     写一个WaveXxxAPI的回调函数:

     配置Wave波形格式:

     尝试打开输入设备并准备缓冲区:

     这时我们可以干其他的事情,因为录音阶段所有的数据都由刚设置的回调函数处理:

     停止录制:

     我们还可以写入wav文件保存起来

    自己很仓促地写了一个WaveRecorder类,想直接用的可以回到顶部下载,可以满足大多数人的需求,但里面用到了STL。 

    MMAPI的实时获取音频数据的实现就写到这

MCI看起来比较文艺(笑),用起来也是简单到几句话而已,虽然是非实时的,但是行数跟MMAPI差距也太大了吧!

Windows基础-实时录音程序(WaveXXX)写在前面 使用MMAPI(WaveXxxAPI) 使用MCI(字符串命令)

继续阅读