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 Handsfree 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