diff options
author | Jean-Marc Valin <jean-marc.valin@usherbrooke.ca> | 2009-12-15 05:19:37 +0300 |
---|---|---|
committer | Jean-Marc Valin <jean-marc.valin@usherbrooke.ca> | 2009-12-15 05:19:37 +0300 |
commit | 5a0fae53c7cb604c11014d1de73bbad293083e28 (patch) | |
tree | 20034f18aea778cb45a71b2934c3c4135c5cba47 | |
parent | b8002a0ef30d10be1f8e851e72115b376744a3f5 (diff) |
PLC: Added lag windowing and constraint to synthesis energy
-rw-r--r-- | libcelt/celt.c | 70 | ||||
-rw-r--r-- | libcelt/plc.c | 6 |
2 files changed, 54 insertions, 22 deletions
diff --git a/libcelt/celt.c b/libcelt/celt.c index 999b356..a2547a7 100644 --- a/libcelt/celt.c +++ b/libcelt/celt.c @@ -54,6 +54,8 @@ #include "float_cast.h" #include <stdarg.h> +#define LPC_ORDER 24 + static const celt_word16 preemph = QCONST16(0.8f,15); #ifdef FIXED_POINT @@ -1089,6 +1091,10 @@ struct CELTDecoder { celt_word16 *oldBandE; +#ifndef FIXED_POINT + celt_word16 *lpc; +#endif + int last_pitch_index; int loss_count; }; @@ -1163,9 +1169,16 @@ CELTDecoder *celt_decoder_create(const CELTMode *mode, int channels, int *error) st->preemph_memD = (celt_sig*)celt_alloc(C*sizeof(celt_sig)); +#ifndef FIXED_POINT + st->lpc = (celt_word16*)celt_alloc(C*LPC_ORDER*sizeof(celt_word16)); +#endif + st->loss_count = 0; if ((st->decode_mem!=NULL) && (st->out_mem!=NULL) && (st->oldBandE!=NULL) && +#ifndef FIXED_POINT + (st->lpc!=NULL) && +#endif (st->preemph_memD!=NULL)) { if (error) @@ -1208,6 +1221,10 @@ void celt_decoder_destroy(CELTDecoder *st) celt_free(st->decode_mem); celt_free(st->oldBandE); celt_free(st->preemph_memD); + +#ifndef FIXED_POINT + celt_free(st->lpc); +#endif st->marker = DECODERFREED; @@ -1217,7 +1234,6 @@ void celt_decoder_destroy(CELTDecoder *st) #ifndef FIXED_POINT #include "plc.c" #endif -#define LPC_ORDER 24 static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict pcm) { int c, N; @@ -1271,17 +1287,29 @@ static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict p float e[MAX_PERIOD]; float exc[MAX_PERIOD]; float ac[LPC_ORDER+1]; - float lpc[LPC_ORDER]; float decay = 1; celt_word32 mem[LPC_ORDER]={0}; for (i=0;i<MAX_PERIOD;i++) exc[i] = st->out_mem[i*C+c]; - _celt_autocorr(exc, ac, st->mode->window, st->mode->overlap, - LPC_ORDER, MAX_PERIOD); - ac[0] *= 1.0001; - _celt_lpc(lpc, ac, LPC_ORDER); - fir(exc, lpc, exc, MAX_PERIOD, LPC_ORDER, mem); + + if (st->loss_count == 0) + { + _celt_autocorr(exc, ac, st->mode->window, st->mode->overlap, + LPC_ORDER, MAX_PERIOD); + + /* Noise floor -50 dB */ + ac[0] *= 1.00001; + /* Lag windowing */ + for (i=1;i<=LPC_ORDER;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ + ac[i] -= ac[i]*(.008*i)*(.008*i); + } + + _celt_lpc(st->lpc, ac, LPC_ORDER); + } + fir(exc, st->lpc, exc, MAX_PERIOD, LPC_ORDER, mem); /* Check if the waveform is decaying (and if so how fast) */ { @@ -1301,6 +1329,7 @@ static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict p decay = 1; } + float S1=0; /* Copy excitation, taking decay into account */ for (i=0;i<len+st->mode->overlap;i++) { @@ -1310,13 +1339,24 @@ static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict p decay *= decay; } e[i] = decay*exc[offset+i]; + S1 += st->out_mem[offset+i]*st->out_mem[offset+i]; + } + + iir(e, st->lpc, e, len+st->mode->overlap, LPC_ORDER, mem); + + { + float ratio, S2=0; + for (i=0;i<len+overlap;i++) + S2 += e[i]*e[i]; + ratio = sqrt((S1+1)/(S2+1)); + if (ratio < 1) + for (i=0;i<len+overlap;i++) + e[i] *= ratio; } for (i=0;i<MAX_PERIOD+st->mode->overlap-N;i++) st->out_mem[C*i+c] = st->out_mem[C*(N+i)+c]; - iir(e, lpc, e, len+st->mode->overlap, LPC_ORDER, mem); - /* Apply TDAC to the concealed audio so that it blends with the previous and next frames */ for (i=0;i<overlap/2;i++) @@ -1338,17 +1378,7 @@ static void celt_decode_lost(CELTDecoder * restrict st, celt_word16 * restrict p } #endif - for (c=0;c<C;c++) - { - int j; - for (j=0;j<N;j++) - { - celt_sig tmp = MAC16_32_Q15(st->out_mem[C*(MAX_PERIOD-N)+C*j+c], - preemph,st->preemph_memD[c]); - st->preemph_memD[c] = tmp; - pcm[C*j+c] = SCALEOUT(SIG2WORD16(tmp)); - } - } + deemphasis(st->out_mem, pcm, N, C, preemph, st->preemph_memD); st->loss_count++; diff --git a/libcelt/plc.c b/libcelt/plc.c index 5689652..8f5100c 100644 --- a/libcelt/plc.c +++ b/libcelt/plc.c @@ -26,9 +26,9 @@ int p for (j = 0; j < i; j++) rr = SUB32(rr,MULT16_16(lpc[j],ac[i - j])); #ifdef FIXED_POINT - r = DIV32_16(rr+PSHR32(error,1),ADD16(error,8)); + r = DIV32_16(rr+PSHR32(error,1),ADD16(error,1)); #else - r = rr/(error+.003*ac[0]); + r = rr/(error+1e-15); #endif /* Update LPC coefficients and total error */ lpc[i] = r; @@ -42,6 +42,8 @@ int p lpc[j] = MAC16_16_P13(lpc[j],lpc[j],r); error = SUB16(error,MULT16_16_Q13(r,MULT16_16_Q13(error,r))); + if (error<.00001*ac[0]) + break; } return error; } |