diff options
Diffstat (limited to 'fdk-aac/libSBRenc/src/env_est.cpp')
-rw-r--r-- | fdk-aac/libSBRenc/src/env_est.cpp | 1986 |
1 files changed, 1986 insertions, 0 deletions
diff --git a/fdk-aac/libSBRenc/src/env_est.cpp b/fdk-aac/libSBRenc/src/env_est.cpp new file mode 100644 index 0000000..4af561b --- /dev/null +++ b/fdk-aac/libSBRenc/src/env_est.cpp @@ -0,0 +1,1986 @@ +/* ----------------------------------------------------------------------------- +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 +----------------------------------------------------------------------------- */ + +/**************************** SBR encoder library ****************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "env_est.h" +#include "tran_det.h" + +#include "qmf.h" + +#include "fram_gen.h" +#include "bit_sbr.h" +#include "cmondata.h" +#include "sbrenc_ram.h" + +#include "genericStds.h" + +#define QUANT_ERROR_THRES 200 +#define Y_NRG_SCALE 5 /* noCols = 32 -> shift(5) */ +#define MAX_NRG_SLOTS_LD 16 + +static const UCHAR panTable[2][10] = {{0, 2, 4, 6, 8, 12, 16, 20, 24}, + {0, 2, 4, 8, 12, 0, 0, 0, 0}}; +static const UCHAR maxIndex[2] = {9, 5}; + +/****************************************************************************** + Functionname: FDKsbrEnc_GetTonality +******************************************************************************/ +/***************************************************************************/ +/*! + + \brief Calculates complete energy per band from the energy values + of the QMF subsamples. + + \brief quotaMatrix - calculated in FDKsbrEnc_CalculateTonalityQuotas() + \brief noEstPerFrame - number of estimations per frame + \brief startIndex - start index for the quota matrix + \brief Energies - energy matrix + \brief startBand - start band + \brief stopBand - number of QMF bands + \brief numberCols - number of QMF subsamples + + \return mean tonality of the 5 bands with the highest energy + scaled by 2^(RELAXATION_SHIFT+2)*RELAXATION_FRACT + +****************************************************************************/ +static FIXP_DBL FDKsbrEnc_GetTonality(const FIXP_DBL *const *quotaMatrix, + const INT noEstPerFrame, + const INT startIndex, + const FIXP_DBL *const *Energies, + const UCHAR startBand, const INT stopBand, + const INT numberCols) { + UCHAR b, e, k; + INT no_enMaxBand[SBR_MAX_ENERGY_VALUES] = {-1, -1, -1, -1, -1}; + FIXP_DBL energyMax[SBR_MAX_ENERGY_VALUES] = { + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f)}; + FIXP_DBL energyMaxMin = MAXVAL_DBL; /* min. energy in energyMax array */ + UCHAR posEnergyMaxMin = 0; /* min. energy in energyMax array position */ + FIXP_DBL tonalityBand[SBR_MAX_ENERGY_VALUES] = { + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f), + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(0.0f)}; + FIXP_DBL globalTonality = FL2FXCONST_DBL(0.0f); + FIXP_DBL energyBand[64]; + INT maxNEnergyValues; /* max. number of max. energy values */ + + /*** Sum up energies for each band ***/ + FDK_ASSERT(numberCols == 15 || numberCols == 16); + /* numberCols is always 15 or 16 for ELD. In case of 16 bands, the + energyBands are initialized with the [15]th column. + The rest of the column energies are added in the next step. */ + if (numberCols == 15) { + for (b = startBand; b < stopBand; b++) { + energyBand[b] = FL2FXCONST_DBL(0.0f); + } + } else { + for (b = startBand; b < stopBand; b++) { + energyBand[b] = Energies[15][b] >> 4; + } + } + + for (k = 0; k < 15; k++) { + for (b = startBand; b < stopBand; b++) { + energyBand[b] += Energies[k][b] >> 4; + } + } + + /*** Determine 5 highest band-energies ***/ + maxNEnergyValues = fMin(SBR_MAX_ENERGY_VALUES, stopBand - startBand); + + /* Get min. value in energyMax array */ + energyMaxMin = energyMax[0] = energyBand[startBand]; + no_enMaxBand[0] = startBand; + posEnergyMaxMin = 0; + for (k = 1; k < maxNEnergyValues; k++) { + energyMax[k] = energyBand[startBand + k]; + no_enMaxBand[k] = startBand + k; + if (energyMaxMin > energyMax[k]) { + energyMaxMin = energyMax[k]; + posEnergyMaxMin = k; + } + } + + for (b = startBand + maxNEnergyValues; b < stopBand; b++) { + if (energyBand[b] > energyMaxMin) { + energyMax[posEnergyMaxMin] = energyBand[b]; + no_enMaxBand[posEnergyMaxMin] = b; + + /* Again, get min. value in energyMax array */ + energyMaxMin = energyMax[0]; + posEnergyMaxMin = 0; + for (k = 1; k < maxNEnergyValues; k++) { + if (energyMaxMin > energyMax[k]) { + energyMaxMin = energyMax[k]; + posEnergyMaxMin = k; + } + } + } + } + /*** End determine 5 highest band-energies ***/ + + /* Get tonality values for 5 highest energies */ + for (e = 0; e < maxNEnergyValues; e++) { + tonalityBand[e] = FL2FXCONST_DBL(0.0f); + for (k = 0; k < noEstPerFrame; k++) { + tonalityBand[e] += quotaMatrix[startIndex + k][no_enMaxBand[e]] >> 1; + } + globalTonality += + tonalityBand[e] >> 2; /* headroom of 2+1 (max. 5 additions) */ + } + + return globalTonality; +} + +/***************************************************************************/ +/*! + + \brief Calculates energy form real and imaginary part of + the QMF subsamples + + \return none + +****************************************************************************/ +LNK_SECTION_CODE_L1 +static void FDKsbrEnc_getEnergyFromCplxQmfData( + FIXP_DBL **RESTRICT energyValues, /*!< the result of the operation */ + FIXP_DBL **RESTRICT realValues, /*!< the real part of the QMF subsamples */ + FIXP_DBL **RESTRICT + imagValues, /*!< the imaginary part of the QMF subsamples */ + INT numberBands, /*!< number of QMF bands */ + INT numberCols, /*!< number of QMF subsamples */ + INT *qmfScale, /*!< sclefactor of QMF subsamples */ + INT *energyScale) /*!< scalefactor of energies */ +{ + int j, k; + int scale; + FIXP_DBL max_val = FL2FXCONST_DBL(0.0f); + + /* Get Scratch buffer */ + C_ALLOC_SCRATCH_START(tmpNrg, FIXP_DBL, 32 * 64 / 2) + + /* Get max possible scaling of QMF data */ + scale = DFRACT_BITS; + for (k = 0; k < numberCols; k++) { + scale = fixMin(scale, fixMin(getScalefactor(realValues[k], numberBands), + getScalefactor(imagValues[k], numberBands))); + } + + /* Tweak scaling stability for zero signal to non-zero signal transitions */ + if (scale >= DFRACT_BITS - 1) { + scale = (FRACT_BITS - 1 - *qmfScale); + } + /* prevent scaling of QMF values to -1.f */ + scale = fixMax(0, scale - 1); + + /* Update QMF scale */ + *qmfScale += scale; + + /* + Calculate energy of each time slot pair, max energy + and shift QMF values as far as possible to the left. + */ + { + FIXP_DBL *nrgValues = tmpNrg; + for (k = 0; k < numberCols; k += 2) { + /* Load band vector addresses of 2 consecutive timeslots */ + FIXP_DBL *RESTRICT r0 = realValues[k]; + FIXP_DBL *RESTRICT i0 = imagValues[k]; + FIXP_DBL *RESTRICT r1 = realValues[k + 1]; + FIXP_DBL *RESTRICT i1 = imagValues[k + 1]; + for (j = 0; j < numberBands; j++) { + FIXP_DBL energy; + FIXP_DBL tr0, tr1, ti0, ti1; + + /* Read QMF values of 2 timeslots */ + tr0 = r0[j]; + tr1 = r1[j]; + ti0 = i0[j]; + ti1 = i1[j]; + + /* Scale QMF Values and Calc Energy average of both timeslots */ + tr0 <<= scale; + ti0 <<= scale; + energy = fPow2AddDiv2(fPow2Div2(tr0), ti0) >> 1; + + tr1 <<= scale; + ti1 <<= scale; + energy += fPow2AddDiv2(fPow2Div2(tr1), ti1) >> 1; + + /* Write timeslot pair energy to scratch */ + *nrgValues++ = energy; + max_val = fixMax(max_val, energy); + + /* Write back scaled QMF values */ + r0[j] = tr0; + r1[j] = tr1; + i0[j] = ti0; + i1[j] = ti1; + } + } + } + /* energyScale: scalefactor energies of current frame */ + *energyScale = + 2 * (*qmfScale) - + 1; /* if qmfScale > 0: nr of right shifts otherwise nr of left shifts */ + + /* Scale timeslot pair energies and write to output buffer */ + scale = CountLeadingBits(max_val); + { + FIXP_DBL *nrgValues = tmpNrg; + for (k = 0; k<numberCols>> 1; k++) { + scaleValues(energyValues[k], nrgValues, numberBands, scale); + nrgValues += numberBands; + } + *energyScale += scale; + } + + /* Free Scratch buffer */ + C_ALLOC_SCRATCH_END(tmpNrg, FIXP_DBL, 32 * 64 / 2) +} + +LNK_SECTION_CODE_L1 +static void FDKsbrEnc_getEnergyFromCplxQmfDataFull( + FIXP_DBL **RESTRICT energyValues, /*!< the result of the operation */ + FIXP_DBL **RESTRICT realValues, /*!< the real part of the QMF subsamples */ + FIXP_DBL **RESTRICT + imagValues, /*!< the imaginary part of the QMF subsamples */ + int numberBands, /*!< number of QMF bands */ + int numberCols, /*!< number of QMF subsamples */ + int *qmfScale, /*!< scalefactor of QMF subsamples */ + int *energyScale) /*!< scalefactor of energies */ +{ + int j, k; + int scale; + FIXP_DBL max_val = FL2FXCONST_DBL(0.0f); + + /* Get Scratch buffer */ + C_ALLOC_SCRATCH_START(tmpNrg, FIXP_DBL, MAX_NRG_SLOTS_LD * 64) + + FDK_ASSERT(numberCols <= MAX_NRG_SLOTS_LD); + FDK_ASSERT(numberBands <= 64); + + /* Get max possible scaling of QMF data */ + scale = DFRACT_BITS; + for (k = 0; k < numberCols; k++) { + scale = fixMin(scale, fixMin(getScalefactor(realValues[k], numberBands), + getScalefactor(imagValues[k], numberBands))); + } + + /* Tweak scaling stability for zero signal to non-zero signal transitions */ + if (scale >= DFRACT_BITS - 1) { + scale = (FRACT_BITS - 1 - *qmfScale); + } + /* prevent scaling of QFM values to -1.f */ + scale = fixMax(0, scale - 1); + + /* Update QMF scale */ + *qmfScale += scale; + + /* + Calculate energy of each time slot pair, max energy + and shift QMF values as far as possible to the left. + */ + { + FIXP_DBL *nrgValues = tmpNrg; + for (k = 0; k < numberCols; k++) { + /* Load band vector addresses of 1 timeslot */ + FIXP_DBL *RESTRICT r0 = realValues[k]; + FIXP_DBL *RESTRICT i0 = imagValues[k]; + for (j = 0; j < numberBands; j++) { + FIXP_DBL energy; + FIXP_DBL tr0, ti0; + + /* Read QMF values of 1 timeslot */ + tr0 = r0[j]; + ti0 = i0[j]; + + /* Scale QMF Values and Calc Energy */ + tr0 <<= scale; + ti0 <<= scale; + energy = fPow2AddDiv2(fPow2Div2(tr0), ti0); + *nrgValues++ = energy; + + max_val = fixMax(max_val, energy); + + /* Write back scaled QMF values */ + r0[j] = tr0; + i0[j] = ti0; + } + } + } + /* energyScale: scalefactor energies of current frame */ + *energyScale = + 2 * (*qmfScale) - + 1; /* if qmfScale > 0: nr of right shifts otherwise nr of left shifts */ + + /* Scale timeslot pair energies and write to output buffer */ + scale = CountLeadingBits(max_val); + { + FIXP_DBL *nrgValues = tmpNrg; + for (k = 0; k < numberCols; k++) { + scaleValues(energyValues[k], nrgValues, numberBands, scale); + nrgValues += numberBands; + } + *energyScale += scale; + } + + /* Free Scratch buffer */ + C_ALLOC_SCRATCH_END(tmpNrg, FIXP_DBL, MAX_NRG_SLOTS_LD * 64) +} + +/***************************************************************************/ +/*! + + \brief Quantisation of the panorama value (balance) + + \return the quantized pan value + +****************************************************************************/ +static INT mapPanorama(INT nrgVal, /*! integer value of the energy */ + INT ampRes, /*! amplitude resolution [1.5/3dB] */ + INT *quantError /*! quantization error of energy val*/ +) { + int i; + INT min_val, val; + UCHAR panIndex; + INT sign; + + sign = nrgVal > 0 ? 1 : -1; + + nrgVal *= sign; + + min_val = FDK_INT_MAX; + panIndex = 0; + for (i = 0; i < maxIndex[ampRes]; i++) { + val = fixp_abs((nrgVal - (INT)panTable[ampRes][i])); + + if (val < min_val) { + min_val = val; + panIndex = i; + } + } + + *quantError = min_val; + + return panTable[ampRes][maxIndex[ampRes] - 1] + + sign * panTable[ampRes][panIndex]; +} + +/***************************************************************************/ +/*! + + \brief Quantisation of the noise floor levels + + \return void + +****************************************************************************/ +static void sbrNoiseFloorLevelsQuantisation( + SCHAR *RESTRICT iNoiseLevels, /*! quantized noise levels */ + FIXP_DBL *RESTRICT + NoiseLevels, /*! the noise levels. Exponent = LD_DATA_SHIFT */ + INT coupling /*! the coupling flag */ +) { + INT i; + INT tmp, dummy; + + /* Quantisation, similar to sfb quant... */ + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) { + /* tmp = NoiseLevels[i] > (PFLOAT)30.0f ? 30: (INT) (NoiseLevels[i] + + * (PFLOAT)0.5); */ + /* 30>>LD_DATA_SHIFT = 0.46875 */ + if ((FIXP_DBL)NoiseLevels[i] > FL2FXCONST_DBL(0.46875f)) { + tmp = 30; + } else { + /* tmp = (INT)((FIXP_DBL)NoiseLevels[i] + (FL2FXCONST_DBL(0.5f)>>(*/ + /* FRACT_BITS+ */ /* 6-1)));*/ + /* tmp = tmp >> (DFRACT_BITS-1-LD_DATA_SHIFT); */ /* conversion to integer + happens here */ + /* rounding is done by shifting one bit less than necessary to the right, + * adding '1' and then shifting the final bit */ + tmp = ((((INT)NoiseLevels[i]) >> + (DFRACT_BITS - 1 - LD_DATA_SHIFT))); /* conversion to integer */ + if (tmp != 0) tmp += 1; + } + + if (coupling) { + tmp = tmp < -30 ? -30 : tmp; + tmp = mapPanorama(tmp, 1, &dummy); + } + iNoiseLevels[i] = tmp; + } +} + +/***************************************************************************/ +/*! + + \brief Calculation of noise floor for coupling + + \return void + +****************************************************************************/ +static void coupleNoiseFloor( + FIXP_DBL *RESTRICT noise_level_left, /*! noise level left (modified)*/ + FIXP_DBL *RESTRICT noise_level_right /*! noise level right (modified)*/ +) { + FIXP_DBL cmpValLeft, cmpValRight; + INT i; + FIXP_DBL temp1, temp2; + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) { + /* Calculation of the power function using ld64: + z = x^y; + z' = CalcLd64(z) = y*CalcLd64(x)/64; + z = CalcInvLd64(z'); + */ + cmpValLeft = NOISE_FLOOR_OFFSET_64 - noise_level_left[i]; + cmpValRight = NOISE_FLOOR_OFFSET_64 - noise_level_right[i]; + + if (cmpValRight < FL2FXCONST_DBL(0.0f)) { + temp1 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_right[i]); + } else { + temp1 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_right[i]); + temp1 = temp1 << (DFRACT_BITS - 1 - LD_DATA_SHIFT - + 1); /* INT to fract conversion of result, if input of + CalcInvLdData is positiv */ + } + + if (cmpValLeft < FL2FXCONST_DBL(0.0f)) { + temp2 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_left[i]); + } else { + temp2 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_left[i]); + temp2 = temp2 << (DFRACT_BITS - 1 - LD_DATA_SHIFT - + 1); /* INT to fract conversion of result, if input of + CalcInvLdData is positiv */ + } + + if ((cmpValLeft < FL2FXCONST_DBL(0.0f)) && + (cmpValRight < FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = + NOISE_FLOOR_OFFSET_64 - + (CalcLdData( + ((temp1 >> 1) + + (temp2 >> 1)))); /* no scaling needed! both values are dfract */ + noise_level_right[i] = CalcLdData(temp2) - CalcLdData(temp1); + } + + if ((cmpValLeft >= FL2FXCONST_DBL(0.0f)) && + (cmpValRight >= FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - + (CalcLdData(((temp1 >> 1) + (temp2 >> 1))) + + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = CalcLdData(temp2) - CalcLdData(temp1); + } + + if ((cmpValLeft >= FL2FXCONST_DBL(0.0f)) && + (cmpValRight < FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - + (CalcLdData(((temp1 >> (7 + 1)) + (temp2 >> 1))) + + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = + (CalcLdData(temp2) + FL2FXCONST_DBL(0.109375f)) - CalcLdData(temp1); + } + + if ((cmpValLeft < FL2FXCONST_DBL(0.0f)) && + (cmpValRight >= FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - + (CalcLdData(((temp1 >> 1) + (temp2 >> (7 + 1)))) + + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = CalcLdData(temp2) - + (CalcLdData(temp1) + + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + } + } +} + +/***************************************************************************/ +/*! + + \brief Calculation of energy starting in lower band (li) up to upper band +(ui) over slots (start_pos) to (stop_pos) + + \return void + +****************************************************************************/ + +static FIXP_DBL getEnvSfbEnergy( + INT li, /*! lower band */ + INT ui, /*! upper band */ + INT start_pos, /*! start slot */ + INT stop_pos, /*! stop slot */ + INT border_pos, /*! slots scaling border */ + FIXP_DBL **YBuffer, /*! sfb energy buffer */ + INT YBufferSzShift, /*! Energy buffer index scale */ + INT scaleNrg0, /*! scaling of lower slots */ + INT scaleNrg1) /*! scaling of upper slots */ +{ + /* use dynamic scaling for outer energy loop; + energies are critical and every bit is important */ + int sc0, sc1, k, l; + + FIXP_DBL nrgSum, nrg1, nrg2, accu1, accu2; + INT dynScale, dynScale1, dynScale2; + if (ui - li == 0) + dynScale = DFRACT_BITS - 1; + else + dynScale = CalcLdInt(ui - li) >> (DFRACT_BITS - 1 - LD_DATA_SHIFT); + + sc0 = fixMin(scaleNrg0, Y_NRG_SCALE); + sc1 = fixMin(scaleNrg1, Y_NRG_SCALE); + /* dynScale{1,2} is set such that the right shift below is positive */ + dynScale1 = fixMin((scaleNrg0 - sc0), dynScale); + dynScale2 = fixMin((scaleNrg1 - sc1), dynScale); + nrgSum = accu1 = accu2 = (FIXP_DBL)0; + + for (k = li; k < ui; k++) { + nrg1 = nrg2 = (FIXP_DBL)0; + for (l = start_pos; l < border_pos; l++) { + nrg1 += YBuffer[l >> YBufferSzShift][k] >> sc0; + } + for (; l < stop_pos; l++) { + nrg2 += YBuffer[l >> YBufferSzShift][k] >> sc1; + } + accu1 += (nrg1 >> dynScale1); + accu2 += (nrg2 >> dynScale2); + } + /* This shift factor is always positive. See comment above. */ + nrgSum += + (accu1 >> fixMin((scaleNrg0 - sc0 - dynScale1), (DFRACT_BITS - 1))) + + (accu2 >> fixMin((scaleNrg1 - sc1 - dynScale2), (DFRACT_BITS - 1))); + + return nrgSum; +} + +/***************************************************************************/ +/*! + + \brief Energy compensation in missing harmonic mode + + \return void + +****************************************************************************/ +static FIXP_DBL mhLoweringEnergy(FIXP_DBL nrg, INT M) { + /* + Compensating for the fact that we in the decoder map the "average energy to + every QMF band, and use this when we calculate the boost-factor. Since the + mapped energy isn't the average energy but the maximum energy in case of + missing harmonic creation, we will in the boost function calculate that too + much limiting has been applied and hence we will boost the signal although + it isn't called for. Hence we need to compensate for this by lowering the + transmitted energy values for the sines so they will get the correct level + after the boost is applied. + */ + if (M > 2) { + INT tmpScale; + tmpScale = CountLeadingBits(nrg); + nrg <<= tmpScale; + nrg = fMult(nrg, FL2FXCONST_DBL(0.398107267f)); /* The maximum boost + is 1.584893, so the + maximum attenuation + should be + square(1/1.584893) = + 0.398107267 */ + nrg >>= tmpScale; + } else { + if (M > 1) { + nrg >>= 1; + } + } + + return nrg; +} + +/***************************************************************************/ +/*! + + \brief Energy compensation in none missing harmonic mode + + \return void + +****************************************************************************/ +static FIXP_DBL nmhLoweringEnergy(FIXP_DBL nrg, const FIXP_DBL nrgSum, + const INT nrgSum_scale, const INT M) { + if (nrg > FL2FXCONST_DBL(0)) { + int sc = 0; + /* gain = nrgSum / (nrg*(M+1)) */ + FIXP_DBL gain = fMult(fDivNorm(nrgSum, nrg, &sc), GetInvInt(M + 1)); + sc += nrgSum_scale; + + /* reduce nrg if gain smaller 1.f */ + if (!((sc >= 0) && (gain > ((FIXP_DBL)MAXVAL_DBL >> sc)))) { + nrg = fMult(scaleValue(gain, sc), nrg); + } + } + return nrg; +} + +/***************************************************************************/ +/*! + + \brief calculates the envelope values from the energies, depending on + framing and stereo mode + + \return void + +****************************************************************************/ +static void calculateSbrEnvelope( + FIXP_DBL **RESTRICT YBufferLeft, /*! energy buffer left */ + FIXP_DBL **RESTRICT YBufferRight, /*! energy buffer right */ + int *RESTRICT YBufferScaleLeft, /*! scale energy buffer left */ + int *RESTRICT YBufferScaleRight, /*! scale energy buffer right */ + const SBR_FRAME_INFO *frame_info, /*! frame info vector */ + SCHAR *RESTRICT sfb_nrgLeft, /*! sfb energy buffer left */ + SCHAR *RESTRICT sfb_nrgRight, /*! sfb energy buffer right */ + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_ENV_CHANNEL h_sbr, /*! envelope channel handle */ + SBR_STEREO_MODE stereoMode, /*! stereo coding mode */ + INT *maxQuantError, /*! maximum quantization error, for panorama. */ + int YBufferSzShift) /*! Energy buffer index scale */ + +{ + int env, j, m = 0; + INT no_of_bands, start_pos, stop_pos, li, ui; + FREQ_RES freq_res; + + INT ca = 2 - h_sbr->encEnvData.init_sbr_amp_res; + INT oneBitLess = 0; + if (ca == 2) + oneBitLess = + 1; /* LD_DATA_SHIFT => ld64 scaling; one bit less for rounding */ + + INT quantError; + INT nEnvelopes = frame_info->nEnvelopes; + INT short_env = frame_info->shortEnv - 1; + INT timeStep = h_sbr->sbrExtractEnvelope.time_step; + INT commonScale, scaleLeft0, scaleLeft1; + INT scaleRight0 = 0, scaleRight1 = 0; + + commonScale = fixMin(YBufferScaleLeft[0], YBufferScaleLeft[1]); + + if (stereoMode == SBR_COUPLING) { + commonScale = fixMin(commonScale, YBufferScaleRight[0]); + commonScale = fixMin(commonScale, YBufferScaleRight[1]); + } + + commonScale = commonScale - 7; + + scaleLeft0 = YBufferScaleLeft[0] - commonScale; + scaleLeft1 = YBufferScaleLeft[1] - commonScale; + FDK_ASSERT((scaleLeft0 >= 0) && (scaleLeft1 >= 0)); + + if (stereoMode == SBR_COUPLING) { + scaleRight0 = YBufferScaleRight[0] - commonScale; + scaleRight1 = YBufferScaleRight[1] - commonScale; + FDK_ASSERT((scaleRight0 >= 0) && (scaleRight1 >= 0)); + *maxQuantError = 0; + } + + for (env = 0; env < nEnvelopes; env++) { + FIXP_DBL pNrgLeft[32]; + FIXP_DBL pNrgRight[32]; + int envNrg_scale; + FIXP_DBL envNrgLeft = FL2FXCONST_DBL(0.0f); + FIXP_DBL envNrgRight = FL2FXCONST_DBL(0.0f); + int missingHarmonic[32]; + int count[32]; + + start_pos = timeStep * frame_info->borders[env]; + stop_pos = timeStep * frame_info->borders[env + 1]; + freq_res = frame_info->freqRes[env]; + no_of_bands = h_con->nSfb[freq_res]; + envNrg_scale = DFRACT_BITS - fNormz((FIXP_DBL)no_of_bands); + if (env == short_env) { + j = fMax(2, timeStep); /* consider at least 2 QMF slots less for short + envelopes (envelopes just before transients) */ + if ((stop_pos - start_pos - j) > 0) { + stop_pos = stop_pos - j; + } + } + for (j = 0; j < no_of_bands; j++) { + FIXP_DBL nrgLeft = FL2FXCONST_DBL(0.0f); + FIXP_DBL nrgRight = FL2FXCONST_DBL(0.0f); + + li = h_con->freqBandTable[freq_res][j]; + ui = h_con->freqBandTable[freq_res][j + 1]; + + if (freq_res == FREQ_RES_HIGH) { + if (j == 0 && ui - li > 1) { + li++; + } + } else { + if (j == 0 && ui - li > 2) { + li++; + } + } + + /* + Find out whether a sine will be missing in the scale-factor + band that we're currently processing. + */ + missingHarmonic[j] = 0; + + if (h_sbr->encEnvData.addHarmonicFlag) { + if (freq_res == FREQ_RES_HIGH) { + if (h_sbr->encEnvData + .addHarmonic[j]) { /*A missing sine in the current band*/ + missingHarmonic[j] = 1; + } + } else { + INT i; + INT startBandHigh = 0; + INT stopBandHigh = 0; + + while (h_con->freqBandTable[FREQ_RES_HIGH][startBandHigh] < + h_con->freqBandTable[FREQ_RES_LOW][j]) + startBandHigh++; + while (h_con->freqBandTable[FREQ_RES_HIGH][stopBandHigh] < + h_con->freqBandTable[FREQ_RES_LOW][j + 1]) + stopBandHigh++; + + for (i = startBandHigh; i < stopBandHigh; i++) { + if (h_sbr->encEnvData.addHarmonic[i]) { + missingHarmonic[j] = 1; + } + } + } + } + + /* + If a sine is missing in a scalefactorband, with more than one qmf + channel use the nrg from the channel with the largest nrg rather than + the mean. Compensate for the boost calculation in the decdoder. + */ + int border_pos = + fixMin(stop_pos, h_sbr->sbrExtractEnvelope.YBufferWriteOffset + << YBufferSzShift); + + if (missingHarmonic[j]) { + int k; + count[j] = stop_pos - start_pos; + nrgLeft = FL2FXCONST_DBL(0.0f); + + for (k = li; k < ui; k++) { + FIXP_DBL tmpNrg; + tmpNrg = getEnvSfbEnergy(k, k + 1, start_pos, stop_pos, border_pos, + YBufferLeft, YBufferSzShift, scaleLeft0, + scaleLeft1); + + nrgLeft = fixMax(nrgLeft, tmpNrg); + } + + /* Energy lowering compensation */ + nrgLeft = mhLoweringEnergy(nrgLeft, ui - li); + + if (stereoMode == SBR_COUPLING) { + nrgRight = FL2FXCONST_DBL(0.0f); + + for (k = li; k < ui; k++) { + FIXP_DBL tmpNrg; + tmpNrg = getEnvSfbEnergy(k, k + 1, start_pos, stop_pos, border_pos, + YBufferRight, YBufferSzShift, scaleRight0, + scaleRight1); + + nrgRight = fixMax(nrgRight, tmpNrg); + } + + /* Energy lowering compensation */ + nrgRight = mhLoweringEnergy(nrgRight, ui - li); + } + } /* end missingHarmonic */ + else { + count[j] = (stop_pos - start_pos) * (ui - li); + + nrgLeft = getEnvSfbEnergy(li, ui, start_pos, stop_pos, border_pos, + YBufferLeft, YBufferSzShift, scaleLeft0, + scaleLeft1); + + if (stereoMode == SBR_COUPLING) { + nrgRight = getEnvSfbEnergy(li, ui, start_pos, stop_pos, border_pos, + YBufferRight, YBufferSzShift, scaleRight0, + scaleRight1); + } + } /* !missingHarmonic */ + + /* save energies */ + pNrgLeft[j] = nrgLeft; + pNrgRight[j] = nrgRight; + envNrgLeft += (nrgLeft >> envNrg_scale); + envNrgRight += (nrgRight >> envNrg_scale); + } /* j */ + + for (j = 0; j < no_of_bands; j++) { + FIXP_DBL nrgLeft2 = FL2FXCONST_DBL(0.0f); + FIXP_DBL nrgLeft = pNrgLeft[j]; + FIXP_DBL nrgRight = pNrgRight[j]; + + /* None missing harmonic Energy lowering compensation */ + if (!missingHarmonic[j] && h_sbr->fLevelProtect) { + /* in case of missing energy in base band, + reduce reference energy to prevent overflows in decoder output */ + nrgLeft = + nmhLoweringEnergy(nrgLeft, envNrgLeft, envNrg_scale, no_of_bands); + if (stereoMode == SBR_COUPLING) { + nrgRight = nmhLoweringEnergy(nrgRight, envNrgRight, envNrg_scale, + no_of_bands); + } + } + + if (stereoMode == SBR_COUPLING) { + /* calc operation later with log */ + nrgLeft2 = nrgLeft; + nrgLeft = (nrgRight + nrgLeft) >> 1; + } + + /* nrgLeft = f20_log2(nrgLeft / (PFLOAT)(count * 64))+(PFLOAT)44; */ + /* If nrgLeft == 0 then the Log calculations below do fail. */ + if (nrgLeft > FL2FXCONST_DBL(0.0f)) { + FIXP_DBL tmp0, tmp1, tmp2, tmp3; + INT tmpScale; + + tmpScale = CountLeadingBits(nrgLeft); + nrgLeft = nrgLeft << tmpScale; + + tmp0 = CalcLdData(nrgLeft); /* scaled by 1/64 */ + tmp1 = ((FIXP_DBL)(commonScale + tmpScale)) + << (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1); /* scaled by 1/64 */ + tmp2 = ((FIXP_DBL)(count[j] * 64)) << (DFRACT_BITS - 1 - 14 - 1); + tmp2 = CalcLdData(tmp2); /* scaled by 1/64 */ + tmp3 = FL2FXCONST_DBL(0.6875f - 0.21875f - 0.015625f) >> + 1; /* scaled by 1/64 */ + + nrgLeft = ((tmp0 - tmp2) >> 1) + (tmp3 - tmp1); + } else { + nrgLeft = FL2FXCONST_DBL(-1.0f); + } + + /* ld64 to integer conversion */ + nrgLeft = fixMin(fixMax(nrgLeft, FL2FXCONST_DBL(0.0f)), + (FL2FXCONST_DBL(0.5f) >> oneBitLess)); + nrgLeft = (FIXP_DBL)(LONG)nrgLeft >> + (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1 - oneBitLess - 1); + sfb_nrgLeft[m] = ((INT)nrgLeft + 1) >> 1; /* rounding */ + + if (stereoMode == SBR_COUPLING) { + FIXP_DBL scaleFract; + int sc0, sc1; + + nrgLeft2 = fixMax((FIXP_DBL)0x1, nrgLeft2); + nrgRight = fixMax((FIXP_DBL)0x1, nrgRight); + + sc0 = CountLeadingBits(nrgLeft2); + sc1 = CountLeadingBits(nrgRight); + + scaleFract = + ((FIXP_DBL)(sc0 - sc1)) + << (DFRACT_BITS - 1 - + LD_DATA_SHIFT); /* scale value in ld64 representation */ + nrgRight = CalcLdData(nrgLeft2 << sc0) - CalcLdData(nrgRight << sc1) - + scaleFract; + + /* ld64 to integer conversion */ + nrgRight = (FIXP_DBL)(LONG)(nrgRight) >> + (DFRACT_BITS - 1 - LD_DATA_SHIFT - 1 - oneBitLess); + nrgRight = (nrgRight + (FIXP_DBL)1) >> 1; /* rounding */ + + sfb_nrgRight[m] = mapPanorama( + nrgRight, h_sbr->encEnvData.init_sbr_amp_res, &quantError); + + *maxQuantError = fixMax(quantError, *maxQuantError); + } + + m++; + } /* j */ + + /* Do energy compensation for sines that are present in two + QMF-bands in the original, but will only occur in one band in + the decoder due to the synthetic sine coding.*/ + if (h_con->useParametricCoding) { + m -= no_of_bands; + for (j = 0; j < no_of_bands; j++) { + if (freq_res == FREQ_RES_HIGH && + h_sbr->sbrExtractEnvelope.envelopeCompensation[j]) { + sfb_nrgLeft[m] -= + (ca * + fixp_abs( + (INT)h_sbr->sbrExtractEnvelope.envelopeCompensation[j])); + } + sfb_nrgLeft[m] = fixMax(0, sfb_nrgLeft[m]); + m++; + } + } /* useParametricCoding */ + + } /* env loop */ +} + +/***************************************************************************/ +/*! + + \brief calculates the noise floor and the envelope values from the + energies, depending on framing and stereo mode + + FDKsbrEnc_extractSbrEnvelope is the main function for encoding and writing the + envelope and the noise floor. The function includes the following processes: + + -Analysis subband filtering. + -Encoding SA and pan parameters (if enabled). + -Transient detection. + +****************************************************************************/ + +LNK_SECTION_CODE_L1 +void FDKsbrEnc_extractSbrEnvelope1( + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, HANDLE_ENV_CHANNEL hEnvChan, + HANDLE_COMMON_DATA hCmonData, SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData) { + HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &hEnvChan->sbrExtractEnvelope; + + if (sbrExtrEnv->YBufferSzShift == 0) + FDKsbrEnc_getEnergyFromCplxQmfDataFull( + &sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset], + sbrExtrEnv->rBuffer + sbrExtrEnv->rBufferReadOffset, + sbrExtrEnv->iBuffer + sbrExtrEnv->rBufferReadOffset, h_con->noQmfBands, + sbrExtrEnv->no_cols, &hEnvChan->qmfScale, &sbrExtrEnv->YBufferScale[1]); + else + FDKsbrEnc_getEnergyFromCplxQmfData( + &sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset], + sbrExtrEnv->rBuffer + sbrExtrEnv->rBufferReadOffset, + sbrExtrEnv->iBuffer + sbrExtrEnv->rBufferReadOffset, h_con->noQmfBands, + sbrExtrEnv->no_cols, &hEnvChan->qmfScale, &sbrExtrEnv->YBufferScale[1]); + + /* Energie values = + * sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset][x].floatVal * + * (1<<2*7-sbrExtrEnv->YBufferScale[1]) */ + + /* + Precalculation of Tonality Quotas COEFF Transform OK + */ + FDKsbrEnc_CalculateTonalityQuotas( + &hEnvChan->TonCorr, sbrExtrEnv->rBuffer, sbrExtrEnv->iBuffer, + h_con->freqBandTable[HI][h_con->nSfb[HI]], hEnvChan->qmfScale); + + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + FIXP_DBL tonality = FDKsbrEnc_GetTonality( + hEnvChan->TonCorr.quotaMatrix, + hEnvChan->TonCorr.numberOfEstimatesPerFrame, + hEnvChan->TonCorr.startIndexMatrix, + sbrExtrEnv->YBuffer + sbrExtrEnv->YBufferWriteOffset, + h_con->freqBandTable[HI][0] + 1, h_con->noQmfBands, + sbrExtrEnv->no_cols); + + hEnvChan->encEnvData.ton_HF[1] = hEnvChan->encEnvData.ton_HF[0]; + hEnvChan->encEnvData.ton_HF[0] = tonality; + + /* tonality is scaled by 2^19/0.524288f (fract part of RELAXATION) */ + hEnvChan->encEnvData.global_tonality = + (hEnvChan->encEnvData.ton_HF[0] >> 1) + + (hEnvChan->encEnvData.ton_HF[1] >> 1); + } + + /* + Transient detection COEFF Transform OK + */ + + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + FDKsbrEnc_fastTransientDetect(&hEnvChan->sbrFastTransientDetector, + sbrExtrEnv->YBuffer, sbrExtrEnv->YBufferScale, + sbrExtrEnv->YBufferWriteOffset, + eData->transient_info); + + } else { + FDKsbrEnc_transientDetect( + &hEnvChan->sbrTransientDetector, sbrExtrEnv->YBuffer, + sbrExtrEnv->YBufferScale, eData->transient_info, + sbrExtrEnv->YBufferWriteOffset, sbrExtrEnv->YBufferSzShift, + sbrExtrEnv->time_step, hEnvChan->SbrEnvFrame.frameMiddleSlot); + } + + /* + Generate flags for 2 env in a FIXFIX-frame. + Remove this function to get always 1 env per FIXFIX-frame. + */ + + /* + frame Splitter COEFF Transform OK + */ + FDKsbrEnc_frameSplitter( + sbrExtrEnv->YBuffer, sbrExtrEnv->YBufferScale, + &hEnvChan->sbrTransientDetector, h_con->freqBandTable[1], + eData->transient_info, sbrExtrEnv->YBufferWriteOffset, + sbrExtrEnv->YBufferSzShift, h_con->nSfb[1], sbrExtrEnv->time_step, + sbrExtrEnv->no_cols, &hEnvChan->encEnvData.global_tonality); +} + +/***************************************************************************/ +/*! + + \brief calculates the noise floor and the envelope values from the + energies, depending on framing and stereo mode + + FDKsbrEnc_extractSbrEnvelope is the main function for encoding and writing the + envelope and the noise floor. The function includes the following processes: + + -Determine time/frequency division of current granule. + -Sending transient info to bitstream. + -Set amp_res to 1.5 dB if the current frame contains only one envelope. + -Lock dynamic bandwidth frequency change if the next envelope not starts on a + frame boundary. + -MDCT transposer (needed to detect where harmonics will be missing). + -Spectrum Estimation (used for pulse train and missing harmonics detection). + -Pulse train detection. + -Inverse Filtering detection. + -Waveform Coding. + -Missing Harmonics detection. + -Extract envelope of current frame. + -Noise floor estimation. + -Noise floor quantisation and coding. + -Encode envelope of current frame. + -Send the encoded data to the bitstream. + -Write to bitstream. + +****************************************************************************/ + +LNK_SECTION_CODE_L1 +void FDKsbrEnc_extractSbrEnvelope2( + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, HANDLE_ENV_CHANNEL h_envChan0, + HANDLE_ENV_CHANNEL h_envChan1, HANDLE_COMMON_DATA hCmonData, + SBR_ENV_TEMP_DATA *eData, SBR_FRAME_TEMP_DATA *fData, int clearOutput) { + HANDLE_ENV_CHANNEL h_envChan[MAX_NUM_CHANNELS] = {h_envChan0, h_envChan1}; + int ch, i, j, c, YSzShift = h_envChan[0]->sbrExtractEnvelope.YBufferSzShift; + + SBR_STEREO_MODE stereoMode = h_con->stereoMode; + int nChannels = h_con->nChannels; + FDK_ASSERT(nChannels <= MAX_NUM_CHANNELS); + const int *v_tuning; + static const int v_tuningHEAAC[6] = {0, 2, 4, 0, 0, 0}; + + static const int v_tuningELD[6] = {0, 2, 3, 0, 0, 0}; + + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) + v_tuning = v_tuningELD; + else + v_tuning = v_tuningHEAAC; + + /* + Select stereo mode. + */ + if (stereoMode == SBR_COUPLING) { + if (eData[0].transient_info[1] && eData[1].transient_info[1]) { + eData[0].transient_info[0] = + fixMin(eData[1].transient_info[0], eData[0].transient_info[0]); + eData[1].transient_info[0] = eData[0].transient_info[0]; + } else { + if (eData[0].transient_info[1] && !eData[1].transient_info[1]) { + eData[1].transient_info[0] = eData[0].transient_info[0]; + } else { + if (!eData[0].transient_info[1] && eData[1].transient_info[1]) + eData[0].transient_info[0] = eData[1].transient_info[0]; + else { + eData[0].transient_info[0] = + fixMax(eData[1].transient_info[0], eData[0].transient_info[0]); + eData[1].transient_info[0] = eData[0].transient_info[0]; + } + } + } + } + + /* + Determine time/frequency division of current granule + */ + eData[0].frame_info = FDKsbrEnc_frameInfoGenerator( + &h_envChan[0]->SbrEnvFrame, eData[0].transient_info, + sbrBitstreamData->rightBorderFIX, + h_envChan[0]->sbrExtractEnvelope.pre_transient_info, + h_envChan[0]->encEnvData.ldGrid, v_tuning); + + h_envChan[0]->encEnvData.hSbrBSGrid = &h_envChan[0]->SbrEnvFrame.SbrGrid; + + /* AAC LD patch for transient prediction */ + if (h_envChan[0]->encEnvData.ldGrid && eData[0].transient_info[2]) { + /* if next frame will start with transient, set shortEnv to + * numEnvelopes(shortend Envelope = shortEnv-1)*/ + h_envChan[0]->SbrEnvFrame.SbrFrameInfo.shortEnv = + h_envChan[0]->SbrEnvFrame.SbrFrameInfo.nEnvelopes; + } + + switch (stereoMode) { + case SBR_LEFT_RIGHT: + case SBR_SWITCH_LRC: + eData[1].frame_info = FDKsbrEnc_frameInfoGenerator( + &h_envChan[1]->SbrEnvFrame, eData[1].transient_info, + sbrBitstreamData->rightBorderFIX, + h_envChan[1]->sbrExtractEnvelope.pre_transient_info, + h_envChan[1]->encEnvData.ldGrid, v_tuning); + + h_envChan[1]->encEnvData.hSbrBSGrid = &h_envChan[1]->SbrEnvFrame.SbrGrid; + + if (h_envChan[1]->encEnvData.ldGrid && eData[1].transient_info[2]) { + /* if next frame will start with transient, set shortEnv to + * numEnvelopes(shortend Envelope = shortEnv-1)*/ + h_envChan[1]->SbrEnvFrame.SbrFrameInfo.shortEnv = + h_envChan[1]->SbrEnvFrame.SbrFrameInfo.nEnvelopes; + } + + /* compare left and right frame_infos */ + if (eData[0].frame_info->nEnvelopes != eData[1].frame_info->nEnvelopes) { + stereoMode = SBR_LEFT_RIGHT; + } else { + for (i = 0; i < eData[0].frame_info->nEnvelopes + 1; i++) { + if (eData[0].frame_info->borders[i] != + eData[1].frame_info->borders[i]) { + stereoMode = SBR_LEFT_RIGHT; + break; + } + } + for (i = 0; i < eData[0].frame_info->nEnvelopes; i++) { + if (eData[0].frame_info->freqRes[i] != + eData[1].frame_info->freqRes[i]) { + stereoMode = SBR_LEFT_RIGHT; + break; + } + } + if (eData[0].frame_info->shortEnv != eData[1].frame_info->shortEnv) { + stereoMode = SBR_LEFT_RIGHT; + } + } + break; + case SBR_COUPLING: + eData[1].frame_info = eData[0].frame_info; + h_envChan[1]->encEnvData.hSbrBSGrid = &h_envChan[0]->SbrEnvFrame.SbrGrid; + break; + case SBR_MONO: + /* nothing to do */ + break; + default: + FDK_ASSERT(0); + } + + for (ch = 0; ch < nChannels; ch++) { + HANDLE_ENV_CHANNEL hEnvChan = h_envChan[ch]; + HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &hEnvChan->sbrExtractEnvelope; + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + + /* + Send transient info to bitstream and store for next call + */ + sbrExtrEnv->pre_transient_info[0] = ed->transient_info[0]; /* tran_pos */ + sbrExtrEnv->pre_transient_info[1] = ed->transient_info[1]; /* tran_flag */ + hEnvChan->encEnvData.noOfEnvelopes = ed->nEnvelopes = + ed->frame_info->nEnvelopes; /* number of envelopes of current frame */ + + /* + Check if the current frame is divided into one envelope only. If so, set + the amplitude resolution to 1.5 dB, otherwise may set back to chosen value + */ + if ((hEnvChan->encEnvData.hSbrBSGrid->frameClass == FIXFIX) && + (ed->nEnvelopes == 1)) { + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + /* Note: global_tonaliy_float_value == + ((float)hEnvChan->encEnvData.global_tonality/((INT64)(1)<<(31-(19+2)))/0.524288*(2.0/3.0))); + threshold_float_value == + ((float)h_con->thresholdAmpResFF_m/((INT64)(1)<<(31-(h_con->thresholdAmpResFF_e)))/0.524288*(2.0/3.0))); + */ + /* decision of SBR_AMP_RES */ + if (fIsLessThan(/* global_tonality > threshold ? */ + h_con->thresholdAmpResFF_m, h_con->thresholdAmpResFF_e, + hEnvChan->encEnvData.global_tonality, + RELAXATION_SHIFT + 2)) { + hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_1_5; + } else { + hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_3_0; + } + } else + hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_1_5; + + if (hEnvChan->encEnvData.currentAmpResFF != + hEnvChan->encEnvData.init_sbr_amp_res) { + FDKsbrEnc_InitSbrHuffmanTables( + &hEnvChan->encEnvData, &hEnvChan->sbrCodeEnvelope, + &hEnvChan->sbrCodeNoiseFloor, hEnvChan->encEnvData.currentAmpResFF); + } + } else { + if (sbrHeaderData->sbr_amp_res != hEnvChan->encEnvData.init_sbr_amp_res) { + FDKsbrEnc_InitSbrHuffmanTables( + &hEnvChan->encEnvData, &hEnvChan->sbrCodeEnvelope, + &hEnvChan->sbrCodeNoiseFloor, sbrHeaderData->sbr_amp_res); + } + } + + if (!clearOutput) { + /* + Tonality correction parameter extraction (inverse filtering level, noise + floor additional sines). + */ + FDKsbrEnc_TonCorrParamExtr( + &hEnvChan->TonCorr, hEnvChan->encEnvData.sbr_invf_mode_vec, + ed->noiseFloor, &hEnvChan->encEnvData.addHarmonicFlag, + hEnvChan->encEnvData.addHarmonic, sbrExtrEnv->envelopeCompensation, + ed->frame_info, ed->transient_info, h_con->freqBandTable[HI], + h_con->nSfb[HI], hEnvChan->encEnvData.sbr_xpos_mode, + h_con->sbrSyntaxFlags); + } + + /* Low energy in low band fix */ + if (hEnvChan->sbrTransientDetector.prevLowBandEnergy < + hEnvChan->sbrTransientDetector.prevHighBandEnergy && + hEnvChan->sbrTransientDetector.prevHighBandEnergy > FL2FX_DBL(0.03) + /* The fix needs the non-fast transient detector running. + It sets prevLowBandEnergy and prevHighBandEnergy. */ + && !(h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY)) { + hEnvChan->fLevelProtect = 1; + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + hEnvChan->encEnvData.sbr_invf_mode_vec[i] = INVF_HIGH_LEVEL; + } else { + hEnvChan->fLevelProtect = 0; + } + + hEnvChan->encEnvData.sbr_invf_mode = + hEnvChan->encEnvData.sbr_invf_mode_vec[0]; + + hEnvChan->encEnvData.noOfnoisebands = + hEnvChan->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + + } /* ch */ + + /* + Save number of scf bands per envelope + */ + for (ch = 0; ch < nChannels; ch++) { + for (i = 0; i < eData[ch].nEnvelopes; i++) { + h_envChan[ch]->encEnvData.noScfBands[i] = + (eData[ch].frame_info->freqRes[i] == FREQ_RES_HIGH + ? h_con->nSfb[FREQ_RES_HIGH] + : h_con->nSfb[FREQ_RES_LOW]); + } + } + + /* + Extract envelope of current frame. + */ + switch (stereoMode) { + case SBR_MONO: + calculateSbrEnvelope(h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, h_con, + h_envChan[0], SBR_MONO, NULL, YSzShift); + break; + case SBR_LEFT_RIGHT: + calculateSbrEnvelope(h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, h_con, + h_envChan[0], SBR_MONO, NULL, YSzShift); + calculateSbrEnvelope(h_envChan[1]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, NULL, + eData[1].frame_info, eData[1].sfb_nrg, NULL, h_con, + h_envChan[1], SBR_MONO, NULL, YSzShift); + break; + case SBR_COUPLING: + calculateSbrEnvelope(h_envChan[0]->sbrExtractEnvelope.YBuffer, + h_envChan[1]->sbrExtractEnvelope.YBuffer, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, + eData[0].frame_info, eData[0].sfb_nrg, + eData[1].sfb_nrg, h_con, h_envChan[0], SBR_COUPLING, + &fData->maxQuantError, YSzShift); + break; + case SBR_SWITCH_LRC: + calculateSbrEnvelope(h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, h_con, + h_envChan[0], SBR_MONO, NULL, YSzShift); + calculateSbrEnvelope(h_envChan[1]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, NULL, + eData[1].frame_info, eData[1].sfb_nrg, NULL, h_con, + h_envChan[1], SBR_MONO, NULL, YSzShift); + calculateSbrEnvelope(h_envChan[0]->sbrExtractEnvelope.YBuffer, + h_envChan[1]->sbrExtractEnvelope.YBuffer, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, + eData[0].frame_info, eData[0].sfb_nrg_coupling, + eData[1].sfb_nrg_coupling, h_con, h_envChan[0], + SBR_COUPLING, &fData->maxQuantError, YSzShift); + break; + } + + /* + Noise floor quantisation and coding. + */ + + switch (stereoMode) { + case SBR_MONO: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level, eData[0].noiseFloor, + 0); + + FDKsbrEnc_codeEnvelope(eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + break; + case SBR_LEFT_RIGHT: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level, eData[0].noiseFloor, + 0); + + FDKsbrEnc_codeEnvelope(eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level, eData[1].noiseFloor, + 0); + + FDKsbrEnc_codeEnvelope(eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 0, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + break; + + case SBR_COUPLING: + coupleNoiseFloor(eData[0].noiseFloor, eData[1].noiseFloor); + + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level, eData[0].noiseFloor, + 0); + + FDKsbrEnc_codeEnvelope(eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 1, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level, eData[1].noiseFloor, + 1); + + FDKsbrEnc_codeEnvelope(eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 1, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 1, + sbrBitstreamData->HeaderActive); + + break; + case SBR_SWITCH_LRC: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level, eData[0].noiseFloor, + 0); + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level, eData[1].noiseFloor, + 0); + coupleNoiseFloor(eData[0].noiseFloor, eData[1].noiseFloor); + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level_coupling, + eData[0].noiseFloor, 0); + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level_coupling, + eData[1].noiseFloor, 1); + break; + } + + /* + Encode envelope of current frame. + */ + switch (stereoMode) { + case SBR_MONO: + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + FDKsbrEnc_codeEnvelope( + eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + break; + case SBR_LEFT_RIGHT: + sbrHeaderData->coupling = 0; + + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + + FDKsbrEnc_codeEnvelope( + eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope( + eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, h_envChan[1]->encEnvData.domain_vec, + sbrHeaderData->coupling, eData[1].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + break; + case SBR_COUPLING: + sbrHeaderData->coupling = 1; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + + FDKsbrEnc_codeEnvelope( + eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope( + eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, h_envChan[1]->encEnvData.domain_vec, + sbrHeaderData->coupling, eData[1].frame_info->nEnvelopes, 1, + sbrBitstreamData->HeaderActive); + break; + case SBR_SWITCH_LRC: { + INT payloadbitsLR; + INT payloadbitsCOUPLING; + + SCHAR sfbNrgPrevTemp[MAX_NUM_CHANNELS][MAX_FREQ_COEFFS]; + SCHAR noisePrevTemp[MAX_NUM_CHANNELS][MAX_NUM_NOISE_COEFFS]; + INT upDateNrgTemp[MAX_NUM_CHANNELS]; + INT upDateNoiseTemp[MAX_NUM_CHANNELS]; + INT domainVecTemp[MAX_NUM_CHANNELS][MAX_ENVELOPES]; + INT domainVecNoiseTemp[MAX_NUM_CHANNELS][MAX_ENVELOPES]; + + INT tempFlagRight = 0; + INT tempFlagLeft = 0; + + /* + Store previous values, in order to be able to "undo" what is being + done. + */ + + for (ch = 0; ch < nChannels; ch++) { + FDKmemcpy(sfbNrgPrevTemp[ch], + h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev, + MAX_FREQ_COEFFS * sizeof(SCHAR)); + + FDKmemcpy(noisePrevTemp[ch], + h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev, + MAX_NUM_NOISE_COEFFS * sizeof(SCHAR)); + + upDateNrgTemp[ch] = h_envChan[ch]->sbrCodeEnvelope.upDate; + upDateNoiseTemp[ch] = h_envChan[ch]->sbrCodeNoiseFloor.upDate; + + /* + forbid time coding in the first envelope in case of a different + previous stereomode + */ + if (sbrHeaderData->prev_coupling) { + h_envChan[ch]->sbrCodeEnvelope.upDate = 0; + h_envChan[ch]->sbrCodeNoiseFloor.upDate = 0; + } + } /* ch */ + + /* + Code ordinary Left/Right stereo + */ + FDKsbrEnc_codeEnvelope(eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, 0, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope(eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, + h_envChan[1]->encEnvData.domain_vec, 0, + eData[1].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + + c = 0; + for (i = 0; i < eData[0].nEnvelopes; i++) { + for (j = 0; j < h_envChan[0]->encEnvData.noScfBands[i]; j++) { + h_envChan[0]->encEnvData.ienvelope[i][j] = eData[0].sfb_nrg[c]; + h_envChan[1]->encEnvData.ienvelope[i][j] = eData[1].sfb_nrg[c]; + c++; + } + } + + FDKsbrEnc_codeEnvelope(eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[0]->encEnvData.sbr_noise_levels[i] = eData[0].noise_level[i]; + + FDKsbrEnc_codeEnvelope(eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 0, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[1]->encEnvData.sbr_noise_levels[i] = eData[1].noise_level[i]; + + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + + payloadbitsLR = FDKsbrEnc_CountSbrChannelPairElement( + sbrHeaderData, hParametricStereo, sbrBitstreamData, + &h_envChan[0]->encEnvData, &h_envChan[1]->encEnvData, hCmonData, + h_con->sbrSyntaxFlags); + + /* + swap saved stored with current values + */ + for (ch = 0; ch < nChannels; ch++) { + INT itmp; + for (i = 0; i < MAX_FREQ_COEFFS; i++) { + /* + swap sfb energies + */ + itmp = h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev[i]; + h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev[i] = + sfbNrgPrevTemp[ch][i]; + sfbNrgPrevTemp[ch][i] = itmp; + } + for (i = 0; i < MAX_NUM_NOISE_COEFFS; i++) { + /* + swap noise energies + */ + itmp = h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev[i]; + h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev[i] = + noisePrevTemp[ch][i]; + noisePrevTemp[ch][i] = itmp; + } + /* swap update flags */ + itmp = h_envChan[ch]->sbrCodeEnvelope.upDate; + h_envChan[ch]->sbrCodeEnvelope.upDate = upDateNrgTemp[ch]; + upDateNrgTemp[ch] = itmp; + + itmp = h_envChan[ch]->sbrCodeNoiseFloor.upDate; + h_envChan[ch]->sbrCodeNoiseFloor.upDate = upDateNoiseTemp[ch]; + upDateNoiseTemp[ch] = itmp; + + /* + save domain vecs + */ + FDKmemcpy(domainVecTemp[ch], h_envChan[ch]->encEnvData.domain_vec, + sizeof(INT) * MAX_ENVELOPES); + FDKmemcpy(domainVecNoiseTemp[ch], + h_envChan[ch]->encEnvData.domain_vec_noise, + sizeof(INT) * MAX_ENVELOPES); + + /* + forbid time coding in the first envelope in case of a different + previous stereomode + */ + + if (!sbrHeaderData->prev_coupling) { + h_envChan[ch]->sbrCodeEnvelope.upDate = 0; + h_envChan[ch]->sbrCodeNoiseFloor.upDate = 0; + } + } /* ch */ + + /* + Coupling + */ + + FDKsbrEnc_codeEnvelope( + eData[0].sfb_nrg_coupling, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, h_envChan[0]->encEnvData.domain_vec, + 1, eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + + FDKsbrEnc_codeEnvelope( + eData[1].sfb_nrg_coupling, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, h_envChan[1]->encEnvData.domain_vec, + 1, eData[1].frame_info->nEnvelopes, 1, + sbrBitstreamData->HeaderActive); + + c = 0; + for (i = 0; i < eData[0].nEnvelopes; i++) { + for (j = 0; j < h_envChan[0]->encEnvData.noScfBands[i]; j++) { + h_envChan[0]->encEnvData.ienvelope[i][j] = + eData[0].sfb_nrg_coupling[c]; + h_envChan[1]->encEnvData.ienvelope[i][j] = + eData[1].sfb_nrg_coupling[c]; + c++; + } + } + + FDKsbrEnc_codeEnvelope(eData[0].noise_level_coupling, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 1, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[0]->encEnvData.sbr_noise_levels[i] = + eData[0].noise_level_coupling[i]; + + FDKsbrEnc_codeEnvelope(eData[1].noise_level_coupling, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 1, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 1, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[1]->encEnvData.sbr_noise_levels[i] = + eData[1].noise_level_coupling[i]; + + sbrHeaderData->coupling = 1; + + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + + tempFlagLeft = h_envChan[0]->encEnvData.addHarmonicFlag; + tempFlagRight = h_envChan[1]->encEnvData.addHarmonicFlag; + + payloadbitsCOUPLING = FDKsbrEnc_CountSbrChannelPairElement( + sbrHeaderData, hParametricStereo, sbrBitstreamData, + &h_envChan[0]->encEnvData, &h_envChan[1]->encEnvData, hCmonData, + h_con->sbrSyntaxFlags); + + h_envChan[0]->encEnvData.addHarmonicFlag = tempFlagLeft; + h_envChan[1]->encEnvData.addHarmonicFlag = tempFlagRight; + + if (payloadbitsCOUPLING < payloadbitsLR) { + /* + copy coded coupling envelope and noise data to l/r + */ + for (ch = 0; ch < nChannels; ch++) { + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + FDKmemcpy(ed->sfb_nrg, ed->sfb_nrg_coupling, + MAX_NUM_ENVELOPE_VALUES * sizeof(SCHAR)); + FDKmemcpy(ed->noise_level, ed->noise_level_coupling, + MAX_NUM_NOISE_VALUES * sizeof(SCHAR)); + } + + sbrHeaderData->coupling = 1; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + } else { + /* + restore saved l/r items + */ + for (ch = 0; ch < nChannels; ch++) { + FDKmemcpy(h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev, + sfbNrgPrevTemp[ch], MAX_FREQ_COEFFS * sizeof(SCHAR)); + + h_envChan[ch]->sbrCodeEnvelope.upDate = upDateNrgTemp[ch]; + + FDKmemcpy(h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev, + noisePrevTemp[ch], MAX_NUM_NOISE_COEFFS * sizeof(SCHAR)); + + FDKmemcpy(h_envChan[ch]->encEnvData.domain_vec, domainVecTemp[ch], + sizeof(INT) * MAX_ENVELOPES); + FDKmemcpy(h_envChan[ch]->encEnvData.domain_vec_noise, + domainVecNoiseTemp[ch], sizeof(INT) * MAX_ENVELOPES); + + h_envChan[ch]->sbrCodeNoiseFloor.upDate = upDateNoiseTemp[ch]; + } + + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + } + } break; + } /* switch */ + + /* tell the envelope encoders how long it has been, since we last sent + a frame starting with a dF-coded envelope */ + if (stereoMode == SBR_MONO) { + if (h_envChan[0]->encEnvData.domain_vec[0] == TIME) + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac++; + else + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + } else { + if (h_envChan[0]->encEnvData.domain_vec[0] == TIME || + h_envChan[1]->encEnvData.domain_vec[0] == TIME) { + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac++; + h_envChan[1]->sbrCodeEnvelope.dF_edge_incr_fac++; + } else { + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + h_envChan[1]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + } + } + + /* + Send the encoded data to the bitstream + */ + for (ch = 0; ch < nChannels; ch++) { + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + c = 0; + for (i = 0; i < ed->nEnvelopes; i++) { + for (j = 0; j < h_envChan[ch]->encEnvData.noScfBands[i]; j++) { + h_envChan[ch]->encEnvData.ienvelope[i][j] = ed->sfb_nrg[c]; + + c++; + } + } + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) { + h_envChan[ch]->encEnvData.sbr_noise_levels[i] = ed->noise_level[i]; + } + } /* ch */ + + /* + Write bitstream + */ + if (nChannels == 2) { + FDKsbrEnc_WriteEnvChannelPairElement( + sbrHeaderData, hParametricStereo, sbrBitstreamData, + &h_envChan[0]->encEnvData, &h_envChan[1]->encEnvData, hCmonData, + h_con->sbrSyntaxFlags); + } else { + FDKsbrEnc_WriteEnvSingleChannelElement( + sbrHeaderData, hParametricStereo, sbrBitstreamData, + &h_envChan[0]->encEnvData, hCmonData, h_con->sbrSyntaxFlags); + } + + /* + * Update buffers. + */ + for (ch = 0; ch < nChannels; ch++) { + int YBufferLength = h_envChan[ch]->sbrExtractEnvelope.no_cols >> + h_envChan[ch]->sbrExtractEnvelope.YBufferSzShift; + for (i = 0; i < h_envChan[ch]->sbrExtractEnvelope.YBufferWriteOffset; i++) { + FDKmemcpy(h_envChan[ch]->sbrExtractEnvelope.YBuffer[i], + h_envChan[ch]->sbrExtractEnvelope.YBuffer[i + YBufferLength], + sizeof(FIXP_DBL) * 64); + } + h_envChan[ch]->sbrExtractEnvelope.YBufferScale[0] = + h_envChan[ch]->sbrExtractEnvelope.YBufferScale[1]; + } + + sbrHeaderData->prev_coupling = sbrHeaderData->coupling; +} + +/***************************************************************************/ +/*! + + \brief creates an envelope extractor handle + + \return error status + +****************************************************************************/ +INT FDKsbrEnc_CreateExtractSbrEnvelope(HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, + INT channel, INT chInEl, + UCHAR *dynamic_RAM) { + INT i; + FIXP_DBL *rBuffer, *iBuffer; + INT n; + FIXP_DBL *YBufferDyn; + + FDKmemclear(hSbrCut, sizeof(SBR_EXTRACT_ENVELOPE)); + + if (NULL == (hSbrCut->p_YBuffer = GetRam_Sbr_envYBuffer(channel))) { + goto bail; + } + + for (i = 0; i < (32 >> 1); i++) { + hSbrCut->YBuffer[i] = hSbrCut->p_YBuffer + (i * 64); + } + YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM); + for (n = 0; i < 32; i++, n++) { + hSbrCut->YBuffer[i] = YBufferDyn + (n * 64); + } + + rBuffer = GetRam_Sbr_envRBuffer(0, dynamic_RAM); + iBuffer = GetRam_Sbr_envIBuffer(0, dynamic_RAM); + + for (i = 0; i < 32; i++) { + hSbrCut->rBuffer[i] = rBuffer + (i * 64); + hSbrCut->iBuffer[i] = iBuffer + (i * 64); + } + + return 0; + +bail: + FDKsbrEnc_deleteExtractSbrEnvelope(hSbrCut); + + return -1; +} + +/***************************************************************************/ +/*! + + \brief Initialize an envelope extractor instance. + + \return error status + +****************************************************************************/ +INT FDKsbrEnc_InitExtractSbrEnvelope(HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, + int no_cols, int no_rows, int start_index, + int time_slots, int time_step, + int tran_off, ULONG statesInitFlag, + int chInEl, UCHAR *dynamic_RAM, + UINT sbrSyntaxFlags) { + int YBufferLength, rBufferLength; + int i; + + if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + int off = TRANSIENT_OFFSET_LD; + hSbrCut->YBufferWriteOffset = (no_cols >> 1) + off * time_step; + } else { + hSbrCut->YBufferWriteOffset = tran_off * time_step; + } + hSbrCut->rBufferReadOffset = 0; + + YBufferLength = hSbrCut->YBufferWriteOffset + no_cols; + rBufferLength = no_cols; + + hSbrCut->pre_transient_info[0] = 0; + hSbrCut->pre_transient_info[1] = 0; + + hSbrCut->no_cols = no_cols; + hSbrCut->no_rows = no_rows; + hSbrCut->start_index = start_index; + + hSbrCut->time_slots = time_slots; + hSbrCut->time_step = time_step; + + FDK_ASSERT(no_rows <= 64); + + /* Use half the Energy values if time step is 2 or greater */ + if (time_step >= 2) + hSbrCut->YBufferSzShift = 1; + else + hSbrCut->YBufferSzShift = 0; + + YBufferLength >>= hSbrCut->YBufferSzShift; + hSbrCut->YBufferWriteOffset >>= hSbrCut->YBufferSzShift; + + FDK_ASSERT(YBufferLength <= 32); + + FIXP_DBL *YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM); + INT n = 0; + for (i = (32 >> 1); i < 32; i++, n++) { + hSbrCut->YBuffer[i] = YBufferDyn + (n * 64); + } + + if (statesInitFlag) { + for (i = 0; i < YBufferLength; i++) { + FDKmemclear(hSbrCut->YBuffer[i], 64 * sizeof(FIXP_DBL)); + } + } + + for (i = 0; i < rBufferLength; i++) { + FDKmemclear(hSbrCut->rBuffer[i], 64 * sizeof(FIXP_DBL)); + FDKmemclear(hSbrCut->iBuffer[i], 64 * sizeof(FIXP_DBL)); + } + + FDKmemclear(hSbrCut->envelopeCompensation, sizeof(UCHAR) * MAX_FREQ_COEFFS); + + if (statesInitFlag) { + hSbrCut->YBufferScale[0] = hSbrCut->YBufferScale[1] = FRACT_BITS - 1; + } + + return (0); +} + +/***************************************************************************/ +/*! + + \brief deinitializes an envelope extractor handle + + \return void + +****************************************************************************/ + +void FDKsbrEnc_deleteExtractSbrEnvelope(HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut) { + if (hSbrCut) { + FreeRam_Sbr_envYBuffer(&hSbrCut->p_YBuffer); + } +} + +INT FDKsbrEnc_GetEnvEstDelay(HANDLE_SBR_EXTRACT_ENVELOPE hSbr) { + return hSbr->no_rows * + ((hSbr->YBufferWriteOffset) * + 2 /* mult 2 because nrg's are grouped half */ + - hSbr->rBufferReadOffset); /* in reference hold half spec and calc + nrg's on overlapped spec */ +} |