diff options
Diffstat (limited to 'libSBRdec/src/env_calc.cpp')
-rw-r--r-- | libSBRdec/src/env_calc.cpp | 2171 |
1 files changed, 2171 insertions, 0 deletions
diff --git a/libSBRdec/src/env_calc.cpp b/libSBRdec/src/env_calc.cpp new file mode 100644 index 0000000..4d545f4 --- /dev/null +++ b/libSBRdec/src/env_calc.cpp @@ -0,0 +1,2171 @@ +/**************************************************************************** + + (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$ + +*******************************************************************************/ +/*! + \file + \brief Envelope calculation $Revision: 36841 $ + + The envelope adjustor compares the energies present in the transposed + highband to the reference energies conveyed with the bitstream. + The highband is amplified (sometimes) or attenuated (mostly) to the + desired level. + + The spectral shape of the reference energies can be changed several times per + frame if necessary. Each set of energy values corresponding to a certain range + in time will be called an <em>envelope</em> here. + The bitstream supports several frequency scales and two resolutions. Normally, + one or more QMF-subbands are grouped to one SBR-band. An envelope contains + reference energies for each SBR-band. + In addition to the energy envelopes, noise envelopes are transmitted that + define the ratio of energy which is generated by adding noise instead of + transposing the lowband. The noise envelopes are given in a coarser time + and frequency resolution. + If a signal contains strong tonal components, synthetic sines can be + generated in individual SBR bands. + + An overlap buffer of 6 QMF-timeslots is used to allow a more + flexible alignment of the envelopes in time that is not restricted to the + core codec's frame borders. + Therefore the envelope adjustor has access to the spectral data of the + current frame as well as the last 6 QMF-timeslots of the previous frame. + However, in average only the data of 1 frame is being processed as + the adjustor is called once per frame. + + Depending on the frequency range set in the bitstream, only QMF-subbands between + <em>lowSubband</em> and <em>highSubband</em> are adjusted. + + Scaling of spectral data to maximize SNR (see #QMF_SCALE_FACTOR) as well as a special Mantissa-Exponent format + ( see calculateSbrEnvelope() ) are being used. The main entry point for this modules is calculateSbrEnvelope(). + + \sa sbr_scale.h, #QMF_SCALE_FACTOR, calculateSbrEnvelope(), \ref documentationOverview +*/ + + +#include "env_calc.h" + +#include "sbrdec_freq_sca.h" +#include "env_extr.h" +#include "transcendent.h" +#include "sbr_ram.h" +#include "sbr_rom.h" + +#include "genericStds.h" /* need FDKpow() for debug outputs */ + +#if defined(__arm__) +#include "arm/env_calc_arm.cpp" +#endif + +typedef struct +{ + FIXP_DBL nrgRef[MAX_FREQ_COEFFS]; + FIXP_DBL nrgEst[MAX_FREQ_COEFFS]; + FIXP_DBL nrgGain[MAX_FREQ_COEFFS]; + FIXP_DBL noiseLevel[MAX_FREQ_COEFFS]; + FIXP_DBL nrgSine[MAX_FREQ_COEFFS]; + + SCHAR nrgRef_e[MAX_FREQ_COEFFS]; + SCHAR nrgEst_e[MAX_FREQ_COEFFS]; + SCHAR nrgGain_e[MAX_FREQ_COEFFS]; + SCHAR noiseLevel_e[MAX_FREQ_COEFFS]; + SCHAR nrgSine_e[MAX_FREQ_COEFFS]; +} +ENV_CALC_NRGS; + +/*static*/ void equalizeFiltBufferExp(FIXP_DBL *filtBuffer, + SCHAR *filtBuffer_e, + FIXP_DBL *NrgGain, + SCHAR *NrgGain_e, + int subbands); + +/*static*/ void calcNrgPerSubband(FIXP_DBL **analysBufferReal, + FIXP_DBL **analysBufferImag, + int lowSubband, int highSubband, + int start_pos, int next_pos, + SCHAR frameExp, + FIXP_DBL *nrgEst, + SCHAR *nrgEst_e ); + +/*static*/ void calcNrgPerSfb(FIXP_DBL **analysBufferReal, + FIXP_DBL **analysBufferImag, + int nSfb, + UCHAR *freqBandTable, + int start_pos, int next_pos, + SCHAR input_e, + FIXP_DBL *nrg_est, + SCHAR *nrg_est_e ); + +/*static*/ void calcSubbandGain(FIXP_DBL nrgRef, SCHAR nrgRef_e, ENV_CALC_NRGS* nrgs, int c, + FIXP_DBL tmpNoise, SCHAR tmpNoise_e, + UCHAR sinePresentFlag, + UCHAR sineMapped, + int noNoiseFlag); + +/*static*/ void calcAvgGain(ENV_CALC_NRGS* nrgs, + int lowSubband, + int highSubband, + FIXP_DBL *sumRef_m, + SCHAR *sumRef_e, + FIXP_DBL *ptrAvgGain_m, + SCHAR *ptrAvgGain_e); + +/*static*/ void adjustTimeSlotLC(FIXP_DBL *ptrReal, + ENV_CALC_NRGS* nrgs, + UCHAR *ptrHarmIndex, + int lowSubbands, + int noSubbands, + int scale_change, + int noNoiseFlag, + int *ptrPhaseIndex, + int fCldfb); +/*static*/ void adjustTimeSlotHQ(FIXP_DBL *ptrReal, + FIXP_DBL *ptrImag, + HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, + ENV_CALC_NRGS* nrgs, + int lowSubbands, + int noSubbands, + int scale_change, + FIXP_SGL smooth_ratio, + int noNoiseFlag, + int filtBufferNoiseShift); + + +/*! + \brief Map sine flags from bitstream to QMF bands + + The bitstream carries only 1 sine flag per band and frame. + This function maps every sine flag from the bitstream to a specific QMF subband + and to a specific envelope where the sine shall start. + The result is stored in the vector sineMapped which contains one entry per + QMF subband. The value of an entry specifies the envelope where a sine + shall start. A value of #MAX_ENVELOPES indicates that no sine is present + in the subband. + The missing harmonics flags from the previous frame (harmFlagsPrev) determine + if a sine starts at the beginning of the frame or at the transient position. + Additionally, the flags in harmFlagsPrev are being updated by this function + for the next frame. +*/ +/*static*/ void mapSineFlags(UCHAR *freqBandTable, /*!< Band borders (there's only 1 flag per band) */ + int nSfb, /*!< Number of bands in the table */ + UCHAR *addHarmonics, /*!< vector with 1 flag per sfb */ + int *harmFlagsPrev, /*!< Packed 'addHarmonics' */ + int tranEnv, /*!< Transient position */ + SCHAR *sineMapped) /*!< Resulting vector of sine start positions for each QMF band */ + +{ + int i; + int lowSubband2 = freqBandTable[0]<<1; + int bitcount = 0; + int oldflags = *harmFlagsPrev; + int newflags = 0; + + /* + Format of harmFlagsPrev: + + first word = flags for highest 16 sfb bands in use + second word = flags for next lower 16 sfb bands (if present) + third word = flags for lowest 16 sfb bands (if present) + + Up to MAX_FREQ_COEFFS sfb bands can be flagged for a sign. + The lowest bit of the first word corresponds to the _highest_ sfb band in use. + This is ensures that each flag is mapped to the same QMF band even after a + change of the crossover-frequency. + */ + + + /* Reset the output vector first */ + FDKmemset(sineMapped, MAX_ENVELOPES,MAX_FREQ_COEFFS); /* MAX_ENVELOPES means 'no sine' */ + + freqBandTable += nSfb; + addHarmonics += nSfb-1; + + for (i=nSfb; i!=0; i--) { + int ui = *freqBandTable--; /* Upper limit of the current scale factor band. */ + int li = *freqBandTable; /* Lower limit of the current scale factor band. */ + + if ( *addHarmonics-- ) { /* There is a sine in this band */ + + unsigned int mask = 1 << bitcount; + newflags |= mask; /* Set flag */ + + /* + If there was a sine in the last frame, let it continue from the first envelope on + else start at the transient position. + */ + sineMapped[(ui+li-lowSubband2) >> 1] = ( oldflags & mask ) ? 0 : tranEnv; + } + + if ((++bitcount == 16) || i==1) { + bitcount = 0; + *harmFlagsPrev++ = newflags; + oldflags = *harmFlagsPrev; /* Fetch 16 of the old flags */ + newflags = 0; + } + } +} + + +/*! + \brief Reduce gain-adjustment induced aliasing for real valued filterbank. +*/ +/*static*/ void +aliasingReduction(FIXP_DBL* degreeAlias, /*!< estimated aliasing for each QMF channel */ + ENV_CALC_NRGS* nrgs, + int* useAliasReduction, /*!< synthetic sine engergy for each subband, used as flag */ + int noSubbands) /*!< number of QMF channels to process */ +{ + FIXP_DBL* nrgGain = nrgs->nrgGain; /*!< subband gains to be modified */ + SCHAR* nrgGain_e = nrgs->nrgGain_e; /*!< subband gains to be modified (exponents) */ + FIXP_DBL* nrgEst = nrgs->nrgEst; /*!< subband energy before amplification */ + SCHAR* nrgEst_e = nrgs->nrgEst_e; /*!< subband energy before amplification (exponents) */ + int grouping = 0, index = 0, noGroups, k; + int groupVector[MAX_FREQ_COEFFS]; + + /* Calculate grouping*/ + for (k = 0; k < noSubbands-1; k++ ){ + if ( (degreeAlias[k + 1] != FL2FXCONST_DBL(0.0f)) && useAliasReduction[k] ) { + if(grouping==0){ + groupVector[index++] = k; + grouping = 1; + } + else{ + if(groupVector[index-1] + 3 == k){ + groupVector[index++] = k + 1; + grouping = 0; + } + } + } + else{ + if(grouping){ + if(useAliasReduction[k]) + groupVector[index++] = k + 1; + else + groupVector[index++] = k; + grouping = 0; + } + } + } + + if(grouping){ + groupVector[index++] = noSubbands; + } + noGroups = index >> 1; + + + /*Calculate new gain*/ + for (int group = 0; group < noGroups; group ++) { + FIXP_DBL nrgOrig = FL2FXCONST_DBL(0.0f); /* Original signal energy in current group of bands */ + SCHAR nrgOrig_e = 0; + FIXP_DBL nrgAmp = FL2FXCONST_DBL(0.0f); /* Amplified signal energy in group (using current gains) */ + SCHAR nrgAmp_e = 0; + FIXP_DBL nrgMod = FL2FXCONST_DBL(0.0f); /* Signal energy in group when applying modified gains */ + SCHAR nrgMod_e = 0; + FIXP_DBL groupGain; /* Total energy gain in group */ + SCHAR groupGain_e; + FIXP_DBL compensation; /* Compensation factor for the energy change when applying modified gains */ + SCHAR compensation_e; + + int startGroup = groupVector[2*group]; + int stopGroup = groupVector[2*group+1]; + + /* Calculate total energy in group before and after amplification with current gains: */ + for(k = startGroup; k < stopGroup; k++){ + /* Get original band energy */ + FIXP_DBL tmp = nrgEst[k]; + SCHAR tmp_e = nrgEst_e[k]; + + FDK_add_MantExp(tmp, tmp_e, nrgOrig, nrgOrig_e, &nrgOrig, &nrgOrig_e); + + /* Multiply band energy with current gain */ + tmp = fMult(tmp,nrgGain[k]); + tmp_e = tmp_e + nrgGain_e[k]; + + FDK_add_MantExp(tmp, tmp_e, nrgAmp, nrgAmp_e, &nrgAmp, &nrgAmp_e); + } + + /* Calculate total energy gain in group */ + FDK_divide_MantExp(nrgAmp, nrgAmp_e, + nrgOrig, nrgOrig_e, + &groupGain, &groupGain_e); + + for(k = startGroup; k < stopGroup; k++){ + FIXP_DBL tmp; + SCHAR tmp_e; + + FIXP_DBL alpha = degreeAlias[k]; + if (k < noSubbands - 1) { + if (degreeAlias[k + 1] > alpha) + alpha = degreeAlias[k + 1]; + } + + /* Modify gain depending on the degree of aliasing */ + FDK_add_MantExp( fMult(alpha,groupGain), groupGain_e, + fMult(/*FL2FXCONST_DBL(1.0f)*/ (FIXP_DBL)MAXVAL_DBL - alpha,nrgGain[k]), nrgGain_e[k], + &nrgGain[k], &nrgGain_e[k] ); + + /* Apply modified gain to original energy */ + tmp = fMult(nrgGain[k],nrgEst[k]); + tmp_e = nrgGain_e[k] + nrgEst_e[k]; + + /* Accumulate energy with modified gains applied */ + FDK_add_MantExp( tmp, tmp_e, + nrgMod, nrgMod_e, + &nrgMod, &nrgMod_e ); + } + + /* Calculate compensation factor to retain the energy of the amplified signal */ + FDK_divide_MantExp(nrgAmp, nrgAmp_e, + nrgMod, nrgMod_e, + &compensation, &compensation_e); + + /* Apply compensation factor to all gains of the group */ + for(k = startGroup; k < stopGroup; k++){ + nrgGain[k] = fMult(nrgGain[k],compensation); + nrgGain_e[k] = nrgGain_e[k] + compensation_e; + } + } +} + + + /* Convert headroom bits to exponent */ +#define SCALE2EXP(s) (15-(s)) +#define EXP2SCALE(e) (15-(e)) + +/*! + \brief Apply spectral envelope to subband samples + + This function is called from sbr_dec.cpp in each frame. + + To enhance accuracy and due to the usage of tables for squareroots and + inverse, some calculations are performed with the operands being split + into mantissa and exponent. The variable names in the source code carry + the suffixes <em>_m</em> and <em>_e</em> respectively. The control data + in #hFrameData containts envelope data which is represented by this format but + stored in single words. (See requantizeEnvelopeData() for details). This data + is unpacked within calculateSbrEnvelope() to follow the described suffix convention. + + The actual value (comparable to the corresponding float-variable in the + research-implementation) of a mantissa/exponent-pair can be calculated as + + \f$ value = value\_m * 2^{value\_e} \f$ + + All energies and noise levels decoded from the bitstream suit for an + original signal magnitude of \f$\pm 32768 \f$ rather than \f$ \pm 1\f$. Therefore, + the scale factor <em>hb_scale</em> passed into this function will be converted + to an 'input exponent' (#input_e), which fits the internal representation. + + Before the actual processing, an exponent #adj_e for resulting adjusted + samples is derived from the maximum reference energy. + + Then, for each envelope, the following steps are performed: + + \li Calculate energy in the signal to be adjusted. Depending on the the value of + #interpolFreq (interpolation mode), this is either done seperately + for each QMF-subband or for each SBR-band. + The resulting energies are stored in #nrgEst_m[#MAX_FREQ_COEFFS] (mantissas) + and #nrgEst_e[#MAX_FREQ_COEFFS] (exponents). + \li Calculate gain and noise level for each subband:<br> + \f$ gain = \sqrt{ \frac{nrgRef}{nrgEst} \cdot (1 - noiseRatio) } + \hspace{2cm} + noise = \sqrt{ nrgRef \cdot noiseRatio } + \f$<br> + where <em>noiseRatio</em> and <em>nrgRef</em> are extracted from the + bitstream and <em>nrgEst</em> is the subband energy before adjustment. + The resulting gains are stored in #nrgGain_m[#MAX_FREQ_COEFFS] + (mantissas) and #nrgGain_e[#MAX_FREQ_COEFFS] (exponents), the noise levels + are stored in #noiseLevel_m[#MAX_FREQ_COEFFS] and #noiseLevel_e[#MAX_FREQ_COEFFS] + (exponents). + The sine levels are stored in #nrgSine_m[#MAX_FREQ_COEFFS] + and #nrgSine_e[#MAX_FREQ_COEFFS]. + \li Noise limiting: The gain for each subband is limited both absolutely + and relatively compared to the total gain over all subbands. + \li Boost gain: Calculate and apply boost factor for each limiter band + in order to compensate for the energy loss imposed by the limiting. + \li Apply gains and add noise: The gains and noise levels are applied + to all timeslots of the current envelope. A short FIR-filter (length 4 + QMF-timeslots) can be used to smooth the sudden change at the envelope borders. + Each complex subband sample of the current timeslot is multiplied by the + smoothed gain, then random noise with the calculated level is added. + + \note + To reduce the stack size, some of the local arrays could be located within + the time output buffer. Of the 512 samples temporarily available there, + about half the size is already used by #SBR_FRAME_DATA. A pointer to the + remaining free memory could be supplied by an additional argument to calculateSbrEnvelope() + in sbr_dec: + + \par + \code + calculateSbrEnvelope (&hSbrDec->sbrScaleFactor, + &hSbrDec->SbrCalculateEnvelope, + hHeaderData, + hFrameData, + QmfBufferReal, + QmfBufferImag, + timeOutPtr + sizeof(SBR_FRAME_DATA)/sizeof(Float) + 1); + \endcode + + \par + Within calculateSbrEnvelope(), some pointers could be defined instead of the arrays + #nrgRef_m, #nrgRef_e, #nrgEst_m, #nrgEst_e, #noiseLevel_m: + + \par + \code + fract* nrgRef_m = timeOutPtr; + SCHAR* nrgRef_e = nrgRef_m + MAX_FREQ_COEFFS; + fract* nrgEst_m = nrgRef_e + MAX_FREQ_COEFFS; + SCHAR* nrgEst_e = nrgEst_m + MAX_FREQ_COEFFS; + fract* noiseLevel_m = nrgEst_e + MAX_FREQ_COEFFS; + \endcode + + <br> +*/ +void +calculateSbrEnvelope (QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */ + HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, /*!< Handle to struct filled by the create-function */ + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */ + FIXP_DBL **analysBufferReal, /*!< Real part of subband samples to be processed */ + FIXP_DBL **analysBufferImag, /*!< Imag part of subband samples to be processed */ + const int useLP, + FIXP_DBL *degreeAlias, /*!< Estimated aliasing for each QMF channel */ + const UINT flags, + const int frameErrorFlag + ) +{ + int c, i, j, envNoise = 0; + UCHAR* borders = hFrameData->frameInfo.borders; + + FIXP_SGL *noiseLevels = hFrameData->sbrNoiseFloorLevel; + HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData; + + int lowSubband = hFreq->lowSubband; + int highSubband = hFreq->highSubband; + int noSubbands = highSubband - lowSubband; + + int noNoiseBands = hFreq->nNfb; + int no_cols = hHeaderData->numberTimeSlots * hHeaderData->timeStep; + UCHAR first_start = borders[0] * hHeaderData->timeStep; + + SCHAR sineMapped[MAX_FREQ_COEFFS]; + SCHAR ov_adj_e = SCALE2EXP(sbrScaleFactor->ov_hb_scale); + SCHAR adj_e = 0; + SCHAR output_e; + SCHAR final_e = 0; + + SCHAR maxGainLimit_e = (frameErrorFlag) ? MAX_GAIN_CONCEAL_EXP : MAX_GAIN_EXP; + + int useAliasReduction[64]; + UCHAR smooth_length = 0; + + FIXP_SGL * pIenv = hFrameData->iEnvelope; + + /* + Extract sine flags for all QMF bands + */ + mapSineFlags(hFreq->freqBandTable[1], + hFreq->nSfb[1], + hFrameData->addHarmonics, + h_sbr_cal_env->harmFlagsPrev, + hFrameData->frameInfo.tranEnv, + sineMapped); + + + /* + Scan for maximum in bufferd noise levels. + This is needed in case that we had strong noise in the previous frame + which is smoothed into the current frame. + The resulting exponent is used as start value for the maximum search + in reference energies + */ + if (!useLP) + adj_e = h_sbr_cal_env->filtBufferNoise_e - getScalefactor(h_sbr_cal_env->filtBufferNoise, noSubbands); + + /* + Scan for maximum reference energy to be able + to select appropriate values for adj_e and final_e. + */ + + for (i = 0; i < hFrameData->frameInfo.nEnvelopes; i++) { + INT maxSfbNrg_e = -FRACT_BITS+NRG_EXP_OFFSET; /* start value for maximum search */ + + /* Fetch frequency resolution for current envelope: */ + for (j=hFreq->nSfb[hFrameData->frameInfo.freqRes[i]]; j!=0; j--) { + maxSfbNrg_e = fixMax(maxSfbNrg_e,(INT)((LONG)(*pIenv++) & MASK_E)); + } + maxSfbNrg_e -= NRG_EXP_OFFSET; + + /* Energy -> magnitude (sqrt halfens exponent) */ + maxSfbNrg_e = (maxSfbNrg_e+1) >> 1; /* +1 to go safe (round to next higher int) */ + + /* Some safety margin is needed for 2 reasons: + - The signal energy is not equally spread over all subband samples in + a specific sfb of an envelope (Nrg could be too high by a factor of + envWidth * sfbWidth) + - Smoothing can smear high gains of the previous envelope into the current + */ + maxSfbNrg_e += 6; + + if (borders[i] < hHeaderData->numberTimeSlots) + /* This envelope affects timeslots that belong to the output frame */ + adj_e = (maxSfbNrg_e > adj_e) ? maxSfbNrg_e : adj_e; + + if (borders[i+1] > hHeaderData->numberTimeSlots) + /* This envelope affects timeslots after the output frame */ + final_e = (maxSfbNrg_e > final_e) ? maxSfbNrg_e : final_e; + + } + + /* + Calculate adjustment factors and apply them for every envelope. + */ + pIenv = hFrameData->iEnvelope; + + for (i = 0; i < hFrameData->frameInfo.nEnvelopes; i++) { + + int k, noNoiseFlag; + SCHAR noise_e, input_e = SCALE2EXP(sbrScaleFactor->hb_scale); + C_ALLOC_SCRATCH_START(pNrgs, ENV_CALC_NRGS, 1); + + /* + Helper variables. + */ + UCHAR start_pos = hHeaderData->timeStep * borders[i]; /* Start-position in time (subband sample) for current envelope. */ + UCHAR stop_pos = hHeaderData->timeStep * borders[i+1]; /* Stop-position in time (subband sample) for current envelope. */ + UCHAR freq_res = hFrameData->frameInfo.freqRes[i]; /* Frequency resolution for current envelope. */ + + + /* Always do fully initialize the temporary energy table. This prevents negative energies and extreme gain factors in + cases where the number of limiter bands exceeds the number of subbands. The latter can be caused by undetected bit + errors and is tested by some streams from the certification set. */ + FDKmemclear(pNrgs, sizeof(ENV_CALC_NRGS)); + + /* If the start-pos of the current envelope equals the stop pos of the current + noise envelope, increase the pointer (i.e. choose the next noise-floor).*/ + if (borders[i] == hFrameData->frameInfo.bordersNoise[envNoise+1]){ + noiseLevels += noNoiseBands; /* The noise floor data is stored in a row [noiseFloor1 noiseFloor2...].*/ + envNoise++; + } + + if(i==hFrameData->frameInfo.tranEnv || i==h_sbr_cal_env->prevTranEnv) /* attack */ + { + noNoiseFlag = 1; + if (!useLP) + smooth_length = 0; /* No smoothing on attacks! */ + } + else { + noNoiseFlag = 0; + if (!useLP) + smooth_length = (1 - hHeaderData->bs_data.smoothingLength) << 2; /* can become either 0 or 4 */ + } + + + /* + Energy estimation in transposed highband. + */ + if (hHeaderData->bs_data.interpolFreq) + calcNrgPerSubband(analysBufferReal, + (useLP) ? NULL : analysBufferImag, + lowSubband, highSubband, + start_pos, stop_pos, + input_e, + pNrgs->nrgEst, + pNrgs->nrgEst_e); + else + calcNrgPerSfb(analysBufferReal, + (useLP) ? NULL : analysBufferImag, + hFreq->nSfb[freq_res], + hFreq->freqBandTable[freq_res], + start_pos, stop_pos, + input_e, + pNrgs->nrgEst, + pNrgs->nrgEst_e); + + /* + Calculate subband gains + */ + { + UCHAR * table = hFreq->freqBandTable[freq_res]; + UCHAR * pUiNoise = &hFreq->freqBandTableNoise[1]; /*! Upper limit of the current noise floor band. */ + + FIXP_SGL * pNoiseLevels = noiseLevels; + + FIXP_DBL tmpNoise = FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M)); + SCHAR tmpNoise_e = (UCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET; + + int cc = 0; + c = 0; + for (j = 0; j < hFreq->nSfb[freq_res]; j++) { + + FIXP_DBL refNrg = FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pIenv) & MASK_M)); + SCHAR refNrg_e = (SCHAR)((LONG)(*pIenv) & MASK_E) - NRG_EXP_OFFSET; + + UCHAR sinePresentFlag = 0; + int li = table[j]; + int ui = table[j+1]; + + for (k=li; k<ui; k++) { + sinePresentFlag |= (i >= sineMapped[cc]); + cc++; + } + + for (k=li; k<ui; k++) { + if (k >= *pUiNoise) { + tmpNoise = FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M)); + tmpNoise_e = (SCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET; + + pUiNoise++; + } + + FDK_ASSERT(k >= lowSubband); + + if (useLP) + useAliasReduction[k-lowSubband] = !sinePresentFlag; + + pNrgs->nrgSine[c] = FL2FXCONST_DBL(0.0f); + pNrgs->nrgSine_e[c] = 0; + + calcSubbandGain(refNrg, refNrg_e, pNrgs, c, + tmpNoise, tmpNoise_e, + sinePresentFlag, i >= sineMapped[c], + noNoiseFlag); + + pNrgs->nrgRef[c] = refNrg; + pNrgs->nrgRef_e[c] = refNrg_e; + + c++; + } + pIenv++; + } + } + + /* + Noise limiting + */ + + for (c = 0; c < hFreq->noLimiterBands; c++) { + + FIXP_DBL sumRef, boostGain, maxGain; + FIXP_DBL accu = FL2FXCONST_DBL(0.0f); + SCHAR sumRef_e, boostGain_e, maxGain_e, accu_e = 0; + + calcAvgGain(pNrgs, + hFreq->limiterBandTable[c], hFreq->limiterBandTable[c+1], + &sumRef, &sumRef_e, + &maxGain, &maxGain_e); + + /* Multiply maxGain with limiterGain: */ + maxGain = fMult(maxGain, FDK_sbrDecoder_sbr_limGains_m[hHeaderData->bs_data.limiterGains]); + maxGain_e += FDK_sbrDecoder_sbr_limGains_e[hHeaderData->bs_data.limiterGains]; + + /* Scale mantissa of MaxGain into range between 0.5 and 1: */ + if (maxGain == FL2FXCONST_DBL(0.0f)) + maxGain_e = -FRACT_BITS; + else { + SCHAR charTemp = CountLeadingBits(maxGain); + maxGain_e -= charTemp; + maxGain <<= (int)charTemp; + } + + if (maxGain_e >= maxGainLimit_e) { /* upper limit (e.g. 96 dB) */ + maxGain = FL2FXCONST_DBL(0.5f); + maxGain_e = maxGainLimit_e; + } + + + /* Every subband gain is compared to the scaled "average gain" + and limited if necessary: */ + for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c+1]; k++) { + if ( (pNrgs->nrgGain_e[k] > maxGain_e) || (pNrgs->nrgGain_e[k] == maxGain_e && pNrgs->nrgGain[k]>maxGain) ) { + + FIXP_DBL noiseAmp; + SCHAR noiseAmp_e; + + FDK_divide_MantExp(maxGain, maxGain_e, pNrgs->nrgGain[k], pNrgs->nrgGain_e[k], &noiseAmp, &noiseAmp_e); + pNrgs->noiseLevel[k] = fMult(pNrgs->noiseLevel[k],noiseAmp); + pNrgs->noiseLevel_e[k] += noiseAmp_e; + pNrgs->nrgGain[k] = maxGain; + pNrgs->nrgGain_e[k] = maxGain_e; + } + } + + /* -- Boost gain + Calculate and apply boost factor for each limiter band: + 1. Check how much energy would be present when using the limited gain + 2. Calculate boost factor by comparison with reference energy + 3. Apply boost factor to compensate for the energy loss due to limiting + */ + for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1]; k++) { + + /* 1.a Add energy of adjusted signal (using preliminary gain) */ + FIXP_DBL tmp = fMult(pNrgs->nrgGain[k],pNrgs->nrgEst[k]); + SCHAR tmp_e = pNrgs->nrgGain_e[k] + pNrgs->nrgEst_e[k]; + FDK_add_MantExp(tmp, tmp_e, accu, accu_e, &accu, &accu_e); + + /* 1.b Add sine energy (if present) */ + if(pNrgs->nrgSine[k] != FL2FXCONST_DBL(0.0f)) { + FDK_add_MantExp(pNrgs->nrgSine[k], pNrgs->nrgSine_e[k], accu, accu_e, &accu, &accu_e); + } + else { + /* 1.c Add noise energy (if present) */ + if(noNoiseFlag == 0) { + FDK_add_MantExp(pNrgs->noiseLevel[k], pNrgs->noiseLevel_e[k], accu, accu_e, &accu, &accu_e); + } + } + } + + /* 2.a Calculate ratio of wanted energy and accumulated energy */ + if (accu == (FIXP_DBL)0) { /* If divisor is 0, limit quotient to +4 dB */ + boostGain = FL2FXCONST_DBL(0.6279716f); + boostGain_e = 2; + } else { + INT div_e; + boostGain = fDivNorm(sumRef, accu, &div_e); + boostGain_e = sumRef_e - accu_e + div_e; + } + + + /* 2.b Result too high? --> Limit the boost factor to +4 dB */ + if((boostGain_e > 3) || + (boostGain_e == 2 && boostGain > FL2FXCONST_DBL(0.6279716f)) || + (boostGain_e == 3 && boostGain > FL2FXCONST_DBL(0.3139858f)) ) + { + boostGain = FL2FXCONST_DBL(0.6279716f); + boostGain_e = 2; + } + /* 3. Multiply all signal components with the boost factor */ + for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1]; k++) { + pNrgs->nrgGain[k] = fMultDiv2(pNrgs->nrgGain[k],boostGain); + pNrgs->nrgGain_e[k] = pNrgs->nrgGain_e[k] + boostGain_e + 1; + + pNrgs->nrgSine[k] = fMultDiv2(pNrgs->nrgSine[k],boostGain); + pNrgs->nrgSine_e[k] = pNrgs->nrgSine_e[k] + boostGain_e + 1; + + pNrgs->noiseLevel[k] = fMultDiv2(pNrgs->noiseLevel[k],boostGain); + pNrgs->noiseLevel_e[k] = pNrgs->noiseLevel_e[k] + boostGain_e + 1; + } + } + /* End of noise limiting */ + + if (useLP) + aliasingReduction(degreeAlias+lowSubband, + pNrgs, + useAliasReduction, + noSubbands); + + /* For the timeslots within the range for the output frame, + use the same scale for the noise levels. + Drawback: If the envelope exceeds the frame border, the noise levels + will have to be rescaled later to fit final_e of + the gain-values. + */ + noise_e = (start_pos < no_cols) ? adj_e : final_e; + + /* + Convert energies to amplitude levels + */ + for (k=0; k<noSubbands; k++) { + FDK_sqrt_MantExp(&pNrgs->nrgSine[k], &pNrgs->nrgSine_e[k], &noise_e); + FDK_sqrt_MantExp(&pNrgs->nrgGain[k], &pNrgs->nrgGain_e[k], &pNrgs->nrgGain_e[k]); + FDK_sqrt_MantExp(&pNrgs->noiseLevel[k], &pNrgs->noiseLevel_e[k], &noise_e); + } + + + + /* + Apply calculated gains and adaptive noise + */ + + /* assembleHfSignals() */ + { + int scale_change, sc_change; + FIXP_SGL smooth_ratio; + int filtBufferNoiseShift=0; + + /* Initialize smoothing buffers with the first valid values */ + if (h_sbr_cal_env->startUp) + { + if (!useLP) { + h_sbr_cal_env->filtBufferNoise_e = noise_e; + + FDKmemcpy(h_sbr_cal_env->filtBuffer_e, pNrgs->nrgGain_e, noSubbands*sizeof(SCHAR)); + FDKmemcpy(h_sbr_cal_env->filtBufferNoise, pNrgs->noiseLevel, noSubbands*sizeof(FIXP_DBL)); + FDKmemcpy(h_sbr_cal_env->filtBuffer, pNrgs->nrgGain, noSubbands*sizeof(FIXP_DBL)); + + } + h_sbr_cal_env->startUp = 0; + } + + if (!useLP) { + + equalizeFiltBufferExp(h_sbr_cal_env->filtBuffer, /* buffered */ + h_sbr_cal_env->filtBuffer_e, /* buffered */ + pNrgs->nrgGain, /* current */ + pNrgs->nrgGain_e, /* current */ + noSubbands); + + /* Adapt exponent of buffered noise levels to the current exponent + so they can easily be smoothed */ + if((h_sbr_cal_env->filtBufferNoise_e - noise_e)>=0) { + int shift = fixMin(DFRACT_BITS-1,(int)(h_sbr_cal_env->filtBufferNoise_e - noise_e)); + for (k=0; k<noSubbands; k++) + h_sbr_cal_env->filtBufferNoise[k] <<= shift; + } + else { + int shift = fixMin(DFRACT_BITS-1,-(int)(h_sbr_cal_env->filtBufferNoise_e - noise_e)); + for (k=0; k<noSubbands; k++) + h_sbr_cal_env->filtBufferNoise[k] >>= shift; + } + + h_sbr_cal_env->filtBufferNoise_e = noise_e; + } + + /* find best scaling! */ + scale_change = -(DFRACT_BITS-1); + for(k=0;k<noSubbands;k++) { + scale_change = fixMax(scale_change,(int)pNrgs->nrgGain_e[k]); + } + sc_change = (start_pos<no_cols)? adj_e - input_e : final_e - input_e; + + if ((scale_change-sc_change+1)<0) + scale_change-=(scale_change-sc_change+1); + + scale_change = (scale_change-sc_change)+1; + + for(k=0;k<noSubbands;k++) { + int sc = scale_change-pNrgs->nrgGain_e[k] + (sc_change-1); + pNrgs->nrgGain[k] >>= sc; + pNrgs->nrgGain_e[k] += sc; + } + + if (!useLP) { + for(k=0;k<noSubbands;k++) { + int sc = scale_change-h_sbr_cal_env->filtBuffer_e[k] + (sc_change-1); + h_sbr_cal_env->filtBuffer[k] >>= sc; + } + } + + for (j = start_pos; j < stop_pos; j++) + { + /* This timeslot is located within the first part of the processing buffer + and will be fed into the QMF-synthesis for the current frame. + adj_e - input_e + This timeslot will not yet be fed into the QMF so we do not care + about the adj_e. + sc_change = final_e - input_e + */ + if ( (j==no_cols) && (start_pos<no_cols) ) + { + int shift = (int) (noise_e - final_e); + if (!useLP) + filtBufferNoiseShift = shift; /* shifting of h_sbr_cal_env->filtBufferNoise[k] will be applied in function adjustTimeSlotHQ() */ + if (shift>=0) { + shift = fixMin(DFRACT_BITS-1,shift); + for (k=0; k<noSubbands; k++) { + pNrgs->nrgSine[k] <<= shift; + pNrgs->noiseLevel[k] <<= shift; + /* + if (!useLP) + h_sbr_cal_env->filtBufferNoise[k] <<= shift; + */ + } + } + else { + shift = fixMin(DFRACT_BITS-1,-shift); + for (k=0; k<noSubbands; k++) { + pNrgs->nrgSine[k] >>= shift; + pNrgs->noiseLevel[k] >>= shift; + /* + if (!useLP) + h_sbr_cal_env->filtBufferNoise[k] >>= shift; + */ + } + } + + /* update noise scaling */ + noise_e = final_e; + if (!useLP) + h_sbr_cal_env->filtBufferNoise_e = noise_e; /* scaling value unused! */ + + /* update gain buffer*/ + sc_change -= (final_e - input_e); + + if (sc_change<0) { + for(k=0;k<noSubbands;k++) { + pNrgs->nrgGain[k] >>= -sc_change; + pNrgs->nrgGain_e[k] += -sc_change; + } + if (!useLP) { + for(k=0;k<noSubbands;k++) { + h_sbr_cal_env->filtBuffer[k] >>= -sc_change; + } + } + } else { + scale_change+=sc_change; + } + + } // if + + if (!useLP) { + + /* Prevent the smoothing filter from running on constant levels */ + if (j-start_pos < smooth_length) + smooth_ratio = FDK_sbrDecoder_sbr_smoothFilter[j-start_pos]; + + else + smooth_ratio = FL2FXCONST_SGL(0.0f); + + adjustTimeSlotHQ(&analysBufferReal[j][lowSubband], + &analysBufferImag[j][lowSubband], + h_sbr_cal_env, + pNrgs, + lowSubband, + noSubbands, + scale_change, + smooth_ratio, + noNoiseFlag, + filtBufferNoiseShift); + } + else + { + adjustTimeSlotLC(&analysBufferReal[j][lowSubband], + pNrgs, + &h_sbr_cal_env->harmIndex, + lowSubband, + noSubbands, + scale_change, + noNoiseFlag, + &h_sbr_cal_env->phaseIndex, + (flags & SBRDEC_ELD_GRID)); + } + } // for + + if (!useLP) { + /* Update time-smoothing-buffers for gains and noise levels + The gains and the noise values of the current envelope are copied into the buffer. + This has to be done at the end of each envelope as the values are required for + a smooth transition to the next envelope. */ + FDKmemcpy(h_sbr_cal_env->filtBuffer, pNrgs->nrgGain, noSubbands*sizeof(FIXP_DBL)); + FDKmemcpy(h_sbr_cal_env->filtBuffer_e, pNrgs->nrgGain_e, noSubbands*sizeof(SCHAR)); + FDKmemcpy(h_sbr_cal_env->filtBufferNoise, pNrgs->noiseLevel, noSubbands*sizeof(FIXP_DBL)); + } + + } + C_ALLOC_SCRATCH_END(pNrgs, ENV_CALC_NRGS, 1); + } + + /* Rescale output samples */ + { + FIXP_DBL maxVal; + int ov_reserve, reserve; + + /* Determine headroom in old adjusted samples */ + maxVal = maxSubbandSample( analysBufferReal, + (useLP) ? NULL : analysBufferImag, + lowSubband, + highSubband, + 0, + first_start); + + ov_reserve = fNorm(maxVal); + + /* Determine headroom in new adjusted samples */ + maxVal = maxSubbandSample( analysBufferReal, + (useLP) ? NULL : analysBufferImag, + lowSubband, + highSubband, + first_start, + no_cols); + + reserve = fNorm(maxVal); + + /* Determine common output exponent */ + if (ov_adj_e - ov_reserve > adj_e - reserve ) /* set output_e to the maximum */ + output_e = ov_adj_e - ov_reserve; + else + output_e = adj_e - reserve; + + /* Rescale old samples */ + rescaleSubbandSamples( analysBufferReal, + (useLP) ? NULL : analysBufferImag, + lowSubband, highSubband, + 0, first_start, + ov_adj_e - output_e); + + /* Rescale new samples */ + rescaleSubbandSamples( analysBufferReal, + (useLP) ? NULL : analysBufferImag, + lowSubband, highSubband, + first_start, no_cols, + adj_e - output_e); + } + + /* Update hb_scale */ + sbrScaleFactor->hb_scale = EXP2SCALE(output_e); + + /* Save the current final exponent for the next frame: */ + sbrScaleFactor->ov_hb_scale = EXP2SCALE(final_e); + + + /* We need to remeber to the next frame that the transient + will occur in the first envelope (if tranEnv == nEnvelopes). */ + if(hFrameData->frameInfo.tranEnv == hFrameData->frameInfo.nEnvelopes) + h_sbr_cal_env->prevTranEnv = 0; + else + h_sbr_cal_env->prevTranEnv = -1; + +} + + +/*! + \brief Create envelope instance + + Must be called once for each channel before calculateSbrEnvelope() can be used. + + \return errorCode, 0 if successful +*/ +SBR_ERROR +createSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hs, /*!< pointer to envelope instance */ + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< static SBR control data, initialized with defaults */ + const int chan, /*!< Channel for which to assign buffers */ + const UINT flags) +{ + SBR_ERROR err = SBRDEC_OK; + int i; + + /* Clear previous missing harmonics flags */ + for (i=0; i<(MAX_FREQ_COEFFS+15)>>4; i++) { + hs->harmFlagsPrev[i] = 0; + } + hs->harmIndex = 0; + + /* + Setup pointers for time smoothing. + The buffer itself will be initialized later triggered by the startUp-flag. + */ + hs->prevTranEnv = -1; + + + /* initialization */ + resetSbrEnvelopeCalc(hs); + + if (chan==0) { /* do this only once */ + err = resetFreqBandTables(hHeaderData, flags); + } + + return err; +} + +/*! + \brief Create envelope instance + + Must be called once for each channel before calculateSbrEnvelope() can be used. + + \return errorCode, 0 if successful +*/ +int +deleteSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hs) +{ + return 0; +} + + +/*! + \brief Reset envelope instance + + This function must be called for each channel on a change of configuration. + Note that resetFreqBandTables should also be called in this case. + + \return errorCode, 0 if successful +*/ +void +resetSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hCalEnv) /*!< pointer to envelope instance */ +{ + hCalEnv->phaseIndex = 0; + + /* Noise exponent needs to be reset because the output exponent for the next frame depends on it */ + hCalEnv->filtBufferNoise_e = 0; + + hCalEnv->startUp = 1; +} + + +/*! + \brief Equalize exponents of the buffered gain values and the new ones + + After equalization of exponents, the FIR-filter addition for smoothing + can be performed. + This function is called once for each envelope before adjusting. +*/ +/*static*/ void equalizeFiltBufferExp(FIXP_DBL *filtBuffer, /*!< bufferd gains */ + SCHAR *filtBuffer_e, /*!< exponents of bufferd gains */ + FIXP_DBL *nrgGain, /*!< gains for current envelope */ + SCHAR *nrgGain_e, /*!< exponents of gains for current envelope */ + int subbands) /*!< Number of QMF subbands */ +{ + int band; + int diff; + + for (band=0; band<subbands; band++){ + diff = (int) (nrgGain_e[band] - filtBuffer_e[band]); + if (diff>0) { + filtBuffer[band] >>= diff; /* Compensate for the scale change by shifting the mantissa. */ + filtBuffer_e[band] += diff; /* New gain is bigger, use its exponent */ + } + else if (diff<0) { + /* The buffered gains seem to be larger, but maybe there + are some unused bits left in the mantissa */ + + int reserve = CntLeadingZeros(fixp_abs(filtBuffer[band]))-1; + + if ((-diff) <= reserve) { + /* There is enough space in the buffered mantissa so + that we can take the new exponent as common. + */ + filtBuffer[band] <<= (-diff); + filtBuffer_e[band] += diff; /* becomes equal to *ptrNewExp */ + } + else { + filtBuffer[band] <<= reserve; /* Shift the mantissa as far as possible: */ + filtBuffer_e[band] -= reserve; /* Compensate in the exponent: */ + + /* For the remaining difference, change the new gain value */ + diff = fixMin(-(reserve + diff),DFRACT_BITS-1); + nrgGain[band] >>= diff; + nrgGain_e[band] += diff; + } + } + } +} + +/*! + \brief Shift left the mantissas of all subband samples + in the giventime and frequency range by the specified number of bits. + + This function is used to rescale the audio data in the overlap buffer + which has already been envelope adjusted with the last frame. +*/ +void rescaleSubbandSamples(FIXP_DBL ** re, /*!< Real part of input and output subband samples */ + FIXP_DBL ** im, /*!< Imaginary part of input and output subband samples */ + int lowSubband, /*!< Begin of frequency range to process */ + int highSubband, /*!< End of frequency range to process */ + int start_pos, /*!< Begin of time rage (QMF-timeslot) */ + int next_pos, /*!< End of time rage (QMF-timeslot) */ + int shift) /*!< number of bits to shift */ +{ + int width = highSubband-lowSubband; + + if ( (width > 0) && (shift!=0) ) { + if (im!=NULL) { + for (int l=start_pos; l<next_pos; l++) { + scaleValues(&re[l][lowSubband], width, shift); + scaleValues(&im[l][lowSubband], width, shift); + } + } else + { + for (int l=start_pos; l<next_pos; l++) { + scaleValues(&re[l][lowSubband], width, shift); + } + } + } +} + + +/*! + \brief Determine headroom for shifting + + Determine by how much the spectrum can be shifted left + for better accuracy in later processing. + + \return Number of free bits in the biggest spectral value +*/ + +FIXP_DBL maxSubbandSample( FIXP_DBL ** re, /*!< Real part of input and output subband samples */ + FIXP_DBL ** im, /*!< Real part of input and output subband samples */ + int lowSubband, /*!< Begin of frequency range to process */ + int highSubband, /*!< Number of QMF bands to process */ + int start_pos, /*!< Begin of time rage (QMF-timeslot) */ + int next_pos /*!< End of time rage (QMF-timeslot) */ + ) +{ + FIXP_DBL maxVal = FL2FX_DBL(0.0f); + unsigned int width = highSubband - lowSubband; + + FDK_ASSERT(width <= (64)); + + if ( width > 0 ) { + if (im!=NULL) + { + for (int l=start_pos; l<next_pos; l++) + { +#ifdef FUNCTION_FDK_get_maxval + maxVal = FDK_get_maxval(maxVal, &re[l][lowSubband], &im[l][lowSubband], width); +#else + int k=width; + FIXP_DBL *reTmp = &re[l][lowSubband]; + FIXP_DBL *imTmp = &im[l][lowSubband]; + do{ + FIXP_DBL tmp1 = *(reTmp++); + FIXP_DBL tmp2 = *(imTmp++); + maxVal |= (FIXP_DBL)((LONG)(tmp1)^((LONG)tmp1>>(DFRACT_BITS-1))); + maxVal |= (FIXP_DBL)((LONG)(tmp2)^((LONG)tmp2>>(DFRACT_BITS-1))); + } while(--k!=0); +#endif + } + } else + { + for (int l=start_pos; l<next_pos; l++) { + int k=width; + FIXP_DBL *reTmp = &re[l][lowSubband]; + do{ + FIXP_DBL tmp = *(reTmp++); + maxVal |= (FIXP_DBL)((LONG)(tmp)^((LONG)tmp>>(DFRACT_BITS-1))); + }while(--k!=0); + } + } + } + + return(maxVal); +} + +#define SHIFT_BEFORE_SQUARE (3) /* (7/2) */ +/*!< + If the accumulator does not provide enough overflow bits or + does not provide a high dynamic range, the below energy calculation + requires an additional shift operation for each sample. + On the other hand, doing the shift allows using a single-precision + multiplication for the square (at least 16bit x 16bit). + For even values of OVRFLW_BITS (0, 2, 4, 6), saturated arithmetic + is required for the energy accumulation. + Theoretically, the sample-squares can sum up to a value of 76, + requiring 7 overflow bits. However since such situations are *very* + rare, accu can be limited to 64. + In case native saturated arithmetic is not available, overflows + can be prevented by replacing the above #define by + #define SHIFT_BEFORE_SQUARE ((8 - OVRFLW_BITS) / 2) + which will result in slightly reduced accuracy. +*/ + +/*! + \brief Estimates the mean energy of each filter-bank channel for the + duration of the current envelope + + This function is used when interpolFreq is true. +*/ +/*static*/ void calcNrgPerSubband(FIXP_DBL **analysBufferReal, /*!< Real part of subband samples */ + FIXP_DBL **analysBufferImag, /*!< Imaginary part of subband samples */ + int lowSubband, /*!< Begin of the SBR frequency range */ + int highSubband, /*!< High end of the SBR frequency range */ + int start_pos, /*!< First QMF-slot of current envelope */ + int next_pos, /*!< Last QMF-slot of current envelope + 1 */ + SCHAR frameExp, /*!< Common exponent for all input samples */ + FIXP_DBL *nrgEst, /*!< resulting Energy (0..1) */ + SCHAR *nrgEst_e ) /*!< Exponent of resulting Energy */ +{ + FIXP_SGL invWidth; + SCHAR preShift; + SCHAR shift; + FIXP_DBL sum; + int k,l; + + /* Divide by width of envelope later: */ + invWidth = FX_DBL2FX_SGL(GetInvInt(next_pos - start_pos)); + /* The common exponent needs to be doubled because all mantissas are squared: */ + frameExp = frameExp << 1; + + for (k=lowSubband; k<highSubband; k++) { + FIXP_DBL bufferReal[(((1024)/(32))+(6))]; + FIXP_DBL bufferImag[(((1024)/(32))+(6))]; + FIXP_DBL maxVal = FL2FX_DBL(0.0f); + + if (analysBufferImag!=NULL) + { + for (l=start_pos;l<next_pos;l++) + { + bufferImag[l] = analysBufferImag[l][k]; + maxVal |= (FIXP_DBL)((LONG)(bufferImag[l])^((LONG)bufferImag[l]>>(DFRACT_BITS-1))); + bufferReal[l] = analysBufferReal[l][k]; + maxVal |= (FIXP_DBL)((LONG)(bufferReal[l])^((LONG)bufferReal[l]>>(DFRACT_BITS-1))); + } + } + else + { + for (l=start_pos;l<next_pos;l++) + { + bufferReal[l] = analysBufferReal[l][k]; + maxVal |= (FIXP_DBL)((LONG)(bufferReal[l])^((LONG)bufferReal[l]>>(DFRACT_BITS-1))); + } + } + + if (maxVal!=FL2FXCONST_DBL(0.f)) { + + + /* If the accu does not provide enough overflow bits, we cannot + shift the samples up to the limit. + Instead, keep up to 3 free bits in each sample, i.e. up to + 6 bits after calculation of square. + Please note the comment on saturated arithmetic above! + */ + FIXP_DBL accu = FL2FXCONST_DBL(0.0f); + preShift = CntLeadingZeros(maxVal)-1; + preShift -= SHIFT_BEFORE_SQUARE; + + if (preShift>=0) { + if (analysBufferImag!=NULL) { + for (l=start_pos; l<next_pos; l++) { + FIXP_DBL temp1 = bufferReal[l] << (int)preShift; + FIXP_DBL temp2 = bufferImag[l] << (int)preShift; + accu = fPow2AddDiv2(accu, temp1); + accu = fPow2AddDiv2(accu, temp2); + } + } else + { + for (l=start_pos; l<next_pos; l++) { + FIXP_DBL temp = bufferReal[l] << (int)preShift; + accu = fPow2AddDiv2(accu, temp); + } + } + } + else { /* if negative shift value */ + int negpreShift = -preShift; + if (analysBufferImag!=NULL) { + for (l=start_pos; l<next_pos; l++) { + FIXP_DBL temp1 = bufferReal[l] >> (int)negpreShift; + FIXP_DBL temp2 = bufferImag[l] >> (int)negpreShift; + accu = fPow2AddDiv2(accu, temp1); + accu = fPow2AddDiv2(accu, temp2); + } + } else + { + for (l=start_pos; l<next_pos; l++) { + FIXP_DBL temp = bufferReal[l] >> (int)negpreShift; + accu = fPow2AddDiv2(accu, temp); + } + } + } + accu <<= 1; + + /* Convert double precision to Mantissa/Exponent: */ + shift = fNorm(accu); + sum = accu << (int)shift; + + /* Divide by width of envelope and apply frame scale: */ + *nrgEst++ = fMult(sum, invWidth); + shift += 2 * preShift; + if (analysBufferImag!=NULL) + *nrgEst_e++ = frameExp - shift; + else + *nrgEst_e++ = frameExp - shift + 1; /* +1 due to missing imag. part */ + } /* maxVal!=0 */ + else { + + /* Prevent a zero-mantissa-number from being misinterpreted + due to its exponent. */ + *nrgEst++ = FL2FXCONST_DBL(0.0f); + *nrgEst_e++ = 0; + } + } +} + +/*! + \brief Estimates the mean energy of each Scale factor band for the + duration of the current envelope. + + This function is used when interpolFreq is false. +*/ +/*static*/ void calcNrgPerSfb(FIXP_DBL **analysBufferReal, /*!< Real part of subband samples */ + FIXP_DBL **analysBufferImag, /*!< Imaginary part of subband samples */ + int nSfb, /*!< Number of scale factor bands */ + UCHAR *freqBandTable, /*!< First Subband for each Sfb */ + int start_pos, /*!< First QMF-slot of current envelope */ + int next_pos, /*!< Last QMF-slot of current envelope + 1 */ + SCHAR input_e, /*!< Common exponent for all input samples */ + FIXP_DBL *nrgEst, /*!< resulting Energy (0..1) */ + SCHAR *nrgEst_e ) /*!< Exponent of resulting Energy */ +{ + FIXP_SGL invWidth; + FIXP_DBL temp; + SCHAR preShift; + SCHAR shift, sum_e; + FIXP_DBL sum; + + int j,k,l,li,ui; + FIXP_DBL sumAll, sumLine; /* Single precision would be sufficient, + but overflow bits are required for accumulation */ + + /* Divide by width of envelope later: */ + invWidth = FX_DBL2FX_SGL(GetInvInt(next_pos - start_pos)); + /* The common exponent needs to be doubled because all mantissas are squared: */ + input_e = input_e << 1; + + for(j=0; j<nSfb; j++) { + li = freqBandTable[j]; + ui = freqBandTable[j+1]; + + FIXP_DBL maxVal = maxSubbandSample( analysBufferReal, + analysBufferImag, + li, + ui, + start_pos, + next_pos ); + + if (maxVal!=FL2FXCONST_DBL(0.f)) { + + preShift = CntLeadingZeros(maxVal)-1; + + /* If the accu does not provide enough overflow bits, we cannot + shift the samples up to the limit. + Instead, keep up to 3 free bits in each sample, i.e. up to + 6 bits after calculation of square. + Please note the comment on saturated arithmetic above! + */ + preShift -= SHIFT_BEFORE_SQUARE; + + sumAll = FL2FXCONST_DBL(0.0f); + + + for (k=li; k<ui; k++) { + + sumLine = FL2FXCONST_DBL(0.0f); + + if (analysBufferImag!=NULL) { + if (preShift>=0) { + for (l=start_pos; l<next_pos; l++) { + temp = analysBufferReal[l][k] << (int)preShift; + sumLine += fPow2Div2(temp); + temp = analysBufferImag[l][k] << (int)preShift; + sumLine += fPow2Div2(temp); + + } + } else { + for (l=start_pos; l<next_pos; l++) { + temp = analysBufferReal[l][k] >> -(int)preShift; + sumLine += fPow2Div2(temp); + temp = analysBufferImag[l][k] >> -(int)preShift; + sumLine += fPow2Div2(temp); + } + } + } else + { + if (preShift>=0) { + for (l=start_pos; l<next_pos; l++) { + temp = analysBufferReal[l][k] << (int)preShift; + sumLine += fPow2Div2(temp); + } + } else { + for (l=start_pos; l<next_pos; l++) { + temp = analysBufferReal[l][k] >> -(int)preShift; + sumLine += fPow2Div2(temp); + } + } + } + + /* The number of QMF-channels per SBR bands may be up to 15. + Shift right to avoid overflows in sum over all channels. */ + sumLine = sumLine >> (4-1); + sumAll += sumLine; + } + + /* Convert double precision to Mantissa/Exponent: */ + shift = fNorm(sumAll); + sum = sumAll << (int)shift; + + /* Divide by width of envelope: */ + sum = fMult(sum,invWidth); + + /* Divide by width of Sfb: */ + sum = fMult(sum, FX_DBL2FX_SGL(GetInvInt(ui-li))); + + /* Set all Subband energies in the Sfb to the average energy: */ + if (analysBufferImag!=NULL) + sum_e = input_e + 4 - shift; /* -4 to compensate right-shift */ + else + sum_e = input_e + 4 + 1 - shift; /* -4 to compensate right-shift; +1 due to missing imag. part */ + + sum_e -= 2 * preShift; + } /* maxVal!=0 */ + else { + + /* Prevent a zero-mantissa-number from being misinterpreted + due to its exponent. */ + sum = FL2FXCONST_DBL(0.0f); + sum_e = 0; + } + + for (k=li; k<ui; k++) + { + *nrgEst++ = sum; + *nrgEst_e++ = sum_e; + } + } +} + + +/*! + \brief Calculate gain, noise, and additional sine level for one subband. + + The resulting energy gain is given by mantissa and exponent. +*/ +/*static*/ void calcSubbandGain(FIXP_DBL nrgRef, /*!< Reference Energy according to envelope data */ + SCHAR nrgRef_e, /*!< Reference Energy according to envelope data (exponent) */ + ENV_CALC_NRGS* nrgs, + int i, + FIXP_DBL tmpNoise, /*!< Relative noise level */ + SCHAR tmpNoise_e, /*!< Relative noise level (exponent) */ + UCHAR sinePresentFlag, /*!< Indicates if sine is present on band */ + UCHAR sineMapped, /*!< Indicates if sine must be added */ + int noNoiseFlag) /*!< Flag to suppress noise addition */ +{ + FIXP_DBL nrgEst = nrgs->nrgEst[i]; /*!< Energy in transposed signal */ + SCHAR nrgEst_e = nrgs->nrgEst_e[i]; /*!< Energy in transposed signal (exponent) */ + FIXP_DBL *ptrNrgGain = &nrgs->nrgGain[i]; /*!< Resulting energy gain */ + SCHAR *ptrNrgGain_e = &nrgs->nrgGain_e[i]; /*!< Resulting energy gain (exponent) */ + FIXP_DBL *ptrNoiseLevel = &nrgs->noiseLevel[i]; /*!< Resulting absolute noise energy */ + SCHAR *ptrNoiseLevel_e = &nrgs->noiseLevel_e[i]; /*!< Resulting absolute noise energy (exponent) */ + FIXP_DBL *ptrNrgSine = &nrgs->nrgSine[i]; /*!< Additional sine energy */ + SCHAR *ptrNrgSine_e = &nrgs->nrgSine_e[i]; /*!< Additional sine energy (exponent) */ + + FIXP_DBL a, b, c; + SCHAR a_e, b_e, c_e; + + /* + This addition of 1 prevents divisions by zero in the reference code. + For very small energies in nrgEst, it prevents the gains from becoming + very high which could cause some trouble due to the smoothing. + */ + b_e = (int)(nrgEst_e - 1); + if (b_e>=0) { + nrgEst = (FL2FXCONST_DBL(0.5f) >> (INT)fixMin(b_e+1,DFRACT_BITS-1)) + (nrgEst >> 1); + nrgEst_e += 1; /* shift by 1 bit to avoid overflow */ + + } else { + nrgEst = (nrgEst >> (INT)(fixMin(-b_e+1,DFRACT_BITS-1))) + (FL2FXCONST_DBL(0.5f) >> 1); + nrgEst_e = 2; /* shift by 1 bit to avoid overflow */ + } + + /* A = NrgRef * TmpNoise */ + a = fMult(nrgRef,tmpNoise); + a_e = nrgRef_e + tmpNoise_e; + + /* B = 1 + TmpNoise */ + b_e = (int)(tmpNoise_e - 1); + if (b_e>=0) { + b = (FL2FXCONST_DBL(0.5f) >> (INT)fixMin(b_e+1,DFRACT_BITS-1)) + (tmpNoise >> 1); + b_e = tmpNoise_e + 1; /* shift by 1 bit to avoid overflow */ + } else { + b = (tmpNoise >> (INT)(fixMin(-b_e+1,DFRACT_BITS-1))) + (FL2FXCONST_DBL(0.5f) >> 1); + b_e = 2; /* shift by 1 bit to avoid overflow */ + } + + /* noiseLevel = A / B = (NrgRef * TmpNoise) / (1 + TmpNoise) */ + FDK_divide_MantExp( a, a_e, + b, b_e, + ptrNoiseLevel, ptrNoiseLevel_e); + + if (sinePresentFlag) { + + /* C = (1 + TmpNoise) * NrgEst */ + c = fMult(b,nrgEst); + c_e = b_e + nrgEst_e; + + /* gain = A / C = (NrgRef * TmpNoise) / (1 + TmpNoise) * NrgEst */ + FDK_divide_MantExp( a, a_e, + c, c_e, + ptrNrgGain, ptrNrgGain_e); + + if (sineMapped) { + + /* sineLevel = nrgRef/ (1 + TmpNoise) */ + FDK_divide_MantExp( nrgRef, nrgRef_e, + b, b_e, + ptrNrgSine, ptrNrgSine_e); + } + } + else { + if (noNoiseFlag) { + /* B = NrgEst */ + b = nrgEst; + b_e = nrgEst_e; + } + else { + /* B = NrgEst * (1 + TmpNoise) */ + b = fMult(b,nrgEst); + b_e = b_e + nrgEst_e; + } + + + /* gain = nrgRef / B */ + FDK_divide_MantExp( nrgRef, nrgRef_e, + b, b_e, + ptrNrgGain, ptrNrgGain_e); + } +} + + +/*! + \brief Calculate "average gain" for the specified subband range. + + This is rather a gain of the average magnitude than the average + of gains! + The result is used as a relative limit for all gains within the + current "limiter band" (a certain frequency range). +*/ +/*static*/ void calcAvgGain(ENV_CALC_NRGS* nrgs, + int lowSubband, /*!< Begin of the limiter band */ + int highSubband, /*!< High end of the limiter band */ + FIXP_DBL *ptrSumRef, + SCHAR *ptrSumRef_e, + FIXP_DBL *ptrAvgGain, /*!< Resulting overall gain (mantissa) */ + SCHAR *ptrAvgGain_e) /*!< Resulting overall gain (exponent) */ +{ + FIXP_DBL *nrgRef = nrgs->nrgRef; /*!< Reference Energy according to envelope data */ + SCHAR *nrgRef_e = nrgs->nrgRef_e; /*!< Reference Energy according to envelope data (exponent) */ + FIXP_DBL *nrgEst = nrgs->nrgEst; /*!< Energy in transposed signal */ + SCHAR *nrgEst_e = nrgs->nrgEst_e; /*!< Energy in transposed signal (exponent) */ + + FIXP_DBL sumRef = 1; + FIXP_DBL sumEst = 1; + SCHAR sumRef_e = -FRACT_BITS; + SCHAR sumEst_e = -FRACT_BITS; + int k; + + for (k=lowSubband; k<highSubband; k++){ + /* Add nrgRef[k] to sumRef: */ + FDK_add_MantExp( sumRef, sumRef_e, + nrgRef[k], nrgRef_e[k], + &sumRef, &sumRef_e ); + + /* Add nrgEst[k] to sumEst: */ + FDK_add_MantExp( sumEst, sumEst_e, + nrgEst[k], nrgEst_e[k], + &sumEst, &sumEst_e ); + } + + FDK_divide_MantExp(sumRef, sumRef_e, + sumEst, sumEst_e, + ptrAvgGain, ptrAvgGain_e); + + *ptrSumRef = sumRef; + *ptrSumRef_e = sumRef_e; +} + + +/*! + \brief Amplify one timeslot of the signal with the calculated gains + and add the noisefloor. +*/ + +/*static*/ void adjustTimeSlotLC(FIXP_DBL *ptrReal, /*!< Subband samples to be adjusted, real part */ + ENV_CALC_NRGS* nrgs, + UCHAR *ptrHarmIndex, /*!< Harmonic index */ + int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */ + int noSubbands, /*!< Number of QMF subbands */ + int scale_change, /*!< Number of bits to shift adjusted samples */ + int noNoiseFlag, /*!< Flag to suppress noise addition */ + int *ptrPhaseIndex, /*!< Start index to random number array */ + int fCldfb) /*!< CLDFB 80 flag */ +{ + FIXP_DBL *pGain = nrgs->nrgGain; /*!< Gains of current envelope */ + FIXP_DBL *pNoiseLevel = nrgs->noiseLevel; /*!< Noise levels of current envelope */ + FIXP_DBL *pSineLevel = nrgs->nrgSine; /*!< Sine levels */ + + int k; + int index = *ptrPhaseIndex; + UCHAR harmIndex = *ptrHarmIndex; + UCHAR freqInvFlag = (lowSubband & 1); + FIXP_DBL signalReal, sineLevel, sineLevelNext, sineLevelPrev; + int tone_count = 0; + int sineSign = 1; + + #define C1 ((FIXP_SGL)FL2FXCONST_SGL(2.f*0.00815f)) + #define C1_CLDFB ((FIXP_SGL)FL2FXCONST_SGL(2.f*0.16773f)) + + /* + First pass for k=0 pulled out of the loop: + */ + + index = (index + 1) & (SBR_NF_NO_RANDOM_VAL - 1); + + /* + The next multiplication constitutes the actual envelope adjustment + of the signal and should be carried out with full accuracy + (supplying #FRACT_BITS valid bits). + */ + signalReal = fMultDiv2(*ptrReal,*pGain++) << ((int)scale_change); + sineLevel = *pSineLevel++; + sineLevelNext = (noSubbands > 1) ? pSineLevel[0] : FL2FXCONST_DBL(0.0f); + + if (sineLevel!=FL2FXCONST_DBL(0.0f)) tone_count++; + + else if (!noNoiseFlag) + /* Add noisefloor to the amplified signal */ + signalReal += (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])<<4); + + if (fCldfb) { + + if (!(harmIndex&0x1)) { + /* harmIndex 0,2 */ + signalReal += (harmIndex&0x2) ? -sineLevel : sineLevel; + *ptrReal++ = signalReal; + } + else { + /* harmIndex 1,3 in combination with freqInvFlag */ + int shift = (int) (scale_change+1); + shift = (shift>=0) ? fixMin(DFRACT_BITS-1,shift) : fixMax(-(DFRACT_BITS-1),shift); + + FIXP_DBL tmp1 = scaleValue( fMultDiv2(C1_CLDFB, sineLevel), -shift ); + + FIXP_DBL tmp2 = fMultDiv2(C1_CLDFB, sineLevelNext); + + + /* save switch and compare operations and reduce to XOR statement */ + if ( ((harmIndex>>1)&0x1)^freqInvFlag) { + *(ptrReal-1) += tmp1; + signalReal -= tmp2; + } else { + *(ptrReal-1) -= tmp1; + signalReal += tmp2; + } + *ptrReal++ = signalReal; + freqInvFlag = !freqInvFlag; + } + + } else + { + if (!(harmIndex&0x1)) { + /* harmIndex 0,2 */ + signalReal += (harmIndex&0x2) ? -sineLevel : sineLevel; + *ptrReal++ = signalReal; + } + else { + /* harmIndex 1,3 in combination with freqInvFlag */ + int shift = (int) (scale_change+1); + shift = (shift>=0) ? fixMin(DFRACT_BITS-1,shift) : fixMax(-(DFRACT_BITS-1),shift); + + FIXP_DBL tmp1 = (shift>=0) ? ( fMultDiv2(C1, sineLevel) >> shift ) + : ( fMultDiv2(C1, sineLevel) << (-shift) ); + FIXP_DBL tmp2 = fMultDiv2(C1, sineLevelNext); + + + /* save switch and compare operations and reduce to XOR statement */ + if ( ((harmIndex>>1)&0x1)^freqInvFlag) { + *(ptrReal-1) += tmp1; + signalReal -= tmp2; + } else { + *(ptrReal-1) -= tmp1; + signalReal += tmp2; + } + *ptrReal++ = signalReal; + freqInvFlag = !freqInvFlag; + } + } + + pNoiseLevel++; + + if ( noSubbands > 2 ) { + if (!(harmIndex&0x1)) { + /* harmIndex 0,2 */ + if(!harmIndex) + { + sineSign = 0; + } + + for (k=noSubbands-2; k!=0; k--) { + FIXP_DBL sinelevel = *pSineLevel++; + index++; + if (((signalReal = (sineSign ? -sinelevel : sinelevel)) == FL2FXCONST_DBL(0.0f)) && !noNoiseFlag) + { + /* Add noisefloor to the amplified signal */ + index &= (SBR_NF_NO_RANDOM_VAL - 1); + signalReal += (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])<<4); + } + + /* The next multiplication constitutes the actual envelope adjustment of the signal. */ + signalReal += fMultDiv2(*ptrReal,*pGain++) << ((int)scale_change); + + pNoiseLevel++; + *ptrReal++ = signalReal; + } /* for ... */ + } + else { + /* harmIndex 1,3 in combination with freqInvFlag */ + if (harmIndex==1) freqInvFlag = !freqInvFlag; + + for (k=noSubbands-2; k!=0; k--) { + index++; + /* The next multiplication constitutes the actual envelope adjustment of the signal. */ + signalReal = fMultDiv2(*ptrReal,*pGain++) << ((int)scale_change); + + if (*pSineLevel++!=FL2FXCONST_DBL(0.0f)) tone_count++; + else if (!noNoiseFlag) { + /* Add noisefloor to the amplified signal */ + index &= (SBR_NF_NO_RANDOM_VAL - 1); + signalReal += (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])<<4); + } + + pNoiseLevel++; + + if (tone_count <= 16) { + FIXP_DBL addSine = fMultDiv2((pSineLevel[-2] - pSineLevel[0]), C1); + signalReal += (freqInvFlag) ? (-addSine) : (addSine); + } + + *ptrReal++ = signalReal; + freqInvFlag = !freqInvFlag; + } /* for ... */ + } + } + + if (noSubbands > -1) { + index++; + /* The next multiplication constitutes the actual envelope adjustment of the signal. */ + signalReal = fMultDiv2(*ptrReal,*pGain) << ((int)scale_change); + sineLevelPrev = fMultDiv2(pSineLevel[-1],FL2FX_SGL(0.0163f)); + sineLevel = pSineLevel[0]; + + if (pSineLevel[0]!=FL2FXCONST_DBL(0.0f)) tone_count++; + else if (!noNoiseFlag) { + /* Add noisefloor to the amplified signal */ + index &= (SBR_NF_NO_RANDOM_VAL - 1); + signalReal = signalReal + (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])<<4); + } + + if (!(harmIndex&0x1)) { + /* harmIndex 0,2 */ + *ptrReal = signalReal + ( (sineSign) ? -sineLevel : sineLevel); + } + else { + /* harmIndex 1,3 in combination with freqInvFlag */ + if(tone_count <= 16){ + if (freqInvFlag) { + *ptrReal++ = signalReal - sineLevelPrev; + if (noSubbands + lowSubband < 63) + *ptrReal = *ptrReal + fMultDiv2(C1, sineLevel); + } + else { + *ptrReal++ = signalReal + sineLevelPrev; + if (noSubbands + lowSubband < 63) + *ptrReal = *ptrReal - fMultDiv2(C1, sineLevel); + } + } + else *ptrReal = signalReal; + } + } + *ptrHarmIndex = (harmIndex + 1) & 3; + *ptrPhaseIndex = index & (SBR_NF_NO_RANDOM_VAL - 1); +} +void adjustTimeSlotHQ(FIXP_DBL *RESTRICT ptrReal, /*!< Subband samples to be adjusted, real part */ + FIXP_DBL *RESTRICT ptrImag, /*!< Subband samples to be adjusted, imag part */ + HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, + ENV_CALC_NRGS* nrgs, + int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */ + int noSubbands, /*!< Number of QMF subbands */ + int scale_change, /*!< Number of bits to shift adjusted samples */ + FIXP_SGL smooth_ratio, /*!< Impact of last envelope */ + int noNoiseFlag, /*!< Start index to random number array */ + int filtBufferNoiseShift) /*!< Shift factor of filtBufferNoise */ +{ + + FIXP_DBL *RESTRICT gain = nrgs->nrgGain; /*!< Gains of current envelope */ + FIXP_DBL *RESTRICT noiseLevel = nrgs->noiseLevel; /*!< Noise levels of current envelope */ + FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */ + + FIXP_DBL *RESTRICT filtBuffer = h_sbr_cal_env->filtBuffer; /*!< Gains of last envelope */ + FIXP_DBL *RESTRICT filtBufferNoise = h_sbr_cal_env->filtBufferNoise; /*!< Noise levels of last envelope */ + UCHAR *RESTRICT ptrHarmIndex =&h_sbr_cal_env->harmIndex; /*!< Harmonic index */ + int *RESTRICT ptrPhaseIndex =&h_sbr_cal_env->phaseIndex; /*!< Start index to random number array */ + + int k; + FIXP_DBL signalReal, signalImag; + FIXP_DBL noiseReal, noiseImag; + FIXP_DBL smoothedGain, smoothedNoise; + FIXP_SGL direct_ratio = /*FL2FXCONST_SGL(1.0f) */ (FIXP_SGL)MAXVAL_SGL - smooth_ratio; + int index = *ptrPhaseIndex; + UCHAR harmIndex = *ptrHarmIndex; + register int freqInvFlag = (lowSubband & 1); + FIXP_DBL sineLevel; + int shift; + + *ptrPhaseIndex = (index+noSubbands) & (SBR_NF_NO_RANDOM_VAL - 1); + *ptrHarmIndex = (harmIndex + 1) & 3; + + /* + Possible optimization: + smooth_ratio and harmIndex stay constant during the loop. + It might be faster to include a separate loop in each path. + + the check for smooth_ratio is now outside the loop and the workload + of the whole function decreased by about 20 % + */ + + filtBufferNoiseShift += 1; /* due to later use of fMultDiv2 instead of fMult */ + if (filtBufferNoiseShift<0) + shift = fixMin(DFRACT_BITS-1,-filtBufferNoiseShift); + else + shift = fixMin(DFRACT_BITS-1, filtBufferNoiseShift); + + if (smooth_ratio > FL2FXCONST_SGL(0.0f)) { + + for (k=0; k<noSubbands; k++) { + /* + Smoothing: The old envelope has been bufferd and a certain ratio + of the old gains and noise levels is used. + */ + + smoothedGain = fMult(smooth_ratio,filtBuffer[k]) + + fMult(direct_ratio,gain[k]); + + if (filtBufferNoiseShift<0) { + smoothedNoise = (fMultDiv2(smooth_ratio,filtBufferNoise[k])>>shift) + + fMult(direct_ratio,noiseLevel[k]); + } + else { + smoothedNoise = (fMultDiv2(smooth_ratio,filtBufferNoise[k])<<shift) + + fMult(direct_ratio,noiseLevel[k]); + } + + /* + The next 2 multiplications constitute the actual envelope adjustment + of the signal and should be carried out with full accuracy + (supplying #DFRACT_BITS valid bits). + */ + signalReal = fMultDiv2(*ptrReal,smoothedGain)<<((int)scale_change); + signalImag = fMultDiv2(*ptrImag,smoothedGain)<<((int)scale_change); + + index++; + + if (pSineLevel[k] != FL2FXCONST_DBL(0.0f)) { + sineLevel = pSineLevel[k]; + + switch(harmIndex) { + case 0: + *ptrReal++ = (signalReal + sineLevel); + *ptrImag++ = (signalImag); + break; + case 2: + *ptrReal++ = (signalReal - sineLevel); + *ptrImag++ = (signalImag); + break; + case 1: + *ptrReal++ = (signalReal); + if (freqInvFlag) + *ptrImag++ = (signalImag - sineLevel); + else + *ptrImag++ = (signalImag + sineLevel); + break; + case 3: + *ptrReal++ = signalReal; + if (freqInvFlag) + *ptrImag++ = (signalImag + sineLevel); + else + *ptrImag++ = (signalImag - sineLevel); + break; + } + } + else { + if (noNoiseFlag) { + /* Just the amplified signal is saved */ + *ptrReal++ = (signalReal); + *ptrImag++ = (signalImag); + } + else { + /* Add noisefloor to the amplified signal */ + index &= (SBR_NF_NO_RANDOM_VAL - 1); + noiseReal = fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise)<<4; + noiseImag = fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise)<<4; + *ptrReal++ = (signalReal + noiseReal); + *ptrImag++ = (signalImag + noiseImag); + } + } + freqInvFlag ^= 1; + } + + } + else + { + for (k=0; k<noSubbands; k++) + { + smoothedGain = gain[k]; + signalReal = fMultDiv2(*ptrReal, smoothedGain) << scale_change; + signalImag = fMultDiv2(*ptrImag, smoothedGain) << scale_change; + + index++; + + if ((sineLevel = pSineLevel[k]) != FL2FXCONST_DBL(0.0f)) + { + switch (harmIndex) + { + case 0: + signalReal += sineLevel; + break; + case 1: + if (freqInvFlag) + signalImag -= sineLevel; + else + signalImag += sineLevel; + break; + case 2: + signalReal -= sineLevel; + break; + case 3: + if (freqInvFlag) + signalImag += sineLevel; + else + signalImag -= sineLevel; + break; + } + } + else + { + if (noNoiseFlag == 0) + { + /* Add noisefloor to the amplified signal */ + smoothedNoise = noiseLevel[k]; + index &= (SBR_NF_NO_RANDOM_VAL - 1); + noiseReal = fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise); + noiseImag = fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise); + signalReal += noiseReal<<4; + signalImag += noiseImag<<4; + } + } + *ptrReal++ = signalReal; + *ptrImag++ = signalImag; + + freqInvFlag ^= 1; + } + } +} + + +/*! + \brief Reset limiter bands. + + Build frequency band table for the gain limiter dependent on + the previously generated transposer patch areas. + + \return SBRDEC_OK if ok, SBRDEC_UNSUPPORTED_CONFIG on error +*/ +SBR_ERROR +ResetLimiterBands ( UCHAR *limiterBandTable, /*!< Resulting band borders in QMF channels */ + UCHAR *noLimiterBands, /*!< Resulting number of limiter band */ + UCHAR *freqBandTable, /*!< Table with possible band borders */ + int noFreqBands, /*!< Number of bands in freqBandTable */ + const PATCH_PARAM *patchParam, /*!< Transposer patch parameters */ + int noPatches, /*!< Number of transposer patches */ + int limiterBands) /*!< Selected 'band density' from bitstream */ +{ + int i, k, isPatchBorder[2], loLimIndex, hiLimIndex, tempNoLim, nBands; + UCHAR workLimiterBandTable[MAX_FREQ_COEFFS / 2 + MAX_NUM_PATCHES + 1]; + int patchBorders[MAX_NUM_PATCHES + 1]; + int kx, k2; + FIXP_DBL temp; + + int lowSubband = freqBandTable[0]; + int highSubband = freqBandTable[noFreqBands]; + + /* 1 limiter band. */ + if(limiterBands == 0) { + limiterBandTable[0] = 0; + limiterBandTable[1] = highSubband - lowSubband; + nBands = 1; + } else { + for (i = 0; i < noPatches; i++) { + patchBorders[i] = patchParam[i].guardStartBand - lowSubband; + } + patchBorders[i] = highSubband - lowSubband; + + /* 1.2, 2, or 3 limiter bands/octave plus bandborders at patchborders. */ + for (k = 0; k <= noFreqBands; k++) { + workLimiterBandTable[k] = freqBandTable[k] - lowSubband; + } + for (k = 1; k < noPatches; k++) { + workLimiterBandTable[noFreqBands + k] = patchBorders[k]; + } + + tempNoLim = nBands = noFreqBands + noPatches - 1; + shellsort(workLimiterBandTable, tempNoLim + 1); + + loLimIndex = 0; + hiLimIndex = 1; + + + while (hiLimIndex <= tempNoLim) { + k2 = workLimiterBandTable[hiLimIndex] + lowSubband; + kx = workLimiterBandTable[loLimIndex] + lowSubband; + + temp = FX_SGL2FX_DBL(FDK_getNumOctavesDiv8(kx,k2)); /* Number of octaves */ + temp = fMult(temp, FDK_sbrDecoder_sbr_limiterBandsPerOctaveDiv4[limiterBands]); + + if (temp < FL2FXCONST_DBL (0.49f)>>5) { + if (workLimiterBandTable[hiLimIndex] == workLimiterBandTable[loLimIndex]) { + workLimiterBandTable[hiLimIndex] = highSubband; + nBands--; + hiLimIndex++; + continue; + } + isPatchBorder[0] = isPatchBorder[1] = 0; + for (k = 0; k <= noPatches; k++) { + if (workLimiterBandTable[hiLimIndex] == patchBorders[k]) { + isPatchBorder[1] = 1; + break; + } + } + if (!isPatchBorder[1]) { + workLimiterBandTable[hiLimIndex] = highSubband; + nBands--; + hiLimIndex++; + continue; + } + for (k = 0; k <= noPatches; k++) { + if (workLimiterBandTable[loLimIndex] == patchBorders[k]) { + isPatchBorder[0] = 1; + break; + } + } + if (!isPatchBorder[0]) { + workLimiterBandTable[loLimIndex] = highSubband; + nBands--; + } + } + loLimIndex = hiLimIndex; + hiLimIndex++; + + } + shellsort(workLimiterBandTable, tempNoLim + 1); + + /* Test if algorithm exceeded maximum allowed limiterbands */ + if( nBands > MAX_NUM_LIMITERS || nBands <= 0) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + /* Copy limiterbands from working buffer into final destination */ + for (k = 0; k <= nBands; k++) { + limiterBandTable[k] = workLimiterBandTable[k]; + } + } + *noLimiterBands = nBands; + + return SBRDEC_OK; +} + |