summaryrefslogtreecommitdiffstats
path: root/libSBRenc/src/env_est.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2012-07-11 10:15:24 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2012-07-11 10:15:24 -0700
commit2228e360595641dd906bf1773307f43d304f5b2e (patch)
tree57f3d390ebb0782cc0de0fb984c8ea7e45b4f386 /libSBRenc/src/env_est.cpp
downloadfdk-aac-2228e360595641dd906bf1773307f43d304f5b2e.tar.gz
fdk-aac-2228e360595641dd906bf1773307f43d304f5b2e.tar.bz2
fdk-aac-2228e360595641dd906bf1773307f43d304f5b2e.zip
Snapshot 2bda038c163298531d47394bc2c09e1409c5d0db
Change-Id: If584e579464f28b97d50e51fc76ba654a5536c54
Diffstat (limited to 'libSBRenc/src/env_est.cpp')
-rw-r--r--libSBRenc/src/env_est.cpp1866
1 files changed, 1866 insertions, 0 deletions
diff --git a/libSBRenc/src/env_est.cpp b/libSBRenc/src/env_est.cpp
new file mode 100644
index 0000000..9423f27
--- /dev/null
+++ b/libSBRenc/src/env_est.cpp
@@ -0,0 +1,1866 @@
+
+/* -----------------------------------------------------------------------------------------------------------
+Software License for The Fraunhofer FDK AAC Codec Library for Android
+
+© Copyright 1995 - 2012 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
+----------------------------------------------------------------------------------------------------------- */
+
+#include "env_est.h"
+#include "tran_det.h"
+
+#include "qmf.h"
+
+#include "fram_gen.h"
+#include "bit_sbr.h"
+#include "cmondata.h"
+#include "sbr_ram.h"
+
+
+#include "genericStds.h"
+
+#define QUANT_ERROR_THRES 200
+#define Y_NRG_SCALE 5 /* noCols = 32 -> shift(5) */
+
+
+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};
+
+
+/***************************************************************************/
+/*!
+
+ \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, QMF_CHANNELS*QMF_MAX_TIME_SLOTS/2);
+
+ FDK_ASSERT(numberBands <= QMF_CHANNELS);
+ FDK_ASSERT(numberCols <= QMF_MAX_TIME_SLOTS);
+
+ /* 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+=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 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, QMF_CHANNELS*QMF_MAX_TIME_SLOTS/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, /*!< 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, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2);
+
+ FDK_ASSERT(numberBands <= QMF_CHANNELS);
+ FDK_ASSERT(numberCols <= QMF_MAX_TIME_SLOTS/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 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 2 consecutive timeslots */
+ 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 2 timeslots */
+ tr0 = r0[j]; ti0 = i0[j];
+
+ /* Scale QMF Values and Calc Energy of both timeslots */
+ 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, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2);
+}
+
+/***************************************************************************/
+/*!
+
+ \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 */
+ 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>>6 = 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-6); */ /* 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, FIXP_DBL nrgSum, 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));
+
+ /* 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 i, 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 (i = 0; i < nEnvelopes; i++) {
+
+ FIXP_DBL pNrgLeft[QMF_MAX_TIME_SLOTS];
+ FIXP_DBL pNrgRight[QMF_MAX_TIME_SLOTS];
+ FIXP_DBL envNrgLeft = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL envNrgRight = FL2FXCONST_DBL(0.0f);
+ int missingHarmonic[QMF_MAX_TIME_SLOTS];
+ int count[QMF_MAX_TIME_SLOTS];
+
+ start_pos = timeStep * frame_info->borders[i];
+ stop_pos = timeStep * frame_info->borders[i + 1];
+ freq_res = frame_info->freqRes[i];
+ no_of_bands = h_con->nSfb[freq_res];
+
+ if (i == short_env) {
+ stop_pos -= fixMax(2, timeStep); /* consider at least 2 QMF slots less for short envelopes (envelopes just before transients) */
+ }
+
+ 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;
+ envNrgRight += nrgRight;
+
+ } /* 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, no_of_bands);
+ if (stereoMode == SBR_COUPLING) {
+ nrgRight = nmhLoweringEnergy(nrgRight, envNrgRight, no_of_bands);
+ }
+ }
+
+ if (stereoMode == SBR_COUPLING) {
+ /* calc operation later with log */
+ nrgLeft2 = nrgLeft;
+ nrgLeft = (nrgRight + nrgLeft) >> 1;
+ }
+
+ /* nrgLeft = f20_log2(nrgLeft / (PFLOAT)(count * h_sbr->sbrQmf.no_channels))+(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]*h_con->noQmfBands)) << (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));
+ 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;
+
+ if (nrgRight != FL2FXCONST_DBL(0.0f)) {
+ int sc0 = CountLeadingBits(nrgLeft2);
+ int 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;
+ }
+ else
+ nrgRight = FL2FXCONST_DBL(0.5f); /* ld64(4294967296.0f) */
+
+ /* 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 */
+
+ } /* i*/
+}
+
+/***************************************************************************/
+/*!
+
+ \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]);
+
+
+
+ /*
+ 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);
+
+
+
+ /*
+ Transient detection COEFF Transform OK
+ */
+ 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);
+
+
+}
+
+/***************************************************************************/
+/*!
+
+ \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;
+ 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,
+ 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,
+ 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 (hEnvChan->encEnvData.ldGrid)
+ hEnvChan->encEnvData.currentAmpResFF = (AMP_RES)h_con->initAmpResFF;
+ 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))
+ {
+ int i;
+
+ 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)*QMF_CHANNELS);
+ }
+ 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* YBuffer = GetRam_Sbr_envYBuffer(channel);
+
+ FDKmemclear(hSbrCut,sizeof(SBR_EXTRACT_ENVELOPE));
+ hSbrCut->p_YBuffer = YBuffer;
+
+
+ for (i = 0; i < (QMF_MAX_TIME_SLOTS>>1); i++) {
+ hSbrCut->YBuffer[i] = YBuffer + (i*QMF_CHANNELS);
+ }
+ FIXP_DBL *YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM);
+ INT n=0;
+ for (; i < QMF_MAX_TIME_SLOTS; i++,n++) {
+ hSbrCut->YBuffer[i] = YBufferDyn + (n*QMF_CHANNELS);
+ }
+
+ FIXP_DBL* rBuffer = GetRam_Sbr_envRBuffer(0, dynamic_RAM);
+ FIXP_DBL* iBuffer = GetRam_Sbr_envIBuffer(0, dynamic_RAM);
+
+ for (i = 0; i < QMF_MAX_TIME_SLOTS; i++) {
+ hSbrCut->rBuffer[i] = rBuffer + (i*QMF_CHANNELS);
+ hSbrCut->iBuffer[i] = iBuffer + (i*QMF_CHANNELS);
+ }
+
+ return 0;
+}
+
+
+/***************************************************************************/
+/*!
+
+ \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;
+#ifndef FULL_DELAY
+ hSbrCut->YBufferWriteOffset = (no_cols>>1)+off*time_step;
+#else
+ hSbrCut->YBufferWriteOffset = no_cols+off*time_step;
+#endif
+ } 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 <= QMF_CHANNELS);
+
+ /* 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<=QMF_MAX_TIME_SLOTS);
+
+ FIXP_DBL *YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM);
+ INT n=0;
+ for (i=(QMF_MAX_TIME_SLOTS>>1); i < QMF_MAX_TIME_SLOTS; i++,n++) {
+ hSbrCut->YBuffer[i] = YBufferDyn + (n*QMF_CHANNELS);
+ }
+
+ if(statesInitFlag) {
+ for (i=0; i<YBufferLength; i++) {
+ FDKmemclear( hSbrCut->YBuffer[i],QMF_CHANNELS*sizeof(FIXP_DBL));
+ }
+ }
+
+ for (i = 0; i < rBufferLength; i++) {
+ FDKmemclear( hSbrCut->rBuffer[i],QMF_CHANNELS*sizeof(FIXP_DBL));
+ FDKmemclear( hSbrCut->iBuffer[i],QMF_CHANNELS*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 */
+
+}
+
+
+
+