[FFmpeg-devel] [PATCH] QCELP decoder postfilter & final gain control
Kenan Gillet
kenan.gillet
Sat Apr 4 02:01:37 CEST 2009
Hi,
here is a series of patch implementing the postfiltering and final gain control
for the QCELP decoder which should make the decoder features complete.
- patches 1, 2 and 3 are splitting and cleanup the current code.
They give the same output on all my test samples
- patch 4 adds a LP zero filter
- patch 5 implements the postfiltering and final gain control.
thanks for the review
Kenan
-------------- next part --------------
Index: libavcodec/qcelpdec.c
===================================================================
--- libavcodec/qcelpdec.c (revision 18292)
+++ libavcodec/qcelpdec.c (working copy)
@@ -412,18 +417,39 @@
}
/**
- * Apply generic gain control.
+ * Compute the gain control
*
- * @param v_out output vector
* @param v_in gain-controlled vector
* @param v_ref vector to control gain of
*
+ * @return gain control
+ *
* 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 float compute_gain_ctrl(const float *v_ref, const float *v_in, const int len)
+{
+ float scalefactor = ff_dot_productf(v_in, v_in, len);
+
+ if(scalefactor)
+ scalefactor = sqrt(ff_dot_productf(v_ref, v_ref, len) / scalefactor);
+ else
+ ff_log_missing_feature(NULL, "Zero energy for gain control", 1);
+ return scalefactor;
+}
+
+/**
+ * Apply generic gain control.
+ *
+ * @param v_out output vector
+ * @param v_in gain-controlled vector
+ * @param v_ref vector to control gain of
+ *
+ * TIA/EIA/IS-733 2.4.8.3, 2.4.8.6
+ */
static void apply_gain_ctrl(float *v_out, const float *v_ref,
const float *v_in)
{
@@ -432,12 +458,7 @@
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
- ff_log_missing_feature(NULL, "Zero energy for gain control", 1);
+ scalefactor = compute_gain_ctrl(v_ref + j, v_in + j, 40);
for(len=j+40; j<len; j++)
v_out[j] = scalefactor * v_in[j];
}
-------------- next part --------------
Index: libavcodec/qcelpdec.c
===================================================================
--- libavcodec/qcelpdec.c (revision 18292)
+++ libavcodec/qcelpdec.c (working copy)
@@ -819,8 +819,8 @@
for(i=0; i<4; i++)
{
interpolate_lpc(q, quantized_lspf, lpc, i);
- ff_celp_lp_synthesis_filterf(formant_mem, lpc, outbuffer + i * 40, 40,
- 10);
+ ff_celp_lp_synthesis_filterf(formant_mem, lpc, outbuffer, 40, 10);
+ outbuffer += 40;
formant_mem += 40;
}
memcpy(q->formant_mem, q->formant_mem + 160, 10 * sizeof(float));
@@ -828,6 +828,7 @@
// FIXME: postfilter and final gain control should be here.
// TIA/EIA/IS-733 2.4.8.6
+ outbuffer -= 160;
formant_mem = q->formant_mem + 10;
for(i=0; i<160; i++)
*outbuffer++ = av_clipf(*formant_mem++, QCELP_CLIP_LOWER_BOUND,
-------------- next part --------------
--- libavcodec/qcelpdec.c 2009-04-01 22:05:11.000000000 -0700
+++ libavcodec/qcelpdec-w-postfilter.c 2009-04-01 22:16:37.000000000 -0700
@@ -733,7 +774,7 @@ static int qcelp_decode_frame(AVCodecCon
{
QCELPContext *q = avctx->priv_data;
float *outbuffer = data;
- int i;
+ int i, j;
float quantized_lspf[10], lpc[10];
float gain[16];
float *formant_mem;
@@ -804,6 +861,9 @@ erasure:
{
interpolate_lpc(q, quantized_lspf, lpc, i);
ff_celp_lp_synthesis_filterf(formant_mem, lpc, outbuffer, 40, 10);
+ for(j=0; j<40; j++)
+ outbuffer[j] = av_clipf(formant_mem[j], QCELP_CLIP_LOWER_BOUND,
+ QCELP_CLIP_UPPER_BOUND);
outbuffer += 40;
formant_mem += 40;
}
@@ -812,12 +872,6 @@ erasure:
// FIXME: postfilter and final gain control should be here.
// TIA/EIA/IS-733 2.4.8.6
- outbuffer -= 160;
- formant_mem = q->formant_mem + 10;
- for(i=0; i<160; i++)
- *outbuffer++ = av_clipf(*formant_mem++, QCELP_CLIP_LOWER_BOUND,
- QCELP_CLIP_UPPER_BOUND);
-
memcpy(q->prev_lspf, quantized_lspf, sizeof(q->prev_lspf));
q->prev_bitrate = q->bitrate;
-------------- next part --------------
Index: libavcodec/celp_filters.c
===================================================================
--- libavcodec/celp_filters.c (revision 18292)
+++ libavcodec/celp_filters.c (working copy)
@@ -105,3 +105,24 @@
out[n] -= filter_coeffs[i] * out[n-i];
}
}
+
+void ff_celp_lp_zero_synthesis_filterf(
+ float *out,
+ const float* filter_coeffs,
+ const float* in,
+ int buffer_length,
+ int filter_length)
+{
+ int i,n;
+
+ // These two lines are to avoid a -1 subtraction in the main loop
+ filter_length++;
+ filter_coeffs--;
+
+ for(n=0; n<buffer_length; n++)
+ {
+ out[n] = in[n];
+ for(i=1; i<filter_length; i++)
+ out[n] -= filter_coeffs[i] * in[n-i];
+ }
+}
Index: libavcodec/celp_filters.h
===================================================================
--- libavcodec/celp_filters.h (revision 18292)
+++ libavcodec/celp_filters.h (working copy)
@@ -91,4 +91,26 @@
int buffer_length,
int filter_length);
+/**
+ * LP zero synthesis filter.
+ * @param out [out] pointer to output buffer
+ * @param filter_coeffs filter coefficients.
+ * @param in input signal
+ * - the array in[-filter_length, -1] must
+ * contain the previous input of this filter
+ * @param buffer_length amount of data to process
+ * @param filter_length filter length (10 for 10th order LP filter)
+ *
+ * @note Output buffer must contain filter_length samples of past
+ * speech data before pointer.
+ *
+ * Routine applies A(z) filter to given speech data.
+ */
+void ff_celp_lp_zero_synthesis_filterf(
+ float *out,
+ const float* filter_coeffs,
+ const float* in,
+ int buffer_length,
+ int filter_length);
+
#endif /* AVCODEC_CELP_FILTERS_H */
-------------- next part --------------
--- libavcodec/qcelpdec.c 2009-04-01 23:26:19.000000000 -0700
+++ libavcodec/qcelpdec-w-postfilter.c 2009-04-01 23:28:23.000000000 -0700
@@ -66,6 +66,9 @@ typedef struct
float pitch_pre_filter_mem[303];
float rnd_fir_filter_mem[180];
float formant_mem[170];
+ float postfilter_pole_mem[170];
+ float prev_anti_tilt_filter_mem;
+ float final_gain;
float last_codebook_gain;
int prev_g1[2];
int prev_bitrate;
@@ -97,6 +100,8 @@ static av_cold int qcelp_decode_init(AVC
for(i=0; i<10; i++)
q->prev_lspf[i] = (i+1)/11.;
+ q->final_gain = 1.;
+
return 0;
}
@@ -656,6 +661,48 @@ void interpolate_lpc(QCELPContext *q, co
lspf2lpc(q->prev_lspf, lpc);
}
+/**
+ * Apply postfilter in subframe steps.
+ *
+ * @param q the context
+ * @param outbuffer the ouput buffer,
+ * it must be at least 40 float large
+ * @param lpc linear predictive coding coefficients
+ * @param formant_mem the formant filter memory,
+ * it must contain 40 samples and 10 previous samples
+ * @param pole_mem the postfilter pole filter memory,
+ * it must contain 40 samples and 10 previous samples
+ *
+ * TIA/EIA/IS-733 2.4.8.6
+ */
+static void do_postfilter(QCELPContext *q, float *outbuffer, const float *lpc,
+ const float *formant_mem, float *pole_mem)
+{
+ float weighted_lpc[10];
+ float weight = -0.625;
+ int i;
+
+ for(i=0; i<10; i++)
+ {
+ weighted_lpc[i] = lpc[i] * weight;
+ weight *= 0.625;
+ }
+ ff_celp_lp_zero_synthesis_filterf(outbuffer, weighted_lpc, formant_mem, 40, 10);
+
+ weight = 0.775;
+ for(i=0; i<10; i++)
+ {
+ weighted_lpc[i] = lpc[i] * weight;
+ weight *= 0.775;
+ }
+ ff_celp_lp_synthesis_filterf(pole_mem, weighted_lpc, outbuffer, 40, 10);
+
+ outbuffer[0] = pole_mem[0] - 0.3 * q->prev_anti_tilt_filter_mem;
+ for(i=1; i<40; i++)
+ outbuffer[i] = pole_mem[i] - 0.3 * outbuffer[i-1];
+ q->prev_anti_tilt_filter_mem = outbuffer[39];
+}
+
static qcelp_packet_rate buf_size2bitrate(const int buf_size)
{
switch(buf_size)
@@ -820,16 +867,19 @@ erasure:
{
interpolate_lpc(q, quantized_lspf, lpc, i);
ff_celp_lp_synthesis_filterf(formant_mem, lpc, outbuffer, 40, 10);
+ do_postfilter(q, outbuffer, lpc, formant_mem, q->postfilter_pole_mem + 10 + 40*i);
+
+ q->final_gain = 0.9375 * q->final_gain
+ + 0.0625 * compute_gain_ctrl(formant_mem, outbuffer, 40);
+
for(j=0; j<40; j++)
- outbuffer[j] = av_clipf(formant_mem[j], QCELP_CLIP_LOWER_BOUND,
+ outbuffer[j] = av_clipf(q->final_gain * outbuffer[j], QCELP_CLIP_LOWER_BOUND,
QCELP_CLIP_UPPER_BOUND);
outbuffer += 40;
formant_mem += 40;
}
memcpy(q->formant_mem, q->formant_mem + 160, 10 * sizeof(float));
-
- // FIXME: postfilter and final gain control should be here.
- // TIA/EIA/IS-733 2.4.8.6
+ memcpy(q->postfilter_pole_mem, q->postfilter_pole_mem + 160, 10 * sizeof(float));
memcpy(q->prev_lspf, quantized_lspf, sizeof(q->prev_lspf));
q->prev_bitrate = q->bitrate;
More information about the ffmpeg-devel
mailing list