Commit 39ded680 authored by Kenan Gillet's avatar Kenan Gillet Committed by Vitor Sessak

More OKed parts of the QCELP decoder

patch by Kenan Gillet, kenan.gillet gmail com

Originally committed as revision 15822 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent eb63b051
......@@ -460,6 +460,15 @@ static const int8_t qcelp_rate_half_codebook[128] = {
};
#define QCELP_RATE_HALF_CODEBOOK_RATIO 0.5
/**
* sqrt(1.887) is the maximum of the pseudorandom
* white sequence used to generate the scaled codebook
* vector for framerate 1/4.
*
* TIA/EIA/IS-733 2.4.8.1.2
*/
#define QCELP_SQRT1887 1.373681186
/**
* table for impulse response of BPF used to filter
* the white excitation for framerate 1/4 synthesis
......
......@@ -51,6 +51,144 @@ static void weighted_vector_sumf(float *out,
+ weight_coeff_b * in_b[i];
}
/**
* 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.
*
......@@ -131,9 +269,9 @@ void interpolate_lpc(QCELPContext *q,
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) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment