aboutsummaryrefslogtreecommitdiffstats
path: root/fdk-aac/libAACdec/src/usacdec_acelp.cpp
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
commit0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch)
treed07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libAACdec/src/usacdec_acelp.cpp
parentefe406d9724f959c8bc2a31802559ca6d41fd897 (diff)
downloadODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since that follows the android source releases, there is no place for a custom DAB+ patch there. So instead of having to maintain a patched fdk-aac that has to have the same .so version as the distribution package on which it is installed, we prefer having a separate fdk-aac-dab library to avoid collision. At that point, there's no reason to keep fdk-aac in a separate repository, as odr-audioenc is the only tool that needs DAB+ encoding support. Including it here simplifies installation, and makes it consistent with toolame-dab, also shipped in this repository. DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop, welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libAACdec/src/usacdec_acelp.cpp')
-rw-r--r--fdk-aac/libAACdec/src/usacdec_acelp.cpp1296
1 files changed, 1296 insertions, 0 deletions
diff --git a/fdk-aac/libAACdec/src/usacdec_acelp.cpp b/fdk-aac/libAACdec/src/usacdec_acelp.cpp
new file mode 100644
index 0000000..a606459
--- /dev/null
+++ b/fdk-aac/libAACdec/src/usacdec_acelp.cpp
@@ -0,0 +1,1296 @@
+/* -----------------------------------------------------------------------------
+Software License for The Fraunhofer FDK AAC Codec Library for Android
+
+© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+Forschung e.V. All rights reserved.
+
+ 1. INTRODUCTION
+The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
+that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
+scheme for digital audio. This FDK AAC Codec software is intended to be used on
+a wide variety of Android devices.
+
+AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
+general perceptual audio codecs. AAC-ELD is considered the best-performing
+full-bandwidth communications codec by independent studies and is widely
+deployed. AAC has been standardized by ISO and IEC as part of the MPEG
+specifications.
+
+Patent licenses for necessary patent claims for the FDK AAC Codec (including
+those of Fraunhofer) may be obtained through Via Licensing
+(www.vialicensing.com) or through the respective patent owners individually for
+the purpose of encoding or decoding bit streams in products that are compliant
+with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
+Android devices already license these patent claims through Via Licensing or
+directly from the patent owners, and therefore FDK AAC Codec software may
+already be covered under those patent licenses when it is used for those
+licensed purposes only.
+
+Commercially-licensed AAC software libraries, including floating-point versions
+with enhanced sound quality, are also available from Fraunhofer. Users are
+encouraged to check the Fraunhofer website for additional applications
+information and documentation.
+
+2. COPYRIGHT LICENSE
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted without payment of copyright license fees provided that you
+satisfy the following conditions:
+
+You must retain the complete text of this software license in redistributions of
+the FDK AAC Codec or your modifications thereto in source code form.
+
+You must retain the complete text of this software license in the documentation
+and/or other materials provided with redistributions of the FDK AAC Codec or
+your modifications thereto in binary form. You must make available free of
+charge copies of the complete source code of the FDK AAC Codec and your
+modifications thereto to recipients of copies in binary form.
+
+The name of Fraunhofer may not be used to endorse or promote products derived
+from this library without prior written permission.
+
+You may not charge copyright license fees for anyone to use, copy or distribute
+the FDK AAC Codec software or your modifications thereto.
+
+Your modified versions of the FDK AAC Codec must carry prominent notices stating
+that you changed the software and the date of any change. For modified versions
+of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
+must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
+AAC Codec Library for Android."
+
+3. NO PATENT LICENSE
+
+NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
+limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
+Fraunhofer provides no warranty of patent non-infringement with respect to this
+software.
+
+You may use this FDK AAC Codec software or modifications thereto only for
+purposes that are authorized by appropriate patent licenses.
+
+4. DISCLAIMER
+
+This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
+holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+including but not limited to the implied warranties of merchantability and
+fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
+or consequential damages, including but not limited to procurement of substitute
+goods or services; loss of use, data, or profits, or business interruption,
+however caused and on any theory of liability, whether in contract, strict
+liability, or tort (including negligence), arising in any way out of the use of
+this software, even if advised of the possibility of such damage.
+
+5. CONTACT INFORMATION
+
+Fraunhofer Institute for Integrated Circuits IIS
+Attention: Audio and Multimedia Departments - FDK AAC LL
+Am Wolfsmantel 33
+91058 Erlangen, Germany
+
+www.iis.fraunhofer.de/amm
+amm-info@iis.fraunhofer.de
+----------------------------------------------------------------------------- */
+
+/**************************** AAC decoder library ******************************
+
+ Author(s): Matthias Hildenbrand
+
+ Description: USAC ACELP frame decoder
+
+*******************************************************************************/
+
+#include "usacdec_acelp.h"
+
+#include "usacdec_ace_d4t64.h"
+#include "usacdec_ace_ltp.h"
+#include "usacdec_rom.h"
+#include "usacdec_lpc.h"
+#include "genericStds.h"
+
+#define PIT_FR2_12k8 128 /* Minimum pitch lag with resolution 1/2 */
+#define PIT_FR1_12k8 160 /* Minimum pitch lag with resolution 1 */
+#define TILT_CODE2 \
+ FL2FXCONST_SGL(0.3f * 2.0f) /* ACELP code pre-emphasis factor ( *2 ) */
+#define PIT_SHARP \
+ FL2FXCONST_SGL(0.85f) /* pitch sharpening factor */
+#define PREEMPH_FAC \
+ FL2FXCONST_SGL(0.68f) /* ACELP synth pre-emphasis factor */
+
+#define ACELP_HEADROOM 1
+#define ACELP_OUTSCALE (MDCT_OUT_HEADROOM - ACELP_HEADROOM)
+
+/**
+ * \brief Calculate pre-emphasis (1 - mu z^-1) on input signal.
+ * \param[in] in pointer to input signal; in[-1] is also needed.
+ * \param[out] out pointer to output signal.
+ * \param[in] L length of filtering.
+ */
+/* static */
+void E_UTIL_preemph(const FIXP_DBL *in, FIXP_DBL *out, INT L) {
+ int i;
+
+ for (i = 0; i < L; i++) {
+ out[i] = in[i] - fMult(PREEMPH_FAC, in[i - 1]);
+ }
+
+ return;
+}
+
+/**
+ * \brief Calculate de-emphasis 1/(1 - TILT_CODE z^-1) on innovative codebook
+ * vector.
+ * \param[in,out] x innovative codebook vector.
+ */
+static void Preemph_code(
+ FIXP_COD x[] /* (i/o) : input signal overwritten by the output */
+) {
+ int i;
+ FIXP_DBL L_tmp;
+
+ /* ARM926: 12 cycles per sample */
+ for (i = L_SUBFR - 1; i > 0; i--) {
+ L_tmp = FX_COD2FX_DBL(x[i]);
+ L_tmp -= fMultDiv2(x[i - 1], TILT_CODE2);
+ x[i] = FX_DBL2FX_COD(L_tmp);
+ }
+}
+
+/**
+ * \brief Apply pitch sharpener to the innovative codebook vector.
+ * \param[in,out] x innovative codebook vector.
+ * \param[in] pit_lag decoded pitch lag.
+ */
+static void Pit_shrp(
+ FIXP_COD x[], /* in/out: impulse response (or algebraic code) */
+ int pit_lag /* input : pitch lag */
+) {
+ int i;
+ FIXP_DBL L_tmp;
+
+ for (i = pit_lag; i < L_SUBFR; i++) {
+ L_tmp = FX_COD2FX_DBL(x[i]);
+ L_tmp += fMult(x[i - pit_lag], PIT_SHARP);
+ x[i] = FX_DBL2FX_COD(L_tmp);
+ }
+
+ return;
+}
+
+ /**
+ * \brief Calculate Quantized codebook gain, Quantized pitch gain and unbiased
+ * Innovative code vector energy.
+ * \param[in] index index of quantizer.
+ * \param[in] code innovative code vector with exponent = SF_CODE.
+ * \param[out] gain_pit Quantized pitch gain g_p with exponent = SF_GAIN_P.
+ * \param[out] gain_code Quantized codebook gain g_c.
+ * \param[in] mean_ener mean_ener defined in open-loop (2 bits), exponent = 7.
+ * \param[out] E_code unbiased innovative code vector energy.
+ * \param[out] E_code_e exponent of unbiased innovative code vector energy.
+ */
+
+#define SF_MEAN_ENER_LG10 9
+
+/* pow(10.0, {18, 30, 42, 54}/20.0) /(float)(1<<SF_MEAN_ENER_LG10) */
+static const FIXP_DBL pow_10_mean_energy[4] = {0x01fc5ebd, 0x07e7db92,
+ 0x1f791f65, 0x7d4bfba3};
+
+static void D_gain2_plus(int index, FIXP_COD code[], FIXP_SGL *gain_pit,
+ FIXP_DBL *gain_code, int mean_ener_bits, int bfi,
+ FIXP_SGL *past_gpit, FIXP_DBL *past_gcode,
+ FIXP_DBL *pEner_code, int *pEner_code_e) {
+ FIXP_DBL Ltmp;
+ FIXP_DBL gcode0, gcode_inov;
+ INT gcode0_e, gcode_inov_e;
+ int i;
+
+ FIXP_DBL ener_code;
+ INT ener_code_e;
+
+ /* ener_code = sum(code[]^2) */
+ ener_code = FIXP_DBL(0);
+ for (i = 0; i < L_SUBFR; i++) {
+ ener_code += fPow2Div2(code[i]);
+ }
+
+ ener_code_e = fMax(fNorm(ener_code) - 1, 0);
+ ener_code <<= ener_code_e;
+ ener_code_e = 2 * SF_CODE + 1 - ener_code_e;
+
+ /* export energy of code for calc_period_factor() */
+ *pEner_code = ener_code;
+ *pEner_code_e = ener_code_e;
+
+ ener_code += scaleValue(FL2FXCONST_DBL(0.01f), -ener_code_e);
+
+ /* ener_code *= 1/L_SUBFR, and make exponent even (because of square root
+ * below). */
+ if (ener_code_e & 1) {
+ ener_code_e -= 5;
+ ener_code >>= 1;
+ } else {
+ ener_code_e -= 6;
+ }
+ gcode_inov = invSqrtNorm2(ener_code, &gcode0_e);
+ gcode_inov_e = gcode0_e - (ener_code_e >> 1);
+
+ if (bfi) {
+ FIXP_DBL tgcode;
+ FIXP_SGL tgpit;
+
+ tgpit = *past_gpit;
+
+ if (tgpit > FL2FXCONST_SGL(0.95f / (1 << SF_GAIN_P))) {
+ tgpit = FL2FXCONST_SGL(0.95f / (1 << SF_GAIN_P));
+ } else if (tgpit < FL2FXCONST_SGL(0.5f / (1 << SF_GAIN_P))) {
+ tgpit = FL2FXCONST_SGL(0.5f / (1 << SF_GAIN_P));
+ }
+ *gain_pit = tgpit;
+ tgpit = FX_DBL2FX_SGL(fMult(tgpit, FL2FXCONST_DBL(0.95f)));
+ *past_gpit = tgpit;
+
+ tgpit = FL2FXCONST_SGL(1.4f / (1 << SF_GAIN_P)) - tgpit;
+ tgcode = fMult(*past_gcode, tgpit) << SF_GAIN_P;
+ *gain_code = scaleValue(fMult(tgcode, gcode_inov), gcode_inov_e);
+ *past_gcode = tgcode;
+
+ return;
+ }
+
+ /*-------------- Decode gains ---------------*/
+ /*
+ gcode0 = pow(10.0, (float)mean_ener/20.0);
+ gcode0 = gcode0 / sqrt(ener_code/L_SUBFR);
+ */
+ gcode0 = pow_10_mean_energy[mean_ener_bits];
+ gcode0 = fMultDiv2(gcode0, gcode_inov);
+ gcode0_e = gcode0_e + SF_MEAN_ENER_LG10 - (ener_code_e >> 1) + 1;
+
+ i = index << 1;
+ *gain_pit = fdk_t_qua_gain7b[i]; /* adaptive codebook gain */
+ /* t_qua_gain[ind2p1] : fixed codebook gain correction factor */
+ Ltmp = fMult(fdk_t_qua_gain7b[i + 1], gcode0);
+ *gain_code = scaleValue(Ltmp, gcode0_e - SF_GAIN_C + SF_QUA_GAIN7B);
+
+ /* update bad frame handler */
+ *past_gpit = *gain_pit;
+
+ /*--------------------------------------------------------
+ past_gcode = gain_code/gcode_inov
+ --------------------------------------------------------*/
+ {
+ FIXP_DBL gcode_m;
+ INT gcode_e;
+
+ gcode_m = fDivNormHighPrec(Ltmp, gcode_inov, &gcode_e);
+ gcode_e += (gcode0_e - SF_GAIN_C + SF_QUA_GAIN7B) - (gcode_inov_e);
+ *past_gcode = scaleValue(gcode_m, gcode_e);
+ }
+}
+
+/**
+ * \brief Calculate period/voicing factor r_v
+ * \param[in] exc pitch excitation.
+ * \param[in] gain_pit gain of pitch g_p.
+ * \param[in] gain_code gain of code g_c.
+ * \param[in] gain_code_e exponent of gain of code.
+ * \param[in] ener_code unbiased innovative code vector energy.
+ * \param[in] ener_code_e exponent of unbiased innovative code vector energy.
+ * \return period/voice factor r_v (-1=unvoiced to 1=voiced), exponent SF_PFAC.
+ */
+static FIXP_DBL calc_period_factor(FIXP_DBL exc[], FIXP_SGL gain_pit,
+ FIXP_DBL gain_code, FIXP_DBL ener_code,
+ int ener_code_e) {
+ int ener_exc_e, L_tmp_e, s = 0;
+ FIXP_DBL ener_exc, L_tmp;
+ FIXP_DBL period_fac;
+
+ /* energy of pitch excitation */
+ ener_exc = (FIXP_DBL)0;
+ for (int i = 0; i < L_SUBFR; i++) {
+ ener_exc += fPow2Div2(exc[i]) >> s;
+ if (ener_exc >= FL2FXCONST_DBL(0.5f)) {
+ ener_exc >>= 1;
+ s++;
+ }
+ }
+
+ ener_exc_e = fNorm(ener_exc);
+ ener_exc = fMult(ener_exc << ener_exc_e, fPow2(gain_pit));
+ if (ener_exc != (FIXP_DBL)0) {
+ ener_exc_e = 2 * SF_EXC + 1 + 2 * SF_GAIN_P - ener_exc_e + s;
+ } else {
+ ener_exc_e = 0;
+ }
+
+ /* energy of innovative code excitation */
+ /* L_tmp = ener_code * gain_code*gain_code; */
+ L_tmp_e = fNorm(gain_code);
+ L_tmp = fPow2(gain_code << L_tmp_e);
+ L_tmp = fMult(ener_code, L_tmp);
+ L_tmp_e = 2 * SF_GAIN_C + ener_code_e - 2 * L_tmp_e;
+
+ /* Find common exponent */
+ {
+ FIXP_DBL num, den;
+ int exp_diff;
+
+ exp_diff = ener_exc_e - L_tmp_e;
+ if (exp_diff >= 0) {
+ ener_exc >>= 1;
+ if (exp_diff <= DFRACT_BITS - 2) {
+ L_tmp >>= exp_diff + 1;
+ } else {
+ L_tmp = (FIXP_DBL)0;
+ }
+ den = ener_exc + L_tmp;
+ if (ener_exc_e < DFRACT_BITS - 1) {
+ den += scaleValue(FL2FXCONST_DBL(0.01f), -ener_exc_e - 1);
+ }
+ } else {
+ if (exp_diff >= -(DFRACT_BITS - 2)) {
+ ener_exc >>= 1 - exp_diff;
+ } else {
+ ener_exc = (FIXP_DBL)0;
+ }
+ L_tmp >>= 1;
+ den = ener_exc + L_tmp;
+ if (L_tmp_e < DFRACT_BITS - 1) {
+ den += scaleValue(FL2FXCONST_DBL(0.01f), -L_tmp_e - 1);
+ }
+ }
+ num = (ener_exc - L_tmp);
+ num >>= SF_PFAC;
+
+ if (den > (FIXP_DBL)0) {
+ if (ener_exc > L_tmp) {
+ period_fac = schur_div(num, den, 16);
+ } else {
+ period_fac = -schur_div(-num, den, 16);
+ }
+ } else {
+ period_fac = (FIXP_DBL)MAXVAL_DBL;
+ }
+ }
+
+ /* exponent = SF_PFAC */
+ return period_fac;
+}
+
+/*------------------------------------------------------------*
+ * noise enhancer *
+ * ~~~~~~~~~~~~~~ *
+ * - Enhance excitation on noise. (modify gain of code) *
+ * If signal is noisy and LPC filter is stable, move gain *
+ * of code 1.5 dB toward gain of code threshold. *
+ * This decrease by 3 dB noise energy variation. *
+ *------------------------------------------------------------*/
+/**
+ * \brief Enhance excitation on noise. (modify gain of code)
+ * \param[in] gain_code Quantized codebook gain g_c, exponent = SF_GAIN_C.
+ * \param[in] period_fac periodicity factor, exponent = SF_PFAC.
+ * \param[in] stab_fac stability factor, exponent = SF_STAB.
+ * \param[in,out] p_gc_threshold modified gain of previous subframe.
+ * \return gain_code smoothed gain of code g_sc, exponent = SF_GAIN_C.
+ */
+static FIXP_DBL
+noise_enhancer(/* (o) : smoothed gain g_sc SF_GAIN_C */
+ FIXP_DBL gain_code, /* (i) : Quantized codebook gain SF_GAIN_C */
+ FIXP_DBL period_fac, /* (i) : periodicity factor (-1=unvoiced to
+ 1=voiced), SF_PFAC */
+ FIXP_SGL stab_fac, /* (i) : stability factor (0 <= ... < 1.0)
+ SF_STAB */
+ FIXP_DBL
+ *p_gc_threshold) /* (io): gain of code threshold SF_GAIN_C */
+{
+ FIXP_DBL fac, L_tmp, gc_thres;
+
+ gc_thres = *p_gc_threshold;
+
+ L_tmp = gain_code;
+ if (L_tmp < gc_thres) {
+ L_tmp += fMultDiv2(gain_code,
+ FL2FXCONST_SGL(2.0 * 0.19f)); /* +1.5dB => *(1.0+0.19) */
+ if (L_tmp > gc_thres) {
+ L_tmp = gc_thres;
+ }
+ } else {
+ L_tmp = fMult(gain_code,
+ FL2FXCONST_SGL(1.0f / 1.19f)); /* -1.5dB => *10^(-1.5/20) */
+ if (L_tmp < gc_thres) {
+ L_tmp = gc_thres;
+ }
+ }
+ *p_gc_threshold = L_tmp;
+
+ /* voicing factor lambda = 0.5*(1-period_fac) */
+ /* gain smoothing factor S_m = lambda*stab_fac (=fac)
+ = 0.5(stab_fac - stab_fac * period_fac) */
+ fac = (FX_SGL2FX_DBL(stab_fac) >> (SF_PFAC + 1)) -
+ fMultDiv2(stab_fac, period_fac);
+ /* fac_e = SF_PFAC + SF_STAB */
+ FDK_ASSERT(fac >= (FIXP_DBL)0);
+
+ /* gain_code = (float)((fac*tmp) + ((1.0-fac)*gain_code)); */
+ gain_code = fMult(fac, L_tmp) -
+ fMult(FL2FXCONST_DBL(-1.0f / (1 << (SF_PFAC + SF_STAB))) + fac,
+ gain_code);
+ gain_code <<= (SF_PFAC + SF_STAB);
+
+ return gain_code;
+}
+
+/**
+ * \brief Update adaptive codebook u'(n) (exc)
+ * Enhance pitch of c(n) and build post-processed excitation u(n) (exc2)
+ * \param[in] code innovative codevector c(n), exponent = SF_CODE.
+ * \param[in,out] exc filtered adaptive codebook v(n), exponent = SF_EXC.
+ * \param[in] gain_pit adaptive codebook gain, exponent = SF_GAIN_P.
+ * \param[in] gain_code innovative codebook gain g_c, exponent = SF_GAIN_C.
+ * \param[in] gain_code_smoothed smoothed innov. codebook gain g_sc, exponent =
+ * SF_GAIN_C.
+ * \param[in] period_fac periodicity factor r_v, exponent = SF_PFAC.
+ * \param[out] exc2 post-processed excitation u(n), exponent = SF_EXC.
+ */
+void BuildAdaptiveExcitation(
+ FIXP_COD code[], /* (i) : algebraic codevector c(n) Q9 */
+ FIXP_DBL exc[], /* (io): filtered adaptive codebook v(n) Q15 */
+ FIXP_SGL gain_pit, /* (i) : adaptive codebook gain g_p Q14 */
+ FIXP_DBL gain_code, /* (i) : innovative codebook gain g_c Q16 */
+ FIXP_DBL gain_code_smoothed, /* (i) : smoothed innov. codebook gain g_sc
+ Q16 */
+ FIXP_DBL period_fac, /* (i) : periodicity factor r_v Q15 */
+ FIXP_DBL exc2[] /* (o) : post-processed excitation u(n) Q15 */
+) {
+/* Note: code[L_SUBFR] and exc2[L_SUBFR] share the same memory!
+ If exc2[i] is written, code[i] will be destroyed!
+*/
+#define SF (SF_CODE + SF_GAIN_C + 1 - SF_EXC)
+
+ int i;
+ FIXP_DBL tmp, cpe, code_smooth_prev, code_smooth;
+
+ FIXP_COD code_i;
+ FIXP_DBL cpe_code_smooth, cpe_code_smooth_prev;
+
+ /* cpe = (1+r_v)/8 * 2 ; ( SF = -1) */
+ cpe = (period_fac >> (2 - SF_PFAC)) + FL2FXCONST_DBL(0.25f);
+
+ /* u'(n) */
+ tmp = fMultDiv2(*exc, gain_pit) << (SF_GAIN_P + 1); /* v(0)*g_p */
+ *exc++ = tmp + (fMultDiv2(code[0], gain_code) << SF);
+
+ /* u(n) */
+ code_smooth_prev = fMultDiv2(*code++, gain_code_smoothed)
+ << SF; /* c(0) * g_sc */
+ code_i = *code++;
+ code_smooth = fMultDiv2(code_i, gain_code_smoothed) << SF; /* c(1) * g_sc */
+ tmp += code_smooth_prev; /* tmp = v(0)*g_p + c(0)*g_sc */
+ cpe_code_smooth = fMultDiv2(cpe, code_smooth);
+ *exc2++ = tmp - cpe_code_smooth;
+ cpe_code_smooth_prev = fMultDiv2(cpe, code_smooth_prev);
+
+ i = L_SUBFR - 2;
+ do /* ARM926: 22 cycles per iteration */
+ {
+ /* u'(n) */
+ tmp = fMultDiv2(*exc, gain_pit) << (SF_GAIN_P + 1);
+ *exc++ = tmp + (fMultDiv2(code_i, gain_code) << SF);
+ /* u(n) */
+ tmp += code_smooth; /* += g_sc * c(i) */
+ tmp -= cpe_code_smooth_prev;
+ cpe_code_smooth_prev = cpe_code_smooth;
+ code_i = *code++;
+ code_smooth = fMultDiv2(code_i, gain_code_smoothed) << SF;
+ cpe_code_smooth = fMultDiv2(cpe, code_smooth);
+ *exc2++ = tmp - cpe_code_smooth; /* tmp - c_pe * g_sc * c(i+1) */
+ } while (--i != 0);
+
+ /* u'(n) */
+ tmp = fMultDiv2(*exc, gain_pit) << (SF_GAIN_P + 1);
+ *exc = tmp + (fMultDiv2(code_i, gain_code) << SF);
+ /* u(n) */
+ tmp += code_smooth;
+ tmp -= cpe_code_smooth_prev;
+ *exc2++ = tmp;
+
+ return;
+}
+
+/**
+ * \brief Interpolate LPC vector in LSP domain for current subframe and convert
+ * to LP domain
+ * \param[in] lsp_old LPC vector (LSP domain) corresponding to the beginning of
+ * current ACELP frame.
+ * \param[in] lsp_new LPC vector (LSP domain) corresponding to the end of
+ * current ACELP frame.
+ * \param[in] subfr_nr number of current ACELP subframe 0..3.
+ * \param[in] nb_subfr total number of ACELP subframes in this frame.
+ * \param[out] A LP filter coefficients for current ACELP subframe, exponent =
+ * SF_A_COEFFS.
+ */
+/* static */
+void int_lpc_acelp(
+ const FIXP_LPC lsp_old[], /* input : LSPs from past frame */
+ const FIXP_LPC lsp_new[], /* input : LSPs from present frame */
+ int subfr_nr, int nb_subfr,
+ FIXP_LPC
+ A[], /* output: interpolated LP coefficients for current subframe */
+ INT *A_exp) {
+ int i;
+ FIXP_LPC lsp_interpol[M_LP_FILTER_ORDER];
+ FIXP_SGL fac_old, fac_new;
+
+ FDK_ASSERT((nb_subfr == 3) || (nb_subfr == 4));
+
+ fac_old = lsp_interpol_factor[nb_subfr & 0x1][(nb_subfr - 1) - subfr_nr];
+ fac_new = lsp_interpol_factor[nb_subfr & 0x1][subfr_nr];
+ for (i = 0; i < M_LP_FILTER_ORDER; i++) {
+ lsp_interpol[i] = FX_DBL2FX_LPC(
+ (fMultDiv2(lsp_old[i], fac_old) + fMultDiv2(lsp_new[i], fac_new)) << 1);
+ }
+
+ E_LPC_f_lsp_a_conversion(lsp_interpol, A, A_exp);
+
+ return;
+}
+
+/**
+ * \brief Perform LP synthesis by filtering the post-processed excitation u(n)
+ * through the LP synthesis filter 1/A(z)
+ * \param[in] a LP filter coefficients, exponent = SF_A_COEFFS.
+ * \param[in] length length of input/output signal.
+ * \param[in] x post-processed excitation u(n).
+ * \param[in,out] y LP synthesis signal and filter memory
+ * y[-M_LP_FILTER_ORDER..-1].
+ */
+
+/* static */
+void Syn_filt(const FIXP_LPC a[], /* (i) : a[m] prediction coefficients Q12 */
+ const INT a_exp,
+ INT length, /* (i) : length of input/output signal (64|128) */
+ FIXP_DBL x[], /* (i) : input signal Qx */
+ FIXP_DBL y[] /* (i/o) : filter states / output signal Qx-s*/
+) {
+ int i, j;
+ FIXP_DBL L_tmp;
+
+ for (i = 0; i < length; i++) {
+ L_tmp = (FIXP_DBL)0;
+
+ for (j = 0; j < M_LP_FILTER_ORDER; j++) {
+ L_tmp -= fMultDiv2(a[j], y[i - (j + 1)]) >> (LP_FILTER_SCALE - 1);
+ }
+
+ L_tmp = scaleValue(L_tmp, a_exp + LP_FILTER_SCALE);
+ y[i] = fAddSaturate(L_tmp, x[i]);
+ }
+
+ return;
+}
+
+/**
+ * \brief Calculate de-emphasis 1/(1 - mu z^-1) on input signal.
+ * \param[in] x input signal.
+ * \param[out] y output signal.
+ * \param[in] L length of signal.
+ * \param[in,out] mem memory (signal[-1]).
+ */
+/* static */
+void Deemph(FIXP_DBL *x, FIXP_DBL *y, int L, FIXP_DBL *mem) {
+ int i;
+ FIXP_DBL yi = *mem;
+
+ for (i = 0; i < L; i++) {
+ FIXP_DBL xi = x[i] >> 1;
+ xi = fMultAddDiv2(xi, PREEMPH_FAC, yi);
+ yi = SATURATE_LEFT_SHIFT(xi, 1, 32);
+ y[i] = yi;
+ }
+ *mem = yi;
+ return;
+}
+
+/**
+ * \brief Compute the LP residual by filtering the input speech through the
+ * analysis filter A(z).
+ * \param[in] a LP filter coefficients, exponent = SF_A_COEFFS
+ * \param[in] x input signal (note that values x[-m..-1] are needed), exponent =
+ * SF_SYNTH
+ * \param[out] y output signal (residual), exponent = SF_EXC
+ * \param[in] l length of filtering
+ */
+/* static */
+void E_UTIL_residu(const FIXP_LPC *a, const INT a_exp, FIXP_DBL *x, FIXP_DBL *y,
+ INT l) {
+ FIXP_DBL s;
+ INT i, j;
+
+ /* (note that values x[-m..-1] are needed) */
+ for (i = 0; i < l; i++) {
+ s = (FIXP_DBL)0;
+
+ for (j = 0; j < M_LP_FILTER_ORDER; j++) {
+ s += fMultDiv2(a[j], x[i - j - 1]) >> (LP_FILTER_SCALE - 1);
+ }
+
+ s = scaleValue(s, a_exp + LP_FILTER_SCALE);
+ y[i] = fAddSaturate(s, x[i]);
+ }
+
+ return;
+}
+
+/* use to map subfr number to number of bits used for acb_index */
+static const UCHAR num_acb_idx_bits_table[2][NB_SUBFR] = {
+ {9, 6, 9, 6}, /* coreCoderFrameLength == 1024 */
+ {9, 6, 6, 0} /* coreCoderFrameLength == 768 */
+};
+
+static int DecodePitchLag(HANDLE_FDK_BITSTREAM hBs,
+ const UCHAR num_acb_idx_bits,
+ const int PIT_MIN, /* TMIN */
+ const int PIT_FR2, /* TFR2 */
+ const int PIT_FR1, /* TFR1 */
+ const int PIT_MAX, /* TMAX */
+ int *pT0, int *pT0_frac, int *pT0_min, int *pT0_max) {
+ int acb_idx;
+ int error = 0;
+ int T0, T0_frac;
+
+ FDK_ASSERT((num_acb_idx_bits == 9) || (num_acb_idx_bits == 6));
+
+ acb_idx = FDKreadBits(hBs, num_acb_idx_bits);
+
+ if (num_acb_idx_bits == 6) {
+ /* When the pitch value is encoded on 6 bits, a pitch resolution of 1/4 is
+ always used in the range [T1-8, T1+7.75], where T1 is nearest integer to
+ the fractional pitch lag of the previous subframe.
+ */
+ T0 = *pT0_min + acb_idx / 4;
+ T0_frac = acb_idx & 0x3;
+ } else { /* num_acb_idx_bits == 9 */
+ /* When the pitch value is encoded on 9 bits, a fractional pitch delay is
+ used with resolutions 0.25 in the range [TMIN, TFR2-0.25], resolutions
+ 0.5 in the range [TFR2, TFR1-0.5], and integers only in the range [TFR1,
+ TMAX]. NOTE: for small sampling rates TMAX can get smaller than TFR1.
+ */
+ int T0_min, T0_max;
+
+ if (acb_idx < (PIT_FR2 - PIT_MIN) * 4) {
+ /* first interval with 0.25 pitch resolution */
+ T0 = PIT_MIN + (acb_idx / 4);
+ T0_frac = acb_idx & 0x3;
+ } else if (acb_idx < ((PIT_FR2 - PIT_MIN) * 4 + (PIT_FR1 - PIT_FR2) * 2)) {
+ /* second interval with 0.5 pitch resolution */
+ acb_idx -= (PIT_FR2 - PIT_MIN) * 4;
+ T0 = PIT_FR2 + (acb_idx / 2);
+ T0_frac = (acb_idx & 0x1) * 2;
+ } else {
+ /* third interval with 1.0 pitch resolution */
+ T0 = acb_idx + PIT_FR1 - ((PIT_FR2 - PIT_MIN) * 4) -
+ ((PIT_FR1 - PIT_FR2) * 2);
+ T0_frac = 0;
+ }
+ /* find T0_min and T0_max for subframe 1 or 3 */
+ T0_min = T0 - 8;
+ if (T0_min < PIT_MIN) {
+ T0_min = PIT_MIN;
+ }
+ T0_max = T0_min + 15;
+ if (T0_max > PIT_MAX) {
+ T0_max = PIT_MAX;
+ T0_min = T0_max - 15;
+ }
+ *pT0_min = T0_min;
+ *pT0_max = T0_max;
+ }
+ *pT0 = T0;
+ *pT0_frac = T0_frac;
+
+ return error;
+}
+static void ConcealPitchLag(CAcelpStaticMem *acelp_mem, const int PIT_MAX,
+ int *pT0, int *pT0_frac) {
+ USHORT *pold_T0 = &acelp_mem->old_T0;
+ UCHAR *pold_T0_frac = &acelp_mem->old_T0_frac;
+
+ if ((int)*pold_T0 >= PIT_MAX) {
+ *pold_T0 = (UCHAR)(PIT_MAX - 5);
+ }
+ *pT0 = (int)*pold_T0;
+ *pT0_frac = (int)*pold_T0_frac;
+}
+
+static UCHAR tab_coremode2nbits[8] = {20, 28, 36, 44, 52, 64, 12, 16};
+
+static int MapCoreMode2NBits(int core_mode) {
+ return (int)tab_coremode2nbits[core_mode];
+}
+
+void CLpd_AcelpDecode(CAcelpStaticMem *acelp_mem, INT i_offset,
+ const FIXP_LPC lsp_old[M_LP_FILTER_ORDER],
+ const FIXP_LPC lsp_new[M_LP_FILTER_ORDER],
+ FIXP_SGL stab_fac, CAcelpChannelData *pAcelpData,
+ INT numLostSubframes, int lastLpcLost, int frameCnt,
+ FIXP_DBL synth[], int pT[], FIXP_DBL *pit_gain,
+ INT coreCoderFrameLength) {
+ int i_subfr, subfr_nr, l_div, T;
+ int T0 = -1, T0_frac = -1; /* mark invalid */
+
+ int pit_gain_index = 0;
+
+ const int PIT_MAX = PIT_MAX_12k8 + (6 * i_offset); /* maximum pitch lag */
+
+ FIXP_COD *code;
+ FIXP_DBL *exc2;
+ FIXP_DBL *syn;
+ FIXP_DBL *exc;
+ FIXP_LPC A[M_LP_FILTER_ORDER];
+ INT A_exp;
+
+ FIXP_DBL period_fac;
+ FIXP_SGL gain_pit;
+ FIXP_DBL gain_code, gain_code_smooth, Ener_code;
+ int Ener_code_e;
+ int n;
+ int bfi = (numLostSubframes > 0) ? 1 : 0;
+
+ C_ALLOC_SCRATCH_START(
+ exc_buf, FIXP_DBL,
+ PIT_MAX_MAX + L_INTERPOL + L_DIV + 1); /* 411 + 17 + 256 + 1 = 685 */
+ C_ALLOC_SCRATCH_START(syn_buf, FIXP_DBL,
+ M_LP_FILTER_ORDER + L_DIV); /* 16 + 256 = 272 */
+ /* use same memory for code[L_SUBFR] and exc2[L_SUBFR] */
+ C_ALLOC_SCRATCH_START(tmp_buf, FIXP_DBL, L_SUBFR); /* 64 */
+ /* make sure they don't overlap if they are accessed alternatingly in
+ * BuildAdaptiveExcitation() */
+#if (COD_BITS == FRACT_BITS)
+ code = (FIXP_COD *)(tmp_buf + L_SUBFR / 2);
+#elif (COD_BITS == DFRACT_BITS)
+ code = (FIXP_COD *)tmp_buf;
+#endif
+ exc2 = (FIXP_DBL *)tmp_buf;
+
+ syn = syn_buf + M_LP_FILTER_ORDER;
+ exc = exc_buf + PIT_MAX_MAX + L_INTERPOL;
+
+ FDKmemcpy(syn_buf, acelp_mem->old_syn_mem,
+ M_LP_FILTER_ORDER * sizeof(FIXP_DBL));
+ FDKmemcpy(exc_buf, acelp_mem->old_exc_mem,
+ (PIT_MAX_MAX + L_INTERPOL) * sizeof(FIXP_DBL));
+
+ FDKmemclear(exc_buf + (PIT_MAX_MAX + L_INTERPOL),
+ (L_DIV + 1) * sizeof(FIXP_DBL));
+
+ l_div = coreCoderFrameLength / NB_DIV;
+
+ for (i_subfr = 0, subfr_nr = 0; i_subfr < l_div;
+ i_subfr += L_SUBFR, subfr_nr++) {
+ /*-------------------------------------------------*
+ * - Decode pitch lag (T0 and T0_frac) *
+ *-------------------------------------------------*/
+ if (bfi) {
+ ConcealPitchLag(acelp_mem, PIT_MAX, &T0, &T0_frac);
+ } else {
+ T0 = (int)pAcelpData->T0[subfr_nr];
+ T0_frac = (int)pAcelpData->T0_frac[subfr_nr];
+ }
+
+ /*-------------------------------------------------*
+ * - Find the pitch gain, the interpolation filter *
+ * and the adaptive codebook vector. *
+ *-------------------------------------------------*/
+ Pred_lt4(&exc[i_subfr], T0, T0_frac);
+
+ if ((!bfi && pAcelpData->ltp_filtering_flag[subfr_nr] == 0) ||
+ (bfi && numLostSubframes == 1 && stab_fac < FL2FXCONST_SGL(0.25f))) {
+ /* find pitch excitation with lp filter: v'(n) => v(n) */
+ Pred_lt4_postfilter(&exc[i_subfr]);
+ }
+
+ /*-------------------------------------------------------*
+ * - Decode innovative codebook. *
+ * - Add the fixed-gain pitch contribution to code[]. *
+ *-------------------------------------------------------*/
+ if (bfi) {
+ for (n = 0; n < L_SUBFR; n++) {
+ code[n] =
+ FX_SGL2FX_COD((FIXP_SGL)E_UTIL_random(&acelp_mem->seed_ace)) >> 4;
+ }
+ } else {
+ int nbits = MapCoreMode2NBits((int)pAcelpData->acelp_core_mode);
+ D_ACELP_decode_4t64(pAcelpData->icb_index[subfr_nr], nbits, &code[0]);
+ }
+
+ T = T0;
+ if (T0_frac > 2) {
+ T += 1;
+ }
+
+ Preemph_code(code);
+ Pit_shrp(code, T);
+
+ /* Output pitch lag for bass post-filter */
+ if (T > PIT_MAX) {
+ pT[subfr_nr] = PIT_MAX;
+ } else {
+ pT[subfr_nr] = T;
+ }
+ D_gain2_plus(
+ pAcelpData->gains[subfr_nr],
+ code, /* (i) : Innovative code vector, exponent = SF_CODE */
+ &gain_pit, /* (o) : Quantized pitch gain, exponent = SF_GAIN_P */
+ &gain_code, /* (o) : Quantized codebook gain */
+ pAcelpData
+ ->mean_energy, /* (i) : mean_ener defined in open-loop (2 bits) */
+ bfi, &acelp_mem->past_gpit, &acelp_mem->past_gcode,
+ &Ener_code, /* (o) : Innovative code vector energy */
+ &Ener_code_e); /* (o) : Innovative code vector energy exponent */
+
+ pit_gain[pit_gain_index++] = FX_SGL2FX_DBL(gain_pit);
+
+ /* calc periodicity factor r_v */
+ period_fac =
+ calc_period_factor(/* (o) : factor (-1=unvoiced to 1=voiced) */
+ &exc[i_subfr], /* (i) : pitch excitation, exponent =
+ SF_EXC */
+ gain_pit, /* (i) : gain of pitch, exponent =
+ SF_GAIN_P */
+ gain_code, /* (i) : gain of code */
+ Ener_code, /* (i) : Energy of code[] */
+ Ener_code_e); /* (i) : Exponent of energy of code[]
+ */
+
+ if (lastLpcLost && frameCnt == 0) {
+ if (gain_pit > FL2FXCONST_SGL(1.0f / (1 << SF_GAIN_P))) {
+ gain_pit = FL2FXCONST_SGL(1.0f / (1 << SF_GAIN_P));
+ }
+ }
+
+ gain_code_smooth =
+ noise_enhancer(/* (o) : smoothed gain g_sc exponent = SF_GAIN_C */
+ gain_code, /* (i) : Quantized codebook gain */
+ period_fac, /* (i) : periodicity factor (-1=unvoiced to
+ 1=voiced) */
+ stab_fac, /* (i) : stability factor (0 <= ... < 1),
+ exponent = 1 */
+ &acelp_mem->gc_threshold);
+
+ /* Compute adaptive codebook update u'(n), pitch enhancement c'(n) and
+ * post-processed excitation u(n). */
+ BuildAdaptiveExcitation(code, exc + i_subfr, gain_pit, gain_code,
+ gain_code_smooth, period_fac, exc2);
+
+ /* Interpolate filter coeffs for current subframe in lsp domain and convert
+ * to LP domain */
+ int_lpc_acelp(lsp_old, /* input : LSPs from past frame */
+ lsp_new, /* input : LSPs from present frame */
+ subfr_nr, /* input : ACELP subframe index */
+ coreCoderFrameLength / L_DIV,
+ A, /* output: LP coefficients of this subframe */
+ &A_exp);
+
+ Syn_filt(A, /* (i) : a[m] prediction coefficients */
+ A_exp, L_SUBFR, /* (i) : length */
+ exc2, /* (i) : input signal */
+ &syn[i_subfr] /* (i/o) : filter states / output signal */
+ );
+
+ } /* end of subframe loop */
+
+ /* update pitch value for bfi procedure */
+ acelp_mem->old_T0_frac = T0_frac;
+ acelp_mem->old_T0 = T0;
+
+ /* save old excitation and old synthesis memory for next ACELP frame */
+ FDKmemcpy(acelp_mem->old_exc_mem, exc + l_div - (PIT_MAX_MAX + L_INTERPOL),
+ sizeof(FIXP_DBL) * (PIT_MAX_MAX + L_INTERPOL));
+ FDKmemcpy(acelp_mem->old_syn_mem, syn_buf + l_div,
+ sizeof(FIXP_DBL) * M_LP_FILTER_ORDER);
+
+ Deemph(syn, synth, l_div,
+ &acelp_mem->de_emph_mem); /* ref soft: mem = synth[-1] */
+
+ scaleValues(synth, l_div, -ACELP_OUTSCALE);
+ acelp_mem->deemph_mem_wsyn = acelp_mem->de_emph_mem;
+
+ C_ALLOC_SCRATCH_END(tmp_buf, FIXP_DBL, L_SUBFR);
+ C_ALLOC_SCRATCH_END(syn_buf, FIXP_DBL, M_LP_FILTER_ORDER + L_DIV);
+ C_ALLOC_SCRATCH_END(exc_buf, FIXP_DBL, PIT_MAX_MAX + L_INTERPOL + L_DIV + 1);
+ return;
+}
+
+void CLpd_AcelpReset(CAcelpStaticMem *acelp) {
+ acelp->gc_threshold = (FIXP_DBL)0;
+
+ acelp->past_gpit = (FIXP_SGL)0;
+ acelp->past_gcode = (FIXP_DBL)0;
+ acelp->old_T0 = 64;
+ acelp->old_T0_frac = 0;
+ acelp->deemph_mem_wsyn = (FIXP_DBL)0;
+ acelp->wsyn_rms = (FIXP_DBL)0;
+ acelp->seed_ace = 0;
+}
+
+/* TCX time domain concealment */
+/* Compare to figure 13a on page 54 in 3GPP TS 26.290 */
+void CLpd_TcxTDConceal(CAcelpStaticMem *acelp_mem, SHORT *pitch,
+ const FIXP_LPC lsp_old[M_LP_FILTER_ORDER],
+ const FIXP_LPC lsp_new[M_LP_FILTER_ORDER],
+ const FIXP_SGL stab_fac, INT nLostSf, FIXP_DBL synth[],
+ INT coreCoderFrameLength, UCHAR last_tcx_noise_factor) {
+ /* repeat past excitation with pitch from previous decoded TCX frame */
+ C_ALLOC_SCRATCH_START(
+ exc_buf, FIXP_DBL,
+ PIT_MAX_MAX + L_INTERPOL + L_DIV); /* 411 + 17 + 256 + 1 = */
+ C_ALLOC_SCRATCH_START(syn_buf, FIXP_DBL,
+ M_LP_FILTER_ORDER + L_DIV); /* 256 + 16 = */
+ /* += */
+ FIXP_DBL ns_buf[L_DIV + 1];
+ FIXP_DBL *syn = syn_buf + M_LP_FILTER_ORDER;
+ FIXP_DBL *exc = exc_buf + PIT_MAX_MAX + L_INTERPOL;
+ FIXP_DBL *ns = ns_buf + 1;
+ FIXP_DBL tmp, fact_exc;
+ INT T = fMin(*pitch, (SHORT)PIT_MAX_MAX);
+ int i, i_subfr, subfr_nr;
+ int lDiv = coreCoderFrameLength / NB_DIV;
+
+ FDKmemcpy(syn_buf, acelp_mem->old_syn_mem,
+ M_LP_FILTER_ORDER * sizeof(FIXP_DBL));
+ FDKmemcpy(exc_buf, acelp_mem->old_exc_mem,
+ (PIT_MAX_MAX + L_INTERPOL) * sizeof(FIXP_DBL));
+
+ /* if we lost all packets (i.e. 1 packet of TCX-20 ms, 2 packets of
+ the TCX-40 ms or 4 packets of the TCX-80ms), we lost the whole
+ coded frame extrapolation strategy: repeat lost excitation and
+ use extrapolated LSFs */
+
+ /* AMR-WB+ like TCX TD concealment */
+
+ /* number of lost frame cmpt */
+ if (nLostSf < 2) {
+ fact_exc = FL2FXCONST_DBL(0.8f);
+ } else {
+ fact_exc = FL2FXCONST_DBL(0.4f);
+ }
+
+ /* repeat past excitation */
+ for (i = 0; i < lDiv; i++) {
+ exc[i] = fMult(fact_exc, exc[i - T]);
+ }
+
+ tmp = fMult(fact_exc, acelp_mem->wsyn_rms);
+ acelp_mem->wsyn_rms = tmp;
+
+ /* init deemph_mem_wsyn */
+ acelp_mem->deemph_mem_wsyn = exc[-1];
+
+ ns[-1] = acelp_mem->deemph_mem_wsyn;
+
+ for (i_subfr = 0, subfr_nr = 0; i_subfr < lDiv;
+ i_subfr += L_SUBFR, subfr_nr++) {
+ FIXP_DBL tRes[L_SUBFR];
+ FIXP_LPC A[M_LP_FILTER_ORDER];
+ INT A_exp;
+
+ /* interpolate LPC coefficients */
+ int_lpc_acelp(lsp_old, lsp_new, subfr_nr, lDiv / L_SUBFR, A, &A_exp);
+
+ Syn_filt(A, /* (i) : a[m] prediction coefficients */
+ A_exp, L_SUBFR, /* (i) : length */
+ &exc[i_subfr], /* (i) : input signal */
+ &syn[i_subfr] /* (i/o) : filter states / output signal */
+ );
+
+ E_LPC_a_weight(
+ A, A,
+ M_LP_FILTER_ORDER); /* overwrite A as it is not needed any longer */
+
+ E_UTIL_residu(A, A_exp, &syn[i_subfr], tRes, L_SUBFR);
+
+ Deemph(tRes, &ns[i_subfr], L_SUBFR, &acelp_mem->deemph_mem_wsyn);
+
+ /* Amplitude limiter (saturate at wsyn_rms) */
+ for (i = i_subfr; i < i_subfr + L_SUBFR; i++) {
+ if (ns[i] > tmp) {
+ ns[i] = tmp;
+ } else {
+ if (ns[i] < -tmp) {
+ ns[i] = -tmp;
+ }
+ }
+ }
+
+ E_UTIL_preemph(&ns[i_subfr], tRes, L_SUBFR);
+
+ Syn_filt(A, /* (i) : a[m] prediction coefficients */
+ A_exp, L_SUBFR, /* (i) : length */
+ tRes, /* (i) : input signal */
+ &syn[i_subfr] /* (i/o) : filter states / output signal */
+ );
+
+ FDKmemmove(&synth[i_subfr], &syn[i_subfr], L_SUBFR * sizeof(FIXP_DBL));
+ }
+
+ /* save old excitation and old synthesis memory for next ACELP frame */
+ FDKmemcpy(acelp_mem->old_exc_mem, exc + lDiv - (PIT_MAX_MAX + L_INTERPOL),
+ sizeof(FIXP_DBL) * (PIT_MAX_MAX + L_INTERPOL));
+ FDKmemcpy(acelp_mem->old_syn_mem, syn_buf + lDiv,
+ sizeof(FIXP_DBL) * M_LP_FILTER_ORDER);
+ acelp_mem->de_emph_mem = acelp_mem->deemph_mem_wsyn;
+
+ C_ALLOC_SCRATCH_END(syn_buf, FIXP_DBL, M_LP_FILTER_ORDER + L_DIV);
+ C_ALLOC_SCRATCH_END(exc_buf, FIXP_DBL, PIT_MAX_MAX + L_INTERPOL + L_DIV);
+}
+
+void Acelp_PreProcessing(FIXP_DBL *synth_buf, FIXP_DBL *old_synth, INT *pitch,
+ INT *old_T_pf, FIXP_DBL *pit_gain,
+ FIXP_DBL *old_gain_pf, INT samplingRate, INT *i_offset,
+ INT coreCoderFrameLength, INT synSfd,
+ INT nbSubfrSuperfr) {
+ int n;
+
+ /* init beginning of synth_buf with old synthesis from previous frame */
+ FDKmemcpy(synth_buf, old_synth, sizeof(FIXP_DBL) * (PIT_MAX_MAX - BPF_DELAY));
+
+ /* calculate pitch lag offset for ACELP decoder */
+ *i_offset =
+ (samplingRate * PIT_MIN_12k8 + (FSCALE_DENOM / 2)) / FSCALE_DENOM -
+ PIT_MIN_12k8;
+
+ /* for bass postfilter */
+ for (n = 0; n < synSfd; n++) {
+ pitch[n] = old_T_pf[n];
+ pit_gain[n] = old_gain_pf[n];
+ }
+ for (n = 0; n < nbSubfrSuperfr; n++) {
+ pitch[n + synSfd] = L_SUBFR;
+ pit_gain[n + synSfd] = (FIXP_DBL)0;
+ }
+}
+
+void Acelp_PostProcessing(FIXP_DBL *synth_buf, FIXP_DBL *old_synth, INT *pitch,
+ INT *old_T_pf, INT coreCoderFrameLength, INT synSfd,
+ INT nbSubfrSuperfr) {
+ int n;
+
+ /* store last part of synth_buf (which is not handled by the IMDCT overlap)
+ * for next frame */
+ FDKmemcpy(old_synth, synth_buf + coreCoderFrameLength,
+ sizeof(FIXP_DBL) * (PIT_MAX_MAX - BPF_DELAY));
+
+ /* for bass postfilter */
+ for (n = 0; n < synSfd; n++) {
+ old_T_pf[n] = pitch[nbSubfrSuperfr + n];
+ }
+}
+
+#define L_FAC_ZIR (LFAC)
+
+void CLpd_Acelp_Zir(const FIXP_LPC A[], const INT A_exp,
+ CAcelpStaticMem *acelp_mem, const INT length,
+ FIXP_DBL zir[], int doDeemph) {
+ C_ALLOC_SCRATCH_START(tmp_buf, FIXP_DBL, L_FAC_ZIR + M_LP_FILTER_ORDER);
+ FDK_ASSERT(length <= L_FAC_ZIR);
+
+ FDKmemcpy(tmp_buf, acelp_mem->old_syn_mem,
+ M_LP_FILTER_ORDER * sizeof(FIXP_DBL));
+ FDKmemset(tmp_buf + M_LP_FILTER_ORDER, 0, L_FAC_ZIR * sizeof(FIXP_DBL));
+
+ Syn_filt(A, A_exp, length, &tmp_buf[M_LP_FILTER_ORDER],
+ &tmp_buf[M_LP_FILTER_ORDER]);
+ if (!doDeemph) {
+ /* if last lpd mode was TD concealment, then bypass deemph */
+ FDKmemcpy(zir, tmp_buf, length * sizeof(*zir));
+ } else {
+ Deemph(&tmp_buf[M_LP_FILTER_ORDER], &zir[0], length,
+ &acelp_mem->de_emph_mem);
+ scaleValues(zir, length, -ACELP_OUTSCALE);
+ }
+ C_ALLOC_SCRATCH_END(tmp_buf, FIXP_DBL, L_FAC_ZIR + M_LP_FILTER_ORDER);
+}
+
+void CLpd_AcelpPrepareInternalMem(const FIXP_DBL *synth, UCHAR last_lpd_mode,
+ UCHAR last_last_lpd_mode,
+ const FIXP_LPC *A_new, const INT A_new_exp,
+ const FIXP_LPC *A_old, const INT A_old_exp,
+ CAcelpStaticMem *acelp_mem,
+ INT coreCoderFrameLength, INT clearOldExc,
+ UCHAR lpd_mode) {
+ int l_div =
+ coreCoderFrameLength / NB_DIV; /* length of one ACELP/TCX20 frame */
+ int l_div_partial;
+ FIXP_DBL *syn, *old_exc_mem;
+
+ C_ALLOC_SCRATCH_START(synth_buf, FIXP_DBL,
+ PIT_MAX_MAX + L_INTERPOL + M_LP_FILTER_ORDER);
+ syn = &synth_buf[M_LP_FILTER_ORDER];
+
+ l_div_partial = PIT_MAX_MAX + L_INTERPOL - l_div;
+ old_exc_mem = acelp_mem->old_exc_mem;
+
+ if (lpd_mode == 4) {
+ /* Bypass Domain conversion. TCXTD Concealment does no deemphasis in the
+ * end. */
+ FDKmemcpy(
+ synth_buf, &synth[-(PIT_MAX_MAX + L_INTERPOL + M_LP_FILTER_ORDER)],
+ (PIT_MAX_MAX + L_INTERPOL + M_LP_FILTER_ORDER) * sizeof(FIXP_DBL));
+ /* Set deemphasis memory state for TD concealment */
+ acelp_mem->deemph_mem_wsyn = scaleValueSaturate(synth[-1], ACELP_OUTSCALE);
+ } else {
+ /* convert past [PIT_MAX_MAX+L_INTERPOL+M_LP_FILTER_ORDER] synthesis to
+ * preemph domain */
+ E_UTIL_preemph(&synth[-(PIT_MAX_MAX + L_INTERPOL + M_LP_FILTER_ORDER)],
+ synth_buf, PIT_MAX_MAX + L_INTERPOL + M_LP_FILTER_ORDER);
+ scaleValuesSaturate(synth_buf, PIT_MAX_MAX + L_INTERPOL + M_LP_FILTER_ORDER,
+ ACELP_OUTSCALE);
+ }
+
+ /* Set deemphasis memory state */
+ acelp_mem->de_emph_mem = scaleValueSaturate(synth[-1], ACELP_OUTSCALE);
+
+ /* update acelp synth filter memory */
+ FDKmemcpy(acelp_mem->old_syn_mem,
+ &syn[PIT_MAX_MAX + L_INTERPOL - M_LP_FILTER_ORDER],
+ M_LP_FILTER_ORDER * sizeof(FIXP_DBL));
+
+ if (clearOldExc) {
+ FDKmemclear(old_exc_mem, (PIT_MAX_MAX + L_INTERPOL) * sizeof(FIXP_DBL));
+ C_ALLOC_SCRATCH_END(synth_buf, FIXP_DBL,
+ PIT_MAX_MAX + L_INTERPOL + M_LP_FILTER_ORDER);
+ return;
+ }
+
+ /* update past [PIT_MAX_MAX+L_INTERPOL] samples of exc memory */
+ if (last_lpd_mode == 1) { /* last frame was TCX20 */
+ if (last_last_lpd_mode == 0) { /* ACELP -> TCX20 -> ACELP transition */
+ /* Delay valid part of excitation buffer (from previous ACELP frame) by
+ * l_div samples */
+ FDKmemmove(old_exc_mem, old_exc_mem + l_div,
+ sizeof(FIXP_DBL) * l_div_partial);
+ } else if (last_last_lpd_mode > 0) { /* TCX -> TCX20 -> ACELP transition */
+ E_UTIL_residu(A_old, A_old_exp, syn, old_exc_mem, l_div_partial);
+ }
+ E_UTIL_residu(A_new, A_new_exp, syn + l_div_partial,
+ old_exc_mem + l_div_partial, l_div);
+ } else { /* prev frame was FD, TCX40 or TCX80 */
+ int exc_A_new_length = (coreCoderFrameLength / 2 > PIT_MAX_MAX + L_INTERPOL)
+ ? PIT_MAX_MAX + L_INTERPOL
+ : coreCoderFrameLength / 2;
+ int exc_A_old_length = PIT_MAX_MAX + L_INTERPOL - exc_A_new_length;
+ E_UTIL_residu(A_old, A_old_exp, syn, old_exc_mem, exc_A_old_length);
+ E_UTIL_residu(A_new, A_new_exp, &syn[exc_A_old_length],
+ &old_exc_mem[exc_A_old_length], exc_A_new_length);
+ }
+ C_ALLOC_SCRATCH_END(synth_buf, FIXP_DBL,
+ PIT_MAX_MAX + L_INTERPOL + M_LP_FILTER_ORDER);
+
+ return;
+}
+
+FIXP_DBL *CLpd_ACELP_GetFreeExcMem(CAcelpStaticMem *acelp_mem, INT length) {
+ FDK_ASSERT(length <= PIT_MAX_MAX + L_INTERPOL);
+ return acelp_mem->old_exc_mem;
+}
+
+INT CLpd_AcelpRead(HANDLE_FDK_BITSTREAM hBs, CAcelpChannelData *acelp,
+ INT acelp_core_mode, INT coreCoderFrameLength,
+ INT i_offset) {
+ int nb_subfr = coreCoderFrameLength / L_DIV;
+ const UCHAR *num_acb_index_bits =
+ (nb_subfr == 4) ? num_acb_idx_bits_table[0] : num_acb_idx_bits_table[1];
+ int nbits;
+ int error = 0;
+
+ const int PIT_MIN = PIT_MIN_12k8 + i_offset;
+ const int PIT_FR2 = PIT_FR2_12k8 - i_offset;
+ const int PIT_FR1 = PIT_FR1_12k8;
+ const int PIT_MAX = PIT_MAX_12k8 + (6 * i_offset);
+ int T0, T0_frac, T0_min = 0, T0_max;
+
+ if (PIT_MAX > PIT_MAX_MAX) {
+ error = AAC_DEC_DECODE_FRAME_ERROR;
+ goto bail;
+ }
+
+ acelp->acelp_core_mode = acelp_core_mode;
+
+ nbits = MapCoreMode2NBits(acelp_core_mode);
+
+ /* decode mean energy with 2 bits : 18, 30, 42 or 54 dB */
+ acelp->mean_energy = FDKreadBits(hBs, 2);
+
+ for (int sfr = 0; sfr < nb_subfr; sfr++) {
+ /* read ACB index and store T0 and T0_frac for each ACELP subframe. */
+ error = DecodePitchLag(hBs, num_acb_index_bits[sfr], PIT_MIN, PIT_FR2,
+ PIT_FR1, PIT_MAX, &T0, &T0_frac, &T0_min, &T0_max);
+ if (error) {
+ goto bail;
+ }
+ acelp->T0[sfr] = (USHORT)T0;
+ acelp->T0_frac[sfr] = (UCHAR)T0_frac;
+ acelp->ltp_filtering_flag[sfr] = FDKreadBits(hBs, 1);
+ switch (nbits) {
+ case 12: /* 12 bits AMR-WB codebook is used */
+ acelp->icb_index[sfr][0] = FDKreadBits(hBs, 1);
+ acelp->icb_index[sfr][1] = FDKreadBits(hBs, 5);
+ acelp->icb_index[sfr][2] = FDKreadBits(hBs, 1);
+ acelp->icb_index[sfr][3] = FDKreadBits(hBs, 5);
+ break;
+ case 16: /* 16 bits AMR-WB codebook is used */
+ acelp->icb_index[sfr][0] = FDKreadBits(hBs, 1);
+ acelp->icb_index[sfr][1] = FDKreadBits(hBs, 5);
+ acelp->icb_index[sfr][2] = FDKreadBits(hBs, 5);
+ acelp->icb_index[sfr][3] = FDKreadBits(hBs, 5);
+ break;
+ case 20: /* 20 bits AMR-WB codebook is used */
+ acelp->icb_index[sfr][0] = FDKreadBits(hBs, 5);
+ acelp->icb_index[sfr][1] = FDKreadBits(hBs, 5);
+ acelp->icb_index[sfr][2] = FDKreadBits(hBs, 5);
+ acelp->icb_index[sfr][3] = FDKreadBits(hBs, 5);
+ break;
+ case 28: /* 28 bits AMR-WB codebook is used */
+ acelp->icb_index[sfr][0] = FDKreadBits(hBs, 9);
+ acelp->icb_index[sfr][1] = FDKreadBits(hBs, 9);
+ acelp->icb_index[sfr][2] = FDKreadBits(hBs, 5);
+ acelp->icb_index[sfr][3] = FDKreadBits(hBs, 5);
+ break;
+ case 36: /* 36 bits AMR-WB codebook is used */
+ acelp->icb_index[sfr][0] = FDKreadBits(hBs, 9);
+ acelp->icb_index[sfr][1] = FDKreadBits(hBs, 9);
+ acelp->icb_index[sfr][2] = FDKreadBits(hBs, 9);
+ acelp->icb_index[sfr][3] = FDKreadBits(hBs, 9);
+ break;
+ case 44: /* 44 bits AMR-WB codebook is used */
+ acelp->icb_index[sfr][0] = FDKreadBits(hBs, 13);
+ acelp->icb_index[sfr][1] = FDKreadBits(hBs, 13);
+ acelp->icb_index[sfr][2] = FDKreadBits(hBs, 9);
+ acelp->icb_index[sfr][3] = FDKreadBits(hBs, 9);
+ break;
+ case 52: /* 52 bits AMR-WB codebook is used */
+ acelp->icb_index[sfr][0] = FDKreadBits(hBs, 13);
+ acelp->icb_index[sfr][1] = FDKreadBits(hBs, 13);
+ acelp->icb_index[sfr][2] = FDKreadBits(hBs, 13);
+ acelp->icb_index[sfr][3] = FDKreadBits(hBs, 13);
+ break;
+ case 64: /* 64 bits AMR-WB codebook is used */
+ acelp->icb_index[sfr][0] = FDKreadBits(hBs, 2);
+ acelp->icb_index[sfr][1] = FDKreadBits(hBs, 2);
+ acelp->icb_index[sfr][2] = FDKreadBits(hBs, 2);
+ acelp->icb_index[sfr][3] = FDKreadBits(hBs, 2);
+ acelp->icb_index[sfr][4] = FDKreadBits(hBs, 14);
+ acelp->icb_index[sfr][5] = FDKreadBits(hBs, 14);
+ acelp->icb_index[sfr][6] = FDKreadBits(hBs, 14);
+ acelp->icb_index[sfr][7] = FDKreadBits(hBs, 14);
+ break;
+ default:
+ FDK_ASSERT(0);
+ break;
+ }
+ acelp->gains[sfr] = FDKreadBits(hBs, 7);
+ }
+
+bail:
+ return error;
+}