Mercurial > libavcodec.hg
diff qcelpdec.c @ 8145:f27d01aff4af libavcodec
More OKed parts of the QCELP decoder
patch by Kenan Gillet, kenan.gillet gmail com
author | vitor |
---|---|
date | Fri, 14 Nov 2008 17:36:47 +0000 |
parents | 3b5256153553 |
children | 4da8fc62ae00 |
line wrap: on
line diff
--- a/qcelpdec.c Fri Nov 14 02:49:23 2008 +0000 +++ b/qcelpdec.c Fri Nov 14 17:36:47 2008 +0000 @@ -52,6 +52,144 @@ } /** + * Initialize the speech codec according to the specification. + * + * TIA/EIA/IS-733 2.4.9 + */ +static av_cold int qcelp_decode_init(AVCodecContext *avctx) { + QCELPContext *q = avctx->priv_data; + int i; + + avctx->sample_fmt = SAMPLE_FMT_FLT; + + for (i = 0; i < 10; i++) + q->prev_lspf[i] = (i + 1) / 11.; + + return 0; +} + +/** + * Computes the scaled codebook vector Cdn From INDEX and GAIN + * for all rates. + * + * The specification lacks some information here. + * + * TIA/EIA/IS-733 has an omission on the codebook index determination + * formula for RATE_FULL and RATE_HALF frames at section 2.4.8.1.1. It says + * you have to subtract the decoded index parameter from the given scaled + * codebook vector index 'n' to get the desired circular codebook index, but + * it does not mention that you have to clamp 'n' to [0-9] in order to get + * RI-compliant results. + * + * The reason for this mistake seems to be the fact they forgot to mention you + * have to do these calculations per codebook subframe and adjust given + * equation values accordingly. + * + * @param q the context + * @param gain array holding the 4 pitch subframe gain values + * @param cdn_vector array for the generated scaled codebook vector + */ +static void compute_svector(const QCELPContext *q, + const float *gain, + float *cdn_vector) { + int i, j, k; + uint16_t cbseed, cindex; + float *rnd, tmp_gain, fir_filter_value; + + switch (q->framerate) { + case RATE_FULL: + for (i = 0; i < 16; i++) { + tmp_gain = gain[i] * QCELP_RATE_FULL_CODEBOOK_RATIO; + cindex = -q->cindex[i]; + for (j = 0; j < 10; j++) + *cdn_vector++ = tmp_gain * qcelp_rate_full_codebook[cindex++ & 127]; + } + break; + case RATE_HALF: + for (i = 0; i < 4; i++) { + tmp_gain = gain[i] * QCELP_RATE_HALF_CODEBOOK_RATIO; + cindex = -q->cindex[i]; + for (j = 0; j < 40; j++) + *cdn_vector++ = tmp_gain * qcelp_rate_half_codebook[cindex++ & 127]; + } + break; + case RATE_QUARTER: + cbseed = (0x0003 & q->lspv[4])<<14 | + (0x003F & q->lspv[3])<< 8 | + (0x0060 & q->lspv[2])<< 1 | + (0x0007 & q->lspv[1])<< 3 | + (0x0038 & q->lspv[0])>> 3 ; + rnd = q->rnd_fir_filter_mem + 20; + for (i = 0; i < 8; i++) { + tmp_gain = gain[i] * (QCELP_SQRT1887 / 32768.0); + for (k = 0; k < 20; k++) { + cbseed = 521 * cbseed + 259; + *rnd = (int16_t)cbseed; + + // FIR filter + fir_filter_value = 0.0; + for (j = 0; j < 10; j++) + fir_filter_value += qcelp_rnd_fir_coefs[j ] * (rnd[-j ] + rnd[-20+j]); + fir_filter_value += qcelp_rnd_fir_coefs[10] * rnd[-10]; + + *cdn_vector++ = tmp_gain * fir_filter_value; + rnd++; + } + } + memcpy(q->rnd_fir_filter_mem, q->rnd_fir_filter_mem + 160, 20 * sizeof(float)); + break; + case RATE_OCTAVE: + cbseed = q->first16bits; + for (i = 0; i < 8; i++) { + tmp_gain = gain[i] * (QCELP_SQRT1887 / 32768.0); + for (j = 0; j < 20; j++) { + cbseed = 521 * cbseed + 259; + *cdn_vector++ = tmp_gain * (int16_t)cbseed; + } + } + break; + case I_F_Q: + cbseed = -44; // random codebook index + for (i = 0; i < 4; i++) { + tmp_gain = gain[i] * QCELP_RATE_FULL_CODEBOOK_RATIO; + for (j = 0; j < 40; j++) + *cdn_vector++ = tmp_gain * qcelp_rate_full_codebook[cbseed++ & 127]; + } + break; + } +} + +/** + * Apply generic gain control. + * + * @param v_out output vector + * @param v_in gain-controlled vector + * @param v_ref vector to control gain of + * + * FIXME: If v_ref is a zero vector, it energy is zero + * and the behavior of the gain control is + * undefined in the specs. + * + * TIA/EIA/IS-733 2.4.8.3-2/3/4/5, 2.4.8.6 + */ +static void apply_gain_ctrl(float *v_out, + const float *v_ref, + const float *v_in) { + int i, j, len; + float scalefactor; + + for (i = 0, j = 0; i < 4; i++) { + scalefactor = ff_dot_productf(v_in + j, v_in + j, 40); + if (scalefactor) + scalefactor = sqrt(ff_dot_productf(v_ref + j, v_ref + j, 40) / scalefactor); + else + av_log_missing_feature(NULL, "Zero energy for gain control", 1); + for (len = j + 40; j < len; j++) + v_out[j] = scalefactor * v_in[j]; + } +} + +/** * Apply filter in pitch-subframe steps. * * @param memory buffer for the previous state of the filter @@ -131,9 +269,9 @@ if (weight != 1.0) { weighted_vector_sumf(interpolated_lspf, curr_lspf, q->prev_lspf, weight, 1.0 - weight, 10); - lspf2lpc(q, interpolated_lspf, lpc); + qcelp_lspf2lpc(interpolated_lspf, lpc); } else if (q->framerate >= RATE_QUARTER || (q->framerate == I_F_Q && !subframe_num)) - lspf2lpc(q, curr_lspf, lpc); + qcelp_lspf2lpc(curr_lspf, lpc); } static int buf_size2framerate(const int buf_size) {