diff options
author | Andreas Huber <andih@google.com> | 2009-12-08 15:40:06 -0800 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2009-12-10 12:23:55 -0800 |
commit | 4f1efc098cb5791c3e9f483f2af84aef70d2d0a0 (patch) | |
tree | a2873e84aed3eecb1198f85954e24cddb1bdc380 /media/libstagefright/codecs/amrnb/common/src/gc_pred.cpp | |
parent | c54176addef15699a518b69cd6bbd40ffc95e72e (diff) | |
download | frameworks_av-4f1efc098cb5791c3e9f483f2af84aef70d2d0a0.zip frameworks_av-4f1efc098cb5791c3e9f483f2af84aef70d2d0a0.tar.gz frameworks_av-4f1efc098cb5791c3e9f483f2af84aef70d2d0a0.tar.bz2 |
Initial check in of AMR (NB and WB) decoders based on PV source code.
Diffstat (limited to 'media/libstagefright/codecs/amrnb/common/src/gc_pred.cpp')
-rw-r--r-- | media/libstagefright/codecs/amrnb/common/src/gc_pred.cpp | 1046 |
1 files changed, 1046 insertions, 0 deletions
diff --git a/media/libstagefright/codecs/amrnb/common/src/gc_pred.cpp b/media/libstagefright/codecs/amrnb/common/src/gc_pred.cpp new file mode 100644 index 0000000..3650f3c --- /dev/null +++ b/media/libstagefright/codecs/amrnb/common/src/gc_pred.cpp @@ -0,0 +1,1046 @@ +/* ------------------------------------------------------------------ + * 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/gc_pred.c + Functions: + gc_pred_reset + gc_pred + gc_pred_update + gc_pred_average_limited + +------------------------------------------------------------------------------ + MODULE DESCRIPTION + + This file contains the functions that perform codebook gain MA prediction. + +------------------------------------------------------------------------------ +*/ + +/*---------------------------------------------------------------------------- +; INCLUDES +----------------------------------------------------------------------------*/ +#include "gc_pred.h" +#include "basicop_malloc.h" +#include "basic_op.h" +#include "cnst.h" +#include "log2.h" + +/*---------------------------------------------------------------------------- +; MACROS +; Define module specific macros here +----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- +; DEFINES +; Include all pre-processor statements here. Include conditional +; compile variables also. +----------------------------------------------------------------------------*/ +#define NPRED 4 /* number of prediction taps */ + +/* average innovation energy. */ +/* MEAN_ENER = 36.0/constant, constant = 20*Log10(2) */ +#define MEAN_ENER_MR122 783741L /* 36/(20*log10(2)) (Q17) */ + +/* minimum quantized energy: -14 dB */ +#define MIN_ENERGY -14336 /* 14 Q10 */ +#define MIN_ENERGY_MR122 -2381 /* 14 / (20*log10(2)) Q10 */ + +/*---------------------------------------------------------------------------- +; LOCAL FUNCTION DEFINITIONS +; Function Prototype declaration +----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- +; LOCAL VARIABLE DEFINITIONS +; Variable declaration - defined here and used outside this module +----------------------------------------------------------------------------*/ + +/* MA prediction coefficients (Q13) */ +static const Word16 pred[NPRED] = {5571, 4751, 2785, 1556}; + +/* MA prediction coefficients (Q6) */ +static const Word16 pred_MR122[NPRED] = {44, 37, 22, 12}; + +/* +------------------------------------------------------------------------------ + FUNCTION NAME: gc_pred_reset +------------------------------------------------------------------------------ + INPUT AND OUTPUT DEFINITIONS + + Inputs: + state = pointer to a structure of type gc_predState + + Outputs: + past_qua_en field in the structure pointed to by state is initialized + to MIN_ENERGY + past_qua_en_MR122 field in the structure pointed to by state is + initialized to MIN_ENERGY_MR122 + + Returns: + return_value = 0, if reset was successful; -1, otherwise (int) + + Global Variables Used: + None + + Local Variables Needed: + None + +------------------------------------------------------------------------------ + FUNCTION DESCRIPTION + + This function initializes the state memory used by gc_pred to zero. + +------------------------------------------------------------------------------ + REQUIREMENTS + + None + +------------------------------------------------------------------------------ + REFERENCES + + gc_pred.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 + +------------------------------------------------------------------------------ + PSEUDO-CODE + +int gc_pred_reset (gc_predState *state) +{ + Word16 i; + + if (state == (gc_predState *) NULL){ + fprintf(stderr, "gc_pred_reset: invalid parameter\n"); + return -1; + } + + for(i = 0; i < NPRED; i++) + { + state->past_qua_en[i] = MIN_ENERGY; + state->past_qua_en_MR122[i] = MIN_ENERGY_MR122; + } + 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 gc_pred_reset(gc_predState *state) +{ + Word16 i; + + if (state == (gc_predState *) NULL) + { + /* fprintf(stderr, "gc_pred_reset: invalid parameter\n"); */ + return -1; + } + + for (i = 0; i < NPRED; i++) + { + state->past_qua_en[i] = MIN_ENERGY; + state->past_qua_en_MR122[i] = MIN_ENERGY_MR122; + } + + return(0); +} + +/****************************************************************************/ + +/* +------------------------------------------------------------------------------ + FUNCTION NAME: gc_pred +------------------------------------------------------------------------------ + INPUT AND OUTPUT DEFINITIONS + + Inputs: + st = pointer to a structure of type gc_predState + mode = AMR mode (enum Mode) + code = pointer to the innovative codebook vector; Q12 in MR122 mode, + otherwise, Q13 (Word16) + exp_gcode0 = pointer to the exponent part of predicted gain factor + (Q0) (Word16) + frac_gcode0 = pointer to the fractional part of predicted gain factor + (Q15) (Word16) + exp_en = pointer to the exponent part of the innovation energy; this + is calculated for MR795 mode, Q0 (Word16) + frac_en = pointer to the fractional part of the innovation energy; + this is calculated for MR795 mode, Q15 (Word16) + pOverflow = pointer to overflow (Flag) + + Outputs: + store pointed to by exp_gcode0 contains the exponent part of the + recently calculated predicted gain factor + store pointed to by frac_gcode0 contains the fractional part of the + recently calculated predicted gain factor + store pointed to by exp_en contains the exponent part of the + recently calculated innovation energy + store pointed to by frac_en contains the fractional part of the + recently calculated innovation energy + pOverflow = 1 if the math functions called by gc_pred + results in overflow else zero. + + Returns: + None + + Global Variables Used: + None + + Local Variables Needed: + pred = table of MA prediction coefficients (Q13) (Word16) + pred_MR122 = table of MA prediction coefficients (Q6) (Word16) + +------------------------------------------------------------------------------ + FUNCTION DESCRIPTION + + This function performs the MA prediction of the innovation energy (in + dB/(20*log10(2))), with the mean removed. + +------------------------------------------------------------------------------ + REQUIREMENTS + + None + +------------------------------------------------------------------------------ + REFERENCES + + gc_pred.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 + +------------------------------------------------------------------------------ + PSEUDO-CODE + +The original etsi reference code uses a global flag Overflow. However, in the +actual implementation a pointer to a the overflow flag is passed in. + +void +gc_pred( + gc_predState *st, // i/o: State struct + enum Mode mode, // i : AMR mode + Word16 *code, // i : innovative codebook vector (L_SUBFR) + // MR122: Q12, other modes: Q13 + Word16 *exp_gcode0, // o : exponent of predicted gain factor, Q0 + Word16 *frac_gcode0,// o : fraction of predicted gain factor Q15 + Word16 *exp_en, // o : exponent of innovation energy, Q0 + // (only calculated for MR795) + Word16 *frac_en // o : fraction of innovation energy, Q15 + // (only calculated for MR795) +) +{ + Word16 i; + Word32 ener_code; + Word16 exp, frac; + + *-------------------------------------------------------------------* + * energy of code: * + * ~~~~~~~~~~~~~~~ * + * ener_code = sum(code[i]^2) * + *-------------------------------------------------------------------* + ener_code = L_mac((Word32) 0, code[0], code[0]); + // MR122: Q12*Q12 -> Q25 + // others: Q13*Q13 -> Q27 + for (i = 1; i < L_SUBFR; i++) + ener_code = L_mac(ener_code, code[i], code[i]); + + if (sub (mode, MR122) == 0) + { + Word32 ener; + + // ener_code = ener_code / lcode; lcode = 40; 1/40 = 26214 Q20 + ener_code = L_mult (pv_round (ener_code), 26214); // Q9 * Q20 -> Q30 + + *-------------------------------------------------------------------* + * energy of code: * + * ~~~~~~~~~~~~~~~ * + * ener_code(Q17) = 10 * Log10(energy) / constant * + * = 1/2 * Log2(energy) * + * constant = 20*Log10(2) * + *-------------------------------------------------------------------* + // ener_code = 1/2 * Log2(ener_code); Note: Log2=log2+30 + Log2(ener_code, &exp, &frac); + ener_code = L_Comp (sub (exp, 30), frac); // Q16 for log() + // ->Q17 for 1/2 log() + + *-------------------------------------------------------------------* + * predicted energy: * + * ~~~~~~~~~~~~~~~~~ * + * ener(Q24) = (Emean + sum{pred[i]*past_en[i]})/constant * + * = MEAN_ENER + sum(pred[i]*past_qua_en[i]) * + * constant = 20*Log10(2) * + *-------------------------------------------------------------------* + + ener = MEAN_ENER_MR122; // Q24 (Q17) + for (i = 0; i < NPRED; i++) + { + ener = L_mac (ener, st->past_qua_en_MR122[i], pred_MR122[i]); + // Q10 * Q13 -> Q24 + // Q10 * Q6 -> Q17 + } + + *-------------------------------------------------------------------* + * predicted codebook gain * + * ~~~~~~~~~~~~~~~~~~~~~~~ * + * gc0 = Pow10( (ener*constant - ener_code*constant) / 20 ) * + * = Pow2(ener-ener_code) * + * = Pow2(int(d)+frac(d)) * + * * + * (store exp and frac for pow2()) * + *-------------------------------------------------------------------* + + ener = L_shr (L_sub (ener, ener_code), 1); // Q16 + L_Extract(ener, exp_gcode0, frac_gcode0); + } + else // all modes except 12.2 + { + Word32 L_tmp; + Word16 exp_code, gcode0; + + *-----------------------------------------------------------------* + * Compute: means_ener - 10log10(ener_code/ L_sufr) * + *-----------------------------------------------------------------* + + exp_code = norm_l (ener_code); + ener_code = L_shl (ener_code, exp_code); + + // Log2 = log2 + 27 + Log2_norm (ener_code, exp_code, &exp, &frac); + + // fact = 10/log2(10) = 3.01 = 24660 Q13 + L_tmp = Mpy_32_16(exp, frac, -24660); // Q0.Q15 * Q13 -> Q14 + + * L_tmp = means_ener - 10log10(ener_code/L_SUBFR) + * = means_ener - 10log10(ener_code) + 10log10(L_SUBFR) + * = K - fact * Log2(ener_code) + * = K - fact * log2(ener_code) - fact*27 + * + * ==> K = means_ener + fact*27 + 10log10(L_SUBFR) + * + * means_ener = 33 = 540672 Q14 (MR475, MR515, MR59) + * means_ener = 28.75 = 471040 Q14 (MR67) + * means_ener = 30 = 491520 Q14 (MR74) + * means_ener = 36 = 589824 Q14 (MR795) + * means_ener = 33 = 540672 Q14 (MR102) + * 10log10(L_SUBFR) = 16.02 = 262481.51 Q14 + * fact * 27 = 1331640 Q14 + * ----------------------------------------- + * (MR475, MR515, MR59) K = 2134793.51 Q14 ~= 16678 * 64 * 2 + * (MR67) K = 2065161.51 Q14 ~= 32268 * 32 * 2 + * (MR74) K = 2085641.51 Q14 ~= 32588 * 32 * 2 + * (MR795) K = 2183945.51 Q14 ~= 17062 * 64 * 2 + * (MR102) K = 2134793.51 Q14 ~= 16678 * 64 * 2 + + + if (sub (mode, MR102) == 0) + { + // mean = 33 dB + L_tmp = L_mac(L_tmp, 16678, 64); // Q14 + } + else if (sub (mode, MR795) == 0) + { + // ener_code = <xn xn> * 2^27*2^exp_code + // frac_en = ener_code / 2^16 + // = <xn xn> * 2^11*2^exp_code + // <xn xn> = <xn xn>*2^11*2^exp * 2^exp_en + // := frac_en * 2^exp_en + + // ==> exp_en = -11-exp_code; + + *frac_en = extract_h (ener_code); + *exp_en = sub (-11, exp_code); + + // mean = 36 dB + L_tmp = L_mac(L_tmp, 17062, 64); // Q14 + } + else if (sub (mode, MR74) == 0) + { + // mean = 30 dB + L_tmp = L_mac(L_tmp, 32588, 32); // Q14 + } + else if (sub (mode, MR67) == 0) + { + // mean = 28.75 dB + L_tmp = L_mac(L_tmp, 32268, 32); // Q14 + } + else // MR59, MR515, MR475 + { + // mean = 33 dB + L_tmp = L_mac(L_tmp, 16678, 64); // Q14 + } + + *-----------------------------------------------------------------* + * Compute gcode0. * + * = Sum(i=0,3) pred[i]*past_qua_en[i] - ener_code + mean_ener * + *-----------------------------------------------------------------* + + L_tmp = L_shl(L_tmp, 10); // Q24 + for (i = 0; i < 4; i++) + L_tmp = L_mac(L_tmp, pred[i], st->past_qua_en[i]); + // Q13 * Q10 -> Q24 + + gcode0 = extract_h(L_tmp); // Q8 + + *-----------------------------------------------------------------* + * gcode0 = pow(10.0, gcode0/20) * + * = pow(2, 3.3219*gcode0/20) * + * = pow(2, 0.166*gcode0) * + *-----------------------------------------------------------------* + + // 5439 Q15 = 0.165985 + // (correct: 1/(20*log10(2)) 0.166096 = 5443 Q15) + if (sub (mode, MR74) == 0) // For IS641 bitexactness + L_tmp = L_mult(gcode0, 5439); // Q8 * Q15 -> Q24 + else + L_tmp = L_mult(gcode0, 5443); // Q8 * Q15 -> Q24 + + L_tmp = L_shr(L_tmp, 8); // -> Q16 + L_Extract(L_tmp, exp_gcode0, frac_gcode0); // -> Q0.Q15 + } +} + +------------------------------------------------------------------------------ + 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 gc_pred( + gc_predState *st, /* i/o: State struct */ + enum Mode mode, /* i : AMR mode */ + Word16 *code, /* i : innovative codebook vector (L_SUBFR) */ + /* MR122: Q12, other modes: Q13 */ + Word16 *exp_gcode0, /* o : exponent of predicted gain factor, Q0 */ + Word16 *frac_gcode0,/* o : fraction of predicted gain factor Q15 */ + Word16 *exp_en, /* o : exponent of innovation energy, Q0 */ + /* (only calculated for MR795) */ + Word16 *frac_en, /* o : fraction of innovation energy, Q15 */ + /* (only calculated for MR795) */ + Flag *pOverflow +) +{ + register Word16 i; + register Word32 L_temp1, L_temp2; + register Word32 L_tmp; + Word32 ener_code; + Word32 ener; + Word16 exp, frac; + Word16 exp_code, gcode0; + Word16 tmp; + Word16 *p_code = &code[0]; + + /*-------------------------------------------------------------------* + * energy of code: * + * ~~~~~~~~~~~~~~~ * + * ener_code = sum(code[i]^2) * + *-------------------------------------------------------------------*/ + ener_code = 0; + + /* MR122: Q12*Q12 -> Q25 */ + /* others: Q13*Q13 -> Q27 */ + + for (i = L_SUBFR >> 2; i != 0; i--) + { + tmp = *(p_code++); + ener_code += ((Word32) tmp * tmp) >> 3; + tmp = *(p_code++); + ener_code += ((Word32) tmp * tmp) >> 3; + tmp = *(p_code++); + ener_code += ((Word32) tmp * tmp) >> 3; + tmp = *(p_code++); + ener_code += ((Word32) tmp * tmp) >> 3; + } + + ener_code <<= 4; + + if (ener_code < 0) /* Check for saturation */ + { + ener_code = MAX_32; + } + + if (mode == MR122) + { + /* ener_code = ener_code / lcode; lcode = 40; 1/40 = 26214 Q20 */ + /* Q9 * Q20 -> Q30 */ + + ener_code = ((Word32)(pv_round(ener_code, pOverflow) * 26214)) << 1; + + /*-------------------------------------------------------------* + * energy of code: * + * ~~~~~~~~~~~~~~~ * + * ener_code(Q17) = 10 * Log10(energy) / constant * + * = 1/2 * Log2(energy) * + * constant = 20*Log10(2) * + *-------------------------------------------------------------*/ + /* ener_code = 1/2 * Log2(ener_code); Note: Log2=log2+30 */ + Log2(ener_code, &exp, &frac, pOverflow); + + /* Q16 for log() */ + /* ->Q17 for 1/2 log()*/ + + L_temp1 = (Word32)(exp - 30) << 16; + ener_code = L_temp1 + ((Word32)frac << 1); + + /*-------------------------------------------------------------* + * predicted energy: * + * ~~~~~~~~~~~~~~~~~ * + * ener(Q24) = (Emean + sum{pred[i]*past_en[i]})/constant * + * = MEAN_ENER + sum(pred[i]*past_qua_en[i]) * + * constant = 20*Log10(2) * + *-------------------------------------------------------------*/ + + ener = MEAN_ENER_MR122; /* Q24 (Q17) */ + for (i = 0; i < NPRED; i++) + { + L_temp1 = (((Word32) st->past_qua_en_MR122[i]) * + pred_MR122[i]) << 1; + ener = L_add(ener, L_temp1, pOverflow); + + /* Q10 * Q13 -> Q24 */ + /* Q10 * Q6 -> Q17 */ + } + + /*---------------------------------------------------------------* + * predicted codebook gain * + * ~~~~~~~~~~~~~~~~~~~~~~~ * + * gc0 = Pow10( (ener*constant - ener_code*constant) / 20 ) * + * = Pow2(ener-ener_code) * + * = Pow2(int(d)+frac(d)) * + * * + * (store exp and frac for pow2()) * + *---------------------------------------------------------------*/ + /* Q16 */ + + L_temp1 = L_sub(ener, ener_code, pOverflow); + + + *exp_gcode0 = (Word16)(L_temp1 >> 17); + + L_temp2 = (Word32) * exp_gcode0 << 15; + L_temp1 >>= 2; + + *frac_gcode0 = (Word16)(L_temp1 - L_temp2); + + } + else /* all modes except 12.2 */ + { + /*-----------------------------------------------------------------* + * Compute: means_ener - 10log10(ener_code/ L_sufr) * + *-----------------------------------------------------------------*/ + + exp_code = norm_l(ener_code); + ener_code = L_shl(ener_code, exp_code, pOverflow); + + /* Log2 = log2 + 27 */ + Log2_norm(ener_code, exp_code, &exp, &frac); + + /* fact = 10/log2(10) = 3.01 = 24660 Q13 */ + /* Q0.Q15 * Q13 -> Q14 */ + + L_temp2 = (((Word32) exp) * -24660) << 1; + L_tmp = (((Word32) frac) * -24660) >> 15; + + /* Sign-extend resulting product */ + if (L_tmp & (Word32) 0x00010000L) + { + L_tmp = L_tmp | (Word32) 0xffff0000L; + } + + L_tmp = L_tmp << 1; + L_tmp = L_add(L_tmp, L_temp2, pOverflow); + + + /* L_tmp = means_ener - 10log10(ener_code/L_SUBFR) + * = means_ener - 10log10(ener_code) + 10log10(L_SUBFR) + * = K - fact * Log2(ener_code) + * = K - fact * log2(ener_code) - fact*27 + * + * ==> K = means_ener + fact*27 + 10log10(L_SUBFR) + * + * means_ener = 33 = 540672 Q14 (MR475, MR515, MR59) + * means_ener = 28.75 = 471040 Q14 (MR67) + * means_ener = 30 = 491520 Q14 (MR74) + * means_ener = 36 = 589824 Q14 (MR795) + * means_ener = 33 = 540672 Q14 (MR102) + * 10log10(L_SUBFR) = 16.02 = 262481.51 Q14 + * fact * 27 = 1331640 Q14 + * ----------------------------------------- + * (MR475, MR515, MR59) K = 2134793.51 Q14 ~= 16678 * 64 * 2 + * (MR67) K = 2065161.51 Q14 ~= 32268 * 32 * 2 + * (MR74) K = 2085641.51 Q14 ~= 32588 * 32 * 2 + * (MR795) K = 2183945.51 Q14 ~= 17062 * 64 * 2 + * (MR102) K = 2134793.51 Q14 ~= 16678 * 64 * 2 + */ + + if (mode == MR102) + { + /* mean = 33 dB */ + L_temp2 = (Word32) 16678 << 7; + L_tmp = L_add(L_tmp, L_temp2, pOverflow); /* Q14 */ + } + else if (mode == MR795) + { + /* ener_code = <xn xn> * 2^27*2^exp_code + frac_en = ener_code / 2^16 + = <xn xn> * 2^11*2^exp_code + <xn xn> = <xn xn>*2^11*2^exp * 2^exp_en + : = frac_en * 2^exp_en + ==> exp_en = -11-exp_code; */ + *frac_en = (Word16)(ener_code >> 16); + *exp_en = sub(-11, exp_code, pOverflow); + + /* mean = 36 dB */ + L_temp2 = (Word32) 17062 << 7; + L_tmp = L_add(L_tmp, L_temp2, pOverflow); /* Q14 */ + } + else if (mode == MR74) + { + /* mean = 30 dB */ + L_temp2 = (Word32) 32588 << 6; + L_tmp = L_add(L_tmp, L_temp2, pOverflow); /* Q14 */ + } + else if (mode == MR67) + { + /* mean = 28.75 dB */ + L_temp2 = (Word32) 32268 << 6; + L_tmp = L_add(L_tmp, L_temp2, pOverflow); /* Q14 */ + } + else /* MR59, MR515, MR475 */ + { + /* mean = 33 dB */ + L_temp2 = (Word32) 16678 << 7; + L_tmp = L_add(L_tmp, L_temp2, pOverflow); /* Q14 */ + } + + /*-------------------------------------------------------------* + * Compute gcode0. * + * = Sum(i=0,3) pred[i]*past_qua_en[i] - ener_code + mean_ener * + *--------------------------------------------------------------*/ + /* Q24 */ + if (L_tmp > (Word32) 0X001fffffL) + { + *pOverflow = 1; + L_tmp = MAX_32; + } + else if (L_tmp < (Word32) 0xffe00000L) + { + *pOverflow = 1; + L_tmp = MIN_32; + } + else + { + L_tmp = L_tmp << 10; + } + + for (i = 0; i < 4; i++) + { + L_temp2 = ((((Word32) pred[i]) * st->past_qua_en[i]) << 1); + L_tmp = L_add(L_tmp, L_temp2, pOverflow); /* Q13 * Q10 -> Q24 */ + } + + gcode0 = (Word16)(L_tmp >> 16); /* Q8 */ + + /*-----------------------------------------------------------* + * gcode0 = pow(10.0, gcode0/20) * + * = pow(2, 3.3219*gcode0/20) * + * = pow(2, 0.166*gcode0) * + *-----------------------------------------------------------*/ + + /* 5439 Q15 = 0.165985 */ + /* (correct: 1/(20*log10(2)) 0.166096 = 5443 Q15) */ + + if (mode == MR74) /* For IS641 bitexactness */ + { + L_tmp = (((Word32) gcode0) * 5439) << 1; /* Q8 * Q15 -> Q24 */ + } + else + { + L_tmp = (((Word32) gcode0) * 5443) << 1; /* Q8 * Q15 -> Q24 */ + } + + if (L_tmp < 0) + { + L_tmp = ~((~L_tmp) >> 8); + } + else + { + L_tmp = L_tmp >> 8; /* -> Q16 */ + } + + *exp_gcode0 = (Word16)(L_tmp >> 16); + if (L_tmp < 0) + { + L_temp1 = ~((~L_tmp) >> 1); + } + else + { + L_temp1 = L_tmp >> 1; + } + L_temp2 = (Word32) * exp_gcode0 << 15; + *frac_gcode0 = (Word16)(L_sub(L_temp1, L_temp2, pOverflow)); + /* -> Q0.Q15 */ + } + + return; +} + +/****************************************************************************/ + +/* +------------------------------------------------------------------------------ + FUNCTION NAME: gc_pred_update +------------------------------------------------------------------------------ + INPUT AND OUTPUT DEFINITIONS + + Inputs: + st = pointer to a structure of type gc_predState + qua_ener_MR122 = quantized energy for update (Q10); calculated as + (log2(qua_err)) (Word16) + qua_ener = quantized energy for update (Q10); calculated as + (20*log10(qua_err)) (Word16) + + Outputs: + structure pointed to by st contains the calculated quantized energy + for update + + Returns: + None + + Global Variables Used: + None + + Local Variables Needed: + None + +------------------------------------------------------------------------------ + FUNCTION DESCRIPTION + + This function updates the MA predictor with the last quantized energy. + +------------------------------------------------------------------------------ + REQUIREMENTS + + None + +------------------------------------------------------------------------------ + REFERENCES + + gc_pred.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 + +------------------------------------------------------------------------------ + PSEUDO-CODE + +void gc_pred_update( + gc_predState *st, // i/o: State struct + Word16 qua_ener_MR122, // i : quantized energy for update, Q10 + // (log2(qua_err)) + Word16 qua_ener // i : quantized energy for update, Q10 + // (20*log10(qua_err)) +) +{ + Word16 i; + + for (i = 3; i > 0; i--) + { + st->past_qua_en[i] = st->past_qua_en[i - 1]; + st->past_qua_en_MR122[i] = st->past_qua_en_MR122[i - 1]; + } + + st->past_qua_en_MR122[0] = qua_ener_MR122; // log2 (qua_err), Q10 + + st->past_qua_en[0] = qua_ener; // 20*log10(qua_err), Q10 + +} + +------------------------------------------------------------------------------ + 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 gc_pred_update( + gc_predState *st, /* i/o: State struct */ + Word16 qua_ener_MR122, /* i : quantized energy for update, Q10 */ + /* (log2(qua_err)) */ + Word16 qua_ener /* i : quantized energy for update, Q10 */ + /* (20*log10(qua_err)) */ +) +{ + st->past_qua_en[3] = st->past_qua_en[2]; + st->past_qua_en_MR122[3] = st->past_qua_en_MR122[2]; + + st->past_qua_en[2] = st->past_qua_en[1]; + st->past_qua_en_MR122[2] = st->past_qua_en_MR122[1]; + + st->past_qua_en[1] = st->past_qua_en[0]; + st->past_qua_en_MR122[1] = st->past_qua_en_MR122[0]; + + st->past_qua_en_MR122[0] = qua_ener_MR122; /* log2 (qua_err), Q10 */ + + st->past_qua_en[0] = qua_ener; /* 20*log10(qua_err), Q10 */ + + return; +} + +/****************************************************************************/ + +/* +------------------------------------------------------------------------------ + FUNCTION NAME: gc_pred_average_limited +------------------------------------------------------------------------------ + INPUT AND OUTPUT DEFINITIONS + + Inputs: + st = pointer to a structure of type gc_predState + ener_avg_MR122 = pointer to the averaged quantized energy (Q10); + calculated as (log2(qua_err)) (Word16) + ener_avg = pointer to the averaged quantized energy (Q10); calculated + as (20*log10(qua_err)) (Word16) + pOverflow = pointer to overflow (Flag) + + Outputs: + store pointed to by ener_avg_MR122 contains the new averaged quantized + energy + store pointed to by ener_avg contains the new averaged quantized + energy + pOverflow = 1 if the math functions called by gc_pred_average_limited + results in overflow else zero. + + Returns: + None + + Global Variables Used: + None + + Local Variables Needed: + None + +------------------------------------------------------------------------------ + FUNCTION DESCRIPTION + + This function calculates the average of MA predictor state values (with a + lower limit) used in error concealment. + +------------------------------------------------------------------------------ + REQUIREMENTS + + None + +------------------------------------------------------------------------------ + REFERENCES + + gc_pred.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 + +------------------------------------------------------------------------------ + PSEUDO-CODE + +The original etsi reference code uses a global flag Overflow. However, in the +actual implementation a pointer to a the overflow flag is passed in. + +void gc_pred_average_limited( + gc_predState *st, // i: State struct + Word16 *ener_avg_MR122, // o: everaged quantized energy, Q10 + // (log2(qua_err)) + Word16 *ener_avg // o: averaged quantized energy, Q10 + // (20*log10(qua_err)) +) +{ + Word16 av_pred_en; + Word16 i; + + // do average in MR122 mode (log2() domain) + av_pred_en = 0; + for (i = 0; i < NPRED; i++) + { + av_pred_en = add (av_pred_en, st->past_qua_en_MR122[i]); + } + + // av_pred_en = 0.25*av_pred_en + av_pred_en = mult (av_pred_en, 8192); + + // if (av_pred_en < -14/(20Log10(2))) av_pred_en = .. + + if (sub (av_pred_en, MIN_ENERGY_MR122) < 0) + { + av_pred_en = MIN_ENERGY_MR122; + } + *ener_avg_MR122 = av_pred_en; + + // do average for other modes (20*log10() domain) + av_pred_en = 0; + for (i = 0; i < NPRED; i++) + { + av_pred_en = add (av_pred_en, st->past_qua_en[i]); + } + + // av_pred_en = 0.25*av_pred_en + av_pred_en = mult (av_pred_en, 8192); + + // if (av_pred_en < -14) av_pred_en = .. + + if (sub (av_pred_en, MIN_ENERGY) < 0) + { + av_pred_en = MIN_ENERGY; + } + *ener_avg = av_pred_en; +} + +------------------------------------------------------------------------------ + 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 gc_pred_average_limited( + gc_predState *st, /* i: State struct */ + Word16 *ener_avg_MR122, /* o: everaged quantized energy, Q10 */ + /* (log2(qua_err)) */ + Word16 *ener_avg, /* o: averaged quantized energy, Q10 */ + /* (20*log10(qua_err)) */ + Flag *pOverflow +) +{ + Word16 av_pred_en; + register Word16 i; + + /* do average in MR122 mode (log2() domain) */ + av_pred_en = 0; + for (i = 0; i < NPRED; i++) + { + av_pred_en = + add(av_pred_en, st->past_qua_en_MR122[i], pOverflow); + } + + /* av_pred_en = 0.25*av_pred_en (with sign-extension)*/ + if (av_pred_en < 0) + { + av_pred_en = (av_pred_en >> 2) | 0xc000; + } + else + { + av_pred_en >>= 2; + } + + /* if (av_pred_en < -14/(20Log10(2))) av_pred_en = .. */ + if (av_pred_en < MIN_ENERGY_MR122) + { + av_pred_en = MIN_ENERGY_MR122; + } + *ener_avg_MR122 = av_pred_en; + + /* do average for other modes (20*log10() domain) */ + av_pred_en = 0; + for (i = 0; i < NPRED; i++) + { + av_pred_en = add(av_pred_en, st->past_qua_en[i], pOverflow); + } + + /* av_pred_en = 0.25*av_pred_en (with sign-extension)*/ + if (av_pred_en < 0) + { + av_pred_en = (av_pred_en >> 2) | 0xc000; + } + else + { + av_pred_en >>= 2; + } + + /* if (av_pred_en < -14) av_pred_en = .. */ + if (av_pred_en < MIN_ENERGY) + { + av_pred_en = MIN_ENERGY; + } + *ener_avg = av_pred_en; +} |