| /* ----------------------------------------------------------------------------- |
| 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; |
| 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 */ |
| } |