1/* Copyright (C) 2006-2008 CSIRO, Jean-Marc Valin, Xiph.Org Foundation
2
3   File: scal.c
4   Shaped comb-allpass filter for channel decorrelation
5
6   Redistribution and use in source and binary forms, with or without
7   modification, are permitted provided that the following conditions are
8   met:
9
10   1. Redistributions of source code must retain the above copyright notice,
11   this list of conditions and the following disclaimer.
12
13   2. Redistributions in binary form must reproduce the above copyright
14   notice, this list of conditions and the following disclaimer in the
15   documentation and/or other materials provided with the distribution.
16
17   3. The name of the author may not be used to endorse or promote products
18   derived from this software without specific prior written permission.
19
20   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23   DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   POSSIBILITY OF SUCH DAMAGE.
31*/
32
33/*
34The algorithm implemented here is described in:
35
36* J.-M. Valin, Perceptually-Motivated Nonlinear Channel Decorrelation For
37  Stereo Acoustic Echo Cancellation, Accepted for Joint Workshop on
38  Hands­free Speech Communication and Microphone Arrays (HSCMA), 2008.
39  http://people.xiph.org/~jm/papers/valin_hscma2008.pdf
40
41*/
42
43#ifdef HAVE_CONFIG_H
44#include "config.h"
45#endif
46
47#include "speex/speex_echo.h"
48#include "vorbis_psy.h"
49#include "arch.h"
50#include "os_support.h"
51#include "smallft.h"
52#include <math.h>
53#include <stdlib.h>
54
55#define ALLPASS_ORDER 20
56
57struct SpeexDecorrState_ {
58   int rate;
59   int channels;
60   int frame_size;
61#ifdef VORBIS_PSYCHO
62   VorbisPsy *psy;
63   struct drft_lookup lookup;
64   float *wola_mem;
65   float *curve;
66#endif
67   float *vorbis_win;
68   int    seed;
69   float *y;
70
71   /* Per-channel stuff */
72   float *buff;
73   float (*ring)[ALLPASS_ORDER];
74   int *ringID;
75   int *order;
76   float *alpha;
77};
78
79
80
81EXPORT SpeexDecorrState *speex_decorrelate_new(int rate, int channels, int frame_size)
82{
83   int i, ch;
84   SpeexDecorrState *st = speex_alloc(sizeof(SpeexDecorrState));
85   st->rate = rate;
86   st->channels = channels;
87   st->frame_size = frame_size;
88#ifdef VORBIS_PSYCHO
89   st->psy = vorbis_psy_init(rate, 2*frame_size);
90   spx_drft_init(&st->lookup, 2*frame_size);
91   st->wola_mem = speex_alloc(frame_size*sizeof(float));
92   st->curve = speex_alloc(frame_size*sizeof(float));
93#endif
94   st->y = speex_alloc(frame_size*sizeof(float));
95
96   st->buff = speex_alloc(channels*2*frame_size*sizeof(float));
97   st->ringID = speex_alloc(channels*sizeof(int));
98   st->order = speex_alloc(channels*sizeof(int));
99   st->alpha = speex_alloc(channels*sizeof(float));
100   st->ring = speex_alloc(channels*ALLPASS_ORDER*sizeof(float));
101
102   /*FIXME: The +20 is there only as a kludge for ALL_PASS_OLA*/
103   st->vorbis_win = speex_alloc((2*frame_size+20)*sizeof(float));
104   for (i=0;i<2*frame_size;i++)
105      st->vorbis_win[i] = sin(.5*M_PI* sin(M_PI*i/(2*frame_size))*sin(M_PI*i/(2*frame_size)) );
106   st->seed = rand();
107
108   for (ch=0;ch<channels;ch++)
109   {
110      for (i=0;i<ALLPASS_ORDER;i++)
111         st->ring[ch][i] = 0;
112      st->ringID[ch] = 0;
113      st->alpha[ch] = 0;
114      st->order[ch] = 10;
115   }
116   return st;
117}
118
119static float uni_rand(int *seed)
120{
121   const unsigned int jflone = 0x3f800000;
122   const unsigned int jflmsk = 0x007fffff;
123   union {int i; float f;} ran;
124   *seed = 1664525 * *seed + 1013904223;
125   ran.i = jflone | (jflmsk & *seed);
126   ran.f -= 1.5;
127   return 2*ran.f;
128}
129
130static unsigned int irand(int *seed)
131{
132   *seed = 1664525 * *seed + 1013904223;
133   return ((unsigned int)*seed)>>16;
134}
135
136
137EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_int16_t *out, int strength)
138{
139   int ch;
140   float amount;
141
142   if (strength<0)
143      strength = 0;
144   if (strength>100)
145      strength = 100;
146
147   amount = .01*strength;
148   for (ch=0;ch<st->channels;ch++)
149   {
150      int i;
151      int N=2*st->frame_size;
152      float beta, beta2;
153      float *x;
154      float max_alpha = 0;
155
156      float *buff;
157      float *ring;
158      int ringID;
159      int order;
160      float alpha;
161
162      buff = st->buff+ch*2*st->frame_size;
163      ring = st->ring[ch];
164      ringID = st->ringID[ch];
165      order = st->order[ch];
166      alpha = st->alpha[ch];
167
168      for (i=0;i<st->frame_size;i++)
169         buff[i] = buff[i+st->frame_size];
170      for (i=0;i<st->frame_size;i++)
171         buff[i+st->frame_size] = in[i*st->channels+ch];
172
173      x = buff+st->frame_size;
174      beta = 1.-.3*amount*amount;
175      if (amount>1)
176         beta = 1-sqrt(.4*amount);
177      else
178         beta = 1-0.63246*amount;
179      if (beta<0)
180         beta = 0;
181
182      beta2 = beta;
183      for (i=0;i<st->frame_size;i++)
184      {
185         st->y[i] = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[st->frame_size+i+order]
186               + x[i-ALLPASS_ORDER]*st->vorbis_win[st->frame_size+i]
187               - alpha*(ring[ringID]
188               - beta*ring[ringID+1>=order?0:ringID+1]);
189         ring[ringID++]=st->y[i];
190         st->y[i] *= st->vorbis_win[st->frame_size+i];
191         if (ringID>=order)
192            ringID=0;
193      }
194      order = order+(irand(&st->seed)%3)-1;
195      if (order < 5)
196         order = 5;
197      if (order > 10)
198         order = 10;
199      /*order = 5+(irand(&st->seed)%6);*/
200      max_alpha = pow(.96+.04*(amount-1),order);
201      if (max_alpha > .98/(1.+beta2))
202         max_alpha = .98/(1.+beta2);
203
204      alpha = alpha + .4*uni_rand(&st->seed);
205      if (alpha > max_alpha)
206         alpha = max_alpha;
207      if (alpha < -max_alpha)
208         alpha = -max_alpha;
209      for (i=0;i<ALLPASS_ORDER;i++)
210         ring[i] = 0;
211      ringID = 0;
212      for (i=0;i<st->frame_size;i++)
213      {
214         float tmp =  alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[i+order]
215               + x[i-ALLPASS_ORDER]*st->vorbis_win[i]
216               - alpha*(ring[ringID]
217               - beta*ring[ringID+1>=order?0:ringID+1]);
218         ring[ringID++]=tmp;
219         tmp *= st->vorbis_win[i];
220         if (ringID>=order)
221            ringID=0;
222         st->y[i] += tmp;
223      }
224
225#ifdef VORBIS_PSYCHO
226      float frame[N];
227      float scale = 1./N;
228      for (i=0;i<2*st->frame_size;i++)
229         frame[i] = buff[i];
230   //float coef = .5*0.78130;
231      float coef = M_PI*0.075063 * 0.93763 * amount * .8 * 0.707;
232      compute_curve(st->psy, buff, st->curve);
233      for (i=1;i<st->frame_size;i++)
234      {
235         float x1,x2;
236         float gain;
237         do {
238            x1 = uni_rand(&st->seed);
239            x2 = uni_rand(&st->seed);
240         } while (x1*x1+x2*x2 > 1.);
241         gain = coef*sqrt(.1+st->curve[i]);
242         frame[2*i-1] = gain*x1;
243         frame[2*i] = gain*x2;
244      }
245      frame[0] = coef*uni_rand(&st->seed)*sqrt(.1+st->curve[0]);
246      frame[2*st->frame_size-1] = coef*uni_rand(&st->seed)*sqrt(.1+st->curve[st->frame_size-1]);
247      spx_drft_backward(&st->lookup,frame);
248      for (i=0;i<2*st->frame_size;i++)
249         frame[i] *= st->vorbis_win[i];
250#endif
251
252      for (i=0;i<st->frame_size;i++)
253      {
254#ifdef VORBIS_PSYCHO
255         float tmp = st->y[i] + frame[i] + st->wola_mem[i];
256         st->wola_mem[i] = frame[i+st->frame_size];
257#else
258         float tmp = st->y[i];
259#endif
260         if (tmp>32767)
261            tmp = 32767;
262         if (tmp < -32767)
263            tmp = -32767;
264         out[i*st->channels+ch] = tmp;
265      }
266
267      st->ringID[ch] = ringID;
268      st->order[ch] = order;
269      st->alpha[ch] = alpha;
270
271   }
272}
273
274EXPORT void speex_decorrelate_destroy(SpeexDecorrState *st)
275{
276#ifdef VORBIS_PSYCHO
277   vorbis_psy_destroy(st->psy);
278   speex_free(st->wola_mem);
279   speex_free(st->curve);
280#endif
281   speex_free(st->buff);
282   speex_free(st->ring);
283   speex_free(st->ringID);
284   speex_free(st->alpha);
285   speex_free(st->vorbis_win);
286   speex_free(st->order);
287   speex_free(st->y);
288   speex_free(st);
289}
290