153a5a1b3Sopenharmony_ci/* Copyright (C) 2006-2008 CSIRO, Jean-Marc Valin, Xiph.Org Foundation
253a5a1b3Sopenharmony_ci
353a5a1b3Sopenharmony_ci   File: scal.c
453a5a1b3Sopenharmony_ci   Shaped comb-allpass filter for channel decorrelation
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci   Redistribution and use in source and binary forms, with or without
753a5a1b3Sopenharmony_ci   modification, are permitted provided that the following conditions are
853a5a1b3Sopenharmony_ci   met:
953a5a1b3Sopenharmony_ci
1053a5a1b3Sopenharmony_ci   1. Redistributions of source code must retain the above copyright notice,
1153a5a1b3Sopenharmony_ci   this list of conditions and the following disclaimer.
1253a5a1b3Sopenharmony_ci
1353a5a1b3Sopenharmony_ci   2. Redistributions in binary form must reproduce the above copyright
1453a5a1b3Sopenharmony_ci   notice, this list of conditions and the following disclaimer in the
1553a5a1b3Sopenharmony_ci   documentation and/or other materials provided with the distribution.
1653a5a1b3Sopenharmony_ci
1753a5a1b3Sopenharmony_ci   3. The name of the author may not be used to endorse or promote products
1853a5a1b3Sopenharmony_ci   derived from this software without specific prior written permission.
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2153a5a1b3Sopenharmony_ci   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2253a5a1b3Sopenharmony_ci   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2353a5a1b3Sopenharmony_ci   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
2453a5a1b3Sopenharmony_ci   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2553a5a1b3Sopenharmony_ci   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2653a5a1b3Sopenharmony_ci   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2753a5a1b3Sopenharmony_ci   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2853a5a1b3Sopenharmony_ci   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2953a5a1b3Sopenharmony_ci   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3053a5a1b3Sopenharmony_ci   POSSIBILITY OF SUCH DAMAGE.
3153a5a1b3Sopenharmony_ci*/
3253a5a1b3Sopenharmony_ci
3353a5a1b3Sopenharmony_ci/*
3453a5a1b3Sopenharmony_ciThe algorithm implemented here is described in:
3553a5a1b3Sopenharmony_ci
3653a5a1b3Sopenharmony_ci* J.-M. Valin, Perceptually-Motivated Nonlinear Channel Decorrelation For
3753a5a1b3Sopenharmony_ci  Stereo Acoustic Echo Cancellation, Accepted for Joint Workshop on
3853a5a1b3Sopenharmony_ci  Hands­free Speech Communication and Microphone Arrays (HSCMA), 2008.
3953a5a1b3Sopenharmony_ci  http://people.xiph.org/~jm/papers/valin_hscma2008.pdf
4053a5a1b3Sopenharmony_ci
4153a5a1b3Sopenharmony_ci*/
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
4453a5a1b3Sopenharmony_ci#include "config.h"
4553a5a1b3Sopenharmony_ci#endif
4653a5a1b3Sopenharmony_ci
4753a5a1b3Sopenharmony_ci#include "speex/speex_echo.h"
4853a5a1b3Sopenharmony_ci#include "vorbis_psy.h"
4953a5a1b3Sopenharmony_ci#include "arch.h"
5053a5a1b3Sopenharmony_ci#include "os_support.h"
5153a5a1b3Sopenharmony_ci#include "smallft.h"
5253a5a1b3Sopenharmony_ci#include <math.h>
5353a5a1b3Sopenharmony_ci#include <stdlib.h>
5453a5a1b3Sopenharmony_ci
5553a5a1b3Sopenharmony_ci#ifndef M_PI
5653a5a1b3Sopenharmony_ci#define M_PI           3.14159265358979323846  /* pi */
5753a5a1b3Sopenharmony_ci#endif
5853a5a1b3Sopenharmony_ci
5953a5a1b3Sopenharmony_ci#define ALLPASS_ORDER 20
6053a5a1b3Sopenharmony_ci
6153a5a1b3Sopenharmony_cistruct SpeexDecorrState_ {
6253a5a1b3Sopenharmony_ci   int rate;
6353a5a1b3Sopenharmony_ci   int channels;
6453a5a1b3Sopenharmony_ci   int frame_size;
6553a5a1b3Sopenharmony_ci#ifdef VORBIS_PSYCHO
6653a5a1b3Sopenharmony_ci   VorbisPsy *psy;
6753a5a1b3Sopenharmony_ci   struct drft_lookup lookup;
6853a5a1b3Sopenharmony_ci   float *wola_mem;
6953a5a1b3Sopenharmony_ci   float *curve;
7053a5a1b3Sopenharmony_ci#endif
7153a5a1b3Sopenharmony_ci   float *vorbis_win;
7253a5a1b3Sopenharmony_ci   int    seed;
7353a5a1b3Sopenharmony_ci   float *y;
7453a5a1b3Sopenharmony_ci
7553a5a1b3Sopenharmony_ci   /* Per-channel stuff */
7653a5a1b3Sopenharmony_ci   float *buff;
7753a5a1b3Sopenharmony_ci   float (*ring)[ALLPASS_ORDER];
7853a5a1b3Sopenharmony_ci   int *ringID;
7953a5a1b3Sopenharmony_ci   int *order;
8053a5a1b3Sopenharmony_ci   float *alpha;
8153a5a1b3Sopenharmony_ci};
8253a5a1b3Sopenharmony_ci
8353a5a1b3Sopenharmony_ci
8453a5a1b3Sopenharmony_ci
8553a5a1b3Sopenharmony_ciEXPORT SpeexDecorrState *speex_decorrelate_new(int rate, int channels, int frame_size)
8653a5a1b3Sopenharmony_ci{
8753a5a1b3Sopenharmony_ci   int i, ch;
8853a5a1b3Sopenharmony_ci   SpeexDecorrState *st = speex_alloc(sizeof(SpeexDecorrState));
8953a5a1b3Sopenharmony_ci   st->rate = rate;
9053a5a1b3Sopenharmony_ci   st->channels = channels;
9153a5a1b3Sopenharmony_ci   st->frame_size = frame_size;
9253a5a1b3Sopenharmony_ci#ifdef VORBIS_PSYCHO
9353a5a1b3Sopenharmony_ci   st->psy = vorbis_psy_init(rate, 2*frame_size);
9453a5a1b3Sopenharmony_ci   spx_drft_init(&st->lookup, 2*frame_size);
9553a5a1b3Sopenharmony_ci   st->wola_mem = speex_alloc(frame_size*sizeof(float));
9653a5a1b3Sopenharmony_ci   st->curve = speex_alloc(frame_size*sizeof(float));
9753a5a1b3Sopenharmony_ci#endif
9853a5a1b3Sopenharmony_ci   st->y = speex_alloc(frame_size*sizeof(float));
9953a5a1b3Sopenharmony_ci
10053a5a1b3Sopenharmony_ci   st->buff = speex_alloc(channels*2*frame_size*sizeof(float));
10153a5a1b3Sopenharmony_ci   st->ringID = speex_alloc(channels*sizeof(int));
10253a5a1b3Sopenharmony_ci   st->order = speex_alloc(channels*sizeof(int));
10353a5a1b3Sopenharmony_ci   st->alpha = speex_alloc(channels*sizeof(float));
10453a5a1b3Sopenharmony_ci   st->ring = speex_alloc(channels*ALLPASS_ORDER*sizeof(float));
10553a5a1b3Sopenharmony_ci
10653a5a1b3Sopenharmony_ci   /*FIXME: The +20 is there only as a kludge for ALL_PASS_OLA*/
10753a5a1b3Sopenharmony_ci   st->vorbis_win = speex_alloc((2*frame_size+20)*sizeof(float));
10853a5a1b3Sopenharmony_ci   for (i=0;i<2*frame_size;i++)
10953a5a1b3Sopenharmony_ci      st->vorbis_win[i] = sin(.5*M_PI* sin(M_PI*i/(2*frame_size))*sin(M_PI*i/(2*frame_size)) );
11053a5a1b3Sopenharmony_ci   st->seed = rand();
11153a5a1b3Sopenharmony_ci
11253a5a1b3Sopenharmony_ci   for (ch=0;ch<channels;ch++)
11353a5a1b3Sopenharmony_ci   {
11453a5a1b3Sopenharmony_ci      for (i=0;i<ALLPASS_ORDER;i++)
11553a5a1b3Sopenharmony_ci         st->ring[ch][i] = 0;
11653a5a1b3Sopenharmony_ci      st->ringID[ch] = 0;
11753a5a1b3Sopenharmony_ci      st->alpha[ch] = 0;
11853a5a1b3Sopenharmony_ci      st->order[ch] = 10;
11953a5a1b3Sopenharmony_ci   }
12053a5a1b3Sopenharmony_ci   return st;
12153a5a1b3Sopenharmony_ci}
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_cistatic float uni_rand(int *seed)
12453a5a1b3Sopenharmony_ci{
12553a5a1b3Sopenharmony_ci   const unsigned int jflone = 0x3f800000;
12653a5a1b3Sopenharmony_ci   const unsigned int jflmsk = 0x007fffff;
12753a5a1b3Sopenharmony_ci   union {int i; float f;} ran;
12853a5a1b3Sopenharmony_ci   *seed = 1664525 * *seed + 1013904223;
12953a5a1b3Sopenharmony_ci   ran.i = jflone | (jflmsk & *seed);
13053a5a1b3Sopenharmony_ci   ran.f -= 1.5;
13153a5a1b3Sopenharmony_ci   return 2*ran.f;
13253a5a1b3Sopenharmony_ci}
13353a5a1b3Sopenharmony_ci
13453a5a1b3Sopenharmony_cistatic unsigned int irand(int *seed)
13553a5a1b3Sopenharmony_ci{
13653a5a1b3Sopenharmony_ci   *seed = 1664525 * *seed + 1013904223;
13753a5a1b3Sopenharmony_ci   return ((unsigned int)*seed)>>16;
13853a5a1b3Sopenharmony_ci}
13953a5a1b3Sopenharmony_ci
14053a5a1b3Sopenharmony_ci
14153a5a1b3Sopenharmony_ciEXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_int16_t *out, int strength)
14253a5a1b3Sopenharmony_ci{
14353a5a1b3Sopenharmony_ci   int ch;
14453a5a1b3Sopenharmony_ci   float amount;
14553a5a1b3Sopenharmony_ci
14653a5a1b3Sopenharmony_ci   if (strength<0)
14753a5a1b3Sopenharmony_ci      strength = 0;
14853a5a1b3Sopenharmony_ci   if (strength>100)
14953a5a1b3Sopenharmony_ci      strength = 100;
15053a5a1b3Sopenharmony_ci
15153a5a1b3Sopenharmony_ci   amount = .01*strength;
15253a5a1b3Sopenharmony_ci   for (ch=0;ch<st->channels;ch++)
15353a5a1b3Sopenharmony_ci   {
15453a5a1b3Sopenharmony_ci      int i;
15553a5a1b3Sopenharmony_ci      int N=2*st->frame_size;
15653a5a1b3Sopenharmony_ci      float beta, beta2;
15753a5a1b3Sopenharmony_ci      float *x;
15853a5a1b3Sopenharmony_ci      float max_alpha = 0;
15953a5a1b3Sopenharmony_ci
16053a5a1b3Sopenharmony_ci      float *buff;
16153a5a1b3Sopenharmony_ci      float *ring;
16253a5a1b3Sopenharmony_ci      int ringID;
16353a5a1b3Sopenharmony_ci      int order;
16453a5a1b3Sopenharmony_ci      float alpha;
16553a5a1b3Sopenharmony_ci
16653a5a1b3Sopenharmony_ci      buff = st->buff+ch*2*st->frame_size;
16753a5a1b3Sopenharmony_ci      ring = st->ring[ch];
16853a5a1b3Sopenharmony_ci      ringID = st->ringID[ch];
16953a5a1b3Sopenharmony_ci      order = st->order[ch];
17053a5a1b3Sopenharmony_ci      alpha = st->alpha[ch];
17153a5a1b3Sopenharmony_ci
17253a5a1b3Sopenharmony_ci      for (i=0;i<st->frame_size;i++)
17353a5a1b3Sopenharmony_ci         buff[i] = buff[i+st->frame_size];
17453a5a1b3Sopenharmony_ci      for (i=0;i<st->frame_size;i++)
17553a5a1b3Sopenharmony_ci         buff[i+st->frame_size] = in[i*st->channels+ch];
17653a5a1b3Sopenharmony_ci
17753a5a1b3Sopenharmony_ci      x = buff+st->frame_size;
17853a5a1b3Sopenharmony_ci
17953a5a1b3Sopenharmony_ci      if (amount>1)
18053a5a1b3Sopenharmony_ci         beta = 1-sqrt(.4*amount);
18153a5a1b3Sopenharmony_ci      else
18253a5a1b3Sopenharmony_ci         beta = 1-0.63246*amount;
18353a5a1b3Sopenharmony_ci      if (beta<0)
18453a5a1b3Sopenharmony_ci         beta = 0;
18553a5a1b3Sopenharmony_ci
18653a5a1b3Sopenharmony_ci      beta2 = beta;
18753a5a1b3Sopenharmony_ci      for (i=0;i<st->frame_size;i++)
18853a5a1b3Sopenharmony_ci      {
18953a5a1b3Sopenharmony_ci         st->y[i] = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[st->frame_size+i+order]
19053a5a1b3Sopenharmony_ci               + x[i-ALLPASS_ORDER]*st->vorbis_win[st->frame_size+i]
19153a5a1b3Sopenharmony_ci               - alpha*(ring[ringID]
19253a5a1b3Sopenharmony_ci               - beta*ring[ringID+1>=order?0:ringID+1]);
19353a5a1b3Sopenharmony_ci         ring[ringID++]=st->y[i];
19453a5a1b3Sopenharmony_ci         st->y[i] *= st->vorbis_win[st->frame_size+i];
19553a5a1b3Sopenharmony_ci         if (ringID>=order)
19653a5a1b3Sopenharmony_ci            ringID=0;
19753a5a1b3Sopenharmony_ci      }
19853a5a1b3Sopenharmony_ci      order = order+(irand(&st->seed)%3)-1;
19953a5a1b3Sopenharmony_ci      if (order < 5)
20053a5a1b3Sopenharmony_ci         order = 5;
20153a5a1b3Sopenharmony_ci      if (order > 10)
20253a5a1b3Sopenharmony_ci         order = 10;
20353a5a1b3Sopenharmony_ci      /*order = 5+(irand(&st->seed)%6);*/
20453a5a1b3Sopenharmony_ci      max_alpha = pow(.96+.04*(amount-1),order);
20553a5a1b3Sopenharmony_ci      if (max_alpha > .98/(1.+beta2))
20653a5a1b3Sopenharmony_ci         max_alpha = .98/(1.+beta2);
20753a5a1b3Sopenharmony_ci
20853a5a1b3Sopenharmony_ci      alpha = alpha + .4*uni_rand(&st->seed);
20953a5a1b3Sopenharmony_ci      if (alpha > max_alpha)
21053a5a1b3Sopenharmony_ci         alpha = max_alpha;
21153a5a1b3Sopenharmony_ci      if (alpha < -max_alpha)
21253a5a1b3Sopenharmony_ci         alpha = -max_alpha;
21353a5a1b3Sopenharmony_ci      for (i=0;i<ALLPASS_ORDER;i++)
21453a5a1b3Sopenharmony_ci         ring[i] = 0;
21553a5a1b3Sopenharmony_ci      ringID = 0;
21653a5a1b3Sopenharmony_ci      for (i=0;i<st->frame_size;i++)
21753a5a1b3Sopenharmony_ci      {
21853a5a1b3Sopenharmony_ci         float tmp =  alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[i+order]
21953a5a1b3Sopenharmony_ci               + x[i-ALLPASS_ORDER]*st->vorbis_win[i]
22053a5a1b3Sopenharmony_ci               - alpha*(ring[ringID]
22153a5a1b3Sopenharmony_ci               - beta*ring[ringID+1>=order?0:ringID+1]);
22253a5a1b3Sopenharmony_ci         ring[ringID++]=tmp;
22353a5a1b3Sopenharmony_ci         tmp *= st->vorbis_win[i];
22453a5a1b3Sopenharmony_ci         if (ringID>=order)
22553a5a1b3Sopenharmony_ci            ringID=0;
22653a5a1b3Sopenharmony_ci         st->y[i] += tmp;
22753a5a1b3Sopenharmony_ci      }
22853a5a1b3Sopenharmony_ci
22953a5a1b3Sopenharmony_ci#ifdef VORBIS_PSYCHO
23053a5a1b3Sopenharmony_ci      float frame[N];
23153a5a1b3Sopenharmony_ci      float scale = 1./N;
23253a5a1b3Sopenharmony_ci      for (i=0;i<2*st->frame_size;i++)
23353a5a1b3Sopenharmony_ci         frame[i] = buff[i];
23453a5a1b3Sopenharmony_ci   //float coef = .5*0.78130;
23553a5a1b3Sopenharmony_ci      float coef = M_PI*0.075063 * 0.93763 * amount * .8 * 0.707;
23653a5a1b3Sopenharmony_ci      compute_curve(st->psy, buff, st->curve);
23753a5a1b3Sopenharmony_ci      for (i=1;i<st->frame_size;i++)
23853a5a1b3Sopenharmony_ci      {
23953a5a1b3Sopenharmony_ci         float x1,x2;
24053a5a1b3Sopenharmony_ci         float gain;
24153a5a1b3Sopenharmony_ci         do {
24253a5a1b3Sopenharmony_ci            x1 = uni_rand(&st->seed);
24353a5a1b3Sopenharmony_ci            x2 = uni_rand(&st->seed);
24453a5a1b3Sopenharmony_ci         } while (x1*x1+x2*x2 > 1.);
24553a5a1b3Sopenharmony_ci         gain = coef*sqrt(.1+st->curve[i]);
24653a5a1b3Sopenharmony_ci         frame[2*i-1] = gain*x1;
24753a5a1b3Sopenharmony_ci         frame[2*i] = gain*x2;
24853a5a1b3Sopenharmony_ci      }
24953a5a1b3Sopenharmony_ci      frame[0] = coef*uni_rand(&st->seed)*sqrt(.1+st->curve[0]);
25053a5a1b3Sopenharmony_ci      frame[2*st->frame_size-1] = coef*uni_rand(&st->seed)*sqrt(.1+st->curve[st->frame_size-1]);
25153a5a1b3Sopenharmony_ci      spx_drft_backward(&st->lookup,frame);
25253a5a1b3Sopenharmony_ci      for (i=0;i<2*st->frame_size;i++)
25353a5a1b3Sopenharmony_ci         frame[i] *= st->vorbis_win[i];
25453a5a1b3Sopenharmony_ci#endif
25553a5a1b3Sopenharmony_ci
25653a5a1b3Sopenharmony_ci      for (i=0;i<st->frame_size;i++)
25753a5a1b3Sopenharmony_ci      {
25853a5a1b3Sopenharmony_ci#ifdef VORBIS_PSYCHO
25953a5a1b3Sopenharmony_ci         float tmp = st->y[i] + frame[i] + st->wola_mem[i];
26053a5a1b3Sopenharmony_ci         st->wola_mem[i] = frame[i+st->frame_size];
26153a5a1b3Sopenharmony_ci#else
26253a5a1b3Sopenharmony_ci         float tmp = st->y[i];
26353a5a1b3Sopenharmony_ci#endif
26453a5a1b3Sopenharmony_ci         if (tmp>32767)
26553a5a1b3Sopenharmony_ci            tmp = 32767;
26653a5a1b3Sopenharmony_ci         if (tmp < -32767)
26753a5a1b3Sopenharmony_ci            tmp = -32767;
26853a5a1b3Sopenharmony_ci         out[i*st->channels+ch] = tmp;
26953a5a1b3Sopenharmony_ci      }
27053a5a1b3Sopenharmony_ci
27153a5a1b3Sopenharmony_ci      st->ringID[ch] = ringID;
27253a5a1b3Sopenharmony_ci      st->order[ch] = order;
27353a5a1b3Sopenharmony_ci      st->alpha[ch] = alpha;
27453a5a1b3Sopenharmony_ci
27553a5a1b3Sopenharmony_ci   }
27653a5a1b3Sopenharmony_ci}
27753a5a1b3Sopenharmony_ci
27853a5a1b3Sopenharmony_ciEXPORT void speex_decorrelate_destroy(SpeexDecorrState *st)
27953a5a1b3Sopenharmony_ci{
28053a5a1b3Sopenharmony_ci#ifdef VORBIS_PSYCHO
28153a5a1b3Sopenharmony_ci   vorbis_psy_destroy(st->psy);
28253a5a1b3Sopenharmony_ci   speex_free(st->wola_mem);
28353a5a1b3Sopenharmony_ci   speex_free(st->curve);
28453a5a1b3Sopenharmony_ci#endif
28553a5a1b3Sopenharmony_ci   speex_free(st->buff);
28653a5a1b3Sopenharmony_ci   speex_free(st->ring);
28753a5a1b3Sopenharmony_ci   speex_free(st->ringID);
28853a5a1b3Sopenharmony_ci   speex_free(st->alpha);
28953a5a1b3Sopenharmony_ci   speex_free(st->vorbis_win);
29053a5a1b3Sopenharmony_ci   speex_free(st->order);
29153a5a1b3Sopenharmony_ci   speex_free(st->y);
29253a5a1b3Sopenharmony_ci   speex_free(st);
29353a5a1b3Sopenharmony_ci}
294