FreeCalypso > hg > gsm-codec-lib
view libtwamr/agc.c @ 478:936a08cc73ce
doc/AMR-library-API: describe the decoder
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 19 May 2024 21:32:31 +0000 |
parents | 6b33f3ba4289 |
children |
line wrap: on
line source
/* ***************************************************************************** * * GSM AMR-NB speech codec R98 Version 7.6.0 December 12, 2001 * R99 Version 3.3.0 * REL-4 Version 4.1.0 * ***************************************************************************** * * File : agc.c * ***************************************************************************** */ /* ***************************************************************************** * MODULE INCLUDE FILE AND VERSION ID ***************************************************************************** */ #include "namespace.h" #include "agc.h" /* ***************************************************************************** * INCLUDE FILES ***************************************************************************** */ #include "typedef.h" #include "basic_op.h" #include "no_count.h" #include "cnst.h" #include "inv_sqrt.h" /* ***************************************************************************** * LOCAL VARIABLES AND TABLES ***************************************************************************** */ /* ***************************************************************************** * LOCAL PROGRAM CODE ***************************************************************************** */ static Word32 energy_old( /* o : return energy of signal */ Word16 in[], /* i : input signal (length l_trm) */ Word16 l_trm /* i : signal length */ ) { Word32 s; Word16 i, temp; temp = shr (in[0], 2); s = L_mult (temp, temp); for (i = 1; i < l_trm; i++) { temp = shr (in[i], 2); s = L_mac (s, temp, temp); } return s; } static Word32 energy_new( /* o : return energy of signal */ Word16 in[], /* i : input signal (length l_trm) */ Word16 l_trm /* i : signal length */ ) { Word32 s; Word16 i; Flag ov_save; ov_save = Overflow; move16 (); /* save overflow flag in case energy_old */ /* must be called */ s = L_mult(in[0], in[0]); for (i = 1; i < l_trm; i++) { s = L_mac(s, in[i], in[i]); } /* check for overflow */ test (); if (L_sub (s, MAX_32) == 0L) { Overflow = ov_save; move16 (); /* restore overflow flag */ s = energy_old (in, l_trm); move32 (); /* function result */ } else { s = L_shr(s, 4); } return s; } /* ***************************************************************************** * PUBLIC PROGRAM CODE ***************************************************************************** */ /* ************************************************************************** * * Function : agc_reset * Purpose : Reset of agc (i.e. set state memory to 1.0) * ************************************************************************** */ void agc_reset (agcState *state) { state->past_gain = 4096; /* initial value of past_gain = 1.0 */ } /* ************************************************************************** * * Function : agc * Purpose : Scales the postfilter output on a subframe basis * ************************************************************************** */ int agc ( agcState *st, /* i/o : agc state */ Word16 *sig_in, /* i : postfilter input signal (l_trm) */ Word16 *sig_out, /* i/o : postfilter output signal (l_trm) */ Word16 agc_fac, /* i : AGC factor */ Word16 l_trm /* i : subframe size */ ) { Word16 i, exp; Word16 gain_in, gain_out, g0, gain; Word32 s; /* calculate gain_out with exponent */ s = energy_new(sig_out, l_trm); move32 (); /* function result */ test (); if (s == 0) { st->past_gain = 0; move16 (); return 0; } exp = sub (norm_l (s), 1); gain_out = round (L_shl (s, exp)); /* calculate gain_in with exponent */ s = energy_new(sig_in, l_trm); move32 (); /* function result */ test (); if (s == 0) { g0 = 0; move16 (); } else { i = norm_l (s); gain_in = round (L_shl (s, i)); exp = sub (exp, i); /*---------------------------------------------------* * g0 = (1-agc_fac) * sqrt(gain_in/gain_out); * *---------------------------------------------------*/ s = L_deposit_l (div_s (gain_out, gain_in)); s = L_shl (s, 7); /* s = gain_out / gain_in */ s = L_shr (s, exp); /* add exponent */ s = Inv_sqrt (s); move32 (); /* function result */ i = round (L_shl (s, 9)); /* g0 = i * (1-agc_fac) */ g0 = mult (i, sub (32767, agc_fac)); } /* compute gain[n] = agc_fac * gain[n-1] + (1-agc_fac) * sqrt(gain_in/gain_out) */ /* sig_out[n] = gain[n] * sig_out[n] */ gain = st->past_gain; move16 (); for (i = 0; i < l_trm; i++) { gain = mult (gain, agc_fac); gain = add (gain, g0); sig_out[i] = extract_h (L_shl (L_mult (sig_out[i], gain), 3)); move16 (); } st->past_gain = gain; move16 (); return 0; } /* ************************************************************************** * * Function : agc2 * Purpose : Scales the excitation on a subframe basis * ************************************************************************** */ void agc2 ( Word16 *sig_in, /* i : postfilter input signal */ Word16 *sig_out, /* i/o : postfilter output signal */ Word16 l_trm /* i : subframe size */ ) { Word16 i, exp; Word16 gain_in, gain_out, g0; Word32 s; /* calculate gain_out with exponent */ s = energy_new(sig_out, l_trm); move32 (); /* function result */ test (); if (s == 0) { return; } exp = sub (norm_l (s), 1); gain_out = round (L_shl (s, exp)); /* calculate gain_in with exponent */ s = energy_new(sig_in, l_trm); move32 (); /* function result */ test (); if (s == 0) { g0 = 0; move16 (); } else { i = norm_l (s); gain_in = round (L_shl (s, i)); exp = sub (exp, i); /*---------------------------------------------------* * g0 = sqrt(gain_in/gain_out); * *---------------------------------------------------*/ s = L_deposit_l (div_s (gain_out, gain_in)); s = L_shl (s, 7); /* s = gain_out / gain_in */ s = L_shr (s, exp); /* add exponent */ s = Inv_sqrt (s); move32 (); /* function result */ g0 = round (L_shl (s, 9)); } /* sig_out(n) = gain(n) sig_out(n) */ for (i = 0; i < l_trm; i++) { sig_out[i] = extract_h (L_shl (L_mult (sig_out[i], g0), 3)); move16 (); } return; }