[FFmpeg-soc] [soc]: r4680 - in amr: amrnbfloatdata.h amrnbfloatdec.c

cmcq subversion at mplayerhq.hu
Sun Jul 12 13:27:36 CEST 2009


Author: cmcq
Date: Sun Jul 12 13:27:36 2009
New Revision: 4680

Log:
Implement post-processing

Modified:
   amr/amrnbfloatdata.h
   amr/amrnbfloatdec.c

Modified: amr/amrnbfloatdata.h
==============================================================================
--- amr/amrnbfloatdata.h	Sun Jul 12 13:22:07 2009	(r4679)
+++ amr/amrnbfloatdata.h	Sun Jul 12 13:27:36 2009	(r4680)
@@ -2331,6 +2331,34 @@ static const float *ir_filters_lookup[2]
 static const float *ir_filters_lookup_MODE_795[2] = { ir_filter_strong_MODE_795, ir_filter_medium };
 
 
+// post-processing tables
+
+// Powers of formant factors (section 6.2.1)
+static const float formant_high_n[10] = {
+0.700000, 0.490000, 0.343000, 0.240100, 0.168070,
+0.117649, 0.082354, 0.057648, 0.040354, 0.028248
+};
+static const float formant_high_d[10] = {
+0.750000, 0.562500, 0.421875, 0.316406, 0.237305,
+0.177979, 0.133484, 0.100113, 0.075085, 0.056314
+};
+static const float formant_low_n[10] = {
+0.550000, 0.302500, 0.166375, 0.091506, 0.050328,
+0.027681, 0.015224, 0.008373, 0.004605, 0.002533
+};
+static const float *formant_low_d = formant_high_n;
+
+// Number of impulse response coefficients used for tilt factor
+#define AMR_TILT_RESPONSE 22
+// Tilt factor = 1st reflection coefficient * gamma_t
+#define AMR_TILT_GAMMA_T 0.8
+// Adaptive gain control factor used in post-filter
+#define AMR_AGC_ALPHA 0.9
+
+// High-pass filter coefficients (section 6.2.2)
+static const float high_pass_n[] = {0.939819335, -1.879638672, 0.939819335};
+static const float high_pass_d[] = {             -1.933105469, 0.935913085};
+
 /**************************** end of tables *****************************/
 
 #endif /* AVCODEC_AMRNBFLOATDATA_H */

Modified: amr/amrnbfloatdec.c
==============================================================================
--- amr/amrnbfloatdec.c	Sun Jul 12 13:22:07 2009	(r4679)
+++ amr/amrnbfloatdec.c	Sun Jul 12 13:27:36 2009	(r4680)
@@ -76,6 +76,11 @@ typedef struct AMRContext {
     uint8_t         prev_ir_filter_strength; ///< previous impulse response filter strength; 0 - strong, 1 - medium, 2 - none
     uint8_t                 ir_filter_onset; ///< flag for impulse response filter strength
 
+    float              post_process_mem[10]; ///< previous intermediate values in the formant filter
+    float                          tilt_mem; ///< previous input to tilt compensation filter
+    float                   post_filter_agc; ///< previous factor used for adaptive gain control
+    float                  high_pass_mem[2]; ///< previous intermediate values in the high-pass filter
+
     float samples_in[LP_FILTER_ORDER + AMR_SUBFRAME_SIZE]; ///< floating point samples
 
 } AMRContext;
@@ -914,9 +919,140 @@ static void update_state(AMRContext *p)
 
 /// @}
 
+/// @defgroup amr_postproc Post processing functions
+/// @{
 
+/**
+ * Get the tilt factor of a formant filter from its transfer function
+ *
+ * @param lpc_n LP_FILTER_ORDER + 1 coefficients of the numerator
+ * @param lpc_d LP_FILTER_ORDER coefficients of the denominator
+ */
+static float tilt_factor(float *lpc_n, float *lpc_d)
+{
+    // Truncated impulse response of the formant filter
+    float tmp[LP_FILTER_ORDER + AMR_TILT_RESPONSE] = {0};
+    float *hf = tmp + LP_FILTER_ORDER;
 
-static int amrnb_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
+    float rh0 = 0.0, rh1 = 0.0;
+
+    // Get impulse response of the transfer function given by lpc_n and lpc_d
+    memcpy(hf, lpc_n, sizeof(float) * (LP_FILTER_ORDER + 1));
+    ff_celp_lp_synthesis_filterf(hf, lpc_d, hf, AMR_TILT_RESPONSE,
+                                 LP_FILTER_ORDER);
+
+    rh0 = ff_dot_productf(hf, hf,     AMR_TILT_RESPONSE);
+    rh1 = ff_dot_productf(hf, hf + 1, AMR_TILT_RESPONSE - 1);
+
+    // The spec only specifies this check for 12.2 and 10.2 kbit/s
+    // modes. But in the ref source the tilt is always non-negative.
+    return rh1 >= 0.0 ? rh1 / rh0 * AMR_TILT_GAMMA_T : 0.0;
+}
+
+/**
+ * Apply tilt compensation filter, 1 - tilt * z^-1
+ *
+ * @param mem Pointer to one float to keep the filter's state
+ * @param tilt Tilt factor
+ * @param samples AMR_SUBFRAME_SIZE array where the filter is applied
+ */
+static void tilt_compensation(float *mem, float tilt, float *samples)
+{
+    float new_tilt_mem = samples[AMR_SUBFRAME_SIZE - 1];
+    int i;
+
+    for (i = AMR_SUBFRAME_SIZE - 1; i > 0; i--)
+         samples[i] -= tilt * samples[i - 1];
+
+    samples[0] -= tilt * *mem;
+    *mem = new_tilt_mem;
+}
+
+/**
+ * Perform adaptive post-filtering to enhance the quality of the speech.
+ * See section 6.2.1.
+ *
+ * @param p             pointer to the AMRContext
+ * @param lpc           interpolated LP coefficients for this subframe
+ * @param buf_out       output of the filter
+ */
+static void post_process(AMRContext *p, float *lpc, float *buf_out)
+{
+    int i;
+    float *samples = p->samples_in + LP_FILTER_ORDER;
+    float gain_scale_factor = 1.0;
+    float speech_gain = ff_dot_productf(samples, samples, AMR_SUBFRAME_SIZE);
+    float post_filter_gain;
+    float tmp[AMR_SUBFRAME_SIZE + LP_FILTER_ORDER];
+    const float *gamma_n, *gamma_d; // Formant filter factor table
+    float lpc_n[LP_FILTER_ORDER + 1], // Transfer function coefficients
+          lpc_d[LP_FILTER_ORDER];     //
+
+    if (p->cur_frame_mode == MODE_122 || p->cur_frame_mode == MODE_102) {
+        gamma_n = formant_high_n;
+        gamma_d = formant_high_d;
+    } else {
+        gamma_n = formant_low_n;
+        gamma_d = formant_low_d;
+    }
+
+    lpc_n[0] = 1;
+    for (i = 0; i < LP_FILTER_ORDER; i++) {
+         lpc_n[i + 1] = lpc[i] * gamma_n[i];
+         lpc_d[i]     = lpc[i] * gamma_d[i];
+    }
+
+    // Apply transfer function given by lpc_n and lpc_d
+    memcpy(tmp, p->post_process_mem, sizeof(float) * LP_FILTER_ORDER);
+    ff_celp_lp_synthesis_filterf(tmp + LP_FILTER_ORDER, lpc_d, samples,
+                                 AMR_SUBFRAME_SIZE, LP_FILTER_ORDER);
+    memcpy(p->post_process_mem, tmp + AMR_SUBFRAME_SIZE,
+           sizeof(float) * LP_FILTER_ORDER);
+    ff_celp_lp_zero_synthesis_filterf(buf_out, lpc_n, tmp + LP_FILTER_ORDER,
+                                      AMR_SUBFRAME_SIZE, LP_FILTER_ORDER + 1);
+
+    // Apply tilt compensation
+    tilt_compensation(&p->tilt_mem, tilt_factor(lpc_n, lpc_d), buf_out);
+
+    // Adaptive gain control
+    post_filter_gain = ff_dot_productf(buf_out, buf_out, AMR_SUBFRAME_SIZE);
+    if (post_filter_gain != 0)
+        gain_scale_factor = sqrt(speech_gain / post_filter_gain);
+
+    p->post_filter_agc = AMR_AGC_ALPHA * p->post_filter_agc +
+                         (1.0 - AMR_AGC_ALPHA) * gain_scale_factor;
+
+    for (i = 0; i < AMR_SUBFRAME_SIZE; i++)
+        buf_out[i] *= p->post_filter_agc;
+}
+
+/**
+ * High-pass filtering and up-scaling
+ *
+ * @param high_pass_mem Pointer to two floats for the filter state
+ * @param samples AMR_SUBFRAME_SIZE buffer where the filter is applied
+ */
+void high_pass_filter(float *high_pass_mem, float *samples)
+{
+    int i;
+    float tmp[AMR_SUBFRAME_SIZE + 2];
+
+    memcpy(tmp, high_pass_mem, sizeof(float) * 2);
+    ff_celp_lp_synthesis_filterf(tmp + 2, high_pass_d, samples,
+                                 AMR_SUBFRAME_SIZE, 2);
+    memcpy(high_pass_mem, tmp + AMR_SUBFRAME_SIZE, sizeof(float) * 2);
+    ff_celp_lp_zero_synthesis_filterf(samples, high_pass_n, tmp + 2,
+                                      AMR_SUBFRAME_SIZE, 3);
+
+    for (i = 0; i < AMR_SUBFRAME_SIZE; i++)
+        // Post-processing up-scales by 2. It's convenient to
+        // scale from PCM values to [-1,1] here too.
+        samples[i] *= 2.0 * AMR_SAMPLE_SCALE;
+}
+
+/// @}
+
+int amrnb_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
                               AVPacket *avpkt)
 {
 
@@ -995,12 +1131,11 @@ static int amrnb_decode_frame(AVCodecCon
 
 /*** end of synthesis ***/
 
+        post_process(p, p->lpc[subframe], buf_out + subframe * AMR_SUBFRAME_SIZE);
+        high_pass_filter(p->high_pass_mem, buf_out + subframe * AMR_SUBFRAME_SIZE);
+
         // update buffers and history
         update_state(p);
-
-        for (i = 0; i < AMR_SUBFRAME_SIZE; i++)
-            buf_out[subframe * AMR_SUBFRAME_SIZE + i] =
-                p->samples_in[LP_FILTER_ORDER + i] * AMR_SAMPLE_SCALE;
     }
 
     /* report how many samples we got */


More information about the FFmpeg-soc mailing list