} } }

    一个简单的灌音法度

    添加时间:2013-7-20 点击量:

    比来要一个语音识此外Demo,研究了下语音辨认常识之后,发明先要实现一个灌音模块,百度的过程中,看到的是应用DirectSound实现灌音,于是欣欣然筹办开端(以前可能懂得过DirectX,一向想找机会进修进修),然后在看DirectX SDK的过程中,DirectSound有一段话介绍灌音也可以应用Windows Multimedia functions,并且DirectSound在这方面并没有机能上风。鉴于比来工作斗劲余暇,想多学点器材的目标,筹算研究下这两种实现体式格式。

    • DirectSound实现办法
    • 首要参考链接:哄骗DirectSound实现声卡灌音,还有根蒂根基使之补充:http://www.cnblogs.com/stg609/archive/2008/10/24/1318931.html。
    • 这里补充一下本身在这个过程中碰到的一点题目。

    1、IID_IDirectSoundCaptureBuffer8的题目

    在创建一个灌音的Buffer对象LPDIRECTSOUNDCAPTUREBUFFER8的过程中,用到QuerryInterface函数,此中第一个参数为IID_IDirectSoundCaptureBuffer8,我当时是链接不上这个标识的,试着加了InitGuid.h 等发明也不可,百度什么的也没找到成果,然后问了以前一个同事,成果人家在Google上一下就搜到成果了,要加上DXGuid.lib,我这里才懂得到,本来baidu和google搜刮同样的内容,成果会这么不一样。汗颜。

    2、IDirectSoundCaptureBuffer8.GetCurrentPosition参数意义

    这个函数的两个参数,一个是Capture指针在缓冲中的地位,一个是Read指针在缓冲中的地位。要重视的是,Read指针是指名当前你可以读到哪个地位,而不是从哪个地位开端读,比如第一次取数据的时辰,会取缓冲的开端地位到Read指针所指的地位。又因为是一个环形的缓冲,所以Capture指针的地位不必然老是大于Read指针的,可以懂得成,Capture注解了在调用这个函数时正在登科的数据将要写到(为止)的地位,而Read是已经写好了的到这个地位为止的地位。所以我们在读取数据的时辰要保存一个偏移量,记录每次要读取的数据的肇端地位。

    3、录出来的声音老是不合错误

    按照SDK以及材料收拾好了Demo的代码,发明生成的文件播放出来的声音老是不合错误,搜检了好久都没找到题目,因为对这方面研究的少所以不知道从何入手了。今朝确认的题目有,IDirectSoundCaptureBuffer8.GetCurrentPosition有时辰前后两次会返回雷同的值,别的生成的wave文件比实际登科的时候要长。

    固然这个题目还没解决,我也发了帖子进行询问,还没找到题目地点,也附上源码,有经验的伴侣也可以辅佐看看。

     

    • Windows WaveIn系类API 实现体式格式
    • 参考链接:基于API的灌音机法度,这个链接里粗略介绍了下全部实现流程,具体的实现体式格式还是要参考各函数的MSDN申明。链接中供给的Demo因为是VC6的,并且我发明没有dsw文件(有可能是我的时辰失足了),所以我在VS2010下新建了一个同名的MFC对话框并把源文件和资料文件全部覆盖掉,更改掉消息映射函数(VCVS2010的消息映射函数情势不一样了,可拜见ON_MESSAGE宏),别的去掉了那个HYPELINK控件(有它编译不过),加上winmm.lib链接,就能编畴昔了,跑起来结果还不错。
    • 这里也补充上本身碰到的一些题目。

    1、列举设备的题目

    今朝我发明waveIn系列的API没有直接供给列举灌音设备的接口,可以采取的一种体式格式是哄骗设备描述表的树布局去接见设备并经由过程断定设备类型来进行列举,这种办法是同事介绍的,我没有做测验测验,斗劲繁琐。所以就用了DirectX的列举接口,然则DirectX应用的是GUID去标识一个设备,而waveInOpen函数是请求一个设备ID,所以就须要一个经由过程GUID获取设备ID的办法,这里也是询问了之前的一个同事,然后从之前做过的项目中借用的项目组代码实现了这个功能,具体实现体式格式我没太看懂,可能是应用了DirectX的属性体式格式之类的,具体的可以看代码。

    2、停止灌音的题目

    waveIn系列API的缓冲机制是边供给边应用的体式格式,就是你供给给他,他应用完了就转交给你,你再提交这种轮回。凡是这个操纵是做在消息WIM_DATA的处理惩罚过程中。这里须要重视停止灌音的时辰,起首调用waveInStop停止灌音(此时体系内部可能还稀有据没有写到缓冲,所以WIM_DATA消息在这之后还会来),然后调用waveInReset,这个函数SDK有明白申明会将所有提交了的未应用的缓冲都返回给我们,所以WIM_DATA仍然会来,但在这个过程中我们不克不及再提交缓冲了(有时辰会提交失败),所以我这里在调用waveInReset函数之前设置了个标记,当这个标记被置位的时辰就不提交缓冲了。最后调用waveInClose函数,这个函数会使得标识设备的句柄失效,所以在这之后就不克不及应用设备句柄了。

     

    最后总结

        我在看第二种体式格式的Demo的时辰,明显感触感染比第一种体式格式的简单,有可能是我对这方面的懂得加深了,所以看起来简单些了。缓冲机制方面,第一种是直接供给一个环形缓冲就行,第二种是用户本身供给若干个缓冲,当体系用完之后就转交给你,你若是要持续应用就又要递交给它,显然第一种在算法上高等一些,但第二种要简单更轻易懂得一些。我小我更偏向于第二种。

        又是好久没写博客了,之前告退在家待了好几个月,然后又出来工作,感触感染太陌生了,这个小法度也算是又一个匹面吧。

    最后附上全部过程中的所有源码,此中SoundCapturer为我应用waveIn所封装的demo,DSRecordDemo为我应用DirectX的demo,RecordHWnd为我从VC常识库的demo进行批改之后的demo,waveInDemo是从网上找到的代码。

    地址:

    http://files.cnblogs.com/monotone/RecordDemo.zip

    容易发怒的意思就是: 别人做了蠢事, 然后我们代替他们, 表现出笨蛋的样子。—— 蔡康永
    分享到: