Adaptive gain control
authorVladimir Voroshilov <voroshil@gmail.com>
Sun, 28 Jun 2009 14:01:23 +0000 (21:01 +0700)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 24 Sep 2011 19:11:01 +0000 (21:11 +0200)
libavcodec/g729dec.c
libavcodec/g729postfilter.c
libavcodec/g729postfilter.h

index bc7fbc1..e977e53 100644 (file)
@@ -145,6 +145,7 @@ typedef struct {
     int16_t onset;              ///< detected onset level (0-2)
     int16_t was_periodic;       ///< whether previous frame was declared as periodic or not (4.4)
     int16_t ht_prev_data;       ///< previous data for 4.2.3, equation 86
+    int gain_coeff;             ///< (1.14) gain coefficient (4.2.4)
     uint16_t rand_value;        ///< random number generator value (4.4.4)
     int ma_predictor_prev;      ///< switched MA predictor of LSP quantizer from last good frame
 
@@ -348,6 +349,8 @@ static av_cold int decoder_init(AVCodecContext * avctx)
     /* Both 8kbit/s and 6.4kbit/s modes uses two subframes per frame. */
     avctx->frame_size = SUBFRAME_SIZE << 1;
 
+    ctx->gain_coeff = 16384; // 1.0 in (1.14)
+
     for (k = 0; k < MA_NP + 1; k++) {
         ctx->past_quantizer_outputs[k] = ctx->past_quantizer_output_buf[k];
         for (i = 1; i < 11; i++)
@@ -397,6 +400,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
     int16_t fc[SUBFRAME_SIZE];   // fixed-codebook vector
     int16_t synth[SUBFRAME_SIZE+10]; // fixed-codebook vector
     int j;
+    int gain_before, gain_after;
     int is_periodic = 0;         // whether one of the subframes is declared as periodic or not
 
     if (*data_size < SUBFRAME_SIZE << 2) {
@@ -637,6 +641,11 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
         /* Save data (without postfilter) for use in next subframe. */
         memcpy(ctx->syn_filter_data, synth+SUBFRAME_SIZE, 10 * sizeof(int16_t));
 
+        /* Calculate gain of unfiltered signal for use in AGC. */
+        gain_before = 0;
+        for (j = 0; j < SUBFRAME_SIZE; j++)
+            gain_before += FFABS(synth[j+10]);
+
         /* Call postfilter and also update voicing decision for use in next frame. */
         g729_postfilter(
                 &ctx->dsp,
@@ -650,6 +659,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size,
                 synth+10,
                 SUBFRAME_SIZE);
 
+        /* Calculate gain of filtered signal for use in AGC. */
+        gain_after = 0;
+        for(j=0; j<SUBFRAME_SIZE; j++)
+            gain_after += FFABS(synth[j+10]);
+
+        ctx->gain_coeff = g729_adaptive_gain_control(
+                gain_before,
+                gain_after,
+                synth+10,
+                SUBFRAME_SIZE,
+                ctx->gain_coeff);
+
         if (frame_erasure)
             ctx->pitch_delay_int_prev = FFMIN(ctx->pitch_delay_int_prev + 1, PITCH_DELAY_MAX);
         else
index 9af6014..971c3d2 100644 (file)
@@ -560,3 +560,51 @@ void g729_postfilter(DSPContext *dsp, int16_t* ht_prev_data, int16_t* voicing,
     *ht_prev_data = apply_tilt_comp(speech, pos_filter_data + 10, tilt_comp_coeff,
                                     subframe_size, *ht_prev_data);
 }
+
+/**
+ * \brief Adaptive gain control (4.2.4)
+ * \param gain_before gain of speech before applying postfilters
+ * \param gain_after  gain of speech after applying postfilters
+ * \param speech [in/out] signal buffer
+ * \param subframe_size length of subframe
+ * \param gain_prev (3.12) previous value of gain coefficient
+ *
+ * \return (3.12) last value of gain coefficient
+ */
+int16_t g729_adaptive_gain_control(int gain_before, int gain_after, int16_t *speech,
+                                   int subframe_size, int16_t gain_prev)
+{
+    int gain; // (3.12)
+    int n;
+    int exp_before, exp_after;
+
+    if(!gain_after && gain_before)
+        return 0;
+
+    if (gain_before) {
+
+        exp_before  = 14 - av_log2(gain_before);
+        gain_before = bidir_sal(gain_before, exp_before);
+
+        exp_after  = 14 - av_log2(gain_after);
+        gain_after = bidir_sal(gain_after, exp_after);
+
+        if (gain_before < gain_after) {
+            gain = (gain_before << 15) / gain_after;
+            gain = bidir_sal(gain, exp_after - exp_before - 1);
+        } else {
+            gain = ((gain_before - gain_after) << 14) / gain_after + 0x4000;
+            gain = bidir_sal(gain, exp_after - exp_before);
+        }
+        gain = (gain * G729_AGC_FAC1 + 0x4000) >> 15; // gain * (1-0.9875)
+    } else
+        gain = 0;
+
+    for (n = 0; n < subframe_size; n++) {
+        // gain_prev = gain + 0.9875 * gain_prev
+        gain_prev = (G729_AGC_FACTOR * gain_prev + 0x4000) >> 15;
+        gain_prev = av_clip_int16(gain + gain_prev);
+        speech[n] = av_clip_int16((speech[n] * gain_prev + 0x2000) >> 14);
+    }
+    return gain_prev;
+}
index 0766799..956cde9 100644 (file)
 #define FORMANT_PP_FACTOR_DEN  22938             //0.70 in Q15
 
 /**
+ * gain adjustment factor (G.729, 4.2.4)
+ * 0.9875 in Q15
+ */
+#define G729_AGC_FACTOR            32358
+#define G729_AGC_FAC1 (32768-G729_AGC_FACTOR)
+
+/**
  * 1.0 / (1.0 + 0.5) in Q15
  * where 0.5 is the minimum value of
  * weight factor, controlling amount of long-term postfiltering
@@ -92,4 +99,17 @@ void g729_postfilter(DSPContext *dsp, int16_t* ht_prev_data, int16_t* voicing,
                      int16_t* pos_filter_data, int16_t *speech,
                      int subframe_size);
 
+/**
+ * \brief Adaptive gain control (4.2.4)
+ * \param gain_before (Q0) gain of speech before applying postfilters
+ * \param gain_after  (Q0) gain of speech after applying postfilters
+ * \param speech [in/out] (Q0) signal buffer
+ * \param subframe_size length of subframe
+ * \param gain_prev (Q12) previous value of gain coefficient
+ *
+ * \return (Q12) last value of gain coefficient
+ */
+int16_t g729_adaptive_gain_control(int gain_before, int gain_after, int16_t *speech,
+                                   int subframe_size, int16_t gain_prev);
+
 #endif // FFMPEG_G729POSTFILTER_H