123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- /* Copyright (C) 2006-2008 CSIRO, Jean-Marc Valin, Xiph.Org Foundation
- File: scal.c
- Shaped comb-allpass filter for channel decorrelation
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
- */
- /*
- The algorithm implemented here is described in:
- * J.-M. Valin, Perceptually-Motivated Nonlinear Channel Decorrelation For
- Stereo Acoustic Echo Cancellation, Accepted for Joint Workshop on
- Handsfree Speech Communication and Microphone Arrays (HSCMA), 2008.
- http://people.xiph.org/~jm/papers/valin_hscma2008.pdf
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "speex/speex_echo.h"
- #include "vorbis_psy.h"
- #include "arch.h"
- #include "os_support.h"
- #include "smallft.h"
- #include <math.h>
- #include <stdlib.h>
- #ifndef M_PI
- #define M_PI 3.14159265358979323846 /* pi */
- #endif
- #define ALLPASS_ORDER 20
- struct SpeexDecorrState_ {
- int rate;
- int channels;
- int frame_size;
- #ifdef VORBIS_PSYCHO
- VorbisPsy *psy;
- struct drft_lookup lookup;
- float *wola_mem;
- float *curve;
- #endif
- float *vorbis_win;
- int seed;
- float *y;
-
- /* Per-channel stuff */
- float *buff;
- float (*ring)[ALLPASS_ORDER];
- int *ringID;
- int *order;
- float *alpha;
- };
- EXPORT SpeexDecorrState *speex_decorrelate_new(int rate, int channels, int frame_size)
- {
- int i, ch;
- SpeexDecorrState *st = speex_alloc(sizeof(SpeexDecorrState));
- st->rate = rate;
- st->channels = channels;
- st->frame_size = frame_size;
- #ifdef VORBIS_PSYCHO
- st->psy = vorbis_psy_init(rate, 2*frame_size);
- spx_drft_init(&st->lookup, 2*frame_size);
- st->wola_mem = speex_alloc(frame_size*sizeof(float));
- st->curve = speex_alloc(frame_size*sizeof(float));
- #endif
- st->y = speex_alloc(frame_size*sizeof(float));
- st->buff = speex_alloc(channels*2*frame_size*sizeof(float));
- st->ringID = speex_alloc(channels*sizeof(int));
- st->order = speex_alloc(channels*sizeof(int));
- st->alpha = speex_alloc(channels*sizeof(float));
- st->ring = speex_alloc(channels*ALLPASS_ORDER*sizeof(float));
-
- /*FIXME: The +20 is there only as a kludge for ALL_PASS_OLA*/
- st->vorbis_win = speex_alloc((2*frame_size+20)*sizeof(float));
- for (i=0;i<2*frame_size;i++)
- st->vorbis_win[i] = sin(.5*M_PI* sin(M_PI*i/(2*frame_size))*sin(M_PI*i/(2*frame_size)) );
- st->seed = rand();
-
- for (ch=0;ch<channels;ch++)
- {
- for (i=0;i<ALLPASS_ORDER;i++)
- st->ring[ch][i] = 0;
- st->ringID[ch] = 0;
- st->alpha[ch] = 0;
- st->order[ch] = 10;
- }
- return st;
- }
- static float uni_rand(int *seed)
- {
- const unsigned int jflone = 0x3f800000;
- const unsigned int jflmsk = 0x007fffff;
- union {int i; float f;} ran;
- *seed = 1664525 * *seed + 1013904223;
- ran.i = jflone | (jflmsk & *seed);
- ran.f -= 1.5;
- return 2*ran.f;
- }
- static unsigned int irand(int *seed)
- {
- *seed = 1664525 * *seed + 1013904223;
- return ((unsigned int)*seed)>>16;
- }
- EXPORT void speex_decorrelate(SpeexDecorrState *st, const spx_int16_t *in, spx_int16_t *out, int strength)
- {
- int ch;
- float amount;
-
- if (strength<0)
- strength = 0;
- if (strength>100)
- strength = 100;
-
- amount = .01*strength;
- for (ch=0;ch<st->channels;ch++)
- {
- int i;
- //int N=2*st->frame_size;
- float beta, beta2;
- float *x;
- float max_alpha = 0;
-
- float *buff;
- float *ring;
- int ringID;
- int order;
- float alpha;
- buff = st->buff+ch*2*st->frame_size;
- ring = st->ring[ch];
- ringID = st->ringID[ch];
- order = st->order[ch];
- alpha = st->alpha[ch];
-
- for (i=0;i<st->frame_size;i++)
- buff[i] = buff[i+st->frame_size];
- for (i=0;i<st->frame_size;i++)
- buff[i+st->frame_size] = in[i*st->channels+ch];
- x = buff+st->frame_size;
- if (amount>1)
- beta = 1-sqrt(.4*amount);
- else
- beta = 1-0.63246*amount;
- if (beta<0)
- beta = 0;
-
- beta2 = beta;
- for (i=0;i<st->frame_size;i++)
- {
- st->y[i] = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[st->frame_size+i+order]
- + x[i-ALLPASS_ORDER]*st->vorbis_win[st->frame_size+i]
- - alpha*(ring[ringID]
- - beta*ring[ringID+1>=order?0:ringID+1]);
- ring[ringID++]=st->y[i];
- st->y[i] *= st->vorbis_win[st->frame_size+i];
- if (ringID>=order)
- ringID=0;
- }
- order = order+(irand(&st->seed)%3)-1;
- if (order < 5)
- order = 5;
- if (order > 10)
- order = 10;
- /*order = 5+(irand(&st->seed)%6);*/
- max_alpha = pow(.96+.04*(amount-1),order);
- if (max_alpha > .98/(1.+beta2))
- max_alpha = .98/(1.+beta2);
-
- alpha = alpha + .4*uni_rand(&st->seed);
- if (alpha > max_alpha)
- alpha = max_alpha;
- if (alpha < -max_alpha)
- alpha = -max_alpha;
- for (i=0;i<ALLPASS_ORDER;i++)
- ring[i] = 0;
- ringID = 0;
- for (i=0;i<st->frame_size;i++)
- {
- float tmp = alpha*(x[i-ALLPASS_ORDER+order]-beta*x[i-ALLPASS_ORDER+order-1])*st->vorbis_win[i+order]
- + x[i-ALLPASS_ORDER]*st->vorbis_win[i]
- - alpha*(ring[ringID]
- - beta*ring[ringID+1>=order?0:ringID+1]);
- ring[ringID++]=tmp;
- tmp *= st->vorbis_win[i];
- if (ringID>=order)
- ringID=0;
- st->y[i] += tmp;
- }
-
- #ifdef VORBIS_PSYCHO
- float frame[N];
- float scale = 1./N;
- for (i=0;i<2*st->frame_size;i++)
- frame[i] = buff[i];
- //float coef = .5*0.78130;
- float coef = M_PI*0.075063 * 0.93763 * amount * .8 * 0.707;
- compute_curve(st->psy, buff, st->curve);
- for (i=1;i<st->frame_size;i++)
- {
- float x1,x2;
- float gain;
- do {
- x1 = uni_rand(&st->seed);
- x2 = uni_rand(&st->seed);
- } while (x1*x1+x2*x2 > 1.);
- gain = coef*sqrt(.1+st->curve[i]);
- frame[2*i-1] = gain*x1;
- frame[2*i] = gain*x2;
- }
- frame[0] = coef*uni_rand(&st->seed)*sqrt(.1+st->curve[0]);
- frame[2*st->frame_size-1] = coef*uni_rand(&st->seed)*sqrt(.1+st->curve[st->frame_size-1]);
- spx_drft_backward(&st->lookup,frame);
- for (i=0;i<2*st->frame_size;i++)
- frame[i] *= st->vorbis_win[i];
- #endif
-
- for (i=0;i<st->frame_size;i++)
- {
- #ifdef VORBIS_PSYCHO
- float tmp = st->y[i] + frame[i] + st->wola_mem[i];
- st->wola_mem[i] = frame[i+st->frame_size];
- #else
- float tmp = st->y[i];
- #endif
- if (tmp>32767)
- tmp = 32767;
- if (tmp < -32767)
- tmp = -32767;
- out[i*st->channels+ch] = tmp;
- }
-
- st->ringID[ch] = ringID;
- st->order[ch] = order;
- st->alpha[ch] = alpha;
- }
- }
- EXPORT void speex_decorrelate_destroy(SpeexDecorrState *st)
- {
- #ifdef VORBIS_PSYCHO
- vorbis_psy_destroy(st->psy);
- speex_free(st->wola_mem);
- speex_free(st->curve);
- #endif
- speex_free(st->buff);
- speex_free(st->ring);
- speex_free(st->ringID);
- speex_free(st->alpha);
- speex_free(st->vorbis_win);
- speex_free(st->order);
- speex_free(st->y);
- speex_free(st);
- }
|