/* ------------------------------------------------------------------ * Copyright (C) 1998-2009 PacketVideo * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. * See the License for the specific language governing permissions * and limitations under the License. * ------------------------------------------------------------------- */ /**************************************************************************************** Portions of this file are derived from the following 3GPP standard: 3GPP TS 26.073 ANSI-C code for the Adaptive Multi-Rate (AMR) speech codec Available from http://www.3gpp.org (C) 2004, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TTA, TTC) Permission to distribute, modify and use this file under the standard license terms listed above has been obtained from the copyright holder. ****************************************************************************************/ /* ------------------------------------------------------------------------------ Pathname: ./audio/gsm-amr/c/src/agc.c Funtions: energy_old energy_new agc_init agc_reset agc_exit agc agc2 ------------------------------------------------------------------------------ MODULE DESCRIPTION This set of modules scale the excitation level and output of the speech signals. ------------------------------------------------------------------------------ */ /*---------------------------------------------------------------------------- ; INCLUDES ----------------------------------------------------------------------------*/ #include "agc.h" #include "cnst.h" #include "inv_sqrt.h" #include "basic_op.h" /*---------------------------------------------------------------------------- ; MACROS ; Define module specific macros here ----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------- ; DEFINES ; Include all pre-processor statements here. Include conditional ; compile variables also. ----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------- ; LOCAL FUNCTION DEFINITIONS ; Function Prototype declaration ----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------- ; LOCAL VARIABLE DEFINITIONS ; Variable declaration - defined here and used outside this module ----------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------------ FUNCTION NAME: energy_old ------------------------------------------------------------------------------ INPUT AND OUTPUT DEFINITIONS Inputs: in = input signal (Word16) l_trm = input signal length (Word16) pOverflow = address of overflow (Flag) Outputs: pOverflow -> 1 if the energy computation saturates Returns: s = return energy of signal (Word32) Global Variables Used: None. Local Variables Needed: None. ------------------------------------------------------------------------------ FUNCTION DESCRIPTION Returns the energy of the signal. ------------------------------------------------------------------------------ REQUIREMENTS None. ------------------------------------------------------------------------------ REFERENCES agc.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 ------------------------------------------------------------------------------ PSEUDO-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; } ------------------------------------------------------------------------------ RESOURCES USED [optional] When the code is written for a specific target processor the the resources used should be documented below. HEAP MEMORY USED: x bytes STACK MEMORY USED: x bytes CLOCK CYCLES: (cycle count equation for this function) + (variable used to represent cycle count for each subroutine called) where: (cycle count variable) = cycle count for [subroutine name] ------------------------------------------------------------------------------ CAUTION [optional] [State any special notes, constraints or cautions for users of this function] ------------------------------------------------------------------------------ */ static Word32 energy_old( /* o : return energy of signal */ Word16 in[], /* i : input signal (length l_trm) */ Word16 l_trm, /* i : signal length */ Flag *pOverflow /* overflow: flag to indicate overflow */ ) { Word32 s = 0; Word16 i; Word16 temp; for (i = 0; i < l_trm; i++) { temp = in[i] >> 2; s = L_mac(s, temp, temp, pOverflow); } return(s); } /*----------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------------ FUNCTION NAME: energy_old__Wrapper ------------------------------------------------------------------------------ INPUT AND OUTPUT DEFINITIONS Inputs: in = input signal (Word16) l_trm = input signal length (Word16) pOverflow = address of overflow (Flag) Outputs: pOverflow -> 1 if the energy computation saturates Returns: s = return energy of signal (Word32) Global Variables Used: None. Local Variables Needed: None. ------------------------------------------------------------------------------ FUNCTION DESCRIPTION This function provides external access to the static function energy_old. ------------------------------------------------------------------------------ REQUIREMENTS None ------------------------------------------------------------------------------ REFERENCES None ------------------------------------------------------------------------------ PSEUDO-CODE CALL energy_old ( in = in l_trm = l_trm pOverflow = pOverflow ) MODIFYING(nothing) RETURNING(energy_old_value = s) ------------------------------------------------------------------------------ RESOURCES USED [optional] When the code is written for a specific target processor the the resources used should be documented below. HEAP MEMORY USED: x bytes STACK MEMORY USED: x bytes CLOCK CYCLES: (cycle count equation for this function) + (variable used to represent cycle count for each subroutine called) where: (cycle count variable) = cycle count for [subroutine name] ------------------------------------------------------------------------------ CAUTION [optional] [State any special notes, constraints or cautions for users of this function] ------------------------------------------------------------------------------ */ Word32 energy_old_Wrapper(Word16 in[], Word16 l_trm, Flag *pOverflow) { Word32 energy_old_value; /*---------------------------------------------------------------------------- CALL energy_old ( in = in l_trm = l_trm pOverflow = pOverflow ) MODIFYING(nothing) RETURNING(energy_old_value = s) ----------------------------------------------------------------------------*/ energy_old_value = energy_old(in, l_trm, pOverflow); return(energy_old_value); } /*--------------------------------------------------------------------------*/ /* ----------------------------------------------------------------------------- FUNCTION NAME: energy_new ------------------------------------------------------------------------------ INPUT AND OUTPUT DEFINITIONS Inputs: in = input signal l_trm = input signal length pOverflow = address of overflow (Flag) Outputs: pOverflow -> 1 if the energy computation saturates Returns: s = return energy of signal Global Variables Used: None. Local Variables Needed: None. ------------------------------------------------------------------------------ FUNCTION DESCRIPTION Returns the energy of the signal. ------------------------------------------------------------------------------ REQUIREMENTS None. ------------------------------------------------------------------------------ REFERENCES agc.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 ------------------------------------------------------------------------------ PSEUDO-CODE 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; //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 if (L_sub (s, MAX_32) == 0L) { Overflow = ov_save; // restore overflow flag s = energy_old (in, l_trm); // function result } else { s = L_shr(s, 4); } return(s); } ------------------------------------------------------------------------------ RESOURCES USED [optional] When the code is written for a specific target processor the the resources used should be documented below. HEAP MEMORY USED: x bytes STACK MEMORY USED: x bytes CLOCK CYCLES: (cycle count equation for this function) + (variable used to represent cycle count for each subroutine called) where: (cycle count variable) = cycle count for [subroutine name] ------------------------------------------------------------------------------ CAUTION [optional] [State any special notes, constraints or cautions for users of this function] ------------------------------------------------------------------------------ */ static Word32 energy_new( /* o : return energy of signal */ Word16 in[], /* i : input signal (length l_trm) */ Word16 l_trm, /* i : signal length */ Flag *pOverflow /* i : overflow flag */ ) { Word32 s = 0; Word16 i; Flag ov_save; ov_save = *(pOverflow); /* save overflow flag in case energy_old */ /* must be called */ for (i = 0; i < l_trm; i++) { s = L_mac(s, in[i], in[i], pOverflow); } /* check for overflow */ if (s != MAX_32) { /* s is a sum of squares, so it won't be negative */ s = s >> 4; } else { *(pOverflow) = ov_save; /* restore overflow flag */ s = energy_old(in, l_trm, pOverflow); /* function result */ } return (s); } /*--------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------------ FUNCTION NAME: energy_new__Wrapper ------------------------------------------------------------------------------ INPUT AND OUTPUT DEFINITIONS Inputs: in = input signal (Word16) l_trm = input signal length (Word16) overflow = address of overflow (Flag) Outputs: pOverflow -> 1 if the energy computation saturates Returns: s = return energy of signal (Word32) Global Variables Used: None. Local Variables Needed: None. ------------------------------------------------------------------------------ FUNCTION DESCRIPTION This function provides external access to the static function energy_new. ------------------------------------------------------------------------------ REQUIREMENTS None ------------------------------------------------------------------------------ REFERENCES None ------------------------------------------------------------------------------ PSEUDO-CODE CALL energy_new ( in = in l_trm = l_trm pOverflow = pOverflow ) MODIFYING(nothing) RETURNING(energy_new_value = s) ------------------------------------------------------------------------------ RESOURCES USED [optional] When the code is written for a specific target processor the the resources used should be documented below. HEAP MEMORY USED: x bytes STACK MEMORY USED: x bytes CLOCK CYCLES: (cycle count equation for this function) + (variable used to represent cycle count for each subroutine called) where: (cycle count variable) = cycle count for [subroutine name] ------------------------------------------------------------------------------ CAUTION [optional] [State any special notes, constraints or cautions for users of this function] ------------------------------------------------------------------------------ */ Word32 energy_new_Wrapper(Word16 in[], Word16 l_trm, Flag *pOverflow) { Word32 energy_new_value; /*---------------------------------------------------------------------------- CALL energy_new ( in = in l_trm = l_trm pOverflow = pOverflow ) MODIFYING(nothing) RETURNING(energy_new_value = s) ----------------------------------------------------------------------------*/ energy_new_value = energy_new(in, l_trm, pOverflow); return(energy_new_value); } /*--------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------------ FUNCTION NAME: agc_reset ------------------------------------------------------------------------------ INPUT AND OUTPUT DEFINITIONS Inputs: state = pointer to a structure of type agcState Outputs: Structure pointed to by state is initialized to zeros Returns: Returns 0 if memory was successfully initialized, otherwise returns -1. Global Variables Used: None. Local Variables Needed: None. ------------------------------------------------------------------------------ FUNCTION DESCRIPTION Reset of agc (i.e. set state memory to 1.0). ------------------------------------------------------------------------------ REQUIREMENTS None. ------------------------------------------------------------------------------ REFERENCES agc.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 ------------------------------------------------------------------------------ PSEUDO-CODE int agc_reset (agcState *state) { if (state == (agcState *) NULL) { fprintf(stderr, "agc_reset: invalid parameter\n"); return -1; } state->past_gain = 4096; // initial value of past_gain = 1.0 return 0; } ------------------------------------------------------------------------------ RESOURCES USED [optional] When the code is written for a specific target processor the the resources used should be documented below. HEAP MEMORY USED: x bytes STACK MEMORY USED: x bytes CLOCK CYCLES: (cycle count equation for this function) + (variable used to represent cycle count for each subroutine called) where: (cycle count variable) = cycle count for [subroutine name] ------------------------------------------------------------------------------ CAUTION [optional] [State any special notes, constraints or cautions for users of this function] ------------------------------------------------------------------------------ */ Word16 agc_reset(agcState *state) { if (state == (agcState *) NULL) { /* fprintf(stderr, "agc_reset: invalid parameter\n"); */ return(-1); } state->past_gain = 4096; /* initial value of past_gain = 1.0 */ return(0); } /*--------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------------ FUNCTION NAME: agc ------------------------------------------------------------------------------ INPUT AND OUTPUT DEFINITIONS Inputs: st = pointer to agc state sig_in = pointer to a buffer containing the postfilter input signal sig_out = pointer to a buffer containing the postfilter output signal agc_fac = AGC factor l_trm = subframe size pOverflow = pointer to the overflow flag Outputs: st->past_gain = gain buffer pointed to by sig_out contains the new postfilter output signal pOverflow -> 1 if the agc computation saturates Returns: return = 0 Global Variables Used: none. Local Variables Needed: none. ------------------------------------------------------------------------------ FUNCTION DESCRIPTION Scales the postfilter output on a subframe basis using: sig_out[n] = sig_out[n] * gain[n] gain[n] = agc_fac * gain[n-1] + (1 - agc_fac) g_in/g_out where: gain[n] = gain at the nth sample given by g_in/g_out = square root of the ratio of energy at the input and output of the postfilter. ------------------------------------------------------------------------------ REQUIREMENTS None. ------------------------------------------------------------------------------ REFERENCES agc.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 ------------------------------------------------------------------------------ PSEUDO-CODE 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); // function result if (s == 0) { st->past_gain = 0; return 0; } exp = sub (norm_l (s), 1); gain_out = pv_round (L_shl (s, exp)); // calculate gain_in with exponent s = energy_new(sig_in, l_trm); // function result if (s == 0) { g0 = 0; } else { i = norm_l (s); gain_in = pv_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); // function result i = pv_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; 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)); } st->past_gain = gain; return 0; } ------------------------------------------------------------------------------ RESOURCES USED [optional] When the code is written for a specific target processor the the resources used should be documented below. HEAP MEMORY USED: x bytes STACK MEMORY USED: x bytes CLOCK CYCLES: (cycle count equation for this function) + (variable used to represent cycle count for each subroutine called) where: (cycle count variable) = cycle count for [subroutine name] ------------------------------------------------------------------------------ CAUTION [optional] [State any special notes, constraints or cautions for users of this function] ------------------------------------------------------------------------------ */ void 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 */ Flag *pOverflow /* i : overflow Flag */ ) { Word16 i; Word16 exp; Word16 gain_in; Word16 gain_out; Word16 g0; Word16 gain; Word32 s; Word32 L_temp; Word16 temp; Word16 *p_sig_out; /* calculate gain_out with exponent */ s = energy_new(sig_out, l_trm, pOverflow); /* function result */ if (s == 0) { st->past_gain = 0; return; } exp = norm_l(s) - 1; L_temp = L_shl(s, exp, pOverflow); gain_out = pv_round(L_temp, pOverflow); /* calculate gain_in with exponent */ s = energy_new(sig_in, l_trm, pOverflow); /* function result */ if (s == 0) { g0 = 0; } else { i = norm_l(s); /* L_temp = L_shl(s, i, pOverflow); */ L_temp = s << i; gain_in = pv_round(L_temp, pOverflow); exp -= i; /*---------------------------------------------------* * g0 = (1-agc_fac) * sqrt(gain_in/gain_out); * *---------------------------------------------------*/ /* s = gain_out / gain_in */ temp = div_s(gain_out, gain_in); /* s = L_deposit_l (temp); */ s = (Word32) temp; s = s << 7; s = L_shr(s, exp, pOverflow); /* add exponent */ s = Inv_sqrt(s, pOverflow); /* function result */ L_temp = s << 9; i = (Word16)((L_temp + (Word32) 0x00008000L) >> 16); /* g0 = i * (1-agc_fac) */ temp = 32767 - agc_fac; g0 = (Word16)(((Word32) i * temp) >> 15); } /* 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; p_sig_out = sig_out; for (i = 0; i < l_trm; i++) { /* gain = mult (gain, agc_fac, pOverflow); */ gain = (Word16)(((Word32) gain * agc_fac) >> 15); /* gain = add (gain, g0, pOverflow); */ gain += g0; /* L_temp = L_mult (sig_out[i], gain, pOverflow); */ L_temp = ((Word32)(*(p_sig_out)) * gain) << 1; *(p_sig_out++) = (Word16)(L_temp >> 13); } st->past_gain = gain; return; } /*--------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------------ FUNCTION NAME: agc2 ------------------------------------------------------------------------------ INPUT AND OUTPUT DEFINITIONS Inputs: sig_in = pointer to a buffer containing the postfilter input signal sig_out = pointer to a buffer containing the postfilter output signal l_trm = subframe size pOverflow = pointer to overflow flag Outputs: sig_out points to a buffer containing the new scaled output signal. pOverflow -> 1 if the agc computation saturates Returns: None. Global Variables Used: None. Local Variables Needed: None. ------------------------------------------------------------------------------ FUNCTION DESCRIPTION Scales the excitation on a subframe basis. ------------------------------------------------------------------------------ REQUIREMENTS None. ------------------------------------------------------------------------------ REFERENCES agc.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 ------------------------------------------------------------------------------ PSEUDO-CODE 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); // function result if (s == 0) { return; } exp = sub (norm_l (s), 1); gain_out = pv_round (L_shl (s, exp)); // calculate gain_in with exponent s = energy_new(sig_in, l_trm); // function result if (s == 0) { g0 = 0; } else { i = norm_l (s); gain_in = pv_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); // function result g0 = pv_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)); } return; } ------------------------------------------------------------------------------ RESOURCES USED [optional] When the code is written for a specific target processor the the resources used should be documented below. HEAP MEMORY USED: x bytes STACK MEMORY USED: x bytes CLOCK CYCLES: (cycle count equation for this function) + (variable used to represent cycle count for each subroutine called) where: (cycle count variable) = cycle count for [subroutine name] ------------------------------------------------------------------------------ CAUTION [optional] [State any special notes, constraints or cautions for users of this function] ------------------------------------------------------------------------------ */ void agc2( Word16 *sig_in, /* i : postfilter input signal */ Word16 *sig_out, /* i/o : postfilter output signal */ Word16 l_trm, /* i : subframe size */ Flag *pOverflow /* i : overflow flag */ ) { Word16 i; Word16 exp; Word16 gain_in; Word16 gain_out; Word16 g0; Word32 s; Word32 L_temp; Word16 temp; /* calculate gain_out with exponent */ s = energy_new(sig_out, l_trm, pOverflow); /* function result */ if (s == 0) { return; } exp = norm_l(s) - 1; L_temp = L_shl(s, exp, pOverflow); gain_out = pv_round(L_temp, pOverflow); /* calculate gain_in with exponent */ s = energy_new(sig_in, l_trm, pOverflow); /* function result */ if (s == 0) { g0 = 0; } else { i = norm_l(s); L_temp = L_shl(s, i, pOverflow); gain_in = pv_round(L_temp, pOverflow); exp -= i; /*---------------------------------------------------* * g0 = sqrt(gain_in/gain_out); * *---------------------------------------------------*/ /* s = gain_out / gain_in */ temp = div_s(gain_out, gain_in); /* s = L_deposit_l (temp); */ s = (Word32)temp; if (s > (Word32) 0x00FFFFFFL) { s = MAX_32; } else if (s < (Word32) 0xFF000000L) { s = MIN_32; } else { s = s << 7; } s = L_shr(s, exp, pOverflow); /* add exponent */ s = Inv_sqrt(s, pOverflow); /* function result */ if (s > (Word32) 0x003FFFFFL) { L_temp = MAX_32; } else if (s < (Word32) 0xFFC00000L) { L_temp = MIN_32; } else { L_temp = s << 9; } g0 = pv_round(L_temp, pOverflow); } /* sig_out(n) = gain(n) sig_out(n) */ for (i = l_trm - 1; i >= 0; i--) { L_temp = L_mult(sig_out[i], g0, pOverflow); if (L_temp > (Word32) 0x0FFFFFFFL) { sig_out[i] = MAX_16; } else if (L_temp < (Word32) 0xF0000000L) { sig_out[i] = MIN_16; } else { sig_out[i] = (Word16)(L_temp >> 13); } } return; }