http://hulong988.blog.51cto.com
解密回声消除技术之一(理论篇) 2009-06-11 22:24:58
本文出自 “碧海银沙” 博客,请务必保留此出处http://silversand.blog.51cto.com/820613/166095
标题: 作者:zhaohl 时间:2006-09-26 16:22 | |
网上可查到的用于回音消除的源码很少。 但对于想做SOFTPHONE的人来说,这些东西也是必不可少的。 在DIRECTSOUND中带有AEC功能,但必须是XP以上系统支持。 [[i] 本帖最后由 zhaohl 于 2006-9-26 16:23 编辑 [/i]] |
|
标题:谢谢楼主 作者:yangziyi 时间:2006-10-18 11:30 | |
你的东西对我太有用了,希望以后能多提供 | |
标题: 作者:y123456 时间:2006-10-21 16:21 | |
bucuo | |
标题: 作者:share2000 时间:2006-10-31 11:27 | |
好东西。楼主是做什么方面的工作的。我是做汽车音箱方面的。有机会多交流。 我的email- [email][email protected][/email] | |
标题: 作者:taijilin 时间:2006-11-14 01:03 | |
好东西,顶一下 | |
标题: 作者:alpha6 时间:2006-11-20 14:45 | |
好东西啊 | |
标题:回复 #1 zhaohl 的帖子 作者:xbwang020 时间:2006-12-13 09:30 | |
好像晚上这方面的资料太少了 ^_^ | |
标题:这个软件怎么测试呀? 作者:11uu 时间:2006-12-13 17:37 | |
请教各位DX,请问这个软件怎么测试呀,直接执行echo.exe吗?没有效果呀。 | |
标题:顶 作者:11uu 时间:2006-12-13 17:41 | |
请教搂主和各位DX | |
标题:搂主 作者:11uu 时间:2006-12-13 17:43 | |
你在哪里呀? | |
标题: 作者:wmh_hong 时间:2006-12-14 23:50 | |
不错~ | |
标题:[转]一个开源的声学回声消除器(Acoustic Echo Cancellation) 作者:zero100 时间:2006-12-18 23:45 | |
前段时间,搞了一阵声学回声消除,非常郁闷,因为没有成功,但可以说学到一点东西吧,至少理论上懂了一点。 为什么需要声学回声消除呢?在一般的VOIP软件或视频会议系统中,假设我们只有A和B两个人在通话,首先,A的声音传给B,B然后用喇叭放出来,而这时B的MIC呢则会采集到喇叭放出来的声音,然后传回给A,如果这个传输的过程中时延足够大,A就会听到一个和自己刚才说过的话一样的声音,这就是回声,声学回声消除器的作用就是在B端对B采集到的声音进行处理,把采集到声音包含的A的声音去掉再传给A,这样,A就不会听到自己说过的话了。 声学回声消除的原理我就不说了,这在网上有很多文档,网上缺少的是实现,所以,我在这把一个开源的声学回声消除器介绍一下,希望对有些有人用,如果有人知道怎么把这消除器用的基于实时流的VOIP软件中,希望能一起分享一下。 这个声学回声消除器是一个著名的音频编解码器speex中的一部分,1.1.9版本后的回声消除器才起作用,以前版本的都不行,我用的也是这个版本,测试表明,用同一个模拟文件,它有效果比INTEL IPP库4.1版中的声学回声消除器的还要好。 先说编译。首先,从[url]www.speex.org[/url]上下载speex1.1.9的源代码,解压,打开speex\win32\libspeex中的libspeex.dsw,这个工作区里有两个工程,一个是libspeex,另一个是libspeex_dynamic。然后,将libspeex中的mdf.c文件添加到工程libspeex中,编译即可。 以下是我根据文档封装的一个类,里面有一个测试程序: //file name: speexEC.h #ifndef SPEEX_EC_H #define SPEEX_EC_H #include <stdio.h> #include <stdlib.h> #include "speex/speex_echo.h" #include "speex/speex_preprocess.h" class CSpeexEC { public: CSpeexEC(); ~CSpeexEC(); void Init(int frame_size=160, int filter_length=1280, int sampling_rate=8000); void DoAEC(short *mic, short *ref, short *out); protected: void Reset(); private: bool m_bHasInit; SpeexEchoState* m_pState; SpeexPreprocessState* m_pPreprocessorState; int m_nFrameSize; int m_nFilterLen; int m_nSampleRate; float* m_pfNoise; }; #endif //fine name:speexEC.cpp #include "SpeexEC.h" CSpeexEC::CSpeexEC() { m_bHasInit = false; m_pState = NULL; m_pPreprocessorState = NULL; m_nFrameSize = 160; m_nFilterLen = 160*8; m_nSampleRate = 8000; m_pfNoise = NULL; } CSpeexEC::~CSpeexEC() { Reset(); } void CSpeexEC::Init(int frame_size, int filter_length, int sampling_rate) { Reset(); if (frame_size<=0 || filter_length<=0 || sampling_rate<=0) { m_nFrameSize =160; m_nFilterLen = 160*8; m_nSampleRate = 8000; } else { m_nFrameSize =frame_size; m_nFilterLen = filter_length; m_nSampleRate = sampling_rate; } m_pState = speex_echo_state_init(m_nFrameSize, m_nFilterLen); m_pPreprocessorState = speex_preprocess_state_init(m_nFrameSize, m_nSampleRate); m_pfNoise = new float[m_nFrameSize+1]; m_bHasInit = true; } void CSpeexEC::Reset() { if (m_pState != NULL) { speex_echo_state_destroy(m_pState); m_pState = NULL; } if (m_pPreprocessorState != NULL) { speex_preprocess_state_destroy(m_pPreprocessorState); m_pPreprocessorState = NULL; } if (m_pfNoise != NULL) { delete []m_pfNoise; m_pfNoise = NULL; } m_bHasInit = false; } void CSpeexEC::DoAEC(short* mic, short* ref, short* out) { if (!m_bHasInit) return; speex_echo_cancel(m_pState, mic, ref, out, m_pfNoise); speex_preprocess(m_pPreprocessorState, (__int16 *)out, m_pfNoise); } 可以看出,这个回声消除器类很简单,只要初始化一下就可以调用了。但是,要注意的是,传给回声消除器的两个声音信号,必须同步得非常的好,就是说,在B端,接收到A说的话以后,要把这些话音数据传给回声消除器做参考,然后再传给声卡,声卡再放出来,这有一段延时,这时,B再采集,然后传给回声消除器,与那个参考数据比较,从采集到的数据中把频域和参考数据相同的部分消除掉。如果传给消除器的两个信号同步得不好,即两个信号找不到频域相同的部分,就没有办法进行消除了。 测试程序: #define NN 160 void main() { FILE* ref_fd, *mic_fd, *out_fd; short ref[NN], mic[NN], out[NN]; ref_fd = fopen ("ref.pcm", "rb"); //打开参考文件,即要消除的声音 mic_fd = fopen ("mic.pcm", "rb");//打开mic采集到的声音文件,包含回声在里面 out_fd = fopen ("echo.pcm", "wb");//消除了回声以后的文件 CSpeexEC ec; ec.Init(); while (fread(mic, 1, NN*2, mic_fd)) { fread(ref, 1, NN*2, ref_fd); ec.DoAEC(mic, ref, out); fwrite(out, 1, NN*2, out_fd); } fclose(ref_fd); fclose(mic_fd); fclose(out_fd); } 以上的程序是用文件来模拟回声和MIC,但在实时流中是大不一样的,在一般的VOIP软件中,接收对方的声音并传到声卡中播放是在一个线程中进行的,而采集本地的声音并传送到对方又是在另一个线程中进行的,而声学回声消除器在对采集到的声音进行回声消除的同时,还需要播放线程中的数据作为参考,而要同步这两个线程中的数据是非常困难的,因为稍稍有些不同步,声学回声消除器中的自适应滤波器就会发散,不但消除不了回声,还会破坏原始采集到的声音,使被破坏的声音难以分辨。我做过好多尝试,始终无法用软件来实现对这两个线程中的数据进行同步,导致实现失败,希望有经验的网友们一起分享一下这方面的经验。 |