/* Copyright (C) 2007 Hong Zhiqian */ | |
/** | |
@file preprocess_tm.h | |
@author Hong Zhiqian | |
@brief Various compatibility routines for Speex (TriMedia version) | |
*/ | |
/* | |
Redistribution and use in source and binary forms, with or without | |
modification, are permitted provided that the following conditions | |
are met: | |
- Redistributions of source code must retain the above copyright | |
notice, this list of conditions and the following disclaimer. | |
- 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. | |
- Neither the name of the Xiph.org Foundation nor the names of its | |
contributors may be used to endorse or promote products derived from | |
this software without specific prior written permission. | |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
``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 FOUNDATION OR | |
CONTRIBUTORS 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. | |
*/ | |
#include <ops/custom_defs.h> | |
#include "profile_tm.h" | |
#ifdef FIXED_POINT | |
#define OVERRIDE_PREPROCESS_ANALYSIS | |
static void preprocess_analysis(SpeexPreprocessState * restrict st, spx_int16_t * restrict x) | |
{ | |
register int i, j, framesize = st->frame_size; | |
register int N = st->ps_size; | |
register int N3 = 2*N - framesize; | |
register int N4 = framesize - N3; | |
register int * restrict ps = st->ps; | |
register int * restrict frame; | |
register int * restrict inbuf; | |
register int * restrict ptr; | |
register int max_val; | |
frame = (int*)(st->frame); | |
inbuf = (int*)(st->inbuf); | |
ptr = (int*)(st->frame+N3); | |
TMDEBUG_ALIGNMEM(x); | |
TMDEBUG_ALIGNMEM(frame); | |
TMDEBUG_ALIGNMEM(inbuf); | |
PREPROCESSANAYLSIS_START(); | |
N3 >>= 1; | |
framesize >>= 1; | |
max_val = 0; | |
for ( i=0,j=0 ; i<N3 ; i+=2,j+=8 ) | |
{ register int r1, r2; | |
r1 = ld32x(inbuf,i); | |
r2 = ld32x(inbuf,i+1); | |
st32d(j, frame, r1); | |
st32d(j+4, frame, r2); | |
} | |
for ( i=0,j=0 ; i<framesize ; i+=2,j+=8 ) | |
{ register int r1, r2; | |
r1 = ld32x(x, i); | |
r2 = ld32x(x, i+1); | |
st32d(j, ptr, r1); | |
st32d(j+4,ptr, r2); | |
} | |
for ( i=0,j=0,ptr=(int*)(x+N4) ; i<N3 ; i+=2,j+=8 ) | |
{ register int r1, r2; | |
r1 = ld32x(ptr, i); | |
r2 = ld32x(ptr, i+1); | |
st32d(j, inbuf, r1); | |
st32d(j+4,inbuf, r2); | |
} | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unroll=2 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0,j=0,ptr=(int*)st->window ; i<N ; ++i,j+=4 ) | |
{ register int f10, w10, r0, r1; | |
f10 = ld32x(frame, i); | |
w10 = ld32x(ptr, i); | |
r0 = (sex16(f10) * sex16(w10)) >> 15; | |
r1 = (asri(16,f10) * asri(16,w10)) >> 15; | |
max_val = imax(iabs(sex16(r0)), max_val); | |
max_val = imax(iabs(sex16(r1)), max_val); | |
r0 = pack16lsb(r1, r0); | |
st32d(j, frame, r0); | |
} | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
max_val = 14 - spx_ilog2(max_val); | |
st->frame_shift = max_val; | |
if ( max_val != 0 ) | |
{ | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0,j=0 ; i<N ; ++i,j+=4 ) | |
{ register int f10; | |
f10 = ld32x(frame, i); | |
f10 = dualasl(f10, max_val); | |
st32d(j, frame, f10); | |
} | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} | |
spx_fft(st->fft_lookup, st->frame, st->ft); | |
power_spectrum(st->ft, ps, N << 1); | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0,ptr=(int*)st->ps,max_val<<=1,j=((1<<((max_val))>>1)) ;i<N ; ++i ) | |
{ | |
ps[i] = (ps[i] + j) >> max_val; | |
} | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
filterbank_compute_bank32(st->bank, ps, ps+N); | |
PREPROCESSANAYLSIS_STOP(); | |
} | |
#define _MULT16_32_Q15(a,b,c) ADD32(MULT16_16((a),(b)), SHR(MULT16_16((a),(c)),15)) | |
#define OVERRIDE_UPDATE_NOISE_PROB | |
static void update_noise_prob(SpeexPreprocessState * restrict st) | |
{ | |
register int i; | |
register int min_range, nb_adapt; | |
register int N = st->ps_size; | |
register int * restrict Smin = (int*)st->Smin; | |
register int * restrict Stmp = (int*)st->Stmp; | |
register int * restrict S = (int*)st->S; | |
UPDATENOISEPROB_START(); | |
{ | |
register int psi_lsb, psi_msb, ips_lsb, ips_msb, psii_lsb, psii_msb; | |
register int psiii_lsb, psiii_msb; | |
register int q8, q05, q2, q1; | |
register int *ps = (int*)st->ps; | |
register int si_lsb, si_msb, sii_lsb, sii_msb; | |
q8 = QCONST16(.8f,15); | |
q05 = QCONST16(.05f,15); | |
q2 = QCONST16(.2f,15); | |
q1 = QCONST16(.1f,15); | |
ips_lsb = ps[0]; | |
psi_lsb = ps[1]; | |
si_lsb = S[0]; | |
ips_msb = ips_lsb >> 15; | |
psi_msb = psi_lsb >> 15; | |
si_msb = si_lsb >> 15; | |
ips_lsb &= 0x00007fff; | |
psi_lsb &= 0x00007fff; | |
si_lsb &= 0x00007fff; | |
S[0] = _MULT16_32_Q15(q8,si_msb,si_lsb) + _MULT16_32_Q15(q2,ips_msb,ips_lsb); | |
for ( i=1 ; i<N-1 ; i+=2 ) | |
{ | |
psii_lsb = ps[i+1]; | |
si_lsb = S[i]; | |
psii_msb = psii_lsb >> 15; | |
si_msb = si_lsb >> 15; | |
si_lsb &= 0x00007fff; | |
psii_lsb &= 0x00007fff; | |
S[i]= _MULT16_32_Q15(q8,si_msb,si_lsb) + | |
_MULT16_32_Q15(q05,ips_msb,ips_lsb) + | |
_MULT16_32_Q15(q1,psi_msb,psi_lsb) + | |
_MULT16_32_Q15(q05,psii_msb,psii_lsb); | |
psiii_lsb = ps[i+2]; | |
sii_lsb = S[i+1]; | |
sii_msb = sii_lsb >> 15; | |
psiii_msb= psiii_lsb >> 15; | |
sii_lsb &= 0x00007fff; | |
psiii_lsb&= 0x00007fff; | |
S[i+1]= _MULT16_32_Q15(q8,sii_msb,sii_lsb) + | |
_MULT16_32_Q15(q05,psi_msb,psi_lsb) + | |
_MULT16_32_Q15(q1,psii_msb,psii_lsb) + | |
_MULT16_32_Q15(q05,psiii_msb,psiii_lsb); | |
ips_lsb = psii_lsb; | |
ips_msb = psii_msb; | |
psi_lsb = psiii_lsb; | |
psi_msb = psiii_msb; | |
} | |
S[N-1] = MULT16_32_Q15(q8,S[N-1]) + MULT16_32_Q15(q2,ps[N-1]); | |
} | |
nb_adapt = st->nb_adapt; | |
if ( nb_adapt==1 ) | |
{ for ( i=0 ; i<N ; ++i ) | |
Smin[i] = Stmp[i] = 0; | |
} | |
min_range = mux(nb_adapt < 100, 15, | |
mux(nb_adapt < 1000, 50, | |
mux(nb_adapt < 10000, 150, 300))); | |
if ( st->min_count > min_range ) | |
{ | |
st->min_count = 0; | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unroll=2 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<N ; ++i ) | |
{ register int si, stmpi; | |
si = S[i]; | |
stmpi = Stmp[i]; | |
Smin[i] = imin(stmpi,si); | |
Stmp[i] = si; | |
} | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} else | |
{ | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unroll=2 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<N ; ++i ) | |
{ register int si, stmpi, smini; | |
si = S[i]; | |
stmpi = Stmp[i]; | |
smini = Smin[i]; | |
Smin[i] = imin(smini,si); | |
Stmp[i] = imin(stmpi,si); | |
} | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} | |
{ | |
register int q4; | |
register int * restrict update_prob = (int*)st->update_prob; | |
q4 = QCONST16(.4f,15); | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<N ; ++i ) | |
{ register int si; | |
register int smini; | |
si = S[i]; | |
smini = Smin[i]; | |
update_prob[i] = mux(MULT16_32_Q15(q4,si) > ADD32(smini,20), 1, 0); | |
} | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} | |
UPDATENOISEPROB_STOP(); | |
} | |
#else | |
#define OVERRIDE_PREPROCESS_ANALYSIS | |
static void preprocess_analysis(SpeexPreprocessState * restrict st, spx_int16_t * restrict x) | |
{ | |
register int i; | |
register int framesize = st->frame_size; | |
register int N = st->ps_size; | |
register int N3 = 2*N - framesize; | |
register int N4 = framesize - N3; | |
register float * restrict ps = st->ps; | |
register float * restrict frame = st->frame; | |
register float * restrict inbuf = st->inbuf; | |
PREPROCESSANAYLSIS_START(); | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<N3 ; ++i ) | |
{ | |
frame[i] = inbuf[i]; | |
} | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<framesize ; ++i ) | |
{ frame[N3+i] = x[i]; | |
} | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0,x+=N4 ; i<N3 ; ++i ) | |
{ inbuf[i] = x[i]; | |
} | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
inbuf = st->window; | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<2*N ; ++i ) | |
{ | |
frame[i] = frame[i] * inbuf[i]; | |
} | |
#if (TM_UNROLL && TM_UNROLL_PREPROCESSANALYSIS) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
spx_fft(st->fft_lookup, frame, st->ft); | |
power_spectrum(st->ft, ps, N << 1); | |
filterbank_compute_bank32(st->bank, ps, ps+N); | |
PREPROCESSANAYLSIS_STOP(); | |
} | |
#define OVERRIDE_UPDATE_NOISE_PROB | |
static void update_noise_prob(SpeexPreprocessState * restrict st) | |
{ | |
register float * restrict S = st->S; | |
register float * restrict ps = st->ps; | |
register int N = st->ps_size; | |
register int min_range; | |
register int i; | |
register int nb_adapt; | |
register float * restrict Smin = st->Smin; | |
register float * restrict Stmp = st->Stmp; | |
UPDATENOISEPROB_START(); | |
{ | |
register float ips, psi; | |
ips = ps[0]; | |
psi = ps[1]; | |
S[0] = .8f * S[0] + .2f * ips; | |
for ( i=1 ; i<N-1 ; i+=2 ) | |
{ | |
register float psii, psiii; | |
psii = ps[i+1]; | |
psiii = ps[i+2]; | |
S[i] = .8f * S[i] + .05f * ips + .1f * psi + .05f * psii; | |
S[i+1] = .8f * S[i+1] + .05f * psi + .1f * psii + .05f * psiii; | |
ips = psii; | |
psi = psiii; | |
} | |
S[N-1] = .8f * S[N-1] + .2f * ps[N-1]; | |
} | |
nb_adapt = st->nb_adapt; | |
if ( nb_adapt==1 ) | |
{ | |
for (i=0;i<N;i++) | |
Smin[i] = st->Stmp[i] = 0; | |
} | |
min_range = mux(nb_adapt < 100, 15, | |
mux(nb_adapt < 1000, 50, | |
mux(nb_adapt < 10000, 150, 300))); | |
if ( st->min_count > min_range ) | |
{ | |
st->min_count = 0; | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<N ; ++i ) | |
{ | |
register float stmpi, si; | |
stmpi = Stmp[i]; | |
si = S[i]; | |
Smin[i] = fmin(stmpi,si); | |
Stmp[i] = si; | |
} | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} else | |
{ | |
register float * restrict Smin = st->Smin; | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<N ; ++i ) | |
{ | |
register float stmpi, si, smini; | |
stmpi = Stmp[i]; | |
si = S[i]; | |
smini = Smin[i]; | |
Smin[i] = fmin(smini,si); | |
Stmp[i] = fmin(stmpi,si); | |
} | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} | |
{ | |
register int * restrict update_prob = (int*)st->update_prob; | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for (i=0;i<N;i++) | |
{ register float si; | |
register float smini; | |
si = S[i]; | |
smini = Smin[i]; | |
update_prob[i] = mux( (.4 * si) > (smini + 20.f), 1, 0); | |
} | |
#if (TM_UNROLL && TM_UNROLL_UPDATENOISEPROB) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} | |
UPDATENOISEPROB_STOP(); | |
} | |
#define OVERRIDE_COMPUTE_GAIN_FLOOR | |
static void compute_gain_floor( | |
int noise_suppress, | |
int effective_echo_suppress, | |
float * restrict noise, | |
float * restrict echo, | |
float * gain_floor, | |
int len | |
) | |
{ | |
register int i; | |
register float echo_floor; | |
register float noise_floor; | |
COMPUTEGAINFLOOR_START(); | |
noise_floor = exp(.2302585f*noise_suppress); | |
echo_floor = exp(.2302585f*effective_echo_suppress); | |
#if (TM_UNROLL && TM_UNROLL_COMPUTEGAINFLOOR) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for (i=0;i<len;i++) | |
{ register float noisei, echoi; | |
noisei = noise[i]; | |
echoi = echo[i]; | |
gain_floor[i] = FRAC_SCALING * sqrt(noise_floor * noisei + echo_floor * echoi) / sqrt(1+noisei+echoi); | |
} | |
#if (TM_UNROLL && TM_UNROLL_COMPUTEGAINFLOOR) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
COMPUTEGAINFLOOR_STOP(); | |
} | |
#endif | |
static inline spx_word32_t hypergeom_gain(spx_word32_t xx); | |
static inline spx_word16_t qcurve(spx_word16_t x); | |
static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len); | |
void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); | |
#ifndef FIXED_POINT | |
static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx_word16_t *ft); | |
#endif | |
void preprocess_residue_echo( | |
SpeexPreprocessState * restrict st, | |
int N, | |
int NM | |
) | |
{ | |
if (st->echo_state) | |
{ | |
register spx_word32_t * restrict r_echo = st->residual_echo; | |
register spx_word32_t * restrict e_noise = st->echo_noise; | |
register int i; | |
#ifndef FIXED_POINT | |
register spx_word32_t r; | |
#endif | |
speex_echo_get_residual(st->echo_state, r_echo, N); | |
#ifndef FIXED_POINT | |
r = r_echo[0]; | |
if (!(r >=0 && r < N*1e9f) ) | |
{ | |
memset(r_echo, 0, N * sizeof(spx_word32_t)); | |
} | |
#endif | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for (i=0;i<N;i++) | |
{ register spx_word32_t eni = e_noise[i]; | |
e_noise[i] = MAX32(MULT16_32_Q15(QCONST16(.6f,15),eni), r_echo[i]); | |
} | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
filterbank_compute_bank32(st->bank, e_noise, e_noise+N); | |
} else | |
{ memset(st->echo_noise, 0, (NM) * sizeof(spx_word32_t)); | |
} | |
} | |
void preprocess_update_noise( | |
SpeexPreprocessState * restrict st, | |
spx_word32_t * restrict ps, | |
int N | |
) | |
{ | |
register spx_word16_t beta, beta_1; | |
register int * restrict up = st->update_prob; | |
register spx_word32_t * restrict noise = st->noise; | |
register int i; | |
beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt)); | |
beta_1 = Q15_ONE-beta; | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for (i=0;i<N;i++) | |
{ register spx_word32_t ni = noise[i]; | |
register spx_word32_t psi = ps[i]; | |
if ( !up[i] || psi < PSHR32(ni, NOISE_SHIFT) ) | |
{ noise[i] = MAX32(EXTEND32(0),MULT16_32_Q15(beta_1,ni) + | |
MULT16_32_Q15(beta,SHL32(psi,NOISE_SHIFT))); | |
} | |
} | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
filterbank_compute_bank32(st->bank, noise, noise+N); | |
} | |
void preprocess_compute_SNR( | |
SpeexPreprocessState * restrict st, | |
spx_word32_t * restrict ps, | |
int NM | |
) | |
{ | |
register spx_word32_t * restrict noise = st->noise; | |
register spx_word32_t * restrict echo = st->echo_noise; | |
register spx_word32_t * restrict reverb = st->reverb_estimate; | |
register spx_word16_t * restrict post = st->post; | |
register spx_word32_t * restrict old_ps = st->old_ps; | |
register spx_word16_t * restrict prior = st->prior; | |
register int i; | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<NM ; i++) | |
{ | |
register spx_word16_t gamma; | |
register spx_word32_t tot_noise; | |
register spx_word16_t posti; | |
register spx_word32_t opsi; | |
register spx_word16_t priori; | |
tot_noise = ADD32(ADD32(ADD32(EXTEND32(1), PSHR32(noise[i],NOISE_SHIFT)), echo[i]) , reverb[i]); | |
posti = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT)); | |
posti = MIN16(posti, QCONST16(100.f,SNR_SHIFT)); | |
post[i] = posti; | |
opsi = old_ps[i]; | |
gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(opsi,ADD32(opsi,tot_noise)))); | |
priori = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,posti)), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(opsi,tot_noise))), 15)); | |
prior[i]=MIN16(priori, QCONST16(100.f,SNR_SHIFT)); | |
} | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} | |
spx_word32_t preprocess_smooth_SNR( | |
SpeexPreprocessState * restrict st, | |
int N, | |
int NM | |
) | |
{ | |
register spx_word16_t * restrict zeta = st->zeta; | |
register spx_word16_t * restrict prior = st->prior; | |
register spx_word32_t Zframe; | |
register spx_word16_t iprior, priori; | |
register int _N = N-1; | |
register int i; | |
iprior = prior[0]; | |
priori = prior[1]; | |
zeta[0] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),zeta[0]), MULT16_16(QCONST16(.3f,15),iprior)),15); | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unroll=2 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=1 ; i<_N ; i++) | |
{ register spx_word16_t zetai = zeta[i]; | |
register spx_word16_t priorii = prior[i+1]; | |
zeta[i] = PSHR32(ADD32(ADD32(ADD32(MULT16_16(QCONST16(.7f,15),zetai), MULT16_16(QCONST16(.15f,15),priori)), | |
MULT16_16(QCONST16(.075f,15),iprior)), MULT16_16(QCONST16(.075f,15),priorii)),15); | |
iprior = priori; | |
priori = priorii; | |
} | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
for (i=_N; i<NM ; i++) | |
{ register spx_word16_t zetai = zeta[i]; | |
priori = prior[i]; | |
zeta[i] = PSHR32(ADD32(MULT16_16(QCONST16(.7f,15),zetai), MULT16_16(QCONST16(.3f,15),priori)),15); | |
} | |
Zframe = 0; | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=N ; i<NM ; i++ ) | |
{ Zframe = ADD32(Zframe, EXTEND32(zeta[i])); | |
} | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
return Zframe; | |
} | |
void preprocess_compute_emgain( | |
SpeexPreprocessState * restrict st, | |
spx_word32_t * restrict ps, | |
spx_word16_t Pframe, | |
int NM | |
) | |
{ | |
register spx_word16_t * restrict zeta = st->zeta; | |
register spx_word16_t * restrict prior = st->prior; | |
register spx_word16_t * restrict gain = st->gain; | |
register spx_word32_t * restrict old_ps = st->old_ps; | |
register spx_word16_t * restrict post = st->post; | |
register spx_word16_t * restrict gain2 = st->gain2; | |
register int i; | |
register int N=st->ps_size; | |
for ( i=N ; i<NM ; ++i ) | |
{ | |
register spx_word32_t theta; | |
register spx_word32_t MM; | |
register spx_word16_t prior_ratio; | |
register spx_word16_t P1; | |
register spx_word16_t q; | |
#ifdef FIXED_POINT | |
register spx_word16_t tmp; | |
#endif | |
register spx_word16_t priori = prior[i]; | |
prior_ratio = PDIV32_16(SHL32(EXTEND32(priori), 15), ADD16(priori, SHL32(1,SNR_SHIFT))); | |
theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(post[i]),EXPIN_SHIFT-SNR_SHIFT)); | |
MM = hypergeom_gain(theta); | |
gain[i] = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); | |
old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(gain[i])),ps[i]); | |
P1 = QCONST16(.199f,15)+MULT16_16_Q15(QCONST16(.8f,15),qcurve (zeta[i])); | |
q = Q15_ONE-MULT16_16_Q15(Pframe,P1); | |
#ifdef FIXED_POINT | |
theta = MIN32(theta, EXTEND32(32767)); | |
tmp = MULT16_16_Q15((SHL32(1,SNR_SHIFT)+priori),EXTRACT16(MIN32(Q15ONE,SHR32(spx_exp(-EXTRACT16(theta)),1)))); | |
tmp = MIN16(QCONST16(3.,SNR_SHIFT), tmp); | |
tmp = EXTRACT16(PSHR32(MULT16_16(PDIV32_16(SHL32(EXTEND32(q),8),(Q15_ONE-q)),tmp),8)); | |
gain2[i]=DIV32_16(SHL32(EXTEND32(32767),SNR_SHIFT), ADD16(256,tmp)); | |
#else | |
gain2[i]=1/(1.f + (q/(1.f-q))*(1+priori)*exp(-theta)); | |
#endif | |
} | |
filterbank_compute_psd16(st->bank,gain2+N, gain2); | |
filterbank_compute_psd16(st->bank,gain+N, gain); | |
} | |
void preprocess_compute_linear_gain( | |
SpeexPreprocessState * restrict st, | |
spx_word32_t * restrict ps, | |
int N | |
) | |
{ | |
register spx_word16_t * restrict gain_floor = st->gain_floor; | |
register spx_word16_t * restrict prior = st->prior; | |
register spx_word16_t * restrict gain = st->gain; | |
register spx_word32_t * restrict old_ps = st->old_ps; | |
register spx_word16_t * restrict post = st->post; | |
register spx_word16_t * restrict gain2 = st->gain2; | |
register int i; | |
filterbank_compute_psd16(st->bank,gain_floor+N,gain_floor); | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for (i=0;i<N;i++) | |
{ | |
register spx_word32_t MM; | |
register spx_word32_t theta; | |
register spx_word16_t prior_ratio; | |
register spx_word16_t tmp; | |
register spx_word16_t p; | |
register spx_word16_t g; | |
register spx_word16_t gfi = gain_floor[i]; | |
prior_ratio = PDIV32_16(SHL32(EXTEND32(st->prior[i]), 15), ADD16(prior[i], SHL32(1,SNR_SHIFT))); | |
theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(post[i]),EXPIN_SHIFT-SNR_SHIFT)); | |
MM = hypergeom_gain(theta); | |
g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); | |
p = gain2[i]; | |
g = VMUX( MULT16_16_Q15(QCONST16(.333f,15),g) > gain[i], MULT16_16(3,gain[i]), g); | |
old_ps[i]= MULT16_32_P15(QCONST16(.2f,15),old_ps[i]) + | |
MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(g)),ps[i]); | |
g = VMUX( g < gfi, gfi, g ); | |
gain[i] = g; | |
tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(g),15))) + | |
MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(gfi),15))); | |
gain2[i]=SQR16_Q15(tmp); | |
/* Use this if you want a log-domain MMSE estimator instead */ | |
/* gain2[i] = pow(g, p) * pow(gfi,1.f-p);*/ | |
} | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} | |
#if 0 | |
void preprocess_compute_bark_gain( | |
SpeexPreprocessState * restrict st, | |
int N, | |
int NM | |
) | |
{ | |
register spx_word16_t * restrict gain_floor = st->gain_floor; | |
register spx_word16_t * restrict gain = st->gain; | |
register spx_word16_t * restrict gain2 = st->gain2; | |
register int i; | |
for (i=N;i<NM;i++) | |
{ | |
register spx_word16_t tmp; | |
register spx_word16_t p = gain2[i]; | |
register spx_word16_t gaini; | |
register spx_word16_t gfi = gain_floor[i]; | |
gaini = MAX16(gain[i], gfi); | |
gain[i] = gaini; | |
tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(gaini),15))) + | |
MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(gfi),15))); | |
gain2[i]=SQR16_Q15(tmp); | |
} | |
filterbank_compute_psd16(st->bank,gain2+N, gain2); | |
} | |
#endif | |
void preprocess_apply_gain( | |
SpeexPreprocessState * restrict st, | |
int N | |
) | |
{ | |
register spx_word16_t * restrict ft = st->ft; | |
register spx_word16_t * restrict gain2 = st->gain2; | |
register int j, i; | |
ft[0] = MULT16_16_P15(gain2[0],ft[0]); | |
for (i=1,j=1; i<N ; i++,j+=2) | |
{ | |
register spx_word16_t gain2i = gain2[i]; | |
register spx_word16_t ftj = ft[j]; | |
register spx_word16_t ftjj = ft[j+1]; | |
ft[j] = MULT16_16_P15(gain2i,ftj); | |
ft[j+1] = MULT16_16_P15(gain2i,ftjj); | |
} | |
ft[(N<<1)-1] = MULT16_16_P15(gain2[N-1],ft[(N<<1)-1]); | |
} | |
#ifdef FIXED_POINT | |
void preprocess_scale( | |
SpeexPreprocessState * restrict st, | |
int N | |
) | |
{ | |
register spx_word16_t * restrict frame = st->frame; | |
register int shift = st->frame_shift; | |
register int i; | |
register int N2 = N << 1; | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<N2 ;i++) | |
{ register spx_word16_t framei = frame[i]; | |
frame[i] = PSHR16(framei,shift); | |
} | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} | |
#else | |
void preprocess_apply_agc( | |
SpeexPreprocessState * restrict st, | |
int N | |
) | |
{ | |
register spx_word16_t max_sample=0; | |
register spx_word16_t * restrict frame = st->frame; | |
register int i; | |
register int N2 = N << 1; | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for (i=0;i<N2;i++) | |
{ register spx_word16_t framei = VABS(frame[i]); | |
max_sample = VMUX( framei > max_sample, framei, max_sample); | |
} | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
if ( max_sample > 28000.f ) | |
{ | |
float damp = 28000.f/max_sample; | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i< N2 ; i++ ) | |
{ frame[i] *= damp; | |
} | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} | |
} | |
#endif | |
void preprocess_update( | |
SpeexPreprocessState * restrict st, | |
spx_int16_t * restrict x, | |
int N | |
) | |
{ | |
register spx_word16_t * restrict frame = st->frame; | |
register spx_word16_t * restrict window = st->window; | |
register spx_word16_t * restrict outbuf = st->outbuf; | |
register int framesize = st->frame_size; | |
register int N2 = N << 1; | |
register int N3 = N2 - framesize; | |
register int N4 = (framesize) - N3; | |
register int i; | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<N2 ; i++) | |
{ register spx_word16_t fi = frame[i]; | |
register spx_word16_t wi = window[i]; | |
frame[i] = MULT16_16_Q15(fi, wi); | |
} | |
for (i=0;i<N3;i++) | |
{ x[i] = outbuf[i] + frame[i]; | |
} | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
for ( i=0;i<N4;i++) | |
{ x[N3+i] = frame[N3+i]; | |
} | |
memcpy(outbuf, frame+framesize, (N3) * sizeof(spx_word16_t)); | |
} | |
#define OVERRIDE_SPEEX_PREPROCESS_RUN | |
int speex_preprocess_run(SpeexPreprocessState * restrict st, spx_int16_t * restrict x) | |
{ | |
register int i, N, M, NM; | |
register spx_word32_t * restrict ps=st->ps; | |
register spx_word32_t Zframe; | |
register spx_word16_t Pframe; | |
st->nb_adapt++; | |
st->min_count++; | |
N = st->ps_size; | |
M = st->nbands; | |
NM = N + M; | |
preprocess_residue_echo(st, N, NM); | |
preprocess_analysis(st, x); | |
update_noise_prob(st); | |
preprocess_update_noise(st, ps, N); | |
if ( st->nb_adapt == 1 ) | |
{ memcpy(st->old_ps, ps, (NM) * sizeof(spx_word32_t)); | |
} | |
preprocess_compute_SNR(st, ps, NM); | |
Zframe = preprocess_smooth_SNR(st, N, NM); | |
{ | |
register spx_word16_t effective_echo_suppress; | |
Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,M))); | |
effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), | |
MULT16_16(Pframe, st->echo_suppress_active)),15)); | |
compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M); | |
} | |
preprocess_compute_emgain(st, ps, Pframe, NM); | |
preprocess_compute_linear_gain(st, ps, N); | |
if (!st->denoise_enabled) | |
{ | |
register spx_word16_t * restrict gain2 = st->gain2; | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unroll=4 | |
#pragma TCS_unrollexact=1 | |
#endif | |
for ( i=0 ; i<NM ; i++ ) | |
{ gain2[i] = Q15_ONE; | |
} | |
#if (TM_UNROLL && TM_UNROLL_SPEEXPREPROCESSRUN) | |
#pragma TCS_unrollexact=0 | |
#pragma TCS_unroll=0 | |
#endif | |
} | |
preprocess_apply_gain(st, N); | |
#ifndef FIXED_POINT | |
if (st->agc_enabled) | |
{ speex_compute_agc(st, Pframe, st->ft); | |
} | |
#endif | |
spx_ifft(st->fft_lookup, st->ft, st->frame); | |
#ifdef FIXED_POINT | |
preprocess_scale(st, N); | |
#endif | |
#ifndef FIXED_POINT | |
if ( st->agc_enabled ) | |
{ preprocess_apply_agc(st, N); | |
} | |
#endif | |
preprocess_update(st, x, N); | |
if ( st->vad_enabled ) | |
{ | |
if (Pframe > st->speech_prob_start || (st->was_speech && Pframe > st->speech_prob_continue)) | |
{ st->was_speech=1; | |
return 1; | |
} else | |
{ st->was_speech=0; | |
return 0; | |
} | |
} else | |
{ return 1; | |
} | |
} |