算法原理:

  Speex的AEC是以NLMS(Normalized Least Mean Square)为基础,用MDF(multidelay block frequency domain)频域实现,最终推导出最优步长估计:残余回声与误差之比。最优步长等于残余回声方差与误差信号方差之比。 只有改与泄露系数相关部分的代码,才是对效果影响最大的地方,因为根据泄露系数,最终会估计出滤波器的最优步长。

使用实例:

  测试代码:

 #include "speex/speex_echo.h"
#include "speex/speex_preprocess.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> #define NN 128
#define TAIL 1024 int main(int argc, char **argv)
{
FILE *echo_fd, *ref_fd, *e_fd;
short echo_buf[NN], ref_buf[NN], e_buf[NN];
SpeexEchoState *st;
SpeexPreprocessState *den;
int sampleRate = ; if (argc != )
{
fprintf(stderr, "testecho mic_signal.sw speaker_signal.sw output.sw\n");
exit();
}
echo_fd = fopen(argv[], "rb");
ref_fd = fopen(argv[], "rb");
e_fd = fopen(argv[], "wb"); st = speex_echo_state_init(NN, TAIL);
den = speex_preprocess_state_init(NN, sampleRate);
speex_echo_ctl(st, SPEEX_ECHO_SET_SAMPLING_RATE, &sampleRate);
speex_preprocess_ctl(den, SPEEX_PREPROCESS_SET_ECHO_STATE, st); while (!feof(ref_fd) && !feof(echo_fd))
{
fread(ref_buf, sizeof(short), NN, ref_fd);
fread(echo_buf, sizeof(short), NN, echo_fd);
speex_echo_cancellation(st, ref_buf, echo_buf, e_buf);
speex_preprocess_run(den, e_buf);
fwrite(e_buf, sizeof(short), NN, e_fd);
}
speex_echo_state_destroy(st);
speex_preprocess_state_destroy(den);
fclose(e_fd);
fclose(echo_fd);
fclose(ref_fd);
return ;
}

  命令: ./testecho speaker1.wav micin1.wav out1.wav

  测试结果:
  最新的speex的aec效果非常的好,超出了我的想象,回声消除效果不是一般的好,看来是speex更新了不少,因为自从2007年之后,speex很长一段时间都没有更新过代码。有兴趣的同学可以听一下消回声后的和之前的音频对比。

代码解析:

  初始化中,第一个参数是每次处理的帧长度,这个一般是从10ms(80) 到30ms(240) 的处理长度,太长和太短都不是很好,filter_length 也是一个长度,它实际上就是speaker到rec之间的时间差。这个在不同设备上是不同的,跟产品的使用场景,结构,以及软件耗时有关系,一般的是可以测试出来的。
SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)

系统默认的消回声采样是8k的,如下所示,假如你想改变采样频率,
/* This is the default sampling rate */
427 st->sampling_rate = 8000;
428 st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate);

要使用下面的函数:speex_preprocess_state_init(NN,sampleRate)
接下来是要配置消回声的参数设置,一般是采样率设置。
speex_echo_ctl(st, SPEEX_ECHO_SET_SAMPLING_RATE, &sampleRate);
参数都可以以下这些:

46 /** Obtain frame size used by the AEC */
47 #define SPEEX_ECHO_GET_FRAME_SIZE 3
48
49 /** Set sampling rate */
50 #define SPEEX_ECHO_SET_SAMPLING_RATE 24
51 /** Get sampling rate */
52 #define SPEEX_ECHO_GET_SAMPLING_RATE 25
53
54 /* Can't set window sizes */
55 /** Get size of impulse response (int32) */
56 #define SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE 27
57
58 /* Can't set window content */
59 /** Get impulse response (int32[]) */
60 #define SPEEX_ECHO_GET_IMPULSE_RESPONSE 29

最重要的函数登场了:这个函数,非常的好用,估计只要看一下入参,你就知道怎么使用了。具体的使用就看上面的例子吧。
void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out)

假如在预处理中有些参数设置,需要调用预处理函数再把输出的结果处理一下,假如预处理没有了,那就不需要了。
speex_preprocess_run(den, e_buf);
其实,代码流程就这么简单,但是,想把系统效果调试的很好,还是要花不少功夫的。

注意事项:

1 AEC的线性算法处理不了Non-linear distortion(非线性失真)
2 在其它预处理前 先调用AEC
3 speex的aec并不是很适合音响系统里,音响中要慎用。耳机中效果还挺好。
4 实验用的音频数据就不放到这里了,有谁需要可以留言邮箱,我发个你。

音频算法speex中的aec分析以及解析的更多相关文章

  1. 音频软件开发中的debug方法和工具

    本文系作者原创.如转载,请注明出处. 谢谢! 音频软件开发同其他软件开发一样,都需要去调试.音频软件调试同其他软件调试方法有相同的地方,也有不同的地方,同时调试时还需要借助一些专门的工具,有了这些方法 ...

  2. WebRTC 音频算法 附完整C代码

    WebRTC提供一套音频处理引擎, 包含以下算法: AGC自动增益控制(Automatic Gain Control) ANS噪音抑制(Automatic Noise Suppression) AEC ...

  3. 音频压缩(Speex使用&Opus简介)--转

    博客地址:http://blog.csdn.net/kevindgk GitHub地址:https://github.com/KevinDGK/MyAudioDemo 一简介 二局域网语音配置 三Sp ...

  4. OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

    http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...

  5. 第2章 rsync算法原理和工作流程分析

    本文通过示例详细分析rsync算法原理和rsync的工作流程,是对rsync官方技术报告和官方推荐文章的解释. 以下是本文的姊妹篇: 1.rsync(一):基本命令和用法 2.rsync(二):ino ...

  6. Android 中图片压缩分析(上)

    作者: shawnzhao,QQ音乐技术团队一员 一.前言 在 Android 中进行图片压缩是非常常见的开发场景,主要的压缩方法有两种:其一是质量压缩,其二是下采样压缩. 前者是在不改变图片尺寸的情 ...

  7. HanLP中人名识别分析

    HanLP中人名识别分析 在看源码之前,先看几遍论文<基于角色标注的中国人名自动识别研究> 关于命名识别的一些问题,可参考下列一些issue: 名字识别的问题 #387 机构名识别错误 关 ...

  8. rsync算法原理和工作流程分析

    本文通过示例详细分析rsync算法原理和rsync的工作流程,是对rsync官方技术报告和官方推荐文章的解释.本文不会介绍如何使用rsync命令(见rsync基本用法),而是详细解释它如何实现高效的增 ...

  9. HanLP中人名识别分析详解

    HanLP中人名识别分析详解 在看源码之前,先看几遍论文<基于角色标注的中国人名自动识别研究> 关于命名识别的一些问题,可参考下列一些issue: l ·名字识别的问题 #387 l ·机 ...

随机推荐

  1. 【C#】WPF的xaml中定义的Trigger为什么有时候会不管用,如Border的MouseOver之类的

    原文:[C#]WPF的xaml中定义的Trigger为什么有时候会不管用,如Border的MouseOver之类的 初学WPF,知道一些控件可以通过定义Style的Trigger改变要显示的样式,但是 ...

  2. 在 __CC_ARM 编译器环境下,使用$Sub$$ 与 $Super$$ 的“补丁”功能

    $Sub$$ 与 $Super$$ 的“补丁”功能(详见 ARM® Compiler v5.06 for µVision® armlink User Guide): 这是一种特殊模式:用于有一个已经存 ...

  3. Android零基础入门第80节:Intent 属性详解(下)

    上一期学习了Intent的前三个属性,本期接着学习其余四个属性,以及Android系统常用内置组件的启动. 四.Data和Type属性 Data属性通常用于向Action属性提供操作的数据.Data属 ...

  4. 在Delphi中创建线程,请一定使用BeginThread()代替CreateThread()创建线程!(更好的管理异常)

    在Delphi中创建线程,请一定使用BeginThread()代替CreateThread()创建线程! 如果直接使用Win32的API函数CreateThread()创建多个线程,也是可以创建的.但 ...

  5. matplotlib简介

    python的matplotlib包可以帮助我们绘制丰富的图表,有助于我们的数据分析. matplotlib官方文档:matplotlib 本博客所有代码默认导入matplotlib.pyplot和n ...

  6. easyui tree后台传json处理问题

    一.tree json格式 [ { "id": 1, "text": "权限管理", "iconCls": " ...

  7. 多玩YY语音的面试题:C++中如何在main()函数之前执行操作?

    多玩YY语音的面试题:C++中如何在main()函数之前执行操作? 第一反应main()函数是所有函数执行的开始.但是问题是main()函数执行之前如何执行呢? 联想到MFC里面的 C**App类的t ...

  8. Delphi&C#代码模拟“显示桌面”的功能(使用CreateOleObject('Shell.Application'))

    今天有人问我:“用shell打开文件(显示桌面.scf)的方式还是用模拟键盘(Win+D)显示桌面”这应该有更好的方法,就搜了搜,关键字定位“ToggleDesktop”因为显示桌面.scf的内容是: ...

  9. 桌面程序阻止Windows关机(使用Message.Result取得DefWindowProc API函数的返回值,非常重要)

    Windows Client 客户端在关机,不外乎两种情况: 1. 没有处理 Windows 关机消息: 2.处理了关机消息,但是超时了: 上面这两种情况,都会让Windows 关不了机.在现实生活中 ...

  10. ORACLE(student)表习题与答案

    因为答案都是小编自己写的,解法可能有多种,如果您觉得我的解法有误,希望您有时间给我留言. 题目:1. 查询student表中的所有记录的sname.ssex和class列. SELECT sname, ...