• 音频算法speex中的aec分析以及解析


    算法原理:

      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 = 8000;
    
       if (argc != 4)
       {   
          fprintf(stderr, "testecho mic_signal.sw speaker_signal.sw output.sw
    ");
          exit(1);
       }   
       echo_fd = fopen(argv[2], "rb");
       ref_fd  = fopen(argv[1],  "rb");
       e_fd    = fopen(argv[3], "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 0;
    }

      命令: ./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 实验用的音频数据就不放到这里了,有谁需要可以留言邮箱,我发个你。

  • 相关阅读:
    HTML 语义化标签-新增标签介绍
    HTML基础知识点
    Android JSON 解析关键代码
    [USACO16DEC]Cities and States省市
    [洛谷P1835]素数密度
    [洛谷P1168]中位数
    [HNOI2008]越狱
    [HAOI2007]上升序列
    [SHOI2009]Booking 会场预约
    [洛谷P1892][codevs2597]团伙
  • 原文地址:https://www.cnblogs.com/dylancao/p/11179717.html
Copyright © 2020-2023  润新知