音頻算法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\n");
      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 實驗用的音頻數據就不放到這里了,有誰需要可以留言郵箱,我發個你。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM