| /* ----------------------------------------------------------------------------- |
| 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): Manuel Jander |
| |
| Description: USAC Linear Prediction Domain coding |
| |
| *******************************************************************************/ |
| |
| #include "usacdec_lpd.h" |
| |
| #include "usacdec_rom.h" |
| #include "usacdec_fac.h" |
| #include "usacdec_lpc.h" |
| #include "FDK_tools_rom.h" |
| #include "fft.h" |
| #include "mdct.h" |
| #include "usacdec_acelp.h" |
| #include "overlapadd.h" |
| |
| #include "conceal.h" |
| |
| #include "block.h" |
| |
| #define SF_PITCH_TRACK 6 |
| #define SF_GAIN 3 |
| #define MIN_VAL FL2FXCONST_DBL(0.0f) |
| #define MAX_VAL (FIXP_DBL) MAXVAL_DBL |
| |
| #include "ac_arith_coder.h" |
| |
| void filtLP(const FIXP_DBL *syn, FIXP_PCM *syn_out, FIXP_DBL *noise, |
| const FIXP_SGL *filt, INT stop, int len) { |
| INT i, j; |
| FIXP_DBL tmp; |
| |
| for (i = 0; i < stop; i++) { |
| tmp = fMultDiv2(noise[i], filt[0]); // Filt in Q-1.16 |
| for (j = 1; j <= len; j++) { |
| tmp += fMultDiv2((noise[i - j] + noise[i + j]), filt[j]); |
| } |
| syn_out[i] = (FIXP_PCM)(IMDCT_SCALE(syn[i] - tmp)); |
| } |
| } |
| |
| void bass_pf_1sf_delay( |
| FIXP_DBL *syn, /* (i) : 12.8kHz synthesis to postfilter */ |
| const INT *T_sf, /* (i) : Pitch period for all subframes (T_sf[16]) */ |
| FIXP_DBL *pit_gain, |
| const int frame_length, /* (i) : frame length (should be 768|1024) */ |
| const INT l_frame, |
| const INT l_next, /* (i) : look ahead for symmetric filtering */ |
| FIXP_PCM *synth_out, /* (o) : filtered synthesis (with delay of 1 subfr) */ |
| FIXP_DBL mem_bpf[]) /* i/o : memory state [L_FILT+L_SUBFR] */ |
| { |
| INT i, sf, i_subfr, T, T2, lg; |
| |
| FIXP_DBL tmp, ener, corr, gain; |
| FIXP_DBL *noise, *noise_in; |
| FIXP_DBL |
| noise_buf[L_FILT + (2 * L_SUBFR)]; // L_FILT = 12, L_SUBFR = 64 => 140 |
| const FIXP_DBL *x, *y; |
| |
| { |
| noise = noise_buf + L_FILT; // L_FILT = 12 delay of upsampling filter |
| noise_in = noise_buf + L_FILT + L_SUBFR; |
| /* Input scaling of the BPF memory */ |
| scaleValues(mem_bpf, (L_FILT + L_SUBFR), 1); |
| } |
| |
| int gain_exp = 17; |
| |
| sf = 0; |
| for (i_subfr = 0; i_subfr < l_frame; i_subfr += L_SUBFR, sf++) { |
| T = T_sf[sf]; |
| gain = pit_gain[sf]; |
| |
| /* Gain is in Q17.14 */ |
| /* If gain > 1 set to 1 */ |
| if (gain > (FIXP_DBL)(1 << 14)) gain = (FIXP_DBL)(1 << 14); |
| |
| /* If gain < 0 set to 0 */ |
| if (gain < (FIXP_DBL)0) gain = (FIXP_DBL)0; |
| |
| if (gain > (FIXP_DBL)0) { |
| /* pitch tracker: test pitch/2 to avoid continuous pitch doubling */ |
| /* Note: pitch is limited to PIT_MIN (34 = 376Hz) at the encoder */ |
| T2 = T >> 1; |
| x = &syn[i_subfr - L_EXTRA]; |
| y = &syn[i_subfr - T2 - L_EXTRA]; |
| |
| ener = (FIXP_DBL)0; |
| corr = (FIXP_DBL)0; |
| tmp = (FIXP_DBL)0; |
| |
| int headroom_x = getScalefactor(x, L_SUBFR + L_EXTRA); |
| int headroom_y = getScalefactor(y, L_SUBFR + L_EXTRA); |
| |
| int width_shift = 7; |
| |
| for (i = 0; i < (L_SUBFR + L_EXTRA); i++) { |
| ener += fPow2Div2((x[i] << headroom_x)) >> width_shift; |
| corr += fMultDiv2((x[i] << headroom_x), (y[i] << headroom_y)) >> |
| width_shift; |
| tmp += fPow2Div2((y[i] << headroom_y)) >> width_shift; |
| } |
| |
| int exp_ener = ((17 - headroom_x) << 1) + width_shift + 1; |
| int exp_corr = (17 - headroom_x) + (17 - headroom_y) + width_shift + 1; |
| int exp_tmp = ((17 - headroom_y) << 1) + width_shift + 1; |
| |
| /* Add 0.01 to "ener". Adjust exponents */ |
| FIXP_DBL point_zero_one = (FIXP_DBL)0x51eb851f; /* In Q-6.37 */ |
| int diff; |
| ener = fAddNorm(ener, exp_ener, point_zero_one, -6, &exp_ener); |
| corr = fAddNorm(corr, exp_corr, point_zero_one, -6, &exp_corr); |
| tmp = fAddNorm(tmp, exp_tmp, point_zero_one, -6, &exp_tmp); |
| |
| /* use T2 if normalized correlation > 0.95 */ |
| INT s1, s2; |
| s1 = CntLeadingZeros(ener) - 1; |
| s2 = CntLeadingZeros(tmp) - 1; |
| |
| FIXP_DBL ener_by_tmp = fMultDiv2(ener << s1, tmp << s2); |
| int ener_by_tmp_exp = (exp_ener - s1) + (exp_tmp - s2) + 1; |
| |
| if (ener_by_tmp_exp & 1) { |
| ener_by_tmp <<= 1; |
| ener_by_tmp_exp -= 1; |
| } |
| |
| int temp_exp = 0; |
| |
| FIXP_DBL temp1 = invSqrtNorm2(ener_by_tmp, &temp_exp); |
| |
| int temp1_exp = temp_exp - (ener_by_tmp_exp >> 1); |
| |
| FIXP_DBL tmp_result = fMult(corr, temp1); |
| |
| int tmp_result_exp = exp_corr + temp1_exp; |
| |
| diff = tmp_result_exp - 0; |
| FIXP_DBL point95 = FL2FXCONST_DBL(0.95f); |
| if (diff >= 0) { |
| diff = fMin(diff, 31); |
| point95 = FL2FXCONST_DBL(0.95f) >> diff; |
| } else { |
| diff = fMax(diff, -31); |
| tmp_result >>= (-diff); |
| } |
| |
| if (tmp_result > point95) T = T2; |
| |
| /* prevent that noise calculation below reaches into not defined signal |
| parts at the end of the synth_buf or in other words restrict the below |
| used index (i+i_subfr+T) < l_frame + l_next |
| */ |
| lg = l_frame + l_next - T - i_subfr; |
| |
| if (lg > L_SUBFR) |
| lg = L_SUBFR; |
| else if (lg < 0) |
| lg = 0; |
| |
| /* limit gain to avoid problem on burst */ |
| if (lg > 0) { |
| FIXP_DBL tmp1; |
| |
| /* max(lg) = 64 => scale with 6 bits minus 1 (fPow2Div2) */ |
| |
| s1 = getScalefactor(&syn[i_subfr], lg); |
| s2 = getScalefactor(&syn[i_subfr + T], lg); |
| INT s = fixMin(s1, s2); |
| |
| tmp = (FIXP_DBL)0; |
| ener = (FIXP_DBL)0; |
| for (i = 0; i < lg; i++) { |
| tmp += fPow2Div2(syn[i + i_subfr] << s1) >> (SF_PITCH_TRACK); |
| ener += fPow2Div2(syn[i + i_subfr + T] << s2) >> (SF_PITCH_TRACK); |
| } |
| tmp = tmp >> fMin(DFRACT_BITS - 1, (2 * (s1 - s))); |
| ener = ener >> fMin(DFRACT_BITS - 1, (2 * (s2 - s))); |
| |
| /* error robustness: for the specific case syn[...] == -1.0f for all 64 |
| samples ener or tmp might overflow and become negative. For all sane |
| cases we have enough headroom. |
| */ |
| if (ener <= (FIXP_DBL)0) { |
| ener = (FIXP_DBL)1; |
| } |
| if (tmp <= (FIXP_DBL)0) { |
| tmp = (FIXP_DBL)1; |
| } |
| FDK_ASSERT(ener > (FIXP_DBL)0); |
| |
| /* tmp = sqrt(tmp/ener) */ |
| int result_e = 0; |
| tmp1 = fDivNorm(tmp, ener, &result_e); |
| if (result_e & 1) { |
| tmp1 >>= 1; |
| result_e += 1; |
| } |
| tmp = sqrtFixp(tmp1); |
| result_e >>= 1; |
| |
| gain_exp = 17; |
| |
| diff = result_e - gain_exp; |
| |
| FIXP_DBL gain1 = gain; |
| |
| if (diff >= 0) { |
| diff = fMin(diff, 31); |
| gain1 >>= diff; |
| } else { |
| result_e += (-diff); |
| diff = fMax(diff, -31); |
| tmp >>= (-diff); |
| } |
| |
| if (tmp < gain1) { |
| gain = tmp; |
| gain_exp = result_e; |
| } |
| } |
| |
| /* calculate noise based on voiced pitch */ |
| /* fMultDiv2() replaces weighting of gain with 0.5 */ |
| diff = gain_exp - 17; |
| if (diff >= 0) { |
| gain <<= diff; |
| } else { |
| gain >>= (-diff); |
| } |
| |
| s1 = CntLeadingZeros(gain) - 1; |
| s1 -= 16; /* Leading bits for SGL */ |
| |
| FIXP_SGL gainSGL = FX_DBL2FX_SGL(gain << 16); |
| |
| gainSGL = gainSGL << s1; |
| |
| { |
| for (i = 0; i < lg; i++) { |
| /* scaled with SF_SYNTH + gain_sf + 1 */ |
| noise_in[i] = |
| (fMult(gainSGL, syn[i + i_subfr] - (syn[i + i_subfr - T] >> 1) - |
| (syn[i + i_subfr + T] >> 1))) >> |
| s1; |
| } |
| |
| for (i = lg; i < L_SUBFR; i++) { |
| /* scaled with SF_SYNTH + gain_sf + 1 */ |
| noise_in[i] = |
| (fMult(gainSGL, syn[i + i_subfr] - syn[i + i_subfr - T])) >> s1; |
| } |
| } |
| } else { |
| FDKmemset(noise_in, (FIXP_DBL)0, L_SUBFR * sizeof(FIXP_DBL)); |
| } |
| |
| { |
| FDKmemcpy(noise_buf, mem_bpf, (L_FILT + L_SUBFR) * sizeof(FIXP_DBL)); |
| |
| FDKmemcpy(mem_bpf, noise_buf + L_SUBFR, |
| (L_FILT + L_SUBFR) * sizeof(FIXP_DBL)); |
| } |
| |
| /* substract from voiced speech low-pass filtered noise */ |
| /* filter coefficients are scaled with factor SF_FILT_LP (1) */ |
| |
| { |
| filtLP(&syn[i_subfr - L_SUBFR], &synth_out[i_subfr], noise, |
| fdk_dec_filt_lp, L_SUBFR, L_FILT); |
| } |
| } |
| |
| { |
| |
| } |
| |
| // To be determined (info from Ben) |
| { |
| /* Output scaling of the BPF memory */ |
| scaleValues(mem_bpf, (L_FILT + L_SUBFR), -1); |
| /* Copy the rest of the signal (after the fac) */ |
| scaleValuesSaturate((FIXP_PCM *)&synth_out[l_frame], |
| (FIXP_DBL *)&syn[l_frame - L_SUBFR], |
| (frame_length - l_frame), MDCT_OUT_HEADROOM); |
| } |
| |
| return; |
| } |
| |
| /* |
| * Frequency Domain Noise Shaping |
| */ |
| |
| /** |
| * \brief Adaptive Low Frequencies Deemphasis of spectral coefficients. |
| * |
| * Ensure quantization of low frequencies in case where the |
| * signal dynamic is higher than the LPC noise shaping. |
| * This is the inverse operation of adap_low_freq_emph(). |
| * Output gain of all blocks. |
| * |
| * \param x pointer to the spectral coefficients, requires 1 bit headroom. |
| * \param lg length of x. |
| * \param bUseNewAlfe if set, apply ALFD for fullband lpd. |
| * \param gainLpc1 pointer to gain based on old input LPC coefficients. |
| * \param gainLpc2 pointer to gain based on new input LPC coefficients. |
| * \param alfd_gains pointer to output gains. |
| * \param s current scale shift factor of x. |
| */ |
| #define ALFDPOW2_SCALE 3 |
| /*static*/ |
| void CLpd_AdaptLowFreqDeemph(FIXP_DBL x[], int lg, FIXP_DBL alfd_gains[], |
| INT s) { |
| { |
| int i, j, k, i_max; |
| FIXP_DBL max, fac; |
| /* Note: This stack array saves temporary accumulation results to be used in |
| * a second run */ |
| /* The size should be limited to (1024/4)/8=32 */ |
| FIXP_DBL tmp_pow2[32]; |
| |
| s = s * 2 + ALFDPOW2_SCALE; |
| |
| k = 8; |
| i_max = lg / 4; /* ALFD range = 1600Hz (lg = 6400Hz) */ |
| |
| /* find spectral peak */ |
| max = FL2FX_DBL(0.01f) >> s; |
| for (i = 0; i < i_max; i += k) { |
| FIXP_DBL tmp; |
| |
| tmp = FIXP_DBL(0); |
| FIXP_DBL *pX = &x[i]; |
| |
| j = 8; |
| do { |
| FIXP_DBL x0 = *pX++; |
| FIXP_DBL x1 = *pX++; |
| x0 = fPow2Div2(x0); |
| x1 = fPow2Div2(x1); |
| tmp = tmp + (x0 >> (ALFDPOW2_SCALE - 1)); |
| tmp = tmp + (x1 >> (ALFDPOW2_SCALE - 1)); |
| } while ((j = j - 2) != 0); |
| tmp = fMax(tmp, (FL2FX_DBL(0.01f) >> s)); |
| tmp_pow2[i >> 3] = tmp; |
| if (tmp > max) { |
| max = tmp; |
| } |
| } |
| |
| /* deemphasis of all blocks below the peak */ |
| fac = FL2FX_DBL(0.1f) >> 1; |
| for (i = 0; i < i_max; i += k) { |
| FIXP_DBL tmp; |
| INT shifti; |
| |
| tmp = tmp_pow2[i >> 3]; |
| |
| /* tmp = (float)sqrt(tmp/max); */ |
| |
| /* value of tmp is between 8/2*max^2 and max^2 / 2. */ |
| /* required shift factor of division can grow up to 27 |
| (grows exponentially for values toward zero) |
| thus using normalized division to assure valid result. */ |
| { |
| INT sd; |
| |
| if (tmp != (FIXP_DBL)0) { |
| tmp = fDivNorm(max, tmp, &sd); |
| if (sd & 1) { |
| sd++; |
| tmp >>= 1; |
| } |
| } else { |
| tmp = (FIXP_DBL)MAXVAL_DBL; |
| sd = 0; |
| } |
| tmp = invSqrtNorm2(tmp, &shifti); |
| tmp = scaleValue(tmp, shifti - 1 - (sd / 2)); |
| } |
| if (tmp > fac) { |
| fac = tmp; |
| } |
| FIXP_DBL *pX = &x[i]; |
| |
| j = 8; |
| do { |
| FIXP_DBL x0 = pX[0]; |
| FIXP_DBL x1 = pX[1]; |
| x0 = fMultDiv2(x0, fac); |
| x1 = fMultDiv2(x1, fac); |
| x0 = x0 << 2; |
| x1 = x1 << 2; |
| *pX++ = x0; |
| *pX++ = x1; |
| |
| } while ((j = j - 2) != 0); |
| /* Store gains for FAC */ |
| *alfd_gains++ = fac; |
| } |
| } |
| } |
| |
| /** |
| * \brief Interpolated Noise Shaping for mdct coefficients. |
| * This algorithm shapes temporally the spectral noise between |
| * the two spectral noise represention (FDNS_NPTS of resolution). |
| * The noise is shaped monotonically between the two points |
| * using a curved shape to favor the lower gain in mid-frame. |
| * ODFT and amplitud calculation are applied to the 2 LPC coefficients first. |
| * |
| * \param r pointer to spectrum data. |
| * \param rms RMS of output spectrum. |
| * \param lg length of r. |
| * \param A1 pointer to old input LPC coefficients of length M_LP_FILTER_ORDER |
| * scaled by SF_A_COEFFS. |
| * \param A2 pointer to new input LPC coefficients of length M_LP_FILTER_ORDER |
| * scaled by SF_A_COEFFS. |
| * \param bLpc2Mdct flags control lpc2mdct conversion and noise shaping. |
| * \param gainLpc1 pointer to gain based on old input LPC coefficients. |
| * \param gainLpc2 pointer to gain based on new input LPC coefficients. |
| * \param gLpc_e pointer to exponent of gainLpc1 and gainLpc2. |
| */ |
| /* static */ |
| #define NSHAPE_SCALE (4) |
| |
| #define LPC2MDCT_CALC (1) |
| #define LPC2MDCT_GAIN_LOAD (2) |
| #define LPC2MDCT_GAIN_SAVE (4) |
| #define LPC2MDCT_APPLY_NSHAPE (8) |
| |
| void lpc2mdctAndNoiseShaping(FIXP_DBL *r, SHORT *pScale, const INT lg, |
| const INT fdns_npts, const FIXP_LPC *A1, |
| const INT A1_exp, const FIXP_LPC *A2, |
| const INT A2_exp) { |
| FIXP_DBL *tmp2 = NULL; |
| FIXP_DBL rr_minus_one; |
| int i, k, s, step; |
| |
| C_AALLOC_SCRATCH_START(tmp1, FIXP_DBL, FDNS_NPTS * 8) |
| |
| { |
| tmp2 = tmp1 + fdns_npts * 4; |
| |
| /* lpc2mdct() */ |
| |
| /* ODFT. E_LPC_a_weight() for A1 and A2 vectors is included into the loop |
| * below. */ |
| FIXP_DBL f = FL2FXCONST_DBL(0.92f); |
| |
| const FIXP_STP *SinTab; |
| int k_step; |
| /* needed values: sin(phi), cos(phi); phi = i*PI/(2*fdns_npts), i = 0 ... |
| * M_LP_FILTER_ORDER */ |
| switch (fdns_npts) { |
| case 64: |
| SinTab = SineTable512; |
| k_step = (512 / 64); |
| FDK_ASSERT(512 >= 64); |
| break; |
| case 48: |
| SinTab = SineTable384; |
| k_step = 384 / 48; |
| FDK_ASSERT(384 >= 48); |
| break; |
| default: |
| FDK_ASSERT(0); |
| return; |
| } |
| |
| for (i = 0, k = k_step; i < M_LP_FILTER_ORDER; i++, k += k_step) { |
| FIXP_STP cs = SinTab[k]; |
| FIXP_DBL wA1, wA2; |
| |
| wA1 = fMult(A1[i], f); |
| wA2 = fMult(A2[i], f); |
| |
| /* r[i] = A[i]*cos() */ |
| tmp1[2 + i * 2] = fMult(wA1, cs.v.re); |
| tmp2[2 + i * 2] = fMult(wA2, cs.v.re); |
| /* i[i] = A[i]*sin() */ |
| tmp1[3 + i * 2] = -fMult(wA1, cs.v.im); |
| tmp2[3 + i * 2] = -fMult(wA2, cs.v.im); |
| |
| f = fMult(f, FL2FXCONST_DBL(0.92f)); |
| } |
| |
| /* Guarantee at least 2 bits of headroom for the FFT */ |
| /* "3" stands for 1.0 with 2 bits of headroom; (A1_exp + 2) guarantess 2 |
| * bits of headroom if A1_exp > 1 */ |
| int A1_exp_fix = fMax(3, A1_exp + 2); |
| int A2_exp_fix = fMax(3, A2_exp + 2); |
| |
| /* Set 1.0 in the proper format */ |
| tmp1[0] = (FIXP_DBL)(INT)((ULONG)0x80000000 >> A1_exp_fix); |
| tmp2[0] = (FIXP_DBL)(INT)((ULONG)0x80000000 >> A2_exp_fix); |
| |
| tmp1[1] = tmp2[1] = (FIXP_DBL)0; |
| |
| /* Clear the resto of the array */ |
| FDKmemclear( |
| tmp1 + 2 * (M_LP_FILTER_ORDER + 1), |
| 2 * (fdns_npts * 2 - (M_LP_FILTER_ORDER + 1)) * sizeof(FIXP_DBL)); |
| FDKmemclear( |
| tmp2 + 2 * (M_LP_FILTER_ORDER + 1), |
| 2 * (fdns_npts * 2 - (M_LP_FILTER_ORDER + 1)) * sizeof(FIXP_DBL)); |
| |
| /* Guarantee 2 bits of headroom for FFT */ |
| scaleValues(&tmp1[2], (2 * M_LP_FILTER_ORDER), (A1_exp - A1_exp_fix)); |
| scaleValues(&tmp2[2], (2 * M_LP_FILTER_ORDER), (A2_exp - A2_exp_fix)); |
| |
| INT s2; |
| s = A1_exp_fix; |
| s2 = A2_exp_fix; |
| |
| fft(2 * fdns_npts, tmp1, &s); |
| fft(2 * fdns_npts, tmp2, &s2); |
| |
| /* Adjust the exponents of both fft outputs if necessary*/ |
| if (s > s2) { |
| scaleValues(tmp2, 2 * fdns_npts, s2 - s); |
| s2 = s; |
| } else if (s < s2) { |
| scaleValues(tmp1, 2 * fdns_npts, s - s2); |
| s = s2; |
| } |
| |
| FDK_ASSERT(s == s2); |
| } |
| |
| /* Get amplitude and apply gains */ |
| step = lg / fdns_npts; |
| rr_minus_one = (FIXP_DBL)0; |
| |
| for (k = 0; k < fdns_npts; k++) { |
| FIXP_DBL g1, g2, inv_g1_g2, a, b; |
| INT inv_g1_g2_e; |
| int g_e, shift; |
| |
| { |
| FIXP_DBL real, imag; |
| int si1, si2, sInput; |
| |
| real = tmp1[k * 2]; |
| imag = tmp1[k * 2 + 1]; |
| sInput = fMax(fMin(fNorm(real), fNorm(imag)) - 1, 0); |
| real <<= sInput; |
| imag <<= sInput; |
| /* g1_e = si1 - 2*s/2 */ |
| g1 = invSqrtNorm2(fPow2(real) + fPow2(imag), &si1); |
| si1 += sInput; |
| |
| real = tmp2[k * 2]; |
| imag = tmp2[k * 2 + 1]; |
| sInput = fMax(fMin(fNorm(real), fNorm(imag)) - 1, 0); |
| real <<= sInput; |
| imag <<= sInput; |
| /* g2_e = si2 - 2*s/2 */ |
| g2 = invSqrtNorm2(fPow2(real) + fPow2(imag), &si2); |
| si2 += sInput; |
| |
| /* Pick a common scale factor for g1 and g2 */ |
| if (si1 > si2) { |
| g2 >>= si1 - si2; |
| g_e = si1 - s; |
| } else { |
| g1 >>= si2 - si1; |
| g_e = si2 - s; |
| } |
| } |
| |
| /* end of lpc2mdct() */ |
| |
| FDK_ASSERT(g1 >= (FIXP_DBL)0); |
| FDK_ASSERT(g2 >= (FIXP_DBL)0); |
| |
| /* mdct_IntNoiseShaping() */ |
| { |
| /* inv_g1_g2 * 2^inv_g1_g2_e = 1/(g1+g2) */ |
| inv_g1_g2 = (g1 >> 1) + (g2 >> 1); |
| if (inv_g1_g2 != (FIXP_DBL)0) { |
| inv_g1_g2 = fDivNorm(FL2FXCONST_DBL(0.5f), inv_g1_g2, &inv_g1_g2_e); |
| inv_g1_g2_e = inv_g1_g2_e - g_e; |
| } else { |
| inv_g1_g2 = (FIXP_DBL)MAXVAL_DBL; |
| inv_g1_g2_e = 0; |
| } |
| |
| if (g_e < 0) { |
| /* a_e = g_e + inv_g1_g2_e + 1 */ |
| a = scaleValue(fMult(fMult(g1, g2), inv_g1_g2), g_e); |
| /* b_e = g_e + inv_g1_g2_e */ |
| b = fMult(g2 - g1, inv_g1_g2); |
| shift = g_e + inv_g1_g2_e + 1 - NSHAPE_SCALE; |
| } else { |
| /* a_e = (g_e+g_e) + inv_g1_g2_e + 1 */ |
| a = fMult(fMult(g1, g2), inv_g1_g2); |
| /* b_e = (g_e+g_e) + inv_g1_g2_e */ |
| b = scaleValue(fMult(g2 - g1, inv_g1_g2), -g_e); |
| shift = (g_e + g_e) + inv_g1_g2_e + 1 - NSHAPE_SCALE; |
| } |
| |
| for (i = k * step; i < (k + 1) * step; i++) { |
| FIXP_DBL tmp; |
| |
| /* rr[i] = 2*a*r[i] + b*rr[i-1] */ |
| tmp = fMult(a, r[i]); |
| tmp += scaleValue(fMultDiv2(b, rr_minus_one), NSHAPE_SCALE); |
| tmp = scaleValueSaturate(tmp, shift); |
| rr_minus_one = tmp; |
| r[i] = tmp; |
| } |
| } |
| } |
| |
| /* end of mdct_IntNoiseShaping() */ |
| { *pScale += NSHAPE_SCALE; } |
| |
| C_AALLOC_SCRATCH_END(tmp1, FIXP_DBL, FDNS_NPTS * 8) |
| } |
| |
| /** |
| * \brief Calculates the energy. |
| * \param r pointer to spectrum. |
| * \param rs scale factor of spectrum r. |
| * \param lg frame length in audio samples. |
| * \param rms_e pointer to exponent of energy value. |
| * \return mantissa of energy value. |
| */ |
| static FIXP_DBL calcEnergy(const FIXP_DBL *r, const SHORT rs, const INT lg, |
| INT *rms_e) { |
| int headroom = getScalefactor(r, lg); |
| |
| FIXP_DBL rms_m = 0; |
| |
| /* Calculate number of growth bits due to addition */ |
| INT shift = (INT)(fNormz((FIXP_DBL)lg)); |
| shift = 31 - shift; |
| |
| /* Generate 1e-2 in Q-6.37 */ |
| const FIXP_DBL value0_01 = 0x51eb851e; |
| const INT value0_01_exp = -6; |
| |
| /* Find the exponent of the resulting energy value */ |
| *rms_e = ((rs - headroom) << 1) + shift + 1; |
| |
| INT delta = *rms_e - value0_01_exp; |
| if (delta > 0) { |
| /* Limit shift_to 31*/ |
| delta = fMin(31, delta); |
| rms_m = value0_01 >> delta; |
| } else { |
| rms_m = value0_01; |
| *rms_e = value0_01_exp; |
| shift = shift - delta; |
| /* Limit shift_to 31*/ |
| shift = fMin(31, shift); |
| } |
| |
| for (int i = 0; i < lg; i++) { |
| rms_m += fPow2Div2(r[i] << headroom) >> shift; |
| } |
| |
| return rms_m; |
| } |
| |
| /** |
| * \brief TCX gain calculation. |
| * \param pAacDecoderChannelInfo channel context data. |
| * \param r output spectrum. |
| * \param rms_e pointer to mantissa of energy value. |
| * \param rms_e pointer to exponent of energy value. |
| * \param frame the frame index of the LPD super frame. |
| * \param lg the frame length in audio samples. |
| * \param gain_m pointer to mantissa of TCX gain. |
| * \param gain_e pointer to exponent of TCX gain. |
| * \param elFlags element specific parser guidance flags. |
| * \param lg_fb the fullband frame length in audio samples. |
| * \param IGF_bgn the IGF start index. |
| */ |
| static void calcTCXGain(CAacDecoderChannelInfo *pAacDecoderChannelInfo, |
| FIXP_DBL *r, FIXP_DBL rms_m, INT rms_e, const INT frame, |
| const INT lg) { |
| if ((rms_m != (FIXP_DBL)0)) { |
| FIXP_DBL tcx_gain_m; |
| INT tcx_gain_e; |
| |
| CLpd_DecodeGain(&tcx_gain_m, &tcx_gain_e, |
| pAacDecoderChannelInfo->pDynData->specificTo.usac |
| .tcx_global_gain[frame]); |
| |
| /* rms * 2^rms_e = lg/sqrt(sum(spec^2)) */ |
| if (rms_e & 1) { |
| rms_m >>= 1; |
| rms_e++; |
| } |
| |
| { |
| FIXP_DBL fx_lg; |
| INT fx_lg_e, s; |
| INT inv_e; |
| |
| /* lg = fx_lg * 2^fx_lg_e */ |
| s = fNorm((FIXP_DBL)lg); |
| fx_lg = (FIXP_DBL)lg << s; |
| fx_lg_e = DFRACT_BITS - 1 - s; |
| /* 1/sqrt(rms) */ |
| rms_m = invSqrtNorm2(rms_m, &inv_e); |
| rms_m = fMult(rms_m, fx_lg); |
| rms_e = inv_e - (rms_e >> 1) + fx_lg_e; |
| } |
| |
| { |
| int s = fNorm(tcx_gain_m); |
| tcx_gain_m = tcx_gain_m << s; |
| tcx_gain_e -= s; |
| } |
| |
| tcx_gain_m = fMultDiv2(tcx_gain_m, rms_m); |
| tcx_gain_e = tcx_gain_e + rms_e; |
| |
| /* global_gain * 2^(global_gain_e+rms_e) = (10^(global_gain/28)) * rms * |
| * 2^rms_e */ |
| { |
| { tcx_gain_e += 1; } |
| } |
| |
| pAacDecoderChannelInfo->data.usac.tcx_gain[frame] = tcx_gain_m; |
| pAacDecoderChannelInfo->data.usac.tcx_gain_e[frame] = tcx_gain_e; |
| |
| pAacDecoderChannelInfo->specScale[frame] += tcx_gain_e; |
| } |
| } |
| |
| /** |
| * \brief FDNS decoding. |
| * \param pAacDecoderChannelInfo channel context data. |
| * \param pAacDecoderStaticChannelInfo channel context static data. |
| * \param r output spectrum. |
| * \param lg the frame length in audio samples. |
| * \param frame the frame index of the LPD super frame. |
| * \param pScale pointer to current scale shift factor of r[]. |
| * \param A1 old input LPC coefficients of length M_LP_FILTER_ORDER. |
| * \param A2 new input LPC coefficients of length M_LP_FILTER_ORDER. |
| * \param pAlfdGains pointer for ALFD gains output scaled by 1. |
| * \param fdns_npts number of lines (FDNS_NPTS). |
| * \param inf_mask pointer to noise mask. |
| * \param IGF_win_mode IGF window mode (LONG, SHORT, TCX10, TCX20). |
| * \param frameType (IGF_FRAME_DIVISION_AAC_OR_TCX_LONG or |
| * IGF_FRAME_DIVISION_TCX_SHORT_1). |
| * \param elFlags element specific parser guidance flags. |
| * \param lg_fb the fullband frame length in audio samples. |
| * \param IGF_bgn the IGF start index. |
| * \param rms_m mantisse of energy. |
| * \param rms_e exponent of energy. |
| */ |
| /* static */ |
| void CLpd_FdnsDecode(CAacDecoderChannelInfo *pAacDecoderChannelInfo, |
| CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, |
| FIXP_DBL r[], const INT lg, const INT frame, SHORT *pScale, |
| const FIXP_LPC A1[M_LP_FILTER_ORDER], const INT A1_exp, |
| const FIXP_LPC A2[M_LP_FILTER_ORDER], const INT A2_exp, |
| FIXP_DBL pAlfdGains[LFAC / 4], const INT fdns_npts) { |
| /* Weight LPC coefficients using Rm values */ |
| CLpd_AdaptLowFreqDeemph(r, lg, pAlfdGains, *pScale); |
| |
| FIXP_DBL rms_m = (FIXP_DBL)0; |
| INT rms_e = 0; |
| { |
| /* Calculate Energy */ |
| rms_m = calcEnergy(r, *pScale, lg, &rms_e); |
| } |
| |
| calcTCXGain(pAacDecoderChannelInfo, r, rms_m, rms_e, frame, lg); |
| |
| /* Apply ODFT and Noise Shaping. LP coefficient (A1, A2) weighting is done |
| * inside on the fly. */ |
| |
| lpc2mdctAndNoiseShaping(r, pScale, lg, fdns_npts, A1, A1_exp, A2, A2_exp); |
| } |
| |
| /** |
| * find pitch for TCX20 (time domain) concealment. |
| */ |
| static int find_mpitch(FIXP_DBL xri[], int lg) { |
| FIXP_DBL max, pitch; |
| INT pitch_e; |
| int i, n; |
| |
| max = (FIXP_DBL)0; |
| n = 2; |
| |
| /* find maximum below 400Hz */ |
| for (i = 2; i < (lg >> 4); i += 2) { |
| FIXP_DBL tmp = fPow2Div2(xri[i]) + fPow2Div2(xri[i + 1]); |
| if (tmp > max) { |
| max = tmp; |
| n = i; |
| } |
| } |
| |
| // pitch = ((float)lg<<1)/(float)n; |
| pitch = fDivNorm((FIXP_DBL)lg << 1, (FIXP_DBL)n, &pitch_e); |
| pitch >>= fixMax(0, DFRACT_BITS - 1 - pitch_e - 16); |
| |
| /* find pitch multiple under 20ms */ |
| if (pitch >= (FIXP_DBL)((256 << 16) - 1)) { /*231.0f*/ |
| n = 256; |
| } else { |
| FIXP_DBL mpitch = pitch; |
| while (mpitch < (FIXP_DBL)(255 << 16)) { |
| mpitch += pitch; |
| } |
| n = (int)(mpitch - pitch) >> 16; |
| } |
| |
| return (n); |
| } |
| |
| /** |
| * number of spectral coefficients / time domain samples using frame mode as |
| * index. |
| */ |
| static const int lg_table_ccfl[2][4] = { |
| {256, 256, 512, 1024}, /* coreCoderFrameLength = 1024 */ |
| {192, 192, 384, 768} /* coreCoderFrameLength = 768 */ |
| }; |
| |
| /** |
| * \brief Decode and render one MDCT-TCX frame. |
| * \param pAacDecoderChannelInfo channel context data. |
| * \param lg the frame length in audio samples. |
| * \param frame the frame index of the LPD super frame. |
| */ |
| static void CLpd_TcxDecode( |
| CAacDecoderChannelInfo *pAacDecoderChannelInfo, |
| CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, UINT flags, |
| int mod, int last_mod, int frame, int frameOk) { |
| FIXP_DBL *pAlfd_gains = pAacDecoderStaticChannelInfo->last_alfd_gains; |
| ULONG *pSeed = &pAacDecoderStaticChannelInfo->nfRandomSeed; |
| int lg = (pAacDecoderChannelInfo->granuleLength == 128) |
| ? lg_table_ccfl[0][mod + 0] |
| : lg_table_ccfl[1][mod + 0]; |
| int next_frame = frame + (1 << (mod - 1)); |
| int isFullBandLpd = 0; |
| |
| /* Obtain r[] vector by combining the quant[] and noise[] vectors */ |
| { |
| FIXP_DBL noise_level; |
| FIXP_DBL *coeffs = |
| SPEC_TCX(pAacDecoderChannelInfo->pSpectralCoefficient, frame, |
| pAacDecoderChannelInfo->granuleLength, isFullBandLpd); |
| int scale = pAacDecoderChannelInfo->specScale[frame]; |
| int i, nfBgn, nfEnd; |
| UCHAR tcx_noise_factor = pAacDecoderChannelInfo->pDynData->specificTo.usac |
| .tcx_noise_factor[frame]; |
| |
| /* find pitch for bfi case */ |
| pAacDecoderStaticChannelInfo->last_tcx_pitch = find_mpitch(coeffs, lg); |
| |
| if (frameOk) { |
| /* store for concealment */ |
| pAacDecoderStaticChannelInfo->last_tcx_noise_factor = tcx_noise_factor; |
| } else { |
| /* restore last frames value */ |
| tcx_noise_factor = pAacDecoderStaticChannelInfo->last_tcx_noise_factor; |
| } |
| |
| noise_level = |
| (FIXP_DBL)((LONG)FL2FXCONST_DBL(0.0625f) * (8 - tcx_noise_factor)); |
| noise_level = scaleValue(noise_level, -scale); |
| |
| const FIXP_DBL neg_noise_level = -noise_level; |
| |
| { |
| nfBgn = lg / 6; |
| nfEnd = lg; |
| } |
| |
| for (i = nfBgn; i < nfEnd - 7; i += 8) { |
| LONG tmp; |
| |
| /* Fill all 8 consecutive zero coeffs with noise */ |
| tmp = coeffs[i + 0] | coeffs[i + 1] | coeffs[i + 2] | coeffs[i + 3] | |
| coeffs[i + 4] | coeffs[i + 5] | coeffs[i + 6] | coeffs[i + 7]; |
| |
| if (tmp == 0) { |
| for (int k = i; k < i + 8; k++) { |
| UsacRandomSign(pSeed) ? (coeffs[k] = neg_noise_level) |
| : (coeffs[k] = noise_level); |
| } |
| } |
| } |
| if ((nfEnd - i) > |
| 0) { /* noise filling for last "band" with less than 8 bins */ |
| LONG tmp = (LONG)coeffs[i]; |
| int k; |
| |
| FDK_ASSERT((nfEnd - i) < 8); |
| for (k = 1; k < (nfEnd - i); k++) { |
| tmp |= (LONG)coeffs[i + k]; |
| } |
| if (tmp == 0) { |
| for (k = i; k < nfEnd; k++) { |
| UsacRandomSign(pSeed) ? (coeffs[k] = neg_noise_level) |
| : (coeffs[k] = noise_level); |
| } |
| } |
| } |
| } |
| |
| { |
| /* Convert LPC to LP domain */ |
| if (last_mod == 0) { |
| /* Note: The case where last_mod == 255 is handled by other means |
| * in CLpdChannelStream_Read() */ |
| E_LPC_f_lsp_a_conversion( |
| pAacDecoderChannelInfo->data.usac.lsp_coeff[frame], |
| pAacDecoderChannelInfo->data.usac.lp_coeff[frame], |
| &pAacDecoderChannelInfo->data.usac.lp_coeff_exp[frame]); |
| } |
| |
| E_LPC_f_lsp_a_conversion( |
| pAacDecoderChannelInfo->data.usac.lsp_coeff[next_frame], |
| pAacDecoderChannelInfo->data.usac.lp_coeff[next_frame], |
| &pAacDecoderChannelInfo->data.usac.lp_coeff_exp[next_frame]); |
| |
| /* FDNS decoding */ |
| CLpd_FdnsDecode( |
| pAacDecoderChannelInfo, pAacDecoderStaticChannelInfo, |
| SPEC_TCX(pAacDecoderChannelInfo->pSpectralCoefficient, frame, |
| pAacDecoderChannelInfo->granuleLength, isFullBandLpd), |
| lg, frame, pAacDecoderChannelInfo->specScale + frame, |
| pAacDecoderChannelInfo->data.usac.lp_coeff[frame], |
| pAacDecoderChannelInfo->data.usac.lp_coeff_exp[frame], |
| pAacDecoderChannelInfo->data.usac.lp_coeff[next_frame], |
| pAacDecoderChannelInfo->data.usac.lp_coeff_exp[next_frame], pAlfd_gains, |
| pAacDecoderChannelInfo->granuleLength / 2 /* == FDNS_NPTS(ccfl) */ |
| ); |
| } |
| } |
| |
| /** |
| * \brief Read the tcx_coding bitstream part |
| * \param hBs bitstream handle to read from. |
| * \param pAacDecoderChannelInfo channel context info to store data into. |
| * \param lg the frame length in audio samples. |
| * \param first_tcx_flag flag indicating that this is the first TCX frame. |
| * \param frame the frame index of the LPD super frame. |
| */ |
| static AAC_DECODER_ERROR CLpd_TCX_Read( |
| HANDLE_FDK_BITSTREAM hBs, CAacDecoderChannelInfo *pAacDecoderChannelInfo, |
| CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, int lg, |
| int first_tcx_flag, int frame, UINT flags) { |
| AAC_DECODER_ERROR errorAAC = AAC_DEC_OK; |
| ARITH_CODING_ERROR error = ARITH_CODER_OK; |
| FIXP_DBL *pSpec; |
| int arith_reset_flag = 0; |
| int isFullBandLpd = 0; |
| |
| pSpec = SPEC_TCX(pAacDecoderChannelInfo->pSpectralCoefficient, frame, |
| pAacDecoderChannelInfo->granuleLength, isFullBandLpd); |
| |
| /* TCX noise level */ |
| { |
| pAacDecoderChannelInfo->pDynData->specificTo.usac.tcx_noise_factor[frame] = |
| FDKreadBits(hBs, 3); |
| } |
| /* TCX global gain */ |
| pAacDecoderChannelInfo->pDynData->specificTo.usac.tcx_global_gain[frame] = |
| FDKreadBits(hBs, 7); |
| |
| /* Arithmetic coded residual/spectrum */ |
| if (first_tcx_flag) { |
| if (flags & AC_INDEP) { |
| arith_reset_flag = 1; |
| } else { |
| arith_reset_flag = FDKreadBits(hBs, 1); |
| } |
| } |
| |
| /* CArco_DecodeArithData() output scale of "pSpec" is DFRACT_BITS-1 */ |
| error = CArco_DecodeArithData(pAacDecoderStaticChannelInfo->hArCo, hBs, pSpec, |
| lg, lg, arith_reset_flag); |
| |
| /* Rescale residual/spectrum */ |
| { |
| int scale = getScalefactor(pSpec, lg) - 2; /* Leave 2 bits headroom */ |
| |
| /* Exponent of CArco_DecodeArithData() output is DFRACT_BITS; integer |
| * values. */ |
| scaleValues(pSpec, lg, scale); |
| scale = DFRACT_BITS - 1 - scale; |
| |
| pAacDecoderChannelInfo->specScale[frame] = scale; |
| } |
| |
| if (error == ARITH_CODER_ERROR) errorAAC = AAC_DEC_UNKNOWN; |
| |
| return errorAAC; |
| } |
| |
| /** |
| * \brief translate lpd_mode into the mod[] array which describes the mode of |
| * each each LPD frame |
| * \param mod[] the array that will be filled with the mode indexes of the |
| * inidividual frames. |
| * \param lpd_mode the lpd_mode field read from the lpd_channel_stream |
| */ |
| static AAC_DECODER_ERROR CLpd_ReadAndMapLpdModeToModArray( |
| UCHAR mod[4], HANDLE_FDK_BITSTREAM hBs, UINT elFlags) { |
| int lpd_mode; |
| |
| { |
| lpd_mode = FDKreadBits(hBs, 5); |
| |
| if (lpd_mode > 25 || lpd_mode < 0) { |
| return AAC_DEC_PARSE_ERROR; |
| } |
| |
| switch (lpd_mode) { |
| case 25: |
| /* 1 80MS frame */ |
| mod[0] = mod[1] = mod[2] = mod[3] = 3; |
| break; |
| case 24: |
| /* 2 40MS frames */ |
| mod[0] = mod[1] = mod[2] = mod[3] = 2; |
| break; |
| default: |
| switch (lpd_mode >> 2) { |
| case 4: |
| /* lpd_mode 19 - 16 => 1 40MS and 2 20MS frames */ |
| mod[0] = mod[1] = 2; |
| mod[2] = (lpd_mode & 1) ? 1 : 0; |
| mod[3] = (lpd_mode & 2) ? 1 : 0; |
| break; |
| case 5: |
| /* lpd_mode 23 - 20 => 2 20MS and 1 40MS frames */ |
| mod[2] = mod[3] = 2; |
| mod[0] = (lpd_mode & 1) ? 1 : 0; |
| mod[1] = (lpd_mode & 2) ? 1 : 0; |
| break; |
| default: |
| /* lpd_mode < 16 => 4 20MS frames */ |
| mod[0] = (lpd_mode & 1) ? 1 : 0; |
| mod[1] = (lpd_mode & 2) ? 1 : 0; |
| mod[2] = (lpd_mode & 4) ? 1 : 0; |
| mod[3] = (lpd_mode & 8) ? 1 : 0; |
| break; |
| } |
| break; |
| } |
| } |
| return AAC_DEC_OK; |
| } |
| |
| static void CLpd_Reset( |
| CAacDecoderChannelInfo *pAacDecoderChannelInfo, |
| CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, |
| int keep_past_signal) { |
| int i; |
| |
| /* Reset TCX / ACELP common memory */ |
| if (!keep_past_signal) { |
| FDKmemclear(pAacDecoderStaticChannelInfo->old_synth, |
| sizeof(pAacDecoderStaticChannelInfo->old_synth)); |
| } |
| |
| /* Initialize the LSFs */ |
| for (i = 0; i < M_LP_FILTER_ORDER; i++) { |
| pAacDecoderStaticChannelInfo->lpc4_lsf[i] = fdk_dec_lsf_init[i]; |
| } |
| |
| /* Reset memory needed by bass post-filter */ |
| FDKmemclear(pAacDecoderStaticChannelInfo->mem_bpf, |
| sizeof(pAacDecoderStaticChannelInfo->mem_bpf)); |
| |
| pAacDecoderStaticChannelInfo->old_bpf_control_info = 0; |
| for (i = 0; i < SYN_SFD; i++) { |
| pAacDecoderStaticChannelInfo->old_T_pf[i] = 64; |
| pAacDecoderStaticChannelInfo->old_gain_pf[i] = (FIXP_DBL)0; |
| } |
| |
| /* Reset ACELP memory */ |
| CLpd_AcelpReset(&pAacDecoderStaticChannelInfo->acelp); |
| |
| pAacDecoderStaticChannelInfo->last_lpc_lost = 0; /* prev_lpc_lost */ |
| pAacDecoderStaticChannelInfo->last_tcx_pitch = L_DIV; /* pitch_tcx */ |
| pAacDecoderStaticChannelInfo->numLostLpdFrames = 0; /* nbLostCmpt */ |
| } |
| |
| /* |
| * Externally visible functions |
| */ |
| |
| AAC_DECODER_ERROR CLpdChannelStream_Read( |
| HANDLE_FDK_BITSTREAM hBs, CAacDecoderChannelInfo *pAacDecoderChannelInfo, |
| CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, |
| const SamplingRateInfo *pSamplingRateInfo, UINT flags) { |
| AAC_DECODER_ERROR error = AAC_DEC_OK; |
| int first_tcx_flag; |
| int k, nbDiv, fFacDataPresent, first_lpd_flag, acelp_core_mode, |
| facGetMemState = 0; |
| UCHAR *mod = pAacDecoderChannelInfo->data.usac.mod; |
| int lpd_mode_last, prev_frame_was_lpd; |
| USAC_COREMODE core_mode_last; |
| const int lg_table_offset = 0; |
| const int *lg_table = (pAacDecoderChannelInfo->granuleLength == 128) |
| ? &lg_table_ccfl[0][lg_table_offset] |
| : &lg_table_ccfl[1][lg_table_offset]; |
| int last_lpc_lost = pAacDecoderStaticChannelInfo->last_lpc_lost; |
| |
| int last_frame_ok = CConcealment_GetLastFrameOk( |
| &pAacDecoderStaticChannelInfo->concealmentInfo, 1); |
| |
| INT i_offset; |
| UINT samplingRate; |
| |
| samplingRate = pSamplingRateInfo->samplingRate; |
| |
| i_offset = |
| (INT)(samplingRate * PIT_MIN_12k8 + (FSCALE_DENOM / 2)) / FSCALE_DENOM - |
| (INT)PIT_MIN_12k8; |
| |
| if (pSamplingRateInfo->samplingRate > |
| FAC_FSCALE_MAX /* maximum allowed core sampling frequency */) { |
| error = AAC_DEC_PARSE_ERROR; |
| goto bail; |
| } |
| |
| acelp_core_mode = FDKreadBits(hBs, 3); |
| |
| /* lpd_mode */ |
| error = CLpd_ReadAndMapLpdModeToModArray(mod, hBs, 0); |
| if (error != AAC_DEC_OK) { |
| goto bail; |
| } |
| |
| /* bpf_control_info */ |
| pAacDecoderChannelInfo->data.usac.bpf_control_info = FDKreadBit(hBs); |
| |
| /* last_core_mode */ |
| prev_frame_was_lpd = FDKreadBit(hBs); |
| /* fac_data_present */ |
| fFacDataPresent = FDKreadBit(hBs); |
| |
| /* Set valid values from |
| * pAacDecoderStaticChannelInfo->{last_core_mode,last_lpd_mode} */ |
| pAacDecoderChannelInfo->data.usac.core_mode_last = |
| pAacDecoderStaticChannelInfo->last_core_mode; |
| lpd_mode_last = pAacDecoderChannelInfo->data.usac.lpd_mode_last = |
| pAacDecoderStaticChannelInfo->last_lpd_mode; |
| |
| if (prev_frame_was_lpd == 0) { |
| /* Last frame was FD */ |
| pAacDecoderChannelInfo->data.usac.core_mode_last = FD_LONG; |
| pAacDecoderChannelInfo->data.usac.lpd_mode_last = 255; |
| } else { |
| /* Last frame was LPD */ |
| pAacDecoderChannelInfo->data.usac.core_mode_last = LPD; |
| if (((mod[0] == 0) && fFacDataPresent) || |
| ((mod[0] != 0) && !fFacDataPresent)) { |
| /* Currend mod is ACELP, fac data present -> TCX, current mod TCX, no fac |
| * data -> TCX */ |
| if (lpd_mode_last == 0) { |
| /* Bit stream interruption detected. Assume last TCX mode as TCX20. */ |
| pAacDecoderChannelInfo->data.usac.lpd_mode_last = 1; |
| } |
| /* Else assume that remembered TCX mode is correct. */ |
| } else { |
| pAacDecoderChannelInfo->data.usac.lpd_mode_last = 0; |
| } |
| } |
| |
| first_lpd_flag = (pAacDecoderChannelInfo->data.usac.core_mode_last != |
| LPD); /* Depends on bitstream configuration */ |
| first_tcx_flag = 1; |
| |
| if (pAacDecoderStaticChannelInfo->last_core_mode != |
| LPD) { /* ATTENTION: Reset depends on what we rendered before! */ |
| CLpd_Reset(pAacDecoderChannelInfo, pAacDecoderStaticChannelInfo, 0); |
| |
| if (!last_frame_ok) { |
| /* If last rendered frame was not LPD and first lpd flag is not set, this |
| * must be an error - set last_lpc_lost flag */ |
| last_lpc_lost |= (first_lpd_flag) ? 0 : 1; |
| } |
| } |
| |
| core_mode_last = pAacDecoderChannelInfo->data.usac.core_mode_last; |
| lpd_mode_last = pAacDecoderChannelInfo->data.usac.lpd_mode_last; |
| |
| nbDiv = NB_DIV; |
| |
| /* k is the frame index. If a frame is of size 40MS or 80MS, |
| this frame index is incremented 2 or 4 instead of 1 respectively. */ |
| |
| k = 0; |
| while (k < nbDiv) { |
| /* Reset FAC data pointers in order to avoid applying old random FAC data. |
| */ |
| pAacDecoderChannelInfo->data.usac.fac_data[k] = NULL; |
| |
| if ((k == 0 && core_mode_last == LPD && fFacDataPresent) || |
| (lpd_mode_last == 0 && mod[k] > 0) || |
| ((lpd_mode_last != 255) && lpd_mode_last > 0 && mod[k] == 0)) { |
| int err; |
| |
| /* Assign FAC memory */ |
| pAacDecoderChannelInfo->data.usac.fac_data[k] = |
| CLpd_FAC_GetMemory(pAacDecoderChannelInfo, mod, &facGetMemState); |
| |
| /* FAC for (ACELP -> TCX) or (TCX -> ACELP) */ |
| err = CLpd_FAC_Read( |
| hBs, pAacDecoderChannelInfo->data.usac.fac_data[k], |
| pAacDecoderChannelInfo->data.usac.fac_data_e, |
| pAacDecoderChannelInfo->granuleLength, /* == fac_length */ |
| 0, k); |
| if (err != 0) { |
| error = AAC_DEC_PARSE_ERROR; |
| goto bail; |
| } |
| } |
| |
| if (mod[k] == 0) /* acelp-mode */ |
| { |
| int err; |
| err = CLpd_AcelpRead( |
| hBs, &pAacDecoderChannelInfo->data.usac.acelp[k], acelp_core_mode, |
| pAacDecoderChannelInfo->granuleLength * 8 /* coreCoderFrameLength */, |
| i_offset); |
| if (err != 0) { |
| error = AAC_DEC_PARSE_ERROR; |
| goto bail; |
| } |
| |
| lpd_mode_last = 0; |
| k++; |
| } else /* mode != 0 => TCX */ |
| { |
| error = CLpd_TCX_Read(hBs, pAacDecoderChannelInfo, |
| pAacDecoderStaticChannelInfo, lg_table[mod[k]], |
| first_tcx_flag, k, flags); |
| |
| lpd_mode_last = mod[k]; |
| first_tcx_flag = 0; |
| k += 1 << (mod[k] - 1); |
| } |
| if (error != AAC_DEC_OK) { |
| error = AAC_DEC_PARSE_ERROR; |
| goto bail; |
| } |
| } |
| |
| { |
| int err; |
| |
| /* Read LPC coefficients */ |
| err = CLpc_Read( |
| hBs, pAacDecoderChannelInfo->data.usac.lsp_coeff, |
| pAacDecoderStaticChannelInfo->lpc4_lsf, |
| pAacDecoderChannelInfo->data.usac.lsf_adaptive_mean_cand, |
| pAacDecoderChannelInfo->data.usac.aStability, mod, first_lpd_flag, |
| /* if last lpc4 is available from concealment do not extrapolate lpc0 |
| from lpc2 */ |
| (mod[0] & 0x3) ? 0 |
| : (last_lpc_lost && |
| pAacDecoderStaticChannelInfo->last_core_mode != LPD), |
| last_frame_ok); |
| if (err != 0) { |
| error = AAC_DEC_PARSE_ERROR; |
| goto bail; |
| } |
| } |
| |
| /* adjust old lsp[] following to a bad frame (to avoid overshoot) (ref: |
| * dec_LPD.c) */ |
| if (last_lpc_lost && !last_frame_ok) { |
| int k_next; |
| k = 0; |
| while (k < nbDiv) { |
| int i; |
| k_next = k + (((mod[k] & 0x3) == 0) ? 1 : (1 << (mod[k] - 1))); |
| FIXP_LPC *lsp_old = pAacDecoderChannelInfo->data.usac.lsp_coeff[k]; |
| FIXP_LPC *lsp_new = pAacDecoderChannelInfo->data.usac.lsp_coeff[k_next]; |
| |
| for (i = 0; i < M_LP_FILTER_ORDER; i++) { |
| if (lsp_new[i] < lsp_old[i]) { |
| lsp_old[i] = lsp_new[i]; |
| } |
| } |
| k = k_next; |
| } |
| } |
| |
| if (!CConcealment_GetLastFrameOk( |
| &pAacDecoderStaticChannelInfo->concealmentInfo, 1)) { |
| E_LPC_f_lsp_a_conversion( |
| pAacDecoderChannelInfo->data.usac.lsp_coeff[0], |
| pAacDecoderChannelInfo->data.usac.lp_coeff[0], |
| &pAacDecoderChannelInfo->data.usac.lp_coeff_exp[0]); |
| } else if (pAacDecoderStaticChannelInfo->last_lpd_mode != 0) { |
| if (pAacDecoderStaticChannelInfo->last_lpd_mode == 255) { |
| /* We need it for TCX decoding or ACELP excitation update */ |
| E_LPC_f_lsp_a_conversion( |
| pAacDecoderChannelInfo->data.usac.lsp_coeff[0], |
| pAacDecoderChannelInfo->data.usac.lp_coeff[0], |
| &pAacDecoderChannelInfo->data.usac.lp_coeff_exp[0]); |
| } else { /* last_lpd_mode was TCX */ |
| /* Copy old LPC4 LP domain coefficients to LPC0 LP domain buffer (to avoid |
| * converting LSP coefficients again). */ |
| FDKmemcpy(pAacDecoderChannelInfo->data.usac.lp_coeff[0], |
| pAacDecoderStaticChannelInfo->lp_coeff_old[0], |
| M_LP_FILTER_ORDER * sizeof(FIXP_LPC)); |
| pAacDecoderChannelInfo->data.usac.lp_coeff_exp[0] = |
| pAacDecoderStaticChannelInfo->lp_coeff_old_exp[0]; |
| } |
| } /* case last_lpd_mode was ACELP is handled by CLpd_TcxDecode() */ |
| |
| if (fFacDataPresent && (core_mode_last != LPD)) { |
| int prev_frame_was_short; |
| |
| prev_frame_was_short = FDKreadBit(hBs); |
| |
| if (prev_frame_was_short) { |
| core_mode_last = pAacDecoderChannelInfo->data.usac.core_mode_last = |
| FD_SHORT; |
| pAacDecoderChannelInfo->data.usac.lpd_mode_last = 255; |
| |
| if ((pAacDecoderStaticChannelInfo->last_core_mode != FD_SHORT) && |
| CConcealment_GetLastFrameOk( |
| &pAacDecoderStaticChannelInfo->concealmentInfo, 1)) { |
| /* USAC Conformance document: |
| short_fac_flag shall be encoded with a value of 1 if the |
| window_sequence of the previous frame was 2 (EIGHT_SHORT_SEQUENCE). |
| Otherwise short_fac_flag shall be encoded with a |
| value of 0. */ |
| error = AAC_DEC_PARSE_ERROR; |
| goto bail; |
| } |
| } |
| |
| /* Assign memory */ |
| pAacDecoderChannelInfo->data.usac.fac_data[0] = |
| CLpd_FAC_GetMemory(pAacDecoderChannelInfo, mod, &facGetMemState); |
| |
| { |
| int err; |
| |
| /* FAC for FD -> ACELP */ |
| err = CLpd_FAC_Read( |
| hBs, pAacDecoderChannelInfo->data.usac.fac_data[0], |
| pAacDecoderChannelInfo->data.usac.fac_data_e, |
| CLpd_FAC_getLength(core_mode_last != FD_SHORT, |
| pAacDecoderChannelInfo->granuleLength), |
| 1, 0); |
| if (err != 0) { |
| error = AAC_DEC_PARSE_ERROR; |
| goto bail; |
| } |
| } |
| } |
| |
| bail: |
| if (error == AAC_DEC_OK) { |
| /* check consitency of last core/lpd mode values */ |
| if ((pAacDecoderChannelInfo->data.usac.core_mode_last != |
| pAacDecoderStaticChannelInfo->last_core_mode) && |
| (pAacDecoderStaticChannelInfo->last_lpc_lost == 0)) { |
| /* Something got wrong! */ |
| /* error = AAC_DEC_PARSE_ERROR; */ /* Throwing errors does not help */ |
| } else if ((pAacDecoderChannelInfo->data.usac.core_mode_last == LPD) && |
| (pAacDecoderChannelInfo->data.usac.lpd_mode_last != |
| pAacDecoderStaticChannelInfo->last_lpd_mode) && |
| (pAacDecoderStaticChannelInfo->last_lpc_lost == 0)) { |
| /* Something got wrong! */ |
| /* error = AAC_DEC_PARSE_ERROR; */ /* Throwing errors does not help */ |
| } |
| } |
| |
| return error; |
| } |
| |
| void CLpdChannelStream_Decode( |
| CAacDecoderChannelInfo *pAacDecoderChannelInfo, |
| CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, UINT flags) { |
| UCHAR *mod = pAacDecoderChannelInfo->data.usac.mod; |
| int k; |
| UCHAR last_lpd_mode; |
| int nbDiv = NB_DIV; |
| |
| /* k is the frame index. If a frame is of size 40MS or 80MS, |
| this frame index is incremented 2 or 4 instead of 1 respectively. */ |
| k = 0; |
| last_lpd_mode = |
| pAacDecoderChannelInfo->data.usac |
| .lpd_mode_last; /* could be different to what has been rendered */ |
| while (k < nbDiv) { |
| if (mod[k] == 0) { |
| /* ACELP */ |
| |
| /* If FAC (fac_data[k] != NULL), and previous frame was TCX, apply (TCX) |
| * gains to FAC data */ |
| if (last_lpd_mode > 0 && last_lpd_mode != 255 && |
| pAacDecoderChannelInfo->data.usac.fac_data[k]) { |
| CFac_ApplyGains(pAacDecoderChannelInfo->data.usac.fac_data[k], |
| pAacDecoderChannelInfo->granuleLength, |
| pAacDecoderStaticChannelInfo->last_tcx_gain, |
| pAacDecoderStaticChannelInfo->last_alfd_gains, |
| (last_lpd_mode < 4) ? last_lpd_mode : 3); |
| |
| pAacDecoderChannelInfo->data.usac.fac_data_e[k] += |
| pAacDecoderStaticChannelInfo->last_tcx_gain_e; |
| } |
| } else { |
| /* TCX */ |
| CLpd_TcxDecode(pAacDecoderChannelInfo, pAacDecoderStaticChannelInfo, |
| flags, mod[k], last_lpd_mode, k, 1 /* frameOk == 1 */ |
| ); |
| |
| /* Store TCX gain scale for next possible FAC transition. */ |
| pAacDecoderStaticChannelInfo->last_tcx_gain = |
| pAacDecoderChannelInfo->data.usac.tcx_gain[k]; |
| pAacDecoderStaticChannelInfo->last_tcx_gain_e = |
| pAacDecoderChannelInfo->data.usac.tcx_gain_e[k]; |
| |
| /* If FAC (fac_data[k] != NULL), apply gains */ |
| if (last_lpd_mode == 0 && pAacDecoderChannelInfo->data.usac.fac_data[k]) { |
| CFac_ApplyGains( |
| pAacDecoderChannelInfo->data.usac.fac_data[k], |
| pAacDecoderChannelInfo->granuleLength /* == fac_length */, |
| pAacDecoderChannelInfo->data.usac.tcx_gain[k], |
| pAacDecoderStaticChannelInfo->last_alfd_gains, mod[k]); |
| |
| pAacDecoderChannelInfo->data.usac.fac_data_e[k] += |
| pAacDecoderChannelInfo->data.usac.tcx_gain_e[k]; |
| } |
| } |
| |
| /* remember previous mode */ |
| last_lpd_mode = mod[k]; |
| |
| /* Increase k to next frame */ |
| k += (mod[k] == 0) ? 1 : (1 << (mod[k] - 1)); |
| } |
| } |
| |
| AAC_DECODER_ERROR CLpd_RenderTimeSignal( |
| CAacDecoderStaticChannelInfo *pAacDecoderStaticChannelInfo, |
| CAacDecoderChannelInfo *pAacDecoderChannelInfo, FIXP_PCM *pTimeData, |
| INT lFrame, SamplingRateInfo *pSamplingRateInfo, UINT frameOk, UINT flags, |
| UINT strmFlags) { |
| UCHAR *mod = pAacDecoderChannelInfo->data.usac.mod; |
| AAC_DECODER_ERROR error = AAC_DEC_OK; |
| int k, i_offset; |
| int last_k; |
| int nrSamples = 0; |
| int facFB = 1; |
| int nbDiv = NB_DIV; |
| int lDiv = lFrame / nbDiv; /* length of division (acelp or tcx20 frame)*/ |
| int lFac = lDiv / 2; |
| int nbSubfr = |
| lFrame / (nbDiv * L_SUBFR); /* number of subframes per division */ |
| int nbSubfrSuperfr = nbDiv * nbSubfr; |
| int synSfd = (nbSubfrSuperfr / 2) - BPF_SFD; |
| int SynDelay = synSfd * L_SUBFR; |
| int aacDelay = lFrame / 2; |
| |
| /* |
| In respect to the reference software, the synth pointer here is lagging by |
| aacDelay ( == SYN_DELAY + BPF_DELAY ) samples. The corresponding old |
| synthesis samples are handled by the IMDCT overlap. |
| */ |
| |
| FIXP_DBL *synth_buf = |
| pAacDecoderChannelInfo->pComStaticData->pWorkBufferCore1->synth_buf; |
| FIXP_DBL *synth = synth_buf + PIT_MAX_MAX - BPF_DELAY; |
| UCHAR last_lpd_mode, last_last_lpd_mode, last_lpc_lost, last_frame_lost; |
| |
| INT pitch[NB_SUBFR_SUPERFR + SYN_SFD]; |
| FIXP_DBL pit_gain[NB_SUBFR_SUPERFR + SYN_SFD]; |
| |
| const int *lg_table; |
| int lg_table_offset = 0; |
| |
| UINT samplingRate = pSamplingRateInfo->samplingRate; |
| |
| FDKmemclear(pitch, (NB_SUBFR_SUPERFR + SYN_SFD) * sizeof(INT)); |
| |
| if (flags & AACDEC_FLUSH) { |
| CLpd_Reset(pAacDecoderChannelInfo, pAacDecoderStaticChannelInfo, |
| flags & AACDEC_FLUSH); |
| frameOk = 0; |
| } |
| |
| switch (lFrame) { |
| case 1024: |
| lg_table = &lg_table_ccfl[0][lg_table_offset]; |
| break; |
| case 768: |
| lg_table = &lg_table_ccfl[1][lg_table_offset]; |
| break; |
| default: |
| FDK_ASSERT(0); |
| return AAC_DEC_UNKNOWN; |
| } |
| |
| last_frame_lost = !CConcealment_GetLastFrameOk( |
| &pAacDecoderStaticChannelInfo->concealmentInfo, 0); |
| |
| /* Maintain LPD mode from previous frame */ |
| if ((pAacDecoderStaticChannelInfo->last_core_mode == FD_LONG) || |
| (pAacDecoderStaticChannelInfo->last_core_mode == FD_SHORT)) { |
| pAacDecoderStaticChannelInfo->last_lpd_mode = 255; |
| } |
| |
| if (!frameOk) { |
| FIXP_DBL old_tcx_gain; |
| FIXP_SGL old_stab; |
| SCHAR old_tcx_gain_e; |
| int nLostSf; |
| |
| last_lpd_mode = pAacDecoderStaticChannelInfo->last_lpd_mode; |
| old_tcx_gain = pAacDecoderStaticChannelInfo->last_tcx_gain; |
| old_tcx_gain_e = pAacDecoderStaticChannelInfo->last_tcx_gain_e; |
| old_stab = pAacDecoderStaticChannelInfo->oldStability; |
| nLostSf = pAacDecoderStaticChannelInfo->numLostLpdFrames; |
| |
| /* patch the last LPD mode */ |
| pAacDecoderChannelInfo->data.usac.lpd_mode_last = last_lpd_mode; |
| |
| /* Do mode extrapolation and repeat the previous mode: |
| if previous mode = ACELP -> ACELP |
| if previous mode = TCX-20/40 -> TCX-20 |
| if previous mode = TCX-80 -> TCX-80 |
| notes: |
| - ACELP is not allowed after TCX (no pitch information to reuse) |
| - TCX-40 is not allowed in the mode repetition to keep the logic simple |
| */ |
| switch (last_lpd_mode) { |
| case 0: |
| mod[0] = mod[1] = mod[2] = mod[3] = 0; /* -> ACELP concealment */ |
| break; |
| case 3: |
| mod[0] = mod[1] = mod[2] = mod[3] = 3; /* -> TCX FD concealment */ |
| break; |
| case 2: |
| mod[0] = mod[1] = mod[2] = mod[3] = 2; /* -> TCX FD concealment */ |
| break; |
| case 1: |
| default: |
| mod[0] = mod[1] = mod[2] = mod[3] = 4; /* -> TCX TD concealment */ |
| break; |
| } |
| |
| /* LPC extrapolation */ |
| CLpc_Conceal(pAacDecoderChannelInfo->data.usac.lsp_coeff, |
| pAacDecoderStaticChannelInfo->lpc4_lsf, |
| pAacDecoderStaticChannelInfo->lsf_adaptive_mean, |
| /*(pAacDecoderStaticChannelInfo->numLostLpdFrames == 0) ||*/ |
| (last_lpd_mode == 255)); |
| |
| if ((last_lpd_mode > 0) && (last_lpd_mode < 255)) { |
| /* Copy old LPC4 LP domain coefficients to LPC0 LP domain buffer (to avoid |
| * converting LSP coefficients again). */ |
| FDKmemcpy(pAacDecoderChannelInfo->data.usac.lp_coeff[0], |
| pAacDecoderStaticChannelInfo->lp_coeff_old[0], |
| M_LP_FILTER_ORDER * sizeof(FIXP_LPC)); |
| pAacDecoderChannelInfo->data.usac.lp_coeff_exp[0] = |
| pAacDecoderStaticChannelInfo->lp_coeff_old_exp[0]; |
| } /* case last_lpd_mode was ACELP is handled by CLpd_TcxDecode() */ |
| /* case last_lpd_mode was Time domain TCX concealment is handled after this |
| * "if (!frameOk)"-block */ |
| |
| /* k is the frame index. If a frame is of size 40MS or 80MS, |
| this frame index is incremented 2 or 4 instead of 1 respectively. */ |
| k = 0; |
| while (k < nbDiv) { |
| pAacDecoderChannelInfo->data.usac.tcx_gain[k] = old_tcx_gain; |
| pAacDecoderChannelInfo->data.usac.tcx_gain_e[k] = old_tcx_gain_e; |
| |
| /* restore stability value from last frame */ |
| pAacDecoderChannelInfo->data.usac.aStability[k] = old_stab; |
| |
| /* Increase k to next frame */ |
| k += ((mod[k] & 0x3) == 0) ? 1 : (1 << ((mod[k] & 0x3) - 1)); |
| |
| nLostSf++; |
| } |
| } else { |
| if ((pAacDecoderStaticChannelInfo->last_lpd_mode == 4) && (mod[0] > 0)) { |
| /* Copy old LPC4 LP domain coefficients to LPC0 LP domain buffer (to avoid |
| * converting LSP coefficients again). */ |
| FDKmemcpy(pAacDecoderChannelInfo->data.usac.lp_coeff[0], |
| pAacDecoderStaticChannelInfo->lp_coeff_old[0], |
| M_LP_FILTER_ORDER * sizeof(FIXP_LPC)); |
| pAacDecoderChannelInfo->data.usac.lp_coeff_exp[0] = |
| pAacDecoderStaticChannelInfo->lp_coeff_old_exp[0]; |
| } |
| } |
| |
| Acelp_PreProcessing(synth_buf, pAacDecoderStaticChannelInfo->old_synth, pitch, |
| pAacDecoderStaticChannelInfo->old_T_pf, pit_gain, |
| pAacDecoderStaticChannelInfo->old_gain_pf, samplingRate, |
| &i_offset, lFrame, synSfd, nbSubfrSuperfr); |
| |
| /* k is the frame index. If a frame is of size 40MS or 80MS, |
| this frame index is incremented 2 or 4 instead of 1 respectively. */ |
| k = 0; |
| last_k = -1; /* mark invalid */ |
| last_lpd_mode = pAacDecoderStaticChannelInfo->last_lpd_mode; |
| last_last_lpd_mode = pAacDecoderStaticChannelInfo->last_last_lpd_mode; |
| last_lpc_lost = pAacDecoderStaticChannelInfo->last_lpc_lost | last_frame_lost; |
| |
| /* This buffer must be avalable for the case of FD->ACELP transition. The |
| beginning of the buffer is used after the BPF to overwrite the output signal. |
| Only the FAC area must be affected by the BPF */ |
| |
| while (k < nbDiv) { |
| if (frameOk == 0) { |
| pAacDecoderStaticChannelInfo->numLostLpdFrames++; |
| } else { |
| last_frame_lost |= |
| (pAacDecoderStaticChannelInfo->numLostLpdFrames > 0) ? 1 : 0; |
| pAacDecoderStaticChannelInfo->numLostLpdFrames = 0; |
| } |
| if (mod[k] == 0 || mod[k] == 4) { |
| /* ACELP or TCX time domain concealment */ |
| FIXP_DBL *acelp_out; |
| |
| /* FAC management */ |
| if ((last_lpd_mode != 0) && (last_lpd_mode != 4)) /* TCX TD concealment */ |
| { |
| FIXP_DBL *pFacData = NULL; |
| |
| if (frameOk && !last_frame_lost) { |
| pFacData = pAacDecoderChannelInfo->data.usac.fac_data[k]; |
| } |
| |
| nrSamples += CLpd_FAC_Mdct2Acelp( |
| &pAacDecoderStaticChannelInfo->IMdct, synth + nrSamples, pFacData, |
| pAacDecoderChannelInfo->data.usac.fac_data_e[k], |
| pAacDecoderChannelInfo->data.usac.lp_coeff[k], |
| pAacDecoderChannelInfo->data.usac.lp_coeff_exp[k], |
| lFrame - nrSamples, |
| CLpd_FAC_getLength( |
| (pAacDecoderStaticChannelInfo->last_core_mode != FD_SHORT) || |
| (k > 0), |
| lFac), |
| (pAacDecoderStaticChannelInfo->last_core_mode != LPD) && (k == 0), |
| 0); |
| |
| FDKmemcpy( |
| synth + nrSamples, pAacDecoderStaticChannelInfo->IMdct.overlap.time, |
| pAacDecoderStaticChannelInfo->IMdct.ov_offset * sizeof(FIXP_DBL)); |
| { |
| FIXP_LPC *lp_prev = |
| pAacDecoderChannelInfo->data.usac |
| .lp_coeff[0]; /* init value does not real matter */ |
| INT lp_prev_exp = pAacDecoderChannelInfo->data.usac.lp_coeff_exp[0]; |
| |
| if (last_lpd_mode != 255) { /* last mode was tcx */ |
| last_k = k - (1 << (last_lpd_mode - 1)); |
| if (last_k < 0) { |
| lp_prev = pAacDecoderStaticChannelInfo->lp_coeff_old[1]; |
| lp_prev_exp = pAacDecoderStaticChannelInfo->lp_coeff_old_exp[1]; |
| } else { |
| lp_prev = pAacDecoderChannelInfo->data.usac.lp_coeff[last_k]; |
| lp_prev_exp = |
| pAacDecoderChannelInfo->data.usac.lp_coeff_exp[last_k]; |
| } |
| } |
| |
| CLpd_AcelpPrepareInternalMem( |
| synth + aacDelay + k * lDiv, last_lpd_mode, |
| (last_last_lpd_mode == 4) ? 0 : last_last_lpd_mode, |
| pAacDecoderChannelInfo->data.usac.lp_coeff[k], |
| pAacDecoderChannelInfo->data.usac.lp_coeff_exp[k], lp_prev, |
| lp_prev_exp, &pAacDecoderStaticChannelInfo->acelp, lFrame, |
| (last_frame_lost && k < 2), mod[k]); |
| } |
| } else { |
| if (k == 0 && pAacDecoderStaticChannelInfo->IMdct.ov_offset != |
| lFrame / facFB / 2) { |
| pAacDecoderStaticChannelInfo->IMdct.ov_offset = lFrame / facFB / 2; |
| } |
| nrSamples += imdct_drain(&pAacDecoderStaticChannelInfo->IMdct, |
| synth + nrSamples, lFrame / facFB - nrSamples); |
| } |
| |
| if (nrSamples >= lFrame / facFB) { |
| /* Write ACELP time domain samples into IMDCT overlap buffer at |
| * pAacDecoderStaticChannelInfo->IMdct.overlap.time + |
| * pAacDecoderStaticChannelInfo->IMdct.ov_offset |
| */ |
| acelp_out = pAacDecoderStaticChannelInfo->IMdct.overlap.time + |
| pAacDecoderStaticChannelInfo->IMdct.ov_offset; |
| |
| /* Account ACELP time domain output samples to overlap buffer */ |
| pAacDecoderStaticChannelInfo->IMdct.ov_offset += lDiv; |
| } else { |
| /* Write ACELP time domain samples into output buffer at pTimeData + |
| * nrSamples */ |
| acelp_out = synth + nrSamples; |
| |
| /* Account ACELP time domain output samples to output buffer */ |
| nrSamples += lDiv; |
| } |
| |
| if (mod[k] == 4) { |
| pAacDecoderStaticChannelInfo->acelp.wsyn_rms = scaleValue( |
| pAacDecoderChannelInfo->data.usac.tcx_gain[k], |
| fixMin(0, |
| pAacDecoderChannelInfo->data.usac.tcx_gain_e[k] - SF_EXC)); |
| CLpd_TcxTDConceal(&pAacDecoderStaticChannelInfo->acelp, |
| &pAacDecoderStaticChannelInfo->last_tcx_pitch, |
| pAacDecoderChannelInfo->data.usac.lsp_coeff[k], |
| pAacDecoderChannelInfo->data.usac.lsp_coeff[k + 1], |
| pAacDecoderChannelInfo->data.usac.aStability[k], |
| pAacDecoderStaticChannelInfo->numLostLpdFrames, |
| acelp_out, lFrame, |
| pAacDecoderStaticChannelInfo->last_tcx_noise_factor); |
| |
| } else { |
| FDK_ASSERT(pAacDecoderChannelInfo->data.usac.aStability[k] >= |
| (FIXP_SGL)0); |
| CLpd_AcelpDecode(&pAacDecoderStaticChannelInfo->acelp, i_offset, |
| pAacDecoderChannelInfo->data.usac.lsp_coeff[k], |
| pAacDecoderChannelInfo->data.usac.lsp_coeff[k + 1], |
| pAacDecoderChannelInfo->data.usac.aStability[k], |
| &pAacDecoderChannelInfo->data.usac.acelp[k], |
| pAacDecoderStaticChannelInfo->numLostLpdFrames, |
| last_lpc_lost, k, acelp_out, |
| &pitch[(k * nbSubfr) + synSfd], |
| &pit_gain[(k * nbSubfr) + synSfd], lFrame); |
| } |
| |
| if (mod[k] != 4) { |
| if (last_lpd_mode != 0 && |
| pAacDecoderChannelInfo->data.usac |
| .bpf_control_info) { /* FD/TCX -> ACELP transition */ |
| /* bass post-filter past FAC area (past two (one for FD short) |
| * subframes) */ |
| int currentSf = synSfd + k * nbSubfr; |
| |
| if ((k > 0) || (pAacDecoderStaticChannelInfo->last_core_mode != |
| FD_SHORT)) { /* TCX or FD long -> ACELP */ |
| pitch[currentSf - 2] = pitch[currentSf - 1] = pitch[currentSf]; |
| pit_gain[currentSf - 2] = pit_gain[currentSf - 1] = |
| pit_gain[currentSf]; |
| } else { /* FD short -> ACELP */ |
| pitch[currentSf - 1] = pitch[currentSf]; |
| pit_gain[currentSf - 1] = pit_gain[currentSf]; |
| } |
| } |
| } |
| } else { /* TCX */ |
| int lg = lg_table[mod[k]]; |
| int isFullBandLpd = 0; |
| |
| /* FAC management */ |
| if ((last_lpd_mode == 0) || (last_lpd_mode == 4)) /* TCX TD concealment */ |
| { |
| C_AALLOC_SCRATCH_START(fac_buf, FIXP_DBL, 1024 / 8); |
| |
| /* pAacDecoderChannelInfo->data.usac.fac_data[k] == NULL means no FAC |
| * data available. */ |
| if (last_frame_lost == 1 || |
| pAacDecoderChannelInfo->data.usac.fac_data[k] == NULL) { |
| FDKmemclear(fac_buf, 1024 / 8 * sizeof(FIXP_DBL)); |
| pAacDecoderChannelInfo->data.usac.fac_data[k] = fac_buf; |
| pAacDecoderChannelInfo->data.usac.fac_data_e[k] = 0; |
| } |
| |
| nrSamples += CLpd_FAC_Acelp2Mdct( |
| &pAacDecoderStaticChannelInfo->IMdct, synth + nrSamples, |
| SPEC_TCX(pAacDecoderChannelInfo->pSpectralCoefficient, k, |
| pAacDecoderChannelInfo->granuleLength, isFullBandLpd), |
| pAacDecoderChannelInfo->specScale + k, 1, |
| pAacDecoderChannelInfo->data.usac.fac_data[k], |
| pAacDecoderChannelInfo->data.usac.fac_data_e[k], |
| pAacDecoderChannelInfo->granuleLength /* == fac_length */, |
| lFrame - nrSamples, lg, |
| FDKgetWindowSlope(lDiv, |
| GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), |
| lDiv, pAacDecoderChannelInfo->data.usac.lp_coeff[k], |
| pAacDecoderChannelInfo->data.usac.lp_coeff_exp[k], |
| &pAacDecoderStaticChannelInfo->acelp, |
| pAacDecoderChannelInfo->data.usac.tcx_gain[k], |
| (last_frame_lost || !frameOk), 0 /* is not FD FAC */ |
| , |
| last_lpd_mode, k, |
| pAacDecoderChannelInfo |
| ->currAliasingSymmetry /* Note: The current aliasing |
| symmetry for a TCX (i.e. LPD) |
| frame must always be 0 */ |
| ); |
| |
| pitch[(k * nbSubfr) + synSfd + 1] = pitch[(k * nbSubfr) + synSfd] = |
| pitch[(k * nbSubfr) + synSfd - 1]; |
| pit_gain[(k * nbSubfr) + synSfd + 1] = |
| pit_gain[(k * nbSubfr) + synSfd] = |
| pit_gain[(k * nbSubfr) + synSfd - 1]; |
| |
| C_AALLOC_SCRATCH_END(fac_buf, FIXP_DBL, 1024 / 8); |
| } else { |
| int tl = lg; |
| int fl = lDiv; |
| int fr = lDiv; |
| |
| nrSamples += imlt_block( |
| &pAacDecoderStaticChannelInfo->IMdct, synth + nrSamples, |
| SPEC_TCX(pAacDecoderChannelInfo->pSpectralCoefficient, k, |
| pAacDecoderChannelInfo->granuleLength, isFullBandLpd), |
| pAacDecoderChannelInfo->specScale + k, 1, lFrame - nrSamples, tl, |
| FDKgetWindowSlope(fl, |
| GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), |
| fl, |
| FDKgetWindowSlope(fr, |
| GetWindowShape(&pAacDecoderChannelInfo->icsInfo)), |
| fr, pAacDecoderChannelInfo->data.usac.tcx_gain[k], |
| pAacDecoderChannelInfo->currAliasingSymmetry |
| ? MLT_FLAG_CURR_ALIAS_SYMMETRY |
| : 0); |
| } |
| } |
| /* remember previous mode */ |
| last_last_lpd_mode = last_lpd_mode; |
| last_lpd_mode = mod[k]; |
| last_lpc_lost = (frameOk == 0) ? 1 : 0; |
| |
| /* Increase k to next frame */ |
| last_k = k; |
| k += ((mod[k] & 0x3) == 0) ? 1 : (1 << (mod[k] - 1)); |
| } |
| |
| if (frameOk) { |
| /* assume data was ok => store for concealment */ |
| FDK_ASSERT(pAacDecoderChannelInfo->data.usac.aStability[last_k] >= |
| (FIXP_SGL)0); |
| pAacDecoderStaticChannelInfo->oldStability = |
| pAacDecoderChannelInfo->data.usac.aStability[last_k]; |
| FDKmemcpy(pAacDecoderStaticChannelInfo->lsf_adaptive_mean, |
| pAacDecoderChannelInfo->data.usac.lsf_adaptive_mean_cand, |
| M_LP_FILTER_ORDER * sizeof(FIXP_LPC)); |
| } |
| |
| /* store past lp coeffs for next superframe (they are only valid and needed if |
| * last_lpd_mode was tcx) */ |
| if (last_lpd_mode > 0) { |
| FDKmemcpy(pAacDecoderStaticChannelInfo->lp_coeff_old[0], |
| pAacDecoderChannelInfo->data.usac.lp_coeff[nbDiv], |
| M_LP_FILTER_ORDER * sizeof(FIXP_LPC)); |
| pAacDecoderStaticChannelInfo->lp_coeff_old_exp[0] = |
| pAacDecoderChannelInfo->data.usac.lp_coeff_exp[nbDiv]; |
| FDKmemcpy(pAacDecoderStaticChannelInfo->lp_coeff_old[1], |
| pAacDecoderChannelInfo->data.usac.lp_coeff[last_k], |
| M_LP_FILTER_ORDER * sizeof(FIXP_LPC)); |
| pAacDecoderStaticChannelInfo->lp_coeff_old_exp[1] = |
| pAacDecoderChannelInfo->data.usac.lp_coeff_exp[last_k]; |
| } |
| |
| FDK_ASSERT(nrSamples == lFrame); |
| |
| /* check whether usage of bass postfilter was de-activated in the bitstream; |
| if yes, set pitch gain to 0 */ |
| if (!(pAacDecoderChannelInfo->data.usac.bpf_control_info)) { |
| if (mod[0] != 0 && (pAacDecoderStaticChannelInfo->old_bpf_control_info)) { |
| for (int i = 2; i < nbSubfrSuperfr; i++) |
| pit_gain[synSfd + i] = (FIXP_DBL)0; |
| } else { |
| for (int i = 0; i < nbSubfrSuperfr; i++) |
| pit_gain[synSfd + i] = (FIXP_DBL)0; |
| } |
| } |
| |
| /* for bass postfilter */ |
| for (int n = 0; n < synSfd; n++) { |
| pAacDecoderStaticChannelInfo->old_T_pf[n] = pitch[nbSubfrSuperfr + n]; |
| pAacDecoderStaticChannelInfo->old_gain_pf[n] = pit_gain[nbSubfrSuperfr + n]; |
| } |
| |
| pAacDecoderStaticChannelInfo->old_bpf_control_info = |
| pAacDecoderChannelInfo->data.usac.bpf_control_info; |
| |
| { |
| INT lookahead = -BPF_DELAY; |
| int copySamp = (mod[nbDiv - 1] == 0) ? (aacDelay) : (aacDelay - lFac); |
| |
| /* Copy enough time domain samples from MDCT to synthesis buffer as needed |
| * by the bass postfilter */ |
| |
| lookahead += imdct_copy_ov_and_nr(&pAacDecoderStaticChannelInfo->IMdct, |
| synth + nrSamples, copySamp); |
| |
| FDK_ASSERT(lookahead == copySamp - BPF_DELAY); |
| |
| FIXP_DBL *p2_synth = synth + BPF_DELAY; |
| |
| /* recalculate pitch gain to allow postfilering on FAC area */ |
| for (int i = 0; i < nbSubfrSuperfr; i++) { |
| int T = pitch[i]; |
| FIXP_DBL gain = pit_gain[i]; |
| |
| if (gain > (FIXP_DBL)0) { |
| gain = get_gain(&p2_synth[i * L_SUBFR], &p2_synth[(i * L_SUBFR) - T], |
| L_SUBFR); |
| pit_gain[i] = gain; |
| } |
| } |
| |
| { |
| bass_pf_1sf_delay(p2_synth, pitch, pit_gain, lFrame, lFrame / facFB, |
| mod[nbDiv - 1] ? (SynDelay - (lDiv / 2)) : SynDelay, |
| pTimeData, pAacDecoderStaticChannelInfo->mem_bpf); |
| } |
| } |
| |
| Acelp_PostProcessing(synth_buf, pAacDecoderStaticChannelInfo->old_synth, |
| pitch, pAacDecoderStaticChannelInfo->old_T_pf, lFrame, |
| synSfd, nbSubfrSuperfr); |
| |
| /* Store last mode for next super frame */ |
| { pAacDecoderStaticChannelInfo->last_core_mode = LPD; } |
| pAacDecoderStaticChannelInfo->last_lpd_mode = last_lpd_mode; |
| pAacDecoderStaticChannelInfo->last_last_lpd_mode = last_last_lpd_mode; |
| pAacDecoderStaticChannelInfo->last_lpc_lost = last_lpc_lost; |
| |
| return error; |
| } |