/************************************************************************ * * FILENAME : sub_dsp.c * * DESCRIPTION : General Purpose Signal Processing Library * ************************************************************************ * * SUB-ROUTINES : - Autocorr() * - Az_Lsp() * - Back_Fil() * - Chebps() * - Convolve() * - Fac_Pond() * - Get_Lsp_Pol() * - Int_Lpc4() * - Lag_Window() * - Levin_32() * - LPC_Gain() * - Lsp_Az() * - Pond_Ai() * - Residu() * - Syn_Filt() * ************************************************************************ * * INCLUDED FILES : source.h * stdio.h * stdlib.h * * grid .tab * lag_wind.tab * window.tab * ************************************************************************/ #include #include #include "source.h" #include "grid.tab" #include "lag_wind.tab" #include "window.tab" /* pp = local LPC order, nc =pp/2 */ #define pp (Word16)10 #define nc (Word16)5 /* Length for local impulse response */ #define llg (Word16)60 /************************************************************************** * * ROUTINE : Autocorr * * DESCRIPTION : Compute autocorrelations * ************************************************************************** * * USAGE : Autocorr(buffer_in,p,buffer_out1,buffer_out2) * (Routine_Name(input1,input2,output1,output2)) * * INPUT ARGUMENT(S) : * * INPUT1 : - Description : Input signal buffer * - Format : Word16 * * INPUT2 : - Description : LPC order * - Format : Word16 * * OUTPUT ARGUMENT(S) : * * OUTPUT1 : - Description : Autocorrelations buffer (msb) * - Format : Word16 * * OUTPUT2 : - Description : Autocorrelations buffer (lsb) * - Format : Word16 * * RETURNED VALUE : None * **************************************************************************/ void Autocorr(Word16 x[], Word16 p, Word16 r_h[], Word16 r_l[]) { Word16 i, j, norm; Word16 y[L_window]; Word32 sum; extern Flag Overflow; /* Windowing of signal */ for(i=0; i 0) max = s; } /* Find the number of right shifts to do on y32[] */ /* so that maximum is on 13 bits */ j = norm_l(max); if( sub(j,(Word16)16) > 0) j = 16; j = sub((Word16)18, j); for(i=0; i mantissa in Q30 plus exponant * A[i] Q26 +- 15.999.. * * The additions are performed in 32 bit. For the summation used to compute the K[i], * numbers in Q30 are multiplied by numbers in Q26, with the results of the multiplications in * Q26, resulting in a dynamic of +/- 32. This is sufficient to avoid overflow, since the final * result of the summation is necessarily < 1.0 as both the K[i] and Alpha are * theoretically < 1.0. * **************************************************************************/ /* Last A(z) for case of unstable filter */ static Word16 old_A[pp+1]={4096,0,0,0,0,0,0,0,0,0,0}; void Levin_32(Word16 Rh[], Word16 Rl[], Word16 A[]) { Word16 i, j; Word16 hi, lo; Word16 Kh, Kl; /* reflexion coefficient; hi and lo */ Word16 alp_h, alp_l, alp_e; /* Prediction gain; hi lo and exponant */ Word16 Ah[pp+1], Al[pp+1]; /* LPC coef. in double prec. */ Word16 Anh[pp+1], Anl[pp+1]; /* LPC coef.for next iterat. in double prec. */ Word32 t0, t1, t2; /* temporary variable */ /* K = A[1] = -R[1] / R[0] */ t1 = L_comp(Rh[1], Rl[1]); /* R[1] in Q30 */ t2 = L_abs(t1); /* abs R[1] */ t0 = div_32(t2, Rh[0], Rl[0]); /* R[1]/R[0] in Q30 */ if(t1 > 0) t0= L_negate(t0); /* -R[1]/R[0] */ L_extract(t0, &Kh, &Kl); /* K in DPF */ t0 = L_shr(t0,(Word16)4); /* A[1] in Q26 */ L_extract(t0, &Ah[1], &Al[1]); /* A[1] in DPF */ /* Alpha = R[0] * (1-K**2) */ t0 = mpy_32(Kh ,Kl, Kh, Kl); /* K*K in Q30 */ t0 = L_abs(t0); /* Some case <0 !! */ t0 = L_sub( (Word32)0x3fffffff, t0 ); /* 1 - K*K in Q30 */ L_extract(t0, &hi, &lo); /* DPF format */ t0 = mpy_32(Rh[0] ,Rl[0], hi, lo); /* Alpha in Q30 */ /* Normalize Alpha */ t0 = norm_v(t0, (Word16)12, &i); t0 = L_shr(t0, (Word16)1); L_extract(t0, &alp_h, &alp_l); /* DPF format */ alp_e = i-1; /* t0 was in Q30 */ /*--------------------------------------* * ITERATIONS I=2 to pp * *--------------------------------------*/ for(i= 2; i<=pp; i++) { /* t0 = SUM ( R[j]*A[i-j] ,j=1,i-1 ) + R[i] */ t0 = 0; for(j=1; jconvert to Q30 */ /* No overflow possible */ t1 = L_comp(Rh[i],Rl[i]); t0 = L_add(t0, t1); /* add R[i] in Q30 */ /* K = -t0 / Alpha */ t1 = L_abs(t0); t2 = div_32(t1, alp_h, alp_l); /* abs(t0)/Alpha */ if(t0 > 0) t2= L_negate(t2); /* K =-t0/Alpha */ t2 = L_shl(t2, alp_e); /* denormalize; compare to Alpha */ L_extract(t2, &Kh, &Kl); /* K in DPF */ /* Test for unstable filter, if unstable keep old A(z) */ if ( abs_s(Kh) > 32750) { for(j=0; j<=pp; j++) A[j] = old_A[j]; return; } /*------------------------------------------* * Compute new LPC coeff. -> An[i] * * An[j]= A[j] + K*A[i-j] , j=1 to i-1 * * An[i]= K * *------------------------------------------*/ for(j=1; jconvert to Q26 */ L_extract(t2, &Anh[i], &Anl[i]); /* An[i] in Q26 */ /* Alpha = Alpha * (1-K**2) */ t0 = mpy_32(Kh ,Kl, Kh, Kl); /* K*K in Q30 */ t0 = L_abs(t0); /* Some case <0 !! */ t0 = L_sub( (Word32)0x3fffffff, t0 ); /* 1 - K*K in Q30 */ L_extract(t0, &hi, &lo); /* DPF format */ t0 = mpy_32(alp_h , alp_l, hi, lo); /* Alpha in Q30 */ /* Normalize Alpha */ t0 = norm_v(t0, (Word16)12, &j); t0 = L_shr(t0, (Word16)1); L_extract(t0, &alp_h, &alp_l); /* DPF format */ alp_e += j-1; /* t0 was in Q30 */ /* A[j] = An[j] Note: can be done with pointers */ for(j=1; j<=i; j++) { Ah[j] =Anh[j]; Al[j] =Anl[j]; } } /* Troncate A[i] in Q26 to Q12 with rounding */ A[0] = 4096; for(i=1; i<=pp; i++) { t0 = L_comp(Ah[i], Al[i]); t0 = add_sh(t0, (Word16)1, (Word16)13); /* rounding */ old_A[i] = A[i] = store_hi(t0,(Word16)2); } return; } /************************************************************************** * * ROUTINE : Lpc_Gain * * DESCRIPTION : Compute energy of impulse response of 1/A(z) * on 60 points * ************************************************************************** * * USAGE : Lpc_Gain(buffer_in) * (Routine_Name(input1)) * * INPUT ARGUMENT(S) : * * INPUT1 : - Description : LPC coefficients * - Format : Word16 * * OUTPUT ARGUMENT(S) : None * * RETURNED VALUE : - Description : Energy of impulse response of 1/A(z) * - Format : Word32 - Q20 * **************************************************************************/ Word32 Lpc_Gain(Word16 a[]) { Word16 i; Word32 ener; Word16 h[llg]; /* Compute the impulse response of A(z) */ h[0] = 1024; /* 1.0 in Q10 */ for(i=1; i 0; i--) { f1[i] = L_add(f1[i], f1[i-1]); /* f1[i] += f1[i-1]; */ f2[i] = L_sub(f2[i], f2[i-1]); /* f2[i] -= f2[i-1]; */ } a[0] = 4096; for (i = 1, j = 10; i <= 5; i++, j--) { t0 = L_add(f1[i], f2[i]); /* f1[i] + f2[i] */ a[i] = extract_l( L_shr_r(t0,(Word16)13) ); /*from Q24 to Q12 and * 0.5*/ t0 = L_sub(f1[i], f2[i]); /* f1[i] - f2[i] */ a[j] = extract_l( L_shr_r(t0,(Word16)13) ); /*from Q24 to Q12 and * 0.5*/ } return; } /************************************************************************** * * ROUTINE : Pond_Ai * * DESCRIPTION : Compute spectral expansion (a_exp[]) of LPC * coefficients (a[]) using spectral expansion * factors (fac[]) with the LPC order fixed to 10 * ************************************************************************** * * USAGE : Pond_Ai(buffer_in1,buffer_in2,buffer_out) * (Routine_Name(input1,input2,output1)) * * INPUT ARGUMENT(S) : * * INPUT1 : - Description : LPC coefficients * - Format : Word16 * * INPUT2 : - Description : Spectral expansion factors * - Format : Word16 - Q15 * * OUTPUT ARGUMENT(S) : * * OUTPUT1 : - Description : Spectral expanded LPC coefficients * - Format : Word16 * * RETURNED VALUE : None * * COMMENTS : - a_exp[i] = a[i] * fac[i-1] i=1,10 * **************************************************************************/ void Pond_Ai(Word16 a[], Word16 fac[], Word16 a_exp[]) { Word16 i; a_exp[0] = a[0]; for(i=1; i<=pp; i++) a_exp[i] = etsi_round( L_mult(a[i], fac[i-1]) ); return; } /************************************************************************** * * ROUTINE : Residu * * DESCRIPTION : Compute the LPC residual by filtering the input * speech through A(z) * ************************************************************************** * * USAGE : Residu(buffer_in1,buffer_in2,buffer_out,lg) * (Routine_Name(input1,input2,output1,input3)) * * INPUT ARGUMENT(S) : * * INPUT1 : - Description : Prediction coefficients * - Format : Word16 - Q12 * * INPUT2 : - Description : Input speech - values of buffer_in2[] * from -p to -1 are needed * - Format : Word16 * * INPUT3 : - Description : Size of filtering * - Format : Word16 * * OUTPUT ARGUMENT(S) : * * OUTPUT1 : - Description : Residual signal * - Format : Word16 * * RETURNED VALUE : None * **************************************************************************/ void Residu(Word16 a[], Word16 x[], Word16 y[], Word16 lg) { Word16 i, j; Word32 s; for (i = 0; i < lg; i++) { s = Load_sh(x[i], (Word16)12); for (j = 1; j <= pp; j++) s = L_mac0(s, a[j], x[i-j]); s = add_sh(s, (Word16)1, (Word16)11); /* Rounding */ s = L_shl(s, (Word16)4); /* Saturation */ y[i] = extract_h(s); } return; } /************************************************************************** * * ROUTINE : Syn_Filt * * DESCRIPTION : Perform the synthesis filtering 1/A(z) * ************************************************************************** * * USAGE : Syn_Filt(buffer_in1,buffer_in2,buffer_out, * lg,buffer,flag) * (Routine_Name(input1,input2,output1, * input3,arg4,input5)) * * INPUT ARGUMENT(S) : * * INPUT1 : - Description : Prediction coefficients * - Format : Word16 - Q12 * * INPUT2 : - Description : Input signal * - Format : Word16 * * INPUT3 : - Description : Size of filtering * - Format : Word16 * * ARG4 : - Description : Memory associated with this filtering * - Format : Word16 * * INPUT5 : - Description : - flag = 0 -> no update of memory * - flag = 1 -> update of memory * - Format : Word16 * * OUTPUT ARGUMENT(S) : * * OUTPUT1 : - Description : Output signal * - Format : Word16 * * RETURNED VALUE : None * **************************************************************************/ void Syn_Filt(Word16 a[], Word16 x[], Word16 y[], Word16 lg, Word16 mem[], Word16 update) { Word16 i, j; Word32 s; Word16 tmp[80]; /* This is usually done by memory allocation (lg+pp) */ Word16 *yy; /* Copy mem[] to yy[] */ yy = tmp; for(i=0; i