From 0f1479d2efb5c2cb87718c77028315774fd3cea3 Mon Sep 17 00:00:00 2001 From: drowe67 Date: Mon, 27 Aug 2012 08:20:47 +0000 Subject: [PATCH] first pass at LPC post filter, sig improvement to hts1a/hts2a, morig, mmt1 git-svn-id: https://svn.code.sf.net/p/freetel/code@642 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/src/c2sim.c | 12 ++-- codec2-dev/src/codec2.c | 6 +- codec2-dev/src/interp.c | 2 +- codec2-dev/src/quantise.c | 126 ++++++++++++++++++++++++++++++++++++-- codec2-dev/src/quantise.h | 2 +- 5 files changed, 132 insertions(+), 16 deletions(-) diff --git a/codec2-dev/src/c2sim.c b/codec2-dev/src/c2sim.c index eb08cb9a..6b326483 100644 --- a/codec2-dev/src/c2sim.c +++ b/codec2-dev/src/c2sim.c @@ -99,6 +99,7 @@ int main(int argc, char *argv[]) float bg_est; int hand_voicing = 0, phaseexp = 0, ampexp = 0, hi = 0, simlpcpf = 0; + int lpcpf; FILE *fvoicing = 0; MODEL prev_model, interp_model; @@ -145,6 +146,7 @@ int main(int argc, char *argv[]) { "dt", no_argument, &dt, 1 }, { "hi", no_argument, &hi, 1 }, { "simlpcpf", no_argument, &simlpcpf, 1 }, + { "lpcpf", no_argument, &lpcpf, 1 }, { "dump_pitch_e", required_argument, &dump_pitch_e, 1 }, { "sq_pitch_e", no_argument, &scalar_quant_Wo_e, 1 }, { "vq_pitch_e", no_argument, &vector_quant_Wo_e, 1 }, @@ -412,10 +414,6 @@ int main(int argc, char *argv[]) autocorrelate(Wn,Rk,M,order); levinson_durbin(Rk,ak,order); - #ifdef DUMP - dump_ak(ak, LPC_ORD); - #endif - /* determine voicing */ snr = est_voicing_mbe(&model, Sw, W, Sw_, Ew, prev_uq_Wo); @@ -612,7 +610,11 @@ int main(int argc, char *argv[]) } - aks_to_M2(fft_fwd_cfg, ak, order, &model, e, &snr, 1, simlpcpf); + #ifdef DUMP + dump_ak(ak, LPC_ORD); + #endif + + aks_to_M2(fft_fwd_cfg, ak, order, &model, e, &snr, 1, simlpcpf, lpcpf); /* note SNR on interpolated frames can't be measured properly by comparing Am as L has changed. We can dump interp lsps diff --git a/codec2-dev/src/codec2.c b/codec2-dev/src/codec2.c index 4e41e1a0..d521aa1a 100644 --- a/codec2-dev/src/codec2.c +++ b/codec2-dev/src/codec2.c @@ -356,7 +356,7 @@ void codec2_decode_2400(struct CODEC2 *c2, short speech[], const unsigned char * interpolate_lsp_ver2(&lsps[0][0], c2->prev_lsps_dec, &lsps[1][0], 0.5); for(i=0; i<2; i++) { lsp_to_lpc(&lsps[i][0], &ak[i][0], LPC_ORD); - aks_to_M2(c2->fft_fwd_cfg, &ak[i][0], LPC_ORD, &model[i], e[i], &snr, 1, 0); + aks_to_M2(c2->fft_fwd_cfg, &ak[i][0], LPC_ORD, &model[i], e[i], &snr, 1, 0, 1); apply_lpc_correction(&model[i]); } @@ -528,7 +528,7 @@ void codec2_decode_1400(struct CODEC2 *c2, short speech[], const unsigned char * } for(i=0; i<4; i++) { lsp_to_lpc(&lsps[i][0], &ak[i][0], LPC_ORD); - aks_to_M2(c2->fft_fwd_cfg, &ak[i][0], LPC_ORD, &model[i], e[i], &snr, 1, 0); + aks_to_M2(c2->fft_fwd_cfg, &ak[i][0], LPC_ORD, &model[i], e[i], &snr, 1, 0, 1); apply_lpc_correction(&model[i]); } @@ -705,7 +705,7 @@ void codec2_decode_1200(struct CODEC2 *c2, short speech[], const unsigned char * } for(i=0; i<4; i++) { lsp_to_lpc(&lsps[i][0], &ak[i][0], LPC_ORD); - aks_to_M2(c2->fft_fwd_cfg, &ak[i][0], LPC_ORD, &model[i], e[i], &snr, 1, 0); + aks_to_M2(c2->fft_fwd_cfg, &ak[i][0], LPC_ORD, &model[i], e[i], &snr, 1, 0, 1); apply_lpc_correction(&model[i]); } diff --git a/codec2-dev/src/interp.c b/codec2-dev/src/interp.c index bd7389fe..ebb579ab 100644 --- a/codec2-dev/src/interp.c +++ b/codec2-dev/src/interp.c @@ -201,7 +201,7 @@ void interpolate_lsp( /* convert back to amplitudes */ lsp_to_lpc(lsps_interp, ak_interp, LPC_ORD); - aks_to_M2(fft_fwd_cfg, ak_interp, LPC_ORD, interp, e, &snr, 0, 0); + aks_to_M2(fft_fwd_cfg, ak_interp, LPC_ORD, interp, e, &snr, 0, 0, 1); //printf(" interp: ak[1]: %f A[1] %f\n", ak_interp[1], interp->A[1]); } diff --git a/codec2-dev/src/quantise.c b/codec2-dev/src/quantise.c index e07b2d7e..91bc3027 100644 --- a/codec2-dev/src/quantise.c +++ b/codec2-dev/src/quantise.c @@ -645,12 +645,121 @@ float lpc_model_amplitudes( } #endif - aks_to_M2(ak,order,model,E,&snr, 1, 0); /* {ak} -> {Am} LPC decode */ + aks_to_M2(ak,order,model,E,&snr, 1, 0, 1); /* {ak} -> {Am} LPC decode */ return snr; } #endif +/*---------------------------------------------------------------------------*\ + + lpc_post_filter() + + Applies a post filter to the LPC synthesis filter power spectrum + Pw, which supresses the inter-formant energy. + + The algorithm is from p267 (Section 8.6) of "Digital Speech", + edited by A.M. Kondoz, 1994 published by Wiley and Sons. Chapter 8 + of this text is on the MBE vocoder, and this is a freq domain + adaptation of post filtering commonly used in CELP. + + I used the Octave simulation lpcpf.m to get an understaing of the + algorithm. + + Requires two more FFTs which is significantly more MIPs. However + it should be possible to implement this more efficiently in the + time domain. Just not sure how to handle relative time delays + between the synthesis stage and updating these coeffs. A smaller + FFT size might also be accetable to save CPU. + + TODO: + [ ] sync var names between Octave and C version + [ ] doc gain normalisation + [ ] I think the first FFT is not rqd as we do the same + thing in aks_to_M2(). + +\*---------------------------------------------------------------------------*/ + +#define LPCPF_GAMMA 0.5 +#define LPCPF_BETA 0.2 + +void lpc_post_filter(kiss_fft_cfg fft_fwd_cfg, COMP Pw[], float ak[], int order) +{ + int i; + COMP x[FFT_ENC]; /* input to FFTs */ + COMP Aw[FFT_ENC]; /* LPC analysis filter spectrum */ + COMP Ww[FFT_ENC]; /* weighting spectrum */ + float Rw[FFT_ENC]; /* R = WA */ + float e_before, e_after, gain; + float Pfw[FFT_ENC]; /* Post filter mag spectrum */ + + /* Determine LPC inverse filter spectrum 1/A(exp(jw)) -----------*/ + + /* we actually want the synthesis filter A(exp(jw) but the inverse + (analysis) filter is easier to find as it's FIR, we just use + the inverse of 1/A to get the synthesis filter A(exp(jw)) */ + + for(i=0; i