aboutsummaryrefslogtreecommitdiffstats
path: root/fdk-aac/libSBRenc/src/tran_det.cpp
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2020-03-31 10:03:58 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2020-03-31 10:03:58 +0200
commita1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d (patch)
tree2b4790eec8f47fb086e645717f07c53b30ace919 /fdk-aac/libSBRenc/src/tran_det.cpp
parent2f84a54ec1d10b10293c7b1f4ab9fee31f3c6327 (diff)
parentc6a73c219dbfdfe639372d9922f4eb512f06fa2f (diff)
downloadODR-AudioEnc-a1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d.tar.gz
ODR-AudioEnc-a1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d.tar.bz2
ODR-AudioEnc-a1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d.zip
Merge GStreamer into next
Diffstat (limited to 'fdk-aac/libSBRenc/src/tran_det.cpp')
-rw-r--r--fdk-aac/libSBRenc/src/tran_det.cpp1092
1 files changed, 1092 insertions, 0 deletions
diff --git a/fdk-aac/libSBRenc/src/tran_det.cpp b/fdk-aac/libSBRenc/src/tran_det.cpp
new file mode 100644
index 0000000..3b6765a
--- /dev/null
+++ b/fdk-aac/libSBRenc/src/tran_det.cpp
@@ -0,0 +1,1092 @@
+/* -----------------------------------------------------------------------------
+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): Tobias Chalupka
+
+ Description: SBR encoder transient detector
+
+*******************************************************************************/
+
+#include "tran_det.h"
+
+#include "fram_gen.h"
+#include "sbrenc_ram.h"
+#include "sbr_misc.h"
+
+#include "genericStds.h"
+
+#define NORM_QMF_ENERGY 9.31322574615479E-10 /* 2^-30 */
+
+/* static FIXP_DBL ABS_THRES = fixMax( FL2FXCONST_DBL(1.28e5 *
+ * NORM_QMF_ENERGY), (FIXP_DBL)1) Minimum threshold for detecting changes */
+#define ABS_THRES ((FIXP_DBL)16)
+
+/*******************************************************************************
+ Functionname: spectralChange
+ *******************************************************************************
+ \brief Calculates a measure for the spectral change within the frame
+
+ The function says how good it would be to split the frame at the given border
+ position into 2 envelopes.
+
+ The return value delta_sum is scaled with the factor 1/64
+
+ \return calculated value
+*******************************************************************************/
+#define NRG_SHIFT 3 /* for energy summation */
+
+static FIXP_DBL spectralChange(
+ FIXP_DBL Energies[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS],
+ INT *scaleEnergies, FIXP_DBL EnergyTotal, INT nSfb, INT start, INT border,
+ INT YBufferWriteOffset, INT stop, INT *result_e) {
+ INT i, j;
+ INT len1, len2;
+ SCHAR energies_e_diff[NUMBER_TIME_SLOTS_2304], energies_e, energyTotal_e = 19,
+ energies_e_add;
+ SCHAR prevEnergies_e_diff, newEnergies_e_diff;
+ FIXP_DBL tmp0, tmp1;
+ FIXP_DBL delta, delta_sum;
+ INT accu_e, tmp_e;
+
+ delta_sum = FL2FXCONST_DBL(0.0f);
+ *result_e = 0;
+
+ len1 = border - start;
+ len2 = stop - border;
+
+ /* prefer borders near the middle of the frame */
+ FIXP_DBL pos_weight;
+ pos_weight = FL2FXCONST_DBL(0.5f) - (len1 * GetInvInt(len1 + len2));
+ pos_weight = /*FL2FXCONST_DBL(1.0)*/ (FIXP_DBL)MAXVAL_DBL -
+ (fMult(pos_weight, pos_weight) << 2);
+
+ /*** Calc scaling for energies ***/
+ FDK_ASSERT(scaleEnergies[0] >= 0);
+ FDK_ASSERT(scaleEnergies[1] >= 0);
+
+ energies_e = 19 - fMin(scaleEnergies[0], scaleEnergies[1]);
+
+ /* limit shift for energy accumulation, energies_e can be -10 min. */
+ if (energies_e < -10) {
+ energies_e_add = -10 - energies_e;
+ energies_e = -10;
+ } else if (energies_e > 17) {
+ energies_e_add = energies_e - 17;
+ energies_e = 17;
+ } else {
+ energies_e_add = 0;
+ }
+
+ /* compensate scaling differences between scaleEnergies[0] and
+ * scaleEnergies[1] */
+ prevEnergies_e_diff = scaleEnergies[0] -
+ fMin(scaleEnergies[0], scaleEnergies[1]) +
+ energies_e_add + NRG_SHIFT;
+ newEnergies_e_diff = scaleEnergies[1] -
+ fMin(scaleEnergies[0], scaleEnergies[1]) +
+ energies_e_add + NRG_SHIFT;
+
+ prevEnergies_e_diff = fMin(prevEnergies_e_diff, DFRACT_BITS - 1);
+ newEnergies_e_diff = fMin(newEnergies_e_diff, DFRACT_BITS - 1);
+
+ for (i = start; i < YBufferWriteOffset; i++) {
+ energies_e_diff[i] = prevEnergies_e_diff;
+ }
+ for (i = YBufferWriteOffset; i < stop; i++) {
+ energies_e_diff[i] = newEnergies_e_diff;
+ }
+
+ /* Sum up energies of all QMF-timeslots for both halfs */
+ FDK_ASSERT(len1 <= 8); /* otherwise an overflow is possible */
+ FDK_ASSERT(len2 <= 8); /* otherwise an overflow is possible */
+
+ for (j = 0; j < nSfb; j++) {
+ FIXP_DBL accu1 = FL2FXCONST_DBL(0.f);
+ FIXP_DBL accu2 = FL2FXCONST_DBL(0.f);
+ accu_e = energies_e + 3;
+
+ /* Sum up energies in first half */
+ for (i = start; i < border; i++) {
+ accu1 += scaleValue(Energies[i][j], -energies_e_diff[i]);
+ }
+
+ /* Sum up energies in second half */
+ for (i = border; i < stop; i++) {
+ accu2 += scaleValue(Energies[i][j], -energies_e_diff[i]);
+ }
+
+ /* Ensure certain energy to prevent division by zero and to prevent
+ * splitting for very low levels */
+ accu1 = fMax(accu1, (FIXP_DBL)len1);
+ accu2 = fMax(accu2, (FIXP_DBL)len2);
+
+/* Energy change in current band */
+#define LN2 FL2FXCONST_DBL(0.6931471806f) /* ln(2) */
+ tmp0 = fLog2(accu2, accu_e) - fLog2(accu1, accu_e);
+ tmp1 = fLog2((FIXP_DBL)len1, 31) - fLog2((FIXP_DBL)len2, 31);
+ delta = fMult(LN2, (tmp0 + tmp1));
+ delta = (FIXP_DBL)fAbs(delta);
+
+ /* Weighting with amplitude ratio of this band */
+ accu_e++; /* scale at least one bit due to (accu1+accu2) */
+ accu1 >>= 1;
+ accu2 >>= 1;
+
+ if (accu_e & 1) {
+ accu_e++; /* for a defined square result exponent, the exponent has to be
+ even */
+ accu1 >>= 1;
+ accu2 >>= 1;
+ }
+
+ delta_sum += fMult(sqrtFixp(accu1 + accu2), delta);
+ *result_e = ((accu_e >> 1) + LD_DATA_SHIFT);
+ }
+
+ if (energyTotal_e & 1) {
+ energyTotal_e += 1; /* for a defined square result exponent, the exponent
+ has to be even */
+ EnergyTotal >>= 1;
+ }
+
+ delta_sum = fMult(delta_sum, invSqrtNorm2(EnergyTotal, &tmp_e));
+ *result_e = *result_e + (tmp_e - (energyTotal_e >> 1));
+
+ return fMult(delta_sum, pos_weight);
+}
+
+/*******************************************************************************
+ Functionname: addLowbandEnergies
+ *******************************************************************************
+ \brief Calculates total lowband energy
+
+ The input values Energies[0] (low-band) are scaled by the factor
+ 2^(14-*scaleEnergies[0])
+ The input values Energies[1] (high-band) are scaled by the factor
+ 2^(14-*scaleEnergies[1])
+
+ \return total energy in the lowband, scaled by the factor 2^19
+*******************************************************************************/
+static FIXP_DBL addLowbandEnergies(FIXP_DBL **Energies, int *scaleEnergies,
+ int YBufferWriteOffset, int nrgSzShift,
+ int tran_off, UCHAR *freqBandTable,
+ int slots) {
+ INT nrgTotal_e;
+ FIXP_DBL nrgTotal_m;
+ FIXP_DBL accu1 = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL accu2 = FL2FXCONST_DBL(0.0f);
+ int tran_offdiv2 = tran_off >> nrgSzShift;
+ const int sc1 =
+ DFRACT_BITS -
+ fNormz((FIXP_DBL)fMax(
+ 1, (freqBandTable[0] * (YBufferWriteOffset - tran_offdiv2) - 1)));
+ const int sc2 =
+ DFRACT_BITS -
+ fNormz((FIXP_DBL)fMax(
+ 1, (freqBandTable[0] *
+ (tran_offdiv2 + (slots >> nrgSzShift) - YBufferWriteOffset) -
+ 1)));
+ int ts, k;
+
+ /* Sum up lowband energy from one frame at offset tran_off */
+ /* freqBandTable[LORES] has MAX_FREQ_COEFFS/2 +1 coeefs max. */
+ for (ts = tran_offdiv2; ts < YBufferWriteOffset; ts++) {
+ for (k = 0; k < freqBandTable[0]; k++) {
+ accu1 += Energies[ts][k] >> sc1;
+ }
+ }
+ for (; ts < tran_offdiv2 + (slots >> nrgSzShift); ts++) {
+ for (k = 0; k < freqBandTable[0]; k++) {
+ accu2 += Energies[ts][k] >> sc2;
+ }
+ }
+
+ nrgTotal_m = fAddNorm(accu1, (sc1 - 5) - scaleEnergies[0], accu2,
+ (sc2 - 5) - scaleEnergies[1], &nrgTotal_e);
+ nrgTotal_m = scaleValueSaturate(nrgTotal_m, nrgTotal_e);
+
+ return (nrgTotal_m);
+}
+
+/*******************************************************************************
+ Functionname: addHighbandEnergies
+ *******************************************************************************
+ \brief Add highband energies
+
+ Highband energies are mapped to an array with smaller dimension:
+ Its time resolution is only 1 SBR-timeslot and its frequency resolution
+ is 1 SBR-band. Therefore the data to be fed into the spectralChange
+ function is reduced.
+
+ The values EnergiesM are scaled by the factor (2^19-scaleEnergies[0]) for
+ slots<YBufferWriteOffset and by the factor (2^19-scaleEnergies[1]) for
+ slots>=YBufferWriteOffset.
+
+ \return total energy in the highband, scaled by factor 2^19
+*******************************************************************************/
+
+static FIXP_DBL addHighbandEnergies(
+ FIXP_DBL **RESTRICT Energies, /*!< input */
+ INT *scaleEnergies, INT YBufferWriteOffset,
+ FIXP_DBL EnergiesM[NUMBER_TIME_SLOTS_2304]
+ [MAX_FREQ_COEFFS], /*!< Combined output */
+ UCHAR *RESTRICT freqBandTable, INT nSfb, INT sbrSlots, INT timeStep) {
+ INT i, j, k, slotIn, slotOut, scale[2];
+ INT li, ui;
+ FIXP_DBL nrgTotal;
+ FIXP_DBL accu = FL2FXCONST_DBL(0.0f);
+
+ /* Combine QMF-timeslots to SBR-timeslots,
+ combine QMF-bands to SBR-bands,
+ combine Left and Right channel */
+ for (slotOut = 0; slotOut < sbrSlots; slotOut++) {
+ /* Note: Below slotIn = slotOut and not slotIn = timeStep*slotOut
+ because the Energies[] time resolution is always the SBR slot resolution
+ regardless of the timeStep. */
+ slotIn = slotOut;
+
+ for (j = 0; j < nSfb; j++) {
+ accu = FL2FXCONST_DBL(0.0f);
+
+ li = freqBandTable[j];
+ ui = freqBandTable[j + 1];
+
+ for (k = li; k < ui; k++) {
+ for (i = 0; i < timeStep; i++) {
+ accu += Energies[slotIn][k] >> 5;
+ }
+ }
+ EnergiesM[slotOut][j] = accu;
+ }
+ }
+
+ /* scale energies down before add up */
+ scale[0] = fixMin(8, scaleEnergies[0]);
+ scale[1] = fixMin(8, scaleEnergies[1]);
+
+ if ((scaleEnergies[0] - scale[0]) > (DFRACT_BITS - 1) ||
+ (scaleEnergies[1] - scale[1]) > (DFRACT_BITS - 1))
+ nrgTotal = FL2FXCONST_DBL(0.0f);
+ else {
+ /* Now add all energies */
+ accu = FL2FXCONST_DBL(0.0f);
+
+ for (slotOut = 0; slotOut < YBufferWriteOffset; slotOut++) {
+ for (j = 0; j < nSfb; j++) {
+ accu += (EnergiesM[slotOut][j] >> scale[0]);
+ }
+ }
+ nrgTotal = accu >> (scaleEnergies[0] - scale[0]);
+
+ for (slotOut = YBufferWriteOffset; slotOut < sbrSlots; slotOut++) {
+ for (j = 0; j < nSfb; j++) {
+ accu += (EnergiesM[slotOut][j] >> scale[0]);
+ }
+ }
+ nrgTotal = fAddSaturate(nrgTotal, accu >> (scaleEnergies[1] - scale[1]));
+ }
+
+ return (nrgTotal);
+}
+
+/*******************************************************************************
+ Functionname: FDKsbrEnc_frameSplitter
+ *******************************************************************************
+ \brief Decides if a FIXFIX-frame shall be splitted into 2 envelopes
+
+ If no transient has been detected before, the frame can still be splitted
+ into 2 envelopes.
+*******************************************************************************/
+void FDKsbrEnc_frameSplitter(
+ FIXP_DBL **Energies, INT *scaleEnergies,
+ HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, UCHAR *freqBandTable,
+ UCHAR *tran_vector, int YBufferWriteOffset, int YBufferSzShift, int nSfb,
+ int timeStep, int no_cols, FIXP_DBL *tonality) {
+ if (tran_vector[1] == 0) /* no transient was detected */
+ {
+ FIXP_DBL delta;
+ INT delta_e;
+ FIXP_DBL(*EnergiesM)[MAX_FREQ_COEFFS];
+ FIXP_DBL EnergyTotal, newLowbandEnergy, newHighbandEnergy;
+ INT border;
+ INT sbrSlots = fMultI(GetInvInt(timeStep), no_cols);
+ C_ALLOC_SCRATCH_START(_EnergiesM, FIXP_DBL,
+ NUMBER_TIME_SLOTS_2304 * MAX_FREQ_COEFFS)
+
+ FDK_ASSERT(sbrSlots * timeStep == no_cols);
+
+ EnergiesM = (FIXP_DBL(*)[MAX_FREQ_COEFFS])_EnergiesM;
+
+ /*
+ Get Lowband-energy over a range of 2 frames (Look half a frame back and
+ ahead).
+ */
+ newLowbandEnergy = addLowbandEnergies(
+ Energies, scaleEnergies, YBufferWriteOffset, YBufferSzShift,
+ h_sbrTransientDetector->tran_off, freqBandTable, no_cols);
+
+ newHighbandEnergy =
+ addHighbandEnergies(Energies, scaleEnergies, YBufferWriteOffset,
+ EnergiesM, freqBandTable, nSfb, sbrSlots, timeStep);
+
+ {
+ /* prevLowBandEnergy: Corresponds to 1 frame, starting with half a frame
+ look-behind newLowbandEnergy: Corresponds to 1 frame, starting in the
+ middle of the current frame */
+ EnergyTotal = (newLowbandEnergy >> 1) +
+ (h_sbrTransientDetector->prevLowBandEnergy >>
+ 1); /* mean of new and prev LB NRG */
+ EnergyTotal =
+ fAddSaturate(EnergyTotal, newHighbandEnergy); /* Add HB NRG */
+ /* The below border should specify the same position as the middle border
+ of a FIXFIX-frame with 2 envelopes. */
+ border = (sbrSlots + 1) >> 1;
+
+ if ((INT)EnergyTotal & 0xffffffe0 &&
+ (scaleEnergies[0] < 32 || scaleEnergies[1] < 32)) /* i.e. > 31 */ {
+ delta = spectralChange(EnergiesM, scaleEnergies, EnergyTotal, nSfb, 0,
+ border, YBufferWriteOffset, sbrSlots, &delta_e);
+ } else {
+ delta = FL2FXCONST_DBL(0.0f);
+ delta_e = 0;
+
+ /* set tonality to 0 when energy is very low, since the amplitude
+ resolution should then be low as well */
+ *tonality = FL2FXCONST_DBL(0.0f);
+ }
+
+ if (fIsLessThan(h_sbrTransientDetector->split_thr_m,
+ h_sbrTransientDetector->split_thr_e, delta, delta_e)) {
+ tran_vector[0] = 1; /* Set flag for splitting */
+ } else {
+ tran_vector[0] = 0;
+ }
+ }
+
+ /* Update prevLowBandEnergy */
+ h_sbrTransientDetector->prevLowBandEnergy = newLowbandEnergy;
+ h_sbrTransientDetector->prevHighBandEnergy = newHighbandEnergy;
+ C_ALLOC_SCRATCH_END(_EnergiesM, FIXP_DBL,
+ NUMBER_TIME_SLOTS_2304 * MAX_FREQ_COEFFS)
+ }
+}
+
+/*
+ * Calculate transient energy threshold for each QMF band
+ */
+static void calculateThresholds(FIXP_DBL **RESTRICT Energies,
+ INT *RESTRICT scaleEnergies,
+ FIXP_DBL *RESTRICT thresholds,
+ int YBufferWriteOffset, int YBufferSzShift,
+ int noCols, int noRows, int tran_off) {
+ FIXP_DBL mean_val, std_val, temp;
+ FIXP_DBL i_noCols;
+ FIXP_DBL i_noCols1;
+ FIXP_DBL accu, accu0, accu1;
+ int scaleFactor0, scaleFactor1, commonScale;
+ int i, j;
+
+ i_noCols = GetInvInt(noCols + tran_off) << YBufferSzShift;
+ i_noCols1 = GetInvInt(noCols + tran_off - 1) << YBufferSzShift;
+
+ /* calc minimum scale of energies of previous and current frame */
+ commonScale = fixMin(scaleEnergies[0], scaleEnergies[1]);
+
+ /* calc scalefactors to adapt energies to common scale */
+ scaleFactor0 = fixMin((scaleEnergies[0] - commonScale), (DFRACT_BITS - 1));
+ scaleFactor1 = fixMin((scaleEnergies[1] - commonScale), (DFRACT_BITS - 1));
+
+ FDK_ASSERT((scaleFactor0 >= 0) && (scaleFactor1 >= 0));
+
+ /* calculate standard deviation in every subband */
+ for (i = 0; i < noRows; i++) {
+ int startEnergy = (tran_off >> YBufferSzShift);
+ int endEnergy = ((noCols >> YBufferSzShift) + tran_off);
+ int shift;
+
+ /* calculate mean value over decimated energy values (downsampled by 2). */
+ accu0 = accu1 = FL2FXCONST_DBL(0.0f);
+
+ for (j = startEnergy; j < YBufferWriteOffset; j++)
+ accu0 = fMultAddDiv2(accu0, Energies[j][i], i_noCols);
+ for (; j < endEnergy; j++)
+ accu1 = fMultAddDiv2(accu1, Energies[j][i], i_noCols);
+
+ mean_val = ((accu0 << 1) >> scaleFactor0) +
+ ((accu1 << 1) >> scaleFactor1); /* average */
+ shift = fixMax(
+ 0, CountLeadingBits(mean_val) -
+ 6); /* -6 to keep room for accumulating upto N = 24 values */
+
+ /* calculate standard deviation */
+ accu = FL2FXCONST_DBL(0.0f);
+
+ /* summe { ((mean_val-nrg)^2) * i_noCols1 } */
+ for (j = startEnergy; j < YBufferWriteOffset; j++) {
+ temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor0))
+ << shift;
+ temp = fPow2Div2(temp);
+ accu = fMultAddDiv2(accu, temp, i_noCols1);
+ }
+ for (; j < endEnergy; j++) {
+ temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor1))
+ << shift;
+ temp = fPow2Div2(temp);
+ accu = fMultAddDiv2(accu, temp, i_noCols1);
+ }
+ accu <<= 2;
+ std_val = sqrtFixp(accu) >> shift; /* standard deviation */
+
+ /*
+ Take new threshold as average of calculated standard deviation ratio
+ and old threshold if greater than absolute threshold
+ */
+ temp = (commonScale <= (DFRACT_BITS - 1))
+ ? fMult(FL2FXCONST_DBL(0.66f), thresholds[i]) +
+ (fMult(FL2FXCONST_DBL(0.34f), std_val) >> commonScale)
+ : (FIXP_DBL)0;
+
+ thresholds[i] = fixMax(ABS_THRES, temp);
+
+ FDK_ASSERT(commonScale >= 0);
+ }
+}
+
+/*
+ * Calculate transient levels for each QMF time slot.
+ */
+static void extractTransientCandidates(
+ FIXP_DBL **RESTRICT Energies, INT *RESTRICT scaleEnergies,
+ FIXP_DBL *RESTRICT thresholds, FIXP_DBL *RESTRICT transients,
+ int YBufferWriteOffset, int YBufferSzShift, int noCols, int start_band,
+ int stop_band, int tran_off, int addPrevSamples) {
+ FIXP_DBL i_thres;
+ C_ALLOC_SCRATCH_START(EnergiesTemp, FIXP_DBL, 2 * 32)
+ int tmpScaleEnergies0, tmpScaleEnergies1;
+ int endCond;
+ int startEnerg, endEnerg;
+ int i, j, jIndex, jpBM;
+
+ tmpScaleEnergies0 = scaleEnergies[0];
+ tmpScaleEnergies1 = scaleEnergies[1];
+
+ /* Scale value for first energies, upto YBufferWriteOffset */
+ tmpScaleEnergies0 = fixMin(tmpScaleEnergies0, MAX_SHIFT_DBL);
+ /* Scale value for first energies, from YBufferWriteOffset upwards */
+ tmpScaleEnergies1 = fixMin(tmpScaleEnergies1, MAX_SHIFT_DBL);
+
+ FDK_ASSERT((tmpScaleEnergies0 >= 0) && (tmpScaleEnergies1 >= 0));
+
+ /* Keep addPrevSamples extra previous transient candidates. */
+ FDKmemmove(transients, transients + noCols - addPrevSamples,
+ (tran_off + addPrevSamples) * sizeof(FIXP_DBL));
+ FDKmemclear(transients + tran_off + addPrevSamples,
+ noCols * sizeof(FIXP_DBL));
+
+ endCond = noCols; /* Amount of new transient values to be calculated. */
+ startEnerg = (tran_off - 3) >> YBufferSzShift; /* >>YBufferSzShift because of
+ amount of energy values. -3
+ because of neighbors being
+ watched. */
+ endEnerg =
+ ((noCols + (YBufferWriteOffset << YBufferSzShift)) - 1) >>
+ YBufferSzShift; /* YBufferSzShift shifts because of half energy values. */
+
+ /* Compute differential values with two different weightings in every subband
+ */
+ for (i = start_band; i < stop_band; i++) {
+ FIXP_DBL thres = thresholds[i];
+
+ if ((LONG)thresholds[i] >= 256)
+ i_thres = (LONG)((LONG)MAXVAL_DBL / ((((LONG)thresholds[i])) + 1))
+ << (32 - 24);
+ else
+ i_thres = (LONG)MAXVAL_DBL;
+
+ /* Copy one timeslot and de-scale and de-squish */
+ if (YBufferSzShift == 1) {
+ for (j = startEnerg; j < YBufferWriteOffset; j++) {
+ FIXP_DBL tmp = Energies[j][i];
+ EnergiesTemp[(j << 1) + 1] = EnergiesTemp[j << 1] =
+ tmp >> tmpScaleEnergies0;
+ }
+ for (; j <= endEnerg; j++) {
+ FIXP_DBL tmp = Energies[j][i];
+ EnergiesTemp[(j << 1) + 1] = EnergiesTemp[j << 1] =
+ tmp >> tmpScaleEnergies1;
+ }
+ } else {
+ for (j = startEnerg; j < YBufferWriteOffset; j++) {
+ FIXP_DBL tmp = Energies[j][i];
+ EnergiesTemp[j] = tmp >> tmpScaleEnergies0;
+ }
+ for (; j <= endEnerg; j++) {
+ FIXP_DBL tmp = Energies[j][i];
+ EnergiesTemp[j] = tmp >> tmpScaleEnergies1;
+ }
+ }
+
+ /* Detect peaks in energy values. */
+
+ jIndex = tran_off;
+ jpBM = jIndex + addPrevSamples;
+
+ for (j = endCond; j--; jIndex++, jpBM++) {
+ FIXP_DBL delta, tran;
+ int d;
+
+ delta = (FIXP_DBL)0;
+ tran = (FIXP_DBL)0;
+
+ for (d = 1; d < 4; d++) {
+ delta += EnergiesTemp[jIndex + d]; /* R */
+ delta -= EnergiesTemp[jIndex - d]; /* L */
+ delta -= thres;
+
+ if (delta > (FIXP_DBL)0) {
+ tran = fMultAddDiv2(tran, i_thres, delta);
+ }
+ }
+ transients[jpBM] += (tran << 1);
+ }
+ }
+ C_ALLOC_SCRATCH_END(EnergiesTemp, FIXP_DBL, 2 * 32)
+}
+
+void FDKsbrEnc_transientDetect(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTran,
+ FIXP_DBL **Energies, INT *scaleEnergies,
+ UCHAR *transient_info, int YBufferWriteOffset,
+ int YBufferSzShift, int timeStep,
+ int frameMiddleBorder) {
+ int no_cols = h_sbrTran->no_cols;
+ int qmfStartSample;
+ int addPrevSamples;
+ int timeStepShift = 0;
+ int i, cond;
+
+ /* Where to start looking for transients in the transient candidate buffer */
+ qmfStartSample = timeStep * frameMiddleBorder;
+ /* We need to look one value backwards in the transients, so we might need one
+ * more previous value. */
+ addPrevSamples = (qmfStartSample > 0) ? 0 : 1;
+
+ switch (timeStep) {
+ case 1:
+ timeStepShift = 0;
+ break;
+ case 2:
+ timeStepShift = 1;
+ break;
+ case 4:
+ timeStepShift = 2;
+ break;
+ }
+
+ calculateThresholds(Energies, scaleEnergies, h_sbrTran->thresholds,
+ YBufferWriteOffset, YBufferSzShift, h_sbrTran->no_cols,
+ h_sbrTran->no_rows, h_sbrTran->tran_off);
+
+ extractTransientCandidates(
+ Energies, scaleEnergies, h_sbrTran->thresholds, h_sbrTran->transients,
+ YBufferWriteOffset, YBufferSzShift, h_sbrTran->no_cols, 0,
+ h_sbrTran->no_rows, h_sbrTran->tran_off, addPrevSamples);
+
+ transient_info[0] = 0;
+ transient_info[1] = 0;
+ transient_info[2] = 0;
+
+ /* Offset by the amount of additional previous transient candidates being
+ * kept. */
+ qmfStartSample += addPrevSamples;
+
+ /* Check for transients in second granule (pick the last value of subsequent
+ * values) */
+ for (i = qmfStartSample; i < qmfStartSample + no_cols; i++) {
+ cond = (h_sbrTran->transients[i] <
+ fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1])) &&
+ (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr);
+
+ if (cond) {
+ transient_info[0] = (i - qmfStartSample) >> timeStepShift;
+ transient_info[1] = 1;
+ break;
+ }
+ }
+
+ if (h_sbrTran->frameShift != 0) {
+ /* transient prediction for LDSBR */
+ /* Check for transients in first <frameShift> qmf-slots of second frame */
+ for (i = qmfStartSample + no_cols;
+ i < qmfStartSample + no_cols + h_sbrTran->frameShift; i++) {
+ cond = (h_sbrTran->transients[i] <
+ fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1])) &&
+ (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr);
+
+ if (cond) {
+ int pos = (int)((i - qmfStartSample - no_cols) >> timeStepShift);
+ if ((pos < 3) && (transient_info[1] == 0)) {
+ transient_info[2] = 1;
+ }
+ break;
+ }
+ }
+ }
+}
+
+int FDKsbrEnc_InitSbrTransientDetector(
+ HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector,
+ UINT sbrSyntaxFlags, /* SBR syntax flags derived from AOT. */
+ INT frameSize, INT sampleFreq, sbrConfigurationPtr params, int tran_fc,
+ int no_cols, int no_rows, int YBufferWriteOffset, int YBufferSzShift,
+ int frameShift, int tran_off) {
+ INT totalBitrate =
+ params->codecSettings.standardBitrate * params->codecSettings.nChannels;
+ INT codecBitrate = params->codecSettings.bitRate;
+ FIXP_DBL bitrateFactor_m, framedur_fix;
+ INT bitrateFactor_e, tmp_e;
+
+ FDKmemclear(h_sbrTransientDetector, sizeof(SBR_TRANSIENT_DETECTOR));
+
+ h_sbrTransientDetector->frameShift = frameShift;
+ h_sbrTransientDetector->tran_off = tran_off;
+
+ if (codecBitrate) {
+ bitrateFactor_m = fDivNorm((FIXP_DBL)totalBitrate,
+ (FIXP_DBL)(codecBitrate << 2), &bitrateFactor_e);
+ bitrateFactor_e += 2;
+ } else {
+ bitrateFactor_m = FL2FXCONST_DBL(1.0 / 4.0);
+ bitrateFactor_e = 2;
+ }
+
+ framedur_fix = fDivNorm(frameSize, sampleFreq);
+
+ /* The longer the frames, the more often should the FIXFIX-
+ case transmit 2 envelopes instead of 1.
+ Frame durations below 10 ms produce the highest threshold
+ so that practically always only 1 env is transmitted. */
+ FIXP_DBL tmp = framedur_fix - FL2FXCONST_DBL(0.010);
+
+ tmp = fixMax(tmp, FL2FXCONST_DBL(0.0001));
+ tmp = fDivNorm(FL2FXCONST_DBL(0.000075), fPow2(tmp), &tmp_e);
+
+ bitrateFactor_e = (tmp_e + bitrateFactor_e);
+
+ if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) {
+ bitrateFactor_e--; /* divide by 2 */
+ }
+
+ FDK_ASSERT(no_cols <= 32);
+ FDK_ASSERT(no_rows <= 64);
+
+ h_sbrTransientDetector->no_cols = no_cols;
+ h_sbrTransientDetector->tran_thr =
+ (FIXP_DBL)((params->tran_thr << (32 - 24 - 1)) / no_rows);
+ h_sbrTransientDetector->tran_fc = tran_fc;
+ h_sbrTransientDetector->split_thr_m = fMult(tmp, bitrateFactor_m);
+ h_sbrTransientDetector->split_thr_e = bitrateFactor_e;
+ h_sbrTransientDetector->no_rows = no_rows;
+ h_sbrTransientDetector->mode = params->tran_det_mode;
+ h_sbrTransientDetector->prevLowBandEnergy = FL2FXCONST_DBL(0.0f);
+
+ return (0);
+}
+
+#define ENERGY_SCALING_SIZE 32
+
+INT FDKsbrEnc_InitSbrFastTransientDetector(
+ HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector,
+ const INT time_slots_per_frame, const INT bandwidth_qmf_slot,
+ const INT no_qmf_channels, const INT sbr_qmf_1st_band) {
+ int i;
+ int buff_size;
+ FIXP_DBL myExp;
+ FIXP_DBL myExpSlot;
+
+ h_sbrFastTransientDetector->lookahead = TRAN_DET_LOOKAHEAD;
+ h_sbrFastTransientDetector->nTimeSlots = time_slots_per_frame;
+
+ buff_size = h_sbrFastTransientDetector->nTimeSlots +
+ h_sbrFastTransientDetector->lookahead;
+
+ for (i = 0; i < buff_size; i++) {
+ h_sbrFastTransientDetector->delta_energy[i] = FL2FXCONST_DBL(0.0f);
+ h_sbrFastTransientDetector->energy_timeSlots[i] = FL2FXCONST_DBL(0.0f);
+ h_sbrFastTransientDetector->lowpass_energy[i] = FL2FXCONST_DBL(0.0f);
+ h_sbrFastTransientDetector->transientCandidates[i] = 0;
+ }
+
+ FDK_ASSERT(bandwidth_qmf_slot > 0.f);
+ h_sbrFastTransientDetector->stopBand =
+ fMin(TRAN_DET_STOP_FREQ / bandwidth_qmf_slot, no_qmf_channels);
+ h_sbrFastTransientDetector->startBand =
+ fMin(sbr_qmf_1st_band,
+ h_sbrFastTransientDetector->stopBand - TRAN_DET_MIN_QMFBANDS);
+
+ FDK_ASSERT(h_sbrFastTransientDetector->startBand < no_qmf_channels);
+ FDK_ASSERT(h_sbrFastTransientDetector->startBand <
+ h_sbrFastTransientDetector->stopBand);
+ FDK_ASSERT(h_sbrFastTransientDetector->startBand > 1);
+ FDK_ASSERT(h_sbrFastTransientDetector->stopBand > 1);
+
+ /* the energy weighting and adding up has a headroom of 6 Bits,
+ so up to 64 bands can be added without potential overflow. */
+ FDK_ASSERT(h_sbrFastTransientDetector->stopBand -
+ h_sbrFastTransientDetector->startBand <=
+ 64);
+
+/* QMF_HP_dB_SLOPE_FIX says that we want a 20 dB per 16 kHz HP filter.
+ The following lines map this to the QMF bandwidth. */
+#define EXP_E 7 /* 64 (=64) multiplications max, max. allowed sum is 0.5 */
+ myExp = fMultNorm(QMF_HP_dBd_SLOPE_FIX, 0, (FIXP_DBL)bandwidth_qmf_slot,
+ DFRACT_BITS - 1, EXP_E);
+ myExpSlot = myExp;
+
+ for (i = 0; i < 64; i++) {
+ /* Calculate dBf over all qmf bands:
+ dBf = (10^(0.002266f/10*bw(slot)))^(band) =
+ = 2^(log2(10)*0.002266f/10*bw(slot)*band) =
+ = 2^(0.00075275f*bw(slot)*band) */
+
+ FIXP_DBL dBf_m; /* dBf mantissa */
+ INT dBf_e; /* dBf exponent */
+ INT tmp;
+
+ INT dBf_int; /* dBf integer part */
+ FIXP_DBL dBf_fract; /* dBf fractional part */
+
+ /* myExp*(i+1) = myExp_int - myExp_fract
+ myExp*(i+1) is split up here for better accuracy of CalcInvLdData(),
+ for its result can be split up into an integer and a fractional part */
+
+ /* Round up to next integer */
+ FIXP_DBL myExp_int =
+ (myExpSlot & (FIXP_DBL)0xfe000000) + (FIXP_DBL)0x02000000;
+
+ /* This is the fractional part that needs to be substracted */
+ FIXP_DBL myExp_fract = myExp_int - myExpSlot;
+
+ /* Calc integer part */
+ dBf_int = CalcInvLdData(myExp_int);
+ /* The result needs to be re-scaled. The ld(myExp_int) had been scaled by
+ EXP_E, the CalcInvLdData expects the operand to be scaled by
+ LD_DATA_SHIFT. Therefore, the correctly scaled result is
+ dBf_int^(2^(EXP_E-LD_DATA_SHIFT)), which is dBf_int^2 */
+
+ if (dBf_int <=
+ 46340) { /* compare with maximum allowed value for signed integer
+ multiplication, 46340 =
+ (INT)floor(sqrt((double)(((UINT)1<<(DFRACT_BITS-1))-1))) */
+ dBf_int *= dBf_int;
+
+ /* Calc fractional part */
+ dBf_fract = CalcInvLdData(-myExp_fract);
+ /* The result needs to be re-scaled. The ld(myExp_fract) had been scaled
+ by EXP_E, the CalcInvLdData expects the operand to be scaled by
+ LD_DATA_SHIFT. Therefore, the correctly scaled result is
+ dBf_fract^(2^(EXP_E-LD_DATA_SHIFT)), which is dBf_fract^2 */
+ dBf_fract = fMultNorm(dBf_fract, dBf_fract, &tmp);
+
+ /* Get worst case scaling of multiplication result */
+ dBf_e = (DFRACT_BITS - 1 - tmp) - CountLeadingBits(dBf_int);
+
+ /* Now multiply integer with fractional part of the result, thus resulting
+ in the overall accurate fractional result */
+ dBf_m = fMultNorm(dBf_int, DFRACT_BITS - 1, dBf_fract, tmp, dBf_e);
+
+ myExpSlot += myExp;
+ } else {
+ dBf_m = (FIXP_DBL)0;
+ dBf_e = 0;
+ }
+
+ /* Keep the results */
+ h_sbrFastTransientDetector->dBf_m[i] = dBf_m;
+ h_sbrFastTransientDetector->dBf_e[i] = dBf_e;
+ }
+
+ /* Make sure that dBf is greater than 1.0 (because it should be a highpass) */
+ /* ... */
+
+ return 0;
+}
+
+void FDKsbrEnc_fastTransientDetect(
+ const HANDLE_FAST_TRAN_DET h_sbrFastTransientDetector,
+ const FIXP_DBL *const *Energies, const int *const scaleEnergies,
+ const INT YBufferWriteOffset, UCHAR *const tran_vector) {
+ int timeSlot, band;
+
+ FIXP_DBL max_delta_energy; /* helper to store maximum energy ratio */
+ int max_delta_energy_scale; /* helper to store scale of maximum energy ratio
+ */
+ int ind_max = 0; /* helper to store index of maximum energy ratio */
+ int isTransientInFrame = 0;
+
+ const int nTimeSlots = h_sbrFastTransientDetector->nTimeSlots;
+ const int lookahead = h_sbrFastTransientDetector->lookahead;
+ const int startBand = h_sbrFastTransientDetector->startBand;
+ const int stopBand = h_sbrFastTransientDetector->stopBand;
+
+ int *transientCandidates = h_sbrFastTransientDetector->transientCandidates;
+
+ FIXP_DBL *energy_timeSlots = h_sbrFastTransientDetector->energy_timeSlots;
+ int *energy_timeSlots_scale =
+ h_sbrFastTransientDetector->energy_timeSlots_scale;
+
+ FIXP_DBL *delta_energy = h_sbrFastTransientDetector->delta_energy;
+ int *delta_energy_scale = h_sbrFastTransientDetector->delta_energy_scale;
+
+ const FIXP_DBL thr = TRAN_DET_THRSHLD;
+ const INT thr_scale = TRAN_DET_THRSHLD_SCALE;
+
+ /*reset transient info*/
+ tran_vector[2] = 0;
+
+ /* reset transient candidates */
+ FDKmemclear(transientCandidates + lookahead, nTimeSlots * sizeof(int));
+
+ for (timeSlot = lookahead; timeSlot < nTimeSlots + lookahead; timeSlot++) {
+ int i, norm;
+ FIXP_DBL tmpE = FL2FXCONST_DBL(0.0f);
+ int headroomEnSlot = DFRACT_BITS - 1;
+
+ FIXP_DBL smallNRG = FL2FXCONST_DBL(1e-2f);
+ FIXP_DBL denominator;
+ INT denominator_scale;
+
+ /* determine minimum headroom of energy values for this timeslot */
+ for (band = startBand; band < stopBand; band++) {
+ int tmp_headroom = fNormz(Energies[timeSlot][band]) - 1;
+ if (tmp_headroom < headroomEnSlot) {
+ headroomEnSlot = tmp_headroom;
+ }
+ }
+
+ for (i = 0, band = startBand; band < stopBand; band++, i++) {
+ /* energy is weighted by weightingfactor stored in dBf_m array */
+ /* dBf_m index runs from 0 to stopBand-startband */
+ /* energy shifted by calculated headroom for maximum precision */
+ FIXP_DBL weightedEnergy =
+ fMult(Energies[timeSlot][band] << headroomEnSlot,
+ h_sbrFastTransientDetector->dBf_m[i]);
+
+ /* energy is added up */
+ /* shift by 6 to have a headroom for maximum 64 additions */
+ /* shift by dBf_e to handle weighting factor dependent scale factors */
+ tmpE +=
+ weightedEnergy >> (6 + (10 - h_sbrFastTransientDetector->dBf_e[i]));
+ }
+
+ /* store calculated energy for timeslot */
+ energy_timeSlots[timeSlot] = tmpE;
+
+ /* calculate overall scale factor for energy of this timeslot */
+ /* = original scale factor of energies
+ * (-scaleEnergies[0]+2*QMF_SCALE_OFFSET or
+ * -scaleEnergies[1]+2*QMF_SCALE_OFFSET */
+ /* depending on YBufferWriteOffset) */
+ /* + weighting factor scale (10) */
+ /* + adding up scale factor ( 6) */
+ /* - headroom of energy value (headroomEnSlot) */
+ if (timeSlot < YBufferWriteOffset) {
+ energy_timeSlots_scale[timeSlot] =
+ (-scaleEnergies[0] + 2 * QMF_SCALE_OFFSET) + (10 + 6) -
+ headroomEnSlot;
+ } else {
+ energy_timeSlots_scale[timeSlot] =
+ (-scaleEnergies[1] + 2 * QMF_SCALE_OFFSET) + (10 + 6) -
+ headroomEnSlot;
+ }
+
+ /* Add a small energy to the denominator, thus making the transient
+ detection energy-dependent. Loud transients are being detected,
+ silent ones not. */
+
+ /* make sure that smallNRG does not overflow */
+ if (-energy_timeSlots_scale[timeSlot - 1] + 1 > 5) {
+ denominator = smallNRG;
+ denominator_scale = 0;
+ } else {
+ /* Leave an additional headroom of 1 bit for this addition. */
+ smallNRG =
+ scaleValue(smallNRG, -(energy_timeSlots_scale[timeSlot - 1] + 1));
+ denominator = (energy_timeSlots[timeSlot - 1] >> 1) + smallNRG;
+ denominator_scale = energy_timeSlots_scale[timeSlot - 1] + 1;
+ }
+
+ delta_energy[timeSlot] =
+ fDivNorm(energy_timeSlots[timeSlot], denominator, &norm);
+ delta_energy_scale[timeSlot] =
+ energy_timeSlots_scale[timeSlot] - denominator_scale + norm;
+ }
+
+ /*get transient candidates*/
+ /* For every timeslot, check if delta(E) exceeds the threshold. If it did,
+ it could potentially be marked as a transient candidate. However, the 2
+ slots before the current one must not be transients with an energy higher
+ than 1.4*E(current). If both aren't transients or if the energy of the
+ current timesolot is more than 1.4 times higher than the energy in the
+ last or the one before the last slot, it is marked as a transient.*/
+
+ FDK_ASSERT(lookahead >= 2);
+ for (timeSlot = lookahead; timeSlot < nTimeSlots + lookahead; timeSlot++) {
+ FIXP_DBL energy_cur_slot_weighted =
+ fMult(energy_timeSlots[timeSlot], FL2FXCONST_DBL(1.0f / 1.4f));
+ if (!fIsLessThan(delta_energy[timeSlot], delta_energy_scale[timeSlot], thr,
+ thr_scale) &&
+ (((transientCandidates[timeSlot - 2] == 0) &&
+ (transientCandidates[timeSlot - 1] == 0)) ||
+ !fIsLessThan(energy_cur_slot_weighted,
+ energy_timeSlots_scale[timeSlot],
+ energy_timeSlots[timeSlot - 1],
+ energy_timeSlots_scale[timeSlot - 1]) ||
+ !fIsLessThan(energy_cur_slot_weighted,
+ energy_timeSlots_scale[timeSlot],
+ energy_timeSlots[timeSlot - 2],
+ energy_timeSlots_scale[timeSlot - 2]))) {
+ /* in case of strong transients, subsequent
+ * qmf slots might be recognized as transients. */
+ transientCandidates[timeSlot] = 1;
+ }
+ }
+
+ /*get transient with max energy*/
+ max_delta_energy = FL2FXCONST_DBL(0.0f);
+ max_delta_energy_scale = 0;
+ ind_max = 0;
+ isTransientInFrame = 0;
+ for (timeSlot = 0; timeSlot < nTimeSlots; timeSlot++) {
+ int scale = fMax(delta_energy_scale[timeSlot], max_delta_energy_scale);
+ if (transientCandidates[timeSlot] &&
+ ((delta_energy[timeSlot] >> (scale - delta_energy_scale[timeSlot])) >
+ (max_delta_energy >> (scale - max_delta_energy_scale)))) {
+ max_delta_energy = delta_energy[timeSlot];
+ max_delta_energy_scale = scale;
+ ind_max = timeSlot;
+ isTransientInFrame = 1;
+ }
+ }
+
+ /*from all transient candidates take the one with the biggest energy*/
+ if (isTransientInFrame) {
+ tran_vector[0] = ind_max;
+ tran_vector[1] = 1;
+ } else {
+ /*reset transient info*/
+ tran_vector[0] = tran_vector[1] = 0;
+ }
+
+ /*check for transients in lookahead*/
+ for (timeSlot = nTimeSlots; timeSlot < nTimeSlots + lookahead; timeSlot++) {
+ if (transientCandidates[timeSlot]) {
+ tran_vector[2] = 1;
+ }
+ }
+
+ /*update buffers*/
+ for (timeSlot = 0; timeSlot < lookahead; timeSlot++) {
+ transientCandidates[timeSlot] = transientCandidates[nTimeSlots + timeSlot];
+
+ /* fixpoint stuff */
+ energy_timeSlots[timeSlot] = energy_timeSlots[nTimeSlots + timeSlot];
+ energy_timeSlots_scale[timeSlot] =
+ energy_timeSlots_scale[nTimeSlots + timeSlot];
+
+ delta_energy[timeSlot] = delta_energy[nTimeSlots + timeSlot];
+ delta_energy_scale[timeSlot] = delta_energy_scale[nTimeSlots + timeSlot];
+ }
+}