| /* ------------------------------------------------------------------ |
| * 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 |
| ) |
| { |
| Word16 i; |
| Word32 L_temp1, L_temp2; |
| 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; |
| 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; |
| } |