/* * The decimation-in-time complex FFT is implemented below. * The input complex numbers are presented as real part followed by * imaginary part for each sample. The counters are therefore * incremented by two to access the complex valued samples. */ void r_fft(Word16 * farray_ptr, Flag *pOverflow) { Word16 ftmp1_real; Word16 ftmp1_imag; Word16 ftmp2_real; Word16 ftmp2_imag; Word32 Lftmp1_real; Word32 Lftmp1_imag; Word16 i; Word16 j; Word32 Ltmp1; /* Perform the complex FFT */ c_fft(farray_ptr, pOverflow); /* First, handle the DC and foldover frequencies */ ftmp1_real = *farray_ptr; ftmp2_real = *(farray_ptr + 1); *farray_ptr = add(ftmp1_real, ftmp2_real, pOverflow); *(farray_ptr + 1) = sub(ftmp1_real, ftmp2_real, pOverflow); /* Now, handle the remaining positive frequencies */ for (i = 2, j = SIZE - i; i <= SIZE_BY_TWO; i = i + 2, j = SIZE - i) { ftmp1_real = add(*(farray_ptr + i), *(farray_ptr + j), pOverflow); ftmp1_imag = sub(*(farray_ptr + i + 1), *(farray_ptr + j + 1), pOverflow); ftmp2_real = add(*(farray_ptr + i + 1), *(farray_ptr + j + 1), pOverflow); ftmp2_imag = sub(*(farray_ptr + j), *(farray_ptr + i), pOverflow); Lftmp1_real = L_deposit_h(ftmp1_real); Lftmp1_imag = L_deposit_h(ftmp1_imag); Ltmp1 = L_mac(Lftmp1_real, ftmp2_real, phs_tbl[i], pOverflow); Ltmp1 = L_msu(Ltmp1, ftmp2_imag, phs_tbl[i + 1], pOverflow); *(farray_ptr + i) = pv_round(L_shr(Ltmp1, 1, pOverflow), pOverflow); Ltmp1 = L_mac(Lftmp1_imag, ftmp2_imag, phs_tbl[i], pOverflow); Ltmp1 = L_mac(Ltmp1, ftmp2_real, phs_tbl[i + 1], pOverflow); *(farray_ptr + i + 1) = pv_round(L_shr(Ltmp1, 1, pOverflow), pOverflow); Ltmp1 = L_mac(Lftmp1_real, ftmp2_real, phs_tbl[j], pOverflow); Ltmp1 = L_mac(Ltmp1, ftmp2_imag, phs_tbl[j + 1], pOverflow); *(farray_ptr + j) = pv_round(L_shr(Ltmp1, 1, pOverflow), pOverflow); Ltmp1 = L_negate(Lftmp1_imag); Ltmp1 = L_msu(Ltmp1, ftmp2_imag, phs_tbl[j], pOverflow); Ltmp1 = L_mac(Ltmp1, ftmp2_real, phs_tbl[j + 1], pOverflow); *(farray_ptr + j + 1) = pv_round(L_shr(Ltmp1, 1, pOverflow), pOverflow); } } /* end r_fft () */
void Post_Process( Post_ProcessState *st, /* i/o : post process state */ Word16 signal[], /* i/o : signal */ Word16 lg, /* i : length of signal */ Flag *pOverflow ) { Word16 i, x2; Word32 L_tmp; Word16 *p_signal; Word16 c_a1 = a[1]; Word16 c_a2 = a[2]; Word16 c_b0 = b[0]; Word16 c_b1 = b[1]; Word16 c_b2 = b[2]; p_signal = &signal[0]; for (i = 0; i < lg; i++) { x2 = st->x1; st->x1 = st->x0; st->x0 = *(p_signal); /* y[i] = b[0]*x[i]*2 + b[1]*x[i-1]*2 + b140[2]*x[i-2]/2 */ /* + a[1]*y[i-1] + a[2] * y[i-2]; */ L_tmp = ((Word32) st->y1_hi) * c_a1; L_tmp += (((Word32) st->y1_lo) * c_a1) >> 15; L_tmp += ((Word32) st->y2_hi) * c_a2; L_tmp += (((Word32) st->y2_lo) * c_a2) >> 15; L_tmp += ((Word32) st->x0) * c_b0; L_tmp += ((Word32) st->x1) * c_b1; L_tmp += ((Word32) x2) * c_b2; L_tmp <<= 3; /* Multiplication by two of output speech with saturation. */ *(p_signal++) = pv_round(L_shl(L_tmp, 1, pOverflow), pOverflow); st->y2_hi = st->y1_hi; st->y2_lo = st->y1_lo; st->y1_hi = (Word16)(L_tmp >> 16); st->y1_lo = (Word16)((L_tmp >> 1) - ((Word32) st->y1_hi << 15)); } return; }
/* ------------------------------------------------------------------------------ FUNCTION NAME: build_code ------------------------------------------------------------------------------ INPUT AND OUTPUT DEFINITIONS Inputs: codvec, position of pulses, array of type Word16 dn_sign, sign of pulses, array of type Word16 h, impulse response of weighted synthesis filter, Word16 array Outputs: cod, innovative code vector, array of type Word16 y[], filtered innovative code, array of type Word16 sign[], sign of 2 pulses, array of type Word16 pOverflow, Flag set when overflow occurs, pointer of type Flag * Returns: Global Variables Used: None Local Variables Needed: None ------------------------------------------------------------------------------ FUNCTION DESCRIPTION Builds the codeword, the filtered codeword and index of the codevector, based on the signs and positions of 2 pulses. ------------------------------------------------------------------------------ REQUIREMENTS None ------------------------------------------------------------------------------ REFERENCES c2_11pf.c, UMTS GSM AMR speech codec, R99 - Version 3.2.0, March 2, 2001 ------------------------------------------------------------------------------ PSEUDO-CODE ------------------------------------------------------------------------------ CAUTION [optional] [State any special notes, constraints or cautions for users of this function] ------------------------------------------------------------------------------ */ static Word16 build_code( Word16 codvec[], /* i : position of pulses */ Word16 dn_sign[], /* i : sign of pulses */ Word16 cod[], /* o : innovative code vector */ Word16 h[], /* i : impulse response of weighted synthesis filter */ Word16 y[], /* o : filtered innovative code */ Word16 sign[], /* o : sign of 2 pulses */ Flag * pOverflow /* o : Flag set when overflow occurs */ ) { Word16 i; Word16 j; Word16 k; Word16 track; Word16 index; Word16 _sign[NB_PULSE]; Word16 indx; Word16 rsign; Word16 tempWord; Word16 *p0; Word16 *p1; Word32 s; for (i = 0; i < L_CODE; i++) { cod[i] = 0; } indx = 0; rsign = 0; for (k = 0; k < NB_PULSE; k++) { i = codvec[k]; /* read pulse position */ j = dn_sign[i]; /* read sign */ /* index = pos/5 */ /* index = mult(i, 6554, pOverflow); */ index = (Word16)(((Word32) i * 6554) >> 15); /* track = pos%5 */ /* tempWord = L_mult( index, 5, pOverflow); */ tempWord = (index << 3) + (index << 1); /* tempWord = L_shr( tempWord, 1, pOverflow); */ tempWord >>= 1; /* track = sub( i, tempWord, pOverflow); */ track = i - tempWord; tempWord = track; if (tempWord == 0) { track = 1; /* index = shl( index, 6, pOverflow); */ index <<= 6; } else if (track == 1) { tempWord = k; if (tempWord == 0) { track = 0; /* index = shl( index, 1, pOverflow); */ index <<= 1; } else { track = 1; /* tempWord = shl( index, 6, pOverflow); */ tempWord = index << 6; /* index = add( tempWord, 16, pOverflow); */ index = tempWord + 16; } } else if (track == 2) { track = 1; /* tempWord = shl( index, 6, pOverflow); */ tempWord = index << 6; /* index = add( tempWord, 32, pOverflow); */ index = tempWord + 32; } else if (track == 3) { track = 0; /* tempWord = shl( index, 1, pOverflow); */ tempWord = index << 1; /* index = add( tempWord, 1, pOverflow); */ index = tempWord + 1; } else if (track == 4) { track = 1; /* tempWord = shl( index, 6, pOverflow); */ tempWord = index << 6; /* index = add( tempWord, 48, pOverflow); */ index = tempWord + 48; } if (j > 0) { cod[i] = 8191; _sign[k] = 32767; tempWord = shl( 1, track, pOverflow); rsign = add_16( rsign, tempWord, pOverflow); } else { cod[i] = -8192; _sign[k] = (Word16) - 32768L; } indx = add_16( indx, index, pOverflow); } *sign = rsign; p0 = h - codvec[0]; p1 = h - codvec[1]; for (i = 0; i < L_CODE; i++) { s = 0; s = L_mac( s, *p0++, _sign[0], pOverflow); s = L_mac( s, *p1++, _sign[1], pOverflow); y[i] = pv_round( s, pOverflow); } return indx; }
static Word16 Lag_max( /* o : lag found */ vadState *vadSt, /* i/o : VAD state struct */ Word32 corr[], /* i : correlation vector. */ Word16 scal_sig[], /* i : scaled signal. */ Word16 L_frame, /* i : length of frame to compute pitch */ Word16 lag_max, /* i : maximum lag */ Word16 lag_min, /* i : minimum lag */ Word16 old_lag, /* i : old open-loop lag */ Word16 *cor_max, /* o : normalized correlation of selected lag */ Word16 wght_flg, /* i : is weighting function used */ Word16 *gain_flg, /* o : open-loop flag */ Flag dtx, /* i : dtx flag; use dtx=1, do not use dtx=0 */ Flag *pOverflow /* o : overflow flag */ ) { Word16 i; Word16 j; Word16 *p; Word16 *p1; Word32 max; Word32 t0; Word16 t0_h; Word16 t0_l; Word16 p_max; const Word16 *ww; const Word16 *we; Word32 t1; Word16 temp; ww = &corrweight[250]; we = &corrweight[123 + lag_max - old_lag]; max = MIN_32; p_max = lag_max; for (i = lag_max; i >= lag_min; i--) { t0 = corr[-i]; /* Weighting of the correlation function. */ L_Extract(corr[-i], &t0_h, &t0_l, pOverflow); t0 = Mpy_32_16(t0_h, t0_l, *ww, pOverflow); ww--; if (wght_flg > 0) { /* Weight the neighbourhood of the old lag. */ L_Extract(t0, &t0_h, &t0_l, pOverflow); t0 = Mpy_32_16(t0_h, t0_l, *we, pOverflow); we--; } /* if (L_sub (t0, max) >= 0) */ if (t0 >= max) { max = t0; p_max = i; } } p = &scal_sig[0]; p1 = &scal_sig[-p_max]; t0 = 0; t1 = 0; for (j = 0; j < L_frame; j++, p++, p1++) { t0 = L_mac(t0, *p, *p1, pOverflow); t1 = L_mac(t1, *p1, *p1, pOverflow); } if (dtx) { /* no test() call since this if is only in simulation env */ #ifdef VAD2 /* Save max correlation */ vadSt->L_Rmax = L_add(vadSt->L_Rmax, t0, pOverflow); /* Save max energy */ vadSt->L_R0 = L_add(vadSt->L_R0, t1, pOverflow); #else /* update and detect tone */ vad_tone_detection_update(vadSt, 0, pOverflow); vad_tone_detection(vadSt, t0, t1, pOverflow); #endif } /* gain flag is set according to the open_loop gain */ /* is t2/t1 > 0.4 ? */ temp = pv_round(t1, pOverflow); t1 = L_msu(t0, temp, 13107, pOverflow); *gain_flg = pv_round(t1, pOverflow); *cor_max = 0; return (p_max); }
void c_fft(Word16 * farray_ptr, Flag *pOverflow) { Word16 i; Word16 j; Word16 k; Word16 ii; Word16 jj; Word16 kk; Word16 ji; Word16 kj; Word16 ii2; Word32 ftmp; Word32 ftmp_real; Word32 ftmp_imag; Word16 tmp; Word16 tmp1; Word16 tmp2; /* Rearrange the input array in bit reversed order */ for (i = 0, j = 0; i < SIZE - 2; i = i + 2) { if (j > i) { ftmp = *(farray_ptr + i); *(farray_ptr + i) = *(farray_ptr + j); *(farray_ptr + j) = (Word16)ftmp; ftmp = *(farray_ptr + i + 1); *(farray_ptr + i + 1) = *(farray_ptr + j + 1); *(farray_ptr + j + 1) = (Word16)ftmp; } k = SIZE_BY_TWO; while (j >= k) { j = sub(j, k, pOverflow); k = shr(k, 1, pOverflow); } j = add(j, k, pOverflow); } /* The FFT part */ for (i = 0; i < NUM_STAGE; i++) { /* i is stage counter */ jj = shl(2, i, pOverflow); /* FFT size */ kk = shl(jj, 1, pOverflow); /* 2 * FFT size */ ii = ii_table[i]; /* 2 * number of FFT's */ ii2 = shl(ii, 1, pOverflow); ji = 0; /* ji is phase table index */ for (j = 0; j < jj; j = j + 2) { /* j is sample counter */ for (k = j; k < SIZE; k = k + kk) { /* k is butterfly top */ kj = add(k, jj, pOverflow); /* kj is butterfly bottom */ /* Butterfly computations */ ftmp_real = L_mult(*(farray_ptr + kj), phs_tbl[ji], pOverflow); ftmp_real = L_msu(ftmp_real, *(farray_ptr + kj + 1), phs_tbl[ji + 1], pOverflow); ftmp_imag = L_mult(*(farray_ptr + kj + 1), phs_tbl[ji], pOverflow); ftmp_imag = L_mac(ftmp_imag, *(farray_ptr + kj), phs_tbl[ji + 1], pOverflow); tmp1 = pv_round(ftmp_real, pOverflow); tmp2 = pv_round(ftmp_imag, pOverflow); tmp = sub(*(farray_ptr + k), tmp1, pOverflow); *(farray_ptr + kj) = shr(tmp, 1, pOverflow); tmp = sub(*(farray_ptr + k + 1), tmp2, pOverflow); *(farray_ptr + kj + 1) = shr(tmp, 1, pOverflow); tmp = add(*(farray_ptr + k), tmp1, pOverflow); *(farray_ptr + k) = shr(tmp, 1, pOverflow); tmp = add(*(farray_ptr + k + 1), tmp2, pOverflow); *(farray_ptr + k + 1) = shr(tmp, 1, pOverflow); } ji = add(ji, ii2, pOverflow); } } } /* end of c_fft () */
//============================================================================= //函数名称:Dec_gain //函数功能:解码的音调和码书增益 //============================================================================= void Dec_gain( gc_predState *pred_state, /* i/o: MA predictor state */ enum Mode mode, /* i : AMR mode */ Word16 index, /* i : index of quantization. */ Word16 code[], /* i : Innovative vector. */ Word16 evenSubfr, /* i : Flag for even subframes */ Word16 * gain_pit, /* o : Pitch gain. */ Word16 * gain_cod, /* o : Code gain. */ Flag * pOverflow ) { const Word16 *p; Word16 frac; Word16 gcode0; Word16 exp; Word16 qua_ener; Word16 qua_ener_MR122; Word16 g_code; Word32 L_tmp; Word16 temp1; Word16 temp2; /* Read the quantized gains (table depends on mode) */ //阅读量化收益(表取决于模式) index = shl(index, 2, pOverflow); if (mode == MR102 || mode == MR74 || mode == MR67) { p = &table_gain_highrates[index]; *gain_pit = *p++; g_code = *p++; qua_ener_MR122 = *p++; qua_ener = *p; } else { if (mode == MR475) { index += (1 ^ evenSubfr) << 1; /* evenSubfr is 0 or 1 */ if (index > (MR475_VQ_SIZE*4 - 2)) { index = (MR475_VQ_SIZE * 4 - 2); /* avoid possible buffer overflow */ } p = &table_gain_MR475[index]; *gain_pit = *p++; g_code = *p++; /*---------------------------------------------------------* * calculate predictor update values (not stored in 4.75 * * quantizer table to save space): * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * * * qua_ener = log2(g) * * qua_ener_MR122 = 20*log10(g) * *---------------------------------------------------------*/ //计算预测更新值(不存储在4.75量化表,以节省空间) /* Log2(x Q12) = log2(x) + 12 */ temp1 = (Word16) L_deposit_l(g_code); Log2(temp1, &exp, &frac, pOverflow); exp = sub(exp, 12, pOverflow); temp1 = shr_r(frac, 5, pOverflow); temp2 = shl(exp, 10, pOverflow); qua_ener_MR122 = add(temp1, temp2, pOverflow); /* 24660 Q12 ~= 6.0206 = 20*log10(2) */ L_tmp = Mpy_32_16(exp, frac, 24660, pOverflow); L_tmp = L_shl(L_tmp, 13, pOverflow); qua_ener = pv_round(L_tmp, pOverflow); /* Q12 * Q0 = Q13 -> Q10 */ } else { p = &table_gain_lowrates[index]; *gain_pit = *p++; g_code = *p++; qua_ener_MR122 = *p++; qua_ener = *p; } } /*-------------------------------------------------------------------* * predict codebook gain * * ~~~~~~~~~~~~~~~~~~~~~ * * gc0 = Pow2(int(d)+frac(d)) * * = 2^exp + 2^frac * * * * gcode0 (Q14) = 2^14*2^frac = gc0 * 2^(14-exp) * *-------------------------------------------------------------------*/ gc_pred(pred_state, mode, code, &exp, &frac, NULL, NULL, pOverflow); gcode0 = (Word16) Pow2(14, frac, pOverflow); /*------------------------------------------------------------------* * read quantized gains, update table of past quantized energies * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * st->past_qua_en(Q10) = 20 * Log10(g_fac) / constant * * = Log2(g_fac) * * = qua_ener * * constant = 20*Log10(2) * *------------------------------------------------------------------*/ L_tmp = L_mult(g_code, gcode0, pOverflow); temp1 = sub(10, exp, pOverflow); L_tmp = L_shr(L_tmp, temp1, pOverflow); *gain_cod = extract_h(L_tmp); /* update table of past quantized energies */ //过去的量化能量表更新 gc_pred_update(pred_state, qua_ener_MR122, qua_ener); return; }
Word16 Cb_gain_average( Cb_gain_averageState *st, /* i/o : State variables for CB gain averaging */ enum Mode mode, /* i : AMR mode */ Word16 gain_code, /* i : CB gain Q1 */ Word16 lsp[], /* i : The LSP for the current frame Q15 */ Word16 lspAver[], /* i : The average of LSP for 8 frames Q15 */ Word16 bfi, /* i : bad frame indication flag */ Word16 prev_bf, /* i : previous bad frame indication flag */ Word16 pdfi, /* i : potential degraded bad frame ind flag */ Word16 prev_pdf, /* i : prev pot. degraded bad frame ind flag */ Word16 inBackgroundNoise, /* i : background noise decision */ Word16 voicedHangover, /* i : # of frames after last voiced frame */ Flag *pOverflow ) { Word16 i; Word16 cbGainMix; Word16 diff; Word16 tmp_diff; Word16 bgMix; Word16 cbGainMean; Word32 L_sum; Word16 tmp[M]; Word16 tmp1; Word16 tmp2; Word16 shift1; Word16 shift2; Word16 shift; /*---------------------------------------------------------* * Compute mixed cb gain, used to make cb gain more * * smooth in background noise for modes 5.15, 5.9 and 6.7 * * states that needs to be updated by all * *---------------------------------------------------------*/ /* set correct cbGainMix for MR74, MR795, MR122 */ cbGainMix = gain_code; /*-------------------------------------------------------* * Store list of CB gain needed in the CB gain * * averaging * *-------------------------------------------------------*/ for (i = 0; i < (L_CBGAINHIST - 1); i++) { st->cbGainHistory[i] = st->cbGainHistory[i+1]; } st->cbGainHistory[L_CBGAINHIST-1] = gain_code; diff = 0; /* compute lsp difference */ for (i = 0; i < M; i++) { tmp1 = abs_s(sub(*(lspAver + i), *(lsp + i), pOverflow)); /* Q15 */ shift1 = sub(norm_s(tmp1), 1, pOverflow); /* Qn */ tmp1 = shl(tmp1, shift1, pOverflow); /* Q15+Qn */ shift2 = norm_s(*(lspAver + i)); /* Qm */ tmp2 = shl(*(lspAver + i), shift2, pOverflow); /* Q15+Qm */ tmp[i] = div_s(tmp1, tmp2); /* Q15+(Q15+Qn)-(Q15+Qm) */ shift = 2 + shift1 - shift2; if (shift >= 0) { *(tmp + i) = shr(*(tmp + i), shift, pOverflow); /* Q15+Qn-Qm-Qx=Q13 */ } else { *(tmp + i) = shl(*(tmp + i), negate(shift), pOverflow); /* Q15+Qn-Qm-Qx=Q13 */ } diff = add(diff, *(tmp + i), pOverflow); /* Q13 */ } /* Compute hangover */ if (diff > 5325) /* 0.65 in Q11 */ { st->hangVar += 1; } else { st->hangVar = 0; } if (st->hangVar > 10) { /* Speech period, reset hangover variable */ st->hangCount = 0; } /* Compute mix constant (bgMix) */ bgMix = 8192; /* 1 in Q13 */ if ((mode <= MR67) || (mode == MR102)) /* MR475, MR515, MR59, MR67, MR102 */ { /* if errors and presumed noise make smoothing probability stronger */ if (((((pdfi != 0) && (prev_pdf != 0)) || (bfi != 0) || (prev_bf != 0)) && (voicedHangover > 1) && (inBackgroundNoise != 0) && ((mode == MR475) || (mode == MR515) || (mode == MR59)))) { /* bgMix = min(0.25, max(0.0, diff-0.55)) / 0.25; */ tmp_diff = sub(diff, 4506, pOverflow); /* 0.55 in Q13 */ } else { /* bgMix = min(0.25, max(0.0, diff-0.40)) / 0.25; */ tmp_diff = sub(diff, 3277, pOverflow); /* 0.4 in Q13 */ } /* max(0.0, diff-0.55) or */ /* max(0.0, diff-0.40) */ if (tmp_diff > 0) { tmp1 = tmp_diff; } else { tmp1 = 0; } /* min(0.25, tmp1) */ if (2048 < tmp1) { bgMix = 8192; } else { bgMix = shl(tmp1, 2, pOverflow); } if ((st->hangCount < 40) || (diff > 5325)) /* 0.65 in Q13 */ { /* disable mix if too short time since */ bgMix = 8192; } /* Smoothen the cb gain trajectory */ /* smoothing depends on mix constant bgMix */ L_sum = L_mult(6554, st->cbGainHistory[2], pOverflow); /* 0.2 in Q15; L_sum in Q17 */ for (i = 3; i < L_CBGAINHIST; i++) { L_sum = L_mac(L_sum, 6554, st->cbGainHistory[i], pOverflow); } cbGainMean = pv_round(L_sum, pOverflow); /* Q1 */ /* more smoothing in error and bg noise (NB no DFI used here) */ if (((bfi != 0) || (prev_bf != 0)) && (inBackgroundNoise != 0) && ((mode == MR475) || (mode == MR515) || (mode == MR59))) { /* 0.143 in Q15; L_sum in Q17 */ L_sum = L_mult(4681, st->cbGainHistory[0], pOverflow); for (i = 1; i < L_CBGAINHIST; i++) { L_sum = L_mac(L_sum, 4681, st->cbGainHistory[i], pOverflow); } cbGainMean = pv_round(L_sum, pOverflow); /* Q1 */ } /* cbGainMix = bgMix*cbGainMix + (1-bgMix)*cbGainMean; */ /* L_sum in Q15 */ L_sum = L_mult(bgMix, cbGainMix, pOverflow); L_sum = L_mac(L_sum, 8192, cbGainMean, pOverflow); L_sum = L_msu(L_sum, bgMix, cbGainMean, pOverflow); cbGainMix = pv_round(L_shl(L_sum, 2, pOverflow), pOverflow); /* Q1 */ } st->hangCount += 1; return (cbGainMix); }
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); }
void A_Refl( Word16 a[], /* i : Directform coefficients */ Word16 refl[], /* o : Reflection coefficients */ Flag *pOverflow ) { /* local variables */ Word16 i; Word16 j; Word16 aState[M]; Word16 bState[M]; Word16 normShift; Word16 normProd; Word32 L_acc; Word16 scale; Word32 L_temp; Word16 temp; Word16 mult; /* initialize states */ for (i = 0; i < M; i++) { aState[i] = a[i]; } /* backward Levinson recursion */ for (i = M - 1; i >= 0; i--) { if (abs_s(aState[i]) >= 4096) { for (i = 0; i < M; i++) { refl[i] = 0; } break; } refl[i] = shl(aState[i], 3, pOverflow); L_temp = L_mult(refl[i], refl[i], pOverflow); L_acc = L_sub(MAX_32, L_temp, pOverflow); normShift = norm_l(L_acc); scale = sub(15, normShift, pOverflow); L_acc = L_shl(L_acc, normShift, pOverflow); normProd = pv_round(L_acc, pOverflow); mult = div_s(16384, normProd); for (j = 0; j < i; j++) { L_acc = L_deposit_h(aState[j]); L_acc = L_msu(L_acc, refl[i], aState[i-j-1], pOverflow); temp = pv_round(L_acc, pOverflow); L_temp = L_mult(mult, temp, pOverflow); L_temp = L_shr_r(L_temp, scale, pOverflow); if (L_abs(L_temp) > 32767) { for (i = 0; i < M; i++) { refl[i] = 0; } break; } bState[j] = extract_l(L_temp); } for (j = 0; j < i; j++) { aState[j] = bState[j]; } } return; }
static Word16 build_code( Word16 subNr, /* i : subframe number */ Word16 codvec[], /* i : position of pulses */ Word16 dn_sign[], /* i : sign of pulses */ Word16 cod[], /* o : innovative code vector */ Word16 h[], /* i : impulse response of weighted synthesis */ /* filter */ Word16 y[], /* o : filtered innovative code */ Word16 sign[], /* o : sign of 2 pulses */ Flag *pOverflow /* o : Flag set when overflow occurs */ ) { register Word16 i; register Word16 j; register Word16 k; register Word16 track; register Word16 first; register Word16 index; register Word16 rsign; Word16 indx; Word16 _sign[NB_PULSE]; Word16 *p0; Word16 *p1; const Word16 *pt; Word32 s; pt = trackTable + subNr + (subNr << 2); for (i = 0; i < L_CODE; i++) { *(cod + i) = 0; } indx = 0; rsign = 0; for (k = 0; k < NB_PULSE; k++) { i = *(codvec + k); /* read pulse position */ j = *(dn_sign + i); /* read sign */ s = ((Word32)(i * 6554)) >> 15; index = (Word16) s; /* index = pos/5 */ track = i - (5 * index); /* track = pos%5 */ first = *(pt + track); if (k == 0) { track = 0; if (first != 0) { index += 64; /* table bit is MSB */ } } else { track = 1; index <<= 3; } if (j > 0) { *(cod + i) = 8191; *(_sign + k) = 32767; rsign += (1 << track); } else { *(cod + i) = ~(8192) + 1; *(_sign + k) = (Word16)(~(32768) + 1); } indx += index; } *sign = rsign; p0 = h - *codvec; p1 = h - *(codvec + 1); for (i = 0; i < L_CODE; i++) { s = 0; s = L_mult( *p0++, *_sign, pOverflow); s = L_mac( s, *p1++, *(_sign + 1), pOverflow); *(y + i) = pv_round( s, pOverflow); } return(indx); }
void set_sign12k2( Word16 dn[], /* i/o : correlation between target and h[] */ Word16 cn[], /* i : residual after long term prediction */ Word16 sign[], /* o : sign of d[n] */ Word16 pos_max[], /* o : position of maximum correlation */ Word16 nb_track, /* i : number of tracks tracks */ Word16 ipos[], /* o : starting position for each pulse */ Word16 step, /* i : the step size in the tracks */ Flag *pOverflow /* i/o: overflow flag */ ) { Word16 i, j; Word16 val; Word16 cor; Word16 k_cn; Word16 k_dn; Word16 max; Word16 max_of_all; Word16 pos = 0; /* initialization only needed to keep gcc silent */ Word16 en[L_CODE]; /* correlation vector */ Word32 s; Word32 t; Word32 L_temp; Word16 *p_cn; Word16 *p_dn; Word16 *p_sign; Word16 *p_en; /* calculate energy for normalization of cn[] and dn[] */ s = 256; t = 256; p_cn = cn; p_dn = dn; /* crosscorrelation values do not have strong peaks, so scaling applied in cor_h_x (sf=2) guaranteed that the mac of the energy for this vector will not overflow */ for (i = L_CODE; i != 0; i--) { val = *(p_cn++); s = L_mac(s, val, val, pOverflow); val = *(p_dn++); t += ((Word32) val * val) << 1; } s = Inv_sqrt(s, pOverflow); k_cn = (Word16)((L_shl(s, 5, pOverflow)) >> 16); t = Inv_sqrt(t, pOverflow); k_dn = (Word16)(t >> 11); p_cn = &cn[L_CODE-1]; p_sign = &sign[L_CODE-1]; p_en = &en[L_CODE-1]; for (i = L_CODE - 1; i >= 0; i--) { L_temp = ((Word32)k_cn * *(p_cn--)) << 1; val = dn[i]; s = L_mac(L_temp, k_dn, val, pOverflow); L_temp = L_shl(s, 10, pOverflow); cor = pv_round(L_temp, pOverflow); if (cor >= 0) { *(p_sign--) = 32767; /* sign = +1 */ } else { *(p_sign--) = -32767; /* sign = -1 */ cor = - (cor); /* modify dn[] according to the fixed sign */ dn[i] = - val; } *(p_en--) = cor; } max_of_all = -1; for (i = 0; i < nb_track; i++) { max = -1; for (j = i; j < L_CODE; j += step) { cor = en[j]; if (cor > max) { max = cor; pos = j; } } /* store maximum correlation position */ pos_max[i] = pos; if (max > max_of_all) { max_of_all = max; /* starting position for i0 */ ipos[0] = i; } } /*----------------------------------------------------------------* * Set starting position of each pulse. * *----------------------------------------------------------------*/ pos = ipos[0]; ipos[nb_track] = pos; for (i = 1; i < nb_track; i++) { pos++; if (pos >= nb_track) { pos = 0; } ipos[ i] = pos; ipos[ i + nb_track] = pos; } return; }
static Word16 MR795_gain_code_quant_mod( /* o : index of quantization. */ Word16 gain_pit, /* i : pitch gain, Q14 */ Word16 exp_gcode0, /* i : predicted CB gain (exponent), Q0 */ Word16 gcode0, /* i : predicted CB gain (norm.), Q14 */ Word16 frac_en[], /* i : energy coefficients (4), fraction part, Q15 */ Word16 exp_en[], /* i : energy coefficients (4), eponent part, Q0 */ Word16 alpha, /* i : gain adaptor factor (>0), Q15 */ Word16 gain_cod_unq, /* i : Code gain (unquantized) */ /* (scaling: Q10 - exp_gcode0) */ Word16 *gain_cod, /* i/o: Code gain (pre-/quantized), Q1 */ Word16 *qua_ener_MR122, /* o : quantized energy error, Q10 */ /* (for MR122 MA predictor update) */ Word16 *qua_ener, /* o : quantized energy error, Q10 */ /* (for other MA predictor update) */ const Word16* qua_gain_code_ptr, /* i : ptr to read-only ptr */ Flag *pOverflow /* o : overflow indicator */ ) { const Word16 *p; Word16 i; Word16 index; Word16 tmp; Word16 one_alpha; Word16 exp; Word16 e_max; Word16 g2_pitch; Word16 g_code; Word16 g2_code_h; Word16 g2_code_l; Word16 d2_code_h; Word16 d2_code_l; Word16 coeff[5]; Word16 coeff_lo[5]; Word16 exp_coeff[5]; Word32 L_tmp; Word32 L_t0; Word32 L_t1; Word32 dist_min; Word16 gain_code; /* Steps in calculation of the error criterion (dist): --------------------------------------------------- underlined = constant; alp = FLP value of alpha, alpha = FIP ---------- ExEn = gp^2 * LtpEn + 2.0*gp*gc[i] * XC + gc[i]^2 * InnEn; ------------ ------ -- ----- aExEn= alp * ExEn = alp*gp^2*LtpEn + 2.0*alp*gp*XC* gc[i] + alp*InnEn* gc[i]^2 -------------- ------------- --------- = t[1] + t[2] + t[3] dist = d1 + d2; d1 = (1.0 - alp) * InnEn * (gcu - gc[i])^2 = t[4] ------------------- --- d2 = alp * (ResEn - 2.0 * sqrt(ResEn*ExEn) + ExEn); --- ----- --- ----- = alp * (sqrt(ExEn) - sqrt(ResEn))^2 --- ----------- = (sqrt(aExEn) - sqrt(alp*ResEn))^2 --------------- = (sqrt(aExEn) - t[0] )^2 ---- */ /* * calculate scalings of the constant terms */ gain_code = shl(*gain_cod, (10 - exp_gcode0), pOverflow); /* Q1 -> Q11 (-ec0) */ g2_pitch = mult(gain_pit, gain_pit, pOverflow); /* Q14 -> Q13 */ /* 0 < alpha <= 0.5 => 0.5 <= 1-alpha < 1, i.e one_alpha is normalized */ one_alpha = add_16((32767 - alpha), 1, pOverflow); /* 32768 - alpha */ /* alpha <= 0.5 -> mult. by 2 to keep precision; compensate in exponent */ L_t1 = L_mult(alpha, frac_en[1], pOverflow); L_t1 = L_shl(L_t1, 1, pOverflow); tmp = (Word16)(L_t1 >> 16); /* directly store in 32 bit variable because no further mult. required */ L_t1 = L_mult(tmp, g2_pitch, pOverflow); exp_coeff[1] = exp_en[1] - 15; tmp = (Word16)(L_shl(L_mult(alpha, frac_en[2], pOverflow), 1, pOverflow) >> 16); coeff[2] = mult(tmp, gain_pit, pOverflow); exp = exp_gcode0 - 10; exp_coeff[2] = add_16(exp_en[2], exp, pOverflow); /* alpha <= 0.5 -> mult. by 2 to keep precision; compensate in exponent */ coeff[3] = (Word16)(L_shl(L_mult(alpha, frac_en[3], pOverflow), 1, pOverflow) >> 16); exp = shl(exp_gcode0, 1, pOverflow) - 7; exp_coeff[3] = add_16(exp_en[3], exp, pOverflow); coeff[4] = mult(one_alpha, frac_en[3], pOverflow); exp_coeff[4] = add_16(exp_coeff[3], 1, pOverflow); L_tmp = L_mult(alpha, frac_en[0], pOverflow); /* sqrt_l returns normalized value and 2*exponent -> result = val >> (exp/2) exp_coeff holds 2*exponent for c[0] */ /* directly store in 32 bit variable because no further mult. required */ L_t0 = sqrt_l_exp(L_tmp, &exp, pOverflow); /* normalization included in sqrt_l_exp */ exp += 47; exp_coeff[0] = exp_en[0] - exp; /* * Determine the maximum exponent occuring in the distance calculation * and adjust all fractions accordingly (including a safety margin) * */ /* find max(e[1..4],e[0]+31) */ e_max = exp_coeff[0] + 31; for (i = 1; i <= 4; i++) { if (exp_coeff[i] > e_max) { e_max = exp_coeff[i]; } } /* scale c[1] (requires no further multiplication) */ tmp = e_max - exp_coeff[1]; L_t1 = L_shr(L_t1, tmp, pOverflow); /* scale c[2..4] (used in Mpy_32_16 in the quantizer loop) */ for (i = 2; i <= 4; i++) { tmp = e_max - exp_coeff[i]; L_tmp = ((Word32)coeff[i] << 16); L_tmp = L_shr(L_tmp, tmp, pOverflow); L_Extract(L_tmp, &coeff[i], &coeff_lo[i], pOverflow); } /* scale c[0] (requires no further multiplication) */ exp = e_max - 31; /* new exponent */ tmp = exp - exp_coeff[0]; L_t0 = L_shr(L_t0, shr(tmp, 1, pOverflow), pOverflow); /* perform correction by 1/sqrt(2) if exponent difference is odd */ if ((tmp & 0x1) != 0) { L_Extract(L_t0, &coeff[0], &coeff_lo[0], pOverflow); L_t0 = Mpy_32_16(coeff[0], coeff_lo[0], 23170, pOverflow); /* 23170 Q15 = 1/sqrt(2)*/ } /* search the quantizer table for the lowest value of the search criterion */ dist_min = MAX_32; index = 0; p = &qua_gain_code_ptr[0]; for (i = 0; i < NB_QUA_CODE; i++) { g_code = *p++; /* this is g_fac (Q11) */ p++; /* skip log2(g_fac) */ p++; /* skip 20*log10(g_fac) */ g_code = mult(g_code, gcode0, pOverflow); /* only continue if gc[i] < 2.0*gc which is equiv. to g_code (Q10-ec0) < gain_code (Q11-ec0) */ if (g_code >= gain_code) { break; } L_tmp = L_mult(g_code, g_code, pOverflow); L_Extract(L_tmp, &g2_code_h, &g2_code_l, pOverflow); tmp = sub(g_code, gain_cod_unq, pOverflow); L_tmp = L_mult(tmp, tmp, pOverflow); L_Extract(L_tmp, &d2_code_h, &d2_code_l, pOverflow); /* t2, t3, t4 */ L_tmp = Mac_32_16(L_t1, coeff[2], coeff_lo[2], g_code, pOverflow); L_tmp = Mac_32(L_tmp, coeff[3], coeff_lo[3], g2_code_h, g2_code_l, pOverflow); L_tmp = sqrt_l_exp(L_tmp, &exp, pOverflow); L_tmp = L_shr(L_tmp, shr(exp, 1, pOverflow), pOverflow); /* d2 */ tmp = pv_round(L_sub(L_tmp, L_t0, pOverflow), pOverflow); L_tmp = L_mult(tmp, tmp, pOverflow); /* dist */ L_tmp = Mac_32(L_tmp, coeff[4], coeff_lo[4], d2_code_h, d2_code_l, pOverflow); /* store table index if distance measure for this index is lower than the minimum seen so far */ if (L_tmp < dist_min) { dist_min = L_tmp; index = i; } } /*------------------------------------------------------------------* * read quantized gains and new values for MA predictor memories * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * *------------------------------------------------------------------*/ /* Read the quantized gains */ p = &qua_gain_code_ptr[(index<<2) - index]; g_code = *p++; *qua_ener_MR122 = *p++; *qua_ener = *p; /*------------------------------------------------------------------* * calculate final fixed codebook gain: * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * * * gc = gc0 * g * *------------------------------------------------------------------*/ L_tmp = L_mult(g_code, gcode0, pOverflow); L_tmp = L_shr(L_tmp, 9 - exp_gcode0, pOverflow); *gain_cod = (Word16)(L_tmp >> 16); return index; }