From 2228e360595641dd906bf1773307f43d304f5b2e Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Wed, 11 Jul 2012 10:15:24 -0700 Subject: Snapshot 2bda038c163298531d47394bc2c09e1409c5d0db Change-Id: If584e579464f28b97d50e51fc76ba654a5536c54 --- libSBRdec/src/env_calc.cpp | 2229 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2229 insertions(+) create mode 100644 libSBRdec/src/env_calc.cpp (limited to 'libSBRdec/src/env_calc.cpp') diff --git a/libSBRdec/src/env_calc.cpp b/libSBRdec/src/env_calc.cpp new file mode 100644 index 0000000..11df761 --- /dev/null +++ b/libSBRdec/src/env_calc.cpp @@ -0,0 +1,2229 @@ + +/* ----------------------------------------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2012 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. + All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements +the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio. +This FDK AAC Codec software is intended to be used on a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual +audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by +independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part +of the MPEG specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer) +may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners +individually for the purpose of encoding or decoding bit streams in products that are compliant with +the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license +these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec +software may already be covered under those patent licenses when it is used for those licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality, +are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional +applications information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, are permitted without +payment of copyright license fees provided that you satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of the FDK AAC Codec or +your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation and/or other materials +provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form. +You must make available free of charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived from this library without +prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec +software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software +and the date of any change. For modified versions of the FDK AAC Codec, the term +"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term +"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer, +ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with +respect to this software. + +You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized +by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors +"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties +of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages, +including but not limited to procurement of substitute goods or services; loss of use, data, or profits, +or business interruption, however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of this software, even if +advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------------------------------------- */ + +/*! + \file + \brief Envelope calculation + + 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 envelope 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 + lowSubband and highSubband 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 _m and _e 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 hb_scale 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:
+ \f$ gain = \sqrt{ \frac{nrgRef}{nrgEst} \cdot (1 - noiseRatio) } + \hspace{2cm} + noise = \sqrt{ nrgRef \cdot noiseRatio } + \f$
+ where noiseRatio and nrgRef are extracted from the + bitstream and nrgEst 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 + +
+*/ +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= sineMapped[cc]); + cc++; + } + + for (k=li; 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; knrgSine[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; kfiltBufferNoise[k] <<= shift; + } + else { + int shift = fixMin(DFRACT_BITS-1,-(int)(h_sbr_cal_env->filtBufferNoise_e - noise_e)); + for (k=0; kfiltBufferNoise[k] >>= shift; + } + + h_sbr_cal_env->filtBufferNoise_e = noise_e; + } + + /* find best scaling! */ + scale_change = -(DFRACT_BITS-1); + for(k=0;knrgGain_e[k]); + } + sc_change = (start_posnrgGain_e[k] + (sc_change-1); + pNrgs->nrgGain[k] >>= sc; + pNrgs->nrgGain_e[k] += sc; + } + + if (!useLP) { + for(k=0;kfiltBuffer_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_posfiltBufferNoise[k] will be applied in function adjustTimeSlotHQ() */ + if (shift>=0) { + shift = fixMin(DFRACT_BITS-1,shift); + for (k=0; knrgSine[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; knrgSine[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;knrgGain[k] >>= -sc_change; + pNrgs->nrgGain_e[k] += -sc_change; + } + if (!useLP) { + for(k=0;kfiltBuffer[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; band0) { + 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 0 ) { + if (im!=NULL) + { + for (int l=start_pos; l>(DFRACT_BITS-1))); + maxVal |= (FIXP_DBL)((LONG)(tmp2)^((LONG)tmp2>>(DFRACT_BITS-1))); + } while(--k!=0); +#endif + } + } else + { + for (int l=start_pos; l>(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>(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>(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> (int)negpreShift; + FIXP_DBL temp2 = bufferImag[l] >> (int)negpreShift; + accu = fPow2AddDiv2(accu, temp1); + accu = fPow2AddDiv2(accu, temp2); + } + } else + { + for (l=start_pos; 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=0) { + for (l=start_pos; l> -(int)preShift; + sumLine += fPow2Div2(temp); + temp = analysBufferImag[l][k] >> -(int)preShift; + sumLine += fPow2Div2(temp); + } + } + } else + { + if (preShift>=0) { + for (l=start_pos; l> -(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; knrgEst[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; knrgGain; /*!< 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>shift) + + fMult(direct_ratio,noiseLevel[k]); + } + else { + smoothedNoise = (fMultDiv2(smooth_ratio,filtBufferNoise[k])<>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; +} + -- cgit v1.2.3