summaryrefslogtreecommitdiffstats
path: root/libSBRenc/src/tran_det.cpp
diff options
context:
space:
mode:
authorDave Burke <daveburke@google.com>2012-04-17 09:51:45 -0700
committerDave Burke <daveburke@google.com>2012-04-17 23:04:43 -0700
commit9bf37cc9712506b2483650c82d3c41152337ef7e (patch)
tree77db44e2bae06e3d144b255628be2b7a55c581d3 /libSBRenc/src/tran_det.cpp
parenta37315fe10ee143d6d0b28c19d41a476a23e63ea (diff)
downloadfdk-aac-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.gz
fdk-aac-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.bz2
fdk-aac-9bf37cc9712506b2483650c82d3c41152337ef7e.zip
Fraunhofer AAC codec.
License boilerplate update to follow. Change-Id: I2810460c11a58b6d148d84673cc031f3685e79b5
Diffstat (limited to 'libSBRenc/src/tran_det.cpp')
-rw-r--r--libSBRenc/src/tran_det.cpp645
1 files changed, 645 insertions, 0 deletions
diff --git a/libSBRenc/src/tran_det.cpp b/libSBRenc/src/tran_det.cpp
new file mode 100644
index 0000000..4011bf3
--- /dev/null
+++ b/libSBRenc/src/tran_det.cpp
@@ -0,0 +1,645 @@
+/****************************************************************************
+
+ (C) Copyright Fraunhofer IIS (2004)
+ All Rights Reserved
+
+ Please be advised that this software and/or program delivery is
+ Confidential Information of Fraunhofer and subject to and covered by the
+
+ Fraunhofer IIS Software Evaluation Agreement
+ between Google Inc. and Fraunhofer
+ effective and in full force since March 1, 2012.
+
+ You may use this software and/or program only under the terms and
+ conditions described in the above mentioned Fraunhofer IIS Software
+ Evaluation Agreement. Any other and/or further use requires a separate agreement.
+
+
+ This software and/or program is protected by copyright law and international
+ treaties. Any reproduction or distribution of this software and/or program,
+ or any portion of it, may result in severe civil and criminal penalties, and
+ will be prosecuted to the maximum extent possible under law.
+
+ $Id$
+
+*******************************************************************************/
+
+#include "tran_det.h"
+
+#include "fram_gen.h"
+#include "sbr_ram.h"
+#include "sbr_misc.h"
+
+#include "genericStds.h"
+
+#define NORM_QMF_ENERGY 5.684341886080801486968994140625e-14 /* 2^-44 */
+
+/* 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
+*******************************************************************************/
+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 stop)
+{
+ INT i,j;
+ INT len1,len2;
+ FIXP_DBL delta,tmp0,tmp1,tmp2;
+ FIXP_DBL accu1,accu2,delta_sum,result;
+
+ FDK_ASSERT(scaleEnergies[0] >= 0);
+
+ /* equal for aac (would be not equal for mp3) */
+ 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);
+
+ delta_sum = FL2FXCONST_DBL(0.0f);
+
+ /* Sum up energies of all QMF-timeslots for both halfs */
+ for (j=0; j<nSfb; j++) {
+ #define NRG_SCALE 3
+ /* init with some energy to prevent division by zero
+ and to prevent splitting for very low levels */
+ accu1 = ((FL2FXCONST_DBL((1.0e6*NORM_QMF_ENERGY*8.0/32))) << fixMin(scaleEnergies[0],25))>>NRG_SCALE; /* complex init for compare with original version */
+ accu2 = ((FL2FXCONST_DBL((1.0e6*NORM_QMF_ENERGY*8.0/32))) << fixMin(scaleEnergies[0],25))>>NRG_SCALE; /* can be simplified in dsp implementation */
+
+ /* Sum up energies in first half */
+ for (i=start; i<border; i++) {
+ accu1 += (Energies[i][j]>>NRG_SCALE);
+ }
+
+ /* Sum up energies in second half */
+ for (i=border; i<stop; i++) {
+ accu2 += (Energies[i][j]>>NRG_SCALE);
+ }
+
+ /* Energy change in current band */
+ tmp0 = CalcLdData(accu2);
+ tmp1 = CalcLdData(accu1);
+ tmp2 = (tmp0 - tmp1 + CalcLdData(len1)-CalcLdData(len2));
+ delta = fixp_abs(fMult(tmp2, FL2FXCONST_DBL(0.6931471806f)));
+
+ /* Weighting with amplitude ratio of this band */
+ result = (EnergyTotal == FL2FXCONST_DBL(0.0f))
+ ? FL2FXCONST_DBL(0.f)
+ : FDKsbrEnc_LSI_divide_scale_fract( (accu1+accu2),
+ (EnergyTotal>>NRG_SCALE)+(FIXP_DBL)1,
+ (FIXP_DBL)MAXVAL_DBL >> fixMin(scaleEnergies[0],(DFRACT_BITS-1)) );
+
+ delta_sum += (FIXP_DBL)(fMult(sqrtFixp(result), delta));
+ }
+
+ return fMult(delta_sum, pos_weight);
+}
+
+
+/*******************************************************************************
+ Functionname: addLowbandEnergies
+ *******************************************************************************
+ \brief Calculates total lowband energy
+
+ The return value nrgTotal is scaled by the factor (1/32.0)
+
+ \return total energy in the lowband
+*******************************************************************************/
+static FIXP_DBL addLowbandEnergies(FIXP_DBL **Energies,
+ int *scaleEnergies,
+ int YBufferWriteOffset,
+ int nrgSzShift,
+ int tran_off,
+ UCHAR *freqBandTable,
+ int slots)
+{
+ FIXP_DBL nrgTotal;
+ FIXP_DBL accu1 = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL accu2 = FL2FXCONST_DBL(0.0f);
+ int tran_offdiv2 = tran_off>>nrgSzShift;
+ int ts,k;
+
+ /* Sum up lowband energy from one frame at offset tran_off */
+ for (ts=tran_offdiv2; ts<YBufferWriteOffset; ts++) {
+ for (k = 0; k < freqBandTable[0]; k++) {
+ accu1 += Energies[ts][k] >> 6;
+ }
+ }
+ for (; ts<tran_offdiv2+(slots>>nrgSzShift); ts++) {
+ for (k = 0; k < freqBandTable[0]; k++) {
+ accu2 += Energies[ts][k] >> 6;
+ }
+ }
+
+ nrgTotal = ( (accu1 >> fixMin(scaleEnergies[0],(DFRACT_BITS-1)))
+ + (accu2 >> fixMin(scaleEnergies[1],(DFRACT_BITS-1))) ) << (2);
+
+ return(nrgTotal);
+}
+
+
+/*******************************************************************************
+ 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 (1/32.0) and scaleEnergies[0]
+ The return value nrgTotal is scaled by the factor (1/32.0)
+
+ \return total energy in the highband
+*******************************************************************************/
+
+static FIXP_DBL addHighbandEnergies(FIXP_DBL **RESTRICT Energies, /*!< input */
+ INT *scaleEnergies,
+ 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;
+ 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++) {
+ slotIn = 2*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+i)>>1][k] >> 5);
+ }
+ }
+ EnergiesM[slotOut][j] = accu;
+ }
+ }
+
+ scale = fixMin(8,scaleEnergies[0]); /* scale energies down before add up */
+
+ if ((scaleEnergies[0]-1) > (DFRACT_BITS-1) )
+ nrgTotal = FL2FXCONST_DBL(0.0f);
+ else {
+ /* Now add all energies */
+ accu = FL2FXCONST_DBL(0.0f);
+ for (slotOut=0; slotOut<sbrSlots; slotOut++) {
+ for (j=0; j<nSfb; j++) {
+ accu += (EnergiesM[slotOut][j] >> scale);
+ }
+ }
+ nrgTotal = accu >> (scaleEnergies[0]-scale);
+ }
+
+ 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)
+{
+ if (tran_vector[1]==0) /* no transient was detected */
+ {
+ FIXP_DBL delta;
+ FIXP_DBL EnergiesM[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS];
+ FIXP_DBL EnergyTotal,newLowbandEnergy,newHighbandEnergy;
+ INT border;
+ INT sbrSlots = fMultI(GetInvInt(timeStep),no_cols);
+
+ FDK_ASSERT( sbrSlots * timeStep == no_cols );
+
+ /*
+ 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,
+ EnergiesM,
+ freqBandTable,
+ nSfb,
+ sbrSlots,
+ timeStep);
+
+ if ( h_sbrTransientDetector->frameShift != 0 ) {
+ if (tran_vector[1]==0)
+ tran_vector[0] = 0;
+ } else
+ {
+ /* 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 + h_sbrTransientDetector->prevLowBandEnergy) >> 1;
+ EnergyTotal += newHighbandEnergy;
+ /* The below border should specify the same position as the middle border
+ of a FIXFIX-frame with 2 envelopes. */
+ border = (sbrSlots+1) >> 1;
+
+ delta = spectralChange(EnergiesM,
+ scaleEnergies,
+ EnergyTotal,
+ nSfb,
+ 0,
+ border,
+ sbrSlots);
+
+ if (delta > (h_sbrTransientDetector->split_thr >> LD_DATA_SHIFT)) /* delta scaled by 1/64 */
+ tran_vector[0] = 1; /* Set flag for splitting */
+ else
+ tran_vector[0] = 0;
+ }
+
+ /* Update prevLowBandEnergy */
+ h_sbrTransientDetector->prevLowBandEnergy = newLowbandEnergy;
+ h_sbrTransientDetector->prevHighBandEnergy = newHighbandEnergy;
+ }
+}
+
+/*
+ * 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 += fMult(Energies[j][i], i_noCols);
+ for (; j<endEnergy; j++)
+ accu1 += fMult(Energies[j][i], i_noCols);
+
+ mean_val = (accu0 >> scaleFactor0) + (accu1 >> 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 = fPow2(temp);
+ temp = fMult(temp, i_noCols1);
+ accu += temp;
+ }
+ for (; j<endEnergy; j++) {
+ temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor1))<<shift;
+ temp = fPow2(temp);
+ temp = fMult(temp, i_noCols1);
+ accu += temp;
+ }
+
+ 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*QMF_MAX_TIME_SLOTS);
+ FIXP_DBL *RESTRICT pEnergiesTemp = EnergiesTemp;
+ 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 += pEnergiesTemp[jIndex+d]; /* R */
+ delta -= pEnergiesTemp[jIndex-d]; /* L */
+ delta -= thres;
+
+ if ( delta > (FIXP_DBL)0 ) {
+ tran += fMult(i_thres, delta);
+ }
+ }
+ transients[jpBM] += tran;
+ }
+ }
+ C_ALLOC_SCRATCH_END(EnergiesTemp, FIXP_DBL, 2*QMF_MAX_TIME_SLOTS);
+}
+
+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;
+ /* FDKprintf("\nSBR Transient at timeSlot %d\n", transient_info[0]); */
+ 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,
+ 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_fix, framedur_fix;
+ INT scale_0, scale_1;
+
+ FDKmemclear(h_sbrTransientDetector,sizeof(SBR_TRANSIENT_DETECTOR));
+
+ h_sbrTransientDetector->frameShift = frameShift;
+ h_sbrTransientDetector->tran_off = tran_off;
+
+ if(codecBitrate) {
+ bitrateFactor_fix = fDivNorm((FIXP_DBL)totalBitrate, (FIXP_DBL)(codecBitrate<<2),&scale_0);
+ }
+ else {
+ bitrateFactor_fix = FL2FXCONST_DBL(1.0/4.0);
+ scale_0 = 0;
+ }
+
+ 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), &scale_1);
+
+ scale_1 = -(scale_1 + scale_0 + 2);
+
+ FDK_ASSERT(no_cols <= QMF_MAX_TIME_SLOTS);
+ FDK_ASSERT(no_rows <= QMF_CHANNELS);
+
+ 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;
+
+ if (scale_1>=0) {
+ h_sbrTransientDetector->split_thr = fMult(tmp, bitrateFactor_fix) >> scale_1;
+ }
+ else {
+ h_sbrTransientDetector->split_thr = fMult(tmp, bitrateFactor_fix) << (-scale_1);
+ }
+
+ h_sbrTransientDetector->no_rows = no_rows;
+ h_sbrTransientDetector->mode = params->tran_det_mode;
+ h_sbrTransientDetector->prevLowBandEnergy = FL2FXCONST_DBL(0.0f);
+
+ return (0);
+}
+