mirror of
https://github.com/mstorsjo/fdk-aac.git
synced 2025-02-10 00:20:35 +01:00
2030 lines
69 KiB
C++
2030 lines
69 KiB
C++
/* -----------------------------------------------------------------------------
|
|
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;
|
|
s = fMin(31, s);
|
|
|
|
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 ((samplingRate < 6000) || (samplingRate > 24000)) {
|
|
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;
|
|
}
|