From 682337672cd38b8e85acf11578a5130fa87ea1d7 Mon Sep 17 00:00:00 2001 From: Vladimir Voroshilov Date: Sun, 28 Jun 2009 21:01:23 +0700 Subject: [PATCH] Adaptive gain control --- libavcodec/g729dec.c | 21 ++++++++++++++++ libavcodec/g729postfilter.c | 48 +++++++++++++++++++++++++++++++++++++ libavcodec/g729postfilter.h | 20 ++++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/libavcodec/g729dec.c b/libavcodec/g729dec.c index bc7fbc13a8..e977e53954 100644 --- a/libavcodec/g729dec.c +++ b/libavcodec/g729dec.c @@ -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; jgain_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 diff --git a/libavcodec/g729postfilter.c b/libavcodec/g729postfilter.c index 9af6014b9e..971c3d2ef6 100644 --- a/libavcodec/g729postfilter.c +++ b/libavcodec/g729postfilter.c @@ -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; +} diff --git a/libavcodec/g729postfilter.h b/libavcodec/g729postfilter.h index 07667994d5..956cde9ab7 100644 --- a/libavcodec/g729postfilter.h +++ b/libavcodec/g729postfilter.h @@ -39,6 +39,13 @@ #define FORMANT_PP_FACTOR_NUM 18022 //0.55 in Q15 #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 @@ -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