| 
							- /* 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 
 -   HandsĀfree 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);
 - }
 
 
  |