diff options
Diffstat (limited to 'libSBRdec/src')
36 files changed, 15402 insertions, 0 deletions
diff --git a/libSBRdec/src/Android.mk b/libSBRdec/src/Android.mk new file mode 100644 index 0000000..21162b9 --- /dev/null +++ b/libSBRdec/src/Android.mk @@ -0,0 +1,32 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + env_calc.cpp \ + env_dec.cpp \ + env_extr.cpp \ + huff_dec.cpp \ + lpp_tran.cpp \ + psbitdec.cpp \ + psdec.cpp \ + psdec_hybrid.cpp \ + sbr_crc.cpp \ + sbr_deb.cpp \ + sbr_dec.cpp \ + sbrdec_drc.cpp \ + sbrdec_freq_sca.cpp \ + sbrdecoder.cpp \ + sbr_ram.cpp \ + sbr_rom.cpp + +LOCAL_CFLAGS := -DANDROID + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../libFDK/include \ + $(LOCAL_PATH)/../../libSYS/include + +LOCAL_MODULE:= libSBRdec + +include $(BUILD_STATIC_LIBRARY) diff --git a/libSBRdec/src/arm/env_calc_arm.cpp b/libSBRdec/src/arm/env_calc_arm.cpp new file mode 100644 index 0000000..8fa3718 --- /dev/null +++ b/libSBRdec/src/arm/env_calc_arm.cpp @@ -0,0 +1,86 @@ +/******************************** Fraunhofer IIS *************************** + + (C) Copyright Fraunhofer IIS (2010) + 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. + + + $Id$ + Author(s): Arthur Tritthart + Description: (ARM optimised) SBR domain coding + + 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. + +******************************************************************************/ +#ifndef INCLUSION_GUARD_CALC_ENV_ARM +#define INCLUSION_GUARD_CALC_ENV_ARM + + +/*! + \brief Compute maximal value of a complex array (re/im) of a given width + Negative values are temporarily logically or'ed with 0xFFFFFFFF + instead of negating the value, if the sign bit is set. + \param maxVal Preset maximal value + \param reTmp real input signal + \param imTmp imaginary input signal + \return new maximal value +*/ + +#ifdef FUNCTION_FDK_get_maxval +__asm FIXP_DBL FDK_get_maxval (FIXP_DBL maxVal, FIXP_DBL *reTmp, FIXP_DBL *imTmp, int width ) +{ + + /* Register map: + r0 maxVal + r1 reTmp + r2 imTmp + r3 width + r4 real + r5 imag + */ + PUSH {r4-r5} + + MOVS r3, r3, ASR #1 + ADC r3, r3, #0 + BCS FDK_get_maxval_loop_2nd_part + BEQ FDK_get_maxval_loop_end + +FDK_get_maxval_loop + LDR r4, [r1], #4 + LDR r5, [r2], #4 + EOR r4, r4, r4, ASR #31 + EOR r5, r5, r5, ASR #31 + ORR r0, r0, r4 + ORR r0, r0, r5 + +FDK_get_maxval_loop_2nd_part + LDR r4, [r1], #4 + LDR r5, [r2], #4 + EOR r4, r4, r4, ASR #31 + EOR r5, r5, r5, ASR #31 + ORR r0, r0, r4 + ORR r0, r0, r5 + + SUBS r3, r3, #1 + BNE FDK_get_maxval_loop + +FDK_get_maxval_loop_end + POP {r4-r5} + BX lr +} +#endif /* FUNCTION_FDK_get_maxval */ + +#endif /* INCLUSION_GUARD_CALC_ENV_ARM */ diff --git a/libSBRdec/src/arm/lpp_tran_arm.cpp b/libSBRdec/src/arm/lpp_tran_arm.cpp new file mode 100644 index 0000000..789f4db --- /dev/null +++ b/libSBRdec/src/arm/lpp_tran_arm.cpp @@ -0,0 +1,89 @@ +/******************************** Fraunhofer IIS *************************** + + (C) Copyright Fraunhofer IIS (2011) + 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. + + + $Id$ + Author(s): Arthur Tritthart + Description: (ARM optimised) LPP transposer subroutines + + 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. + +******************************************************************************/ + + +#if defined(__arm__) + + +#define FUNCTION_LPPTRANSPOSER_func1 + +#ifdef FUNCTION_LPPTRANSPOSER_func1 + +/* Note: This code requires only 43 cycles per iteration instead of 61 on ARM926EJ-S */ +__attribute__ ((noinline)) static void lppTransposer_func1( + FIXP_DBL *lowBandReal, + FIXP_DBL *lowBandImag, + FIXP_DBL **qmfBufferReal, + FIXP_DBL **qmfBufferImag, + int loops, + int hiBand, + int dynamicScale, + int descale, + FIXP_SGL a0r, + FIXP_SGL a0i, + FIXP_SGL a1r, + FIXP_SGL a1i) +{ + + FIXP_DBL real1, real2, imag1, imag2, accu1, accu2; + + real2 = lowBandReal[-2]; + real1 = lowBandReal[-1]; + imag2 = lowBandImag[-2]; + imag1 = lowBandImag[-1]; + for(int i=0; i < loops; i++) + { + accu1 = fMultDiv2( a0r,real1); + accu2 = fMultDiv2( a0i,imag1); + accu1 = fMultAddDiv2(accu1,a1r,real2); + accu2 = fMultAddDiv2(accu2,a1i,imag2); + real2 = fMultDiv2( a1i,real2); + accu1 = accu1 - accu2; + accu1 = accu1 >> dynamicScale; + + accu2 = fMultAddDiv2(real2,a1r,imag2); + real2 = real1; + imag2 = imag1; + accu2 = fMultAddDiv2(accu2,a0i,real1); + real1 = lowBandReal[i]; + accu2 = fMultAddDiv2(accu2,a0r,imag1); + imag1 = lowBandImag[i]; + accu2 = accu2 >> dynamicScale; + + accu1 <<= 1; + accu2 <<= 1; + + qmfBufferReal[i][hiBand] = accu1 + (real1>>descale); + qmfBufferImag[i][hiBand] = accu2 + (imag1>>descale); + } +} +#endif /* #ifdef FUNCTION_LPPTRANSPOSER_func1 */ +#endif /* __arm__ */ + + + 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; +} + diff --git a/libSBRdec/src/env_calc.h b/libSBRdec/src/env_calc.h new file mode 100644 index 0000000..ef14996 --- /dev/null +++ b/libSBRdec/src/env_calc.h @@ -0,0 +1,107 @@ +/**************************************************************************** + + (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 prototypes $Revision: 36841 $ +*/ +#ifndef __ENV_CALC_H +#define __ENV_CALC_H + +#include "sbrdecoder.h" +#include "env_extr.h" /* for HANDLE_SBR_HEADER_DATA */ +#include "sbr_scale.h" + + +typedef struct +{ + FIXP_DBL filtBuffer[MAX_FREQ_COEFFS]; /*!< previous gains (required for smoothing) */ + FIXP_DBL filtBufferNoise[MAX_FREQ_COEFFS]; /*!< previous noise levels (required for smoothing) */ + SCHAR filtBuffer_e[MAX_FREQ_COEFFS]; /*!< Exponents of previous gains */ + SCHAR filtBufferNoise_e; /*!< Common exponent of previous noise levels */ + + int startUp; /*!< flag to signal initial conditions in buffers */ + int phaseIndex; /*!< Index for randomPase array */ + int prevTranEnv; /*!< The transient envelope of the previous frame. */ + + int harmFlagsPrev[(MAX_FREQ_COEFFS+15)/16]; + /*!< Words with 16 flags each indicating where a sine was added in the previous frame.*/ + UCHAR harmIndex; /*!< Current phase of synthetic sine */ + +} +SBR_CALCULATE_ENVELOPE; + +typedef SBR_CALCULATE_ENVELOPE *HANDLE_SBR_CALCULATE_ENVELOPE; + + + +void +calculateSbrEnvelope (QMF_SCALE_FACTOR *sbrScaleFactor, + HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA hFrameData, + FIXP_DBL **analysBufferReal, + 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 + ); + +SBR_ERROR +createSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hSbrCalculateEnvelope, + HANDLE_SBR_HEADER_DATA hHeaderData, + const int chan, + const UINT flags); + +int +deleteSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hSbrCalculateEnvelope); + +void +resetSbrEnvelopeCalc (HANDLE_SBR_CALCULATE_ENVELOPE hCalEnv); + +SBR_ERROR +ResetLimiterBands ( UCHAR *limiterBandTable, + UCHAR *noLimiterBands, + UCHAR *freqBandTable, + int noFreqBands, + const PATCH_PARAM *patchParam, + int noPatches, + int limiterBands); + +void rescaleSubbandSamples( FIXP_DBL ** re, + FIXP_DBL ** im, + int lowSubband, int noSubbands, + int start_pos, int next_pos, + int shift); + +FIXP_DBL maxSubbandSample( FIXP_DBL ** analysBufferReal_m, + FIXP_DBL ** analysBufferImag_m, + int lowSubband, + int highSubband, + int start_pos, + int stop_pos); + +#endif // __ENV_CALC_H diff --git a/libSBRdec/src/env_dec.cpp b/libSBRdec/src/env_dec.cpp new file mode 100644 index 0000000..f49694e --- /dev/null +++ b/libSBRdec/src/env_dec.cpp @@ -0,0 +1,794 @@ +/**************************************************************************** + + (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 decoding $Revision: 36841 $ + This module provides envelope decoding and error concealment algorithms. The main + entry point is decodeSbrData(). + + \sa decodeSbrData(),\ref documentationOverview +*/ + +#include "env_dec.h" + +#include "env_extr.h" +#include "transcendent.h" + +#include "genericStds.h" + + +static void decodeEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_sbr_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data_otherChannel); +static void sbr_envelope_unmapping (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_data_left, + HANDLE_SBR_FRAME_DATA h_data_right); +static void requantizeEnvelopeData (HANDLE_SBR_FRAME_DATA h_sbr_data, + int ampResolution); +static void deltaToLinearPcmEnvelopeDecoding (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_sbr_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data); +static void decodeNoiseFloorlevels (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_sbr_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data); +static void timeCompensateFirstEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_sbr_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data); +static int checkEnvelopeData (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_sbr_data, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data); + + + +#define SBR_ENERGY_PAN_OFFSET (12 << ENV_EXP_FRACT) +#define SBR_MAX_ENERGY (35 << ENV_EXP_FRACT) + +#define DECAY ( 1 << ENV_EXP_FRACT) + +#if ENV_EXP_FRACT +#define DECAY_COUPLING ( 1 << (ENV_EXP_FRACT-1) ) /*!< corresponds to a value of 0.5 */ +#else +#define DECAY_COUPLING 1 /*!< If the energy data is not shifted, use 1 instead of 0.5 */ +#endif + + +/*! + \brief Convert table index +*/ +static int indexLow2High(int offset, /*!< mapping factor */ + int index, /*!< index to scalefactor band */ + int res) /*!< frequency resolution */ +{ + if(res == 0) + { + if (offset >= 0) + { + if (index < offset) + return(index); + else + return(2*index - offset); + } + else + { + offset = -offset; + if (index < offset) + return(2*index+index); + else + return(2*index + offset); + } + } + else + return(index); +} + + +/*! + \brief Update previous envelope value for delta-coding + + The current envelope values needs to be stored for delta-coding + in the next frame. The stored envelope is always represented with + the high frequency resolution. If the current envelope uses the + low frequency resolution, the energy value will be mapped to the + corresponding high-res bands. +*/ +static void mapLowResEnergyVal(FIXP_SGL currVal, /*!< current energy value */ + FIXP_SGL* prevData,/*!< pointer to previous data vector */ + int offset, /*!< mapping factor */ + int index, /*!< index to scalefactor band */ + int res) /*!< frequeny resolution */ +{ + if(res == 0) + { + if (offset >= 0) + { + if(index < offset) + prevData[index] = currVal; + else + { + prevData[2*index - offset] = currVal; + prevData[2*index+1 - offset] = currVal; + } + } + else + { + offset = -offset; + if (index < offset) + { + prevData[3*index] = currVal; + prevData[3*index+1] = currVal; + prevData[3*index+2] = currVal; + } + else + { + prevData[2*index + offset] = currVal; + prevData[2*index + 1 + offset] = currVal; + } + } + } + else + prevData[index] = currVal; +} + + + +/*! + \brief Convert raw envelope and noisefloor data to energy levels + + This function is being called by sbrDecoder_ParseElement() and provides two important algorithms: + + First the function decodes envelopes and noise floor levels as described in requantizeEnvelopeData() + and sbr_envelope_unmapping(). The function also implements concealment algorithms in case there are errors + within the sbr data. For both operations fractional arithmetic is used. + Therefore you might encounter different output values on your target + system compared to the reference implementation. +*/ +void +decodeSbrData (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_data_left, /*!< pointer to left channel frame data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data_left, /*!< pointer to left channel previous frame data */ + HANDLE_SBR_FRAME_DATA h_data_right, /*!< pointer to right channel frame data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data_right)/*!< pointer to right channel previous frame data */ +{ + FIXP_SGL tempSfbNrgPrev[MAX_FREQ_COEFFS]; + int errLeft; + + /* Save previous energy values to be able to reuse them later for concealment. */ + FDKmemcpy (tempSfbNrgPrev, h_prev_data_left->sfb_nrg_prev, MAX_FREQ_COEFFS * sizeof(FIXP_SGL)); + + decodeEnvelope (hHeaderData, h_data_left, h_prev_data_left, h_prev_data_right); + decodeNoiseFloorlevels (hHeaderData, h_data_left, h_prev_data_left); + + if(h_data_right != NULL) { + errLeft = hHeaderData->frameErrorFlag; + decodeEnvelope (hHeaderData, h_data_right, h_prev_data_right, h_prev_data_left); + decodeNoiseFloorlevels (hHeaderData, h_data_right, h_prev_data_right); + + if (!errLeft && hHeaderData->frameErrorFlag) { + /* If an error occurs in the right channel where the left channel seemed ok, + we apply concealment also on the left channel. This ensures that the coupling + modes of both channels match and that we have the same number of envelopes in + coupling mode. + However, as the left channel has already been processed before, the resulting + energy levels are not the same as if the left channel had been concealed + during the first call of decodeEnvelope(). + */ + /* Restore previous energy values for concealment, because the values have been + overwritten by the first call of decodeEnvelope(). */ + FDKmemcpy (h_prev_data_left->sfb_nrg_prev, tempSfbNrgPrev, MAX_FREQ_COEFFS * sizeof(FIXP_SGL)); + /* Do concealment */ + decodeEnvelope (hHeaderData, h_data_left, h_prev_data_left, h_prev_data_right); + } + + if (h_data_left->coupling) { + sbr_envelope_unmapping (hHeaderData, h_data_left, h_data_right); + } + } + + /* Display the data for debugging: */ +} + + +/*! + \brief Convert from coupled channels to independent L/R data +*/ +static void +sbr_envelope_unmapping (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_data_left, /*!< pointer to left channel */ + HANDLE_SBR_FRAME_DATA h_data_right) /*!< pointer to right channel */ +{ + int i; + FIXP_SGL tempL_m, tempR_m, tempRplus1_m, newL_m, newR_m; + SCHAR tempL_e, tempR_e, tempRplus1_e, newL_e, newR_e; + + + /* 1. Unmap (already dequantized) coupled envelope energies */ + + for (i = 0; i < h_data_left->nScaleFactors; i++) { + tempR_m = (FIXP_SGL)((LONG)h_data_right->iEnvelope[i] & MASK_M); + tempR_e = (SCHAR)((LONG)h_data_right->iEnvelope[i] & MASK_E); + + tempR_e -= (18 + NRG_EXP_OFFSET); /* -18 = ld(UNMAPPING_SCALE / h_data_right->nChannels) */ + tempL_m = (FIXP_SGL)((LONG)h_data_left->iEnvelope[i] & MASK_M); + tempL_e = (SCHAR)((LONG)h_data_left->iEnvelope[i] & MASK_E); + + tempL_e -= NRG_EXP_OFFSET; + + /* Calculate tempRight+1 */ + FDK_add_MantExp( tempR_m, tempR_e, + FL2FXCONST_SGL(0.5f), 1, /* 1.0 */ + &tempRplus1_m, &tempRplus1_e); + + FDK_divide_MantExp( tempL_m, tempL_e+1, /* 2 * tempLeft */ + tempRplus1_m, tempRplus1_e, + &newR_m, &newR_e ); + + if (newR_m >= ((FIXP_SGL)MAXVAL_SGL - ROUNDING)) { + newR_m >>= 1; + newR_e += 1; + } + + newL_m = FX_DBL2FX_SGL(fMult(tempR_m,newR_m)); + newL_e = tempR_e + newR_e; + + h_data_right->iEnvelope[i] = ((FIXP_SGL)((SHORT)(FIXP_SGL)(newR_m + ROUNDING) & MASK_M)) + + (FIXP_SGL)((SHORT)(FIXP_SGL)(newR_e + NRG_EXP_OFFSET) & MASK_E); + h_data_left->iEnvelope[i] = ((FIXP_SGL)((SHORT)(FIXP_SGL)(newL_m + ROUNDING) & MASK_M)) + + (FIXP_SGL)((SHORT)(FIXP_SGL)(newL_e + NRG_EXP_OFFSET) & MASK_E); + } + + /* 2. Dequantize and unmap coupled noise floor levels */ + + for (i = 0; i < hHeaderData->freqBandData.nNfb * h_data_left->frameInfo.nNoiseEnvelopes; i++) { + + tempL_e = (SCHAR)(6 - (LONG)h_data_left->sbrNoiseFloorLevel[i]); + tempR_e = (SCHAR)((LONG)h_data_right->sbrNoiseFloorLevel[i] - 12) /*SBR_ENERGY_PAN_OFFSET*/; + + /* Calculate tempR+1 */ + FDK_add_MantExp( FL2FXCONST_SGL(0.5f), 1+tempR_e, /* tempR */ + FL2FXCONST_SGL(0.5f), 1, /* 1.0 */ + &tempRplus1_m, &tempRplus1_e); + + /* Calculate 2*tempLeft/(tempR+1) */ + FDK_divide_MantExp( FL2FXCONST_SGL(0.5f), tempL_e+2, /* 2 * tempLeft */ + tempRplus1_m, tempRplus1_e, + &newR_m, &newR_e ); + + /* if (newR_m >= ((FIXP_SGL)MAXVAL_SGL - ROUNDING)) { + newR_m >>= 1; + newR_e += 1; + } */ + + /* L = tempR * R */ + newL_m = newR_m; + newL_e = newR_e + tempR_e; + h_data_right->sbrNoiseFloorLevel[i] = ((FIXP_SGL)((SHORT)(FIXP_SGL)(newR_m + ROUNDING) & MASK_M)) + + (FIXP_SGL)((SHORT)(FIXP_SGL)(newR_e + NOISE_EXP_OFFSET) & MASK_E); + h_data_left->sbrNoiseFloorLevel[i] = ((FIXP_SGL)((SHORT)(FIXP_SGL)(newL_m + ROUNDING) & MASK_M)) + + (FIXP_SGL)((SHORT)(FIXP_SGL)(newL_e + NOISE_EXP_OFFSET) & MASK_E); + } +} + + +/*! + \brief Simple alternative to the real SBR concealment + + If the real frameInfo is not available due to a frame loss, a replacement will + be constructed with 1 envelope spanning the whole frame (FIX-FIX). + The delta-coded energies are set to negative values, resulting in a fade-down. + In case of coupling, the balance-channel will move towards the center. +*/ +static void +leanSbrConcealment(HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data /*!< pointer to data of last frame */ + ) +{ + FIXP_SGL target; /* targeted level for sfb_nrg_prev during fade-down */ + FIXP_SGL step; /* speed of fade */ + int i; + + int currentStartPos = h_prev_data->stopPos - hHeaderData->numberTimeSlots; + int currentStopPos = hHeaderData->numberTimeSlots; + + + /* Use some settings of the previous frame */ + h_sbr_data->ampResolutionCurrentFrame = h_prev_data->ampRes; + h_sbr_data->coupling = h_prev_data->coupling; + for(i=0;i<MAX_INVF_BANDS;i++) + h_sbr_data->sbr_invf_mode[i] = h_prev_data->sbr_invf_mode[i]; + + /* Generate concealing control data */ + + h_sbr_data->frameInfo.nEnvelopes = 1; + h_sbr_data->frameInfo.borders[0] = currentStartPos; + h_sbr_data->frameInfo.borders[1] = currentStopPos; + h_sbr_data->frameInfo.freqRes[0] = 1; + h_sbr_data->frameInfo.tranEnv = -1; /* no transient */ + h_sbr_data->frameInfo.nNoiseEnvelopes = 1; + h_sbr_data->frameInfo.bordersNoise[0] = currentStartPos; + h_sbr_data->frameInfo.bordersNoise[1] = currentStopPos; + + h_sbr_data->nScaleFactors = hHeaderData->freqBandData.nSfb[1]; + + /* Generate fake envelope data */ + + h_sbr_data->domain_vec[0] = 1; + + if (h_sbr_data->coupling == COUPLING_BAL) { + target = (FIXP_SGL)SBR_ENERGY_PAN_OFFSET; + step = (FIXP_SGL)DECAY_COUPLING; + } + else { + target = FL2FXCONST_SGL(0.0f); + step = (FIXP_SGL)DECAY; + } + if (hHeaderData->bs_info.ampResolution == 0) { + target <<= 1; + step <<= 1; + } + + for (i=0; i < h_sbr_data->nScaleFactors; i++) { + if (h_prev_data->sfb_nrg_prev[i] > target) + h_sbr_data->iEnvelope[i] = -step; + else + h_sbr_data->iEnvelope[i] = step; + } + + /* Noisefloor levels are always cleared ... */ + + h_sbr_data->domain_vec_noise[0] = 1; + for (i=0; i < hHeaderData->freqBandData.nNfb; i++) + h_sbr_data->sbrNoiseFloorLevel[i] = FL2FXCONST_SGL(0.0f); + + /* ... and so are the sines */ + FDKmemclear(h_sbr_data->addHarmonics, MAX_FREQ_COEFFS); +} + + +/*! + \brief Build reference energies and noise levels from bitstream elements +*/ +static void +decodeEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data, /*!< pointer to data of last frame */ + HANDLE_SBR_PREV_FRAME_DATA otherChannel /*!< other channel's last frame data */ + ) +{ + int i; + int fFrameError = hHeaderData->frameErrorFlag; + FIXP_SGL tempSfbNrgPrev[MAX_FREQ_COEFFS]; + + if (!fFrameError) { + /* + To avoid distortions after bad frames, set the error flag if delta coding in time occurs. + However, SBR can take a little longer to come up again. + */ + if ( h_prev_data->frameErrorFlag ) { + if (h_sbr_data->domain_vec[0] != 0) { + fFrameError = 1; + } + } else { + /* Check that the previous stop position and the current start position match. + (Could be done in checkFrameInfo(), but the previous frame data is not available there) */ + if ( h_sbr_data->frameInfo.borders[0] != h_prev_data->stopPos - hHeaderData->numberTimeSlots ) { + /* Both the previous as well as the current frame are flagged to be ok, but they do not match! */ + if (h_sbr_data->domain_vec[0] == 1) { + /* Prefer concealment over delta-time coding between the mismatching frames */ + fFrameError = 1; + } + else { + /* Close the gap in time by triggering timeCompensateFirstEnvelope() */ + fFrameError = 1; + } + } + } + } + + + if (fFrameError) /* Error is detected */ + { + leanSbrConcealment(hHeaderData, + h_sbr_data, + h_prev_data); + + /* decode the envelope data to linear PCM */ + deltaToLinearPcmEnvelopeDecoding (hHeaderData, h_sbr_data, h_prev_data); + } + else /*Do a temporary dummy decoding and check that the envelope values are within limits */ + { + if (h_prev_data->frameErrorFlag) { + timeCompensateFirstEnvelope (hHeaderData, h_sbr_data, h_prev_data); + if (h_sbr_data->coupling != h_prev_data->coupling) { + /* + Coupling mode has changed during concealment. + The stored energy levels need to be converted. + */ + for (i = 0; i < hHeaderData->freqBandData.nSfb[1]; i++) { + /* Former Level-Channel will be used for both channels */ + if (h_prev_data->coupling == COUPLING_BAL) + h_prev_data->sfb_nrg_prev[i] = otherChannel->sfb_nrg_prev[i]; + /* Former L/R will be combined as the new Level-Channel */ + else if (h_sbr_data->coupling == COUPLING_LEVEL) + h_prev_data->sfb_nrg_prev[i] = (h_prev_data->sfb_nrg_prev[i] + otherChannel->sfb_nrg_prev[i]) >> 1; + else if (h_sbr_data->coupling == COUPLING_BAL) + h_prev_data->sfb_nrg_prev[i] = (FIXP_SGL)SBR_ENERGY_PAN_OFFSET; + } + } + } + FDKmemcpy (tempSfbNrgPrev, h_prev_data->sfb_nrg_prev, + MAX_FREQ_COEFFS * sizeof (FIXP_SGL)); + + deltaToLinearPcmEnvelopeDecoding (hHeaderData, h_sbr_data, h_prev_data); + + fFrameError = checkEnvelopeData (hHeaderData, h_sbr_data, h_prev_data); + + if (fFrameError) + { + hHeaderData->frameErrorFlag = 1; + FDKmemcpy (h_prev_data->sfb_nrg_prev, tempSfbNrgPrev, + MAX_FREQ_COEFFS * sizeof (FIXP_SGL)); + decodeEnvelope (hHeaderData, h_sbr_data, h_prev_data, otherChannel); + return; + } + } + + requantizeEnvelopeData (h_sbr_data, h_sbr_data->ampResolutionCurrentFrame); + + hHeaderData->frameErrorFlag = fFrameError; +} + + +/*! + \brief Verify that envelope energies are within the allowed range + \return 0 if all is fine, 1 if an envelope value was too high +*/ +static int +checkEnvelopeData (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data /*!< pointer to data of last frame */ + ) +{ + FIXP_SGL *iEnvelope = h_sbr_data->iEnvelope; + FIXP_SGL *sfb_nrg_prev = h_prev_data->sfb_nrg_prev; + int i = 0, errorFlag = 0; + FIXP_SGL sbr_max_energy = + (h_sbr_data->ampResolutionCurrentFrame == 1) ? SBR_MAX_ENERGY : (SBR_MAX_ENERGY << 1); + + /* + Range check for current energies + */ + for (i = 0; i < h_sbr_data->nScaleFactors; i++) { + if (iEnvelope[i] > sbr_max_energy) { + errorFlag = 1; + } + if (iEnvelope[i] < FL2FXCONST_SGL(0.0f)) { + errorFlag = 1; + /* iEnvelope[i] = FL2FXCONST_SGL(0.0f); */ + } + } + + /* + Range check for previous energies + */ + for (i = 0; i < hHeaderData->freqBandData.nSfb[1]; i++) { + sfb_nrg_prev[i] = fixMax(sfb_nrg_prev[i], FL2FXCONST_SGL(0.0f)); + sfb_nrg_prev[i] = fixMin(sfb_nrg_prev[i], sbr_max_energy); + } + + return (errorFlag); +} + + +/*! + \brief Verify that the noise levels are within the allowed range + + The function is equivalent to checkEnvelopeData(). + When the noise-levels are being decoded, it is already too late for + concealment. Therefore the noise levels are simply limited here. +*/ +static void +limitNoiseLevels(HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data) /*!< pointer to current data */ +{ + int i; + int nNfb = hHeaderData->freqBandData.nNfb; + + /* + Set range limits. The exact values depend on the coupling mode. + However this limitation is primarily intended to avoid unlimited + accumulation of the delta-coded noise levels. + */ + #define lowerLimit ((FIXP_SGL)0) /* lowerLimit actually refers to the _highest_ noise energy */ + #define upperLimit ((FIXP_SGL)35) /* upperLimit actually refers to the _lowest_ noise energy */ + + /* + Range check for current noise levels + */ + for (i = 0; i < h_sbr_data->frameInfo.nNoiseEnvelopes * nNfb; i++) { + h_sbr_data->sbrNoiseFloorLevel[i] = fixMin(h_sbr_data->sbrNoiseFloorLevel[i], upperLimit); + h_sbr_data->sbrNoiseFloorLevel[i] = fixMax(h_sbr_data->sbrNoiseFloorLevel[i], lowerLimit); + } +} + + +/*! + \brief Compensate for the wrong timing that might occur after a frame error. +*/ +static void +timeCompensateFirstEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to actual data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data) /*!< pointer to data of last frame */ +{ + int i, nScalefactors; + FRAME_INFO *pFrameInfo = &h_sbr_data->frameInfo; + UCHAR *nSfb = hHeaderData->freqBandData.nSfb; + int estimatedStartPos = h_prev_data->stopPos - hHeaderData->numberTimeSlots; + int refLen, newLen, shift; + FIXP_SGL deltaExp; + + /* Original length of first envelope according to bitstream */ + refLen = pFrameInfo->borders[1] - pFrameInfo->borders[0]; + /* Corrected length of first envelope (concealing can make the first envelope longer) */ + newLen = pFrameInfo->borders[1] - estimatedStartPos; + + if (newLen <= 0) { + /* An envelope length of <= 0 would not work, so we don't use it. + May occur if the previous frame was flagged bad due to a mismatch + of the old and new frame infos. */ + newLen = refLen; + estimatedStartPos = pFrameInfo->borders[0]; + } + + deltaExp = FDK_getNumOctavesDiv8(newLen, refLen); + + /* Shift by -3 to rescale ld-table, 1-ampRes to enable coarser steps */ + shift = (FRACT_BITS - 1 - ENV_EXP_FRACT + 1 - h_sbr_data->ampResolutionCurrentFrame - 3); + deltaExp = deltaExp >> shift; + pFrameInfo->borders[0] = estimatedStartPos; + pFrameInfo->bordersNoise[0] = estimatedStartPos; + + if (h_sbr_data->coupling != COUPLING_BAL) { + nScalefactors = (pFrameInfo->freqRes[0]) ? nSfb[1] : nSfb[0]; + + for (i = 0; i < nScalefactors; i++) + h_sbr_data->iEnvelope[i] = h_sbr_data->iEnvelope[i] + deltaExp; + } +} + + + +/*! + \brief Convert each envelope value from logarithmic to linear domain + + Energy levels are transmitted in powers of 2, i.e. only the exponent + is extracted from the bitstream. + Therefore, normally only integer exponents can occur. However during + fading (in case of a corrupt bitstream), a fractional part can also + occur. The data in the array iEnvelope is shifted left by ENV_EXP_FRACT + compared to an integer representation so that numbers smaller than 1 + can be represented. + + This function calculates a mantissa corresponding to the fractional + part of the exponent for each reference energy. The array iEnvelope + is converted in place to save memory. Input and output data must + be interpreted differently, as shown in the below figure: + + \image html EnvelopeData.png + + The data is then used in calculateSbrEnvelope(). +*/ +static void +requantizeEnvelopeData (HANDLE_SBR_FRAME_DATA h_sbr_data, int ampResolution) +{ + int i; + FIXP_SGL mantissa; + int ampShift = 1 - ampResolution; + int exponent; + + /* In case that ENV_EXP_FRACT is changed to something else but 0 or 8, + the initialization of this array has to be adapted! + */ +#if ENV_EXP_FRACT + static const FIXP_SGL pow2[ENV_EXP_FRACT] = + { + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 1))), /* 0.7071 */ + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 2))), /* 0.5946 */ + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 3))), + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 4))), + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 5))), + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 6))), + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 7))), + FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 8))) /* 0.5013 */ + }; + + int bit, mask; +#endif + + for (i = 0; i < h_sbr_data->nScaleFactors; i++) { + exponent = (LONG)h_sbr_data->iEnvelope[i]; + +#if ENV_EXP_FRACT + + exponent = exponent >> ampShift; + mantissa = 0.5f; + + /* Amplify mantissa according to the fractional part of the + exponent (result will be between 0.500000 and 0.999999) + */ + mask = 1; /* begin with lowest bit of exponent */ + + for ( bit=ENV_EXP_FRACT-1; bit>=0; bit-- ) { + if (exponent & mask) { + /* The current bit of the exponent is set, + multiply mantissa with the corresponding factor: */ + mantissa = (FIXP_SGL)( (mantissa * pow2[bit]) << 1); + } + /* Advance to next bit */ + mask = mask << 1; + } + + /* Make integer part of exponent right aligned */ + exponent = exponent >> ENV_EXP_FRACT; + +#else + /* In case of the high amplitude resolution, 1 bit of the exponent gets lost by the shift. + This will be compensated by a mantissa of 0.5*sqrt(2) instead of 0.5 if that bit is 1. */ + mantissa = (exponent & ampShift) ? FL2FXCONST_SGL(0.707106781186548f) : FL2FXCONST_SGL(0.5f); + exponent = exponent >> ampShift; +#endif + + /* + Mantissa was set to 0.5 (instead of 1.0, therefore increase exponent by 1). + Multiply by L=nChannels=64 by increasing exponent by another 6. + => Increase exponent by 7 + */ + exponent += 7 + NRG_EXP_OFFSET; + + /* Combine mantissa and exponent and write back the result */ + h_sbr_data->iEnvelope[i] = (FIXP_SGL)(((LONG)mantissa & MASK_M) | (exponent & MASK_E)); + + } +} + + +/*! + \brief Build new reference energies from old ones and delta coded data +*/ +static void +deltaToLinearPcmEnvelopeDecoding (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data) /*!< pointer to previous data */ +{ + int i, domain, no_of_bands, band, freqRes; + + FIXP_SGL *sfb_nrg_prev = h_prev_data->sfb_nrg_prev; + FIXP_SGL *ptr_nrg = h_sbr_data->iEnvelope; + + int offset = 2 * hHeaderData->freqBandData.nSfb[0] - hHeaderData->freqBandData.nSfb[1]; + + for (i = 0; i < h_sbr_data->frameInfo.nEnvelopes; i++) { + domain = h_sbr_data->domain_vec[i]; + freqRes = h_sbr_data->frameInfo.freqRes[i]; + + FDK_ASSERT(freqRes >= 0 && freqRes <= 1); + + no_of_bands = hHeaderData->freqBandData.nSfb[freqRes]; + + FDK_ASSERT(no_of_bands < (64)); + + if (domain == 0) + { + mapLowResEnergyVal(*ptr_nrg, sfb_nrg_prev, offset, 0, freqRes); + ptr_nrg++; + for (band = 1; band < no_of_bands; band++) + { + *ptr_nrg = *ptr_nrg + *(ptr_nrg-1); + mapLowResEnergyVal(*ptr_nrg, sfb_nrg_prev, offset, band, freqRes); + ptr_nrg++; + } + } + else + { + for (band = 0; band < no_of_bands; band++) + { + *ptr_nrg = *ptr_nrg + sfb_nrg_prev[indexLow2High(offset, band, freqRes)]; + mapLowResEnergyVal(*ptr_nrg, sfb_nrg_prev, offset, band, freqRes); + ptr_nrg++; + } + } + } +} + + +/*! + \brief Build new noise levels from old ones and delta coded data +*/ +static void +decodeNoiseFloorlevels (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */ + HANDLE_SBR_PREV_FRAME_DATA h_prev_data) /*!< pointer to previous data */ +{ + int i; + int nNfb = hHeaderData->freqBandData.nNfb; + int nNoiseFloorEnvelopes = h_sbr_data->frameInfo.nNoiseEnvelopes; + + /* Decode first noise envelope */ + + if (h_sbr_data->domain_vec_noise[0] == 0) { + FIXP_SGL noiseLevel = h_sbr_data->sbrNoiseFloorLevel[0]; + for (i = 1; i < nNfb; i++) { + noiseLevel += h_sbr_data->sbrNoiseFloorLevel[i]; + h_sbr_data->sbrNoiseFloorLevel[i] = noiseLevel; + } + } + else { + for (i = 0; i < nNfb; i++) { + h_sbr_data->sbrNoiseFloorLevel[i] += h_prev_data->prevNoiseLevel[i]; + } + } + + /* If present, decode the second noise envelope + Note: nNoiseFloorEnvelopes can only be 1 or 2 */ + + if (nNoiseFloorEnvelopes > 1) { + if (h_sbr_data->domain_vec_noise[1] == 0) { + FIXP_SGL noiseLevel = h_sbr_data->sbrNoiseFloorLevel[nNfb]; + for (i = nNfb + 1; i < 2*nNfb; i++) { + noiseLevel += h_sbr_data->sbrNoiseFloorLevel[i]; + h_sbr_data->sbrNoiseFloorLevel[i] = noiseLevel; + } + } + else { + for (i = 0; i < nNfb; i++) { + h_sbr_data->sbrNoiseFloorLevel[i + nNfb] += h_sbr_data->sbrNoiseFloorLevel[i]; + } + } + } + + limitNoiseLevels(hHeaderData, h_sbr_data); + + /* Update prevNoiseLevel with the last noise envelope */ + for (i = 0; i < nNfb; i++) + h_prev_data->prevNoiseLevel[i] = h_sbr_data->sbrNoiseFloorLevel[i + nNfb*(nNoiseFloorEnvelopes-1)]; + + + /* Requantize the noise floor levels in COUPLING_OFF-mode */ + if (!h_sbr_data->coupling) { + int nf_e; + + for (i = 0; i < nNoiseFloorEnvelopes*nNfb; i++) { + nf_e = 6 - (LONG)h_sbr_data->sbrNoiseFloorLevel[i] + 1 + NOISE_EXP_OFFSET; + /* +1 to compensate for a mantissa of 0.5 instead of 1.0 */ + + h_sbr_data->sbrNoiseFloorLevel[i] = + (FIXP_SGL)( ((LONG)FL2FXCONST_SGL(0.5f)) + /* mantissa */ + (nf_e & MASK_E) ); /* exponent */ + + } + } +} diff --git a/libSBRdec/src/env_dec.h b/libSBRdec/src/env_dec.h new file mode 100644 index 0000000..554c6c2 --- /dev/null +++ b/libSBRdec/src/env_dec.h @@ -0,0 +1,43 @@ +/**************************************************************************** + + (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 decoding $Revision: 36841 $ +*/ +#ifndef __ENV_DEC_H +#define __ENV_DEC_H + +#include "sbrdecoder.h" +#include "env_extr.h" + +void decodeSbrData (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_data_left, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data_left, + HANDLE_SBR_FRAME_DATA h_data_right, + HANDLE_SBR_PREV_FRAME_DATA h_prev_data_right); + + +#endif diff --git a/libSBRdec/src/env_extr.cpp b/libSBRdec/src/env_extr.cpp new file mode 100644 index 0000000..040b812 --- /dev/null +++ b/libSBRdec/src/env_extr.cpp @@ -0,0 +1,1333 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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 extraction $Revision: 36841 $ + The functions provided by this module are mostly called by applySBR(). After it is + determined that there is valid SBR data, sbrGetHeaderData() might be called if the current + SBR data contains an \ref SBR_HEADER_ELEMENT as opposed to a \ref SBR_STANDARD_ELEMENT. This function + may return various error codes as defined in #SBR_HEADER_STATUS . Most importantly it returns HEADER_RESET when decoder + settings need to be recalculated according to the SBR specifications. In that case applySBR() + will initiatite the required re-configuration. + + The header data is stored in a #SBR_HEADER_DATA structure. + + The actual SBR data for the current frame is decoded into SBR_FRAME_DATA stuctures by sbrGetChannelPairElement() + [for stereo streams] and sbrGetSingleChannelElement() [for mono streams]. There is no fractional arithmetic involved. + + Once the information is extracted, the data needs to be further prepared before the actual decoding process. + This is done in decodeSbrData(). + + \sa Description of buffer management in applySBR(). \ref documentationOverview + + <h1>About the SBR data format:</h1> + + Each frame includes SBR data (side chain information), and can be either the \ref SBR_HEADER_ELEMENT or the \ref SBR_STANDARD_ELEMENT. + Parts of the data can be protected by a CRC checksum. + + \anchor SBR_HEADER_ELEMENT <h2>The SBR_HEADER_ELEMENT</h2> + + The SBR_HEADER_ELEMENT can be transmitted with every frame, however, it typically is send every second or so. It contains fundamental + information such as SBR sampling frequency and frequency range as well as control signals that do not require frequent changes. It also + includes the \ref SBR_STANDARD_ELEMENT. + + Depending on the changes between the information in a current SBR_HEADER_ELEMENT and the previous SBR_HEADER_ELEMENT, the SBR decoder might need + to be reset and reconfigured (e.g. new tables need to be calculated). + + \anchor SBR_STANDARD_ELEMENT <h2>The SBR_STANDARD_ELEMENT</h2> + + This data can be subdivided into "side info" and "raw data", where side info is defined as signals needed to decode the raw data + and some decoder tuning signals. Raw data is referred to as PCM and Huffman coded envelope and noise floor estimates. The side info also + includes information about the time-frequency grid for the current frame. + + \sa \ref documentationOverview +*/ + +#include "env_extr.h" + +#include "sbr_ram.h" +#include "sbr_rom.h" +#include "huff_dec.h" + + +#include "psbitdec.h" + +#define DRM_PARAMETRIC_STEREO 0 +#define EXTENSION_ID_PS_CODING 2 + + +static int extractFrameInfo (HANDLE_FDK_BITSTREAM hBs, + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_frame_data, + const UINT nrOfChannels, + const UINT flags + ); + + +static int sbrGetEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_frame_data, + HANDLE_FDK_BITSTREAM hBs, + const UINT flags); + +static void sbrGetDirectionControlData (HANDLE_SBR_FRAME_DATA hFrameData, + HANDLE_FDK_BITSTREAM hBs); + +static void sbrGetNoiseFloorData (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_frame_data, + HANDLE_FDK_BITSTREAM hBs); + +static int checkFrameInfo (FRAME_INFO *pFrameInfo, int numberOfTimeSlots, int overlap, int timeStep); + +SBR_ERROR +initHeaderData ( + HANDLE_SBR_HEADER_DATA hHeaderData, + const int sampleRateIn, + const int sampleRateOut, + const int samplesPerFrame, + const UINT flags + ) +{ + HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData; + SBR_ERROR sbrError = SBRDEC_OK; + int numAnalysisBands; + + if ( sampleRateIn == sampleRateOut ) { + hHeaderData->sbrProcSmplRate = sampleRateOut<<1; + numAnalysisBands = 32; + } else { + hHeaderData->sbrProcSmplRate = sampleRateOut; + if ( (sampleRateOut>>1) == sampleRateIn) { + /* 1:2 */ + numAnalysisBands = 32; + } else if ( (sampleRateOut>>2) == sampleRateIn ) { + /* 1:4 */ + numAnalysisBands = 32; + } else if ( (sampleRateOut*3)>>3 == (sampleRateIn*8)>>3 ) { + /* 3:8, 3/4 core frame length */ + numAnalysisBands = 24; + } else { + sbrError = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + } + + /* Fill in default values first */ + hHeaderData->syncState = SBR_NOT_INITIALIZED; + hHeaderData->status = 0; + hHeaderData->frameErrorFlag = 0; + + hHeaderData->bs_info.ampResolution = 1; + hHeaderData->bs_info.xover_band = 0; + hHeaderData->bs_info.sbr_preprocessing = 0; + + hHeaderData->bs_data.startFreq = 5; + hHeaderData->bs_data.stopFreq = 0; + hHeaderData->bs_data.freqScale = 2; + hHeaderData->bs_data.alterScale = 1; + hHeaderData->bs_data.noise_bands = 2; + hHeaderData->bs_data.limiterBands = 2; + hHeaderData->bs_data.limiterGains = 2; + hHeaderData->bs_data.interpolFreq = 1; + hHeaderData->bs_data.smoothingLength = 1; + + hHeaderData->timeStep = (flags & SBRDEC_ELD_GRID) ? 1 : 2; + + /* Setup pointers to frequency band tables */ + hFreq->freqBandTable[0] = hFreq->freqBandTableLo; + hFreq->freqBandTable[1] = hFreq->freqBandTableHi; + + /* Patch some entries */ + if (sampleRateOut > 24000) { /* Trigger an error if SBR is going to be processed without */ + hHeaderData->bs_data.startFreq = 7; /* having read these frequency values from bit stream before. */ + hHeaderData->bs_data.stopFreq = 3; + } + + /* One SBR timeslot corresponds to the amount of samples equal to the amount of analysis bands, divided by the timestep. */ + hHeaderData->numberTimeSlots = (samplesPerFrame/numAnalysisBands) >> (hHeaderData->timeStep - 1); + hHeaderData->numberOfAnalysisBands = numAnalysisBands; + +bail: + return sbrError; +} + + +/*! + \brief Initialize the SBR_PREV_FRAME_DATA struct +*/ +void +initSbrPrevFrameData (HANDLE_SBR_PREV_FRAME_DATA h_prev_data, /*!< handle to struct SBR_PREV_FRAME_DATA */ + int timeSlots) /*!< Framelength in SBR-timeslots */ +{ + int i; + + /* Set previous energy and noise levels to 0 for the case + that decoding starts in the middle of a bitstream */ + for (i=0; i < MAX_FREQ_COEFFS; i++) + h_prev_data->sfb_nrg_prev[i] = (FIXP_DBL)0; + for (i=0; i < MAX_NOISE_COEFFS; i++) + h_prev_data->prevNoiseLevel[i] = (FIXP_DBL)0; + for (i=0; i < MAX_INVF_BANDS; i++) + h_prev_data->sbr_invf_mode[i] = INVF_OFF; + + h_prev_data->stopPos = timeSlots; + h_prev_data->coupling = COUPLING_OFF; + h_prev_data->ampRes = 0; +} + + +/*! + \brief Read header data from bitstream + + \return error status - 0 if ok +*/ +SBR_HEADER_STATUS +sbrGetHeaderData (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_FDK_BITSTREAM hBs, + const UINT flags, + const int fIsSbrData) +{ + SBR_HEADER_DATA_BS *pBsData; + SBR_HEADER_DATA_BS lastHeader; + SBR_HEADER_DATA_BS_INFO lastInfo; + int headerExtra1=0, headerExtra2=0; + + /* Copy SBR bit stream header to temporary header */ + lastHeader = hHeaderData->bs_data; + lastInfo = hHeaderData->bs_info; + + /* Read new header from bitstream */ + { + pBsData = &hHeaderData->bs_data; + } + + { + hHeaderData->bs_info.ampResolution = FDKreadBits (hBs, 1); + } + + pBsData->startFreq = FDKreadBits (hBs, 4); + pBsData->stopFreq = FDKreadBits (hBs, 4); + + { + hHeaderData->bs_info.xover_band = FDKreadBits (hBs, 3); + FDKreadBits (hBs, 2); + } + + headerExtra1 = FDKreadBits (hBs, 1); + headerExtra2 = FDKreadBits (hBs, 1); + + /* Handle extra header information */ + if( headerExtra1) + { + pBsData->freqScale = FDKreadBits (hBs, 2); + pBsData->alterScale = FDKreadBits (hBs, 1); + pBsData->noise_bands = FDKreadBits (hBs, 2); + } + else { + pBsData->freqScale = 2; + pBsData->alterScale = 1; + pBsData->noise_bands = 2; + } + + if (headerExtra2) { + pBsData->limiterBands = FDKreadBits (hBs, 2); + pBsData->limiterGains = FDKreadBits (hBs, 2); + pBsData->interpolFreq = FDKreadBits (hBs, 1); + pBsData->smoothingLength = FDKreadBits (hBs, 1); + } + else { + pBsData->limiterBands = 2; + pBsData->limiterGains = 2; + pBsData->interpolFreq = 1; + pBsData->smoothingLength = 1; + } + + /* Look for new settings. IEC 14496-3, 4.6.18.3.1 */ + if(hHeaderData->syncState != SBR_ACTIVE || + lastHeader.startFreq != pBsData->startFreq || + lastHeader.stopFreq != pBsData->stopFreq || + lastHeader.freqScale != pBsData->freqScale || + lastHeader.alterScale != pBsData->alterScale || + lastHeader.noise_bands != pBsData->noise_bands || + lastInfo.xover_band != hHeaderData->bs_info.xover_band) { + return HEADER_RESET; /* New settings */ + } + + return HEADER_OK; +} + +/*! + \brief Get missing harmonics parameters (only used for AAC+SBR) + + \return error status - 0 if ok +*/ +int +sbrGetSyntheticCodedData(HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA hFrameData, + HANDLE_FDK_BITSTREAM hBs) +{ + int i, bitsRead = 0; + + int flag = FDKreadBits(hBs,1); + bitsRead++; + + if(flag){ + for(i=0;i<hHeaderData->freqBandData.nSfb[1];i++){ + hFrameData->addHarmonics[i] = FDKreadBits (hBs, 1 ); + bitsRead++; + } + } + else { + for(i=0; i<MAX_FREQ_COEFFS; i++) + hFrameData->addHarmonics[i] = 0; + } + return(bitsRead); +} + +/*! + \brief Reads extension data from the bitstream + + The bitstream format allows up to 4 kinds of extended data element. + Extended data may contain several elements, each identified by a 2-bit-ID. + So far, no extended data elements are defined hence the first 2 parameters + are unused. The data should be skipped in order to update the number + of read bits for the consistency check in applySBR(). +*/ +static int extractExtendedData( + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< handle to SBR header */ + HANDLE_FDK_BITSTREAM hBs /*!< Handle to the bit buffer */ + ,HANDLE_PS_DEC hParametricStereoDec /*!< Parametric Stereo Decoder */ + ) { + INT nBitsLeft; + int extended_data; + int i, frameOk = 1; + + + extended_data = FDKreadBits(hBs, 1); + + if (extended_data) { + int cnt; + int bPsRead = 0; + + cnt = FDKreadBits(hBs, 4); + if (cnt == (1<<4)-1) + cnt += FDKreadBits(hBs, 8); + + + nBitsLeft = 8 * cnt; + + /* sanity check for cnt */ + if (nBitsLeft > (INT)FDKgetValidBits(hBs)) { + /* limit nBitsLeft */ + nBitsLeft = (INT)FDKgetValidBits(hBs); + /* set frame error */ + frameOk = 0; + } + + while (nBitsLeft > 7) { + int extension_id = FDKreadBits(hBs, 2); + nBitsLeft -= 2; + + switch(extension_id) { + + + + case EXTENSION_ID_PS_CODING: + + /* Read PS data from bitstream */ + + if (hParametricStereoDec != NULL) { + if(bPsRead && !hParametricStereoDec->bsData[hParametricStereoDec->bsReadSlot].mpeg.bPsHeaderValid) { + cnt = nBitsLeft >> 3; /* number of remaining bytes */ + for (i=0; i<cnt; i++) + FDKreadBits(hBs, 8); + nBitsLeft -= cnt * 8; + } else { + nBitsLeft -= ReadPsData(hParametricStereoDec, hBs, nBitsLeft); + bPsRead = 1; + } + } + + /* parametric stereo detected, could set channelMode accordingly here */ + /* */ + /* "The usage of this parametric stereo extension to HE-AAC is */ + /* signalled implicitly in the bitstream. Hence, if an sbr_extension() */ + /* with bs_extension_id==EXTENSION_ID_PS is found in the SBR part of */ + /* the bitstream, a decoder supporting the combination of SBR and PS */ + /* shall operate the PS tool to generate a stereo output signal." */ + /* source: ISO/IEC 14496-3:2001/FDAM 2:2004(E) */ + + break; + + + default: + cnt = nBitsLeft >> 3; /* number of remaining bytes */ + for (i=0; i<cnt; i++) + FDKreadBits(hBs, 8); + nBitsLeft -= cnt * 8; + break; + } + } + + if (nBitsLeft < 0) { + frameOk = 0; + goto bail; + } + else { + /* Read fill bits for byte alignment */ + FDKreadBits(hBs, nBitsLeft); + } + } + +bail: + return (frameOk); +} + + +/*! + \brief Read bitstream elements of one channel + + \return SbrFrameOK: 1=ok, 0=error +*/ +int +sbrGetSingleChannelElement (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */ + HANDLE_FDK_BITSTREAM hBs, /*!< Handle to struct BIT_BUF */ + HANDLE_PS_DEC hParametricStereoDec, /*!< Handle to PS decoder */ + const UINT flags, + const int overlap + ) +{ + int i; + + + hFrameData->coupling = COUPLING_OFF; + + { + /* Reserved bits */ + if (FDKreadBits(hBs, 1)) { /* bs_data_extra */ + FDKreadBits(hBs, 4); + if (flags & SBRDEC_SYNTAX_SCAL) { + FDKreadBits(hBs, 4); + } + } + } + + if (flags & SBRDEC_SYNTAX_SCAL) { + FDKreadBits (hBs, 1); /* bs_coupling */ + } + + /* + Grid control + */ + if ( !extractFrameInfo ( hBs, hHeaderData, hFrameData, 1, flags) ) + return 0; + + if ( !checkFrameInfo (&hFrameData->frameInfo, hHeaderData->numberTimeSlots, overlap, hHeaderData->timeStep) ) + return 0; + + + /* + Fetch domain vectors (time or frequency direction for delta-coding) + */ + sbrGetDirectionControlData (hFrameData, hBs); + + for (i=0; i<hHeaderData->freqBandData.nInvfBands; i++) { + hFrameData->sbr_invf_mode[i] = + (INVF_MODE) FDKreadBits (hBs, 2); + } + + + + /* raw data */ + if ( !sbrGetEnvelope (hHeaderData, hFrameData, hBs, flags) ) + return 0; + + + sbrGetNoiseFloorData (hHeaderData, hFrameData, hBs); + + sbrGetSyntheticCodedData(hHeaderData, hFrameData, hBs); + + { + /* sbr extended data */ + if (! extractExtendedData( + hHeaderData, + hBs + ,hParametricStereoDec + )) { + return 0; + } + } + + return 1; +} + + + +/*! + \brief Read bitstream elements of a channel pair + \return SbrFrameOK +*/ +int +sbrGetChannelPairElement (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA hFrameDataLeft, /*!< Dynamic control data for first channel */ + HANDLE_SBR_FRAME_DATA hFrameDataRight,/*!< Dynamic control data for second channel */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to struct BIT_BUF */ + const UINT flags, + const int overlap ) +{ + int i, bit; + + + /* Reserved bits */ + if (FDKreadBits(hBs, 1)) { /* bs_data_extra */ + FDKreadBits(hBs, 4); + FDKreadBits(hBs, 4); + } + + /* Read coupling flag */ + bit = FDKreadBits (hBs, 1); + + if (bit) { + hFrameDataLeft->coupling = COUPLING_LEVEL; + hFrameDataRight->coupling = COUPLING_BAL; + } + else { + hFrameDataLeft->coupling = COUPLING_OFF; + hFrameDataRight->coupling = COUPLING_OFF; + } + + + /* + Grid control + */ + if ( !extractFrameInfo (hBs, hHeaderData, hFrameDataLeft, 2, flags) ) + return 0; + + if ( !checkFrameInfo (&hFrameDataLeft->frameInfo, hHeaderData->numberTimeSlots, overlap, hHeaderData->timeStep) ) + return 0; + + if (hFrameDataLeft->coupling) { + FDKmemcpy (&hFrameDataRight->frameInfo, &hFrameDataLeft->frameInfo, sizeof(FRAME_INFO)); + hFrameDataRight->ampResolutionCurrentFrame = hFrameDataLeft->ampResolutionCurrentFrame; + } + else { + if ( !extractFrameInfo (hBs, hHeaderData, hFrameDataRight, 2, flags) ) + return 0; + + if ( !checkFrameInfo (&hFrameDataRight->frameInfo, hHeaderData->numberTimeSlots, overlap, hHeaderData->timeStep) ) + return 0; + } + + /* + Fetch domain vectors (time or frequency direction for delta-coding) + */ + sbrGetDirectionControlData (hFrameDataLeft, hBs); + sbrGetDirectionControlData (hFrameDataRight, hBs); + + for (i=0; i<hHeaderData->freqBandData.nInvfBands; i++) { + hFrameDataLeft->sbr_invf_mode[i] = (INVF_MODE) FDKreadBits (hBs, 2); + } + + if (hFrameDataLeft->coupling) { + for (i=0; i<hHeaderData->freqBandData.nInvfBands; i++) { + hFrameDataRight->sbr_invf_mode[i] = hFrameDataLeft->sbr_invf_mode[i]; + } + + + if ( !sbrGetEnvelope (hHeaderData, hFrameDataLeft, hBs, flags) ) { + return 0; + } + + sbrGetNoiseFloorData (hHeaderData, hFrameDataLeft, hBs); + + if ( !sbrGetEnvelope (hHeaderData, hFrameDataRight, hBs, flags) ) { + return 0; + } + } + else { + + for (i=0; i<hHeaderData->freqBandData.nInvfBands; i++) { + hFrameDataRight->sbr_invf_mode[i] = (INVF_MODE) FDKreadBits (hBs, 2); + } + + + + if ( !sbrGetEnvelope (hHeaderData, hFrameDataLeft, hBs, flags) ) + return 0; + + if ( !sbrGetEnvelope (hHeaderData, hFrameDataRight, hBs, flags) ) + return 0; + + sbrGetNoiseFloorData (hHeaderData, hFrameDataLeft, hBs); + + } + sbrGetNoiseFloorData (hHeaderData, hFrameDataRight, hBs); + + sbrGetSyntheticCodedData(hHeaderData, hFrameDataLeft, hBs); + sbrGetSyntheticCodedData(hHeaderData, hFrameDataRight, hBs); + + { + if (! extractExtendedData( + hHeaderData, + hBs + ,NULL + ) ) { + return 0; + } + } + + return 1; +} + + + + +/*! + \brief Read direction control data from bitstream +*/ +void +sbrGetDirectionControlData (HANDLE_SBR_FRAME_DATA h_frame_data, /*!< handle to struct SBR_FRAME_DATA */ + HANDLE_FDK_BITSTREAM hBs) /*!< handle to struct BIT_BUF */ +{ + int i; + + for (i = 0; i < h_frame_data->frameInfo.nEnvelopes; i++) { + h_frame_data->domain_vec[i] = FDKreadBits (hBs, 1); + } + + for (i = 0; i < h_frame_data->frameInfo.nNoiseEnvelopes; i++) { + h_frame_data->domain_vec_noise[i] = FDKreadBits (hBs, 1); + } +} + + + +/*! + \brief Read noise-floor-level data from bitstream +*/ +void +sbrGetNoiseFloorData (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_frame_data, /*!< handle to struct SBR_FRAME_DATA */ + HANDLE_FDK_BITSTREAM hBs) /*!< handle to struct BIT_BUF */ +{ + int i,j; + int delta; + COUPLING_MODE coupling; + int noNoiseBands = hHeaderData->freqBandData.nNfb; + + Huffman hcb_noiseF; + Huffman hcb_noise; + int envDataTableCompFactor; + + coupling = h_frame_data->coupling; + + + /* + Select huffman codebook depending on coupling mode + */ + if (coupling == COUPLING_BAL) { + hcb_noise = (Huffman)&FDK_sbrDecoder_sbr_huffBook_NoiseBalance11T; + hcb_noiseF = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance11F; /* "sbr_huffBook_NoiseBalance11F" */ + envDataTableCompFactor = 1; + } + else { + hcb_noise = (Huffman)&FDK_sbrDecoder_sbr_huffBook_NoiseLevel11T; + hcb_noiseF = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel11F; /* "sbr_huffBook_NoiseLevel11F" */ + envDataTableCompFactor = 0; + } + + /* + Read raw noise-envelope data + */ + for (i=0; i<h_frame_data->frameInfo.nNoiseEnvelopes; i++) { + + + if (h_frame_data->domain_vec_noise[i] == 0) { + if (coupling == COUPLING_BAL) { + h_frame_data->sbrNoiseFloorLevel[i*noNoiseBands] = + (FIXP_SGL) (((int)FDKreadBits (hBs, 5)) << envDataTableCompFactor); + } + else { + h_frame_data->sbrNoiseFloorLevel[i*noNoiseBands] = + (FIXP_SGL) (int)FDKreadBits (hBs, 5); + } + + for (j = 1; j < noNoiseBands; j++) { + delta = DecodeHuffmanCW(hcb_noiseF, hBs); + h_frame_data->sbrNoiseFloorLevel[i*noNoiseBands+j] = (FIXP_SGL) (delta << envDataTableCompFactor); + } + } + else { + for (j = 0; j < noNoiseBands; j++) { + delta = DecodeHuffmanCW(hcb_noise, hBs); + h_frame_data->sbrNoiseFloorLevel[i*noNoiseBands+j] = (FIXP_SGL) (delta << envDataTableCompFactor); + } + } + } +} + + +/*! + \brief Read envelope data from bitstream +*/ +static int +sbrGetEnvelope (HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_frame_data, /*!< handle to struct SBR_FRAME_DATA */ + HANDLE_FDK_BITSTREAM hBs, /*!< handle to struct BIT_BUF */ + const UINT flags) +{ + int i, j; + UCHAR no_band[MAX_ENVELOPES]; + int delta = 0; + int offset = 0; + COUPLING_MODE coupling = h_frame_data->coupling; + int ampRes = hHeaderData->bs_info.ampResolution; + int nEnvelopes = h_frame_data->frameInfo.nEnvelopes; + int envDataTableCompFactor; + int start_bits, start_bits_balance; + Huffman hcb_t, hcb_f; + + h_frame_data->nScaleFactors = 0; + + if ( (h_frame_data->frameInfo.frameClass == 0) && (nEnvelopes == 1) ) { + if (flags & SBRDEC_ELD_GRID) + ampRes = h_frame_data->ampResolutionCurrentFrame; + else + ampRes = 0; + } + h_frame_data->ampResolutionCurrentFrame = ampRes; + + /* + Set number of bits for first value depending on amplitude resolution + */ + if(ampRes == 1) + { + start_bits = 6; + start_bits_balance = 5; + } + else + { + start_bits = 7; + start_bits_balance = 6; + } + + /* + Calculate number of values for each envelope and alltogether + */ + for (i = 0; i < nEnvelopes; i++) { + no_band[i] = hHeaderData->freqBandData.nSfb[h_frame_data->frameInfo.freqRes[i]]; + h_frame_data->nScaleFactors += no_band[i]; + } + if (h_frame_data->nScaleFactors > MAX_NUM_ENVELOPE_VALUES) + return 0; + + /* + Select Huffman codebook depending on coupling mode and amplitude resolution + */ + if (coupling == COUPLING_BAL) { + envDataTableCompFactor = 1; + if (ampRes == 0) { + hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance10T; + hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance10F; + } + else { + hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance11T; + hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance11F; + } + } + else { + envDataTableCompFactor = 0; + if (ampRes == 0) { + hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel10T; + hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel10F; + } + else { + hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel11T; + hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel11F; + } + } + + /* + Now read raw envelope data + */ + for (j = 0, offset = 0; j < nEnvelopes; j++) { + + + if (h_frame_data->domain_vec[j] == 0) { + if (coupling == COUPLING_BAL) { + h_frame_data->iEnvelope[offset] = + (FIXP_SGL) (( (int)FDKreadBits(hBs, start_bits_balance)) << envDataTableCompFactor); + } + else { + h_frame_data->iEnvelope[offset] = + (FIXP_SGL) (int)FDKreadBits (hBs, start_bits); + } + } + + for (i = (1 - h_frame_data->domain_vec[j]); i < no_band[j]; i++) { + + if (h_frame_data->domain_vec[j] == 0) { + delta = DecodeHuffmanCW(hcb_f, hBs); + } + else { + delta = DecodeHuffmanCW(hcb_t, hBs); + } + + h_frame_data->iEnvelope[offset + i] = (FIXP_SGL) (delta << envDataTableCompFactor); + } + offset += no_band[j]; + } + +#if ENV_EXP_FRACT + /* Convert from int to scaled fract (ENV_EXP_FRACT bits for the fractional part) */ + for (i = 0; i < h_frame_data->nScaleFactors; i++) { + h_frame_data->iEnvelope[i] <<= ENV_EXP_FRACT; + } +#endif + + return 1; +} + + +//static const FRAME_INFO v_frame_info1_8 = { 0, 1, {0, 8}, {1}, -1, 1, {0, 8} }; +static const FRAME_INFO v_frame_info2_8 = { 0, 2, {0, 4, 8}, {1, 1}, -1, 2, {0, 4, 8} }; +static const FRAME_INFO v_frame_info4_8 = { 0, 4, {0, 2, 4, 6, 8}, {1, 1, 1, 1}, -1, 2, {0, 4, 8} }; + +/***************************************************************************/ +/*! + \brief Generates frame info for FIXFIXonly frame class used for low delay version + + \return nothing + ****************************************************************************/ + static void generateFixFixOnly ( FRAME_INFO *hSbrFrameInfo, + int tranPosInternal, + int numberTimeSlots + ) +{ + int nEnv, i, tranIdx; + const int *pTable; + + switch (numberTimeSlots) { + case 8: + pTable = FDK_sbrDecoder_envelopeTable_8[tranPosInternal]; + break; + case 15: + pTable = FDK_sbrDecoder_envelopeTable_15[tranPosInternal]; + break; + case 16: + pTable = FDK_sbrDecoder_envelopeTable_16[tranPosInternal]; + break; + default: + FDK_ASSERT(0); + } + + /* look number of envelopes in table */ + nEnv = pTable[0]; + /* look up envelope distribution in table */ + for (i=1; i<nEnv; i++) + hSbrFrameInfo->borders[i] = pTable[i+2]; + /* open and close frame border */ + hSbrFrameInfo->borders[0] = 0; + hSbrFrameInfo->borders[nEnv] = numberTimeSlots; + hSbrFrameInfo->nEnvelopes = nEnv; + + /* transient idx */ + tranIdx = hSbrFrameInfo->tranEnv = pTable[1]; + + /* add noise floors */ + hSbrFrameInfo->bordersNoise[0] = 0; + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[tranIdx?tranIdx:1]; + hSbrFrameInfo->bordersNoise[2] = numberTimeSlots; + /* nEnv is always > 1, so nNoiseEnvelopes is always 2 (IEC 14496-3 4.6.19.3.2) */ + hSbrFrameInfo->nNoiseEnvelopes = 2; +} + +/*! + \brief Extracts LowDelaySBR control data from the bitstream. + + \return zero for bitstream error, one for correct. +*/ +static int +extractLowDelayGrid (HANDLE_FDK_BITSTREAM hBitBuf, /*!< bitbuffer handle */ + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA h_frame_data, /*!< contains the FRAME_INFO struct to be filled */ + int timeSlots + ) +{ + FRAME_INFO * pFrameInfo = &h_frame_data->frameInfo; + INT numberTimeSlots = hHeaderData->numberTimeSlots; + INT temp = 0, k; + + /* FIXFIXonly framing case */ + h_frame_data->frameInfo.frameClass = 0; + + /* get the transient position from the bitstream */ + switch (timeSlots){ + case 8: + /* 3bit transient position (temp={0;..;7}) */ + temp = FDKreadBits( hBitBuf, 3); + break; + + case 16: + case 15: + /* 4bit transient position (temp={0;..;15}) */ + temp = FDKreadBits( hBitBuf, 4); + break; + + default: + return 0; + } + + /* calculate borders according to the transient position */ + generateFixFixOnly ( pFrameInfo, + temp, + numberTimeSlots + ); + + /* decode freq res: */ + for (k = 0; k < pFrameInfo->nEnvelopes; k++) { + pFrameInfo->freqRes[k] = (UCHAR) FDKreadBits (hBitBuf, 1); /* f = F [1 bits] */ + } + + + return 1; +} + +/*! + \brief Extract the frame information (structure FRAME_INFO) from the bitstream + \return Zero for bitstream error, one for correct. +*/ +int +extractFrameInfo ( HANDLE_FDK_BITSTREAM hBs, /*!< bitbuffer handle */ + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + HANDLE_SBR_FRAME_DATA h_frame_data, /*!< pointer to memory where the frame-info will be stored */ + const UINT nrOfChannels, + const UINT flags + ) +{ + FRAME_INFO * pFrameInfo = &h_frame_data->frameInfo; + int numberTimeSlots = hHeaderData->numberTimeSlots; + int pointer_bits = 0, nEnv = 0, b = 0, border, i, n = 0, + k, p, aL, aR, nL, nR, + temp = 0, staticFreqRes; + UCHAR frameClass; + + if (flags & SBRDEC_ELD_GRID) { + /* CODEC_AACLD (LD+SBR) only uses the normal 0 Grid for non-transient Frames and the LowDelayGrid for transient Frames */ + frameClass = FDKreadBits (hBs, 1); /* frameClass = [1 bit] */ + if ( frameClass == 1 ) { + /* if frameClass == 1, extract LowDelaySbrGrid, otherwise extract normal SBR-Grid for FIXIFX */ + /* extract the AACLD-Sbr-Grid */ + pFrameInfo->frameClass = frameClass; + extractLowDelayGrid (hBs, hHeaderData, h_frame_data, numberTimeSlots); + return 1; + } + } else + { + frameClass = FDKreadBits (hBs, 2); /* frameClass = C [2 bits] */ + } + + + switch (frameClass) { + case 0: + temp = FDKreadBits (hBs, 2); /* E [2 bits ] */ + nEnv = (int) (1 << temp); /* E -> e */ + + if ((flags & SBRDEC_ELD_GRID) && (nEnv == 1)) + h_frame_data->ampResolutionCurrentFrame = FDKreadBits( hBs, 1); /* new ELD Syntax 07-11-09 */ + + staticFreqRes = FDKreadBits (hBs, 1); + + { + if (nEnv > MAX_ENVELOPES_HEAAC) + return 0; + } + + b = nEnv + 1; + switch (nEnv) { + case 1: + switch (numberTimeSlots) { + case 15: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info1_15, sizeof(FRAME_INFO)); + break; + case 16: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info1_16, sizeof(FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 2: + switch (numberTimeSlots) { + case 15: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info2_15, sizeof(FRAME_INFO)); + break; + case 16: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info2_16, sizeof(FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 4: + switch (numberTimeSlots) { + case 15: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info4_15, sizeof(FRAME_INFO)); + break; + case 16: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info4_16, sizeof(FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 8: +#if (MAX_ENVELOPES >= 8) + switch (numberTimeSlots) { + case 15: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info8_15, sizeof(FRAME_INFO)); + break; + case 16: + FDKmemcpy (pFrameInfo, &FDK_sbrDecoder_sbr_frame_info8_16, sizeof(FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; +#else + return 0; +#endif + } + /* Apply correct freqRes (High is default) */ + if (!staticFreqRes) { + for (i = 0; i < nEnv ; i++) + pFrameInfo->freqRes[i] = 0; + } + + break; + case 1: + case 2: + temp = FDKreadBits (hBs, 2); /* A [2 bits] */ + + n = FDKreadBits (hBs, 2); /* n = N [2 bits] */ + + nEnv = n + 1; /* # envelopes */ + b = nEnv + 1; /* # borders */ + + break; + } + + switch (frameClass) { + case 1: + /* Decode borders: */ + pFrameInfo->borders[0] = 0; /* first border */ + border = temp + numberTimeSlots; /* A -> aR */ + i = b-1; /* frame info index for last border */ + pFrameInfo->borders[i] = border; /* last border */ + + for (k = 0; k < n; k++) { + temp = FDKreadBits (hBs, 2);/* R [2 bits] */ + border -= (2 * temp + 2); /* R -> r */ + pFrameInfo->borders[--i] = border; + } + + + /* Decode pointer: */ + pointer_bits = DFRACT_BITS - 1 - CountLeadingBits((FIXP_DBL)(n+1)); + p = FDKreadBits (hBs, pointer_bits); /* p = P [pointer_bits bits] */ + + if (p > n+1) + return 0; + + pFrameInfo->tranEnv = p ? n + 2 - p : -1; + + + /* Decode freq res: */ + for (k = n; k >= 0; k--) { + pFrameInfo->freqRes[k] = FDKreadBits (hBs, 1); /* f = F [1 bits] */ + } + + + /* Calculate noise floor middle border: */ + if (p == 0 || p == 1) + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[n]; + else + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[pFrameInfo->tranEnv]; + + break; + + case 2: + /* Decode borders: */ + border = temp; /* A -> aL */ + pFrameInfo->borders[0] = border; /* first border */ + + for (k = 1; k <= n; k++) { + temp = FDKreadBits (hBs, 2);/* R [2 bits] */ + border += (2 * temp + 2); /* R -> r */ + pFrameInfo->borders[k] = border; + } + pFrameInfo->borders[k] = numberTimeSlots; /* last border */ + + + /* Decode pointer: */ + pointer_bits = DFRACT_BITS - 1 - CountLeadingBits((FIXP_DBL)(n+1)); + p = FDKreadBits (hBs, pointer_bits); /* p = P [pointer_bits bits] */ + if (p > n+1) + return 0; + + if (p == 0 || p == 1) + pFrameInfo->tranEnv = -1; + else + pFrameInfo->tranEnv = p - 1; + + + + /* Decode freq res: */ + for (k = 0; k <= n; k++) { + pFrameInfo->freqRes[k] = FDKreadBits(hBs, 1); /* f = F [1 bits] */ + } + + + + /* Calculate noise floor middle border: */ + switch (p) { + case 0: + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[1]; + break; + case 1: + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[n]; + break; + default: + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[pFrameInfo->tranEnv]; + break; + } + + break; + + case 3: + /* v_ctrlSignal = [frameClass,aL,aR,nL,nR,v_rL,v_rR,p,v_fLR]; */ + + aL = FDKreadBits (hBs, 2); /* AL [2 bits], AL -> aL */ + + aR = FDKreadBits (hBs, 2) + numberTimeSlots; /* AR [2 bits], AR -> aR */ + + nL = FDKreadBits (hBs, 2); /* nL = NL [2 bits] */ + + nR = FDKreadBits (hBs, 2); /* nR = NR [2 bits] */ + + + + /*------------------------------------------------------------------------- + Calculate help variables + --------------------------------------------------------------------------*/ + + /* general: */ + nEnv = nL + nR + 1; /* # envelopes */ + if (nEnv > MAX_ENVELOPES) + return 0; + b = nEnv + 1; /* # borders */ + + + + /*------------------------------------------------------------------------- + Decode envelopes + --------------------------------------------------------------------------*/ + + + /* L-borders: */ + border = aL; /* first border */ + pFrameInfo->borders[0] = border; + + for (k = 1; k <= nL; k++) { + temp = FDKreadBits (hBs, 2);/* R [2 bits] */ + border += (2 * temp + 2); /* R -> r */ + pFrameInfo->borders[k] = border; + } + + + /* R-borders: */ + border = aR; /* last border */ + i = nEnv; + + pFrameInfo->borders[i] = border; + + for (k = 0; k < nR; k++) { + temp = FDKreadBits (hBs, 2);/* R [2 bits] */ + border -= (2 * temp + 2); /* R -> r */ + pFrameInfo->borders[--i] = border; + } + + + /* decode pointer: */ + pointer_bits = DFRACT_BITS - 1 - CountLeadingBits((FIXP_DBL)(nL+nR+1)); + p = FDKreadBits (hBs, pointer_bits); /* p = P [pointer_bits bits] */ + + if (p > nL+nR+1) + return 0; + + pFrameInfo->tranEnv = p ? b - p : -1; + + + + /* decode freq res: */ + for (k = 0; k < nEnv; k++) { + pFrameInfo->freqRes[k] = FDKreadBits(hBs, 1); /* f = F [1 bits] */ + } + + + + /*------------------------------------------------------------------------- + Decode noise floors + --------------------------------------------------------------------------*/ + pFrameInfo->bordersNoise[0] = aL; + + if (nEnv == 1) { + /* 1 noise floor envelope: */ + pFrameInfo->bordersNoise[1] = aR; + } + else { + /* 2 noise floor envelopes */ + if (p == 0 || p == 1) + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[nEnv - 1]; + else + pFrameInfo->bordersNoise[1] = pFrameInfo->borders[pFrameInfo->tranEnv]; + pFrameInfo->bordersNoise[2] = aR; + } + break; + } + + + /* + Store number of envelopes, noise floor envelopes and frame class + */ + pFrameInfo->nEnvelopes = nEnv; + + if (nEnv == 1) + pFrameInfo->nNoiseEnvelopes = 1; + else + pFrameInfo->nNoiseEnvelopes = 2; + + pFrameInfo->frameClass = frameClass; + + if (pFrameInfo->frameClass == 2 || pFrameInfo->frameClass == 1) { + /* calculate noise floor first and last borders: */ + pFrameInfo->bordersNoise[0] = pFrameInfo->borders[0]; + pFrameInfo->bordersNoise[pFrameInfo->nNoiseEnvelopes] = pFrameInfo->borders[nEnv]; + } + + + return 1; +} + + +/*! + \brief Check if the frameInfo vector has reasonable values. + \return Zero for error, one for correct +*/ +static int +checkFrameInfo (FRAME_INFO * pFrameInfo, /*!< pointer to frameInfo */ + int numberOfTimeSlots, /*!< QMF time slots per frame */ + int overlap, /*!< Amount of overlap QMF time slots */ + int timeStep) /*!< QMF slots to SBR slots step factor */ +{ + int maxPos,i,j; + int startPos; + int stopPos; + int tranEnv; + int startPosNoise; + int stopPosNoise; + int nEnvelopes = pFrameInfo->nEnvelopes; + int nNoiseEnvelopes = pFrameInfo->nNoiseEnvelopes; + + if(nEnvelopes < 1 || nEnvelopes > MAX_ENVELOPES) + return 0; + + if(nNoiseEnvelopes > MAX_NOISE_ENVELOPES) + return 0; + + startPos = pFrameInfo->borders[0]; + stopPos = pFrameInfo->borders[nEnvelopes]; + tranEnv = pFrameInfo->tranEnv; + startPosNoise = pFrameInfo->bordersNoise[0]; + stopPosNoise = pFrameInfo->bordersNoise[nNoiseEnvelopes]; + + if (overlap < 0 || overlap > (6)) { + return 0; + } + if (timeStep < 1 || timeStep > 2) { + return 0; + } + maxPos = numberOfTimeSlots + (overlap/timeStep); + + /* Check that the start and stop positions of the frame are reasonable values. */ + if( (startPos < 0) || (startPos >= stopPos) ) + return 0; + if( startPos > maxPos-numberOfTimeSlots ) /* First env. must start in or directly after the overlap buffer */ + return 0; + if( stopPos < numberOfTimeSlots ) /* One complete frame must be ready for output after processing */ + return 0; + if(stopPos > maxPos) + return 0; + + /* Check that the start border for every envelope is strictly later in time */ + for(i=0;i<nEnvelopes;i++) { + if(pFrameInfo->borders[i] >= pFrameInfo->borders[i+1]) + return 0; + } + + /* Check that the envelope to be shortened is actually among the envelopes */ + if(tranEnv>nEnvelopes) + return 0; + + + /* Check the noise borders */ + if(nEnvelopes==1 && nNoiseEnvelopes>1) + return 0; + + if(startPos != startPosNoise || stopPos != stopPosNoise) + return 0; + + + /* Check that the start border for every noise-envelope is strictly later in time*/ + for(i=0; i<nNoiseEnvelopes; i++) { + if(pFrameInfo->bordersNoise[i] >= pFrameInfo->bordersNoise[i+1]) + return 0; + } + + /* Check that every noise border is the same as an envelope border*/ + for(i=0; i<nNoiseEnvelopes; i++) { + startPosNoise = pFrameInfo->bordersNoise[i]; + + for(j=0; j<nEnvelopes; j++) { + if(pFrameInfo->borders[j] == startPosNoise) + break; + } + if(j==nEnvelopes) + return 0; + } + + return 1; +} diff --git a/libSBRdec/src/env_extr.h b/libSBRdec/src/env_extr.h new file mode 100644 index 0000000..23721a8 --- /dev/null +++ b/libSBRdec/src/env_extr.h @@ -0,0 +1,261 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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 extraction prototypes $Revision: 36841 $ +*/ + +#ifndef __ENVELOPE_EXTRACTION_H +#define __ENVELOPE_EXTRACTION_H + +#include "sbrdecoder.h" + +#include "FDK_bitstream.h" +#include "lpp_tran.h" + +#include "psdec.h" + +#define ENV_EXP_FRACT 0 +/*!< Shift raw envelope data to support fractional numbers. + Can be set to 8 instead of 0 to enhance accuracy during concealment. + This is not required for conformance and #requantizeEnvelopeData() will + become more expensive. +*/ + +#define EXP_BITS 6 +/*!< Size of exponent-part of a pseudo float envelope value (should be at least 6). + The remaining bits in each word are used for the mantissa (should be at least 10). + This format is used in the arrays iEnvelope[] and sbrNoiseFloorLevel[] + in the FRAME_DATA struct which must fit in a certain part of the output buffer + (See buffer management in sbr_dec.cpp). + Exponents and mantissas could also be stored in separate arrays. + Accessing the exponent or the mantissa would be simplified and the masks #MASK_E + resp. #MASK_M would no longer be required. +*/ + +#define MASK_M (((1 << (FRACT_BITS - EXP_BITS)) - 1) << EXP_BITS) /*!< Mask for extracting the mantissa of a pseudo float envelope value */ +#define MASK_E ((1 << EXP_BITS) - 1) /*!< Mask for extracting the exponent of a pseudo float envelope value */ + +#define SIGN_EXT ( ((SCHAR)-1) ^ MASK_E) /*!< a CHAR-constant with all bits above our sign-bit set */ +#define ROUNDING ( (FIXP_SGL)(1<<(EXP_BITS-1)) ) /*!< 0.5-offset for rounding the mantissa of a pseudo-float envelope value */ +#define NRG_EXP_OFFSET 16 /*!< Will be added to the reference energy's exponent to prevent negative numbers */ +#define NOISE_EXP_OFFSET 38 /*!< Will be added to the noise level exponent to prevent negative numbers */ + +typedef enum +{ + HEADER_NOT_PRESENT, + HEADER_OK, + HEADER_RESET +} +SBR_HEADER_STATUS; + +typedef enum +{ + SBR_NOT_INITIALIZED, + UPSAMPLING, + SBR_HEADER, + SBR_ACTIVE +} +SBR_SYNC_STATE; + + +typedef enum +{ + COUPLING_OFF = 0, + COUPLING_LEVEL, + COUPLING_BAL +} +COUPLING_MODE; + +typedef struct +{ + UCHAR nSfb[2]; /*!< Number of SBR-bands for low and high freq-resolution */ + UCHAR nNfb; /*!< Actual number of noise bands to read from the bitstream*/ + UCHAR numMaster; /*!< Number of SBR-bands in v_k_master */ + UCHAR lowSubband; /*!< QMF-band where SBR frequency range starts */ + UCHAR highSubband; /*!< QMF-band where SBR frequency range ends */ + UCHAR limiterBandTable[MAX_NUM_LIMITERS+1]; /*!< Limiter band table. */ + UCHAR noLimiterBands; /*!< Number of limiter bands. */ + UCHAR nInvfBands; /*!< Number of bands for inverse filtering */ + UCHAR *freqBandTable[2]; /*!< Pointers to freqBandTableLo and freqBandTableHi */ + UCHAR freqBandTableLo[MAX_FREQ_COEFFS/2+1]; + /*!< Mapping of SBR bands to QMF bands for low frequency resolution */ + UCHAR freqBandTableHi[MAX_FREQ_COEFFS+1]; + /*!< Mapping of SBR bands to QMF bands for high frequency resolution */ + UCHAR freqBandTableNoise[MAX_NOISE_COEFFS+1]; + /*!< Mapping of SBR noise bands to QMF bands */ + UCHAR v_k_master[MAX_FREQ_COEFFS+1]; + /*!< Master BandTable which freqBandTable is derived from */ +} +FREQ_BAND_DATA; + +typedef FREQ_BAND_DATA *HANDLE_FREQ_BAND_DATA; + +#define SBRDEC_ELD_GRID 1 +#define SBRDEC_SYNTAX_SCAL 2 +#define SBRDEC_SYNTAX_USAC 4 +#define SBRDEC_SYNTAX_RSVD50 8 +#define SBRDEC_LOW_POWER 16 /* Flag indicating that Low Power QMF mode shall be used. */ +#define SBRDEC_PS_DECODED 32 /* Flag indicating that PS was decoded and rendered. */ +#define SBRDEC_LD_MPS_QMF 512 /* Flag indicating that the LD-MPS QMF shall be used. */ + +#define SBRDEC_HDR_STAT_RESET 1 +#define SBRDEC_HDR_STAT_UPDATE 2 + +typedef struct { + UCHAR ampResolution; /*!< Amplitude resolution of envelope values (0: 1.5dB, 1: 3dB) */ + UCHAR xover_band; /*!< Start index in #v_k_master[] used for dynamic crossover frequency */ + UCHAR sbr_preprocessing; /*!< SBR prewhitening flag. */ +} SBR_HEADER_DATA_BS_INFO; + +typedef struct { + /* Changes in these variables causes a reset of the decoder */ + UCHAR startFreq; /*!< Index for SBR start frequency */ + UCHAR stopFreq; /*!< Index for SBR highest frequency */ + UCHAR freqScale; /*!< 0: linear scale, 1-3 logarithmic scales */ + UCHAR alterScale; /*!< Flag for coarser frequency resolution */ + UCHAR noise_bands; /*!< Noise bands per octave, read from bitstream*/ + + /* don't require reset */ + UCHAR limiterBands; /*!< Index for number of limiter bands per octave */ + UCHAR limiterGains; /*!< Index to select gain limit */ + UCHAR interpolFreq; /*!< Select gain calculation method (1: per QMF channel, 0: per SBR band) */ + UCHAR smoothingLength; /*!< Smoothing of gains over time (0: on 1: off) */ + +} SBR_HEADER_DATA_BS; + +typedef struct +{ + SBR_SYNC_STATE syncState; /*!< The current initialization status of the header */ + + UCHAR status; /*!< Flags field used for signaling a reset right before the processing starts and an update from config (e.g. ASC). */ + UCHAR frameErrorFlag; /*!< Frame data valid flag. CAUTION: This variable will be overwritten by the flag stored in the element structure. + This is necessary because of the frame delay. There it might happen that different slots use the same header. */ + UCHAR numberTimeSlots; /*!< AAC: 16,15 */ + UCHAR numberOfAnalysisBands; /*!< Number of QMF analysis bands */ + UCHAR timeStep; /*!< Time resolution of SBR in QMF-slots */ + UINT sbrProcSmplRate; /*!< SBR processing sampling frequency (!= OutputSamplingRate) + (always: CoreSamplingRate * UpSamplingFactor; even in single rate mode) */ + + SBR_HEADER_DATA_BS bs_data; /*!< current SBR header. */ + SBR_HEADER_DATA_BS_INFO bs_info; /*!< SBR info. */ + + FREQ_BAND_DATA freqBandData; /*!< Pointer to struct #FREQ_BAND_DATA */ +} +SBR_HEADER_DATA; + +typedef SBR_HEADER_DATA *HANDLE_SBR_HEADER_DATA; + + +typedef struct +{ + UCHAR frameClass; /*!< Select grid type */ + UCHAR nEnvelopes; /*!< Number of envelopes */ + UCHAR borders[MAX_ENVELOPES+1]; /*!< Envelope borders (in SBR-timeslots, e.g. mp3PRO: 0..11) */ + UCHAR freqRes[MAX_ENVELOPES]; /*!< Frequency resolution for each envelope (0=low, 1=high) */ + SCHAR tranEnv; /*!< Transient envelope, -1 if none */ + UCHAR nNoiseEnvelopes; /*!< Number of noise envelopes */ + UCHAR bordersNoise[MAX_NOISE_ENVELOPES+1];/*!< borders of noise envelopes */ +} +FRAME_INFO; + + +typedef struct +{ + FIXP_SGL sfb_nrg_prev[MAX_FREQ_COEFFS]; /*!< Previous envelope (required for differential-coded values) */ + FIXP_SGL prevNoiseLevel[MAX_NOISE_COEFFS]; /*!< Previous noise envelope (required for differential-coded values) */ + COUPLING_MODE coupling; /*!< Stereo-mode of previous frame */ + INVF_MODE sbr_invf_mode[MAX_INVF_BANDS]; /*!< Previous strength of filtering in transposer */ + UCHAR ampRes; /*!< Previous amplitude resolution (0: 1.5dB, 1: 3dB) */ + UCHAR stopPos; /*!< Position in time where last envelope ended */ + UCHAR frameErrorFlag; /*!< Previous frame status */ +} +SBR_PREV_FRAME_DATA; + +typedef SBR_PREV_FRAME_DATA *HANDLE_SBR_PREV_FRAME_DATA; + + +typedef struct +{ + int nScaleFactors; /*!< total number of scalefactors in frame */ + + FRAME_INFO frameInfo; /*!< time grid for current frame */ + UCHAR domain_vec[MAX_ENVELOPES]; /*!< Bitfield containing direction of delta-coding for each envelope (0:frequency, 1:time) */ + UCHAR domain_vec_noise[MAX_NOISE_ENVELOPES]; /*!< Same as above, but for noise envelopes */ + + INVF_MODE sbr_invf_mode[MAX_INVF_BANDS]; /*!< Strength of filtering in transposer */ + COUPLING_MODE coupling; /*!< Stereo-mode */ + int ampResolutionCurrentFrame; /*!< Amplitude resolution of envelope values (0: 1.5dB, 1: 3dB) */ + + UCHAR addHarmonics[MAX_FREQ_COEFFS]; /*!< Flags for synthetic sine addition */ + + FIXP_SGL iEnvelope[MAX_NUM_ENVELOPE_VALUES]; /*!< Envelope data */ + FIXP_SGL sbrNoiseFloorLevel[MAX_NUM_NOISE_VALUES]; /*!< Noise envelope data */ +} +SBR_FRAME_DATA; + +typedef SBR_FRAME_DATA *HANDLE_SBR_FRAME_DATA; + +void initSbrPrevFrameData (HANDLE_SBR_PREV_FRAME_DATA h_prev_data, + int timeSlots); + + +int sbrGetSingleChannelElement (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA hFrameData, + HANDLE_FDK_BITSTREAM hBitBuf, + HANDLE_PS_DEC hParametricStereoDec, + const UINT flags, + const int overlap + ); + +int sbrGetChannelPairElement (HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA hFrameDataLeft, + HANDLE_SBR_FRAME_DATA hFrameDataRight, + HANDLE_FDK_BITSTREAM hBitBuf, + const UINT flags, + const int overlap); + +SBR_HEADER_STATUS +sbrGetHeaderData (HANDLE_SBR_HEADER_DATA headerData, + HANDLE_FDK_BITSTREAM hBitBuf, + const UINT flags, + const int fIsSbrData); + +/*! + \brief Initialize SBR header data + + Copy default values to the header data struct and patch some entries + depending on the core codec. +*/ +SBR_ERROR +initHeaderData ( + HANDLE_SBR_HEADER_DATA hHeaderData, + const int sampleRateIn, + const int sampleRateOut, + const int samplesPerFrame, + const UINT flags + ); +#endif diff --git a/libSBRdec/src/huff_dec.cpp b/libSBRdec/src/huff_dec.cpp new file mode 100644 index 0000000..1af3554 --- /dev/null +++ b/libSBRdec/src/huff_dec.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** + + (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 Huffman Decoder $Revision: 36841 $ +*/ + +#include "huff_dec.h" + +/***************************************************************************/ +/*! + \brief Decodes one huffman code word + + Reads bits from the bitstream until a valid codeword is found. + The table entries are interpreted either as index to the next entry + or - if negative - as the codeword. + + \return decoded value + + \author + +****************************************************************************/ +int +DecodeHuffmanCW (Huffman h, /*!< pointer to huffman codebook table */ + HANDLE_FDK_BITSTREAM hBs) /*!< Handle to Bitbuffer */ +{ + SCHAR index = 0; + int value, bit; + + while (index >= 0) { + bit = FDKreadBits (hBs, 1); + index = h[index][bit]; + } + + value = index+64; /* Add offset */ + + + return value; +} diff --git a/libSBRdec/src/huff_dec.h b/libSBRdec/src/huff_dec.h new file mode 100644 index 0000000..a113c0e --- /dev/null +++ b/libSBRdec/src/huff_dec.h @@ -0,0 +1,42 @@ +/**************************************************************************** + + (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 Huffman Decoder $Revision: 36841 $ +*/ +#ifndef __HUFF_DEC_H +#define __HUFF_DEC_H + +#include "sbrdecoder.h" +#include "FDK_bitstream.h" + +typedef const SCHAR (*Huffman)[2]; + +int +DecodeHuffmanCW (Huffman h, + HANDLE_FDK_BITSTREAM hBitBuf); + +#endif diff --git a/libSBRdec/src/lpp_tran.cpp b/libSBRdec/src/lpp_tran.cpp new file mode 100644 index 0000000..0a7721e --- /dev/null +++ b/libSBRdec/src/lpp_tran.cpp @@ -0,0 +1,942 @@ +/**************************************************************************** + + (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 Low Power Profile Transposer, $Revision: 36841 $ + This module provides the transposer. The main entry point is lppTransposer(). The function generates + high frequency content by copying data from the low band (provided by core codec) into the high band. + This process is also referred to as "patching". The function also implements spectral whitening by means of + inverse filtering based on LPC coefficients. + + Together with the QMF filterbank the transposer can be tested using a supplied test program. See main_audio.cpp for details. + This module does use fractional arithmetic and the accuracy of the computations has an impact on the overall sound quality. + The module also needs to take into account the different scaling of spectral data. + + \sa lppTransposer(), main_audio.cpp, sbr_scale.h, \ref documentationOverview +*/ + +#include "lpp_tran.h" + +#include "sbr_ram.h" +#include "sbr_rom.h" + +#include "genericStds.h" +#include "autocorr2nd.h" + + + +#if defined(__arm__) +#include "arm/lpp_tran_arm.cpp" +#endif + + + +#define LPC_SCALE_FACTOR 2 + + +/*! + * + * \brief Get bandwidth expansion factor from filtering level + * + * Returns a filter parameter (bandwidth expansion factor) depending on + * the desired filtering level signalled in the bitstream. + * When switching the filtering level from LOW to OFF, an additional + * level is being inserted to achieve a smooth transition. + */ + +#ifndef FUNCTION_mapInvfMode +static FIXP_DBL +mapInvfMode (INVF_MODE mode, + INVF_MODE prevMode, + WHITENING_FACTORS whFactors) +{ + switch (mode) { + case INVF_LOW_LEVEL: + if(prevMode == INVF_OFF) + return whFactors.transitionLevel; + else + return whFactors.lowLevel; + + case INVF_MID_LEVEL: + return whFactors.midLevel; + + case INVF_HIGH_LEVEL: + return whFactors.highLevel; + + default: + if(prevMode == INVF_LOW_LEVEL) + return whFactors.transitionLevel; + else + return whFactors.off; + } +} +#endif /* #ifndef FUNCTION_mapInvfMode */ + +/*! + * + * \brief Perform inverse filtering level emphasis + * + * Retrieve bandwidth expansion factor and apply smoothing for each filter band + * + */ + +#ifndef FUNCTION_inverseFilteringLevelEmphasis +static void +inverseFilteringLevelEmphasis(HANDLE_SBR_LPP_TRANS hLppTrans,/*!< Handle of lpp transposer */ + UCHAR nInvfBands, /*!< Number of bands for inverse filtering */ + INVF_MODE *sbr_invf_mode, /*!< Current inverse filtering modes */ + INVF_MODE *sbr_invf_mode_prev, /*!< Previous inverse filtering modes */ + FIXP_DBL * bwVector /*!< Resulting filtering levels */ + ) +{ + for(int i = 0; i < nInvfBands; i++) { + FIXP_DBL accu; + FIXP_DBL bwTmp = mapInvfMode (sbr_invf_mode[i], + sbr_invf_mode_prev[i], + hLppTrans->pSettings->whFactors); + + if(bwTmp < hLppTrans->bwVectorOld[i]) { + accu = fMultDiv2(FL2FXCONST_DBL(0.75f),bwTmp) + + fMultDiv2(FL2FXCONST_DBL(0.25f),hLppTrans->bwVectorOld[i]); + } + else { + accu = fMultDiv2(FL2FXCONST_DBL(0.90625f),bwTmp) + + fMultDiv2(FL2FXCONST_DBL(0.09375f),hLppTrans->bwVectorOld[i]); + } + + if (accu < FL2FXCONST_DBL(0.015625f)>>1) + bwVector[i] = FL2FXCONST_DBL(0.0f); + else + bwVector[i] = fixMin(accu<<1,FL2FXCONST_DBL(0.99609375f)); + } +} +#endif /* #ifndef FUNCTION_inverseFilteringLevelEmphasis */ + +/* Resulting autocorrelation determinant exponent */ +#define ACDET_EXP (2*(DFRACT_BITS+sbrScaleFactor->lb_scale+10-ac.det_scale)) +#define AC_EXP (-sbrScaleFactor->lb_scale+LPC_SCALE_FACTOR) +#define ALPHA_EXP (-sbrScaleFactor->lb_scale+LPC_SCALE_FACTOR+1) +/* Resulting transposed QMF values exponent 16 bit normalized samplebits assumed. */ +#define QMFOUT_EXP ((SAMPLE_BITS-15)-sbrScaleFactor->lb_scale) + +/*! + * + * \brief Perform transposition by patching of subband samples. + * This function serves as the main entry point into the module. The function determines the areas for the + * patching process (these are the source range as well as the target range) and implements spectral whitening + * by means of inverse filtering. The function autoCorrelation2nd() is an auxiliary function for calculating the + * LPC coefficients for the filtering. The actual calculation of the LPC coefficients and the implementation + * of the filtering are done as part of lppTransposer(). + * + * Note that the filtering is done on all available QMF subsamples, whereas the patching is only done on those QMF + * subsamples that will be used in the next QMF synthesis. The filtering is also implemented before the patching + * includes further dependencies on parameters from the SBR data. + * + */ + +void lppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */ + QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */ + FIXP_DBL **qmfBufferReal, /*!< Pointer to pointer to real part of subband samples (source) */ + + FIXP_DBL *degreeAlias, /*!< Vector for results of aliasing estimation */ + FIXP_DBL **qmfBufferImag, /*!< Pointer to pointer to imaginary part of subband samples (source) */ + const int useLP, + const int timeStep, /*!< Time step of envelope */ + const int firstSlotOffs, /*!< Start position in time */ + const int lastSlotOffs, /*!< Number of overlap-slots into next frame */ + const int nInvfBands, /*!< Number of bands for inverse filtering */ + INVF_MODE *sbr_invf_mode, /*!< Current inverse filtering modes */ + INVF_MODE *sbr_invf_mode_prev /*!< Previous inverse filtering modes */ + ) +{ + INT bwIndex[MAX_NUM_PATCHES]; + FIXP_DBL bwVector[MAX_NUM_PATCHES]; /*!< pole moving factors */ + + int i; + int loBand, start, stop; + TRANSPOSER_SETTINGS *pSettings = hLppTrans->pSettings; + PATCH_PARAM *patchParam = pSettings->patchParam; + int patch; + + FIXP_SGL alphar[LPC_ORDER], a0r, a1r; + FIXP_SGL alphai[LPC_ORDER], a0i=0, a1i=0; + FIXP_SGL bw = FL2FXCONST_SGL(0.0f); + + int autoCorrLength; + + FIXP_DBL k1, k1_below=0, k1_below2=0; + + ACORR_COEFS ac; + int startSample; + int stopSample; + int stopSampleClear; + + int comLowBandScale; + int ovLowBandShift; + int lowBandShift; +/* int ovHighBandShift;*/ + int targetStopBand; + + + alphai[0] = FL2FXCONST_SGL(0.0f); + alphai[1] = FL2FXCONST_SGL(0.0f); + + + startSample = firstSlotOffs * timeStep; + stopSample = pSettings->nCols + lastSlotOffs * timeStep; + + + inverseFilteringLevelEmphasis(hLppTrans, nInvfBands, sbr_invf_mode, sbr_invf_mode_prev, bwVector); + + stopSampleClear = stopSample; + + autoCorrLength = pSettings->nCols + pSettings->overlap; + + /* Set upper subbands to zero: + This is required in case that the patches do not cover the complete highband + (because the last patch would be too short). + Possible optimization: Clearing bands up to usb would be sufficient here. */ + targetStopBand = patchParam[pSettings->noOfPatches-1].targetStartBand + + patchParam[pSettings->noOfPatches-1].numBandsInPatch; + + int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL); + + if (!useLP) { + for (i = startSample; i < stopSampleClear; i++) { + FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize); + FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize); + } + } else + for (i = startSample; i < stopSampleClear; i++) { + FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize); + } + + /* init bwIndex for each patch */ + FDKmemclear(bwIndex, pSettings->noOfPatches*sizeof(INT)); + + /* + Calc common low band scale factor + */ + comLowBandScale = fixMin(sbrScaleFactor->ov_lb_scale,sbrScaleFactor->lb_scale); + + ovLowBandShift = sbrScaleFactor->ov_lb_scale - comLowBandScale; + lowBandShift = sbrScaleFactor->lb_scale - comLowBandScale; + /* ovHighBandShift = firstSlotOffs == 0 ? ovLowBandShift:0;*/ + + /* outer loop over bands to do analysis only once for each band */ + + if (!useLP) { + start = pSettings->lbStartPatching; + stop = pSettings->lbStopPatching; + } else + { + start = fixMax(1, pSettings->lbStartPatching - 2); + stop = patchParam[0].targetStartBand; + } + + + for ( loBand = start; loBand < stop; loBand++ ) { + + FIXP_DBL lowBandReal[(((1024)/(32))+(6))+LPC_ORDER]; + FIXP_DBL *plowBandReal = lowBandReal; + FIXP_DBL **pqmfBufferReal = qmfBufferReal; + FIXP_DBL lowBandImag[(((1024)/(32))+(6))+LPC_ORDER]; + FIXP_DBL *plowBandImag = lowBandImag; + FIXP_DBL **pqmfBufferImag = qmfBufferImag; + int resetLPCCoeffs=0; + int dynamicScale = DFRACT_BITS-1-LPC_SCALE_FACTOR; + int acDetScale = 0; /* scaling of autocorrelation determinant */ + + for(i=0;i<LPC_ORDER;i++){ + *plowBandReal++ = hLppTrans->lpcFilterStatesReal[i][loBand]; + if (!useLP) + *plowBandImag++ = hLppTrans->lpcFilterStatesImag[i][loBand]; + } + + /* + Take old slope length qmf slot source values out of (overlap)qmf buffer + */ + if (!useLP) { + for(i=0;i<pSettings->nCols+pSettings->overlap;i++){ + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + *plowBandImag++ = (*pqmfBufferImag++)[loBand]; + } + } else + { + /* pSettings->overlap is always even */ + FDK_ASSERT((pSettings->overlap & 1) == 0); + + for(i=0;i<((pSettings->overlap+pSettings->nCols)>>1);i++) { + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + } + if (pSettings->nCols & 1) { + *plowBandReal++ = (*pqmfBufferReal++)[loBand]; + } + } + + /* + Determine dynamic scaling value. + */ + dynamicScale = fixMin(dynamicScale, getScalefactor(lowBandReal, LPC_ORDER+pSettings->overlap) + ovLowBandShift); + dynamicScale = fixMin(dynamicScale, getScalefactor(&lowBandReal[LPC_ORDER+pSettings->overlap], pSettings->nCols) + lowBandShift); + if (!useLP) { + dynamicScale = fixMin(dynamicScale, getScalefactor(lowBandImag, LPC_ORDER+pSettings->overlap) + ovLowBandShift); + dynamicScale = fixMin(dynamicScale, getScalefactor(&lowBandImag[LPC_ORDER+pSettings->overlap], pSettings->nCols) + lowBandShift); + } + dynamicScale = fixMax(0, dynamicScale-1); /* one additional bit headroom to prevent -1.0 */ + + /* + Scale temporal QMF buffer. + */ + scaleValues(&lowBandReal[0], LPC_ORDER+pSettings->overlap, dynamicScale-ovLowBandShift); + scaleValues(&lowBandReal[LPC_ORDER+pSettings->overlap], pSettings->nCols, dynamicScale-lowBandShift); + + if (!useLP) { + scaleValues(&lowBandImag[0], LPC_ORDER+pSettings->overlap, dynamicScale-ovLowBandShift); + scaleValues(&lowBandImag[LPC_ORDER+pSettings->overlap], pSettings->nCols, dynamicScale-lowBandShift); + } + + + if (!useLP) { + acDetScale += autoCorr2nd_cplx(&ac, lowBandReal+LPC_ORDER, lowBandImag+LPC_ORDER, autoCorrLength); + } + else + { + acDetScale += autoCorr2nd_real(&ac, lowBandReal+LPC_ORDER, autoCorrLength); + } + + /* Examine dynamic of determinant in autocorrelation. */ + acDetScale += 2*(comLowBandScale + dynamicScale); + acDetScale *= 2; /* two times reflection coefficent scaling */ + acDetScale += ac.det_scale; /* ac scaling of determinant */ + + /* In case of determinant < 10^-38, resetLPCCoeffs=1 has to be enforced. */ + if (acDetScale>126 ) { + resetLPCCoeffs = 1; + } + + + alphar[1] = FL2FXCONST_SGL(0.0f); + if (!useLP) + alphai[1] = FL2FXCONST_SGL(0.0f); + + if (ac.det != FL2FXCONST_DBL(0.0f)) { + FIXP_DBL tmp,absTmp,absDet; + + absDet = fixp_abs(ac.det); + + if (!useLP) { + tmp = ( fMultDiv2(ac.r01r,ac.r12r) >> (LPC_SCALE_FACTOR-1) ) - + ( (fMultDiv2(ac.r01i,ac.r12i) + fMultDiv2(ac.r02r,ac.r11r)) >> (LPC_SCALE_FACTOR-1) ); + } else + { + tmp = ( fMultDiv2(ac.r01r,ac.r12r) >> (LPC_SCALE_FACTOR-1) ) - + ( fMultDiv2(ac.r02r,ac.r11r) >> (LPC_SCALE_FACTOR-1) ); + } + absTmp = fixp_abs(tmp); + + /* + Quick check: is first filter coeff >= 1(4) + */ + { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, absDet, &scale); + scale = scale+ac.det_scale; + + if ( (scale > 0) && (result >= (FIXP_DBL)MAXVAL_DBL>>scale) ) { + resetLPCCoeffs = 1; + } + else { + alphar[1] = FX_DBL2FX_SGL(scaleValue(result,scale)); + if((tmp<FL2FX_DBL(0.0f)) ^ (ac.det<FL2FX_DBL(0.0f))) { + alphar[1] = -alphar[1]; + } + } + } + + if (!useLP) + { + tmp = ( fMultDiv2(ac.r01i,ac.r12r) >> (LPC_SCALE_FACTOR-1) ) + + ( (fMultDiv2(ac.r01r,ac.r12i) - (FIXP_DBL)fMultDiv2(ac.r02i,ac.r11r)) >> (LPC_SCALE_FACTOR-1) ) ; + + absTmp = fixp_abs(tmp); + + /* + Quick check: is second filter coeff >= 1(4) + */ + { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, absDet, &scale); + scale = scale+ac.det_scale; + + if ( (scale > 0) && (result >= /*FL2FXCONST_DBL(1.f)*/ (FIXP_DBL)MAXVAL_DBL>>scale) ) { + resetLPCCoeffs = 1; + } + else { + alphai[1] = FX_DBL2FX_SGL(scaleValue(result,scale)); + if((tmp<FL2FX_DBL(0.0f)) ^ (ac.det<FL2FX_DBL(0.0f))) { + alphai[1] = -alphai[1]; + } + } + } + } + } + + alphar[0] = FL2FXCONST_SGL(0.0f); + if (!useLP) + alphai[0] = FL2FXCONST_SGL(0.0f); + + if ( ac.r11r != FL2FXCONST_DBL(0.0f) ) { + + /* ac.r11r is always >=0 */ + FIXP_DBL tmp,absTmp; + + if (!useLP) { + tmp = (ac.r01r>>(LPC_SCALE_FACTOR+1)) + + (fMultDiv2(alphar[1],ac.r12r) + fMultDiv2(alphai[1],ac.r12i)); + } else + { + if(ac.r01r>=FL2FXCONST_DBL(0.0f)) + tmp = (ac.r01r>>(LPC_SCALE_FACTOR+1)) + fMultDiv2(alphar[1],ac.r12r); + else + tmp = -((-ac.r01r)>>(LPC_SCALE_FACTOR+1)) + fMultDiv2(alphar[1],ac.r12r); + } + + absTmp = fixp_abs(tmp); + + /* + Quick check: is first filter coeff >= 1(4) + */ + + if (absTmp >= (ac.r11r>>1)) { + resetLPCCoeffs=1; + } + else { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); + alphar[0] = FX_DBL2FX_SGL(scaleValue(result,scale+1)); + + if((tmp>FL2FX_DBL(0.0f)) ^ (ac.r11r<FL2FX_DBL(0.0f))) + alphar[0] = -alphar[0]; + } + + if (!useLP) + { + tmp = (ac.r01i>>(LPC_SCALE_FACTOR+1)) + + (fMultDiv2(alphai[1],ac.r12r) - fMultDiv2(alphar[1],ac.r12i)); + + absTmp = fixp_abs(tmp); + + /* + Quick check: is second filter coeff >= 1(4) + */ + if (absTmp >= (ac.r11r>>1)) { + resetLPCCoeffs=1; + } + else { + INT scale; + FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale); + alphai[0] = FX_DBL2FX_SGL(scaleValue(result,scale+1)); + if((tmp>FL2FX_DBL(0.0f)) ^ (ac.r11r<FL2FX_DBL(0.0f))) + alphai[0] = -alphai[0]; + } + } + } + + + if (!useLP) + { + /* Now check the quadratic criteria */ + if( (fMultDiv2(alphar[0],alphar[0]) + fMultDiv2(alphai[0],alphai[0])) >= FL2FXCONST_DBL(0.5f) ) + resetLPCCoeffs=1; + if( (fMultDiv2(alphar[1],alphar[1]) + fMultDiv2(alphai[1],alphai[1])) >= FL2FXCONST_DBL(0.5f) ) + resetLPCCoeffs=1; + } + + if(resetLPCCoeffs){ + alphar[0] = FL2FXCONST_SGL(0.0f); + alphar[1] = FL2FXCONST_SGL(0.0f); + if (!useLP) + { + alphai[0] = FL2FXCONST_SGL(0.0f); + alphai[1] = FL2FXCONST_SGL(0.0f); + } + } + + if (useLP) + { + + /* Aliasing detection */ + if(ac.r11r==FL2FXCONST_DBL(0.0f)) { + k1 = FL2FXCONST_DBL(0.0f); + } + else { + if ( fixp_abs(ac.r01r) >= fixp_abs(ac.r11r) ) { + if ( fMultDiv2(ac.r01r,ac.r11r) < FL2FX_DBL(0.0f)) { + k1 = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_SGL(1.0f)*/; + }else { + /* Since this value is squared later, it must not ever become -1.0f. */ + k1 = (FIXP_DBL)(MINVAL_DBL+1) /*FL2FXCONST_SGL(-1.0f)*/; + } + } + else { + INT scale; + FIXP_DBL result = fDivNorm(fixp_abs(ac.r01r), fixp_abs(ac.r11r), &scale); + k1 = scaleValue(result,scale); + + if(!((ac.r01r<FL2FX_DBL(0.0f)) ^ (ac.r11r<FL2FX_DBL(0.0f)))) { + k1 = -k1; + } + } + } + if(loBand > 1){ + /* Check if the gain should be locked */ + FIXP_DBL deg = /*FL2FXCONST_DBL(1.0f)*/ (FIXP_DBL)MAXVAL_DBL - fPow2(k1_below); + degreeAlias[loBand] = FL2FXCONST_DBL(0.0f); + if (((loBand & 1) == 0) && (k1 < FL2FXCONST_DBL(0.0f))){ + if (k1_below < FL2FXCONST_DBL(0.0f)) { /* 2-Ch Aliasing Detection */ + degreeAlias[loBand] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + if ( k1_below2 > FL2FXCONST_DBL(0.0f) ) { /* 3-Ch Aliasing Detection */ + degreeAlias[loBand-1] = deg; + } + } + else if ( k1_below2 > FL2FXCONST_DBL(0.0f) ) { /* 3-Ch Aliasing Detection */ + degreeAlias[loBand] = deg; + } + } + if (((loBand & 1) == 1) && (k1 > FL2FXCONST_DBL(0.0f))){ + if (k1_below > FL2FXCONST_DBL(0.0f)) { /* 2-CH Aliasing Detection */ + degreeAlias[loBand] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + if ( k1_below2 < FL2FXCONST_DBL(0.0f) ) { /* 3-CH Aliasing Detection */ + degreeAlias[loBand-1] = deg; + } + } + else if ( k1_below2 < FL2FXCONST_DBL(0.0f) ) { /* 3-CH Aliasing Detection */ + degreeAlias[loBand] = deg; + } + } + } + /* remember k1 values of the 2 QMF channels below the current channel */ + k1_below2 = k1_below; + k1_below = k1; + } + + patch = 0; + + while ( patch < pSettings->noOfPatches ) { /* inner loop over every patch */ + + int hiBand = loBand + patchParam[patch].targetBandOffs; + + if ( loBand < patchParam[patch].sourceStartBand + || loBand >= patchParam[patch].sourceStopBand + //|| hiBand >= hLppTrans->pSettings->noChannels + ) { + /* Lowband not in current patch - proceed */ + patch++; + continue; + } + + FDK_ASSERT( hiBand < (64) ); + + /* bwIndex[patch] is already initialized with value from previous band inside this patch */ + while (hiBand >= pSettings->bwBorders[bwIndex[patch]]) + bwIndex[patch]++; + + + /* + Filter Step 2: add the left slope with the current filter to the buffer + pure source values are already in there + */ + bw = FX_DBL2FX_SGL(bwVector[bwIndex[patch]]); + + a0r = FX_DBL2FX_SGL(fMult(bw,alphar[0])); /* Apply current bandwidth expansion factor */ + + + if (!useLP) + a0i = FX_DBL2FX_SGL(fMult(bw,alphai[0])); + bw = FX_DBL2FX_SGL(fPow2(bw)); + a1r = FX_DBL2FX_SGL(fMult(bw,alphar[1])); + if (!useLP) + a1i = FX_DBL2FX_SGL(fMult(bw,alphai[1])); + + + + /* + Filter Step 3: insert the middle part which won't be windowed + */ + + if ( bw <= FL2FXCONST_SGL(0.0f) ) { + if (!useLP) { + int descale = fixMin(DFRACT_BITS-1, (LPC_SCALE_FACTOR+dynamicScale)); + for(i = startSample; i < stopSample; i++ ) { + qmfBufferReal[i][hiBand] = lowBandReal[LPC_ORDER+i]>>descale; + qmfBufferImag[i][hiBand] = lowBandImag[LPC_ORDER+i]>>descale; + } + } else + { + int descale = fixMin(DFRACT_BITS-1, (LPC_SCALE_FACTOR+dynamicScale)); + for(i = startSample; i < stopSample; i++ ) { + qmfBufferReal[i][hiBand] = lowBandReal[LPC_ORDER+i]>>descale; + } + } + } + else { /* bw <= 0 */ + + if (!useLP) { + int descale = fixMin(DFRACT_BITS-1, (LPC_SCALE_FACTOR+dynamicScale)); +#ifdef FUNCTION_LPPTRANSPOSER_func1 + lppTransposer_func1(lowBandReal+LPC_ORDER+startSample,lowBandImag+LPC_ORDER+startSample, + qmfBufferReal+startSample,qmfBufferImag+startSample, + stopSample-startSample, (int) hiBand, + dynamicScale,descale, + a0r, a0i, a1r, a1i); +#else + for(i = startSample; i < stopSample; i++ ) { + FIXP_DBL accu1, accu2; + + accu1 = (fMultDiv2(a0r,lowBandReal[LPC_ORDER+i-1]) - fMultDiv2(a0i,lowBandImag[LPC_ORDER+i-1]) + + fMultDiv2(a1r,lowBandReal[LPC_ORDER+i-2]) - fMultDiv2(a1i,lowBandImag[LPC_ORDER+i-2]))>>dynamicScale; + accu2 = (fMultDiv2(a0i,lowBandReal[LPC_ORDER+i-1]) + fMultDiv2(a0r,lowBandImag[LPC_ORDER+i-1]) + + fMultDiv2(a1i,lowBandReal[LPC_ORDER+i-2]) + fMultDiv2(a1r,lowBandImag[LPC_ORDER+i-2]))>>dynamicScale; + + qmfBufferReal[i][hiBand] = (lowBandReal[LPC_ORDER+i]>>descale) + (accu1<<1); + qmfBufferImag[i][hiBand] = (lowBandImag[LPC_ORDER+i]>>descale) + (accu2<<1); + } +#endif + } else + { + int descale = fixMin(DFRACT_BITS-1, (LPC_SCALE_FACTOR+dynamicScale)); + + FDK_ASSERT(dynamicScale >= 0); + for(i = startSample; i < stopSample; i++ ) { + FIXP_DBL accu1; + + accu1 = (fMultDiv2(a0r,lowBandReal[LPC_ORDER+i-1]) + fMultDiv2(a1r,lowBandReal[LPC_ORDER+i-2]))>>dynamicScale; + + qmfBufferReal[i][hiBand] = (lowBandReal[LPC_ORDER+i]>>descale) + (accu1<<1); + } + } + } /* bw <= 0 */ + + patch++; + + } /* inner loop over patches */ + + /* + * store the unmodified filter coefficients if there is + * an overlapping envelope + *****************************************************************/ + + + } /* outer loop over bands (loBand) */ + + if (useLP) + { + for ( loBand = pSettings->lbStartPatching; loBand < pSettings->lbStopPatching; loBand++ ) { + patch = 0; + while ( patch < pSettings->noOfPatches ) { + + UCHAR hiBand = loBand + patchParam[patch].targetBandOffs; + + if ( loBand < patchParam[patch].sourceStartBand + || loBand >= patchParam[patch].sourceStopBand + || hiBand >= (64) /* Highband out of range (biterror) */ + ) { + /* Lowband not in current patch or highband out of range (might be caused by biterrors)- proceed */ + patch++; + continue; + } + + if(hiBand != patchParam[patch].targetStartBand) + degreeAlias[hiBand] = degreeAlias[loBand]; + + patch++; + } + }/* end for loop */ + } + + for (i = 0; i < nInvfBands; i++ ) { + hLppTrans->bwVectorOld[i] = bwVector[i]; + } + + /* + set high band scale factor + */ + sbrScaleFactor->hb_scale = comLowBandScale-(LPC_SCALE_FACTOR); + +} + +/*! + * + * \brief Initialize one low power transposer instance + * + * + */ +SBR_ERROR +createLppTransposer (HANDLE_SBR_LPP_TRANS hs, /*!< Handle of low power transposer */ + TRANSPOSER_SETTINGS *pSettings, /*!< Pointer to settings */ + const int highBandStartSb, /*!< ? */ + UCHAR *v_k_master, /*!< Master table */ + const int numMaster, /*!< Valid entries in master table */ + const int usb, /*!< Highband area stop subband */ + const int timeSlots, /*!< Number of time slots */ + const int nCols, /*!< Number of colums (codec qmf bank) */ + UCHAR *noiseBandTable, /*!< Mapping of SBR noise bands to QMF bands */ + const int noNoiseBands, /*!< Number of noise bands */ + UINT fs, /*!< Sample Frequency */ + const int chan, /*!< Channel number */ + const int overlap + ) +{ + /* FB inverse filtering settings */ + hs->pSettings = pSettings; + + pSettings->nCols = nCols; + pSettings->overlap = overlap; + + switch (timeSlots) { + + case 15: + case 16: + break; + + default: + return SBRDEC_UNSUPPORTED_CONFIG; /* Unimplemented */ + } + + if (chan==0) { + /* Init common data only once */ + hs->pSettings->nCols = nCols; + + return resetLppTransposer (hs, + highBandStartSb, + v_k_master, + numMaster, + noiseBandTable, + noNoiseBands, + usb, + fs); + } + return SBRDEC_OK; +} + + +static int findClosestEntry(UCHAR goalSb, UCHAR *v_k_master, UCHAR numMaster, UCHAR direction) +{ + int index; + + if( goalSb <= v_k_master[0] ) + return v_k_master[0]; + + if( goalSb >= v_k_master[numMaster] ) + return v_k_master[numMaster]; + + if(direction) { + index = 0; + while( v_k_master[index] < goalSb ) { + index++; + } + } else { + index = numMaster; + while( v_k_master[index] > goalSb ) { + index--; + } + } + + return v_k_master[index]; +} + + +/*! + * + * \brief Reset memory for one lpp transposer instance + * + * \return SBRDEC_OK on success, SBRDEC_UNSUPPORTED_CONFIG on error + */ +SBR_ERROR +resetLppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */ + UCHAR highBandStartSb, /*!< High band area: start subband */ + UCHAR *v_k_master, /*!< Master table */ + UCHAR numMaster, /*!< Valid entries in master table */ + UCHAR *noiseBandTable, /*!< Mapping of SBR noise bands to QMF bands */ + UCHAR noNoiseBands, /*!< Number of noise bands */ + UCHAR usb, /*!< High band area: stop subband */ + UINT fs /*!< SBR output sampling frequency */ + ) +{ + TRANSPOSER_SETTINGS *pSettings = hLppTrans->pSettings; + PATCH_PARAM *patchParam = pSettings->patchParam; + + int i, patch; + int targetStopBand; + int sourceStartBand; + int patchDistance; + int numBandsInPatch; + + int lsb = v_k_master[0]; /* Start subband expressed in "non-critical" sampling terms*/ + int xoverOffset = highBandStartSb - lsb; /* Calculate distance in QMF bands between k0 and kx */ + int startFreqHz; + + int desiredBorder; + + usb = fixMin(usb, v_k_master[numMaster]); /* Avoid endless loops (compare with float code). */ + + /* + * Plausibility check + */ + + if ( lsb - SHIFT_START_SB < 4 ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + + /* + * Initialize the patching parameter + */ + desiredBorder = 21; + if (fs < 92017) { + desiredBorder = 23; + } + if (fs < 75132) { + desiredBorder = 32; + } + if (fs < 55426) { + desiredBorder = 43; + } + if (fs < 46009) { + desiredBorder = 46; + } + if (fs < 35777) { + desiredBorder = 64; + } + + desiredBorder = findClosestEntry(desiredBorder, v_k_master, numMaster, 1); /* Adapt region to master-table */ + + /* First patch */ + sourceStartBand = SHIFT_START_SB + xoverOffset; + targetStopBand = lsb + xoverOffset; /* upperBand */ + + /* Even (odd) numbered channel must be patched to even (odd) numbered channel */ + patch = 0; + while(targetStopBand < usb) { + + /* Too many patches? + Allow MAX_NUM_PATCHES+1 patches here. + we need to check later again, since patch might be the highest patch + AND contain less than 3 bands => actual number of patches will be reduced by 1. + */ + if (patch > MAX_NUM_PATCHES) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + patchParam[patch].guardStartBand = targetStopBand; + patchParam[patch].targetStartBand = targetStopBand; + + numBandsInPatch = desiredBorder - targetStopBand; /* Get the desired range of the patch */ + + if ( numBandsInPatch >= lsb - sourceStartBand ) { + /* Desired number bands are not available -> patch whole source range */ + patchDistance = targetStopBand - sourceStartBand; /* Get the targetOffset */ + patchDistance = patchDistance & ~1; /* Rounding off odd numbers and make all even */ + numBandsInPatch = lsb - (targetStopBand - patchDistance); /* Update number of bands to be patched */ + numBandsInPatch = findClosestEntry(targetStopBand + numBandsInPatch, v_k_master, numMaster, 0) - + targetStopBand; /* Adapt region to master-table */ + } + + /* Desired number bands are available -> get the minimal even patching distance */ + patchDistance = numBandsInPatch + targetStopBand - lsb; /* Get minimal distance */ + patchDistance = (patchDistance + 1) & ~1; /* Rounding up odd numbers and make all even */ + + if (numBandsInPatch > 0) { + patchParam[patch].sourceStartBand = targetStopBand - patchDistance; + patchParam[patch].targetBandOffs = patchDistance; + patchParam[patch].numBandsInPatch = numBandsInPatch; + patchParam[patch].sourceStopBand = patchParam[patch].sourceStartBand + numBandsInPatch; + + targetStopBand += patchParam[patch].numBandsInPatch; + patch++; + } + + /* All patches but first */ + sourceStartBand = SHIFT_START_SB; + + /* Check if we are close to desiredBorder */ + if( desiredBorder - targetStopBand < 3) /* MPEG doc */ + { + desiredBorder = usb; + } + + } + + patch--; + + /* If highest patch contains less than three subband: skip it */ + if ( (patch>0) && (patchParam[patch].numBandsInPatch < 3) ) { + patch--; + targetStopBand = patchParam[patch].targetStartBand + patchParam[patch].numBandsInPatch; + } + + /* now check if we don't have one too many */ + if (patch >= MAX_NUM_PATCHES) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + pSettings->noOfPatches = patch + 1; + + /* Check lowest and highest source subband */ + pSettings->lbStartPatching = targetStopBand; + pSettings->lbStopPatching = 0; + for ( patch = 0; patch < pSettings->noOfPatches; patch++ ) { + pSettings->lbStartPatching = fixMin( pSettings->lbStartPatching, patchParam[patch].sourceStartBand ); + pSettings->lbStopPatching = fixMax( pSettings->lbStopPatching, patchParam[patch].sourceStopBand ); + } + + for(i = 0 ; i < noNoiseBands; i++){ + pSettings->bwBorders[i] = noiseBandTable[i+1]; + } + + /* + * Choose whitening factors + */ + + startFreqHz = ( (lsb + xoverOffset)*fs ) >> 7; /* Shift does a division by 2*(64) */ + + for( i = 1; i < NUM_WHFACTOR_TABLE_ENTRIES; i++ ) + { + if( startFreqHz < FDK_sbrDecoder_sbr_whFactorsIndex[i]) + break; + } + i--; + + pSettings->whFactors.off = FDK_sbrDecoder_sbr_whFactorsTable[i][0]; + pSettings->whFactors.transitionLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][1]; + pSettings->whFactors.lowLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][2]; + pSettings->whFactors.midLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][3]; + pSettings->whFactors.highLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][4]; + + return SBRDEC_OK; +} diff --git a/libSBRdec/src/lpp_tran.h b/libSBRdec/src/lpp_tran.h new file mode 100644 index 0000000..dcaadd9 --- /dev/null +++ b/libSBRdec/src/lpp_tran.h @@ -0,0 +1,184 @@ +/**************************************************************************** + + (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 Low Power Profile Transposer, $Revision: 36841 $ +*/ + +#ifndef _LPP_TRANS_H +#define _LPP_TRANS_H + +#include "sbrdecoder.h" +#include "qmf.h" + +/* + Common +*/ +#define QMF_OUT_SCALE 8 + +/* + Env-Adjust +*/ +#define MAX_NOISE_ENVELOPES 2 +#define MAX_NOISE_COEFFS 5 +#define MAX_NUM_NOISE_VALUES (MAX_NOISE_ENVELOPES * MAX_NOISE_COEFFS) +#define MAX_NUM_LIMITERS 12 + +/* Set MAX_ENVELOPES to the largest value of all supported BSFORMATs + by overriding MAX_ENVELOPES in the correct order: */ +#define MAX_ENVELOPES_HEAAC 5 +#define MAX_ENVELOPES MAX_ENVELOPES_HEAAC + +#define MAX_FREQ_COEFFS 48 +#define MAX_FREQ_COEFFS_FS44100 35 +#define MAX_FREQ_COEFFS_FS48000 32 + + +#define MAX_NUM_ENVELOPE_VALUES (MAX_ENVELOPES * MAX_FREQ_COEFFS) + +#define MAX_GAIN_EXP 34 +/* Maximum gain will be sqrt(0.5 * 2^MAX_GAIN_EXP) + example: 34=99dB */ +#define MAX_GAIN_CONCEAL_EXP 1 +/* Maximum gain will be sqrt(0.5 * 2^MAX_GAIN_CONCEAL_EXP) in concealment case (0dB) */ + +/* + LPP Transposer +*/ +#define LPC_ORDER 2 + +#define MAX_INVF_BANDS MAX_NOISE_COEFFS + +#define MAX_NUM_PATCHES 6 +#define SHIFT_START_SB 1 /*!< lowest subband of source range */ + +typedef enum +{ + INVF_OFF = 0, + INVF_LOW_LEVEL, + INVF_MID_LEVEL, + INVF_HIGH_LEVEL, + INVF_SWITCHED /* not a real choice but used here to control behaviour */ +} +INVF_MODE; + + +/** parameter set for one single patch */ +typedef struct { + UCHAR sourceStartBand; /*!< first band in lowbands where to take the samples from */ + UCHAR sourceStopBand; /*!< first band in lowbands which is not included in the patch anymore */ + UCHAR guardStartBand; /*!< first band in highbands to be filled with zeros in order to + reduce interferences between patches */ + UCHAR targetStartBand; /*!< first band in highbands to be filled with whitened lowband signal */ + UCHAR targetBandOffs; /*!< difference between 'startTargetBand' and 'startSourceBand' */ + UCHAR numBandsInPatch; /*!< number of consecutive bands in this one patch */ +} PATCH_PARAM; + + +/** whitening factors for different levels of whitening + need to be initialized corresponding to crossover frequency */ +typedef struct { + FIXP_DBL off; /*!< bw factor for signal OFF */ + FIXP_DBL transitionLevel; + FIXP_DBL lowLevel; /*!< bw factor for signal LOW_LEVEL */ + FIXP_DBL midLevel; /*!< bw factor for signal MID_LEVEL */ + FIXP_DBL highLevel; /*!< bw factor for signal HIGH_LEVEL */ +} WHITENING_FACTORS; + + +/*! The transposer settings are calculated on a header reset and are shared by both channels. */ +typedef struct { + UCHAR nCols; /*!< number subsamples of a codec frame */ + UCHAR noOfPatches; /*!< number of patches */ + UCHAR lbStartPatching; /*!< first band of lowbands that will be patched */ + UCHAR lbStopPatching; /*!< first band that won't be patched anymore*/ + UCHAR bwBorders[MAX_NUM_NOISE_VALUES]; /*!< spectral bands with different inverse filtering levels */ + + PATCH_PARAM patchParam[MAX_NUM_PATCHES]; /*!< new parameter set for patching */ + WHITENING_FACTORS whFactors; /*!< the pole moving factors for certain whitening levels as indicated + in the bitstream depending on the crossover frequency */ + UCHAR overlap; /*!< Overlap size */ +} TRANSPOSER_SETTINGS; + + +typedef struct +{ + TRANSPOSER_SETTINGS *pSettings; /*!< Common settings for both channels */ + FIXP_DBL bwVectorOld[MAX_NUM_PATCHES]; /*!< pole moving factors of past frame */ + FIXP_DBL lpcFilterStatesReal[LPC_ORDER][(32)]; /*!< pointer array to save filter states */ + FIXP_DBL lpcFilterStatesImag[LPC_ORDER][(32)]; /*!< pointer array to save filter states */ +} +SBR_LPP_TRANS; + +typedef SBR_LPP_TRANS *HANDLE_SBR_LPP_TRANS; + + +void lppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans, + QMF_SCALE_FACTOR *sbrScaleFactor, + FIXP_DBL **qmfBufferReal, + + FIXP_DBL *degreeAlias, + FIXP_DBL **qmfBufferImag, + const int useLP, + const int timeStep, + const int firstSlotOffset, + const int lastSlotOffset, + const int nInvfBands, + INVF_MODE *sbr_invf_mode, + INVF_MODE *sbr_invf_mode_prev + ); + + +SBR_ERROR +createLppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans, + TRANSPOSER_SETTINGS *pSettings, + const int highBandStartSb, + UCHAR *v_k_master, + const int numMaster, + const int usb, + const int timeSlots, + const int nCols, + UCHAR *noiseBandTable, + const int noNoiseBands, + UINT fs, + const int chan, + const int overlap); + + +SBR_ERROR +resetLppTransposer (HANDLE_SBR_LPP_TRANS hLppTrans, + UCHAR highBandStartSb, + UCHAR *v_k_master, + UCHAR numMaster, + UCHAR *noiseBandTable, + UCHAR noNoiseBands, + UCHAR usb, + UINT fs); + + + +#endif /* _LPP_TRANS_H */ + diff --git a/libSBRdec/src/psbitdec.cpp b/libSBRdec/src/psbitdec.cpp new file mode 100644 index 0000000..0a5687a --- /dev/null +++ b/libSBRdec/src/psbitdec.cpp @@ -0,0 +1,536 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "psbitdec.h" + + +#include "sbr_rom.h" +#include "huff_dec.h" + +/* PS dec privat functions */ +SBR_ERROR ResetPsDec(HANDLE_PS_DEC h_ps_d); +void ResetPsDeCor (HANDLE_PS_DEC h_ps_d); + +/***************************************************************************/ +/*! + \brief huffman decoding by codebook table + + \return index of huffman codebook table + +****************************************************************************/ +static SCHAR +decode_huff_cw (Huffman h, /*!< pointer to huffman codebook table */ + HANDLE_FDK_BITSTREAM hBitBuf, /*!< Handle to Bitbuffer */ + int *length) /*!< length of huffman codeword (or NULL) */ +{ + UCHAR bit = 0; + SCHAR index = 0; + UCHAR bitCount = 0; + + while (index >= 0) { + bit = FDKreadBits (hBitBuf, 1); + bitCount++; + index = h[index][bit]; + } + if (length) { + *length = bitCount; + } + return( index+64 ); /* Add offset */ +} + +/***************************************************************************/ +/*! + \brief helper function - limiting of value to min/max values + + \return limited value + +****************************************************************************/ + +static SCHAR +limitMinMax(SCHAR i, + SCHAR min, + SCHAR max) +{ + if (i<min) + return min; + else if (i>max) + return max; + else + return i; +} + +/***************************************************************************/ +/*! + \brief Decodes delta values in-place and updates + data buffers according to quantization classes. + + When delta coded in frequency the first element is deltacode from zero. + aIndex buffer is decoded from delta values to actual values. + + \return none + +****************************************************************************/ +static void +deltaDecodeArray(SCHAR enable, + SCHAR *aIndex, /*!< ICC/IID parameters */ + SCHAR *aPrevFrameIndex, /*!< ICC/IID parameters of previous frame */ + SCHAR DtDf, + UCHAR nrElements, /*!< as conveyed in bitstream */ + /*!< output array size: nrElements*stride */ + UCHAR stride, /*!< 1=dflt, 2=half freq. resolution */ + SCHAR minIdx, + SCHAR maxIdx) +{ + int i; + + /* Delta decode */ + if ( enable==1 ) { + if (DtDf == 0) { /* Delta coded in freq */ + aIndex[0] = 0 + aIndex[0]; + aIndex[0] = limitMinMax(aIndex[0],minIdx,maxIdx); + for (i = 1; i < nrElements; i++) { + aIndex[i] = aIndex[i-1] + aIndex[i]; + aIndex[i] = limitMinMax(aIndex[i],minIdx,maxIdx); + } + } + else { /* Delta time */ + for (i = 0; i < nrElements; i++) { + aIndex[i] = aPrevFrameIndex[i*stride] + aIndex[i]; + aIndex[i] = limitMinMax(aIndex[i],minIdx,maxIdx); + } + } + } + else { /* No data is sent, set index to zero */ + for (i = 0; i < nrElements; i++) { + aIndex[i] = 0; + } + } + if (stride==2) { + for (i=nrElements*stride-1; i>0; i--) { + aIndex[i] = aIndex[i>>1]; + } + } +} + +/***************************************************************************/ +/*! + \brief Mapping of ICC/IID parameters to 20 stereo bands + + \return none + +****************************************************************************/ +static void map34IndexTo20 (SCHAR *aIndex, /*!< decoded ICC/IID parameters */ + UCHAR noBins) /*!< number of stereo bands */ +{ + aIndex[0] = (2*aIndex[0]+aIndex[1])/3; + aIndex[1] = (aIndex[1]+2*aIndex[2])/3; + aIndex[2] = (2*aIndex[3]+aIndex[4])/3; + aIndex[3] = (aIndex[4]+2*aIndex[5])/3; + aIndex[4] = (aIndex[6]+aIndex[7])/2; + aIndex[5] = (aIndex[8]+aIndex[9])/2; + aIndex[6] = aIndex[10]; + aIndex[7] = aIndex[11]; + aIndex[8] = (aIndex[12]+aIndex[13])/2; + aIndex[9] = (aIndex[14]+aIndex[15])/2; + aIndex[10] = aIndex[16]; + /* For IPD/OPD it stops here */ + + if (noBins == NO_HI_RES_BINS) + { + aIndex[11] = aIndex[17]; + aIndex[12] = aIndex[18]; + aIndex[13] = aIndex[19]; + aIndex[14] = (aIndex[20]+aIndex[21])/2; + aIndex[15] = (aIndex[22]+aIndex[23])/2; + aIndex[16] = (aIndex[24]+aIndex[25])/2; + aIndex[17] = (aIndex[26]+aIndex[27])/2; + aIndex[18] = (aIndex[28]+aIndex[29]+aIndex[30]+aIndex[31])/4; + aIndex[19] = (aIndex[32]+aIndex[33])/2; + } +} + +/***************************************************************************/ +/*! + \brief Decodes delta coded IID, ICC, IPD and OPD indices + + \return PS processing flag. If set to 1 + +****************************************************************************/ +int +DecodePs( struct PS_DEC *h_ps_d, /*!< PS handle */ + const UCHAR frameError ) /*!< Flag telling that frame had errors */ +{ + MPEG_PS_BS_DATA *pBsData; + UCHAR gr, env; + int bPsHeaderValid, bPsDataAvail; + + /* Shortcuts to avoid deferencing and keep the code readable */ + pBsData = &h_ps_d->bsData[h_ps_d->processSlot].mpeg; + bPsHeaderValid = pBsData->bPsHeaderValid; + bPsDataAvail = (h_ps_d->bPsDataAvail[h_ps_d->processSlot] == ppt_mpeg) ? 1 : 0; + + /*************************************************************************************** + * Decide whether to process or to conceal PS data or not. */ + + if ( ( h_ps_d->psDecodedPrv && !frameError && !bPsDataAvail) + || (!h_ps_d->psDecodedPrv && (frameError || !bPsDataAvail || !bPsHeaderValid)) ) { + /* Don't apply PS processing. + * Declare current PS header and bitstream data invalid. */ + pBsData->bPsHeaderValid = 0; + h_ps_d->bPsDataAvail[h_ps_d->processSlot] = ppt_none; + return (0); + } + + if (frameError || !bPsHeaderValid) + { /* no new PS data available (e.g. frame loss) */ + /* => keep latest data constant (i.e. FIX with noEnv=0) */ + pBsData->noEnv = 0; + } + + /*************************************************************************************** + * Decode bitstream payload or prepare parameter for concealment: + */ + for (env=0; env<pBsData->noEnv; env++) { + SCHAR *aPrevIidIndex; + SCHAR *aPrevIccIndex; + + UCHAR noIidSteps = pBsData->bFineIidQ?NO_IID_STEPS_FINE:NO_IID_STEPS; + + if (env==0) { + aPrevIidIndex = h_ps_d->specificTo.mpeg.aIidPrevFrameIndex; + aPrevIccIndex = h_ps_d->specificTo.mpeg.aIccPrevFrameIndex; + } + else { + aPrevIidIndex = pBsData->aaIidIndex[env-1]; + aPrevIccIndex = pBsData->aaIccIndex[env-1]; + } + + deltaDecodeArray(pBsData->bEnableIid, + pBsData->aaIidIndex[env], + aPrevIidIndex, + pBsData->abIidDtFlag[env], + FDK_sbrDecoder_aNoIidBins[pBsData->freqResIid], + (pBsData->freqResIid)?1:2, + -noIidSteps, + noIidSteps); + + deltaDecodeArray(pBsData->bEnableIcc, + pBsData->aaIccIndex[env], + aPrevIccIndex, + pBsData->abIccDtFlag[env], + FDK_sbrDecoder_aNoIccBins[pBsData->freqResIcc], + (pBsData->freqResIcc)?1:2, + 0, + NO_ICC_STEPS-1); + } /* for (env=0; env<pBsData->noEnv; env++) */ + + /* handling of FIX noEnv=0 */ + if (pBsData->noEnv==0) { + /* set noEnv=1, keep last parameters or force 0 if not enabled */ + pBsData->noEnv = 1; + + if (pBsData->bEnableIid) { + for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) { + pBsData->aaIidIndex[pBsData->noEnv-1][gr] = + h_ps_d->specificTo.mpeg.aIidPrevFrameIndex[gr]; + } + } + else { + for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) { + pBsData->aaIidIndex[pBsData->noEnv-1][gr] = 0; + } + } + + if (pBsData->bEnableIcc) { + for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) { + pBsData->aaIccIndex[pBsData->noEnv-1][gr] = + h_ps_d->specificTo.mpeg.aIccPrevFrameIndex[gr]; + } + } + else { + for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) { + pBsData->aaIccIndex[pBsData->noEnv-1][gr] = 0; + } + } + } + + /* Update previous frame index buffers */ + for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) { + h_ps_d->specificTo.mpeg.aIidPrevFrameIndex[gr] = + pBsData->aaIidIndex[pBsData->noEnv-1][gr]; + } + for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) { + h_ps_d->specificTo.mpeg.aIccPrevFrameIndex[gr] = + pBsData->aaIccIndex[pBsData->noEnv-1][gr]; + } + + /* PS data from bitstream (if avail) was decoded now */ + h_ps_d->bPsDataAvail[h_ps_d->processSlot] = ppt_none; + + /* handling of env borders for FIX & VAR */ + if (pBsData->bFrameClass == 0) { + /* FIX_BORDERS NoEnv=0,1,2,4 */ + pBsData->aEnvStartStop[0] = 0; + for (env=1; env<pBsData->noEnv; env++) { + pBsData->aEnvStartStop[env] = + (env * h_ps_d->noSubSamples) / pBsData->noEnv; + } + pBsData->aEnvStartStop[pBsData->noEnv] = h_ps_d->noSubSamples; + /* 1024 (32 slots) env borders: 0, 8, 16, 24, 32 */ + /* 960 (30 slots) env borders: 0, 7, 15, 22, 30 */ + } + else { /* if (h_ps_d->bFrameClass == 0) */ + /* VAR_BORDERS NoEnv=1,2,3,4 */ + pBsData->aEnvStartStop[0] = 0; + + /* handle case aEnvStartStop[noEnv]<noSubSample for VAR_BORDERS by + duplicating last PS parameters and incrementing noEnv */ + if (pBsData->aEnvStartStop[pBsData->noEnv] < h_ps_d->noSubSamples) { + for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) { + pBsData->aaIidIndex[pBsData->noEnv][gr] = + pBsData->aaIidIndex[pBsData->noEnv-1][gr]; + } + for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) { + pBsData->aaIccIndex[pBsData->noEnv][gr] = + pBsData->aaIccIndex[pBsData->noEnv-1][gr]; + } + pBsData->noEnv++; + pBsData->aEnvStartStop[pBsData->noEnv] = h_ps_d->noSubSamples; + } + + /* enforce strictly monotonic increasing borders */ + for (env=1; env<pBsData->noEnv; env++) { + UCHAR thr; + thr = (UCHAR)h_ps_d->noSubSamples - (pBsData->noEnv - env); + if (pBsData->aEnvStartStop[env] > thr) { + pBsData->aEnvStartStop[env] = thr; + } + else { + thr = pBsData->aEnvStartStop[env-1]+1; + if (pBsData->aEnvStartStop[env] < thr) { + pBsData->aEnvStartStop[env] = thr; + } + } + } + } /* if (h_ps_d->bFrameClass == 0) ... else */ + + /* copy data prior to possible 20<->34 in-place mapping */ + for (env=0; env<pBsData->noEnv; env++) { + UCHAR i; + for (i=0; i<NO_HI_RES_IID_BINS; i++) { + h_ps_d->specificTo.mpeg.coef.aaIidIndexMapped[env][i] = pBsData->aaIidIndex[env][i]; + } + for (i=0; i<NO_HI_RES_ICC_BINS; i++) { + h_ps_d->specificTo.mpeg.coef.aaIccIndexMapped[env][i] = pBsData->aaIccIndex[env][i]; + } + } + + + /* MPEG baseline PS */ + /* Baseline version of PS always uses the hybrid filter structure with 20 stereo bands. */ + /* If ICC/IID parameters for 34 stereo bands are decoded they have to be mapped to 20 */ + /* stereo bands. */ + /* Additionaly the IPD/OPD parameters won't be used. */ + + for (env=0; env<pBsData->noEnv; env++) { + if (pBsData->freqResIid == 2) + map34IndexTo20 (h_ps_d->specificTo.mpeg.coef.aaIidIndexMapped[env], NO_HI_RES_IID_BINS); + if (pBsData->freqResIcc == 2) + map34IndexTo20 (h_ps_d->specificTo.mpeg.coef.aaIccIndexMapped[env], NO_HI_RES_ICC_BINS); + + /* IPD/OPD is disabled in baseline version and thus was removed here */ + } + + return (1); +} + + +/***************************************************************************/ +/*! + + \brief Reads parametric stereo data from bitstream + + \return + +****************************************************************************/ +unsigned int +ReadPsData (HANDLE_PS_DEC h_ps_d, /*!< handle to struct PS_DEC */ + HANDLE_FDK_BITSTREAM hBitBuf, /*!< handle to struct BIT_BUF */ + int nBitsLeft /*!< max number of bits available */ + ) +{ + MPEG_PS_BS_DATA *pBsData; + + UCHAR gr, env; + SCHAR dtFlag; + INT startbits; + Huffman CurrentTable; + SCHAR bEnableHeader; + + if (!h_ps_d) + return 0; + + pBsData = &h_ps_d->bsData[h_ps_d->bsReadSlot].mpeg; + + if (h_ps_d->bsReadSlot != h_ps_d->bsLastSlot) { + /* Copy last header data */ + FDKmemcpy(pBsData, &h_ps_d->bsData[h_ps_d->bsLastSlot].mpeg, sizeof(MPEG_PS_BS_DATA)); + } + + + startbits = (INT) FDKgetValidBits(hBitBuf); + + bEnableHeader = (SCHAR) FDKreadBits (hBitBuf, 1); + + /* Read header */ + if (bEnableHeader) { + pBsData->bPsHeaderValid = 1; + pBsData->bEnableIid = (UCHAR) FDKreadBits (hBitBuf, 1); + if (pBsData->bEnableIid) { + pBsData->modeIid = (UCHAR) FDKreadBits (hBitBuf, 3); + } + + pBsData->bEnableIcc = (UCHAR) FDKreadBits (hBitBuf, 1); + if (pBsData->bEnableIcc) { + pBsData->modeIcc = (UCHAR) FDKreadBits (hBitBuf, 3); + } + + pBsData->bEnableExt = (UCHAR) FDKreadBits (hBitBuf, 1); + } + + pBsData->bFrameClass = (UCHAR) FDKreadBits (hBitBuf, 1); + if (pBsData->bFrameClass == 0) { + /* FIX_BORDERS NoEnv=0,1,2,4 */ + pBsData->noEnv = FDK_sbrDecoder_aFixNoEnvDecode[(UCHAR) FDKreadBits (hBitBuf, 2)]; + /* all additional handling of env borders is now in DecodePs() */ + } + else { + /* VAR_BORDERS NoEnv=1,2,3,4 */ + pBsData->noEnv = 1+(UCHAR) FDKreadBits (hBitBuf, 2); + for (env=1; env<pBsData->noEnv+1; env++) + pBsData->aEnvStartStop[env] = ((UCHAR) FDKreadBits (hBitBuf, 5)) + 1; + /* all additional handling of env borders is now in DecodePs() */ + } + + /* verify that IID & ICC modes (quant grid, freq res) are supported */ + if ((pBsData->modeIid > 5) || (pBsData->modeIcc > 5)) { + /* no useful PS data could be read from bitstream */ + h_ps_d->bPsDataAvail[h_ps_d->bsReadSlot] = ppt_none; + /* discard all remaining bits */ + nBitsLeft -= startbits - FDKgetValidBits(hBitBuf); + while (nBitsLeft) { + int i = nBitsLeft; + if (i>8) { + i = 8; + } + FDKreadBits (hBitBuf, i); + nBitsLeft -= i; + } + return (startbits - FDKgetValidBits(hBitBuf)); + } + + if (pBsData->modeIid > 2){ + pBsData->freqResIid = pBsData->modeIid-3; + pBsData->bFineIidQ = 1; + } + else{ + pBsData->freqResIid = pBsData->modeIid; + pBsData->bFineIidQ = 0; + } + + if (pBsData->modeIcc > 2){ + pBsData->freqResIcc = pBsData->modeIcc-3; + } + else{ + pBsData->freqResIcc = pBsData->modeIcc; + } + + + /* Extract IID data */ + if (pBsData->bEnableIid) { + for (env=0; env<pBsData->noEnv; env++) { + dtFlag = (SCHAR)FDKreadBits (hBitBuf, 1); + if (!dtFlag) + { + if (pBsData->bFineIidQ) + CurrentTable = (Huffman)&aBookPsIidFineFreqDecode; + else + CurrentTable = (Huffman)&aBookPsIidFreqDecode; + } + else + { + if (pBsData->bFineIidQ) + CurrentTable = (Huffman)&aBookPsIidFineTimeDecode; + else + CurrentTable = (Huffman)&aBookPsIidTimeDecode; + } + + for (gr = 0; gr < FDK_sbrDecoder_aNoIidBins[pBsData->freqResIid]; gr++) + pBsData->aaIidIndex[env][gr] = decode_huff_cw(CurrentTable,hBitBuf,NULL); + pBsData->abIidDtFlag[env] = dtFlag; + } + } + + /* Extract ICC data */ + if (pBsData->bEnableIcc) { + for (env=0; env<pBsData->noEnv; env++) { + dtFlag = (SCHAR)FDKreadBits (hBitBuf, 1); + if (!dtFlag) + CurrentTable = (Huffman)&aBookPsIccFreqDecode; + else + CurrentTable = (Huffman)&aBookPsIccTimeDecode; + + for (gr = 0; gr < FDK_sbrDecoder_aNoIccBins[pBsData->freqResIcc]; gr++) + pBsData->aaIccIndex[env][gr] = decode_huff_cw(CurrentTable,hBitBuf,NULL); + pBsData->abIccDtFlag[env] = dtFlag; + } + } + + if (pBsData->bEnableExt) { + + /*! + Decoders that support only the baseline version of the PS tool are allowed + to ignore the IPD/OPD data, but according header data has to be parsed. + ISO/IEC 14496-3 Subpart 8 Annex 4 + */ + + int cnt = FDKreadBits(hBitBuf, PS_EXTENSION_SIZE_BITS); + if (cnt == (1<<PS_EXTENSION_SIZE_BITS)-1) { + cnt += FDKreadBits(hBitBuf, PS_EXTENSION_ESC_COUNT_BITS); + } + while (cnt--) + FDKreadBits(hBitBuf, 8); + } + + + /* new PS data was read from bitstream */ + h_ps_d->bPsDataAvail[h_ps_d->bsReadSlot] = ppt_mpeg; + + + + return (startbits - FDKgetValidBits(hBitBuf)); +} + diff --git a/libSBRdec/src/psbitdec.h b/libSBRdec/src/psbitdec.h new file mode 100644 index 0000000..ff94bf8 --- /dev/null +++ b/libSBRdec/src/psbitdec.h @@ -0,0 +1,46 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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$ + +*******************************************************************************/ + +#ifndef __PSBITDEC_H +#define __PSBITDEC_H + +#include "sbrdecoder.h" + + +#include "psdec.h" + + +unsigned int +ReadPsData (struct PS_DEC *h_ps_d, + HANDLE_FDK_BITSTREAM hBs, + int nBitsLeft); + +int +DecodePs(struct PS_DEC *h_ps_d, + const UCHAR frameError); + + +#endif /* __PSBITDEC_H */ diff --git a/libSBRdec/src/psdec.cpp b/libSBRdec/src/psdec.cpp new file mode 100644 index 0000000..86ccdc4 --- /dev/null +++ b/libSBRdec/src/psdec.cpp @@ -0,0 +1,1356 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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 parametric stereo decoder $Revision: 36841 $ +*/ + +#include "psdec.h" + + + +#include "FDK_bitbuffer.h" +#include "psdec_hybrid.h" + +#include "sbr_rom.h" +#include "sbr_ram.h" + +#include "FDK_tools_rom.h" + +#include "genericStds.h" + +#include "FDK_trigFcts.h" + + +/********************************************************************/ +/* MLQUAL DEFINES */ +/********************************************************************/ + + #define FRACT_ZERO FRACT_BITS-1 +/********************************************************************/ + +SBR_ERROR ResetPsDec( HANDLE_PS_DEC h_ps_d ); + +void ResetPsDeCor( HANDLE_PS_DEC h_ps_d ); + + +/***** HELPERS *****/ + +static void assignTimeSlotsPS (FIXP_DBL *bufAdr, FIXP_DBL **bufPtr, const int numSlots, const int numChan); + + + +/*******************/ + +#define DIV3 FL2FXCONST_DBL(1.f/3.f) /* division 3.0 */ +#define DIV1_5 FL2FXCONST_DBL(2.f/3.f) /* division 1.5 */ + +/***************************************************************************/ +/*! + \brief Creates one instance of the PS_DEC struct + + \return Error info + +****************************************************************************/ +int +CreatePsDec( HANDLE_PS_DEC *h_PS_DEC, /*!< pointer to the module state */ + int aacSamplesPerFrame + ) +{ + SBR_ERROR errorInfo = SBRDEC_OK; + HANDLE_PS_DEC h_ps_d; + int i; + + if (*h_PS_DEC == NULL) { + /* Get ps dec ram */ + h_ps_d = GetRam_ps_dec(); + if (h_ps_d == NULL) { + errorInfo = SBRDEC_MEM_ALLOC_FAILED; + goto bail; + } + } else { + /* Reset an open instance */ + h_ps_d = *h_PS_DEC; + } + + /* initialisation */ + switch (aacSamplesPerFrame) { + case 960: + h_ps_d->noSubSamples = 30; /* col */ + break; + case 1024: + h_ps_d->noSubSamples = 32; /* col */ + break; + default: + h_ps_d->noSubSamples = -1; + break; + } + + if (h_ps_d->noSubSamples > MAX_NUM_COL + || h_ps_d->noSubSamples <= 0) + { + goto bail; + } + h_ps_d->noChannels = NO_QMF_CHANNELS; /* row */ + + h_ps_d->psDecodedPrv = 0; + h_ps_d->procFrameBased = -1; + for (i = 0; i < (1)+1; i++) { + h_ps_d->bPsDataAvail[i] = ppt_none; + } + + + for (i = 0; i < (1)+1; i++) { + FDKmemclear(&h_ps_d->bsData[i].mpeg, sizeof(MPEG_PS_BS_DATA)); + } + + errorInfo = ResetPsDec( h_ps_d ); + + if ( errorInfo != SBRDEC_OK ) + goto bail; + + ResetPsDeCor( h_ps_d ); + + *h_PS_DEC = h_ps_d; + + + + return 0; + +bail: + DeletePsDec(&h_ps_d); + + return -1; +} /*END CreatePsDec */ + +/***************************************************************************/ +/*! + \brief Delete one instance of the PS_DEC struct + + \return Error info + +****************************************************************************/ +int +DeletePsDec( HANDLE_PS_DEC *h_PS_DEC) /*!< pointer to the module state */ +{ + if (*h_PS_DEC == NULL) { + return -1; + } + + + FreeRam_ps_dec(h_PS_DEC); + + + return 0; +} /*END DeletePsDec */ + +/***************************************************************************/ +/*! + \brief resets some values of the PS handle to default states + + \return + +****************************************************************************/ +SBR_ERROR ResetPsDec( HANDLE_PS_DEC h_ps_d ) /*!< pointer to the module state */ +{ + SBR_ERROR errorInfo = SBRDEC_OK; + INT i; + + const UCHAR noQmfBandsInHybrid20 = 3; + /* const UCHAR noQmfBandsInHybrid34 = 5; */ + + const UCHAR aHybridResolution20[] = { HYBRID_8_CPLX, + HYBRID_2_REAL, + HYBRID_2_REAL }; + + h_ps_d->specificTo.mpeg.delayBufIndex = 0; + + /* explicitly init state variables to safe values (until first ps header arrives) */ + + h_ps_d->specificTo.mpeg.lastUsb = 0; + + h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer = -(DFRACT_BITS-1); + + FDKmemclear(h_ps_d->specificTo.mpeg.aDelayBufIndexDelayQmf, (NO_QMF_CHANNELS-FIRST_DELAY_SB)*sizeof(UCHAR)); + h_ps_d->specificTo.mpeg.noSampleDelay = delayIndexQmf[0]; + + for (i=0 ; i < NO_SERIAL_ALLPASS_LINKS; i++) { + h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[i] = 0; + } + + h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[0] = h_ps_d->specificTo.mpeg.aaQmfDelayBufReal; + + assignTimeSlotsPS ( h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[0] + (NO_QMF_CHANNELS-FIRST_DELAY_SB), + &h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[1], + h_ps_d->specificTo.mpeg.noSampleDelay-1, + (NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB)); + + h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[0] = h_ps_d->specificTo.mpeg.aaQmfDelayBufImag; + + assignTimeSlotsPS ( h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[0] + (NO_QMF_CHANNELS-FIRST_DELAY_SB), + &h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[1], + h_ps_d->specificTo.mpeg.noSampleDelay-1, + (NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB)); + + /* Hybrid Filter Bank 1 creation. */ + errorInfo = InitHybridFilterBank ( &h_ps_d->specificTo.mpeg.hybrid, + h_ps_d->noSubSamples, + noQmfBandsInHybrid20, + aHybridResolution20 ); + + for ( i = 0; i < NO_IID_GROUPS; i++ ) + { + h_ps_d->specificTo.mpeg.h11rPrev[i] = FL2FXCONST_DBL(0.5f); + h_ps_d->specificTo.mpeg.h12rPrev[i] = FL2FXCONST_DBL(0.5f); + } + + FDKmemclear( h_ps_d->specificTo.mpeg.h21rPrev, sizeof( h_ps_d->specificTo.mpeg.h21rPrev ) ); + FDKmemclear( h_ps_d->specificTo.mpeg.h22rPrev, sizeof( h_ps_d->specificTo.mpeg.h22rPrev ) ); + + return errorInfo; +} + +/***************************************************************************/ +/*! + \brief clear some buffers used in decorrelation process + + \return + +****************************************************************************/ +void ResetPsDeCor( HANDLE_PS_DEC h_ps_d ) /*!< pointer to the module state */ +{ + INT i; + + FDKmemclear(h_ps_d->specificTo.mpeg.aPeakDecayFastBin, NO_MID_RES_BINS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aPrevNrgBin, NO_MID_RES_BINS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aPrevPeakDiffBin, NO_MID_RES_BINS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aPowerPrevScal, NO_MID_RES_BINS*sizeof(SCHAR)); + + for (i=0 ; i < FIRST_DELAY_SB ; i++) { + FDKmemclear(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + } + for (i=0 ; i < NO_SUB_QMF_CHANNELS ; i++) { + FDKmemclear(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + } + +} + +/*******************************************************************************/ + +/* slot based funcion prototypes */ + +static void deCorrelateSlotBased( HANDLE_PS_DEC h_ps_d, + + FIXP_DBL *mHybridRealLeft, + FIXP_DBL *mHybridImagLeft, + SCHAR sf_mHybridLeft, + + FIXP_DBL *rIntBufferLeft, + FIXP_DBL *iIntBufferLeft, + SCHAR sf_IntBuffer, + + FIXP_DBL *mHybridRealRight, + FIXP_DBL *mHybridImagRight, + + FIXP_DBL *rIntBufferRight, + FIXP_DBL *iIntBufferRight ); + +static void applySlotBasedRotation( HANDLE_PS_DEC h_ps_d, + + FIXP_DBL *mHybridRealLeft, + FIXP_DBL *mHybridImagLeft, + + FIXP_DBL *QmfLeftReal, + FIXP_DBL *QmfLeftImag, + + FIXP_DBL *mHybridRealRight, + FIXP_DBL *mHybridImagRight, + + FIXP_DBL *QmfRightReal, + FIXP_DBL *QmfRightImag + ); + + +/***************************************************************************/ +/*! + \brief Get scale factor for all ps delay buffer. + + \return + +****************************************************************************/ +static +int getScaleFactorPsStatesBuffer(HANDLE_PS_DEC h_ps_d) +{ + INT i; + int scale = DFRACT_BITS-1; + + for (i=0; i<NO_QMF_BANDS_HYBRID20; i++) { + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.hybrid.mQmfBufferRealSlot[i], NO_SUB_QMF_CHANNELS)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.hybrid.mQmfBufferImagSlot[i], NO_SUB_QMF_CHANNELS)); + } + + for (i=0; i<NO_SAMPLE_DELAY_ALLPASS; i++) { + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaRealDelayBufferQmf[i], FIRST_DELAY_SB)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaImagDelayBufferQmf[i], FIRST_DELAY_SB)); + } + + for (i=0; i<NO_SAMPLE_DELAY_ALLPASS; i++) { + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaRealDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaImagDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS)); + } + + for (i=0; i<FIRST_DELAY_SB; i++) { + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS)); + } + + for (i=0; i<NO_SUB_QMF_CHANNELS; i++) { + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS)); + } + + for (i=0; i<MAX_DELAY_BUFFER_SIZE; i++) + { + INT len; + if (i==0) + len = NO_QMF_CHANNELS-FIRST_DELAY_SB; + else + len = NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB; + + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[i], len)); + scale = fMin(scale, getScalefactor(h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[i], len)); + } + + return (scale); +} + +/***************************************************************************/ +/*! + \brief Rescale all ps delay buffer. + + \return + +****************************************************************************/ +static +void scalePsStatesBuffer(HANDLE_PS_DEC h_ps_d, + int scale) +{ + INT i; + + if (scale < 0) + scale = fixMax((INT)scale,(INT)-(DFRACT_BITS-1)); + else + scale = fixMin((INT)scale,(INT)DFRACT_BITS-1); + + for (i=0; i<NO_QMF_BANDS_HYBRID20; i++) { + scaleValues( h_ps_d->specificTo.mpeg.hybrid.mQmfBufferRealSlot[i], NO_SUB_QMF_CHANNELS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.hybrid.mQmfBufferImagSlot[i], NO_SUB_QMF_CHANNELS, scale ); + } + + for (i=0; i<NO_SAMPLE_DELAY_ALLPASS; i++) { + scaleValues( h_ps_d->specificTo.mpeg.aaRealDelayBufferQmf[i], FIRST_DELAY_SB, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aaImagDelayBufferQmf[i], FIRST_DELAY_SB, scale ); + } + + for (i=0; i<NO_SAMPLE_DELAY_ALLPASS; i++) { + scaleValues( h_ps_d->specificTo.mpeg.aaRealDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aaImagDelayBufferSubQmf[i], NO_SUB_QMF_CHANNELS, scale ); + } + + for (i=0; i<FIRST_DELAY_SB; i++) { + scaleValues( h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); + } + + for (i=0; i<NO_SUB_QMF_CHANNELS; i++) { + scaleValues( h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[i], NO_DELAY_LENGTH_VECTORS, scale ); + } + + for (i=0; i<MAX_DELAY_BUFFER_SIZE; i++) { + INT len; + if (i==0) + len = NO_QMF_CHANNELS-FIRST_DELAY_SB; + else + len = NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB; + + scaleValues( h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[i], len, scale ); + scaleValues( h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[i], len, scale ); + } + + scale <<= 1; + + scaleValues( h_ps_d->specificTo.mpeg.aPeakDecayFastBin, NO_MID_RES_BINS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aPrevPeakDiffBin, NO_MID_RES_BINS, scale ); + scaleValues( h_ps_d->specificTo.mpeg.aPrevNrgBin, NO_MID_RES_BINS, scale ); +} + +/***************************************************************************/ +/*! + \brief Scale input channel to the same scalefactor and rescale hybrid + filterbank values + + \return + +****************************************************************************/ + +void scalFilterBankValues( HANDLE_PS_DEC h_ps_d, + FIXP_DBL **fixpQmfReal, + FIXP_DBL **fixpQmfImag, + int lsb, + int scaleFactorLowBandSplitLow, + int scaleFactorLowBandSplitHigh, + SCHAR *scaleFactorLowBand_lb, + SCHAR *scaleFactorLowBand_hb, + int scaleFactorHighBands, + INT *scaleFactorHighBand, + INT noCols + ) +{ + INT maxScal; + + INT i; + + scaleFactorHighBands = -scaleFactorHighBands; + scaleFactorLowBandSplitLow = -scaleFactorLowBandSplitLow; + scaleFactorLowBandSplitHigh = -scaleFactorLowBandSplitHigh; + + /* get max scale factor */ + maxScal = fixMax(scaleFactorHighBands,fixMax(scaleFactorLowBandSplitLow, scaleFactorLowBandSplitHigh )); + + { + int headroom = getScaleFactorPsStatesBuffer(h_ps_d); + maxScal = fixMax(maxScal,(INT)(h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer-headroom)); + maxScal += 1; + } + + /* scale whole left channel to the same scale factor */ + + /* low band ( overlap buffer ) */ + if ( maxScal != scaleFactorLowBandSplitLow ) { + INT scale = scaleFactorLowBandSplitLow - maxScal; + for ( i=0; i<(6); i++ ) { + scaleValues( fixpQmfReal[i], lsb, scale ); + scaleValues( fixpQmfImag[i], lsb, scale ); + } + } + /* low band ( current frame ) */ + if ( maxScal != scaleFactorLowBandSplitHigh ) { + INT scale = scaleFactorLowBandSplitHigh - maxScal; + /* for ( i=(6); i<(6)+MAX_NUM_COL; i++ ) { */ + for ( i=(6); i<(6)+noCols; i++ ) { + scaleValues( fixpQmfReal[i], lsb, scale ); + scaleValues( fixpQmfImag[i], lsb, scale ); + } + } + /* high band */ + if ( maxScal != scaleFactorHighBands ) { + INT scale = scaleFactorHighBands - maxScal; + /* for ( i=0; i<MAX_NUM_COL; i++ ) { */ + for ( i=0; i<noCols; i++ ) { + scaleValues( &fixpQmfReal[i][lsb], (64)-lsb, scale ); + scaleValues( &fixpQmfImag[i][lsb], (64)-lsb, scale ); + } + } + + if ( maxScal != h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer ) + scalePsStatesBuffer(h_ps_d,(h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer-maxScal)); + + h_ps_d->specificTo.mpeg.hybrid.sf_mQmfBuffer = maxScal; + h_ps_d->specificTo.mpeg.scaleFactorPsDelayBuffer = maxScal; + + *scaleFactorHighBand += maxScal - scaleFactorHighBands; + + h_ps_d->rescal = maxScal - scaleFactorLowBandSplitHigh; + h_ps_d->sf_IntBuffer = maxScal; + + *scaleFactorLowBand_lb += maxScal - scaleFactorLowBandSplitLow; + *scaleFactorLowBand_hb += maxScal - scaleFactorLowBandSplitHigh; +} + +void rescalFilterBankValues( HANDLE_PS_DEC h_ps_d, /* parametric stereo decoder handle */ + FIXP_DBL **QmfBufferReal, /* qmf filterbank values */ + FIXP_DBL **QmfBufferImag, /* qmf filterbank values */ + int lsb, /* sbr start subband */ + INT noCols) +{ + int i; + /* scale back 6 timeslots look ahead for hybrid filterbank to original value */ + for ( i=noCols; i<noCols + (6); i++ ) { + scaleValues( QmfBufferReal[i], lsb, h_ps_d->rescal ); + scaleValues( QmfBufferImag[i], lsb, h_ps_d->rescal ); + } +} + +/***************************************************************************/ +/*! + \brief Generate decorrelated side channel using allpass/delay + + \return + +****************************************************************************/ +static void +deCorrelateSlotBased( HANDLE_PS_DEC h_ps_d, /*!< pointer to the module state */ + + FIXP_DBL *mHybridRealLeft, /*!< left (mono) hybrid values real */ + FIXP_DBL *mHybridImagLeft, /*!< left (mono) hybrid values imag */ + SCHAR sf_mHybridLeft, /*!< scalefactor for left (mono) hybrid bands */ + + FIXP_DBL *rIntBufferLeft, /*!< real qmf bands left (mono) (38x64) */ + FIXP_DBL *iIntBufferLeft, /*!< real qmf bands left (mono) (38x64) */ + SCHAR sf_IntBuffer, /*!< scalefactor for all left and right qmf bands */ + + FIXP_DBL *mHybridRealRight, /*!< right (decorrelated) hybrid values real */ + FIXP_DBL *mHybridImagRight, /*!< right (decorrelated) hybrid values imag */ + + FIXP_DBL *rIntBufferRight, /*!< real qmf bands right (decorrelated) (38x64) */ + FIXP_DBL *iIntBufferRight ) /*!< real qmf bands right (decorrelated) (38x64) */ +{ + + INT i, m, sb, gr, bin; + + FIXP_DBL peakDiff, nrg, transRatio; + + FIXP_DBL *RESTRICT aaLeftReal; + FIXP_DBL *RESTRICT aaLeftImag; + + FIXP_DBL *RESTRICT aaRightReal; + FIXP_DBL *RESTRICT aaRightImag; + + FIXP_DBL *RESTRICT pRealDelayBuffer; + FIXP_DBL *RESTRICT pImagDelayBuffer; + + C_ALLOC_SCRATCH_START(aaPowerSlot, FIXP_DBL, NO_MID_RES_BINS); + C_ALLOC_SCRATCH_START(aaTransRatioSlot, FIXP_DBL, NO_MID_RES_BINS); + +/*! +<pre> + parameter index qmf bands hybrid bands + ---------------------------------------------------------------------------- + 0 0 0,7 + 1 0 1,6 + 2 0 2 + 3 0 3 HYBRID BANDS + 4 1 9 + 5 1 8 + 6 2 10 + 7 2 11 + ---------------------------------------------------------------------------- + 8 3 + 9 4 + 10 5 + 11 6 + 12 7 + 13 8 + 14 9,10 (2 ) QMF BANDS + 15 11 - 13 (3 ) + 16 14 - 17 (4 ) + 17 18 - 22 (5 ) + 18 23 - 34 (12) + 19 35 - 63 (29) + ---------------------------------------------------------------------------- +</pre> +*/ + + #define FLTR_SCALE 3 + + /* hybrid bands (parameter index 0 - 7) */ + aaLeftReal = mHybridRealLeft; + aaLeftImag = mHybridImagLeft; + + aaPowerSlot[0] = ( fMultAddDiv2( fMultDiv2(aaLeftReal[0], aaLeftReal[0]), aaLeftImag[0], aaLeftImag[0] ) >> FLTR_SCALE ) + + ( fMultAddDiv2( fMultDiv2(aaLeftReal[7], aaLeftReal[7]), aaLeftImag[7], aaLeftImag[7] ) >> FLTR_SCALE ); + + aaPowerSlot[1] = ( fMultAddDiv2( fMultDiv2(aaLeftReal[1], aaLeftReal[1]), aaLeftImag[1], aaLeftImag[1] ) >> FLTR_SCALE ) + + ( fMultAddDiv2( fMultDiv2(aaLeftReal[6], aaLeftReal[6]), aaLeftImag[6], aaLeftImag[6] ) >> FLTR_SCALE ); + + aaPowerSlot[2] = fMultAddDiv2( fMultDiv2(aaLeftReal[2], aaLeftReal[2]), aaLeftImag[2], aaLeftImag[2] ) >> FLTR_SCALE; + aaPowerSlot[3] = fMultAddDiv2( fMultDiv2(aaLeftReal[3], aaLeftReal[3]), aaLeftImag[3], aaLeftImag[3] ) >> FLTR_SCALE; + + aaPowerSlot[4] = fMultAddDiv2( fMultDiv2(aaLeftReal[9], aaLeftReal[9]), aaLeftImag[9], aaLeftImag[9] ) >> FLTR_SCALE; + aaPowerSlot[5] = fMultAddDiv2( fMultDiv2(aaLeftReal[8], aaLeftReal[8]), aaLeftImag[8], aaLeftImag[8] ) >> FLTR_SCALE; + + aaPowerSlot[6] = fMultAddDiv2( fMultDiv2(aaLeftReal[10], aaLeftReal[10]), aaLeftImag[10], aaLeftImag[10] ) >> FLTR_SCALE; + aaPowerSlot[7] = fMultAddDiv2( fMultDiv2(aaLeftReal[11], aaLeftReal[11]), aaLeftImag[11], aaLeftImag[11] ) >> FLTR_SCALE; + + /* qmf bands (parameter index 8 - 19) */ + for ( bin = 8; bin < NO_MID_RES_BINS; bin++ ) { + FIXP_DBL slotNrg = FL2FXCONST_DBL(0.f); + + for ( i = groupBorders20[bin+2]; i < groupBorders20[bin+3]; i++ ) { /* max loops: 29 */ + slotNrg += fMultAddDiv2 ( fMultDiv2(rIntBufferLeft[i], rIntBufferLeft[i]), iIntBufferLeft[i], iIntBufferLeft[i]) >> FLTR_SCALE; + } + aaPowerSlot[bin] = slotNrg; + + } + + + /* calculation of transient ratio */ + for (bin=0; bin < NO_MID_RES_BINS; bin++) { /* noBins = 20 ( BASELINE_PS ) */ + + h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] = fMult( h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin], PEAK_DECAY_FACTOR ); + + if (h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] < aaPowerSlot[bin]) { + h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] = aaPowerSlot[bin]; + } + + /* calculate PSmoothPeakDecayDiffNrg */ + peakDiff = fMultAdd ( (h_ps_d->specificTo.mpeg.aPrevPeakDiffBin[bin]>>1), + INT_FILTER_COEFF, h_ps_d->specificTo.mpeg.aPeakDecayFastBin[bin] - aaPowerSlot[bin] - h_ps_d->specificTo.mpeg.aPrevPeakDiffBin[bin]); + + /* save peakDiff for the next frame */ + h_ps_d->specificTo.mpeg.aPrevPeakDiffBin[bin] = peakDiff; + + nrg = h_ps_d->specificTo.mpeg.aPrevNrgBin[bin] + fMult( INT_FILTER_COEFF, aaPowerSlot[bin] - h_ps_d->specificTo.mpeg.aPrevNrgBin[bin] ); + + /* Negative energies don't exist. But sometimes they appear due to rounding. */ + + nrg = fixMax(nrg,FL2FXCONST_DBL(0.f)); + + /* save nrg for the next frame */ + h_ps_d->specificTo.mpeg.aPrevNrgBin[bin] = nrg; + + nrg = fMult( nrg, TRANSIENT_IMPACT_FACTOR ); + + /* save transient impact factor */ + if ( peakDiff <= nrg || peakDiff == FL2FXCONST_DBL(0.0) ) { + aaTransRatioSlot[bin] = (FIXP_DBL)MAXVAL_DBL /* FL2FXCONST_DBL(1.0f)*/; + } + else if ( nrg <= FL2FXCONST_DBL(0.0f) ) { + aaTransRatioSlot[bin] = FL2FXCONST_DBL(0.f); + } + else { + /* scale to denominator */ + INT scale_left = fixMax(0, CntLeadingZeros(peakDiff) - 1); + aaTransRatioSlot[bin] = schur_div( nrg<<scale_left, peakDiff<<scale_left, 16); + } + } /* bin */ + + + + + #define DELAY_GROUP_OFFSET 20 + #define NR_OF_DELAY_GROUPS 2 + + FIXP_DBL rTmp, iTmp, rTmp0, iTmp0, rR0, iR0; + + INT TempDelay = h_ps_d->specificTo.mpeg.delayBufIndex; /* set delay indices */ + + pRealDelayBuffer = h_ps_d->specificTo.mpeg.aaRealDelayBufferSubQmf[TempDelay]; + pImagDelayBuffer = h_ps_d->specificTo.mpeg.aaImagDelayBufferSubQmf[TempDelay]; + + aaLeftReal = mHybridRealLeft; + aaLeftImag = mHybridImagLeft; + aaRightReal = mHybridRealRight; + aaRightImag = mHybridImagRight; + + /************************/ + /* ICC groups : 0 - 9 */ + /************************/ + + /* gr = ICC groups */ + for (gr=0; gr < SUBQMF_GROUPS; gr++) { + + transRatio = aaTransRatioSlot[bins2groupMap20[gr]]; + + /* sb = subQMF/QMF subband */ + sb = groupBorders20[gr]; + + /* Update delay buffers, sample delay allpass = 2 */ + rTmp0 = pRealDelayBuffer[sb]; + iTmp0 = pImagDelayBuffer[sb]; + + pRealDelayBuffer[sb] = aaLeftReal[sb]; + pImagDelayBuffer[sb] = aaLeftImag[sb]; + + /* delay by fraction */ + cplxMultDiv2(&rR0, &iR0, rTmp0, iTmp0, aaFractDelayPhaseFactorReSubQmf20[sb], aaFractDelayPhaseFactorImSubQmf20[sb]); + rR0<<=1; + iR0<<=1; + + FIXP_DBL *pAaaRealDelayRBufferSerSubQmf = h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerSubQmf[sb]; + FIXP_DBL *pAaaImagDelayRBufferSerSubQmf = h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerSubQmf[sb]; + + for (m=0; m<NO_SERIAL_ALLPASS_LINKS ; m++) { + + INT tmpDelayRSer = h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[m]; + + /* get delayed values from according buffer : m(0)=3; m(1)=4; m(2)=5; */ + rTmp0 = pAaaRealDelayRBufferSerSubQmf[tmpDelayRSer]; + iTmp0 = pAaaImagDelayRBufferSerSubQmf[tmpDelayRSer]; + + /* delay by fraction */ + cplxMultDiv2(&rTmp, &iTmp, rTmp0, iTmp0, aaFractDelayPhaseFactorSerReSubQmf20[sb][m], aaFractDelayPhaseFactorSerImSubQmf20[sb][m]); + + rTmp = (rTmp - fMultDiv2(aAllpassLinkDecaySer[m], rR0)) << 1; + iTmp = (iTmp - fMultDiv2(aAllpassLinkDecaySer[m], iR0)) << 1; + + pAaaRealDelayRBufferSerSubQmf[tmpDelayRSer] = rR0 + fMult(aAllpassLinkDecaySer[m], rTmp); + pAaaImagDelayRBufferSerSubQmf[tmpDelayRSer] = iR0 + fMult(aAllpassLinkDecaySer[m], iTmp); + + rR0 = rTmp; + iR0 = iTmp; + + pAaaRealDelayRBufferSerSubQmf += aAllpassLinkDelaySer[m]; + pAaaImagDelayRBufferSerSubQmf += aAllpassLinkDelaySer[m]; + + } /* m */ + + /* duck if a past transient is found */ + aaRightReal[sb] = fMult(transRatio, rR0); + aaRightImag[sb] = fMult(transRatio, iR0); + + } /* gr */ + + + scaleValues( mHybridRealLeft, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); + scaleValues( mHybridImagLeft, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); + scaleValues( mHybridRealRight, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); + scaleValues( mHybridImagRight, NO_SUB_QMF_CHANNELS, -SCAL_HEADROOM ); + + + /************************/ + + aaLeftReal = rIntBufferLeft; + aaLeftImag = iIntBufferLeft; + aaRightReal = rIntBufferRight; + aaRightImag = iIntBufferRight; + + pRealDelayBuffer = h_ps_d->specificTo.mpeg.aaRealDelayBufferQmf[TempDelay]; + pImagDelayBuffer = h_ps_d->specificTo.mpeg.aaImagDelayBufferQmf[TempDelay]; + + /************************/ + /* ICC groups : 10 - 19 */ + /************************/ + + + /* gr = ICC groups */ + for (gr=SUBQMF_GROUPS; gr < NO_IID_GROUPS - NR_OF_DELAY_GROUPS; gr++) { + + transRatio = aaTransRatioSlot[bins2groupMap20[gr]]; + + /* sb = subQMF/QMF subband */ + for (sb = groupBorders20[gr]; sb < groupBorders20[gr+1]; sb++) { + FIXP_DBL resR, resI; + + /* decayScaleFactor = 1.0f + decay_cutoff * DECAY_SLOPE - DECAY_SLOPE * sb; DECAY_SLOPE = 0.05 */ + FIXP_DBL decayScaleFactor = decayScaleFactTable[sb]; + + /* Update delay buffers, sample delay allpass = 2 */ + rTmp0 = pRealDelayBuffer[sb]; + iTmp0 = pImagDelayBuffer[sb]; + + pRealDelayBuffer[sb] = aaLeftReal[sb]; + pImagDelayBuffer[sb] = aaLeftImag[sb]; + + /* delay by fraction */ + cplxMultDiv2(&rR0, &iR0, rTmp0, iTmp0, aaFractDelayPhaseFactorReQmf[sb], aaFractDelayPhaseFactorImQmf[sb]); + rR0<<=1; + iR0<<=1; + + resR = fMult(decayScaleFactor, rR0); + resI = fMult(decayScaleFactor, iR0); + + FIXP_DBL *pAaaRealDelayRBufferSerQmf = h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[sb]; + FIXP_DBL *pAaaImagDelayRBufferSerQmf = h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[sb]; + + for (m=0; m<NO_SERIAL_ALLPASS_LINKS ; m++) { + + INT tmpDelayRSer = h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[m]; + + /* get delayed values from according buffer : m(0)=3; m(1)=4; m(2)=5; */ + rTmp0 = pAaaRealDelayRBufferSerQmf[tmpDelayRSer]; + iTmp0 = pAaaImagDelayRBufferSerQmf[tmpDelayRSer]; + + /* delay by fraction */ + cplxMultDiv2(&rTmp, &iTmp, rTmp0, iTmp0, aaFractDelayPhaseFactorSerReQmf[sb][m], aaFractDelayPhaseFactorSerImQmf[sb][m]); + + rTmp = (rTmp - fMultDiv2(aAllpassLinkDecaySer[m], resR))<<1; + iTmp = (iTmp - fMultDiv2(aAllpassLinkDecaySer[m], resI))<<1; + + resR = fMult(decayScaleFactor, rTmp); + resI = fMult(decayScaleFactor, iTmp); + + pAaaRealDelayRBufferSerQmf[tmpDelayRSer] = rR0 + fMult(aAllpassLinkDecaySer[m], resR); + pAaaImagDelayRBufferSerQmf[tmpDelayRSer] = iR0 + fMult(aAllpassLinkDecaySer[m], resI); + + rR0 = rTmp; + iR0 = iTmp; + + pAaaRealDelayRBufferSerQmf += aAllpassLinkDelaySer[m]; + pAaaImagDelayRBufferSerQmf += aAllpassLinkDelaySer[m]; + + } /* m */ + + /* duck if a past transient is found */ + aaRightReal[sb] = fMult(transRatio, rR0); + aaRightImag[sb] = fMult(transRatio, iR0); + + } /* sb */ + } /* gr */ + + /************************/ + /* ICC groups : 20, 21 */ + /************************/ + + + /* gr = ICC groups */ + for (gr=DELAY_GROUP_OFFSET; gr < NO_IID_GROUPS; gr++) { + + INT sbStart = groupBorders20[gr]; + INT sbStop = groupBorders20[gr+1]; + + UCHAR *pDelayBufIdx = &h_ps_d->specificTo.mpeg.aDelayBufIndexDelayQmf[sbStart-FIRST_DELAY_SB]; + + transRatio = aaTransRatioSlot[bins2groupMap20[gr]]; + + /* sb = subQMF/QMF subband */ + for (sb = sbStart; sb < sbStop; sb++) { + + /* Update delay buffers */ + rR0 = h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB]; + iR0 = h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB]; + + h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB] = aaLeftReal[sb]; + h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[*pDelayBufIdx][sb-FIRST_DELAY_SB] = aaLeftImag[sb]; + + /* duck if a past transient is found */ + aaRightReal[sb] = fMult(transRatio, rR0); + aaRightImag[sb] = fMult(transRatio, iR0); + + if (++(*pDelayBufIdx) >= delayIndexQmf[sb]) { + *pDelayBufIdx = 0; + } + pDelayBufIdx++; + + } /* sb */ + } /* gr */ + + + /* Update delay buffer index */ + if (++h_ps_d->specificTo.mpeg.delayBufIndex >= NO_SAMPLE_DELAY_ALLPASS) + h_ps_d->specificTo.mpeg.delayBufIndex = 0; + + for (m=0; m<NO_SERIAL_ALLPASS_LINKS ; m++) { + if (++h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[m] >= aAllpassLinkDelaySer[m]) + h_ps_d->specificTo.mpeg.aDelayRBufIndexSer[m] = 0; + } + + + scaleValues( &rIntBufferLeft[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); + scaleValues( &iIntBufferLeft[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); + scaleValues( &rIntBufferRight[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); + scaleValues( &iIntBufferRight[NO_QMF_BANDS_HYBRID20], NO_QMF_CHANNELS-NO_QMF_BANDS_HYBRID20, -SCAL_HEADROOM ); + + /* free memory on scratch */ + C_ALLOC_SCRATCH_END(aaTransRatioSlot, FIXP_DBL, NO_MID_RES_BINS); + C_ALLOC_SCRATCH_END(aaPowerSlot, FIXP_DBL, NO_MID_RES_BINS); +} + + +void initSlotBasedRotation( HANDLE_PS_DEC h_ps_d, /*!< pointer to the module state */ + int env, + int usb + ) { + + INT group = 0; + INT bin = 0; + INT noIidSteps; + +/* const UCHAR *pQuantizedIIDs;*/ + + FIXP_SGL invL; + FIXP_DBL ScaleL, ScaleR; + FIXP_DBL Alpha, Beta; + FIXP_DBL h11r, h12r, h21r, h22r; + + const FIXP_DBL *PScaleFactors; + + /* Overwrite old values in delay buffers when upper subband is higher than in last frame */ + if (env == 0) { + + if ((usb > h_ps_d->specificTo.mpeg.lastUsb) && h_ps_d->specificTo.mpeg.lastUsb) { + + INT i,k,length; + + for (i=h_ps_d->specificTo.mpeg.lastUsb ; i < FIRST_DELAY_SB; i++) { + FDKmemclear(h_ps_d->specificTo.mpeg.aaaRealDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + FDKmemclear(h_ps_d->specificTo.mpeg.aaaImagDelayRBufferSerQmf[i], NO_DELAY_LENGTH_VECTORS*sizeof(FIXP_DBL)); + } + + for (k=0 ; k<NO_SAMPLE_DELAY_ALLPASS; k++) { + FDKmemclear(h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[k], FIRST_DELAY_SB*sizeof(FIXP_DBL)); + } + length = (usb-FIRST_DELAY_SB)*sizeof(FIXP_DBL); + if(length>0) { + FDKmemclear(h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[0], length); + FDKmemclear(h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[0], length); + } + length = (fixMin(NO_DELAY_BUFFER_BANDS,(INT)usb)-FIRST_DELAY_SB)*sizeof(FIXP_DBL); + if(length>0) { + for (k=1 ; k < h_ps_d->specificTo.mpeg.noSampleDelay; k++) { + FDKmemclear(h_ps_d->specificTo.mpeg.pAaRealDelayBufferQmf[k], length); + FDKmemclear(h_ps_d->specificTo.mpeg.pAaImagDelayBufferQmf[k], length); + } + } + } + h_ps_d->specificTo.mpeg.lastUsb = usb; + } /* env == 0 */ + + if (h_ps_d->bsData[h_ps_d->processSlot].mpeg.bFineIidQ) + { + PScaleFactors = ScaleFactorsFine; /* values are shiftet right by one */ + noIidSteps = NO_IID_STEPS_FINE; + /*pQuantizedIIDs = quantizedIIDsFine;*/ + } + + else + { + PScaleFactors = ScaleFactors; /* values are shiftet right by one */ + noIidSteps = NO_IID_STEPS; + /*pQuantizedIIDs = quantizedIIDs;*/ + } + + + /* dequantize and decode */ + for ( group = 0; group < NO_IID_GROUPS; group++ ) { + + bin = bins2groupMap20[group]; + + /*! + <h3> type 'A' rotation </h3> + mixing procedure R_a, used in baseline version<br> + + Scale-factor vectors c1 and c2 are precalculated in initPsTables () and stored in + scaleFactors[] and scaleFactorsFine[] = pScaleFactors []. + From the linearized IID parameters (intensity differences), two scale factors are + calculated. They are used to obtain the coefficients h11... h22. + */ + + /* ScaleR and ScaleL are scaled by 1 shift right */ + + ScaleR = PScaleFactors[noIidSteps + h_ps_d->specificTo.mpeg.coef.aaIidIndexMapped[env][bin]]; + ScaleL = PScaleFactors[noIidSteps - h_ps_d->specificTo.mpeg.coef.aaIidIndexMapped[env][bin]]; + + Beta = fMult (fMult( Alphas[h_ps_d->specificTo.mpeg.coef.aaIccIndexMapped[env][bin]], ( ScaleR - ScaleL )), FIXP_SQRT05); + Alpha = Alphas[h_ps_d->specificTo.mpeg.coef.aaIccIndexMapped[env][bin]]>>1; + + /* Alpha and Beta are now both scaled by 2 shifts right */ + + /* calculate the coefficients h11... h22 from scale-factors and ICC parameters */ + + /* h values are scaled by 1 shift right */ + { + FIXP_DBL trigData[4]; + + inline_fixp_cos_sin(Beta + Alpha, Beta - Alpha, 2, trigData); + h11r = fMult( ScaleL, trigData[0]); + h12r = fMult( ScaleR, trigData[2]); + h21r = fMult( ScaleL, trigData[1]); + h22r = fMult( ScaleR, trigData[3]); + } + /*****************************************************************************************/ + /* Interpolation of the matrices H11... H22: */ + /* */ + /* H11(k,n) = H11(k,n[e]) + (n-n[e]) * (H11(k,n[e+1] - H11(k,n[e])) / (n[e+1] - n[e]) */ + /* ... */ + /*****************************************************************************************/ + + /* invL = 1/(length of envelope) */ + invL = FX_DBL2FX_SGL(GetInvInt(h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env + 1] - h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env])); + + h_ps_d->specificTo.mpeg.coef.H11r[group] = h_ps_d->specificTo.mpeg.h11rPrev[group]; + h_ps_d->specificTo.mpeg.coef.H12r[group] = h_ps_d->specificTo.mpeg.h12rPrev[group]; + h_ps_d->specificTo.mpeg.coef.H21r[group] = h_ps_d->specificTo.mpeg.h21rPrev[group]; + h_ps_d->specificTo.mpeg.coef.H22r[group] = h_ps_d->specificTo.mpeg.h22rPrev[group]; + + h_ps_d->specificTo.mpeg.coef.DeltaH11r[group] = fMult ( h11r - h_ps_d->specificTo.mpeg.coef.H11r[group], invL ); + h_ps_d->specificTo.mpeg.coef.DeltaH12r[group] = fMult ( h12r - h_ps_d->specificTo.mpeg.coef.H12r[group], invL ); + h_ps_d->specificTo.mpeg.coef.DeltaH21r[group] = fMult ( h21r - h_ps_d->specificTo.mpeg.coef.H21r[group], invL ); + h_ps_d->specificTo.mpeg.coef.DeltaH22r[group] = fMult ( h22r - h_ps_d->specificTo.mpeg.coef.H22r[group], invL ); + + /* update prev coefficients for interpolation in next envelope */ + + h_ps_d->specificTo.mpeg.h11rPrev[group] = h11r; + h_ps_d->specificTo.mpeg.h12rPrev[group] = h12r; + h_ps_d->specificTo.mpeg.h21rPrev[group] = h21r; + h_ps_d->specificTo.mpeg.h22rPrev[group] = h22r; + + } /* group loop */ +} + + +static void applySlotBasedRotation( HANDLE_PS_DEC h_ps_d, /*!< pointer to the module state */ + + FIXP_DBL *mHybridRealLeft, /*!< hybrid values real left */ + FIXP_DBL *mHybridImagLeft, /*!< hybrid values imag left */ + + FIXP_DBL *QmfLeftReal, /*!< real bands left qmf channel */ + FIXP_DBL *QmfLeftImag, /*!< imag bands left qmf channel */ + + FIXP_DBL *mHybridRealRight, /*!< hybrid values real right */ + FIXP_DBL *mHybridImagRight, /*!< hybrid values imag right */ + + FIXP_DBL *QmfRightReal, /*!< real bands right qmf channel */ + FIXP_DBL *QmfRightImag /*!< imag bands right qmf channel */ + ) +{ + INT group; + INT subband; + + FIXP_DBL *RESTRICT HybrLeftReal; + FIXP_DBL *RESTRICT HybrLeftImag; + FIXP_DBL *RESTRICT HybrRightReal; + FIXP_DBL *RESTRICT HybrRightImag; + + FIXP_DBL tmpLeft, tmpRight; + + + /**********************************************************************************************/ + /*! + <h2> Mapping </h2> + + The number of stereo bands that is actually used depends on the number of availble + parameters for IID and ICC: + <pre> + nr. of IID para.| nr. of ICC para. | nr. of Stereo bands + ----------------|------------------|------------------- + 10,20 | 10,20 | 20 + 10,20 | 34 | 34 + 34 | 10,20 | 34 + 34 | 34 | 34 + </pre> + In the case the number of parameters for IIS and ICC differs from the number of stereo + bands, a mapping from the lower number to the higher number of parameters is applied. + Index mapping of IID and ICC parameters is already done in psbitdec.cpp. Further mapping is + not needed here in baseline version. + **********************************************************************************************/ + + /************************************************************************************************/ + /*! + <h2> Mixing </h2> + + To generate the QMF subband signals for the subband samples n = n[e]+1 ,,, n_[e+1] the + parameters at position n[e] and n[e+1] are required as well as the subband domain signals + s_k(n) and d_k(n) for n = n[e]+1... n_[e+1]. n[e] represents the start position for + envelope e. The border positions n[e] are handled in DecodePS(). + + The stereo sub subband signals are constructed as: + <pre> + l_k(n) = H11(k,n) s_k(n) + H21(k,n) d_k(n) + r_k(n) = H21(k,n) s_k(n) + H22(k,n) d_k(n) + </pre> + In order to obtain the matrices H11(k,n)... H22 (k,n), the vectors h11(b)... h22(b) need to + be calculated first (b: parameter index). Depending on ICC mode either mixing procedure R_a + or R_b is used for that. For both procedures, the parameters for parameter position n[e+1] + is used. + ************************************************************************************************/ + + + /************************************************************************************************/ + /*! + <h2>Phase parameters </h2> + With disabled phase parameters (which is the case in baseline version), the H-matrices are + just calculated by: + + <pre> + H11(k,n[e+1] = h11(b(k)) + (...) + b(k): parameter index according to mapping table + </pre> + + <h2>Processing of the samples in the sub subbands </h2> + this loop includes the interpolation of the coefficients Hxx + ************************************************************************************************/ + + + /* loop thru all groups ... */ + HybrLeftReal = mHybridRealLeft; + HybrLeftImag = mHybridImagLeft; + HybrRightReal = mHybridRealRight; + HybrRightImag = mHybridImagRight; + + /******************************************************/ + /* construct stereo sub subband signals according to: */ + /* */ + /* l_k(n) = H11(k,n) s_k(n) + H21(k,n) d_k(n) */ + /* r_k(n) = H12(k,n) s_k(n) + H22(k,n) d_k(n) */ + /******************************************************/ + for ( group = 0; group < SUBQMF_GROUPS; group++ ) { + + h_ps_d->specificTo.mpeg.coef.H11r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH11r[group]; + h_ps_d->specificTo.mpeg.coef.H12r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH12r[group]; + h_ps_d->specificTo.mpeg.coef.H21r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH21r[group]; + h_ps_d->specificTo.mpeg.coef.H22r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH22r[group]; + + subband = groupBorders20[group]; + + tmpLeft = fMultAddDiv2( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightReal[subband]); + tmpRight = fMultAddDiv2( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightReal[subband]); + HybrLeftReal [subband] = tmpLeft<<1; + HybrRightReal[subband] = tmpRight<<1; + + tmpLeft = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightImag[subband]); + tmpRight = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightImag[subband]); + HybrLeftImag [subband] = tmpLeft; + HybrRightImag[subband] = tmpRight; + } + + /* continue in the qmf buffers */ + HybrLeftReal = QmfLeftReal; + HybrLeftImag = QmfLeftImag; + HybrRightReal = QmfRightReal; + HybrRightImag = QmfRightImag; + + for (; group < NO_IID_GROUPS; group++ ) { + + h_ps_d->specificTo.mpeg.coef.H11r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH11r[group]; + h_ps_d->specificTo.mpeg.coef.H12r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH12r[group]; + h_ps_d->specificTo.mpeg.coef.H21r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH21r[group]; + h_ps_d->specificTo.mpeg.coef.H22r[group] += h_ps_d->specificTo.mpeg.coef.DeltaH22r[group]; + + for ( subband = groupBorders20[group]; subband < groupBorders20[group + 1]; subband++ ) + { + tmpLeft = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightReal[subband]); + tmpRight = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftReal[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightReal[subband]); + HybrLeftReal [subband] = tmpLeft; + HybrRightReal[subband] = tmpRight; + + tmpLeft = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H11r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H21r[group], HybrRightImag[subband]); + tmpRight = fMultAdd( fMultDiv2(h_ps_d->specificTo.mpeg.coef.H12r[group], HybrLeftImag[subband]), h_ps_d->specificTo.mpeg.coef.H22r[group], HybrRightImag[subband]); + HybrLeftImag [subband] = tmpLeft; + HybrRightImag[subband] = tmpRight; + + } /* subband */ + } +} + + +/***************************************************************************/ +/*! + \brief Applies IID, ICC, IPD and OPD parameters to the current frame. + + \return none + +****************************************************************************/ +void +ApplyPsSlot( HANDLE_PS_DEC h_ps_d, /*!< handle PS_DEC*/ + FIXP_DBL **rIntBufferLeft, /*!< real bands left qmf channel (38x64) */ + FIXP_DBL **iIntBufferLeft, /*!< imag bands left qmf channel (38x64) */ + FIXP_DBL *rIntBufferRight, /*!< real bands right qmf channel (38x64) */ + FIXP_DBL *iIntBufferRight /*!< imag bands right qmf channel (38x64) */ + ) +{ + + /*! + The 64-band QMF representation of the monaural signal generated by the SBR tool + is used as input of the PS tool. After the PS processing, the outputs of the left + and right hybrid synthesis filterbanks are used to generate the stereo output + signal. + + <pre> + + ------------- ---------- ------------- + | Hybrid | M_n[k,m] | | L_n[k,m] | Hybrid | l[n] + m[n] --->| analysis |--------->| |--------->| synthesis |-----> + | filter bank | | | | filter bank | + ------------- | Stereo | ------------- + | | recon- | + | | stuction | + \|/ | | + ------------- | | + | De- | D_n[k,m] | | + | correlation |--------->| | + ------------- | | ------------- + | | R_n[k,m] | Hybrid | r[n] + | |--------->| synthesis |-----> + IID, ICC ------------------------>| | | filter bank | + (IPD, OPD) ---------- ------------- + + m[n]: QMF represantation of the mono input + M_n[k,m]: (sub-)sub-band domain signals of the mono input + D_n[k,m]: decorrelated (sub-)sub-band domain signals + L_n[k,m]: (sub-)sub-band domain signals of the left output + R_n[k,m]: (sub-)sub-band domain signals of the right output + l[n],r[n]: left/right output signals + + </pre> + */ + + /* get temporary hybrid qmf values of one timeslot */ + C_ALLOC_SCRATCH_START(hybridRealLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_START(hybridImagLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_START(hybridRealRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_START(hybridImagRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); + + SCHAR sf_IntBuffer = h_ps_d->sf_IntBuffer; + + /* clear workbuffer */ + FDKmemclear(hybridRealLeft, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); + FDKmemclear(hybridImagLeft, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); + FDKmemclear(hybridRealRight, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); + FDKmemclear(hybridImagRight, NO_SUB_QMF_CHANNELS*sizeof(FIXP_DBL)); + + + /*! + Hybrid analysis filterbank: + The lower 3 (5) of the 64 QMF subbands are further split to provide better frequency resolution. + for PS processing. + For the 10 and 20 stereo bands configuration, the QMF band H_0(w) is split + up into 8 (sub-) sub-bands and the QMF bands H_1(w) and H_2(w) are spit into 2 (sub-) + 4th. (See figures 8.20 and 8.22 of ISO/IEC 14496-3:2001/FDAM 2:2004(E) ) + */ + + + if (h_ps_d->procFrameBased == 1) /* If we have switched from frame to slot based processing */ + { /* fill hybrid delay buffer. */ + h_ps_d->procFrameBased = 0; + + fillHybridDelayLine( rIntBufferLeft, + iIntBufferLeft, + hybridRealLeft, + hybridImagLeft, + hybridRealRight, + hybridImagRight, + &h_ps_d->specificTo.mpeg.hybrid ); + } + + slotBasedHybridAnalysis ( rIntBufferLeft[HYBRID_FILTER_DELAY], /* qmf filterbank values */ + iIntBufferLeft[HYBRID_FILTER_DELAY], /* qmf filterbank values */ + hybridRealLeft, /* hybrid filterbank values */ + hybridImagLeft, /* hybrid filterbank values */ + &h_ps_d->specificTo.mpeg.hybrid); /* hybrid filterbank handle */ + + + SCHAR hybridScal = h_ps_d->specificTo.mpeg.hybrid.sf_mQmfBuffer; + + + /*! + Decorrelation: + By means of all-pass filtering and delaying, the (sub-)sub-band samples s_k(n) are + converted into de-correlated (sub-)sub-band samples d_k(n). + - k: frequency in hybrid spectrum + - n: time index + */ + + deCorrelateSlotBased( h_ps_d, /* parametric stereo decoder handle */ + hybridRealLeft, /* left hybrid time slot */ + hybridImagLeft, + hybridScal, /* scale factor of left hybrid time slot */ + rIntBufferLeft[0], /* left qmf time slot */ + iIntBufferLeft[0], + sf_IntBuffer, /* scale factor of left and right qmf time slot */ + hybridRealRight, /* right hybrid time slot */ + hybridImagRight, + rIntBufferRight, /* right qmf time slot */ + iIntBufferRight ); + + + + /*! + Stereo Processing: + The sets of (sub-)sub-band samples s_k(n) and d_k(n) are processed according to + the stereo cues which are defined per stereo band. + */ + + + applySlotBasedRotation( h_ps_d, /* parametric stereo decoder handle */ + hybridRealLeft, /* left hybrid time slot */ + hybridImagLeft, + rIntBufferLeft[0], /* left qmf time slot */ + iIntBufferLeft[0], + hybridRealRight, /* right hybrid time slot */ + hybridImagRight, + rIntBufferRight, /* right qmf time slot */ + iIntBufferRight ); + + + + + /*! + Hybrid synthesis filterbank: + The stereo processed hybrid subband signals l_k(n) and r_k(n) are fed into the hybrid synthesis + filterbanks which are identical to the 64 complex synthesis filterbank of the SBR tool. The + input to the filterbank are slots of 64 QMF samples. For each slot the filterbank outputs one + block of 64 samples of one reconstructed stereo channel. The hybrid synthesis filterbank is + computed seperatly for the left and right channel. + */ + + + /* left channel */ + slotBasedHybridSynthesis ( hybridRealLeft, /* one timeslot of hybrid filterbank values */ + hybridImagLeft, + rIntBufferLeft[0], /* one timeslot of qmf filterbank values */ + iIntBufferLeft[0], + &h_ps_d->specificTo.mpeg.hybrid ); /* hybrid filterbank handle */ + + /* right channel */ + slotBasedHybridSynthesis ( hybridRealRight, /* one timeslot of hybrid filterbank values */ + hybridImagRight, + rIntBufferRight, /* one timeslot of qmf filterbank values */ + iIntBufferRight, + &h_ps_d->specificTo.mpeg.hybrid ); /* hybrid filterbank handle */ + + + + + + + + /* free temporary hybrid qmf values of one timeslot */ + C_ALLOC_SCRATCH_END(hybridImagRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_END(hybridRealRight, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_END(hybridImagLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); + C_ALLOC_SCRATCH_END(hybridRealLeft, FIXP_DBL, NO_SUB_QMF_CHANNELS); + +}/* END ApplyPsSlot */ + + +/***************************************************************************/ +/*! + + \brief assigns timeslots to an array + + \return + +****************************************************************************/ + +static void assignTimeSlotsPS (FIXP_DBL *bufAdr, + FIXP_DBL **bufPtr, + const int numSlots, + const int numChan) +{ + FIXP_DBL *ptr; + int slot; + ptr = bufAdr; + for(slot=0; slot < numSlots; slot++) { + bufPtr [slot] = ptr; + ptr += numChan; + } +} + diff --git a/libSBRdec/src/psdec.h b/libSBRdec/src/psdec.h new file mode 100644 index 0000000..fd0a5b6 --- /dev/null +++ b/libSBRdec/src/psdec.h @@ -0,0 +1,294 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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 Sbr decoder $Revision: 36841 $ +*/ +#ifndef __PSDEC_H +#define __PSDEC_H + +#include "sbrdecoder.h" + + + +/* This PS decoder implements the baseline version. So it always uses the */ +/* hybrid filter structure for 20 stereo bands and does not implemet IPD/OPD */ +/* synthesis. The baseline version has to support the complete PS bitstream */ +/* syntax. But IPD/OPD data is ignored and set to 0. If 34 stereo band config */ +/* is used in the bitstream for IIS/ICC the decoded parameters are mapped to */ +/* 20 stereo bands. */ + + +#include "FDK_bitstream.h" + +#include "psdec_hybrid.h" + +#define SCAL_HEADROOM ( 2 ) + +#define PS_EXTENSION_SIZE_BITS ( 4 ) +#define PS_EXTENSION_ESC_COUNT_BITS ( 8 ) + +#define NO_QMF_CHANNELS ( 64 ) +#define MAX_NUM_COL ( 32 ) + + + #define NO_QMF_BANDS_HYBRID20 ( 3 ) + #define NO_SUB_QMF_CHANNELS ( 12 ) + + #define NRG_INT_COEFF ( 0.75f ) + #define INT_FILTER_COEFF (FL2FXCONST_DBL( 1.0f - NRG_INT_COEFF )) + #define PEAK_DECAY_FACTOR (FL2FXCONST_DBL( 0.765928338364649f )) + #define TRANSIENT_IMPACT_FACTOR (FL2FXCONST_DBL( 2.0 / 3.0 )) + + #define NO_SERIAL_ALLPASS_LINKS ( 3 ) + #define MAX_NO_PS_ENV ( 4 + 1 ) /* +1 needed for VAR_BORDER */ + + #define MAX_DELAY_BUFFER_SIZE ( 14 ) + #define NO_DELAY_BUFFER_BANDS ( 35 ) + + #define NO_HI_RES_BINS ( 34 ) + #define NO_MID_RES_BINS ( 20 ) + #define NO_LOW_RES_BINS ( 10 ) + + #define FIRST_DELAY_SB ( 23 ) + #define NO_SAMPLE_DELAY_ALLPASS ( 2 ) + #define NO_DELAY_LENGTH_VECTORS ( 12 ) /* d(m): d(0)=3 + d(1)=4 + d(2)=5 */ + + #define NO_HI_RES_IID_BINS ( NO_HI_RES_BINS ) + #define NO_HI_RES_ICC_BINS ( NO_HI_RES_BINS ) + + #define NO_MID_RES_IID_BINS ( NO_MID_RES_BINS ) + #define NO_MID_RES_ICC_BINS ( NO_MID_RES_BINS ) + + #define NO_LOW_RES_IID_BINS ( NO_LOW_RES_BINS ) + #define NO_LOW_RES_ICC_BINS ( NO_LOW_RES_BINS ) + + #define SUBQMF_GROUPS ( 10 ) + #define QMF_GROUPS ( 12 ) + + #define SUBQMF_GROUPS_HI_RES ( 32 ) + #define QMF_GROUPS_HI_RES ( 18 ) + + #define NO_IID_GROUPS ( SUBQMF_GROUPS + QMF_GROUPS ) + #define NO_IID_GROUPS_HI_RES ( SUBQMF_GROUPS_HI_RES + QMF_GROUPS_HI_RES ) + + #define NO_IID_STEPS ( 7 ) /* 1 .. + 7 */ + #define NO_IID_STEPS_FINE ( 15 ) /* 1 .. +15 */ + #define NO_ICC_STEPS ( 8 ) /* 0 .. + 7 */ + + #define NO_IID_LEVELS ( 2 * NO_IID_STEPS + 1 ) /* - 7 .. + 7 */ + #define NO_IID_LEVELS_FINE ( 2 * NO_IID_STEPS_FINE + 1 ) /* -15 .. +15 */ + #define NO_ICC_LEVELS ( NO_ICC_STEPS ) /* 0 .. + 7 */ + + #define FIXP_SQRT05 ((FIXP_DBL)0x5a827980) /* 1/SQRT2 */ + + struct PS_DEC_COEFFICIENTS { + + FIXP_DBL H11r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL H12r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL H21r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL H22r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + + FIXP_DBL DeltaH11r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL DeltaH12r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL DeltaH21r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + FIXP_DBL DeltaH22r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */ + + SCHAR aaIidIndexMapped[MAX_NO_PS_ENV][NO_HI_RES_IID_BINS]; /*!< The mapped IID index for all envelopes and all IID bins */ + SCHAR aaIccIndexMapped[MAX_NO_PS_ENV][NO_HI_RES_ICC_BINS]; /*!< The mapped ICC index for all envelopes and all ICC bins */ + + }; + + + + +typedef enum { + ppt_none = 0, + ppt_mpeg = 1, + ppt_drm = 2 +} PS_PAYLOAD_TYPE; + + +typedef struct { + UCHAR bPsHeaderValid; /*!< set if new header is available from bitstream */ + + UCHAR bEnableIid; /*!< One bit denoting the presence of IID parameters */ + UCHAR bEnableIcc; /*!< One bit denoting the presence of ICC parameters */ + UCHAR bEnableExt; /*!< The PS extension layer is enabled using the enable_ext bit. + If it is set to %1 the IPD and OPD parameters are sent. + If it is disabled, i.e. %0, the extension layer is skipped. */ + + UCHAR modeIid; /*!< The configuration of IID parameters (number of bands and + quantisation grid, iid_quant) is determined by iid_mode. */ + UCHAR modeIcc; /*!< The configuration of Inter-channel Coherence parameters + (number of bands and quantisation grid) is determined by + icc_mode. */ + + UCHAR freqResIid; /*!< 0=low, 1=mid or 2=high frequency resolution for iid */ + UCHAR freqResIcc; /*!< 0=low, 1=mid or 2=high frequency resolution for icc */ + + UCHAR bFineIidQ; /*!< Use fine Iid quantisation. */ + + UCHAR bFrameClass; /*!< The frame_class bit determines whether the parameter + positions of the current frame are uniformly spaced + accross the frame or they are defined using the positions + described by border_position. */ + + UCHAR noEnv; /*!< The number of envelopes per frame */ + UCHAR aEnvStartStop[MAX_NO_PS_ENV+1]; /*!< In case of variable parameter spacing the parameter + positions are determined by border_position */ + + SCHAR abIidDtFlag[MAX_NO_PS_ENV]; /*!< Deltacoding time/freq flag for IID, 0 => freq */ + SCHAR abIccDtFlag[MAX_NO_PS_ENV]; /*!< Deltacoding time/freq flag for ICC, 0 => freq */ + + SCHAR aaIidIndex[MAX_NO_PS_ENV][NO_HI_RES_IID_BINS]; /*!< The IID index for all envelopes and all IID bins */ + SCHAR aaIccIndex[MAX_NO_PS_ENV][NO_HI_RES_ICC_BINS]; /*!< The ICC index for all envelopes and all ICC bins */ + +} MPEG_PS_BS_DATA; + + + +struct PS_DEC { + + SCHAR noSubSamples; + SCHAR noChannels; + + SCHAR procFrameBased; /*!< Helper to detected switching from frame based to slot based + processing */ + + PS_PAYLOAD_TYPE bPsDataAvail[(1)+1]; /*!< set if new data available from bitstream */ + UCHAR psDecodedPrv; /*!< set if PS has been processed in the last frame */ + + /* helpers for frame delay line */ + UCHAR bsLastSlot; /*!< Index of last read slot. */ + UCHAR bsReadSlot; /*!< Index of current read slot for additional delay. */ + UCHAR processSlot; /*!< Index of current slot for processing (need for add. delay). */ + + + INT rescal; + INT sf_IntBuffer; + + union { /* Bitstream data */ + MPEG_PS_BS_DATA mpeg; /*!< Struct containing all MPEG specific PS data from bitstream. */ + } bsData[(1)+1]; + + shouldBeUnion { /* Static data */ + struct { + SCHAR aIidPrevFrameIndex[NO_HI_RES_IID_BINS]; /*!< The IID index for previous frame */ + SCHAR aIccPrevFrameIndex[NO_HI_RES_ICC_BINS]; /*!< The ICC index for previous frame */ + + UCHAR delayBufIndex; /*!< Pointer to where the latest sample is in buffer */ + UCHAR noSampleDelay; /*!< How many QMF samples delay is used. */ + UCHAR lastUsb; /*!< uppermost WMF delay band of last frame */ + + UCHAR aDelayRBufIndexSer[NO_SERIAL_ALLPASS_LINKS]; /*!< Delay buffer for reverb filter */ + UCHAR aDelayBufIndexDelayQmf[NO_QMF_CHANNELS-FIRST_DELAY_SB]; /*!< Delay buffer for ICC group 20 & 21 */ + + SCHAR scaleFactorPsDelayBuffer; /*!< Scale factor for ps delay buffer */ + + /* hybrid filter bank delay lines */ + FIXP_DBL aaQmfDelayBufReal[(NO_QMF_CHANNELS-FIRST_DELAY_SB) + (MAX_DELAY_BUFFER_SIZE-1)*(NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB)]; + FIXP_DBL aaQmfDelayBufImag[(NO_QMF_CHANNELS-FIRST_DELAY_SB) + (MAX_DELAY_BUFFER_SIZE-1)*(NO_DELAY_BUFFER_BANDS-FIRST_DELAY_SB)]; + + FIXP_DBL *pAaRealDelayBufferQmf[MAX_DELAY_BUFFER_SIZE]; /*!< Real part delay buffer */ + FIXP_DBL *pAaImagDelayBufferQmf[MAX_DELAY_BUFFER_SIZE]; /*!< Imaginary part delay buffer */ + + FIXP_DBL aaRealDelayBufferQmf[NO_SAMPLE_DELAY_ALLPASS][FIRST_DELAY_SB]; /*!< Real part delay buffer */ + FIXP_DBL aaImagDelayBufferQmf[NO_SAMPLE_DELAY_ALLPASS][FIRST_DELAY_SB]; /*!< Imaginary part delay buffer*/ + + FIXP_DBL aaRealDelayBufferSubQmf[NO_SAMPLE_DELAY_ALLPASS][NO_SUB_QMF_CHANNELS]; /*!< Real part delay buffer */ + FIXP_DBL aaImagDelayBufferSubQmf[NO_SAMPLE_DELAY_ALLPASS][NO_SUB_QMF_CHANNELS]; /*!< Imaginary part delay buffer */ + + FIXP_DBL aaaRealDelayRBufferSerQmf[FIRST_DELAY_SB][NO_DELAY_LENGTH_VECTORS]; /*!< Real part delay buffer */ + FIXP_DBL aaaImagDelayRBufferSerQmf[FIRST_DELAY_SB][NO_DELAY_LENGTH_VECTORS]; /*!< Imaginary part delay buffer */ + + FIXP_DBL aaaRealDelayRBufferSerSubQmf[NO_SUB_QMF_CHANNELS][NO_DELAY_LENGTH_VECTORS]; /*!< Real part delay buffer */ + FIXP_DBL aaaImagDelayRBufferSerSubQmf[NO_SUB_QMF_CHANNELS][NO_DELAY_LENGTH_VECTORS]; /*!< Imaginary part delay buffer */ + + HYBRID hybrid; /*!< hybrid filter bank struct 1 or 2. */ + + FIXP_DBL aPrevNrgBin[NO_MID_RES_BINS]; /*!< energy of previous frame */ + FIXP_DBL aPrevPeakDiffBin[NO_MID_RES_BINS]; /*!< peak difference of previous frame */ + FIXP_DBL aPeakDecayFastBin[NO_MID_RES_BINS]; /*!< Saved max. peak decay value per bin */ + SCHAR aPowerPrevScal[NO_MID_RES_BINS]; /*!< Last power value (each bin) of previous frame */ + + FIXP_DBL h11rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy) coefficients */ + FIXP_DBL h12rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy) coefficients */ + FIXP_DBL h21rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy) coefficients */ + FIXP_DBL h22rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy) coefficients */ + + PS_DEC_COEFFICIENTS coef; /*!< temporal coefficients (reusable scratch memory) */ + + } mpeg; + + } specificTo; + + +}; + +typedef struct PS_DEC *HANDLE_PS_DEC; + + +int CreatePsDec(HANDLE_PS_DEC *h_PS_DEC, int aacSamplesPerFrame); + +int DeletePsDec(HANDLE_PS_DEC *h_PS_DEC); + +void +scalFilterBankValues( HANDLE_PS_DEC h_ps_d, /* parametric stereo decoder handle */ + FIXP_DBL **fixpQmfReal, /* qmf filterbank values */ + FIXP_DBL **fixpQmfImag, /* qmf filterbank values */ + int lsb, /* sbr start subband */ + int scaleFactorLowBandSplitLow, + int scaleFactorLowBandSplitHigh, + SCHAR *scaleFactorLowBand_lb, + SCHAR *scaleFactorLowBand_hb, + int scaleFactorHighBands, + INT *scaleFactorHighBand, + INT noCols); + +void +rescalFilterBankValues( HANDLE_PS_DEC h_ps_d, /* parametric stereo decoder handle */ + FIXP_DBL **QmfBufferReal, /* qmf filterbank values */ + FIXP_DBL **QmfBufferImag, /* qmf filterbank values */ + int lsb, /* sbr start subband */ + INT noCols); + + +void +initSlotBasedRotation( HANDLE_PS_DEC h_ps_d, + int env, + int usb); + +void +ApplyPsSlot( HANDLE_PS_DEC h_ps_d, /* parametric stereo decoder handle */ + FIXP_DBL **rIntBufferLeft, /* real values of left qmf timeslot */ + FIXP_DBL **iIntBufferLeft, /* imag values of left qmf timeslot */ + FIXP_DBL *rIntBufferRight, /* real values of right qmf timeslot */ + FIXP_DBL *iIntBufferRight); /* imag values of right qmf timeslot */ + + + +#endif /* __PSDEC_H */ diff --git a/libSBRdec/src/psdec_hybrid.cpp b/libSBRdec/src/psdec_hybrid.cpp new file mode 100644 index 0000000..9c73c69 --- /dev/null +++ b/libSBRdec/src/psdec_hybrid.cpp @@ -0,0 +1,595 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "psdec_hybrid.h" + + +#include "fft.h" +#include "sbr_ram.h" + +#include "FDK_tools_rom.h" +#include "sbr_rom.h" + +/******************************************************************************* + Functionname: InitHybridFilterBank + ******************************************************************************* + + Description: Init one instance of HANDLE_HYBRID stuct + + Arguments: + + Return: none + +*******************************************************************************/ + + +SBR_ERROR +InitHybridFilterBank ( HANDLE_HYBRID hs, /*!< Handle to HYBRID struct. */ + SCHAR frameSize, /*!< Framesize (in Qmf súbband samples). */ + SCHAR noBands, /*!< Number of Qmf bands for hybrid filtering. */ + const UCHAR *pResolution ) /*!< Resolution in Qmf bands (length noBands). */ +{ + SCHAR i; + UCHAR maxNoChannels = 0; + + for (i = 0; i < noBands; i++) { + hs->pResolution[i] = pResolution[i]; + if(pResolution[i] > maxNoChannels) + maxNoChannels = pResolution[i]; + } + + hs->nQmfBands = noBands; + hs->frameSize = frameSize; + hs->qmfBufferMove = HYBRID_FILTER_LENGTH - 1; + + hs->sf_mQmfBuffer = 0; + + return SBRDEC_OK; +} + +/******************************************************************************* + Functionname: dualChannelFiltering + ******************************************************************************* + + Description: fast 2-channel real-valued filtering with 6-tap delay. + + Arguments: + + Return: none + +*******************************************************************************/ + +/*! +2 channel filter +<pre> + Filter Coefs: + 0.0, + 0.01899487526049, + 0.0, + -0.07293139167538, + 0.0, + 0.30596630545168, + 0.5, + 0.30596630545168, + 0.0, + -0.07293139167538, + 0.0, + 0.01899487526049, + 0.0 + + + Filter design: + h[q,n] = g[n] * cos(2pi/2 * q * (n-6) ); n = 0..12, q = 0,1; + + -> h[0,n] = g[n] * 1; + -> h[1,n] = g[n] * pow(-1,n); +</pre> +*/ + +static void slotBasedDualChannelFiltering( const FIXP_DBL *pQmfReal, + const FIXP_DBL *pQmfImag, + + FIXP_DBL *mHybridReal, + FIXP_DBL *mHybridImag) +{ + + FIXP_DBL t1, t3, t5, t6; + + /* symmetric filter coefficients */ + + /* you don't have to shift the result after fMult because of p2_13_20 <= 0.5 */ + t1 = fMultDiv2(p2_13_20[1] , ( (pQmfReal[1] >> 1) + (pQmfReal[11] >> 1))); + t3 = fMultDiv2(p2_13_20[3] , ( (pQmfReal[3] >> 1) + (pQmfReal[ 9] >> 1))); + t5 = fMultDiv2(p2_13_20[5] , ( (pQmfReal[5] >> 1) + (pQmfReal[ 7] >> 1))); + t6 = fMultDiv2(p2_13_20[6] , (pQmfReal[6] >> 1) ); + + mHybridReal[0] = (t1 + t3 + t5 + t6) << 2; + mHybridReal[1] = (- t1 - t3 - t5 + t6) << 2; + + t1 = fMultDiv2(p2_13_20[1] , ( (pQmfImag[1] >> 1) + (pQmfImag[11] >> 1))); + t3 = fMultDiv2(p2_13_20[3] , ( (pQmfImag[3] >> 1) + (pQmfImag[ 9] >> 1))); + t5 = fMultDiv2(p2_13_20[5] , ( (pQmfImag[5] >> 1) + (pQmfImag[ 7] >> 1))); + t6 = fMultDiv2(p2_13_20[6] , pQmfImag[6] >> 1 ); + + mHybridImag[0] = (t1 + t3 + t5 + t6) << 2; + mHybridImag[1] = (- t1 - t3 - t5 + t6) << 2; +} + + +/******************************************************************************* + Functionname: eightChannelFiltering + ******************************************************************************* + + Description: fast 8-channel complex-valued filtering with 6-tap delay. + + Arguments: + + Return: none + +*******************************************************************************/ +/*! + 8 channel filter + + Implementation using a FFT of length 8 +<pre> + prototype filter coefficients: + 0.00746082949812 0.02270420949825 0.04546865930473 0.07266113929591 0.09885108575264 0.11793710567217 + 0.125 + 0.11793710567217 0.09885108575264 0.07266113929591 0.04546865930473 0.02270420949825 0.00746082949812 + + Filter design: + N = 13; Q = 8; + h[q,n] = g[n] * exp(j * 2 * pi / Q * (q + .5) * (n - 6)); n = 0..(N-1), q = 0..(Q-1); + + Time Signal: x[t]; + Filter Bank Output + y[q,t] = conv(x[t],h[q,t]) = conv(h[q,t],x[t]) = sum(x[k] * h[q, t - k] ) = sum(h[q, k] * x[t - k] ); k = 0..(N-1); + + y[q,t] = x[t - 12]*h[q, 12] + x[t - 11]*h[q, 11] + x[t - 10]*h[q, 10] + x[t - 9]*h[q, 9] + + x[t - 8]*h[q, 8] + x[t - 7]*h[q, 7] + + x[t - 6]*h[q, 6] + + x[t - 5]*h[q, 5] + x[t - 4]*h[q, 4] + + x[t - 3]*h[q, 3] + x[t - 2]*h[q, 2] + x[t - 1]*h[q, 1] + x[t - 0]*h[q, 0]; + + h'[q, n] = h[q,(N-1)-n] = g[n] * exp(j * 2 * pi / Q * (q + .5) * (6 - n)); n = 0..(N-1), q = 0..(Q-1); + + y[q,t] = x[t - 12]*h'[q, 0] + x[t - 11]*h'[q, 1] + x[t - 10]*h'[q, 2] + x[t - 9]*h'[q, 3] + + x[t - 8]*h'[q, 4] + x[t - 7]*h'[q, 5] + + x[t - 6]*h'[q, 6] + + x[t - 5]*h'[q, 7] + x[t - 4]*h'[q, 8] + + x[t - 3]*h'[q, 9] + x[t - 2]*h'[q, 10] + x[t - 1]*h'[q, 11] + x[t - 0]*h'[q, 12]; + + Try to split off FFT Modulation Term: + FFT(x[t], q) = sum(x[t+k]*exp(-j*2*pi/N *q * k)) + c m + Step 1: h'[q,n] = g[n] * ( exp(j * 2 * pi / 8 * .5 * (6 - n)) ) * ( exp (j * 2 * pi / 8 * q * (6 - n)) ); + + h'[q,n] = g[n] *c[n] * m[q,n]; (see above) + c[n] = exp( j * 2 * pi / 8 * .5 * (6 - n) ); + m[q,n] = exp( j * 2 * pi / 8 * q * (6 - n) ); + + y[q,t] = x[t - 0]*g[0]*c[0]*m[q,0] + x[t - 1]*g[1]*c[ 1]*m[q, 1] + ... + ... + x[t - 12]*g[2]*c[12]*m[q,12]; + + | + n m *exp(-j*2*pi) | n' fft +------------------------------------------------------------------------------------------------------------------------- + 0 exp( j * 2 * pi / 8 * q * 6) -> exp(-j * 2 * pi / 8 * q * 2) | 2 exp(-j * 2 * pi / 8 * q * 0) + 1 exp( j * 2 * pi / 8 * q * 5) -> exp(-j * 2 * pi / 8 * q * 3) | 3 exp(-j * 2 * pi / 8 * q * 1) + 2 exp( j * 2 * pi / 8 * q * 4) -> exp(-j * 2 * pi / 8 * q * 4) | 4 exp(-j * 2 * pi / 8 * q * 2) + 3 exp( j * 2 * pi / 8 * q * 3) -> exp(-j * 2 * pi / 8 * q * 5) | 5 exp(-j * 2 * pi / 8 * q * 3) + 4 exp( j * 2 * pi / 8 * q * 2) -> exp(-j * 2 * pi / 8 * q * 6) | 6 exp(-j * 2 * pi / 8 * q * 4) + 5 exp( j * 2 * pi / 8 * q * 1) -> exp(-j * 2 * pi / 8 * q * 7) | 7 exp(-j * 2 * pi / 8 * q * 5) + 6 exp( j * 2 * pi / 8 * q * 0) | 0 exp(-j * 2 * pi / 8 * q * 6) + 7 exp(-j * 2 * pi / 8 * q * 1) | 1 exp(-j * 2 * pi / 8 * q * 7) + 8 exp(-j * 2 * pi / 8 * q * 2) | 2 + 9 exp(-j * 2 * pi / 8 * q * 3) | 3 + 10 exp(-j * 2 * pi / 8 * q * 4) | 4 + 11 exp(-j * 2 * pi / 8 * q * 5) | 5 + 12 exp(-j * 2 * pi / 8 * q * 6) | 6 + + + now use fft modulation coefficients + m[6] = = fft[0] + m[7] = = fft[1] + m[8] = m[ 0] = fft[2] + m[9] = m[ 1] = fft[3] + m[10] = m[ 2] = fft[4] + m[11] = m[ 3] = fft[5] + m[12] = m[ 4] = fft[6] + m[ 5] = fft[7] + + y[q,t] = ( x[t- 6]*g[ 6]*c[ 6] ) * fft[q,0] + + ( x[t- 7]*g[ 7]*c[ 7] ) * fft[q,1] + + ( x[t- 0]*g[ 0]*c[ 0] + x[t- 8]*g[ 8]*c[ 8] ) * fft[q,2] + + ( x[t- 1]*g[ 1]*c[ 1] + x[t- 9]*g[ 9]*c[ 9] ) * fft[q,3] + + ( x[t- 2]*g[ 2]*c[ 2] + x[t-10]*g[10]*c[10] ) * fft[q,4] + + ( x[t- 3]*g[ 3]*c[ 3] + x[t-11]*g[11]*c[11] ) * fft[q,5] + + ( x[t- 4]*g[ 4]*c[ 4] + x[t-12]*g[12]*c[12] ) * fft[q,6] + + ( x[t- 5]*g[ 5]*c[ 5] ) * fft[q,7]; + + pre twiddle factors c[n] = exp(j * 2 * pi / 8 * .5 * (6 - n)); + n c] | n c[n] | n c[n] +--------------------------------------------------------------------------------------------------- + 0 exp( j * 6 * pi / 8) | 1 exp( j * 5 * pi / 8) | 2 exp( j * 4 * pi / 8) + 3 exp( j * 3 * pi / 8) | 4 exp( j * 2 * pi / 8) | 5 exp( j * 1 * pi / 8) + 6 exp( j * 0 * pi / 8) | 7 exp(-j * 1 * pi / 8) | 8 exp(-j * 2 * pi / 8) + 9 exp(-j * 3 * pi / 8) | 10 exp(-j * 4 * pi / 8) | 11 exp(-j * 5 * pi / 8) + 12 exp(-j * 6 * pi / 8) | | +</pre> +*/ + +/* defining rotation factors for *ChannelFiltering */ + +#define cos0Pi FL2FXCONST_DBL( 1.f) +#define sin0Pi FL2FXCONST_DBL( 0.f) + +#define cos1Pi FL2FXCONST_DBL(-1.f) +#define sin1Pi FL2FXCONST_DBL( 0.f) + +#define cos1Pi_2 FL2FXCONST_DBL( 0.f) +#define sin1Pi_2 FL2FXCONST_DBL( 1.f) + +#define cos1Pi_3 FL2FXCONST_DBL( 0.5f) +#define sin1Pi_3 FL2FXCONST_DBL( 0.86602540378444f) + +#define cos0Pi_4 cos0Pi +#define cos1Pi_4 FL2FXCONST_DBL(0.70710678118655f) +#define cos2Pi_4 cos1Pi_2 +#define cos3Pi_4 (-cos1Pi_4) +#define cos4Pi_4 (-cos0Pi_4) +#define cos5Pi_4 cos3Pi_4 +#define cos6Pi_4 cos2Pi_4 + +#define sin0Pi_4 sin0Pi +#define sin1Pi_4 FL2FXCONST_DBL(0.70710678118655f) +#define sin2Pi_4 sin1Pi_2 +#define sin3Pi_4 sin1Pi_4 +#define sin4Pi_4 sin0Pi_4 +#define sin5Pi_4 (-sin3Pi_4) +#define sin6Pi_4 (-sin2Pi_4) + +#define cos0Pi_8 cos0Pi +#define cos1Pi_8 FL2FXCONST_DBL(0.92387953251129f) +#define cos2Pi_8 cos1Pi_4 +#define cos3Pi_8 FL2FXCONST_DBL(0.38268343236509f) +#define cos4Pi_8 cos2Pi_4 +#define cos5Pi_8 (-cos3Pi_8) +#define cos6Pi_8 (-cos2Pi_8) + +#define sin0Pi_8 sin0Pi +#define sin1Pi_8 cos3Pi_8 +#define sin2Pi_8 sin1Pi_4 +#define sin3Pi_8 cos1Pi_8 +#define sin4Pi_8 sin2Pi_4 +#define sin5Pi_8 sin3Pi_8 +#define sin6Pi_8 sin1Pi_4 + +#if defined(ARCH_PREFER_MULT_32x16) + #define FIXP_HYB FIXP_SGL + #define FIXP_CAST FX_DBL2FX_SGL +#else + #define FIXP_HYB FIXP_DBL + #define FIXP_CAST +#endif + +static const FIXP_HYB cr[13] = +{ + FIXP_CAST(cos6Pi_8), FIXP_CAST(cos5Pi_8), FIXP_CAST(cos4Pi_8), + FIXP_CAST(cos3Pi_8), FIXP_CAST(cos2Pi_8), FIXP_CAST(cos1Pi_8), + FIXP_CAST(cos0Pi_8), + FIXP_CAST(cos1Pi_8), FIXP_CAST(cos2Pi_8), FIXP_CAST(cos3Pi_8), + FIXP_CAST(cos4Pi_8), FIXP_CAST(cos5Pi_8), FIXP_CAST(cos6Pi_8) +}; + +static const FIXP_HYB ci[13] = +{ + FIXP_CAST( sin6Pi_8), FIXP_CAST( sin5Pi_8), FIXP_CAST( sin4Pi_8), + FIXP_CAST( sin3Pi_8), FIXP_CAST( sin2Pi_8), FIXP_CAST( sin1Pi_8), + FIXP_CAST( sin0Pi_8) , + FIXP_CAST(-sin1Pi_8), FIXP_CAST(-sin2Pi_8), FIXP_CAST(-sin3Pi_8), + FIXP_CAST(-sin4Pi_8), FIXP_CAST(-sin5Pi_8), FIXP_CAST(-sin6Pi_8) +}; + +static void slotBasedEightChannelFiltering( const FIXP_DBL *pQmfReal, + const FIXP_DBL *pQmfImag, + + FIXP_DBL *mHybridReal, + FIXP_DBL *mHybridImag) +{ + + int bin; + FIXP_DBL _fft[128 + ALIGNMENT_DEFAULT - 1]; + FIXP_DBL *fft = (FIXP_DBL *)ALIGN_PTR(_fft); + +#if defined(ARCH_PREFER_MULT_32x16) + const FIXP_SGL *p = p8_13_20; /* BASELINE_PS */ +#else + const FIXP_DBL *p = p8_13_20; /* BASELINE_PS */ +#endif + + /* pre twiddeling */ + + /* x*(a*b + c*d) = fMultDiv2(x, fMultAddDiv2(fMultDiv2(a, b), c, d)) */ + /* x*(a*b - c*d) = fMultDiv2(x, fMultSubDiv2(fMultDiv2(a, b), c, d)) */ + FIXP_DBL accu1, accu2, accu3, accu4; + + #define TWIDDLE_1(n_0,n_1,n_2) \ + cplxMultDiv2(&accu1, &accu2, pQmfReal[n_0], pQmfImag[n_0], cr[n_0], ci[n_0]); \ + accu1 = fMultDiv2(p[n_0], accu1); \ + accu2 = fMultDiv2(p[n_0], accu2); \ + cplxMultDiv2(&accu3, &accu4, pQmfReal[n_1], pQmfImag[n_1], cr[n_1], ci[n_1]); \ + accu3 = fMultDiv2(p[n_1], accu3); \ + accu4 = fMultDiv2(p[n_1], accu4); \ + fft[FIXP_FFT_IDX_R(n_2)] = accu1 + accu3; \ + fft[FIXP_FFT_IDX_I(n_2)] = accu2 + accu4; + + #define TWIDDLE_0(n_0,n_1) \ + cplxMultDiv2(&accu1, &accu2, pQmfReal[n_0], pQmfImag[n_0], cr[n_0], ci[n_0]); \ + fft[FIXP_FFT_IDX_R(n_1)] = fMultDiv2(p[n_0], accu1); \ + fft[FIXP_FFT_IDX_I(n_1)] = fMultDiv2(p[n_0], accu2); + + TWIDDLE_0( 6, 0) + TWIDDLE_0( 7, 1) + + TWIDDLE_1( 0, 8, 2) + TWIDDLE_1( 1, 9, 3) + TWIDDLE_1( 2,10, 4) + TWIDDLE_1( 3,11, 5) + TWIDDLE_1( 4,12, 6) + + TWIDDLE_0( 5, 7) + + fft_8 (fft); + + /* resort fft data into output array*/ + for(bin=0; bin<8;bin++ ) { + mHybridReal[bin] = fft[FIXP_FFT_IDX_R(bin)] << 4; + mHybridImag[bin] = fft[FIXP_FFT_IDX_I(bin)] << 4; + } +} + + +/******************************************************************************* + Functionname: fillHybridDelayLine + ******************************************************************************* + + Description: The delay line of the hybrid filter is filled and copied from + left to right. + + Return: none + +*******************************************************************************/ + +void +fillHybridDelayLine( FIXP_DBL **fixpQmfReal, /*!< Qmf real Values */ + FIXP_DBL **fixpQmfImag, /*!< Qmf imag Values */ + FIXP_DBL fixpHybridLeftR[12], /*!< Hybrid real Values left channel */ + FIXP_DBL fixpHybridLeftI[12], /*!< Hybrid imag Values left channel */ + FIXP_DBL fixpHybridRightR[12], /*!< Hybrid real Values right channel */ + FIXP_DBL fixpHybridRightI[12], /*!< Hybrid imag Values right channel */ + HANDLE_HYBRID hHybrid ) +{ + int i; + + for (i = 0; i < HYBRID_FILTER_DELAY; i++) { + slotBasedHybridAnalysis ( fixpQmfReal[i], + fixpQmfReal[i], + fixpHybridLeftR, + fixpHybridLeftI, + hHybrid ); + } + + FDKmemcpy(fixpHybridRightR, fixpHybridLeftR, sizeof(FIXP_DBL)*NO_SUB_QMF_CHANNELS); + FDKmemcpy(fixpHybridRightI, fixpHybridLeftI, sizeof(FIXP_DBL)*NO_SUB_QMF_CHANNELS); +} + + +/******************************************************************************* + Functionname: slotBasedHybridAnalysis + ******************************************************************************* + + Description: The lower QMF subbands are further split to provide better + frequency resolution for PS processing. + + Return: none + +*******************************************************************************/ + + +void +slotBasedHybridAnalysis ( FIXP_DBL *fixpQmfReal, /*!< Qmf real Values */ + FIXP_DBL *fixpQmfImag, /*!< Qmf imag Values */ + + FIXP_DBL fixpHybridReal[12], /*!< Hybrid real Values */ + FIXP_DBL fixpHybridImag[12], /*!< Hybrid imag Values */ + + HANDLE_HYBRID hHybrid) +{ + int k, band; + HYBRID_RES hybridRes; + int chOffset = 0; + + C_ALLOC_SCRATCH_START(pTempRealSlot, FIXP_DBL, 4*HYBRID_FILTER_LENGTH); + + FIXP_DBL *pTempImagSlot = pTempRealSlot + HYBRID_FILTER_LENGTH; + FIXP_DBL *pWorkRealSlot = pTempImagSlot + HYBRID_FILTER_LENGTH; + FIXP_DBL *pWorkImagSlot = pWorkRealSlot + HYBRID_FILTER_LENGTH; + + /*! + Hybrid filtering is applied to the first hHybrid->nQmfBands QMF bands (3 when 10 or 20 stereo bands + are used, 5 when 34 stereo bands are used). For the remaining QMF bands a delay would be necessary. + But there is no need to implement a delay because there is a look-ahead of HYBRID_FILTER_DELAY = 6 + QMF samples in the low-band buffer. + */ + + for(band = 0; band < hHybrid->nQmfBands; band++) { + + /* get hybrid resolution per qmf band */ + /* in case of baseline ps 10/20 band stereo mode : */ + /* */ + /* qmfBand[0] : 8 ( HYBRID_8_CPLX ) */ + /* qmfBand[1] : 2 ( HYBRID_2_REAL ) */ + /* qmfBand[2] : 2 ( HYBRID_2_REAL ) */ + /* */ + /* (split the 3 lower qmf band to 12 hybrid bands) */ + + hybridRes = (HYBRID_RES)hHybrid->pResolution[band]; + + FDKmemcpy(pWorkRealSlot, hHybrid->mQmfBufferRealSlot[band], hHybrid->qmfBufferMove * sizeof(FIXP_DBL)); + FDKmemcpy(pWorkImagSlot, hHybrid->mQmfBufferImagSlot[band], hHybrid->qmfBufferMove * sizeof(FIXP_DBL)); + + pWorkRealSlot[hHybrid->qmfBufferMove] = fixpQmfReal[band]; + pWorkImagSlot[hHybrid->qmfBufferMove] = fixpQmfImag[band]; + + FDKmemcpy(hHybrid->mQmfBufferRealSlot[band], pWorkRealSlot + 1, hHybrid->qmfBufferMove * sizeof(FIXP_DBL)); + FDKmemcpy(hHybrid->mQmfBufferImagSlot[band], pWorkImagSlot + 1, hHybrid->qmfBufferMove * sizeof(FIXP_DBL)); + + if (fixpQmfReal) { + + /* actual filtering only if output signal requested */ + switch( hybridRes ) { + + /* HYBRID_2_REAL & HYBRID_8_CPLX are only needful for baseline ps */ + case HYBRID_2_REAL: + + slotBasedDualChannelFiltering( pWorkRealSlot, + pWorkImagSlot, + pTempRealSlot, + pTempImagSlot); + break; + + case HYBRID_8_CPLX: + + slotBasedEightChannelFiltering( pWorkRealSlot, + pWorkImagSlot, + pTempRealSlot, + pTempImagSlot); + break; + + default: + FDK_ASSERT(0); + } + + for(k = 0; k < (SCHAR)hybridRes; k++) { + fixpHybridReal [chOffset + k] = pTempRealSlot[k]; + fixpHybridImag [chOffset + k] = pTempImagSlot[k]; + } + chOffset += hybridRes; + } /* if (mHybridReal) */ + } + + /* group hybrid channels 3+4 -> 3 and 2+5 -> 2 */ + fixpHybridReal[3] += fixpHybridReal[4]; + fixpHybridImag[3] += fixpHybridImag[4]; + fixpHybridReal[4] = (FIXP_DBL)0; + fixpHybridImag[4] = (FIXP_DBL)0; + + fixpHybridReal[2] += fixpHybridReal[5]; + fixpHybridImag[2] += fixpHybridImag[5]; + fixpHybridReal[5] = (FIXP_DBL)0; + fixpHybridImag[5] = (FIXP_DBL)0; + + /* free memory on scratch */ + C_ALLOC_SCRATCH_END(pTempRealSlot, FIXP_DBL, 4*HYBRID_FILTER_LENGTH); + +} + + +/******************************************************************************* + Functionname: slotBasedHybridSynthesis + ******************************************************************************* + + Description: The coefficients offering higher resolution for the lower QMF + channel are simply added prior to the synthesis with the 54 + subbands QMF. + + Arguments: + + Return: none + +*******************************************************************************/ + +/*! <pre> + l,r0(n) ---\ + l,r1(n) ---- + --\ + l,r2(n) ---/ \ + + --> F0(w) + l,r3(n) ---\ / + l,r4(n) ---- + --/ + l,r5(n) ---/ + + + l,r6(n) ---\ + + ---------> F1(w) + l,r7(n) ---/ + + + l,r8(n) ---\ + + ---------> F2(w) + l,r9(n) ---/ + + </pre> + Hybrid QMF synthesis filterbank for the 10 and 20 stereo-bands configurations. The + coefficients offering higher resolution for the lower QMF channel are simply added + prior to the synthesis with the 54 subbands QMF. + + [see ISO/IEC 14496-3:2001/FDAM 2:2004(E) - Page 52] +*/ + + +void +slotBasedHybridSynthesis ( FIXP_DBL *fixpHybridReal, /*!< Hybrid real Values */ + FIXP_DBL *fixpHybridImag, /*!< Hybrid imag Values */ + FIXP_DBL *fixpQmfReal, /*!< Qmf real Values */ + FIXP_DBL *fixpQmfImag, /*!< Qmf imag Values */ + HANDLE_HYBRID hHybrid ) /*!< Handle to HYBRID struct. */ +{ + int k, band; + + HYBRID_RES hybridRes; + int chOffset = 0; + + for(band = 0; band < hHybrid->nQmfBands; band++) { + + FIXP_DBL qmfReal = FL2FXCONST_DBL(0.f); + FIXP_DBL qmfImag = FL2FXCONST_DBL(0.f); + hybridRes = (HYBRID_RES)hHybrid->pResolution[band]; + + for(k = 0; k < (SCHAR)hybridRes; k++) { + qmfReal += fixpHybridReal[chOffset + k]; + qmfImag += fixpHybridImag[chOffset + k]; + } + + fixpQmfReal[band] = qmfReal; + fixpQmfImag[band] = qmfImag; + + chOffset += hybridRes; + } +} + + + diff --git a/libSBRdec/src/psdec_hybrid.h b/libSBRdec/src/psdec_hybrid.h new file mode 100644 index 0000000..69e8707 --- /dev/null +++ b/libSBRdec/src/psdec_hybrid.h @@ -0,0 +1,109 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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$ + +*******************************************************************************/ + + +#ifndef __HYBRID_H +#define __HYBRID_H + +#include "sbrdecoder.h" + + +#define HYBRID_FILTER_LENGTH 13 +#define HYBRID_FILTER_DELAY 6 + + +#define FAST_FILTER2 +#define FAST_FILTER4 +#define FAST_FILTER8 +#define FAST_FILTER12 + +#define FFT_IDX_R(a) (2*a) +#define FFT_IDX_I(a) (2*a+1) + +#define FIXP_FFT_IDX_R(a) (a<<1) +#define FIXP_FFT_IDX_I(a) ((a<<1) + 1) + + +typedef enum { + + HYBRID_2_REAL = 2, + HYBRID_4_CPLX = 4, + HYBRID_8_CPLX = 8, + HYBRID_12_CPLX = 12 + +} HYBRID_RES; + +typedef struct +{ + SCHAR nQmfBands; + SCHAR frameSize; + SCHAR qmfBufferMove; + + UCHAR pResolution[3]; + + FIXP_DBL mQmfBufferRealSlot[3][HYBRID_FILTER_LENGTH]; /**< Stores old Qmf samples. */ + FIXP_DBL mQmfBufferImagSlot[3][HYBRID_FILTER_LENGTH]; + SCHAR sf_mQmfBuffer; + +} HYBRID; + +typedef HYBRID *HANDLE_HYBRID; + +void +fillHybridDelayLine( FIXP_DBL **fixpQmfReal, + FIXP_DBL **fixpQmfImag, + FIXP_DBL fixpHybridLeftR[12], + FIXP_DBL fixpHybridLeftI[12], + FIXP_DBL fixpHybridRightR[12], + FIXP_DBL fixpHybridRightI[12], + HANDLE_HYBRID hHybrid ); + +void +slotBasedHybridAnalysis ( FIXP_DBL *fixpQmfReal, + FIXP_DBL *fixpQmfImag, + + FIXP_DBL *fixpHybridReal, + FIXP_DBL *fixpHybridImag, + + HANDLE_HYBRID hHybrid); + + +void +slotBasedHybridSynthesis ( FIXP_DBL *fixpHybridReal, + FIXP_DBL *fixpHybridImag, + + FIXP_DBL *fixpQmfReal, + FIXP_DBL *fixpQmfImag, + + HANDLE_HYBRID hHybrid ); + +SBR_ERROR InitHybridFilterBank ( HANDLE_HYBRID hHybrid, + SCHAR frameSize, + SCHAR noBands, + const UCHAR *pResolution ); + + +#endif /* __HYBRID_H */ diff --git a/libSBRdec/src/sbr_crc.cpp b/libSBRdec/src/sbr_crc.cpp new file mode 100644 index 0000000..3463710 --- /dev/null +++ b/libSBRdec/src/sbr_crc.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** + + (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 CRC check coutines $Revision: 36841 $ +*/ + +#include "sbr_crc.h" + +#include "FDK_bitstream.h" +#include "transcendent.h" + +#define MAXCRCSTEP 16 +#define MAXCRCSTEP_LD 4 + +/*! + \brief crc calculation +*/ +static ULONG +calcCRC (HANDLE_CRC hCrcBuf, ULONG bValue, int nBits) +{ + int i; + ULONG bMask = (1UL << (nBits - 1)); + + for (i = 0; i < nBits; i++, bMask >>= 1) { + USHORT flag = (hCrcBuf->crcState & hCrcBuf->crcMask) ? 1 : 0; + USHORT flag1 = (bMask & bValue) ? 1 : 0; + + flag ^= flag1; + hCrcBuf->crcState <<= 1; + if (flag) + hCrcBuf->crcState ^= hCrcBuf->crcPoly; + } + + return (hCrcBuf->crcState); +} + + +/*! + \brief crc +*/ +static int +getCrc (HANDLE_FDK_BITSTREAM hBs, ULONG NrBits) +{ + int i; + CRC_BUFFER CrcBuf; + + CrcBuf.crcState = SBR_CRC_START; + CrcBuf.crcPoly = SBR_CRC_POLY; + CrcBuf.crcMask = SBR_CRC_MASK; + + int CrcStep = NrBits>>MAXCRCSTEP_LD; + + int CrcNrBitsRest = (NrBits - CrcStep * MAXCRCSTEP); + ULONG bValue; + + for (i = 0; i < CrcStep; i++) { + bValue = FDKreadBits (hBs, MAXCRCSTEP); + calcCRC (&CrcBuf, bValue, MAXCRCSTEP); + } + + bValue = FDKreadBits (hBs, CrcNrBitsRest); + calcCRC (&CrcBuf, bValue, CrcNrBitsRest); + + return (CrcBuf.crcState & SBR_CRC_RANGE); + +} + + +/*! + \brief crc interface + \return 1: CRC OK, 0: CRC check failure +*/ +int +SbrCrcCheck (HANDLE_FDK_BITSTREAM hBs, /*!< handle to bit-buffer */ + LONG NrBits) /*!< max. CRC length */ +{ + int crcResult = 1; + ULONG NrCrcBits; + ULONG crcCheckResult; + LONG NrBitsAvailable; + ULONG crcCheckSum; + + crcCheckSum = FDKreadBits (hBs, 10); + + NrBitsAvailable = FDKgetValidBits(hBs); + if (NrBitsAvailable <= 0){ + return 0; + } + + NrCrcBits = fixMin ((INT)NrBits, (INT)NrBitsAvailable); + + crcCheckResult = getCrc (hBs, NrCrcBits); + FDKpushBack(hBs, (NrBitsAvailable - FDKgetValidBits(hBs)) ); + + + if (crcCheckResult != crcCheckSum) { + crcResult = 0; + } + + return (crcResult); +} diff --git a/libSBRdec/src/sbr_crc.h b/libSBRdec/src/sbr_crc.h new file mode 100644 index 0000000..281f30c --- /dev/null +++ b/libSBRdec/src/sbr_crc.h @@ -0,0 +1,65 @@ +/**************************************************************************** + + (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 CRC checking routines $Revision: 36841 $ +*/ +#ifndef __SBR_CRC_H +#define __SBR_CRC_H + +#include "sbrdecoder.h" + +#include "FDK_bitstream.h" + +/* some useful crc polynoms: + +crc5: x^5+x^4+x^2+x^1+1 +crc6: x^6+x^5+x^3+x^2+x+1 +crc7: x^7+x^6+x^2+1 +crc8: x^8+x^2+x+x+1 +*/ + +/* default SBR CRC */ /* G(x) = x^10 + x^9 + x^5 + x^4 + x + 1 */ +#define SBR_CRC_POLY 0x0233 +#define SBR_CRC_MASK 0x0200 +#define SBR_CRC_START 0x0000 +#define SBR_CRC_RANGE 0x03FF + +typedef struct +{ + USHORT crcState; + USHORT crcMask; + USHORT crcPoly; +} +CRC_BUFFER; + +typedef CRC_BUFFER *HANDLE_CRC; + +int SbrCrcCheck (HANDLE_FDK_BITSTREAM hBitBuf, + LONG NrCrcBits); + + +#endif diff --git a/libSBRdec/src/sbr_deb.cpp b/libSBRdec/src/sbr_deb.cpp new file mode 100644 index 0000000..9bb3179 --- /dev/null +++ b/libSBRdec/src/sbr_deb.cpp @@ -0,0 +1,32 @@ +/**************************************************************************** + + (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 Print selected debug messages $Revision: 36841 $ +*/ + +#include "sbr_deb.h" + diff --git a/libSBRdec/src/sbr_deb.h b/libSBRdec/src/sbr_deb.h new file mode 100644 index 0000000..9135158 --- /dev/null +++ b/libSBRdec/src/sbr_deb.h @@ -0,0 +1,36 @@ +/**************************************************************************** + + (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 Debugging aids $Revision: 36841 $ +*/ + +#ifndef __SBR_DEB_H +#define __SBR_DEB_H + +#include "sbrdecoder.h" + +#endif diff --git a/libSBRdec/src/sbr_dec.cpp b/libSBRdec/src/sbr_dec.cpp new file mode 100644 index 0000000..a075ca3 --- /dev/null +++ b/libSBRdec/src/sbr_dec.cpp @@ -0,0 +1,985 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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 Sbr decoder $Revision: 36841 $ + This module provides the actual decoder implementation. The SBR data (side information) is already + decoded. Only three functions are provided: + + \li 1.) createSbrDec(): One time initialization + \li 2.) resetSbrDec(): Called by sbr_Apply() when the information contained in an SBR_HEADER_ELEMENT requires a reset + and recalculation of important SBR structures. + \li 3.) sbr_dec(): The actual decoder. Calls the different tools such as filterbanks, lppTransposer(), and calculateSbrEnvelope() + [the envelope adjuster]. + + \sa sbr_dec(), \ref documentationOverview +*/ + +#include "sbr_dec.h" + +#include "sbr_ram.h" +#include "env_extr.h" +#include "env_calc.h" +#include "scale.h" + +#include "genericStds.h" + +#include "sbrdec_drc.h" + + + +static void assignLcTimeSlots( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + FIXP_DBL **QmfBufferReal, + int noCols ) +{ + int slot, i; + FIXP_DBL *ptr; + + /* Number of QMF timeslots in the overlap buffer: */ + ptr = hSbrDec->pSbrOverlapBuffer; + for(slot=0; slot<hSbrDec->LppTrans.pSettings->overlap; slot++) { + QmfBufferReal[slot] = ptr; ptr += (64); + } + + /* Assign timeslots to Workbuffer1 */ + ptr = hSbrDec->WorkBuffer1; + for(i=0; i<noCols; i++) { + QmfBufferReal[slot] = ptr; ptr += (64); + slot++; + } +} + + +static void assignHqTimeSlots( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + FIXP_DBL **QmfBufferReal, + FIXP_DBL **QmfBufferImag, + int noCols ) +{ + FIXP_DBL *ptr; + int slot; + + /* Number of QMF timeslots in one half of a frame (size of Workbuffer1 or 2): */ + int halflen = (noCols >> 1) + hSbrDec->LppTrans.pSettings->overlap; + int totCols = noCols + hSbrDec->LppTrans.pSettings->overlap; + + /* Number of QMF timeslots in the overlap buffer: */ + ptr = hSbrDec->pSbrOverlapBuffer; + for(slot=0; slot<hSbrDec->LppTrans.pSettings->overlap; slot++) { + QmfBufferReal[slot] = ptr; ptr += (64); + QmfBufferImag[slot] = ptr; ptr += (64); + } + + /* Assign first half of timeslots to Workbuffer1 */ + ptr = hSbrDec->WorkBuffer1; + for(; slot<halflen; slot++) { + QmfBufferReal[slot] = ptr; ptr += (64); + QmfBufferImag[slot] = ptr; ptr += (64); + } + + /* Assign second half of timeslots to Workbuffer2 */ + ptr = hSbrDec->WorkBuffer2; + for(; slot<totCols; slot++) { + QmfBufferReal[slot] = ptr; ptr += (64); + QmfBufferImag[slot] = ptr; ptr += (64); + } +} + + +static void assignTimeSlots( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + int noCols, + int useLP ) +{ + /* assign qmf time slots */ + hSbrDec->useLP = useLP; + if (useLP) { + hSbrDec->SynthesisQMF.flags |= QMF_FLAG_LP; + hSbrDec->AnalysiscQMF.flags |= QMF_FLAG_LP; + } else { + hSbrDec->SynthesisQMF.flags &= ~QMF_FLAG_LP; + hSbrDec->AnalysiscQMF.flags &= ~QMF_FLAG_LP; + } + if (!useLP) + assignHqTimeSlots( hSbrDec, hSbrDec->QmfBufferReal, hSbrDec->QmfBufferImag, noCols ); + else + { + assignLcTimeSlots( hSbrDec, hSbrDec->QmfBufferReal, noCols ); + } +} + +static void changeQmfType( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + int useLdTimeAlign ) +{ + UINT synQmfFlags = hSbrDec->SynthesisQMF.flags; + UINT anaQmfFlags = hSbrDec->AnalysiscQMF.flags; + int resetSynQmf = 0; + int resetAnaQmf = 0; + + /* assign qmf type */ + if (useLdTimeAlign) { + if (synQmfFlags & QMF_FLAG_CLDFB) { + /* change the type to MPSLD */ + synQmfFlags &= ~QMF_FLAG_CLDFB; + synQmfFlags |= QMF_FLAG_MPSLDFB; + resetSynQmf = 1; + } + if (anaQmfFlags & QMF_FLAG_CLDFB) { + /* change the type to MPSLD */ + anaQmfFlags &= ~QMF_FLAG_CLDFB; + anaQmfFlags |= QMF_FLAG_MPSLDFB; + resetAnaQmf = 1; + } + } else { + if (synQmfFlags & QMF_FLAG_MPSLDFB) { + /* change the type to CLDFB */ + synQmfFlags &= ~QMF_FLAG_MPSLDFB; + synQmfFlags |= QMF_FLAG_CLDFB; + resetSynQmf = 1; + } + if (anaQmfFlags & QMF_FLAG_MPSLDFB) { + /* change the type to CLDFB */ + anaQmfFlags &= ~QMF_FLAG_MPSLDFB; + anaQmfFlags |= QMF_FLAG_CLDFB; + resetAnaQmf = 1; + } + } + + if (resetAnaQmf) { + int qmfErr = qmfInitAnalysisFilterBank ( + &hSbrDec->AnalysiscQMF, + hSbrDec->anaQmfStates, + hSbrDec->AnalysiscQMF.no_col, + hSbrDec->AnalysiscQMF.lsb, + hSbrDec->AnalysiscQMF.usb, + hSbrDec->AnalysiscQMF.no_channels, + anaQmfFlags | QMF_FLAG_KEEP_STATES + ); + if (qmfErr != 0) { + FDK_ASSERT(0); + } + } + + if (resetSynQmf) { + int qmfErr = qmfInitSynthesisFilterBank ( + &hSbrDec->SynthesisQMF, + hSbrDec->pSynQmfStates, + hSbrDec->SynthesisQMF.no_col, + hSbrDec->SynthesisQMF.lsb, + hSbrDec->SynthesisQMF.usb, + hSbrDec->SynthesisQMF.no_channels, + synQmfFlags | QMF_FLAG_KEEP_STATES + ); + + if (qmfErr != 0) { + FDK_ASSERT(0); + } + } +} + + +/*! + \brief SBR decoder core function for one channel + + \image html BufferMgmtDetailed-1632.png + + Besides the filter states of the QMF filter bank and the LPC-states of + the LPP-Transposer, processing is mainly based on four buffers: + #timeIn, #timeOut, #WorkBuffer2 and #OverlapBuffer. The #WorkBuffer2 + is reused for all channels and might be used by the core decoder, a + static overlap buffer is required for each channel. Du to in-place + processing, #timeIn and #timeOut point to identical locations. + + The spectral data is organized in so-called slots, each slot + containing 64 bands of complex data. The number of slots per frame is + dependend on the frame size. For mp3PRO, there are 18 slots per frame + and 6 slots per #OverlapBuffer. It is not necessary to have the slots + in located consecutive address ranges. + + To optimize memory usage and to minimize the number of memory + accesses, the memory management is organized as follows (Slot numbers + based on mp3PRO): + + 1.) Input time domain signal is located in #timeIn, the last slots + (0..5) of the spectral data of the previous frame are located in the + #OverlapBuffer. In addition, #frameData of the current frame resides + in the upper part of #timeIn. + + 2.) During the cplxAnalysisQmfFiltering(), 32 samples from #timeIn are transformed + into a slot of up to 32 complex spectral low band values at a + time. The first spectral slot -- nr. 6 -- is written at slot number + zero of #WorkBuffer2. #WorkBuffer2 will be completely filled with + spectral data. + + 3.) LPP-Transposition in lppTransposer() is processed on 24 slots. During the + transposition, the high band part of the spectral data is replicated + based on the low band data. + + Envelope Adjustment is processed on the high band part of the spectral + data only by calculateSbrEnvelope(). + + 4.) The cplxSynthesisQmfFiltering() creates 64 time domain samples out + of a slot of 64 complex spectral values at a time. The first 6 slots + in #timeOut are filled from the results of spectral slots 0..5 in the + #OverlapBuffer. The consecutive slots in timeOut are now filled with + the results of spectral slots 6..17. + + 5.) The preprocessed slots 18..23 have to be stored in the + #OverlapBuffer. + +*/ + +void +sbr_dec ( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + INT_PCM *timeIn, /*!< pointer to input time signal */ + INT_PCM *timeOut, /*!< pointer to output time signal */ + HANDLE_SBR_DEC hSbrDecRight, /*!< handle to Decoder channel right */ + INT_PCM *timeOutRight, /*!< pointer to output time signal */ + const int strideIn, /*!< Time data traversal strideIn */ + const int strideOut, /*!< Time data traversal strideOut */ + HANDLE_SBR_HEADER_DATA hHeaderData,/*!< Static control data */ + HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */ + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, /*!< Some control data of last frame */ + const int applyProcessing, /*!< Flag for SBR operation */ + HANDLE_PS_DEC h_ps_d, + const UINT flags + ) +{ + int i, slot, reserve; + int saveLbScale; + int ov_len; + int lastSlotOffs; + FIXP_DBL maxVal; + + /* 1+1/3 frames of spectral data: */ + FIXP_DBL **QmfBufferReal = hSbrDec->QmfBufferReal; + FIXP_DBL **QmfBufferImag = hSbrDec->QmfBufferImag; + + /* Number of QMF timeslots in the overlap buffer: */ + ov_len = hSbrDec->LppTrans.pSettings->overlap; + + /* Number of QMF slots per frame */ + int noCols = hHeaderData->numberTimeSlots * hHeaderData->timeStep; + + /* assign qmf time slots */ + if ( ((flags & SBRDEC_LOW_POWER ) ? 1 : 0) != ((hSbrDec->SynthesisQMF.flags & QMF_FLAG_LP) ? 1 : 0) ) { + assignTimeSlots( hSbrDec, hHeaderData->numberTimeSlots * hHeaderData->timeStep, flags & SBRDEC_LOW_POWER); + } + + if (flags & SBRDEC_ELD_GRID) { + /* Choose the right low delay filter bank */ + changeQmfType( hSbrDec, (flags & SBRDEC_LD_MPS_QMF) ? 1 : 0 ); + } + + /* + low band codec signal subband filtering + */ + + { + C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2*(64)); + + qmfAnalysisFiltering( &hSbrDec->AnalysiscQMF, + QmfBufferReal + ov_len, + QmfBufferImag + ov_len, + &hSbrDec->sbrScaleFactor, + timeIn, + strideIn, + qmfTemp + ); + + C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2*(64)); + } + + /* + Clear upper half of spectrum + */ + { + int nAnalysisBands = hHeaderData->numberOfAnalysisBands; + + if (! (flags & SBRDEC_LOW_POWER)) { + for (slot = ov_len; slot < noCols+ov_len; slot++) { + FDKmemclear(&QmfBufferReal[slot][nAnalysisBands],((64)-nAnalysisBands)*sizeof(FIXP_DBL)); + FDKmemclear(&QmfBufferImag[slot][nAnalysisBands],((64)-nAnalysisBands)*sizeof(FIXP_DBL)); + } + } else + for (slot = ov_len; slot < noCols+ov_len; slot++) { + FDKmemclear(&QmfBufferReal[slot][nAnalysisBands],((64)-nAnalysisBands)*sizeof(FIXP_DBL)); + } + } + + + + /* + Shift spectral data left to gain accuracy in transposer and adjustor + */ + maxVal = maxSubbandSample( QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + 0, + hSbrDec->AnalysiscQMF.lsb, + ov_len, + noCols+ov_len ); + + reserve = fixMax(0,CntLeadingZeros(maxVal)-1) ; + reserve = fixMin(reserve,DFRACT_BITS-1-hSbrDec->sbrScaleFactor.lb_scale); + + /* If all data is zero, lb_scale could become too large */ + rescaleSubbandSamples( QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + 0, + hSbrDec->AnalysiscQMF.lsb, + ov_len, + noCols+ov_len, + reserve); + + hSbrDec->sbrScaleFactor.lb_scale += reserve; + + /* + save low band scale, wavecoding or parametric stereo may modify it + */ + saveLbScale = hSbrDec->sbrScaleFactor.lb_scale; + + + if (applyProcessing) + { + UCHAR * borders = hFrameData->frameInfo.borders; + lastSlotOffs = borders[hFrameData->frameInfo.nEnvelopes] - hHeaderData->numberTimeSlots; + + FIXP_DBL degreeAlias[(64)]; + + /* The transposer will override most values in degreeAlias[]. + The array needs to be cleared at least from lowSubband to highSubband before. */ + if (flags & SBRDEC_LOW_POWER) + FDKmemclear(°reeAlias[hHeaderData->freqBandData.lowSubband], (hHeaderData->freqBandData.highSubband-hHeaderData->freqBandData.lowSubband)*sizeof(FIXP_DBL)); + + /* + Inverse filtering of lowband and transposition into the SBR-frequency range + */ + + lppTransposer ( &hSbrDec->LppTrans, + &hSbrDec->sbrScaleFactor, + QmfBufferReal, + degreeAlias, // only used if useLP = 1 + QmfBufferImag, + flags & SBRDEC_LOW_POWER, + hHeaderData->timeStep, + borders[0], + lastSlotOffs, + hHeaderData->freqBandData.nInvfBands, + hFrameData->sbr_invf_mode, + hPrevFrameData->sbr_invf_mode ); + + + + + + /* + Adjust envelope of current frame. + */ + + calculateSbrEnvelope (&hSbrDec->sbrScaleFactor, + &hSbrDec->SbrCalculateEnvelope, + hHeaderData, + hFrameData, + QmfBufferReal, + QmfBufferImag, + flags & SBRDEC_LOW_POWER, + + degreeAlias, + flags, + (hHeaderData->frameErrorFlag || hPrevFrameData->frameErrorFlag)); + + + /* + Update hPrevFrameData (to be used in the next frame) + */ + for (i=0; i<hHeaderData->freqBandData.nInvfBands; i++) { + hPrevFrameData->sbr_invf_mode[i] = hFrameData->sbr_invf_mode[i]; + } + hPrevFrameData->coupling = hFrameData->coupling; + hPrevFrameData->stopPos = borders[hFrameData->frameInfo.nEnvelopes]; + hPrevFrameData->ampRes = hFrameData->ampResolutionCurrentFrame; + } + else { + /* Reset hb_scale if no highband is present, because hb_scale is considered in the QMF-synthesis */ + hSbrDec->sbrScaleFactor.hb_scale = saveLbScale; + } + + + for (i=0; i<LPC_ORDER; i++){ + /* + Store the unmodified qmf Slots values (required for LPC filtering) + */ + if (! (flags & SBRDEC_LOW_POWER)) { + FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesReal[i], QmfBufferReal[noCols-LPC_ORDER+i], hSbrDec->AnalysiscQMF.lsb*sizeof(FIXP_DBL)); + FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesImag[i], QmfBufferImag[noCols-LPC_ORDER+i], hSbrDec->AnalysiscQMF.lsb*sizeof(FIXP_DBL)); + } else + FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesReal[i], QmfBufferReal[noCols-LPC_ORDER+i], hSbrDec->AnalysiscQMF.lsb*sizeof(FIXP_DBL)); + } + + /* + Synthesis subband filtering. + */ + + if ( ! (flags & SBRDEC_PS_DECODED) ) { + + { + int outScalefactor = 0; + + if (h_ps_d != NULL) { + h_ps_d->procFrameBased = 1; /* we here do frame based processing */ + } + + + sbrDecoder_drcApply(&hSbrDec->sbrDrcChannel, + QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + hSbrDec->SynthesisQMF.no_col, + &outScalefactor + ); + + + + qmfChangeOutScalefactor(&hSbrDec->SynthesisQMF, outScalefactor ); + + { + C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2*(64)); + + qmfSynthesisFiltering( &hSbrDec->SynthesisQMF, + QmfBufferReal, + (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag, + &hSbrDec->sbrScaleFactor, + hSbrDec->LppTrans.pSettings->overlap, + timeOut, + strideOut, + qmfTemp); + + C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2*(64)); + } + + } + + } else { /* (flags & SBRDEC_PS_DECODED) */ + INT i, sdiff, outScalefactor, scaleFactorLowBand, scaleFactorHighBand; + SCHAR scaleFactorLowBand_ov, scaleFactorLowBand_no_ov; + + HANDLE_QMF_FILTER_BANK synQmf = &hSbrDec->SynthesisQMF; + HANDLE_QMF_FILTER_BANK synQmfRight = &hSbrDecRight->SynthesisQMF; + + /* adapt scaling */ + sdiff = hSbrDec->sbrScaleFactor.lb_scale - reserve; /* Scaling difference */ + scaleFactorHighBand = sdiff - hSbrDec->sbrScaleFactor.hb_scale; /* Scale of current high band */ + scaleFactorLowBand_ov = sdiff - hSbrDec->sbrScaleFactor.ov_lb_scale; /* Scale of low band overlapping QMF data */ + scaleFactorLowBand_no_ov = sdiff - hSbrDec->sbrScaleFactor.lb_scale; /* Scale of low band current QMF data */ + outScalefactor = 0; /* Initial output scale */ + + if (h_ps_d->procFrameBased == 1) /* If we have switched from frame to slot based processing copy filter states */ + { /* procFrameBased will be unset later */ + /* copy filter states from left to right */ + FDKmemcpy(synQmfRight->FilterStates, synQmf->FilterStates, ((640)-(64))*sizeof(FIXP_QSS)); + } + + /* scale ALL qmf vales ( real and imag ) of mono / left channel to the + same scale factor ( ov_lb_sf, lb_sf and hq_sf ) */ + scalFilterBankValues( h_ps_d, /* parametric stereo decoder handle */ + QmfBufferReal, /* qmf filterbank values */ + QmfBufferImag, /* qmf filterbank values */ + synQmf->lsb, /* sbr start subband */ + hSbrDec->sbrScaleFactor.ov_lb_scale, + hSbrDec->sbrScaleFactor.lb_scale, + &scaleFactorLowBand_ov, /* adapt scaling values */ + &scaleFactorLowBand_no_ov, /* adapt scaling values */ + hSbrDec->sbrScaleFactor.hb_scale, /* current frame ( highband ) */ + &scaleFactorHighBand, + synQmf->no_col); + + /* use the same synthese qmf values for left and right channel */ + synQmfRight->no_col = synQmf->no_col; + synQmfRight->lsb = synQmf->lsb; + synQmfRight->usb = synQmf->usb; + + int env=0; + + outScalefactor += (SCAL_HEADROOM+1); /* psDiffScale! */ + + { + C_ALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 2*(64)); + + int maxShift = 0; + + if (hSbrDec->sbrDrcChannel.prevFact_exp > maxShift) { + maxShift = hSbrDec->sbrDrcChannel.prevFact_exp; + } + if (hSbrDec->sbrDrcChannel.currFact_exp > maxShift) { + maxShift = hSbrDec->sbrDrcChannel.currFact_exp; + } + if (hSbrDec->sbrDrcChannel.nextFact_exp > maxShift) { + maxShift = hSbrDec->sbrDrcChannel.nextFact_exp; + } + + for (i = 0; i < synQmf->no_col; i++) { /* ----- no_col loop ----- */ + + INT outScalefactorR, outScalefactorL; + outScalefactorR = outScalefactorL = outScalefactor; + + /* qmf timeslot of right channel */ + FIXP_DBL* rQmfReal = pWorkBuffer; + FIXP_DBL* rQmfImag = pWorkBuffer + 64; + + + { + if ( i == h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env] ) { + initSlotBasedRotation( h_ps_d, env, hHeaderData->freqBandData.highSubband ); + env++; + } + + ApplyPsSlot( h_ps_d, /* parametric stereo decoder handle */ + (QmfBufferReal + i), /* one timeslot of left/mono channel */ + (QmfBufferImag + i), /* one timeslot of left/mono channel */ + rQmfReal, /* one timeslot or right channel */ + rQmfImag); /* one timeslot or right channel */ + } + + + scaleFactorLowBand = (i<(6)) ? scaleFactorLowBand_ov : scaleFactorLowBand_no_ov; + + + sbrDecoder_drcApplySlot ( /* right channel */ + &hSbrDec->sbrDrcChannel, + rQmfReal, + rQmfImag, + i, + synQmfRight->no_col, + maxShift + ); + + outScalefactorR += maxShift; + + sbrDecoder_drcApplySlot ( /* left channel */ + &hSbrDec->sbrDrcChannel, + *(QmfBufferReal + i), + *(QmfBufferImag + i), + i, + synQmf->no_col, + maxShift + ); + + outScalefactorL += maxShift; + + + /* scale filter states for left and right channel */ + qmfChangeOutScalefactor( synQmf, outScalefactorL ); + qmfChangeOutScalefactor( synQmfRight, outScalefactorR ); + + { + + qmfSynthesisFilteringSlot( synQmfRight, + rQmfReal, /* QMF real buffer */ + rQmfImag, /* QMF imag buffer */ + scaleFactorLowBand, + scaleFactorHighBand, + timeOutRight+(i*synQmf->no_channels*strideOut), + strideOut, + pWorkBuffer); + + qmfSynthesisFilteringSlot( synQmf, + *(QmfBufferReal + i), /* QMF real buffer */ + *(QmfBufferImag + i), /* QMF imag buffer */ + scaleFactorLowBand, + scaleFactorHighBand, + timeOut+(i*synQmf->no_channels*strideOut), + strideOut, + pWorkBuffer); + + } + } /* no_col loop i */ + + /* scale back (6) timeslots look ahead for hybrid filterbank to original value */ + rescalFilterBankValues( h_ps_d, + QmfBufferReal, + QmfBufferImag, + synQmf->lsb, + synQmf->no_col ); + + C_ALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 2*(64)); + } + } + + sbrDecoder_drcUpdateChannel( &hSbrDec->sbrDrcChannel ); + + + /* + Update overlap buffer + Even bands above usb are copied to avoid outdated spectral data in case + the stop frequency raises. + */ + + if (hSbrDec->LppTrans.pSettings->overlap > 0) + { + if (! (flags & SBRDEC_LOW_POWER)) { + for ( i=0; i<hSbrDec->LppTrans.pSettings->overlap; i++ ) { + FDKmemcpy(QmfBufferReal[i], QmfBufferReal[i+noCols], (64)*sizeof(FIXP_DBL)); + FDKmemcpy(QmfBufferImag[i], QmfBufferImag[i+noCols], (64)*sizeof(FIXP_DBL)); + } + } else + for ( i=0; i<hSbrDec->LppTrans.pSettings->overlap; i++ ) { + FDKmemcpy(QmfBufferReal[i], QmfBufferReal[i+noCols], (64)*sizeof(FIXP_DBL)); + } + } + + hSbrDec->sbrScaleFactor.ov_lb_scale = saveLbScale; + + /* Save current frame status */ + hPrevFrameData->frameErrorFlag = hHeaderData->frameErrorFlag; + +} // sbr_dec() + + +/*! + \brief Creates sbr decoder structure + \return errorCode, 0 if successful +*/ +SBR_ERROR +createSbrDec (SBR_CHANNEL * hSbrChannel, + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */ + TRANSPOSER_SETTINGS *pSettings, + const int downsampleFac, /*!< Downsampling factor */ + const UINT qmfFlags, /*!< flags -> 1: HQ/LP selector, 2: CLDFB */ + const UINT flags, + const int overlap, + int chan) /*!< Channel for which to assign buffers etc. */ + +{ + SBR_ERROR err = SBRDEC_OK; + int timeSlots = hHeaderData->numberTimeSlots; /* Number of SBR slots per frame */ + int noCols = timeSlots * hHeaderData->timeStep; /* Number of QMF slots per frame */ + HANDLE_SBR_DEC hs = &(hSbrChannel->SbrDec); + + /* Initialize scale factors */ + hs->sbrScaleFactor.ov_lb_scale = 0; + hs->sbrScaleFactor.ov_hb_scale = 0; + hs->sbrScaleFactor.hb_scale = 0; + + + /* + create envelope calculator + */ + err = createSbrEnvelopeCalc (&hs->SbrCalculateEnvelope, + hHeaderData, + chan, + flags); + if (err != SBRDEC_OK) { + return err; + } + + /* + create QMF filter banks + */ + { + int qmfErr; + + qmfErr = qmfInitAnalysisFilterBank ( + &hs->AnalysiscQMF, + hs->anaQmfStates, + noCols, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.highSubband, + hHeaderData->numberOfAnalysisBands, + qmfFlags & (~QMF_FLAG_KEEP_STATES) + ); + if (qmfErr != 0) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + } + if (hs->pSynQmfStates == NULL) { + hs->pSynQmfStates = GetRam_sbr_QmfStatesSynthesis(chan); + if (hs->pSynQmfStates == NULL) + return SBRDEC_MEM_ALLOC_FAILED; + } + + { + int qmfErr; + + qmfErr = qmfInitSynthesisFilterBank ( + &hs->SynthesisQMF, + hs->pSynQmfStates, + noCols, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.highSubband, + (64) / downsampleFac, + qmfFlags & (~QMF_FLAG_KEEP_STATES) + ); + + if (qmfErr != 0) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + } + initSbrPrevFrameData (&hSbrChannel->prevFrameData, timeSlots); + + /* + create transposer + */ + err = createLppTransposer (&hs->LppTrans, + pSettings, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.v_k_master, + hHeaderData->freqBandData.numMaster, + hs->SynthesisQMF.usb, + timeSlots, + hs->AnalysiscQMF.no_col, + hHeaderData->freqBandData.freqBandTableNoise, + hHeaderData->freqBandData.nNfb, + hHeaderData->sbrProcSmplRate, + chan, + overlap ); + if (err != SBRDEC_OK) { + return err; + } + + /* The CLDFB does not have overlap */ + if ((qmfFlags & QMF_FLAG_CLDFB) == 0) { + if (hs->pSbrOverlapBuffer == NULL) { + hs->pSbrOverlapBuffer = GetRam_sbr_OverlapBuffer(chan); + if (hs->pSbrOverlapBuffer == NULL) { + return SBRDEC_MEM_ALLOC_FAILED; + } + } else { + /* Clear overlap buffer */ + FDKmemclear( hs->pSbrOverlapBuffer, + sizeof(FIXP_DBL) * 2 * (6) * (64) + ); + } + } + + /* assign qmf time slots */ + assignTimeSlots( &hSbrChannel->SbrDec, hHeaderData->numberTimeSlots * hHeaderData->timeStep, qmfFlags & QMF_FLAG_LP); + + return err; +} + +/*! + \brief Delete sbr decoder structure + \return errorCode, 0 if successful +*/ +int +deleteSbrDec (SBR_CHANNEL * hSbrChannel) +{ + HANDLE_SBR_DEC hs = &hSbrChannel->SbrDec; + + deleteSbrEnvelopeCalc (&hs->SbrCalculateEnvelope); + + /* delete QMF filter states */ + if (hs->pSynQmfStates != NULL) { + FreeRam_sbr_QmfStatesSynthesis(&hs->pSynQmfStates); + } + + + if (hs->pSbrOverlapBuffer != NULL) { + FreeRam_sbr_OverlapBuffer(&hs->pSbrOverlapBuffer); + } + + return 0; +} + + +/*! + \brief resets sbr decoder structure + \return errorCode, 0 if successful +*/ +SBR_ERROR +resetSbrDec (HANDLE_SBR_DEC hSbrDec, + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, + const int useLP, + const int downsampleFac + ) +{ + SBR_ERROR sbrError = SBRDEC_OK; + + int old_lsb = hSbrDec->SynthesisQMF.lsb; + int new_lsb = hHeaderData->freqBandData.lowSubband; + int l, startBand, stopBand, startSlot, size; + + int source_scale, target_scale, delta_scale, target_lsb, target_usb, reserve; + FIXP_DBL maxVal; + + /* overlapBuffer point to first (6) slots */ + FIXP_DBL **OverlapBufferReal = hSbrDec->QmfBufferReal; + FIXP_DBL **OverlapBufferImag = hSbrDec->QmfBufferImag; + + /* assign qmf time slots */ + assignTimeSlots( hSbrDec, hHeaderData->numberTimeSlots * hHeaderData->timeStep, useLP); + + + + resetSbrEnvelopeCalc (&hSbrDec->SbrCalculateEnvelope); + + hSbrDec->SynthesisQMF.lsb = hHeaderData->freqBandData.lowSubband; + hSbrDec->SynthesisQMF.usb = fixMin((INT)hSbrDec->SynthesisQMF.no_channels, (INT)hHeaderData->freqBandData.highSubband); + + hSbrDec->AnalysiscQMF.lsb = hSbrDec->SynthesisQMF.lsb; + hSbrDec->AnalysiscQMF.usb = hSbrDec->SynthesisQMF.usb; + + + /* + The following initialization of spectral data in the overlap buffer + is required for dynamic x-over or a change of the start-freq for 2 reasons: + + 1. If the lowband gets _wider_, unadjusted data would remain + + 2. If the lowband becomes _smaller_, the highest bands of the old lowband + must be cleared because the whitening would be affected + */ + startBand = old_lsb; + stopBand = new_lsb; + startSlot = hHeaderData->timeStep * (hPrevFrameData->stopPos - hHeaderData->numberTimeSlots); + size = fixMax(0,stopBand-startBand); + + /* keep already adjusted data in the x-over-area */ + if (!useLP) { + for (l=startSlot; l<hSbrDec->LppTrans.pSettings->overlap; l++) { + FDKmemclear(&OverlapBufferReal[l][startBand], size*sizeof(FIXP_DBL)); + FDKmemclear(&OverlapBufferImag[l][startBand], size*sizeof(FIXP_DBL)); + } + } else + for (l=startSlot; l<hSbrDec->LppTrans.pSettings->overlap ; l++) { + FDKmemclear(&OverlapBufferReal[l][startBand], size*sizeof(FIXP_DBL)); + } + + + /* + reset LPC filter states + */ + startBand = fixMin(old_lsb,new_lsb); + stopBand = fixMax(old_lsb,new_lsb); + size = fixMax(0,stopBand-startBand); + + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesReal[0][startBand], size*sizeof(FIXP_DBL)); + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesReal[1][startBand], size*sizeof(FIXP_DBL)); + if (!useLP) { + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImag[0][startBand], size*sizeof(FIXP_DBL)); + FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImag[1][startBand], size*sizeof(FIXP_DBL)); + } + + + /* + Rescale already processed spectral data between old and new x-over frequency. + This must be done because of the separate scalefactors for lowband and highband. + */ + startBand = fixMin(old_lsb,new_lsb); + stopBand = fixMax(old_lsb,new_lsb); + + if (new_lsb > old_lsb) { + /* The x-over-area was part of the highband before and will now belong to the lowband */ + source_scale = hSbrDec->sbrScaleFactor.ov_hb_scale; + target_scale = hSbrDec->sbrScaleFactor.ov_lb_scale; + target_lsb = 0; + target_usb = old_lsb; + } + else { + /* The x-over-area was part of the lowband before and will now belong to the highband */ + source_scale = hSbrDec->sbrScaleFactor.ov_lb_scale; + target_scale = hSbrDec->sbrScaleFactor.ov_hb_scale; + /* jdr: The values old_lsb and old_usb might be wrong because the previous frame might have been "upsamling". */ + target_lsb = hSbrDec->SynthesisQMF.lsb; + target_usb = hSbrDec->SynthesisQMF.usb; + } + + /* Shift left all samples of the x-over-area as much as possible + An unnecessary coarse scale could cause ov_lb_scale or ov_hb_scale to be + adapted and the accuracy in the next frame would seriously suffer! */ + + maxVal = maxSubbandSample( OverlapBufferReal, + (useLP) ? NULL : OverlapBufferImag, + startBand, + stopBand, + 0, + startSlot); + + reserve = CntLeadingZeros(maxVal)-1; + reserve = fixMin(reserve,DFRACT_BITS-1-source_scale); + + rescaleSubbandSamples( OverlapBufferReal, + (useLP) ? NULL : OverlapBufferImag, + startBand, + stopBand, + 0, + startSlot, + reserve); + source_scale += reserve; + + delta_scale = target_scale - source_scale; + + if (delta_scale > 0) { /* x-over-area is dominant */ + delta_scale = -delta_scale; + startBand = target_lsb; + stopBand = target_usb; + + if (new_lsb > old_lsb) { + /* The lowband has to be rescaled */ + hSbrDec->sbrScaleFactor.ov_lb_scale = source_scale; + } + else { + /* The highband has be be rescaled */ + hSbrDec->sbrScaleFactor.ov_hb_scale = source_scale; + } + } + + FDK_ASSERT(startBand <= stopBand); + + if (!useLP) { + for (l=0; l<startSlot; l++) { + scaleValues( OverlapBufferReal[l] + startBand, stopBand-startBand, delta_scale ); + scaleValues( OverlapBufferImag[l] + startBand, stopBand-startBand, delta_scale ); + } + } else + for (l=0; l<startSlot; l++) { + scaleValues( OverlapBufferReal[l] + startBand, stopBand-startBand, delta_scale ); + } + + + /* + Initialize transposer and limiter + */ + sbrError = resetLppTransposer (&hSbrDec->LppTrans, + hHeaderData->freqBandData.lowSubband, + hHeaderData->freqBandData.v_k_master, + hHeaderData->freqBandData.numMaster, + hHeaderData->freqBandData.freqBandTableNoise, + hHeaderData->freqBandData.nNfb, + hHeaderData->freqBandData.highSubband, + hHeaderData->sbrProcSmplRate); + if (sbrError != SBRDEC_OK) + return sbrError; + + sbrError = ResetLimiterBands ( hHeaderData->freqBandData.limiterBandTable, + &hHeaderData->freqBandData.noLimiterBands, + hHeaderData->freqBandData.freqBandTable[0], + hHeaderData->freqBandData.nSfb[0], + hSbrDec->LppTrans.pSettings->patchParam, + hSbrDec->LppTrans.pSettings->noOfPatches, + hHeaderData->bs_data.limiterBands); + + + return sbrError; +} diff --git a/libSBRdec/src/sbr_dec.h b/libSBRdec/src/sbr_dec.h new file mode 100644 index 0000000..d967957 --- /dev/null +++ b/libSBRdec/src/sbr_dec.h @@ -0,0 +1,152 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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 Sbr decoder $Revision: 36841 $ +*/ +#ifndef __SBR_DEC_H +#define __SBR_DEC_H + +#include "sbrdecoder.h" + +#include "lpp_tran.h" +#include "qmf.h" +#include "env_calc.h" +#include "FDK_audio.h" + + +#include "sbrdec_drc.h" + +#define SACDEC_ALIGNMENT_FIX + +typedef struct +{ + QMF_FILTER_BANK AnalysiscQMF; + QMF_FILTER_BANK SynthesisQMF; + + SBR_CALCULATE_ENVELOPE SbrCalculateEnvelope; + SBR_LPP_TRANS LppTrans; + + QMF_SCALE_FACTOR sbrScaleFactor; + QMF_SCALE_FACTOR sbrScaleFactorRight; + + /*! Delayed spectral data needed for the dynamic framing of SBR. Not required in case of CLDFB */ + FIXP_DBL * pSbrOverlapBuffer; + + /* References to workbuffers */ + FIXP_DBL * WorkBuffer1; + FIXP_DBL * WorkBuffer2; + + /* QMF filter states */ + FIXP_QAS anaQmfStates[(320)]; + FIXP_QSS * pSynQmfStates; + + /* Reference pointer arrays for QMF time slots, + mixed among overlap and current slots. */ + FIXP_DBL * QmfBufferReal[(((1024)/(32))+(6))]; + FIXP_DBL * QmfBufferImag[(((1024)/(32))+(6))]; + int useLP; + + /* QMF domain extension time slot reference pointer array */ + + SBRDEC_DRC_CHANNEL sbrDrcChannel; + +} SBR_DEC; + +typedef SBR_DEC *HANDLE_SBR_DEC; + + +typedef struct +{ + SBR_FRAME_DATA frameData[(1)+1]; + SBR_PREV_FRAME_DATA prevFrameData; + SBR_DEC SbrDec; +} +SBR_CHANNEL; + +typedef SBR_CHANNEL *HANDLE_SBR_CHANNEL; + +void +SbrDecodeAndProcess (HANDLE_SBR_DEC hSbrDec, + INT_PCM *timeIn, + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_FRAME_DATA hFrameData, + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, + int applyProcessing, + int channelNr + , UCHAR useLP + ); + + +void +SbrConstructTimeOutput (HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + INT_PCM *timeOut, /*!< pointer to output time signal */ + HANDLE_SBR_HEADER_DATA hHeaderData,/*!< Static control data */ + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, /*!< Some control data of last frame */ + int channelNr + ,UCHAR useLP + ); + + +void +sbr_dec (HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ + INT_PCM *timeIn, /*!< pointer to input time signal */ + INT_PCM *timeOut, /*!< pointer to output time signal */ + HANDLE_SBR_DEC hSbrDecRight, /*!< handle to Decoder channel right */ + INT_PCM *timeOutRight, /*!< pointer to output time signal */ + const int strideIn, /*!< Time data traversal strideIn */ + const int strideOut, /*!< Time data traversal strideOut */ + HANDLE_SBR_HEADER_DATA hHeaderData,/*!< Static control data */ + HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */ + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, /*!< Some control data of last frame */ + const int applyProcessing, /*!< Flag for SBR operation */ + HANDLE_PS_DEC h_ps_d, + const UINT flags + ); + + + +SBR_ERROR +createSbrDec (SBR_CHANNEL * hSbrChannel, + HANDLE_SBR_HEADER_DATA hHeaderData, + TRANSPOSER_SETTINGS *pSettings, + const int downsampleFac, + const UINT qmfFlags, + const UINT flags, + const int overlap, + int chan); + +int +deleteSbrDec (SBR_CHANNEL * hSbrChannel); + +SBR_ERROR +resetSbrDec (HANDLE_SBR_DEC hSbrDec, + HANDLE_SBR_HEADER_DATA hHeaderData, + HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, + const int useLP, + const int downsampleFac); + +#endif diff --git a/libSBRdec/src/sbr_ram.cpp b/libSBRdec/src/sbr_ram.cpp new file mode 100644 index 0000000..6fa34a5 --- /dev/null +++ b/libSBRdec/src/sbr_ram.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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 Memory layout + $Revision: 36841 $ + + This module declares all static and dynamic memory spaces +*/ + +#include "sbr_ram.h" + + + + +#define WORKBUFFER1_TAG 0 +#define WORKBUFFER2_TAG 1 + +/*! + \name StaticSbrData + + Static memory areas, must not be overwritten in other sections of the decoder +*/ +/* @{ */ + +/*! SBR Decoder main structure */ +C_ALLOC_MEM(Ram_SbrDecoder, struct SBR_DECODER_INSTANCE, 1) +/*! SBR Decoder element data <br> + Dimension: (4) */ +C_ALLOC_MEM2(Ram_SbrDecElement, SBR_DECODER_ELEMENT, 1, (4)) +/*! SBR Decoder individual channel data <br> + Dimension: (6) */ +C_ALLOC_MEM2(Ram_SbrDecChannel, SBR_CHANNEL, 1, (6)+1) + +/*! Filter states for QMF-synthesis. <br> + Dimension: #(6) * (#QMF_FILTER_STATE_SYN_SIZE-#(64)) */ +C_AALLOC_MEM2_L(Ram_sbr_QmfStatesSynthesis, FIXP_QSS, (640)-(64), (6)+1, SECT_DATA_L1) + +/*! Delayed spectral data needed for the dynamic framing of SBR. + For mp3PRO, 1/3 of a frame is buffered (#(6) 6) */ +C_AALLOC_MEM2(Ram_sbr_OverlapBuffer, FIXP_DBL, 2 * (6) * (64), (6)+1) + +/*! Static Data of PS */ + +C_ALLOC_MEM(Ram_ps_dec, PS_DEC, 1) + + +/* @} */ + + +/*! + \name DynamicSbrData + + Dynamic memory areas, might be reused in other algorithm sections, + e.g. the core decoder + <br> + Depending on the mode set by DONT_USE_CORE_WORKBUFFER, workbuffers are + defined additionally to the CoreWorkbuffer. + <br> + The size of WorkBuffers is ((1024)/(32))*(64) = 2048. + <br> + WorkBuffer2 is a pointer to the CoreWorkBuffer wich is reused here in the SBR part. In case of + DONT_USE_CORE_WORKBUFFER, the CoreWorkbuffer is not used and the according + Workbuffer2 is defined locally in this file. + <br> + WorkBuffer1 is reused in the AAC core (-> aacdecoder.cpp, aac_ram.cpp) + <br> + + Use of WorkBuffers: + <pre> + + ------------------------------------------------------------- + AAC core: + + CoreWorkbuffer: spectral coefficients + WorkBuffer1: CAacDecoderChannelInfo, CAacDecoderDynamicData + + ------------------------------------------------------------- + SBR part: + ---------------------------------------------- + Low Power Mode (useLP=1 or LOW_POWER_SBR_ONLY), see assignLcTimeSlots() + + SLOT_BASED_PROTOTYPE_SYN_FILTER + + WorkBuffer1 WorkBuffer2(=CoreWorkbuffer) + ________________ ________________ + | RealLeft | | RealRight | + |________________| |________________| + + ---------------------------------------------- + High Quality Mode (!LOW_POWER_SBR_ONLY and useLP=0), see assignHqTimeSlots() + + SLOTBASED_PS + + WorkBuffer1 WorkBuffer2(=CoreWorkbuffer) + ________________ ________________ + | Real/Imag | interleaved | Real/Imag | interleaved + |________________| first half actual ch |________________| second half actual ch + + ------------------------------------------------------------- + + </pre> + +*/ +/* @{ */ +C_ALLOC_MEM_OVERLAY(Ram_SbrDecWorkBuffer1, FIXP_DBL, ((1024)/(32))*(64), SECT_DATA_L1, WORKBUFFER1_TAG) +C_ALLOC_MEM_OVERLAY(Ram_SbrDecWorkBuffer2, FIXP_DBL, ((1024)/(32))*(64), SECT_DATA_L2, WORKBUFFER2_TAG) + +/* @} */ + + + + diff --git a/libSBRdec/src/sbr_ram.h b/libSBRdec/src/sbr_ram.h new file mode 100644 index 0000000..378d3c9 --- /dev/null +++ b/libSBRdec/src/sbr_ram.h @@ -0,0 +1,100 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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 Memory layout +$Revision: 36841 $ +*/ +#ifndef _SBR_RAM_H_ +#define _SBR_RAM_H_ + +#include "sbrdecoder.h" + +#include "env_extr.h" +#include "sbr_dec.h" + + + +#define SBRDEC_MAX_CH_PER_ELEMENT (2) + +typedef struct +{ + SBR_CHANNEL *pSbrChannel[SBRDEC_MAX_CH_PER_ELEMENT]; + TRANSPOSER_SETTINGS transposerSettings; /* Common transport settings for each individual channel of an element */ + HANDLE_FDK_BITSTREAM hBs; + + MP4_ELEMENT_ID elementID; /* Element ID set during initialization. Can be used for concealment */ + int nChannels; /* Number of elements output channels (=2 in case of PS) */ + + UCHAR frameErrorFlag[(1)+1]; /* Frame error status (for every slot in the delay line). + Will be copied into header at the very beginning of decodeElement() routine. */ + + UCHAR useFrameSlot; /* Index which defines which slot will be decoded/filled next (used with additional delay) */ + UCHAR useHeaderSlot[(1)+1]; /* Index array that provides the link between header and frame data + (important when processing with additional delay). */ +} SBR_DECODER_ELEMENT; + + +struct SBR_DECODER_INSTANCE +{ + SBR_DECODER_ELEMENT *pSbrElement[(4)]; + SBR_HEADER_DATA sbrHeader[(4)][(1)+1]; /* Sbr header for each individual channel of an element */ + + FIXP_DBL *workBuffer1; + FIXP_DBL *workBuffer2; + + HANDLE_PS_DEC hParametricStereoDec; + + /* Global parameters */ + AUDIO_OBJECT_TYPE coreCodec; /* AOT of core codec */ + int numSbrElements; + int numSbrChannels; + INT sampleRateIn; /* SBR decoder input sampling rate; might be different than the transposer input sampling rate. */ + INT sampleRateOut; /* Sampling rate of the SBR decoder output audio samples. */ + USHORT codecFrameSize; + UCHAR synDownsampleFac; + UCHAR numDelayFrames; /* The current number of additional delay frames used for processing. */ + + UINT flags; + +}; + +H_ALLOC_MEM(Ram_SbrDecElement, SBR_DECODER_ELEMENT) +H_ALLOC_MEM(Ram_SbrDecChannel, SBR_CHANNEL) +H_ALLOC_MEM(Ram_SbrDecoder, struct SBR_DECODER_INSTANCE) + +H_ALLOC_MEM(Ram_sbr_QmfStatesSynthesis, FIXP_QSS) +H_ALLOC_MEM(Ram_sbr_OverlapBuffer, FIXP_DBL) + + +H_ALLOC_MEM(Ram_ps_dec, PS_DEC) + + +H_ALLOC_MEM_OVERLAY(Ram_SbrDecWorkBuffer1, FIXP_DBL) +H_ALLOC_MEM_OVERLAY(Ram_SbrDecWorkBuffer2, FIXP_DBL) + + +#endif /* _SBR_RAM_H_ */ diff --git a/libSBRdec/src/sbr_rom.cpp b/libSBRdec/src/sbr_rom.cpp new file mode 100644 index 0000000..75e15e9 --- /dev/null +++ b/libSBRdec/src/sbr_rom.cpp @@ -0,0 +1,1354 @@ +/**************************************************************************** + + (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 Definition of constant tables + $Revision: 36841 $ + + This module contains most of the constant data that can be stored in ROM. +*/ + +#include "sbr_rom.h" + + + + +/*! + \name StartStopBands + \brief Start and stop subbands of the highband. + + k_o = startMin + offset[bs_start_freq]; + startMin = {3000,4000,5000} * (128/FS_sbr) / FS_sbr < 32Khz, 32Khz <= FS_sbr < 64KHz, 64KHz <= FS_sbr + The stop subband can also be calculated to save memory by defining #CALC_STOP_BAND. +*/ +//@{ +const UCHAR FDK_sbrDecoder_sbr_start_freq_16[16] = {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_22[16] = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_24[16] = {11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_32[16] = {10, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_40[16] = {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 26, 28, 30, 32}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_44[16] = { 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 23, 25, 28, 32}; +const UCHAR FDK_sbrDecoder_sbr_start_freq_48[16] = { 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 27, 31}; +//@} + + +/*! + \name Whitening + \brief Coefficients for spectral whitening in the transposer +*/ +//@{ +/*! Assignment of whitening tuning depending on the crossover frequency */ +const USHORT FDK_sbrDecoder_sbr_whFactorsIndex[NUM_WHFACTOR_TABLE_ENTRIES] = { + 0, + 5000, + 6000, + 6500, + 7000, + 7500, + 8000, + 9000, + 10000 +}; + +/*! + \brief Whithening levels tuning table + + With the current tuning, there are some redundant entries: + + \li NUM_WHFACTOR_TABLE_ENTRIES can be reduced by 3, + \li the first coloumn can be eliminated. + +*/ +const FIXP_DBL FDK_sbrDecoder_sbr_whFactorsTable[NUM_WHFACTOR_TABLE_ENTRIES][6] = { + /* OFF_LEVEL, TRANSITION_LEVEL, LOW_LEVEL, MID_LEVEL, HIGH_LEVEL */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* < 5000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 5000 < 6000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 6000 < 6500 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 6500 < 7000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 7000 < 7500 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 7500 < 8000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 8000 < 9000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 9000 < 10000 */ + { FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f), FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* > 10000 */ +}; + + +//@} + + +/*! + \name EnvAdj + \brief Constants and tables used for envelope adjustment +*/ +//@{ + +/*! Mantissas of gain limits */ +const FIXP_SGL FDK_sbrDecoder_sbr_limGains_m[4] = +{ + FL2FXCONST_SGL(0.5011932025f), /*!< -3 dB. Gain limit when limiterGains in frameData is 0 */ + FL2FXCONST_SGL(0.5f), /*!< 0 dB. Gain limit when limiterGains in frameData is 1 */ + FL2FXCONST_SGL(0.9976346258f), /*!< +3 dB. Gain limit when limiterGains in frameData is 2 */ + FL2FXCONST_SGL(0.6776263578f) /*!< Inf. Gain limit when limiterGains in frameData is 3 */ +}; + +/*! Exponents of gain limits */ +const UCHAR FDK_sbrDecoder_sbr_limGains_e[4] = +{ + 0, 1, 1, 67 +}; + +/*! Constants for calculating the number of limiter bands */ +const FIXP_SGL FDK_sbrDecoder_sbr_limiterBandsPerOctaveDiv4[4] = +{ + FL2FXCONST_SGL(1.0f / 4.0f), + FL2FXCONST_SGL(1.2f / 4.0f), + FL2FXCONST_SGL(2.0f / 4.0f), + FL2FXCONST_SGL(3.0f / 4.0f) +}; + +/*! Ratio of old gains and noise levels for the first 4 timeslots of an envelope */ +const FIXP_SGL FDK_sbrDecoder_sbr_smoothFilter[4] = { + FL2FXCONST_SGL(0.66666666666666f), + FL2FXCONST_SGL(0.36516383427084f), + FL2FXCONST_SGL(0.14699433520835f), + FL2FXCONST_SGL(0.03183050093751f) +}; + + +/*! Real and imaginary part of random noise which will be modulated + to the desired level. An accuracy of 13 bits is sufficient for these + random numbers. +*/ +const FIXP_SGL FDK_sbrDecoder_sbr_randomPhase[SBR_NF_NO_RANDOM_VAL][2] = { + { FL2FXCONST_SGL(-0.99948153278296f / 8.0), FL2FXCONST_SGL(-0.59483417516607f / 8.0) }, + { FL2FXCONST_SGL( 0.97113454393991f / 8.0), FL2FXCONST_SGL(-0.67528515225647f / 8.0) }, + { FL2FXCONST_SGL( 0.14130051758487f / 8.0), FL2FXCONST_SGL(-0.95090983575689f / 8.0) }, + { FL2FXCONST_SGL(-0.47005496701697f / 8.0), FL2FXCONST_SGL(-0.37340549728647f / 8.0) }, + { FL2FXCONST_SGL( 0.80705063769351f / 8.0), FL2FXCONST_SGL( 0.29653668284408f / 8.0) }, + { FL2FXCONST_SGL(-0.38981478896926f / 8.0), FL2FXCONST_SGL( 0.89572605717087f / 8.0) }, + { FL2FXCONST_SGL(-0.01053049862020f / 8.0), FL2FXCONST_SGL(-0.66959058036166f / 8.0) }, + { FL2FXCONST_SGL(-0.91266367957293f / 8.0), FL2FXCONST_SGL(-0.11522938140034f / 8.0) }, + { FL2FXCONST_SGL( 0.54840422910309f / 8.0), FL2FXCONST_SGL( 0.75221367176302f / 8.0) }, + { FL2FXCONST_SGL( 0.40009252867955f / 8.0), FL2FXCONST_SGL(-0.98929400334421f / 8.0) }, + { FL2FXCONST_SGL(-0.99867974711855f / 8.0), FL2FXCONST_SGL(-0.88147068645358f / 8.0) }, + { FL2FXCONST_SGL(-0.95531076805040f / 8.0), FL2FXCONST_SGL( 0.90908757154593f / 8.0) }, + { FL2FXCONST_SGL(-0.45725933317144f / 8.0), FL2FXCONST_SGL(-0.56716323646760f / 8.0) }, + { FL2FXCONST_SGL(-0.72929675029275f / 8.0), FL2FXCONST_SGL(-0.98008272727324f / 8.0) }, + { FL2FXCONST_SGL( 0.75622801399036f / 8.0), FL2FXCONST_SGL( 0.20950329995549f / 8.0) }, + { FL2FXCONST_SGL( 0.07069442601050f / 8.0), FL2FXCONST_SGL(-0.78247898470706f / 8.0) }, + { FL2FXCONST_SGL( 0.74496252926055f / 8.0), FL2FXCONST_SGL(-0.91169004445807f / 8.0) }, + { FL2FXCONST_SGL(-0.96440182703856f / 8.0), FL2FXCONST_SGL(-0.94739918296622f / 8.0) }, + { FL2FXCONST_SGL( 0.30424629369539f / 8.0), FL2FXCONST_SGL(-0.49438267012479f / 8.0) }, + { FL2FXCONST_SGL( 0.66565033746925f / 8.0), FL2FXCONST_SGL( 0.64652935542491f / 8.0) }, + { FL2FXCONST_SGL( 0.91697008020594f / 8.0), FL2FXCONST_SGL( 0.17514097332009f / 8.0) }, + { FL2FXCONST_SGL(-0.70774918760427f / 8.0), FL2FXCONST_SGL( 0.52548653416543f / 8.0) }, + { FL2FXCONST_SGL(-0.70051415345560f / 8.0), FL2FXCONST_SGL(-0.45340028808763f / 8.0) }, + { FL2FXCONST_SGL(-0.99496513054797f / 8.0), FL2FXCONST_SGL(-0.90071908066973f / 8.0) }, + { FL2FXCONST_SGL( 0.98164490790123f / 8.0), FL2FXCONST_SGL(-0.77463155528697f / 8.0) }, + { FL2FXCONST_SGL(-0.54671580548181f / 8.0), FL2FXCONST_SGL(-0.02570928536004f / 8.0) }, + { FL2FXCONST_SGL(-0.01689629065389f / 8.0), FL2FXCONST_SGL( 0.00287506445732f / 8.0) }, + { FL2FXCONST_SGL(-0.86110349531986f / 8.0), FL2FXCONST_SGL( 0.42548583726477f / 8.0) }, + { FL2FXCONST_SGL(-0.98892980586032f / 8.0), FL2FXCONST_SGL(-0.87881132267556f / 8.0) }, + { FL2FXCONST_SGL( 0.51756627678691f / 8.0), FL2FXCONST_SGL( 0.66926784710139f / 8.0) }, + { FL2FXCONST_SGL(-0.99635026409640f / 8.0), FL2FXCONST_SGL(-0.58107730574765f / 8.0) }, + { FL2FXCONST_SGL(-0.99969370862163f / 8.0), FL2FXCONST_SGL( 0.98369989360250f / 8.0) }, + { FL2FXCONST_SGL( 0.55266258627194f / 8.0), FL2FXCONST_SGL( 0.59449057465591f / 8.0) }, + { FL2FXCONST_SGL( 0.34581177741673f / 8.0), FL2FXCONST_SGL( 0.94879421061866f / 8.0) }, + { FL2FXCONST_SGL( 0.62664209577999f / 8.0), FL2FXCONST_SGL(-0.74402970906471f / 8.0) }, + { FL2FXCONST_SGL(-0.77149701404973f / 8.0), FL2FXCONST_SGL(-0.33883658042801f / 8.0) }, + { FL2FXCONST_SGL(-0.91592244254432f / 8.0), FL2FXCONST_SGL( 0.03687901376713f / 8.0) }, + { FL2FXCONST_SGL(-0.76285492357887f / 8.0), FL2FXCONST_SGL(-0.91371867919124f / 8.0) }, + { FL2FXCONST_SGL( 0.79788337195331f / 8.0), FL2FXCONST_SGL(-0.93180971199849f / 8.0) }, + { FL2FXCONST_SGL( 0.54473080610200f / 8.0), FL2FXCONST_SGL(-0.11919206037186f / 8.0) }, + { FL2FXCONST_SGL(-0.85639281671058f / 8.0), FL2FXCONST_SGL( 0.42429854760451f / 8.0) }, + { FL2FXCONST_SGL(-0.92882402971423f / 8.0), FL2FXCONST_SGL( 0.27871809078609f / 8.0) }, + { FL2FXCONST_SGL(-0.11708371046774f / 8.0), FL2FXCONST_SGL(-0.99800843444966f / 8.0) }, + { FL2FXCONST_SGL( 0.21356749817493f / 8.0), FL2FXCONST_SGL(-0.90716295627033f / 8.0) }, + { FL2FXCONST_SGL(-0.76191692573909f / 8.0), FL2FXCONST_SGL( 0.99768118356265f / 8.0) }, + { FL2FXCONST_SGL( 0.98111043100884f / 8.0), FL2FXCONST_SGL(-0.95854459734407f / 8.0) }, + { FL2FXCONST_SGL(-0.85913269895572f / 8.0), FL2FXCONST_SGL( 0.95766566168880f / 8.0) }, + { FL2FXCONST_SGL(-0.93307242253692f / 8.0), FL2FXCONST_SGL( 0.49431757696466f / 8.0) }, + { FL2FXCONST_SGL( 0.30485754879632f / 8.0), FL2FXCONST_SGL(-0.70540034357529f / 8.0) }, + { FL2FXCONST_SGL( 0.85289650925190f / 8.0), FL2FXCONST_SGL( 0.46766131791044f / 8.0) }, + { FL2FXCONST_SGL( 0.91328082618125f / 8.0), FL2FXCONST_SGL(-0.99839597361769f / 8.0) }, + { FL2FXCONST_SGL(-0.05890199924154f / 8.0), FL2FXCONST_SGL( 0.70741827819497f / 8.0) }, + { FL2FXCONST_SGL( 0.28398686150148f / 8.0), FL2FXCONST_SGL( 0.34633555702188f / 8.0) }, + { FL2FXCONST_SGL( 0.95258164539612f / 8.0), FL2FXCONST_SGL(-0.54893416026939f / 8.0) }, + { FL2FXCONST_SGL(-0.78566324168507f / 8.0), FL2FXCONST_SGL(-0.75568541079691f / 8.0) }, + { FL2FXCONST_SGL(-0.95789495447877f / 8.0), FL2FXCONST_SGL(-0.20423194696966f / 8.0) }, + { FL2FXCONST_SGL( 0.82411158711197f / 8.0), FL2FXCONST_SGL( 0.96654618432562f / 8.0) }, + { FL2FXCONST_SGL(-0.65185446735885f / 8.0), FL2FXCONST_SGL(-0.88734990773289f / 8.0) }, + { FL2FXCONST_SGL(-0.93643603134666f / 8.0), FL2FXCONST_SGL( 0.99870790442385f / 8.0) }, + { FL2FXCONST_SGL( 0.91427159529618f / 8.0), FL2FXCONST_SGL(-0.98290505544444f / 8.0) }, + { FL2FXCONST_SGL(-0.70395684036886f / 8.0), FL2FXCONST_SGL( 0.58796798221039f / 8.0) }, + { FL2FXCONST_SGL( 0.00563771969365f / 8.0), FL2FXCONST_SGL( 0.61768196727244f / 8.0) }, + { FL2FXCONST_SGL( 0.89065051931895f / 8.0), FL2FXCONST_SGL( 0.52783352697585f / 8.0) }, + { FL2FXCONST_SGL(-0.68683707712762f / 8.0), FL2FXCONST_SGL( 0.80806944710339f / 8.0) }, + { FL2FXCONST_SGL( 0.72165342518718f / 8.0), FL2FXCONST_SGL(-0.69259857349564f / 8.0) }, + { FL2FXCONST_SGL(-0.62928247730667f / 8.0), FL2FXCONST_SGL( 0.13627037407335f / 8.0) }, + { FL2FXCONST_SGL( 0.29938434065514f / 8.0), FL2FXCONST_SGL(-0.46051329682246f / 8.0) }, + { FL2FXCONST_SGL(-0.91781958879280f / 8.0), FL2FXCONST_SGL(-0.74012716684186f / 8.0) }, + { FL2FXCONST_SGL( 0.99298717043688f / 8.0), FL2FXCONST_SGL( 0.40816610075661f / 8.0) }, + { FL2FXCONST_SGL( 0.82368298622748f / 8.0), FL2FXCONST_SGL(-0.74036047190173f / 8.0) }, + { FL2FXCONST_SGL(-0.98512833386833f / 8.0), FL2FXCONST_SGL(-0.99972330709594f / 8.0) }, + { FL2FXCONST_SGL(-0.95915368242257f / 8.0), FL2FXCONST_SGL(-0.99237800466040f / 8.0) }, + { FL2FXCONST_SGL(-0.21411126572790f / 8.0), FL2FXCONST_SGL(-0.93424819052545f / 8.0) }, + { FL2FXCONST_SGL(-0.68821476106884f / 8.0), FL2FXCONST_SGL(-0.26892306315457f / 8.0) }, + { FL2FXCONST_SGL( 0.91851997982317f / 8.0), FL2FXCONST_SGL( 0.09358228901785f / 8.0) }, + { FL2FXCONST_SGL(-0.96062769559127f / 8.0), FL2FXCONST_SGL( 0.36099095133739f / 8.0) }, + { FL2FXCONST_SGL( 0.51646184922287f / 8.0), FL2FXCONST_SGL(-0.71373332873917f / 8.0) }, + { FL2FXCONST_SGL( 0.61130721139669f / 8.0), FL2FXCONST_SGL( 0.46950141175917f / 8.0) }, + { FL2FXCONST_SGL( 0.47336129371299f / 8.0), FL2FXCONST_SGL(-0.27333178296162f / 8.0) }, + { FL2FXCONST_SGL( 0.90998308703519f / 8.0), FL2FXCONST_SGL( 0.96715662938132f / 8.0) }, + { FL2FXCONST_SGL( 0.44844799194357f / 8.0), FL2FXCONST_SGL( 0.99211574628306f / 8.0) }, + { FL2FXCONST_SGL( 0.66614891079092f / 8.0), FL2FXCONST_SGL( 0.96590176169121f / 8.0) }, + { FL2FXCONST_SGL( 0.74922239129237f / 8.0), FL2FXCONST_SGL(-0.89879858826087f / 8.0) }, + { FL2FXCONST_SGL(-0.99571588506485f / 8.0), FL2FXCONST_SGL( 0.52785521494349f / 8.0) }, + { FL2FXCONST_SGL( 0.97401082477563f / 8.0), FL2FXCONST_SGL(-0.16855870075190f / 8.0) }, + { FL2FXCONST_SGL( 0.72683747733879f / 8.0), FL2FXCONST_SGL(-0.48060774432251f / 8.0) }, + { FL2FXCONST_SGL( 0.95432193457128f / 8.0), FL2FXCONST_SGL( 0.68849603408441f / 8.0) }, + { FL2FXCONST_SGL(-0.72962208425191f / 8.0), FL2FXCONST_SGL(-0.76608443420917f / 8.0) }, + { FL2FXCONST_SGL(-0.85359479233537f / 8.0), FL2FXCONST_SGL( 0.88738125901579f / 8.0) }, + { FL2FXCONST_SGL(-0.81412430338535f / 8.0), FL2FXCONST_SGL(-0.97480768049637f / 8.0) }, + { FL2FXCONST_SGL(-0.87930772356786f / 8.0), FL2FXCONST_SGL( 0.74748307690436f / 8.0) }, + { FL2FXCONST_SGL(-0.71573331064977f / 8.0), FL2FXCONST_SGL(-0.98570608178923f / 8.0) }, + { FL2FXCONST_SGL( 0.83524300028228f / 8.0), FL2FXCONST_SGL( 0.83702537075163f / 8.0) }, + { FL2FXCONST_SGL(-0.48086065601423f / 8.0), FL2FXCONST_SGL(-0.98848504923531f / 8.0) }, + { FL2FXCONST_SGL( 0.97139128574778f / 8.0), FL2FXCONST_SGL( 0.80093621198236f / 8.0) }, + { FL2FXCONST_SGL( 0.51992825347895f / 8.0), FL2FXCONST_SGL( 0.80247631400510f / 8.0) }, + { FL2FXCONST_SGL(-0.00848591195325f / 8.0), FL2FXCONST_SGL(-0.76670128000486f / 8.0) }, + { FL2FXCONST_SGL(-0.70294374303036f / 8.0), FL2FXCONST_SGL( 0.55359910445577f / 8.0) }, + { FL2FXCONST_SGL(-0.95894428168140f / 8.0), FL2FXCONST_SGL(-0.43265504344783f / 8.0) }, + { FL2FXCONST_SGL( 0.97079252950321f / 8.0), FL2FXCONST_SGL( 0.09325857238682f / 8.0) }, + { FL2FXCONST_SGL(-0.92404293670797f / 8.0), FL2FXCONST_SGL( 0.85507704027855f / 8.0) }, + { FL2FXCONST_SGL(-0.69506469500450f / 8.0), FL2FXCONST_SGL( 0.98633412625459f / 8.0) }, + { FL2FXCONST_SGL( 0.26559203620024f / 8.0), FL2FXCONST_SGL( 0.73314307966524f / 8.0) }, + { FL2FXCONST_SGL( 0.28038443336943f / 8.0), FL2FXCONST_SGL( 0.14537913654427f / 8.0) }, + { FL2FXCONST_SGL(-0.74138124825523f / 8.0), FL2FXCONST_SGL( 0.99310339807762f / 8.0) }, + { FL2FXCONST_SGL(-0.01752795995444f / 8.0), FL2FXCONST_SGL(-0.82616635284178f / 8.0) }, + { FL2FXCONST_SGL(-0.55126773094930f / 8.0), FL2FXCONST_SGL(-0.98898543862153f / 8.0) }, + { FL2FXCONST_SGL( 0.97960898850996f / 8.0), FL2FXCONST_SGL(-0.94021446752851f / 8.0) }, + { FL2FXCONST_SGL(-0.99196309146936f / 8.0), FL2FXCONST_SGL( 0.67019017358456f / 8.0) }, + { FL2FXCONST_SGL(-0.67684928085260f / 8.0), FL2FXCONST_SGL( 0.12631491649378f / 8.0) }, + { FL2FXCONST_SGL( 0.09140039465500f / 8.0), FL2FXCONST_SGL(-0.20537731453108f / 8.0) }, + { FL2FXCONST_SGL(-0.71658965751996f / 8.0), FL2FXCONST_SGL(-0.97788200391224f / 8.0) }, + { FL2FXCONST_SGL( 0.81014640078925f / 8.0), FL2FXCONST_SGL( 0.53722648362443f / 8.0) }, + { FL2FXCONST_SGL( 0.40616991671205f / 8.0), FL2FXCONST_SGL(-0.26469008598449f / 8.0) }, + { FL2FXCONST_SGL(-0.67680188682972f / 8.0), FL2FXCONST_SGL( 0.94502052337695f / 8.0) }, + { FL2FXCONST_SGL( 0.86849774348749f / 8.0), FL2FXCONST_SGL(-0.18333598647899f / 8.0) }, + { FL2FXCONST_SGL(-0.99500381284851f / 8.0), FL2FXCONST_SGL(-0.02634122068550f / 8.0) }, + { FL2FXCONST_SGL( 0.84329189340667f / 8.0), FL2FXCONST_SGL( 0.10406957462213f / 8.0) }, + { FL2FXCONST_SGL(-0.09215968531446f / 8.0), FL2FXCONST_SGL( 0.69540012101253f / 8.0) }, + { FL2FXCONST_SGL( 0.99956173327206f / 8.0), FL2FXCONST_SGL(-0.12358542001404f / 8.0) }, + { FL2FXCONST_SGL(-0.79732779473535f / 8.0), FL2FXCONST_SGL(-0.91582524736159f / 8.0) }, + { FL2FXCONST_SGL( 0.96349973642406f / 8.0), FL2FXCONST_SGL( 0.96640458041000f / 8.0) }, + { FL2FXCONST_SGL(-0.79942778496547f / 8.0), FL2FXCONST_SGL( 0.64323902822857f / 8.0) }, + { FL2FXCONST_SGL(-0.11566039853896f / 8.0), FL2FXCONST_SGL( 0.28587846253726f / 8.0) }, + { FL2FXCONST_SGL(-0.39922954514662f / 8.0), FL2FXCONST_SGL( 0.94129601616966f / 8.0) }, + { FL2FXCONST_SGL( 0.99089197565987f / 8.0), FL2FXCONST_SGL(-0.92062625581587f / 8.0) }, + { FL2FXCONST_SGL( 0.28631285179909f / 8.0), FL2FXCONST_SGL(-0.91035047143603f / 8.0) }, + { FL2FXCONST_SGL(-0.83302725605608f / 8.0), FL2FXCONST_SGL(-0.67330410892084f / 8.0) }, + { FL2FXCONST_SGL( 0.95404443402072f / 8.0), FL2FXCONST_SGL( 0.49162765398743f / 8.0) }, + { FL2FXCONST_SGL(-0.06449863579434f / 8.0), FL2FXCONST_SGL( 0.03250560813135f / 8.0) }, + { FL2FXCONST_SGL(-0.99575054486311f / 8.0), FL2FXCONST_SGL( 0.42389784469507f / 8.0) }, + { FL2FXCONST_SGL(-0.65501142790847f / 8.0), FL2FXCONST_SGL( 0.82546114655624f / 8.0) }, + { FL2FXCONST_SGL(-0.81254441908887f / 8.0), FL2FXCONST_SGL(-0.51627234660629f / 8.0) }, + { FL2FXCONST_SGL(-0.99646369485481f / 8.0), FL2FXCONST_SGL( 0.84490533520752f / 8.0) }, + { FL2FXCONST_SGL( 0.00287840603348f / 8.0), FL2FXCONST_SGL( 0.64768261158166f / 8.0) }, + { FL2FXCONST_SGL( 0.70176989408455f / 8.0), FL2FXCONST_SGL(-0.20453028573322f / 8.0) }, + { FL2FXCONST_SGL( 0.96361882270190f / 8.0), FL2FXCONST_SGL( 0.40706967140989f / 8.0) }, + { FL2FXCONST_SGL(-0.68883758192426f / 8.0), FL2FXCONST_SGL( 0.91338958840772f / 8.0) }, + { FL2FXCONST_SGL(-0.34875585502238f / 8.0), FL2FXCONST_SGL( 0.71472290693300f / 8.0) }, + { FL2FXCONST_SGL( 0.91980081243087f / 8.0), FL2FXCONST_SGL( 0.66507455644919f / 8.0) }, + { FL2FXCONST_SGL(-0.99009048343881f / 8.0), FL2FXCONST_SGL( 0.85868021604848f / 8.0) }, + { FL2FXCONST_SGL( 0.68865791458395f / 8.0), FL2FXCONST_SGL( 0.55660316809678f / 8.0) }, + { FL2FXCONST_SGL(-0.99484402129368f / 8.0), FL2FXCONST_SGL(-0.20052559254934f / 8.0) }, + { FL2FXCONST_SGL( 0.94214511408023f / 8.0), FL2FXCONST_SGL(-0.99696425367461f / 8.0) }, + { FL2FXCONST_SGL(-0.67414626793544f / 8.0), FL2FXCONST_SGL( 0.49548221180078f / 8.0) }, + { FL2FXCONST_SGL(-0.47339353684664f / 8.0), FL2FXCONST_SGL(-0.85904328834047f / 8.0) }, + { FL2FXCONST_SGL( 0.14323651387360f / 8.0), FL2FXCONST_SGL(-0.94145598222488f / 8.0) }, + { FL2FXCONST_SGL(-0.29268293575672f / 8.0), FL2FXCONST_SGL( 0.05759224927952f / 8.0) }, + { FL2FXCONST_SGL( 0.43793861458754f / 8.0), FL2FXCONST_SGL(-0.78904969892724f / 8.0) }, + { FL2FXCONST_SGL(-0.36345126374441f / 8.0), FL2FXCONST_SGL( 0.64874435357162f / 8.0) }, + { FL2FXCONST_SGL(-0.08750604656825f / 8.0), FL2FXCONST_SGL( 0.97686944362527f / 8.0) }, + { FL2FXCONST_SGL(-0.96495267812511f / 8.0), FL2FXCONST_SGL(-0.53960305946511f / 8.0) }, + { FL2FXCONST_SGL( 0.55526940659947f / 8.0), FL2FXCONST_SGL( 0.78891523734774f / 8.0) }, + { FL2FXCONST_SGL( 0.73538215752630f / 8.0), FL2FXCONST_SGL( 0.96452072373404f / 8.0) }, + { FL2FXCONST_SGL(-0.30889773919437f / 8.0), FL2FXCONST_SGL(-0.80664389776860f / 8.0) }, + { FL2FXCONST_SGL( 0.03574995626194f / 8.0), FL2FXCONST_SGL(-0.97325616900959f / 8.0) }, + { FL2FXCONST_SGL( 0.98720684660488f / 8.0), FL2FXCONST_SGL( 0.48409133691962f / 8.0) }, + { FL2FXCONST_SGL(-0.81689296271203f / 8.0), FL2FXCONST_SGL(-0.90827703628298f / 8.0) }, + { FL2FXCONST_SGL( 0.67866860118215f / 8.0), FL2FXCONST_SGL( 0.81284503870856f / 8.0) }, + { FL2FXCONST_SGL(-0.15808569732583f / 8.0), FL2FXCONST_SGL( 0.85279555024382f / 8.0) }, + { FL2FXCONST_SGL( 0.80723395114371f / 8.0), FL2FXCONST_SGL(-0.24717418514605f / 8.0) }, + { FL2FXCONST_SGL( 0.47788757329038f / 8.0), FL2FXCONST_SGL(-0.46333147839295f / 8.0) }, + { FL2FXCONST_SGL( 0.96367554763201f / 8.0), FL2FXCONST_SGL( 0.38486749303242f / 8.0) }, + { FL2FXCONST_SGL(-0.99143875716818f / 8.0), FL2FXCONST_SGL(-0.24945277239809f / 8.0) }, + { FL2FXCONST_SGL( 0.83081876925833f / 8.0), FL2FXCONST_SGL(-0.94780851414763f / 8.0) }, + { FL2FXCONST_SGL(-0.58753191905341f / 8.0), FL2FXCONST_SGL( 0.01290772389163f / 8.0) }, + { FL2FXCONST_SGL( 0.95538108220960f / 8.0), FL2FXCONST_SGL(-0.85557052096538f / 8.0) }, + { FL2FXCONST_SGL(-0.96490920476211f / 8.0), FL2FXCONST_SGL(-0.64020970923102f / 8.0) }, + { FL2FXCONST_SGL(-0.97327101028521f / 8.0), FL2FXCONST_SGL( 0.12378128133110f / 8.0) }, + { FL2FXCONST_SGL( 0.91400366022124f / 8.0), FL2FXCONST_SGL( 0.57972471346930f / 8.0) }, + { FL2FXCONST_SGL(-0.99925837363824f / 8.0), FL2FXCONST_SGL( 0.71084847864067f / 8.0) }, + { FL2FXCONST_SGL(-0.86875903507313f / 8.0), FL2FXCONST_SGL(-0.20291699203564f / 8.0) }, + { FL2FXCONST_SGL(-0.26240034795124f / 8.0), FL2FXCONST_SGL(-0.68264554369108f / 8.0) }, + { FL2FXCONST_SGL(-0.24664412953388f / 8.0), FL2FXCONST_SGL(-0.87642273115183f / 8.0) }, + { FL2FXCONST_SGL( 0.02416275806869f / 8.0), FL2FXCONST_SGL( 0.27192914288905f / 8.0) }, + { FL2FXCONST_SGL( 0.82068619590515f / 8.0), FL2FXCONST_SGL(-0.85087787994476f / 8.0) }, + { FL2FXCONST_SGL( 0.88547373760759f / 8.0), FL2FXCONST_SGL(-0.89636802901469f / 8.0) }, + { FL2FXCONST_SGL(-0.18173078152226f / 8.0), FL2FXCONST_SGL(-0.26152145156800f / 8.0) }, + { FL2FXCONST_SGL( 0.09355476558534f / 8.0), FL2FXCONST_SGL( 0.54845123045604f / 8.0) }, + { FL2FXCONST_SGL(-0.54668414224090f / 8.0), FL2FXCONST_SGL( 0.95980774020221f / 8.0) }, + { FL2FXCONST_SGL( 0.37050990604091f / 8.0), FL2FXCONST_SGL(-0.59910140383171f / 8.0) }, + { FL2FXCONST_SGL(-0.70373594262891f / 8.0), FL2FXCONST_SGL( 0.91227665827081f / 8.0) }, + { FL2FXCONST_SGL(-0.34600785879594f / 8.0), FL2FXCONST_SGL(-0.99441426144200f / 8.0) }, + { FL2FXCONST_SGL(-0.68774481731008f / 8.0), FL2FXCONST_SGL(-0.30238837956299f / 8.0) }, + { FL2FXCONST_SGL(-0.26843291251234f / 8.0), FL2FXCONST_SGL( 0.83115668004362f / 8.0) }, + { FL2FXCONST_SGL( 0.49072334613242f / 8.0), FL2FXCONST_SGL(-0.45359708737775f / 8.0) }, + { FL2FXCONST_SGL( 0.38975993093975f / 8.0), FL2FXCONST_SGL( 0.95515358099121f / 8.0) }, + { FL2FXCONST_SGL(-0.97757125224150f / 8.0), FL2FXCONST_SGL( 0.05305894580606f / 8.0) }, + { FL2FXCONST_SGL(-0.17325552859616f / 8.0), FL2FXCONST_SGL(-0.92770672250494f / 8.0) }, + { FL2FXCONST_SGL( 0.99948035025744f / 8.0), FL2FXCONST_SGL( 0.58285545563426f / 8.0) }, + { FL2FXCONST_SGL(-0.64946246527458f / 8.0), FL2FXCONST_SGL( 0.68645507104960f / 8.0) }, + { FL2FXCONST_SGL(-0.12016920576437f / 8.0), FL2FXCONST_SGL(-0.57147322153312f / 8.0) }, + { FL2FXCONST_SGL(-0.58947456517751f / 8.0), FL2FXCONST_SGL(-0.34847132454388f / 8.0) }, + { FL2FXCONST_SGL(-0.41815140454465f / 8.0), FL2FXCONST_SGL( 0.16276422358861f / 8.0) }, + { FL2FXCONST_SGL( 0.99885650204884f / 8.0), FL2FXCONST_SGL( 0.11136095490444f / 8.0) }, + { FL2FXCONST_SGL(-0.56649614128386f / 8.0), FL2FXCONST_SGL(-0.90494866361587f / 8.0) }, + { FL2FXCONST_SGL( 0.94138021032330f / 8.0), FL2FXCONST_SGL( 0.35281916733018f / 8.0) }, + { FL2FXCONST_SGL(-0.75725076534641f / 8.0), FL2FXCONST_SGL( 0.53650549640587f / 8.0) }, + { FL2FXCONST_SGL( 0.20541973692630f / 8.0), FL2FXCONST_SGL(-0.94435144369918f / 8.0) }, + { FL2FXCONST_SGL( 0.99980371023351f / 8.0), FL2FXCONST_SGL( 0.79835913565599f / 8.0) }, + { FL2FXCONST_SGL( 0.29078277605775f / 8.0), FL2FXCONST_SGL( 0.35393777921520f / 8.0) }, + { FL2FXCONST_SGL(-0.62858772103030f / 8.0), FL2FXCONST_SGL( 0.38765693387102f / 8.0) }, + { FL2FXCONST_SGL( 0.43440904467688f / 8.0), FL2FXCONST_SGL(-0.98546330463232f / 8.0) }, + { FL2FXCONST_SGL(-0.98298583762390f / 8.0), FL2FXCONST_SGL( 0.21021524625209f / 8.0) }, + { FL2FXCONST_SGL( 0.19513029146934f / 8.0), FL2FXCONST_SGL(-0.94239832251867f / 8.0) }, + { FL2FXCONST_SGL(-0.95476662400101f / 8.0), FL2FXCONST_SGL( 0.98364554179143f / 8.0) }, + { FL2FXCONST_SGL( 0.93379635304810f / 8.0), FL2FXCONST_SGL(-0.70881994583682f / 8.0) }, + { FL2FXCONST_SGL(-0.85235410573336f / 8.0), FL2FXCONST_SGL(-0.08342347966410f / 8.0) }, + { FL2FXCONST_SGL(-0.86425093011245f / 8.0), FL2FXCONST_SGL(-0.45795025029466f / 8.0) }, + { FL2FXCONST_SGL( 0.38879779059045f / 8.0), FL2FXCONST_SGL( 0.97274429344593f / 8.0) }, + { FL2FXCONST_SGL( 0.92045124735495f / 8.0), FL2FXCONST_SGL(-0.62433652524220f / 8.0) }, + { FL2FXCONST_SGL( 0.89162532251878f / 8.0), FL2FXCONST_SGL( 0.54950955570563f / 8.0) }, + { FL2FXCONST_SGL(-0.36834336949252f / 8.0), FL2FXCONST_SGL( 0.96458298020975f / 8.0) }, + { FL2FXCONST_SGL( 0.93891760988045f / 8.0), FL2FXCONST_SGL(-0.89968353740388f / 8.0) }, + { FL2FXCONST_SGL( 0.99267657565094f / 8.0), FL2FXCONST_SGL(-0.03757034316958f / 8.0) }, + { FL2FXCONST_SGL(-0.94063471614176f / 8.0), FL2FXCONST_SGL( 0.41332338538963f / 8.0) }, + { FL2FXCONST_SGL( 0.99740224117019f / 8.0), FL2FXCONST_SGL(-0.16830494996370f / 8.0) }, + { FL2FXCONST_SGL(-0.35899413170555f / 8.0), FL2FXCONST_SGL(-0.46633226649613f / 8.0) }, + { FL2FXCONST_SGL( 0.05237237274947f / 8.0), FL2FXCONST_SGL(-0.25640361602661f / 8.0) }, + { FL2FXCONST_SGL( 0.36703583957424f / 8.0), FL2FXCONST_SGL(-0.38653265641875f / 8.0) }, + { FL2FXCONST_SGL( 0.91653180367913f / 8.0), FL2FXCONST_SGL(-0.30587628726597f / 8.0) }, + { FL2FXCONST_SGL( 0.69000803499316f / 8.0), FL2FXCONST_SGL( 0.90952171386132f / 8.0) }, + { FL2FXCONST_SGL(-0.38658751133527f / 8.0), FL2FXCONST_SGL( 0.99501571208985f / 8.0) }, + { FL2FXCONST_SGL(-0.29250814029851f / 8.0), FL2FXCONST_SGL( 0.37444994344615f / 8.0) }, + { FL2FXCONST_SGL(-0.60182204677608f / 8.0), FL2FXCONST_SGL( 0.86779651036123f / 8.0) }, + { FL2FXCONST_SGL(-0.97418588163217f / 8.0), FL2FXCONST_SGL( 0.96468523666475f / 8.0) }, + { FL2FXCONST_SGL( 0.88461574003963f / 8.0), FL2FXCONST_SGL( 0.57508405276414f / 8.0) }, + { FL2FXCONST_SGL( 0.05198933055162f / 8.0), FL2FXCONST_SGL( 0.21269661669964f / 8.0) }, + { FL2FXCONST_SGL(-0.53499621979720f / 8.0), FL2FXCONST_SGL( 0.97241553731237f / 8.0) }, + { FL2FXCONST_SGL(-0.49429560226497f / 8.0), FL2FXCONST_SGL( 0.98183865291903f / 8.0) }, + { FL2FXCONST_SGL(-0.98935142339139f / 8.0), FL2FXCONST_SGL(-0.40249159006933f / 8.0) }, + { FL2FXCONST_SGL(-0.98081380091130f / 8.0), FL2FXCONST_SGL(-0.72856895534041f / 8.0) }, + { FL2FXCONST_SGL(-0.27338148835532f / 8.0), FL2FXCONST_SGL( 0.99950922447209f / 8.0) }, + { FL2FXCONST_SGL( 0.06310802338302f / 8.0), FL2FXCONST_SGL(-0.54539587529618f / 8.0) }, + { FL2FXCONST_SGL(-0.20461677199539f / 8.0), FL2FXCONST_SGL(-0.14209977628489f / 8.0) }, + { FL2FXCONST_SGL( 0.66223843141647f / 8.0), FL2FXCONST_SGL( 0.72528579940326f / 8.0) }, + { FL2FXCONST_SGL(-0.84764345483665f / 8.0), FL2FXCONST_SGL( 0.02372316801261f / 8.0) }, + { FL2FXCONST_SGL(-0.89039863483811f / 8.0), FL2FXCONST_SGL( 0.88866581484602f / 8.0) }, + { FL2FXCONST_SGL( 0.95903308477986f / 8.0), FL2FXCONST_SGL( 0.76744927173873f / 8.0) }, + { FL2FXCONST_SGL( 0.73504123909879f / 8.0), FL2FXCONST_SGL(-0.03747203173192f / 8.0) }, + { FL2FXCONST_SGL(-0.31744434966056f / 8.0), FL2FXCONST_SGL(-0.36834111883652f / 8.0) }, + { FL2FXCONST_SGL(-0.34110827591623f / 8.0), FL2FXCONST_SGL( 0.40211222807691f / 8.0) }, + { FL2FXCONST_SGL( 0.47803883714199f / 8.0), FL2FXCONST_SGL(-0.39423219786288f / 8.0) }, + { FL2FXCONST_SGL( 0.98299195879514f / 8.0), FL2FXCONST_SGL( 0.01989791390047f / 8.0) }, + { FL2FXCONST_SGL(-0.30963073129751f / 8.0), FL2FXCONST_SGL(-0.18076720599336f / 8.0) }, + { FL2FXCONST_SGL( 0.99992588229018f / 8.0), FL2FXCONST_SGL(-0.26281872094289f / 8.0) }, + { FL2FXCONST_SGL(-0.93149731080767f / 8.0), FL2FXCONST_SGL(-0.98313162570490f / 8.0) }, + { FL2FXCONST_SGL( 0.99923472302773f / 8.0), FL2FXCONST_SGL(-0.80142993767554f / 8.0) }, + { FL2FXCONST_SGL(-0.26024169633417f / 8.0), FL2FXCONST_SGL(-0.75999759855752f / 8.0) }, + { FL2FXCONST_SGL(-0.35712514743563f / 8.0), FL2FXCONST_SGL( 0.19298963768574f / 8.0) }, + { FL2FXCONST_SGL(-0.99899084509530f / 8.0), FL2FXCONST_SGL( 0.74645156992493f / 8.0) }, + { FL2FXCONST_SGL( 0.86557171579452f / 8.0), FL2FXCONST_SGL( 0.55593866696299f / 8.0) }, + { FL2FXCONST_SGL( 0.33408042438752f / 8.0), FL2FXCONST_SGL( 0.86185953874709f / 8.0) }, + { FL2FXCONST_SGL( 0.99010736374716f / 8.0), FL2FXCONST_SGL( 0.04602397576623f / 8.0) }, + { FL2FXCONST_SGL(-0.66694269691195f / 8.0), FL2FXCONST_SGL(-0.91643611810148f / 8.0) }, + { FL2FXCONST_SGL( 0.64016792079480f / 8.0), FL2FXCONST_SGL( 0.15649530836856f / 8.0) }, + { FL2FXCONST_SGL( 0.99570534804836f / 8.0), FL2FXCONST_SGL( 0.45844586038111f / 8.0) }, + { FL2FXCONST_SGL(-0.63431466947340f / 8.0), FL2FXCONST_SGL( 0.21079116459234f / 8.0) }, + { FL2FXCONST_SGL(-0.07706847005931f / 8.0), FL2FXCONST_SGL(-0.89581437101329f / 8.0) }, + { FL2FXCONST_SGL( 0.98590090577724f / 8.0), FL2FXCONST_SGL( 0.88241721133981f / 8.0) }, + { FL2FXCONST_SGL( 0.80099335254678f / 8.0), FL2FXCONST_SGL(-0.36851896710853f / 8.0) }, + { FL2FXCONST_SGL( 0.78368131392666f / 8.0), FL2FXCONST_SGL( 0.45506999802597f / 8.0) }, + { FL2FXCONST_SGL( 0.08707806671691f / 8.0), FL2FXCONST_SGL( 0.80938994918745f / 8.0) }, + { FL2FXCONST_SGL(-0.86811883080712f / 8.0), FL2FXCONST_SGL( 0.39347308654705f / 8.0) }, + { FL2FXCONST_SGL(-0.39466529740375f / 8.0), FL2FXCONST_SGL(-0.66809432114456f / 8.0) }, + { FL2FXCONST_SGL( 0.97875325649683f / 8.0), FL2FXCONST_SGL(-0.72467840967746f / 8.0) }, + { FL2FXCONST_SGL(-0.95038560288864f / 8.0), FL2FXCONST_SGL( 0.89563219587625f / 8.0) }, + { FL2FXCONST_SGL( 0.17005239424212f / 8.0), FL2FXCONST_SGL( 0.54683053962658f / 8.0) }, + { FL2FXCONST_SGL(-0.76910792026848f / 8.0), FL2FXCONST_SGL(-0.96226617549298f / 8.0) }, + { FL2FXCONST_SGL( 0.99743281016846f / 8.0), FL2FXCONST_SGL( 0.42697157037567f / 8.0) }, + { FL2FXCONST_SGL( 0.95437383549973f / 8.0), FL2FXCONST_SGL( 0.97002324109952f / 8.0) }, + { FL2FXCONST_SGL( 0.99578905365569f / 8.0), FL2FXCONST_SGL(-0.54106826257356f / 8.0) }, + { FL2FXCONST_SGL( 0.28058259829990f / 8.0), FL2FXCONST_SGL(-0.85361420634036f / 8.0) }, + { FL2FXCONST_SGL( 0.85256524470573f / 8.0), FL2FXCONST_SGL(-0.64567607735589f / 8.0) }, + { FL2FXCONST_SGL(-0.50608540105128f / 8.0), FL2FXCONST_SGL(-0.65846015480300f / 8.0) }, + { FL2FXCONST_SGL(-0.97210735183243f / 8.0), FL2FXCONST_SGL(-0.23095213067791f / 8.0) }, + { FL2FXCONST_SGL( 0.95424048234441f / 8.0), FL2FXCONST_SGL(-0.99240147091219f / 8.0) }, + { FL2FXCONST_SGL(-0.96926570524023f / 8.0), FL2FXCONST_SGL( 0.73775654896574f / 8.0) }, + { FL2FXCONST_SGL( 0.30872163214726f / 8.0), FL2FXCONST_SGL( 0.41514960556126f / 8.0) }, + { FL2FXCONST_SGL(-0.24523839572639f / 8.0), FL2FXCONST_SGL( 0.63206633394807f / 8.0) }, + { FL2FXCONST_SGL(-0.33813265086024f / 8.0), FL2FXCONST_SGL(-0.38661779441897f / 8.0) }, + { FL2FXCONST_SGL(-0.05826828420146f / 8.0), FL2FXCONST_SGL(-0.06940774188029f / 8.0) }, + { FL2FXCONST_SGL(-0.22898461455054f / 8.0), FL2FXCONST_SGL( 0.97054853316316f / 8.0) }, + { FL2FXCONST_SGL(-0.18509915019881f / 8.0), FL2FXCONST_SGL( 0.47565762892084f / 8.0) }, + { FL2FXCONST_SGL(-0.10488238045009f / 8.0), FL2FXCONST_SGL(-0.87769947402394f / 8.0) }, + { FL2FXCONST_SGL(-0.71886586182037f / 8.0), FL2FXCONST_SGL( 0.78030982480538f / 8.0) }, + { FL2FXCONST_SGL( 0.99793873738654f / 8.0), FL2FXCONST_SGL( 0.90041310491497f / 8.0) }, + { FL2FXCONST_SGL( 0.57563307626120f / 8.0), FL2FXCONST_SGL(-0.91034337352097f / 8.0) }, + { FL2FXCONST_SGL( 0.28909646383717f / 8.0), FL2FXCONST_SGL( 0.96307783970534f / 8.0) }, + { FL2FXCONST_SGL( 0.42188998312520f / 8.0), FL2FXCONST_SGL( 0.48148651230437f / 8.0) }, + { FL2FXCONST_SGL( 0.93335049681047f / 8.0), FL2FXCONST_SGL(-0.43537023883588f / 8.0) }, + { FL2FXCONST_SGL(-0.97087374418267f / 8.0), FL2FXCONST_SGL( 0.86636445711364f / 8.0) }, + { FL2FXCONST_SGL( 0.36722871286923f / 8.0), FL2FXCONST_SGL( 0.65291654172961f / 8.0) }, + { FL2FXCONST_SGL(-0.81093025665696f / 8.0), FL2FXCONST_SGL( 0.08778370229363f / 8.0) }, + { FL2FXCONST_SGL(-0.26240603062237f / 8.0), FL2FXCONST_SGL(-0.92774095379098f / 8.0) }, + { FL2FXCONST_SGL( 0.83996497984604f / 8.0), FL2FXCONST_SGL( 0.55839849139647f / 8.0) }, + { FL2FXCONST_SGL(-0.99909615720225f / 8.0), FL2FXCONST_SGL(-0.96024605713970f / 8.0) }, + { FL2FXCONST_SGL( 0.74649464155061f / 8.0), FL2FXCONST_SGL( 0.12144893606462f / 8.0) }, + { FL2FXCONST_SGL(-0.74774595569805f / 8.0), FL2FXCONST_SGL(-0.26898062008959f / 8.0) }, + { FL2FXCONST_SGL( 0.95781667469567f / 8.0), FL2FXCONST_SGL(-0.79047927052628f / 8.0) }, + { FL2FXCONST_SGL( 0.95472308713099f / 8.0), FL2FXCONST_SGL(-0.08588776019550f / 8.0) }, + { FL2FXCONST_SGL( 0.48708332746299f / 8.0), FL2FXCONST_SGL( 0.99999041579432f / 8.0) }, + { FL2FXCONST_SGL( 0.46332038247497f / 8.0), FL2FXCONST_SGL( 0.10964126185063f / 8.0) }, + { FL2FXCONST_SGL(-0.76497004940162f / 8.0), FL2FXCONST_SGL( 0.89210929242238f / 8.0) }, + { FL2FXCONST_SGL( 0.57397389364339f / 8.0), FL2FXCONST_SGL( 0.35289703373760f / 8.0) }, + { FL2FXCONST_SGL( 0.75374316974495f / 8.0), FL2FXCONST_SGL( 0.96705214651335f / 8.0) }, + { FL2FXCONST_SGL(-0.59174397685714f / 8.0), FL2FXCONST_SGL(-0.89405370422752f / 8.0) }, + { FL2FXCONST_SGL( 0.75087906691890f / 8.0), FL2FXCONST_SGL(-0.29612672982396f / 8.0) }, + { FL2FXCONST_SGL(-0.98607857336230f / 8.0), FL2FXCONST_SGL( 0.25034911730023f / 8.0) }, + { FL2FXCONST_SGL(-0.40761056640505f / 8.0), FL2FXCONST_SGL(-0.90045573444695f / 8.0) }, + { FL2FXCONST_SGL( 0.66929266740477f / 8.0), FL2FXCONST_SGL( 0.98629493401748f / 8.0) }, + { FL2FXCONST_SGL(-0.97463695257310f / 8.0), FL2FXCONST_SGL(-0.00190223301301f / 8.0) }, + { FL2FXCONST_SGL( 0.90145509409859f / 8.0), FL2FXCONST_SGL( 0.99781390365446f / 8.0) }, + { FL2FXCONST_SGL(-0.87259289048043f / 8.0), FL2FXCONST_SGL( 0.99233587353666f / 8.0) }, + { FL2FXCONST_SGL(-0.91529461447692f / 8.0), FL2FXCONST_SGL(-0.15698707534206f / 8.0) }, + { FL2FXCONST_SGL(-0.03305738840705f / 8.0), FL2FXCONST_SGL(-0.37205262859764f / 8.0) }, + { FL2FXCONST_SGL( 0.07223051368337f / 8.0), FL2FXCONST_SGL(-0.88805001733626f / 8.0) }, + { FL2FXCONST_SGL( 0.99498012188353f / 8.0), FL2FXCONST_SGL( 0.97094358113387f / 8.0) }, + { FL2FXCONST_SGL(-0.74904939500519f / 8.0), FL2FXCONST_SGL( 0.99985483641521f / 8.0) }, + { FL2FXCONST_SGL( 0.04585228574211f / 8.0), FL2FXCONST_SGL( 0.99812337444082f / 8.0) }, + { FL2FXCONST_SGL(-0.89054954257993f / 8.0), FL2FXCONST_SGL(-0.31791913188064f / 8.0) }, + { FL2FXCONST_SGL(-0.83782144651251f / 8.0), FL2FXCONST_SGL( 0.97637632547466f / 8.0) }, + { FL2FXCONST_SGL( 0.33454804933804f / 8.0), FL2FXCONST_SGL(-0.86231516800408f / 8.0) }, + { FL2FXCONST_SGL(-0.99707579362824f / 8.0), FL2FXCONST_SGL( 0.93237990079441f / 8.0) }, + { FL2FXCONST_SGL(-0.22827527843994f / 8.0), FL2FXCONST_SGL( 0.18874759397997f / 8.0) }, + { FL2FXCONST_SGL( 0.67248046289143f / 8.0), FL2FXCONST_SGL(-0.03646211390569f / 8.0) }, + { FL2FXCONST_SGL(-0.05146538187944f / 8.0), FL2FXCONST_SGL(-0.92599700120679f / 8.0) }, + { FL2FXCONST_SGL( 0.99947295749905f / 8.0), FL2FXCONST_SGL( 0.93625229707912f / 8.0) }, + { FL2FXCONST_SGL( 0.66951124390363f / 8.0), FL2FXCONST_SGL( 0.98905825623893f / 8.0) }, + { FL2FXCONST_SGL(-0.99602956559179f / 8.0), FL2FXCONST_SGL(-0.44654715757688f / 8.0) }, + { FL2FXCONST_SGL( 0.82104905483590f / 8.0), FL2FXCONST_SGL( 0.99540741724928f / 8.0) }, + { FL2FXCONST_SGL( 0.99186510988782f / 8.0), FL2FXCONST_SGL( 0.72023001312947f / 8.0) }, + { FL2FXCONST_SGL(-0.65284592392918f / 8.0), FL2FXCONST_SGL( 0.52186723253637f / 8.0) }, + { FL2FXCONST_SGL( 0.93885443798188f / 8.0), FL2FXCONST_SGL(-0.74895312615259f / 8.0) }, + { FL2FXCONST_SGL( 0.96735248738388f / 8.0), FL2FXCONST_SGL( 0.90891816978629f / 8.0) }, + { FL2FXCONST_SGL(-0.22225968841114f / 8.0), FL2FXCONST_SGL( 0.57124029781228f / 8.0) }, + { FL2FXCONST_SGL(-0.44132783753414f / 8.0), FL2FXCONST_SGL(-0.92688840659280f / 8.0) }, + { FL2FXCONST_SGL(-0.85694974219574f / 8.0), FL2FXCONST_SGL( 0.88844532719844f / 8.0) }, + { FL2FXCONST_SGL( 0.91783042091762f / 8.0), FL2FXCONST_SGL(-0.46356892383970f / 8.0) }, + { FL2FXCONST_SGL( 0.72556974415690f / 8.0), FL2FXCONST_SGL(-0.99899555770747f / 8.0) }, + { FL2FXCONST_SGL(-0.99711581834508f / 8.0), FL2FXCONST_SGL( 0.58211560180426f / 8.0) }, + { FL2FXCONST_SGL( 0.77638976371966f / 8.0), FL2FXCONST_SGL( 0.94321834873819f / 8.0) }, + { FL2FXCONST_SGL( 0.07717324253925f / 8.0), FL2FXCONST_SGL( 0.58638399856595f / 8.0) }, + { FL2FXCONST_SGL(-0.56049829194163f / 8.0), FL2FXCONST_SGL( 0.82522301569036f / 8.0) }, + { FL2FXCONST_SGL( 0.98398893639988f / 8.0), FL2FXCONST_SGL( 0.39467440420569f / 8.0) }, + { FL2FXCONST_SGL( 0.47546946844938f / 8.0), FL2FXCONST_SGL( 0.68613044836811f / 8.0) }, + { FL2FXCONST_SGL( 0.65675089314631f / 8.0), FL2FXCONST_SGL( 0.18331637134880f / 8.0) }, + { FL2FXCONST_SGL( 0.03273375457980f / 8.0), FL2FXCONST_SGL(-0.74933109564108f / 8.0) }, + { FL2FXCONST_SGL(-0.38684144784738f / 8.0), FL2FXCONST_SGL( 0.51337349030406f / 8.0) }, + { FL2FXCONST_SGL(-0.97346267944545f / 8.0), FL2FXCONST_SGL(-0.96549364384098f / 8.0) }, + { FL2FXCONST_SGL(-0.53282156061942f / 8.0), FL2FXCONST_SGL(-0.91423265091354f / 8.0) }, + { FL2FXCONST_SGL( 0.99817310731176f / 8.0), FL2FXCONST_SGL( 0.61133572482148f / 8.0) }, + { FL2FXCONST_SGL(-0.50254500772635f / 8.0), FL2FXCONST_SGL(-0.88829338134294f / 8.0) }, + { FL2FXCONST_SGL( 0.01995873238855f / 8.0), FL2FXCONST_SGL( 0.85223515096765f / 8.0) }, + { FL2FXCONST_SGL( 0.99930381973804f / 8.0), FL2FXCONST_SGL( 0.94578896296649f / 8.0) }, + { FL2FXCONST_SGL( 0.82907767600783f / 8.0), FL2FXCONST_SGL(-0.06323442598128f / 8.0) }, + { FL2FXCONST_SGL(-0.58660709669728f / 8.0), FL2FXCONST_SGL( 0.96840773806582f / 8.0) }, + { FL2FXCONST_SGL(-0.17573736667267f / 8.0), FL2FXCONST_SGL(-0.48166920859485f / 8.0) }, + { FL2FXCONST_SGL( 0.83434292401346f / 8.0), FL2FXCONST_SGL(-0.13023450646997f / 8.0) }, + { FL2FXCONST_SGL( 0.05946491307025f / 8.0), FL2FXCONST_SGL( 0.20511047074866f / 8.0) }, + { FL2FXCONST_SGL( 0.81505484574602f / 8.0), FL2FXCONST_SGL(-0.94685947861369f / 8.0) }, + { FL2FXCONST_SGL(-0.44976380954860f / 8.0), FL2FXCONST_SGL( 0.40894572671545f / 8.0) }, + { FL2FXCONST_SGL(-0.89746474625671f / 8.0), FL2FXCONST_SGL( 0.99846578838537f / 8.0) }, + { FL2FXCONST_SGL( 0.39677256130792f / 8.0), FL2FXCONST_SGL(-0.74854668609359f / 8.0) }, + { FL2FXCONST_SGL(-0.07588948563079f / 8.0), FL2FXCONST_SGL( 0.74096214084170f / 8.0) }, + { FL2FXCONST_SGL( 0.76343198951445f / 8.0), FL2FXCONST_SGL( 0.41746629422634f / 8.0) }, + { FL2FXCONST_SGL(-0.74490104699626f / 8.0), FL2FXCONST_SGL( 0.94725911744610f / 8.0) }, + { FL2FXCONST_SGL( 0.64880119792759f / 8.0), FL2FXCONST_SGL( 0.41336660830571f / 8.0) }, + { FL2FXCONST_SGL( 0.62319537462542f / 8.0), FL2FXCONST_SGL(-0.93098313552599f / 8.0) }, + { FL2FXCONST_SGL( 0.42215817594807f / 8.0), FL2FXCONST_SGL(-0.07712787385208f / 8.0) }, + { FL2FXCONST_SGL( 0.02704554141885f / 8.0), FL2FXCONST_SGL(-0.05417518053666f / 8.0) }, + { FL2FXCONST_SGL( 0.80001773566818f / 8.0), FL2FXCONST_SGL( 0.91542195141039f / 8.0) }, + { FL2FXCONST_SGL(-0.79351832348816f / 8.0), FL2FXCONST_SGL(-0.36208897989136f / 8.0) }, + { FL2FXCONST_SGL( 0.63872359151636f / 8.0), FL2FXCONST_SGL( 0.08128252493444f / 8.0) }, + { FL2FXCONST_SGL( 0.52890520960295f / 8.0), FL2FXCONST_SGL( 0.60048872455592f / 8.0) }, + { FL2FXCONST_SGL( 0.74238552914587f / 8.0), FL2FXCONST_SGL( 0.04491915291044f / 8.0) }, + { FL2FXCONST_SGL( 0.99096131449250f / 8.0), FL2FXCONST_SGL(-0.19451182854402f / 8.0) }, + { FL2FXCONST_SGL(-0.80412329643109f / 8.0), FL2FXCONST_SGL(-0.88513818199457f / 8.0) }, + { FL2FXCONST_SGL(-0.64612616129736f / 8.0), FL2FXCONST_SGL( 0.72198674804544f / 8.0) }, + { FL2FXCONST_SGL( 0.11657770663191f / 8.0), FL2FXCONST_SGL(-0.83662833815041f / 8.0) }, + { FL2FXCONST_SGL(-0.95053182488101f / 8.0), FL2FXCONST_SGL(-0.96939905138082f / 8.0) }, + { FL2FXCONST_SGL(-0.62228872928622f / 8.0), FL2FXCONST_SGL( 0.82767262846661f / 8.0) }, + { FL2FXCONST_SGL( 0.03004475787316f / 8.0), FL2FXCONST_SGL(-0.99738896333384f / 8.0) }, + { FL2FXCONST_SGL(-0.97987214341034f / 8.0), FL2FXCONST_SGL( 0.36526129686425f / 8.0) }, + { FL2FXCONST_SGL(-0.99986980746200f / 8.0), FL2FXCONST_SGL(-0.36021610299715f / 8.0) }, + { FL2FXCONST_SGL( 0.89110648599879f / 8.0), FL2FXCONST_SGL(-0.97894250343044f / 8.0) }, + { FL2FXCONST_SGL( 0.10407960510582f / 8.0), FL2FXCONST_SGL( 0.77357793811619f / 8.0) }, + { FL2FXCONST_SGL( 0.95964737821728f / 8.0), FL2FXCONST_SGL(-0.35435818285502f / 8.0) }, + { FL2FXCONST_SGL( 0.50843233159162f / 8.0), FL2FXCONST_SGL( 0.96107691266205f / 8.0) }, + { FL2FXCONST_SGL( 0.17006334670615f / 8.0), FL2FXCONST_SGL(-0.76854025314829f / 8.0) }, + { FL2FXCONST_SGL( 0.25872675063360f / 8.0), FL2FXCONST_SGL( 0.99893303933816f / 8.0) }, + { FL2FXCONST_SGL(-0.01115998681937f / 8.0), FL2FXCONST_SGL( 0.98496019742444f / 8.0) }, + { FL2FXCONST_SGL(-0.79598702973261f / 8.0), FL2FXCONST_SGL( 0.97138411318894f / 8.0) }, + { FL2FXCONST_SGL(-0.99264708948101f / 8.0), FL2FXCONST_SGL(-0.99542822402536f / 8.0) }, + { FL2FXCONST_SGL(-0.99829663752818f / 8.0), FL2FXCONST_SGL( 0.01877138824311f / 8.0) }, + { FL2FXCONST_SGL(-0.70801016548184f / 8.0), FL2FXCONST_SGL( 0.33680685948117f / 8.0) }, + { FL2FXCONST_SGL(-0.70467057786826f / 8.0), FL2FXCONST_SGL( 0.93272777501857f / 8.0) }, + { FL2FXCONST_SGL( 0.99846021905254f / 8.0), FL2FXCONST_SGL(-0.98725746254433f / 8.0) }, + { FL2FXCONST_SGL(-0.63364968534650f / 8.0), FL2FXCONST_SGL(-0.16473594423746f / 8.0) }, + { FL2FXCONST_SGL(-0.16258217500792f / 8.0), FL2FXCONST_SGL(-0.95939125400802f / 8.0) }, + { FL2FXCONST_SGL(-0.43645594360633f / 8.0), FL2FXCONST_SGL(-0.94805030113284f / 8.0) }, + { FL2FXCONST_SGL(-0.99848471702976f / 8.0), FL2FXCONST_SGL( 0.96245166923809f / 8.0) }, + { FL2FXCONST_SGL(-0.16796458968998f / 8.0), FL2FXCONST_SGL(-0.98987511890470f / 8.0) }, + { FL2FXCONST_SGL(-0.87979225745213f / 8.0), FL2FXCONST_SGL(-0.71725725041680f / 8.0) }, + { FL2FXCONST_SGL( 0.44183099021786f / 8.0), FL2FXCONST_SGL(-0.93568974498761f / 8.0) }, + { FL2FXCONST_SGL( 0.93310180125532f / 8.0), FL2FXCONST_SGL(-0.99913308068246f / 8.0) }, + { FL2FXCONST_SGL(-0.93941931782002f / 8.0), FL2FXCONST_SGL(-0.56409379640356f / 8.0) }, + { FL2FXCONST_SGL(-0.88590003188677f / 8.0), FL2FXCONST_SGL( 0.47624600491382f / 8.0) }, + { FL2FXCONST_SGL( 0.99971463703691f / 8.0), FL2FXCONST_SGL(-0.83889954253462f / 8.0) }, + { FL2FXCONST_SGL(-0.75376385639978f / 8.0), FL2FXCONST_SGL( 0.00814643438625f / 8.0) }, + { FL2FXCONST_SGL( 0.93887685615875f / 8.0), FL2FXCONST_SGL(-0.11284528204636f / 8.0) }, + { FL2FXCONST_SGL( 0.85126435782309f / 8.0), FL2FXCONST_SGL( 0.52349251543547f / 8.0) }, + { FL2FXCONST_SGL( 0.39701421446381f / 8.0), FL2FXCONST_SGL( 0.81779634174316f / 8.0) }, + { FL2FXCONST_SGL(-0.37024464187437f / 8.0), FL2FXCONST_SGL(-0.87071656222959f / 8.0) }, + { FL2FXCONST_SGL(-0.36024828242896f / 8.0), FL2FXCONST_SGL( 0.34655735648287f / 8.0) }, + { FL2FXCONST_SGL(-0.93388812549209f / 8.0), FL2FXCONST_SGL(-0.84476541096429f / 8.0) }, + { FL2FXCONST_SGL(-0.65298804552119f / 8.0), FL2FXCONST_SGL(-0.18439575450921f / 8.0) }, + { FL2FXCONST_SGL( 0.11960319006843f / 8.0), FL2FXCONST_SGL( 0.99899346780168f / 8.0) }, + { FL2FXCONST_SGL( 0.94292565553160f / 8.0), FL2FXCONST_SGL( 0.83163906518293f / 8.0) }, + { FL2FXCONST_SGL( 0.75081145286948f / 8.0), FL2FXCONST_SGL(-0.35533223142265f / 8.0) }, + { FL2FXCONST_SGL( 0.56721979748394f / 8.0), FL2FXCONST_SGL(-0.24076836414499f / 8.0) }, + { FL2FXCONST_SGL( 0.46857766746029f / 8.0), FL2FXCONST_SGL(-0.30140233457198f / 8.0) }, + { FL2FXCONST_SGL( 0.97312313923635f / 8.0), FL2FXCONST_SGL(-0.99548191630031f / 8.0) }, + { FL2FXCONST_SGL(-0.38299976567017f / 8.0), FL2FXCONST_SGL( 0.98516909715427f / 8.0) }, + { FL2FXCONST_SGL( 0.41025800019463f / 8.0), FL2FXCONST_SGL( 0.02116736935734f / 8.0) }, + { FL2FXCONST_SGL( 0.09638062008048f / 8.0), FL2FXCONST_SGL( 0.04411984381457f / 8.0) }, + { FL2FXCONST_SGL(-0.85283249275397f / 8.0), FL2FXCONST_SGL( 0.91475563922421f / 8.0) }, + { FL2FXCONST_SGL( 0.88866808958124f / 8.0), FL2FXCONST_SGL(-0.99735267083226f / 8.0) }, + { FL2FXCONST_SGL(-0.48202429536989f / 8.0), FL2FXCONST_SGL(-0.96805608884164f / 8.0) }, + { FL2FXCONST_SGL( 0.27572582416567f / 8.0), FL2FXCONST_SGL( 0.58634753335832f / 8.0) }, + { FL2FXCONST_SGL(-0.65889129659168f / 8.0), FL2FXCONST_SGL( 0.58835634138583f / 8.0) }, + { FL2FXCONST_SGL( 0.98838086953732f / 8.0), FL2FXCONST_SGL( 0.99994349600236f / 8.0) }, + { FL2FXCONST_SGL(-0.20651349620689f / 8.0), FL2FXCONST_SGL( 0.54593044066355f / 8.0) }, + { FL2FXCONST_SGL(-0.62126416356920f / 8.0), FL2FXCONST_SGL(-0.59893681700392f / 8.0) }, + { FL2FXCONST_SGL( 0.20320105410437f / 8.0), FL2FXCONST_SGL(-0.86879180355289f / 8.0) }, + { FL2FXCONST_SGL(-0.97790548600584f / 8.0), FL2FXCONST_SGL( 0.96290806999242f / 8.0) }, + { FL2FXCONST_SGL( 0.11112534735126f / 8.0), FL2FXCONST_SGL( 0.21484763313301f / 8.0) }, + { FL2FXCONST_SGL(-0.41368337314182f / 8.0), FL2FXCONST_SGL( 0.28216837680365f / 8.0) }, + { FL2FXCONST_SGL( 0.24133038992960f / 8.0), FL2FXCONST_SGL( 0.51294362630238f / 8.0) }, + { FL2FXCONST_SGL(-0.66393410674885f / 8.0), FL2FXCONST_SGL(-0.08249679629081f / 8.0) }, + { FL2FXCONST_SGL(-0.53697829178752f / 8.0), FL2FXCONST_SGL(-0.97649903936228f / 8.0) }, + { FL2FXCONST_SGL(-0.97224737889348f / 8.0), FL2FXCONST_SGL( 0.22081333579837f / 8.0) }, + { FL2FXCONST_SGL( 0.87392477144549f / 8.0), FL2FXCONST_SGL(-0.12796173740361f / 8.0) }, + { FL2FXCONST_SGL( 0.19050361015753f / 8.0), FL2FXCONST_SGL( 0.01602615387195f / 8.0) }, + { FL2FXCONST_SGL(-0.46353441212724f / 8.0), FL2FXCONST_SGL(-0.95249041539006f / 8.0) }, + { FL2FXCONST_SGL(-0.07064096339021f / 8.0), FL2FXCONST_SGL(-0.94479803205886f / 8.0) }, + { FL2FXCONST_SGL(-0.92444085484466f / 8.0), FL2FXCONST_SGL(-0.10457590187436f / 8.0) }, + { FL2FXCONST_SGL(-0.83822593578728f / 8.0), FL2FXCONST_SGL(-0.01695043208885f / 8.0) }, + { FL2FXCONST_SGL( 0.75214681811150f / 8.0), FL2FXCONST_SGL(-0.99955681042665f / 8.0) }, + { FL2FXCONST_SGL(-0.42102998829339f / 8.0), FL2FXCONST_SGL( 0.99720941999394f / 8.0) }, + { FL2FXCONST_SGL(-0.72094786237696f / 8.0), FL2FXCONST_SGL(-0.35008961934255f / 8.0) }, + { FL2FXCONST_SGL( 0.78843311019251f / 8.0), FL2FXCONST_SGL( 0.52851398958271f / 8.0) }, + { FL2FXCONST_SGL( 0.97394027897442f / 8.0), FL2FXCONST_SGL(-0.26695944086561f / 8.0) }, + { FL2FXCONST_SGL( 0.99206463477946f / 8.0), FL2FXCONST_SGL(-0.57010120849429f / 8.0) }, + { FL2FXCONST_SGL( 0.76789609461795f / 8.0), FL2FXCONST_SGL(-0.76519356730966f / 8.0) }, + { FL2FXCONST_SGL(-0.82002421836409f / 8.0), FL2FXCONST_SGL(-0.73530179553767f / 8.0) }, + { FL2FXCONST_SGL( 0.81924990025724f / 8.0), FL2FXCONST_SGL( 0.99698425250579f / 8.0) }, + { FL2FXCONST_SGL(-0.26719850873357f / 8.0), FL2FXCONST_SGL( 0.68903369776193f / 8.0) }, + { FL2FXCONST_SGL(-0.43311260380975f / 8.0), FL2FXCONST_SGL( 0.85321815947490f / 8.0) }, + { FL2FXCONST_SGL( 0.99194979673836f / 8.0), FL2FXCONST_SGL( 0.91876249766422f / 8.0) }, + { FL2FXCONST_SGL(-0.80692001248487f / 8.0), FL2FXCONST_SGL(-0.32627540663214f / 8.0) }, + { FL2FXCONST_SGL( 0.43080003649976f / 8.0), FL2FXCONST_SGL(-0.21919095636638f / 8.0) }, + { FL2FXCONST_SGL( 0.67709491937357f / 8.0), FL2FXCONST_SGL(-0.95478075822906f / 8.0) }, + { FL2FXCONST_SGL( 0.56151770568316f / 8.0), FL2FXCONST_SGL(-0.70693811747778f / 8.0) }, + { FL2FXCONST_SGL( 0.10831862810749f / 8.0), FL2FXCONST_SGL(-0.08628837174592f / 8.0) }, + { FL2FXCONST_SGL( 0.91229417540436f / 8.0), FL2FXCONST_SGL(-0.65987351408410f / 8.0) }, + { FL2FXCONST_SGL(-0.48972893932274f / 8.0), FL2FXCONST_SGL( 0.56289246362686f / 8.0) }, + { FL2FXCONST_SGL(-0.89033658689697f / 8.0), FL2FXCONST_SGL(-0.71656563987082f / 8.0) }, + { FL2FXCONST_SGL( 0.65269447475094f / 8.0), FL2FXCONST_SGL( 0.65916004833932f / 8.0) }, + { FL2FXCONST_SGL( 0.67439478141121f / 8.0), FL2FXCONST_SGL(-0.81684380846796f / 8.0) }, + { FL2FXCONST_SGL(-0.47770832416973f / 8.0), FL2FXCONST_SGL(-0.16789556203025f / 8.0) }, + { FL2FXCONST_SGL(-0.99715979260878f / 8.0), FL2FXCONST_SGL(-0.93565784007648f / 8.0) }, + { FL2FXCONST_SGL(-0.90889593602546f / 8.0), FL2FXCONST_SGL( 0.62034397054380f / 8.0) }, + { FL2FXCONST_SGL(-0.06618622548177f / 8.0), FL2FXCONST_SGL(-0.23812217221359f / 8.0) }, + { FL2FXCONST_SGL( 0.99430266919728f / 8.0), FL2FXCONST_SGL( 0.18812555317553f / 8.0) }, + { FL2FXCONST_SGL( 0.97686402381843f / 8.0), FL2FXCONST_SGL(-0.28664534366620f / 8.0) }, + { FL2FXCONST_SGL( 0.94813650221268f / 8.0), FL2FXCONST_SGL(-0.97506640027128f / 8.0) }, + { FL2FXCONST_SGL(-0.95434497492853f / 8.0), FL2FXCONST_SGL(-0.79607978501983f / 8.0) }, + { FL2FXCONST_SGL(-0.49104783137150f / 8.0), FL2FXCONST_SGL( 0.32895214359663f / 8.0) }, + { FL2FXCONST_SGL( 0.99881175120751f / 8.0), FL2FXCONST_SGL( 0.88993983831354f / 8.0) }, + { FL2FXCONST_SGL( 0.50449166760303f / 8.0), FL2FXCONST_SGL(-0.85995072408434f / 8.0) }, + { FL2FXCONST_SGL( 0.47162891065108f / 8.0), FL2FXCONST_SGL(-0.18680204049569f / 8.0) }, + { FL2FXCONST_SGL(-0.62081581361840f / 8.0), FL2FXCONST_SGL( 0.75000676218956f / 8.0) }, + { FL2FXCONST_SGL(-0.43867015250812f / 8.0), FL2FXCONST_SGL( 0.99998069244322f / 8.0) }, + { FL2FXCONST_SGL( 0.98630563232075f / 8.0), FL2FXCONST_SGL(-0.53578899600662f / 8.0) }, + { FL2FXCONST_SGL(-0.61510362277374f / 8.0), FL2FXCONST_SGL(-0.89515019899997f / 8.0) }, + { FL2FXCONST_SGL(-0.03841517601843f / 8.0), FL2FXCONST_SGL(-0.69888815681179f / 8.0) }, + { FL2FXCONST_SGL(-0.30102157304644f / 8.0), FL2FXCONST_SGL(-0.07667808922205f / 8.0) }, + { FL2FXCONST_SGL( 0.41881284182683f / 8.0), FL2FXCONST_SGL( 0.02188098922282f / 8.0) }, + { FL2FXCONST_SGL(-0.86135454941237f / 8.0), FL2FXCONST_SGL( 0.98947480909359f / 8.0) }, + { FL2FXCONST_SGL( 0.67226861393788f / 8.0), FL2FXCONST_SGL(-0.13494389011014f / 8.0) }, + { FL2FXCONST_SGL(-0.70737398842068f / 8.0), FL2FXCONST_SGL(-0.76547349325992f / 8.0) }, + { FL2FXCONST_SGL( 0.94044946687963f / 8.0), FL2FXCONST_SGL( 0.09026201157416f / 8.0) }, + { FL2FXCONST_SGL(-0.82386352534327f / 8.0), FL2FXCONST_SGL( 0.08924768823676f / 8.0) }, + { FL2FXCONST_SGL(-0.32070666698656f / 8.0), FL2FXCONST_SGL( 0.50143421908753f / 8.0) }, + { FL2FXCONST_SGL( 0.57593163224487f / 8.0), FL2FXCONST_SGL(-0.98966422921509f / 8.0) }, + { FL2FXCONST_SGL(-0.36326018419965f / 8.0), FL2FXCONST_SGL( 0.07440243123228f / 8.0) }, + { FL2FXCONST_SGL( 0.99979044674350f / 8.0), FL2FXCONST_SGL(-0.14130287347405f / 8.0) }, + { FL2FXCONST_SGL(-0.92366023326932f / 8.0), FL2FXCONST_SGL(-0.97979298068180f / 8.0) }, + { FL2FXCONST_SGL(-0.44607178518598f / 8.0), FL2FXCONST_SGL(-0.54233252016394f / 8.0) }, + { FL2FXCONST_SGL( 0.44226800932956f / 8.0), FL2FXCONST_SGL( 0.71326756742752f / 8.0) }, + { FL2FXCONST_SGL( 0.03671907158312f / 8.0), FL2FXCONST_SGL( 0.63606389366675f / 8.0) }, + { FL2FXCONST_SGL( 0.52175424682195f / 8.0), FL2FXCONST_SGL(-0.85396826735705f / 8.0) }, + { FL2FXCONST_SGL(-0.94701139690956f / 8.0), FL2FXCONST_SGL(-0.01826348194255f / 8.0) }, + { FL2FXCONST_SGL(-0.98759606946049f / 8.0), FL2FXCONST_SGL( 0.82288714303073f / 8.0) }, + { FL2FXCONST_SGL( 0.87434794743625f / 8.0), FL2FXCONST_SGL( 0.89399495655433f / 8.0) }, + { FL2FXCONST_SGL(-0.93412041758744f / 8.0), FL2FXCONST_SGL( 0.41374052024363f / 8.0) }, + { FL2FXCONST_SGL( 0.96063943315511f / 8.0), FL2FXCONST_SGL( 0.93116709541280f / 8.0) }, + { FL2FXCONST_SGL( 0.97534253457837f / 8.0), FL2FXCONST_SGL( 0.86150930812689f / 8.0) }, + { FL2FXCONST_SGL( 0.99642466504163f / 8.0), FL2FXCONST_SGL( 0.70190043427512f / 8.0) }, + { FL2FXCONST_SGL(-0.94705089665984f / 8.0), FL2FXCONST_SGL(-0.29580042814306f / 8.0) }, + { FL2FXCONST_SGL( 0.91599807087376f / 8.0), FL2FXCONST_SGL(-0.98147830385781f / 8.0) } +}; +//@} + +/* +static const FIXP_SGL harmonicPhase [2][4] = { + { 1.0, 0.0, -1.0, 0.0}, + { 0.0, 1.0, 0.0, -1.0} +}; +*/ + + +/* The CLDFB-80 is not linear phase (unsymmetric), but the exact + phase difference between adjacent bands, at exact positions + (in this case exactly in the frequency band centre), can of + course be determined anyway. While the standard symmetric QMF + bank has a phase difference of 0.5*pi, the CLDFB-80 + bank has the difference 0.2337*pi. */ +const FIXP_SGL harmonicPhaseX [2][4] = { + { FL2FXCONST_SGL( 7.423735494778151e-001), FL2FXCONST_SGL(-6.699862036159475e-001), + FL2FXCONST_SGL(-7.423735494778152e-001), FL2FXCONST_SGL( 6.699862036159474e-001) }, + { FL2FXCONST_SGL( 7.423735494778151e-001), FL2FXCONST_SGL( 6.699862036159476e-001), + FL2FXCONST_SGL(-7.423735494778151e-001), FL2FXCONST_SGL(-6.699862036159476e-001) } +}; + +/* tables for SBR and AAC LD */ +/* table for 8 time slot index */ +const int FDK_sbrDecoder_envelopeTable_8 [8][5] = { +/* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ +/* borders from left to right side; -1 = not in use */ + /*[|T-|------]*/ { 2, 0, 0, 1, -1 }, + /*[|-T-|-----]*/ { 2, 0, 0, 2, -1 }, + /*[--|T-|----]*/ { 3, 1, 1, 2, 4 }, + /*[---|T-|---]*/ { 3, 1, 1, 3, 5 }, + /*[----|T-|--]*/ { 3, 1, 1, 4, 6 }, + /*[-----|T--|]*/ { 2, 1, 1, 5, -1 }, + /*[------|T-|]*/ { 2, 1, 1, 6, -1 }, + /*[-------|T|]*/ { 2, 1, 1, 7, -1 }, +}; + +/* table for 15 time slot index */ +const int FDK_sbrDecoder_envelopeTable_15 [15][6] = { + /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ + /* length from left to right side; -1 = not in use */ + /*[|T---|------------]*/ { 2, 0, 0, 4, -1, -1}, + /*[|-T---|-----------]*/ { 2, 0, 0, 5, -1, -1}, + /*[|--|T---|---------]*/ { 3, 1, 1, 2, 6, -1}, + /*[|---|T---|--------]*/ { 3, 1, 1, 3, 7, -1}, + /*[|----|T---|-------]*/ { 3, 1, 1, 4, 8, -1}, + /*[|-----|T---|------]*/ { 3, 1, 1, 5, 9, -1}, + /*[|------|T---|-----]*/ { 3, 1, 1, 6, 10, -1}, + /*[|-------|T---|----]*/ { 3, 1, 1, 7, 11, -1}, + /*[|--------|T---|---]*/ { 3, 1, 1, 8, 12, -1}, + /*[|---------|T---|--]*/ { 3, 1, 1, 9, 13, -1}, + /*[|----------|T----|]*/ { 2, 1, 1,10, -1, -1}, + /*[|-----------|T---|]*/ { 2, 1, 1,11, -1, -1}, + /*[|------------|T--|]*/ { 2, 1, 1,12, -1, -1}, + /*[|-------------|T-|]*/ { 2, 1, 1,13, -1, -1}, + /*[|--------------|T|]*/ { 2, 1, 1,14, -1, -1}, +}; + +/* table for 16 time slot index */ +const int FDK_sbrDecoder_envelopeTable_16 [16][6] = { + /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ + /* length from left to right side; -1 = not in use */ + /*[|T---|------------|]*/ { 2, 0, 0, 4, -1, -1}, + /*[|-T---|-----------|]*/ { 2, 0, 0, 5, -1, -1}, + /*[|--|T---|----------]*/ { 3, 1, 1, 2, 6, -1}, + /*[|---|T---|---------]*/ { 3, 1, 1, 3, 7, -1}, + /*[|----|T---|--------]*/ { 3, 1, 1, 4, 8, -1}, + /*[|-----|T---|-------]*/ { 3, 1, 1, 5, 9, -1}, + /*[|------|T---|------]*/ { 3, 1, 1, 6, 10, -1}, + /*[|-------|T---|-----]*/ { 3, 1, 1, 7, 11, -1}, + /*[|--------|T---|----]*/ { 3, 1, 1, 8, 12, -1}, + /*[|---------|T---|---]*/ { 3, 1, 1, 9, 13, -1}, + /*[|----------|T---|--]*/ { 3, 1, 1,10, 14, -1}, + /*[|-----------|T----|]*/ { 2, 1, 1,11, -1, -1}, + /*[|------------|T---|]*/ { 2, 1, 1,12, -1, -1}, + /*[|-------------|T--|]*/ { 2, 1, 1,13, -1, -1}, + /*[|--------------|T-|]*/ { 2, 1, 1,14, -1, -1}, + /*[|---------------|T|]*/ { 2, 1, 1,15, -1, -1}, +}; + +/*! + \name FrameInfoDefaults + + Predefined envelope positions for the FIX-FIX case (static framing) +*/ +//@{ +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info1_15 = { 0, 1, {0, 15, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, -1, 1, {0, 15, 0} }; +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info2_15 = { 0, 2, {0, 8, 15, 0, 0, 0}, {1, 1, 0, 0, 0}, -1, 2, {0, 8, 15} }; +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info4_15 = { 0, 4, {0, 4, 8, 12, 15, 0}, {1, 1, 1, 1, 0}, -1, 2, {0, 8, 15} }; +#if (MAX_ENVELOPES >= 8) +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info8_15 = { 0, 8, {0, 2, 4, 6, 8, 10, 12, 14, 15}, {1, 1, 1, 1, 1, 1, 1, 1}, -1, 2, {0, 8, 15} }; +#endif + +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info1_16 = { 0, 1, {0, 16, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, -1, 1, {0, 16, 0} }; +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info2_16 = { 0, 2, {0, 8, 16, 0, 0, 0}, {1, 1, 0, 0, 0}, -1, 2, {0, 8, 16} }; +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info4_16 = { 0, 4, {0, 4, 8, 12, 16, 0}, {1, 1, 1, 1, 0}, -1, 2, {0, 8, 16} }; + +#if (MAX_ENVELOPES >= 8) +const FRAME_INFO FDK_sbrDecoder_sbr_frame_info8_16 = { 0, 8, {0, 2, 4, 6, 8, 10, 12, 14, 16}, {1, 1, 1, 1, 1, 1, 1, 1}, -1, 2, {0, 8, 16} }; +#endif + + +//@} + +/*! + \name SBR_HuffmanTables + + SBR Huffman Table Overview: \n + \n + o envelope level, 1.5 dB: \n + 1) sbr_huffBook_EnvLevel10T[120][2] \n + 2) sbr_huffBook_EnvLevel10F[120][2] \n + \n + o envelope balance, 1.5 dB: \n + 3) sbr_huffBook_EnvBalance10T[48][2] \n + 4) sbr_huffBook_EnvBalance10F[48][2] \n + \n + o envelope level, 3.0 dB: \n + 5) sbr_huffBook_EnvLevel11T[62][2] \n + 6) sbr_huffBook_EnvLevel11F[62][2] \n + \n + o envelope balance, 3.0 dB: \n + 7) sbr_huffBook_EnvBalance11T[24][2] \n + 8) sbr_huffBook_EnvBalance11F[24][2] \n + \n + o noise level, 3.0 dB: \n + 9) sbr_huffBook_NoiseLevel11T[62][2] \n + -) (sbr_huffBook_EnvLevel11F[62][2] is used for freq dir)\n + \n + o noise balance, 3.0 dB: \n + 10) sbr_huffBook_NoiseBalance11T[24][2]\n + -) (sbr_huffBook_EnvBalance11F[24][2] is used for freq dir)\n + \n + (1.5 dB is never used for noise) + +*/ +//@{ +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel10T[120][2] = { + { 1, 2 }, { -64, -65 }, { 3, 4 }, { -63, -66 }, + { 5, 6 }, { -62, -67 }, { 7, 8 }, { -61, -68 }, + { 9, 10 }, { -60, -69 }, { 11, 12 }, { -59, -70 }, + { 13, 14 }, { -58, -71 }, { 15, 16 }, { -57, -72 }, + { 17, 18 }, { -73, -56 }, { 19, 21 }, { -74, 20 }, + { -55, -75 }, { 22, 26 }, { 23, 24 }, { -54, -76 }, + { -77, 25 }, { -53, -78 }, { 27, 34 }, { 28, 29 }, + { -52, -79 }, { 30, 31 }, { -80, -51 }, { 32, 33 }, + { -83, -82 }, { -81, -50 }, { 35, 57 }, { 36, 40 }, + { 37, 38 }, { -88, -84 }, { -48, 39 }, { -90, -85 }, + { 41, 46 }, { 42, 43 }, { -49, -87 }, { 44, 45 }, + { -89, -86 }, {-124,-123 }, { 47, 50 }, { 48, 49 }, + {-122,-121 }, {-120,-119 }, { 51, 54 }, { 52, 53 }, + {-118,-117 }, {-116,-115 }, { 55, 56 }, {-114,-113 }, + {-112,-111 }, { 58, 89 }, { 59, 74 }, { 60, 67 }, + { 61, 64 }, { 62, 63 }, {-110,-109 }, {-108,-107 }, + { 65, 66 }, {-106,-105 }, {-104,-103 }, { 68, 71 }, + { 69, 70 }, {-102,-101 }, {-100, -99 }, { 72, 73 }, + { -98, -97 }, { -96, -95 }, { 75, 82 }, { 76, 79 }, + { 77, 78 }, { -94, -93 }, { -92, -91 }, { 80, 81 }, + { -47, -46 }, { -45, -44 }, { 83, 86 }, { 84, 85 }, + { -43, -42 }, { -41, -40 }, { 87, 88 }, { -39, -38 }, + { -37, -36 }, { 90, 105 }, { 91, 98 }, { 92, 95 }, + { 93, 94 }, { -35, -34 }, { -33, -32 }, { 96, 97 }, + { -31, -30 }, { -29, -28 }, { 99, 102 }, { 100, 101 }, + { -27, -26 }, { -25, -24 }, { 103, 104 }, { -23, -22 }, + { -21, -20 }, { 106, 113 }, { 107, 110 }, { 108, 109 }, + { -19, -18 }, { -17, -16 }, { 111, 112 }, { -15, -14 }, + { -13, -12 }, { 114, 117 }, { 115, 116 }, { -11, -10 }, + { -9, -8 }, { 118, 119 }, { -7, -6 }, { -5, -4 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel10F[120][2] = { + { 1, 2 }, { -64, -65 }, { 3, 4 }, { -63, -66 }, + { 5, 6 }, { -67, -62 }, { 7, 8 }, { -68, -61 }, + { 9, 10 }, { -69, -60 }, { 11, 13 }, { -70, 12 }, + { -59, -71 }, { 14, 16 }, { -58, 15 }, { -72, -57 }, + { 17, 19 }, { -73, 18 }, { -56, -74 }, { 20, 23 }, + { 21, 22 }, { -55, -75 }, { -54, -53 }, { 24, 27 }, + { 25, 26 }, { -76, -52 }, { -77, -51 }, { 28, 31 }, + { 29, 30 }, { -50, -78 }, { -79, -49 }, { 32, 36 }, + { 33, 34 }, { -48, -47 }, { -80, 35 }, { -81, -82 }, + { 37, 47 }, { 38, 41 }, { 39, 40 }, { -83, -46 }, + { -45, -84 }, { 42, 44 }, { -85, 43 }, { -44, -43 }, + { 45, 46 }, { -88, -87 }, { -86, -90 }, { 48, 66 }, + { 49, 56 }, { 50, 53 }, { 51, 52 }, { -92, -42 }, + { -41, -39 }, { 54, 55 }, {-105, -89 }, { -38, -37 }, + { 57, 60 }, { 58, 59 }, { -94, -91 }, { -40, -36 }, + { 61, 63 }, { -20, 62 }, {-115,-110 }, { 64, 65 }, + {-108,-107 }, {-101, -97 }, { 67, 89 }, { 68, 75 }, + { 69, 72 }, { 70, 71 }, { -95, -93 }, { -34, -27 }, + { 73, 74 }, { -22, -17 }, { -16,-124 }, { 76, 82 }, + { 77, 79 }, {-123, 78 }, {-122,-121 }, { 80, 81 }, + {-120,-119 }, {-118,-117 }, { 83, 86 }, { 84, 85 }, + {-116,-114 }, {-113,-112 }, { 87, 88 }, {-111,-109 }, + {-106,-104 }, { 90, 105 }, { 91, 98 }, { 92, 95 }, + { 93, 94 }, {-103,-102 }, {-100, -99 }, { 96, 97 }, + { -98, -96 }, { -35, -33 }, { 99, 102 }, { 100, 101 }, + { -32, -31 }, { -30, -29 }, { 103, 104 }, { -28, -26 }, + { -25, -24 }, { 106, 113 }, { 107, 110 }, { 108, 109 }, + { -23, -21 }, { -19, -18 }, { 111, 112 }, { -15, -14 }, + { -13, -12 }, { 114, 117 }, { 115, 116 }, { -11, -10 }, + { -9, -8 }, { 118, 119 }, { -7, -6 }, { -5, -4 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance10T[48][2] = { + { -64, 1 }, { -63, 2 }, { -65, 3 }, { -62, 4 }, + { -66, 5 }, { -61, 6 }, { -67, 7 }, { -60, 8 }, + { -68, 9 }, { 10, 11 }, { -69, -59 }, { 12, 13 }, + { -70, -58 }, { 14, 28 }, { 15, 21 }, { 16, 18 }, + { -57, 17 }, { -71, -56 }, { 19, 20 }, { -88, -87 }, + { -86, -85 }, { 22, 25 }, { 23, 24 }, { -84, -83 }, + { -82, -81 }, { 26, 27 }, { -80, -79 }, { -78, -77 }, + { 29, 36 }, { 30, 33 }, { 31, 32 }, { -76, -75 }, + { -74, -73 }, { 34, 35 }, { -72, -55 }, { -54, -53 }, + { 37, 41 }, { 38, 39 }, { -52, -51 }, { -50, 40 }, + { -49, -48 }, { 42, 45 }, { 43, 44 }, { -47, -46 }, + { -45, -44 }, { 46, 47 }, { -43, -42 }, { -41, -40 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance10F[48][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { -66, 4 }, + { -62, 5 }, { -61, 6 }, { -67, 7 }, { -68, 8 }, + { -60, 9 }, { 10, 11 }, { -69, -59 }, { -70, 12 }, + { -58, 13 }, { 14, 17 }, { -71, 15 }, { -57, 16 }, + { -56, -73 }, { 18, 32 }, { 19, 25 }, { 20, 22 }, + { -72, 21 }, { -88, -87 }, { 23, 24 }, { -86, -85 }, + { -84, -83 }, { 26, 29 }, { 27, 28 }, { -82, -81 }, + { -80, -79 }, { 30, 31 }, { -78, -77 }, { -76, -75 }, + { 33, 40 }, { 34, 37 }, { 35, 36 }, { -74, -55 }, + { -54, -53 }, { 38, 39 }, { -52, -51 }, { -50, -49 }, + { 41, 44 }, { 42, 43 }, { -48, -47 }, { -46, -45 }, + { 45, 46 }, { -44, -43 }, { -42, 47 }, { -41, -40 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel11T[62][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { -66, 4 }, + { -62, 5 }, { -67, 6 }, { -61, 7 }, { -68, 8 }, + { -60, 9 }, { 10, 11 }, { -69, -59 }, { 12, 14 }, + { -70, 13 }, { -71, -58 }, { 15, 18 }, { 16, 17 }, + { -72, -57 }, { -73, -74 }, { 19, 22 }, { -56, 20 }, + { -55, 21 }, { -54, -77 }, { 23, 31 }, { 24, 25 }, + { -75, -76 }, { 26, 27 }, { -78, -53 }, { 28, 29 }, + { -52, -95 }, { -94, 30 }, { -93, -92 }, { 32, 47 }, + { 33, 40 }, { 34, 37 }, { 35, 36 }, { -91, -90 }, + { -89, -88 }, { 38, 39 }, { -87, -86 }, { -85, -84 }, + { 41, 44 }, { 42, 43 }, { -83, -82 }, { -81, -80 }, + { 45, 46 }, { -79, -51 }, { -50, -49 }, { 48, 55 }, + { 49, 52 }, { 50, 51 }, { -48, -47 }, { -46, -45 }, + { 53, 54 }, { -44, -43 }, { -42, -41 }, { 56, 59 }, + { 57, 58 }, { -40, -39 }, { -38, -37 }, { 60, 61 }, + { -36, -35 }, { -34, -33 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel11F[62][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { -66, 4 }, + { -62, 5 }, { -67, 6 }, { 7, 8 }, { -61, -68 }, + { 9, 10 }, { -60, -69 }, { 11, 12 }, { -59, -70 }, + { 13, 14 }, { -58, -71 }, { 15, 16 }, { -57, -72 }, + { 17, 19 }, { -56, 18 }, { -55, -73 }, { 20, 24 }, + { 21, 22 }, { -74, -54 }, { -53, 23 }, { -75, -76 }, + { 25, 30 }, { 26, 27 }, { -52, -51 }, { 28, 29 }, + { -77, -79 }, { -50, -49 }, { 31, 39 }, { 32, 35 }, + { 33, 34 }, { -78, -46 }, { -82, -88 }, { 36, 37 }, + { -83, -48 }, { -47, 38 }, { -86, -85 }, { 40, 47 }, + { 41, 44 }, { 42, 43 }, { -80, -44 }, { -43, -42 }, + { 45, 46 }, { -39, -87 }, { -84, -40 }, { 48, 55 }, + { 49, 52 }, { 50, 51 }, { -95, -94 }, { -93, -92 }, + { 53, 54 }, { -91, -90 }, { -89, -81 }, { 56, 59 }, + { 57, 58 }, { -45, -41 }, { -38, -37 }, { 60, 61 }, + { -36, -35 }, { -34, -33 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance11T[24][2] = { + { -64, 1 }, { -63, 2 }, { -65, 3 }, { -66, 4 }, + { -62, 5 }, { -61, 6 }, { -67, 7 }, { -68, 8 }, + { -60, 9 }, { 10, 16 }, { 11, 13 }, { -69, 12 }, + { -76, -75 }, { 14, 15 }, { -74, -73 }, { -72, -71 }, + { 17, 20 }, { 18, 19 }, { -70, -59 }, { -58, -57 }, + { 21, 22 }, { -56, -55 }, { -54, 23 }, { -53, -52 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance11F[24][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { -66, 4 }, + { -62, 5 }, { -61, 6 }, { -67, 7 }, { -68, 8 }, + { -60, 9 }, { 10, 13 }, { -69, 11 }, { -59, 12 }, + { -58, -76 }, { 14, 17 }, { 15, 16 }, { -75, -74 }, + { -73, -72 }, { 18, 21 }, { 19, 20 }, { -71, -70 }, + { -57, -56 }, { 22, 23 }, { -55, -54 }, { -53, -52 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_NoiseLevel11T[62][2] = { + { -64, 1 }, { -63, 2 }, { -65, 3 }, { -66, 4 }, + { -62, 5 }, { -67, 6 }, { 7, 8 }, { -61, -68 }, + { 9, 30 }, { 10, 15 }, { -60, 11 }, { -69, 12 }, + { 13, 14 }, { -59, -53 }, { -95, -94 }, { 16, 23 }, + { 17, 20 }, { 18, 19 }, { -93, -92 }, { -91, -90 }, + { 21, 22 }, { -89, -88 }, { -87, -86 }, { 24, 27 }, + { 25, 26 }, { -85, -84 }, { -83, -82 }, { 28, 29 }, + { -81, -80 }, { -79, -78 }, { 31, 46 }, { 32, 39 }, + { 33, 36 }, { 34, 35 }, { -77, -76 }, { -75, -74 }, + { 37, 38 }, { -73, -72 }, { -71, -70 }, { 40, 43 }, + { 41, 42 }, { -58, -57 }, { -56, -55 }, { 44, 45 }, + { -54, -52 }, { -51, -50 }, { 47, 54 }, { 48, 51 }, + { 49, 50 }, { -49, -48 }, { -47, -46 }, { 52, 53 }, + { -45, -44 }, { -43, -42 }, { 55, 58 }, { 56, 57 }, + { -41, -40 }, { -39, -38 }, { 59, 60 }, { -37, -36 }, + { -35, 61 }, { -34, -33 } +}; + +const SCHAR FDK_sbrDecoder_sbr_huffBook_NoiseBalance11T[24][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { 4, 9 }, + { -66, 5 }, { -62, 6 }, { 7, 8 }, { -76, -75 }, + { -74, -73 }, { 10, 17 }, { 11, 14 }, { 12, 13 }, + { -72, -71 }, { -70, -69 }, { 15, 16 }, { -68, -67 }, + { -61, -60 }, { 18, 21 }, { 19, 20 }, { -59, -58 }, + { -57, -56 }, { 22, 23 }, { -55, -54 }, { -53, -52 } +}; +//@} + + + + +/*! + \name parametric stereo + \brief constants used by the parametric stereo part of the decoder + +*/ + + +/* constants used in psbitdec.cpp */ + +/* FIX_BORDER can have 0, 1, 2, 4 envelopes */ +const UCHAR FDK_sbrDecoder_aFixNoEnvDecode[4] = {0, 1, 2, 4}; + + +/* IID & ICC Huffman codebooks */ +const SCHAR aBookPsIidTimeDecode[28][2] = { + { -64, 1 }, { -65, 2 }, { -63, 3 }, { -66, 4 }, + { -62, 5 }, { -67, 6 }, { -61, 7 }, { -68, 8 }, + { -60, 9 }, { -69, 10 }, { -59, 11 }, { -70, 12 }, + { -58, 13 }, { -57, 14 }, { -71, 15 }, { 16, 17 }, + { -56, -72 }, { 18, 21 }, { 19, 20 }, { -55, -78 }, + { -77, -76 }, { 22, 25 }, { 23, 24 }, { -75, -74 }, + { -73, -54 }, { 26, 27 }, { -53, -52 }, { -51, -50 } +}; + +const SCHAR aBookPsIidFreqDecode[28][2] = { + { -64, 1 }, { 2, 3 }, { -63, -65 }, { 4, 5 }, + { -62, -66 }, { 6, 7 }, { -61, -67 }, { 8, 9 }, + { -68, -60 }, { -59, 10 }, { -69, 11 }, { -58, 12 }, + { -70, 13 }, { -71, 14 }, { -57, 15 }, { 16, 17 }, + { -56, -72 }, { 18, 19 }, { -55, -54 }, { 20, 21 }, + { -73, -53 }, { 22, 24 }, { -74, 23 }, { -75, -78 }, + { 25, 26 }, { -77, -76 }, { -52, 27 }, { -51, -50 } +}; + +const SCHAR aBookPsIccTimeDecode[14][2] = { + { -64, 1 }, { -63, 2 }, { -65, 3 }, { -62, 4 }, + { -66, 5 }, { -61, 6 }, { -67, 7 }, { -60, 8 }, + { -68, 9 }, { -59, 10 }, { -69, 11 }, { -58, 12 }, + { -70, 13 }, { -71, -57 } +}; + +const SCHAR aBookPsIccFreqDecode[14][2] = { + { -64, 1 }, { -63, 2 }, { -65, 3 }, { -62, 4 }, + { -66, 5 }, { -61, 6 }, { -67, 7 }, { -60, 8 }, + { -59, 9 }, { -68, 10 }, { -58, 11 }, { -69, 12 }, + { -57, 13 }, { -70, -71 } +}; + +/* IID-fine Huffman codebooks */ + +const SCHAR aBookPsIidFineTimeDecode[60][2] = { + { 1, -64 }, { -63, 2 }, { 3, -65 }, { 4, 59 }, + { 5, 7 }, { 6, -67 }, { -68, -60 }, { -61, 8 }, + { 9, 11 }, { -59, 10 }, { -70, -58 }, { 12, 41 }, + { 13, 20 }, { 14, -71 }, { -55, 15 }, { -53, 16 }, + { 17, -77 }, { 18, 19 }, { -85, -84 }, { -46, -45 }, + { -57, 21 }, { 22, 40 }, { 23, 29 }, { -51, 24 }, + { 25, 26 }, { -83, -82 }, { 27, 28 }, { -90, -38 }, + { -92, -91 }, { 30, 37 }, { 31, 34 }, { 32, 33 }, + { -35, -34 }, { -37, -36 }, { 35, 36 }, { -94, -93 }, + { -89, -39 }, { 38, -79 }, { 39, -81 }, { -88, -40 }, + { -74, -54 }, { 42, -69 }, { 43, 44 }, { -72, -56 }, + { 45, 52 }, { 46, 50 }, { 47, -76 }, { -49, 48 }, + { -47, 49 }, { -87, -41 }, { -52, 51 }, { -78, -50 }, + { 53, -73 }, { 54, -75 }, { 55, 57 }, { 56, -80 }, + { -86, -42 }, { -48, 58 }, { -44, -43 }, { -66, -62 } +}; + + +const SCHAR aBookPsIidFineFreqDecode[60][2] = { + { 1, -64 }, { 2, 4 }, { 3, -65 }, { -66, -62 }, + { -63, 5 }, { 6, 7 }, { -67, -61 }, { 8, 9 }, + { -68, -60 }, { 10, 11 }, { -69, -59 }, { 12, 13 }, + { -70, -58 }, { 14, 18 }, { -57, 15 }, { 16, -72 }, + { -54, 17 }, { -75, -53 }, { 19, 37 }, { -56, 20 }, + { 21, -73 }, { 22, 29 }, { 23, -76 }, { 24, -78 }, + { 25, 28 }, { 26, 27 }, { -85, -43 }, { -83, -45 }, + { -81, -47 }, { -52, 30 }, { -50, 31 }, { 32, -79 }, + { 33, 34 }, { -82, -46 }, { 35, 36 }, { -90, -89 }, + { -92, -91 }, { 38, -71 }, { -55, 39 }, { 40, -74 }, + { 41, 50 }, { 42, -77 }, { -49, 43 }, { 44, 47 }, + { 45, 46 }, { -86, -42 }, { -88, -87 }, { 48, 49 }, + { -39, -38 }, { -41, -40 }, { -51, 51 }, { 52, 59 }, + { 53, 56 }, { 54, 55 }, { -35, -34 }, { -37, -36 }, + { 57, 58 }, { -94, -93 }, { -84, -44 }, { -80, -48 } +}; + +/* constants used in psdec.cpp */ + +const FIXP_DBL decayScaleFactTable[64] = { + + FL2FXCONST_DBL(1.000000), FL2FXCONST_DBL(1.000000), FL2FXCONST_DBL(1.000000), FL2FXCONST_DBL(1.000000), + FL2FXCONST_DBL(0.950000), FL2FXCONST_DBL(0.900000), FL2FXCONST_DBL(0.850000), FL2FXCONST_DBL(0.800000), + FL2FXCONST_DBL(0.750000), FL2FXCONST_DBL(0.700000), FL2FXCONST_DBL(0.650000), FL2FXCONST_DBL(0.600000), + FL2FXCONST_DBL(0.550000), FL2FXCONST_DBL(0.500000), FL2FXCONST_DBL(0.450000), FL2FXCONST_DBL(0.400000), + FL2FXCONST_DBL(0.350000), FL2FXCONST_DBL(0.300000), FL2FXCONST_DBL(0.250000), FL2FXCONST_DBL(0.200000), + FL2FXCONST_DBL(0.150000), FL2FXCONST_DBL(0.100000), FL2FXCONST_DBL(0.050000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), + FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000), FL2FXCONST_DBL(0.000000) }; + +/* the values of the following 3 tables are shiftet right by 1 ! */ +const FIXP_DBL ScaleFactors[NO_IID_LEVELS] = { + + 0x5a5ded00, 0x59cd0400, 0x58c29680, 0x564c2e80, 0x52a3d480, + 0x4c8be080, 0x46df3080, 0x40000000, 0x384ba5c0, 0x304c2980, + 0x24e9f640, 0x1b4a2940, 0x11b5c0a0, 0x0b4e2540, 0x0514ea90 +}; + +const FIXP_DBL ScaleFactorsFine[NO_IID_LEVELS_FINE] = { + + 0x5a825c00, 0x5a821c00, 0x5a815100, 0x5a7ed000, 0x5a76e600, + 0x5a5ded00, 0x5a39b880, 0x59f1fd00, 0x5964d680, 0x5852ca00, + 0x564c2e80, 0x54174480, 0x50ea7500, 0x4c8be080, 0x46df3080, + 0x40000000, 0x384ba5c0, 0x304c2980, 0x288dd240, 0x217a2900, + 0x1b4a2940, 0x13c5ece0, 0x0e2b0090, 0x0a178ef0, 0x072ab798, + 0x0514ea90, 0x02dc5944, 0x019bf87c, 0x00e7b173, 0x00824b8b, + 0x00494568 +}; +const FIXP_DBL Alphas[NO_ICC_LEVELS] = { + + 0x00000000, 0x0b6b5be0, 0x12485f80, 0x1da2fa40, + 0x2637ebc0, 0x3243f6c0, 0x466b7480, 0x6487ed80 +}; + +#if defined(ARCH_PREFER_MULT_32x16) +#define FIXP_PS FIXP_SGL +#define FXP_CAST(a) FX_DBL2FX_SGL((FIXP_DBL)a) +#define FL2FXCONST_PS FL2FXCONST_SGL +#else +#define FIXP_PS FIXP_DBL +#define FXP_CAST +#define FL2FXCONST_PS FL2FXCONST_DBL +#endif + +const FIXP_PS aAllpassLinkDecaySer[NO_SERIAL_ALLPASS_LINKS] = { +FXP_CAST(0x53625b00), FXP_CAST(0x4848af00), FXP_CAST(0x3ea94d00) }; + +const FIXP_PS aaFractDelayPhaseFactorReQmf[NO_QMF_CHANNELS] = { +FXP_CAST(0x68b92180), FXP_CAST(0xde396900), FXP_CAST(0x80650380), FXP_CAST(0xcb537e40), FXP_CAST(0x5beb8f00), FXP_CAST(0x72f29200), FXP_CAST(0xf1f43c50), FXP_CAST(0x83896280), +FXP_CAST(0xb9b99c00), FXP_CAST(0x4cda8f00), FXP_CAST(0x7a576e00), FXP_CAST(0x060799e0), FXP_CAST(0x89be5280), FXP_CAST(0xa9dab600), FXP_CAST(0x3be51b00), FXP_CAST(0x7eb91900), +FXP_CAST(0x19f4f540), FXP_CAST(0x92dcb380), FXP_CAST(0x9c1ad700), FXP_CAST(0x29761940), FXP_CAST(0x7ffbf500), FXP_CAST(0x2d3eb180), FXP_CAST(0x9eab0a00), FXP_CAST(0x90d0aa80), +FXP_CAST(0x1601bcc0), FXP_CAST(0x7e180e80), FXP_CAST(0x3f6b3940), FXP_CAST(0xacdeeb00), FXP_CAST(0x88435b00), FXP_CAST(0x0202a768), FXP_CAST(0x79194f80), FXP_CAST(0x5007fd00), +FXP_CAST(0xbd1ecf00), FXP_CAST(0x82a8d100), FXP_CAST(0xedf6e5e0), FXP_CAST(0x711f3500), FXP_CAST(0x5eac4480), FXP_CAST(0xcf0447c0), FXP_CAST(0x80245f80), FXP_CAST(0xda5cd4c0), +FXP_CAST(0x665c0800), FXP_CAST(0x6afbc500), FXP_CAST(0xe21e85e0), FXP_CAST(0x80c5e500), FXP_CAST(0xc7b003c0), FXP_CAST(0x59139f80), FXP_CAST(0x74a8e400), FXP_CAST(0xf5f51f40), +FXP_CAST(0x84896680), FXP_CAST(0xb6662b00), FXP_CAST(0x4999b600), FXP_CAST(0x7b76a300), FXP_CAST(0x0a0b0650), FXP_CAST(0x8b572b80), FXP_CAST(0xa6ec4580), FXP_CAST(0x384fda80), +FXP_CAST(0x7f3a1f00), FXP_CAST(0x1de19ec0), FXP_CAST(0x95045000), FXP_CAST(0x99a3e180), FXP_CAST(0x25a30740), FXP_CAST(0x7fdb9e80), FXP_CAST(0x30fbdb00), FXP_CAST(0xa153d500) }; + +const FIXP_PS aaFractDelayPhaseFactorImQmf[NO_QMF_CHANNELS] = { +FXP_CAST(0xb6663a80), FXP_CAST(0x84896200), FXP_CAST(0xf5f50c70), FXP_CAST(0x74a8dc80), FXP_CAST(0x5913ad00), FXP_CAST(0xc7b01480), FXP_CAST(0x80c5e300), FXP_CAST(0xe21e73a0), +FXP_CAST(0x6afbba80), FXP_CAST(0x665c1380), FXP_CAST(0xda5ce6c0), FXP_CAST(0x80246080), FXP_CAST(0xcf043640), FXP_CAST(0x5eac3800), FXP_CAST(0x711f3e00), FXP_CAST(0xedf6f8a0), +FXP_CAST(0x82a8d500), FXP_CAST(0xbd1ebe80), FXP_CAST(0x5007ee00), FXP_CAST(0x79195580), FXP_CAST(0x0202ba40), FXP_CAST(0x88436180), FXP_CAST(0xacdedc80), FXP_CAST(0x3f6b28c0), +FXP_CAST(0x7e181180), FXP_CAST(0x1601cf40), FXP_CAST(0x90d0b380), FXP_CAST(0x9eaafd80), FXP_CAST(0x2d3e9fc0), FXP_CAST(0x7ffbf580), FXP_CAST(0x29762b00), FXP_CAST(0x9c1ae280), +FXP_CAST(0x92dca980), FXP_CAST(0x19f4e2c0), FXP_CAST(0x7eb91680), FXP_CAST(0x3be52b80), FXP_CAST(0xa9dac400), FXP_CAST(0x89be4b80), FXP_CAST(0x06078710), FXP_CAST(0x7a576880), +FXP_CAST(0x4cda9e00), FXP_CAST(0xb9b9ac00), FXP_CAST(0x83895e00), FXP_CAST(0xf1f42990), FXP_CAST(0x72f28a00), FXP_CAST(0x5beb9c00), FXP_CAST(0xcb538f40), FXP_CAST(0x80650200), +FXP_CAST(0xde3956c0), FXP_CAST(0x68b91680), FXP_CAST(0x68b92c00), FXP_CAST(0xde397b40), FXP_CAST(0x80650500), FXP_CAST(0xcb536d00), FXP_CAST(0x5beb8180), FXP_CAST(0x72f29a80), +FXP_CAST(0xf1f44f10), FXP_CAST(0x83896700), FXP_CAST(0xb9b98c80), FXP_CAST(0x4cda8000), FXP_CAST(0x7a577380), FXP_CAST(0x0607acb8), FXP_CAST(0x89be5a00), FXP_CAST(0xa9daa800) }; + +const FIXP_PS aaFractDelayPhaseFactorReSubQmf20[NO_SUB_QMF_CHANNELS] = { +FXP_CAST(0x7e807380), FXP_CAST(0x72b9bb00), FXP_CAST(0x5c44ee80), FXP_CAST(0x3d3938c0), FXP_CAST(0x80000000), FXP_CAST(0x80000000), +FXP_CAST(0x72b9bb00), FXP_CAST(0x7e807380), FXP_CAST(0xba914700), FXP_CAST(0x050677b0), FXP_CAST(0x895cc380), FXP_CAST(0x834e4900) }; + +const FIXP_PS aaFractDelayPhaseFactorImSubQmf20[NO_SUB_QMF_CHANNELS] = { +FXP_CAST(0xec791720), FXP_CAST(0xc73ca080), FXP_CAST(0xa748ea00), FXP_CAST(0x8f976980), FXP_CAST(0x00000000), FXP_CAST(0x00000000), +FXP_CAST(0x38c35f80), FXP_CAST(0x1386e8e0), FXP_CAST(0x9477d000), FXP_CAST(0x80194380), FXP_CAST(0xcff26140), FXP_CAST(0x1ce70d40) }; + +const FIXP_PS aaFractDelayPhaseFactorSerReQmf[NO_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS] = { +{FXP_CAST(0x63e52480), FXP_CAST(0x30fbc540), FXP_CAST(0x6d73af00)}, {FXP_CAST(0xc7b01280), FXP_CAST(0x89be5100), FXP_CAST(0xf7c31cb0)}, {FXP_CAST(0x83896200), FXP_CAST(0x7641af00), FXP_CAST(0x8aee2700)}, +{FXP_CAST(0x0202b330), FXP_CAST(0xcf043ac0), FXP_CAST(0x9bfab500)}, {FXP_CAST(0x7d572c80), FXP_CAST(0xcf043ac0), FXP_CAST(0x1893b960)}, {FXP_CAST(0x34ac7fc0), FXP_CAST(0x7641af00), FXP_CAST(0x7abf7980)}, +{FXP_CAST(0x99a3ee00), FXP_CAST(0x89be5100), FXP_CAST(0x58eead80)}, {FXP_CAST(0x9eab0580), FXP_CAST(0x30fbc540), FXP_CAST(0xd77dae40)}, {FXP_CAST(0x3be52140), FXP_CAST(0x30fbc540), FXP_CAST(0x819b8500)}, +{FXP_CAST(0x7b769d80), FXP_CAST(0x89be5100), FXP_CAST(0xb3a12280)}, {FXP_CAST(0xf9f86878), FXP_CAST(0x7641af00), FXP_CAST(0x37c519c0)}, {FXP_CAST(0x81e7ef80), FXP_CAST(0xcf043ac0), FXP_CAST(0x7ff16880)}, +{FXP_CAST(0xcf043cc0), FXP_CAST(0xcf043ac0), FXP_CAST(0x3e8b2340)}, {FXP_CAST(0x68b92280), FXP_CAST(0x7641af00), FXP_CAST(0xb9e4a900)}, {FXP_CAST(0x5eac3980), FXP_CAST(0x89be5100), FXP_CAST(0x80a05200)}, +{FXP_CAST(0xc094cd00), FXP_CAST(0x30fbc540), FXP_CAST(0xd051dc80)}, {FXP_CAST(0x85a89400), FXP_CAST(0x30fbc540), FXP_CAST(0x53483b00)}, {FXP_CAST(0x0a0af5e0), FXP_CAST(0x89be5100), FXP_CAST(0x7cb1b680)}, +{FXP_CAST(0x7eb91900), FXP_CAST(0x7641af00), FXP_CAST(0x2006e8c0)}, {FXP_CAST(0x2d3ea680), FXP_CAST(0xcf043ac0), FXP_CAST(0xa0ec1c00)}, {FXP_CAST(0x95044180), FXP_CAST(0xcf043ac0), FXP_CAST(0x880d2180)}, +{FXP_CAST(0xa4147300), FXP_CAST(0x7641af00), FXP_CAST(0xf0282870)}, {FXP_CAST(0x42e13f80), FXP_CAST(0x89be5100), FXP_CAST(0x694c4a00)}, {FXP_CAST(0x79195200), FXP_CAST(0x30fbc540), FXP_CAST(0x71374780)}, +{FXP_CAST(0xf1f43550), FXP_CAST(0x30fbc540), FXP_CAST(0xff6593ea)}, {FXP_CAST(0x80c5e280), FXP_CAST(0x89be5100), FXP_CAST(0x8e39ec00)}, {FXP_CAST(0xd689e480), FXP_CAST(0x7641af00), FXP_CAST(0x97648100)}, +{FXP_CAST(0x6d235300), FXP_CAST(0xcf043ac0), FXP_CAST(0x110a20c0)}, {FXP_CAST(0x5913a800), FXP_CAST(0xcf043ac0), FXP_CAST(0x785d4f80)}, {FXP_CAST(0xb9b99a00), FXP_CAST(0x7641af00), FXP_CAST(0x5e440880)}, +{FXP_CAST(0x88436100), FXP_CAST(0x89be5100), FXP_CAST(0xdece7000)}, {FXP_CAST(0x12091320), FXP_CAST(0x30fbc540), FXP_CAST(0x8309f800)}, {FXP_CAST(0x7f9afd00), FXP_CAST(0x30fbc540), FXP_CAST(0xada33f00)}, +{FXP_CAST(0x25a31700), FXP_CAST(0x89be5100), FXP_CAST(0x30cc3600)}, {FXP_CAST(0x90d0ab80), FXP_CAST(0x7641af00), FXP_CAST(0x7f7cbe80)}, {FXP_CAST(0xa9dabf00), FXP_CAST(0xcf043ac0), FXP_CAST(0x45182580)}, +{FXP_CAST(0x4999cb80), FXP_CAST(0xcf043ac0), FXP_CAST(0xc0681c80)}, {FXP_CAST(0x7641ac80), FXP_CAST(0x7641af00), FXP_CAST(0x80194380)}, {FXP_CAST(0xe9fe3300), FXP_CAST(0x89be5100), FXP_CAST(0xc95184c0)}, +{FXP_CAST(0x80246000), FXP_CAST(0x30fbc540), FXP_CAST(0x4d55d800)}, {FXP_CAST(0xde396fc0), FXP_CAST(0x30fbc540), FXP_CAST(0x7e324000)}, {FXP_CAST(0x711f3f00), FXP_CAST(0x89be5100), FXP_CAST(0x275ce480)}, +{FXP_CAST(0x53211700), FXP_CAST(0x7641af00), FXP_CAST(0xa6343580)}, {FXP_CAST(0xb3256780), FXP_CAST(0xcf043ac0), FXP_CAST(0x85997b80)}, {FXP_CAST(0x8b572680), FXP_CAST(0xcf043ac0), FXP_CAST(0xe89ba660)}, +{FXP_CAST(0x19f4f780), FXP_CAST(0x7641af00), FXP_CAST(0x64c4e100)}, {FXP_CAST(0x7ffbf580), FXP_CAST(0x89be5100), FXP_CAST(0x7493a380)}, {FXP_CAST(0x1de18100), FXP_CAST(0x30fbc540), FXP_CAST(0x070897f0)}, +{FXP_CAST(0x8d0d6a80), FXP_CAST(0x30fbc540), FXP_CAST(0x91ed6f00)}, {FXP_CAST(0xaff81380), FXP_CAST(0x89be5100), FXP_CAST(0x932db000)}, {FXP_CAST(0x5007fb00), FXP_CAST(0x7641af00), FXP_CAST(0x0970feb0)}, +{FXP_CAST(0x72f28d00), FXP_CAST(0xcf043ac0), FXP_CAST(0x758d6500)}, {FXP_CAST(0xe21e6cc0), FXP_CAST(0xcf043ac0), FXP_CAST(0x63436f80)}, {FXP_CAST(0x80040b00), FXP_CAST(0x7641af00), FXP_CAST(0xe63d7600)}, +{FXP_CAST(0xe60b1ae0), FXP_CAST(0x89be5100), FXP_CAST(0x84ea5c80)}, {FXP_CAST(0x74a8e100), FXP_CAST(0x30fbc540), FXP_CAST(0xa7f07500)}, {FXP_CAST(0x4cda8980), FXP_CAST(0x30fbc540), FXP_CAST(0x29a6d340)}, +{FXP_CAST(0xacdeda80), FXP_CAST(0x89be5100), FXP_CAST(0x7e93d600)}, {FXP_CAST(0x8ee0c980), FXP_CAST(0x7641af00), FXP_CAST(0x4b662680)}, {FXP_CAST(0x21c6a280), FXP_CAST(0xcf043ac0), FXP_CAST(0xc7258c80)}, +{FXP_CAST(0x7fdb9f00), FXP_CAST(0xcf043ac0), FXP_CAST(0x8006d500)}, {FXP_CAST(0x1601ba60), FXP_CAST(0x7641af00), FXP_CAST(0xc2830940)}, {FXP_CAST(0x89be4c80), FXP_CAST(0x89be5100), FXP_CAST(0x471cf100)}, +{FXP_CAST(0xb6664400), FXP_CAST(0x30fbc540), FXP_CAST(0x7f3fb800)}}; + +const FIXP_PS aaFractDelayPhaseFactorSerImQmf[NO_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS] = { +{FXP_CAST(0xaff80c80), FXP_CAST(0x89be5100), FXP_CAST(0xbda29e00)}, {FXP_CAST(0x8d0d6f00), FXP_CAST(0x30fbc540), FXP_CAST(0x8043ee80)}, {FXP_CAST(0x1de18a20), FXP_CAST(0x30fbc540), FXP_CAST(0xcc3e7840)}, +{FXP_CAST(0x7ffbf500), FXP_CAST(0x89be5100), FXP_CAST(0x4fdfc180)}, {FXP_CAST(0x19f4ee40), FXP_CAST(0x7641af00), FXP_CAST(0x7d9e4c00)}, {FXP_CAST(0x8b572300), FXP_CAST(0xcf043ac0), FXP_CAST(0x244a2940)}, +{FXP_CAST(0xb3256f00), FXP_CAST(0xcf043ac0), FXP_CAST(0xa3f0a500)}, {FXP_CAST(0x53211e00), FXP_CAST(0x7641af00), FXP_CAST(0x86944500)}, {FXP_CAST(0x711f3a80), FXP_CAST(0x89be5100), FXP_CAST(0xebc72040)}, +{FXP_CAST(0xde3966c0), FXP_CAST(0x30fbc540), FXP_CAST(0x66b87e00)}, {FXP_CAST(0x80246080), FXP_CAST(0x30fbc540), FXP_CAST(0x73362c00)}, {FXP_CAST(0xe9fe3c40), FXP_CAST(0x89be5100), FXP_CAST(0x03d1d110)}, +{FXP_CAST(0x7641b000), FXP_CAST(0x7641af00), FXP_CAST(0x90520c80)}, {FXP_CAST(0x4999c380), FXP_CAST(0xcf043ac0), FXP_CAST(0x94e80a80)}, {FXP_CAST(0xa9dab800), FXP_CAST(0xcf043ac0), FXP_CAST(0x0ca570e0)}, +{FXP_CAST(0x90d0b000), FXP_CAST(0x7641af00), FXP_CAST(0x76c9bc80)}, {FXP_CAST(0x25a32000), FXP_CAST(0x89be5100), FXP_CAST(0x61338500)}, {FXP_CAST(0x7f9afc80), FXP_CAST(0x30fbc540), FXP_CAST(0xe318f060)}, +{FXP_CAST(0x120909c0), FXP_CAST(0x30fbc540), FXP_CAST(0x84124e00)}, {FXP_CAST(0x88435d80), FXP_CAST(0x89be5100), FXP_CAST(0xaa4d2f80)}, {FXP_CAST(0xb9b9a200), FXP_CAST(0x7641af00), FXP_CAST(0x2cae1800)}, +{FXP_CAST(0x5913ae80), FXP_CAST(0xcf043ac0), FXP_CAST(0x7f040680)}, {FXP_CAST(0x6d234e00), FXP_CAST(0xcf043ac0), FXP_CAST(0x48c6a100)}, {FXP_CAST(0xd689db80), FXP_CAST(0x7641af00), FXP_CAST(0xc44860c0)}, +{FXP_CAST(0x80c5e380), FXP_CAST(0x89be5100), FXP_CAST(0x80005d00)}, {FXP_CAST(0xf1f43eb0), FXP_CAST(0x30fbc540), FXP_CAST(0xc55a3a00)}, {FXP_CAST(0x79195500), FXP_CAST(0x30fbc540), FXP_CAST(0x49c3de00)}, +{FXP_CAST(0x42e13700), FXP_CAST(0x89be5100), FXP_CAST(0x7edc5b00)}, {FXP_CAST(0xa4146c80), FXP_CAST(0x7641af00), FXP_CAST(0x2b8c2c00)}, {FXP_CAST(0x95044680), FXP_CAST(0xcf043ac0), FXP_CAST(0xa968c100)}, +{FXP_CAST(0x2d3eaf40), FXP_CAST(0xcf043ac0), FXP_CAST(0x8460fd80)}, {FXP_CAST(0x7eb91780), FXP_CAST(0x7641af00), FXP_CAST(0xe44621e0)}, {FXP_CAST(0x0a0aec80), FXP_CAST(0x89be5100), FXP_CAST(0x61fb5c00)}, +{FXP_CAST(0x85a89100), FXP_CAST(0x30fbc540), FXP_CAST(0x76555780)}, {FXP_CAST(0xc094d500), FXP_CAST(0x30fbc540), FXP_CAST(0x0b71f790)}, {FXP_CAST(0x5eac4000), FXP_CAST(0x89be5100), FXP_CAST(0x94401a80)}, +{FXP_CAST(0x68b91d80), FXP_CAST(0x7641af00), FXP_CAST(0x90ea3980)}, {FXP_CAST(0xcf043440), FXP_CAST(0xcf043ac0), FXP_CAST(0x05067a08)}, {FXP_CAST(0x81e7f180), FXP_CAST(0xcf043ac0), FXP_CAST(0x73bb6d00)}, +{FXP_CAST(0xf9f871e0), FXP_CAST(0x7641af00), FXP_CAST(0x65ff0e00)}, {FXP_CAST(0x7b76a000), FXP_CAST(0x89be5100), FXP_CAST(0xea9664c0)}, {FXP_CAST(0x3be518c0), FXP_CAST(0x30fbc540), FXP_CAST(0x8633e880)}, +{FXP_CAST(0x9eaaff00), FXP_CAST(0x30fbc540), FXP_CAST(0xa4c84500)}, {FXP_CAST(0x99a3f400), FXP_CAST(0x89be5100), FXP_CAST(0x2571eac0)}, {FXP_CAST(0x34ac8840), FXP_CAST(0x7641af00), FXP_CAST(0x7dd82b00)}, +{FXP_CAST(0x7d572a80), FXP_CAST(0xcf043ac0), FXP_CAST(0x4eed8400)}, {FXP_CAST(0x0202a9c4), FXP_CAST(0xcf043ac0), FXP_CAST(0xcb249700)}, {FXP_CAST(0x83896000), FXP_CAST(0x7641af00), FXP_CAST(0x80318200)}, +{FXP_CAST(0xc7b01b00), FXP_CAST(0x89be5100), FXP_CAST(0xbeab7580)}, {FXP_CAST(0x63e52a80), FXP_CAST(0x30fbc540), FXP_CAST(0x4364b700)}, {FXP_CAST(0x63e51f00), FXP_CAST(0x30fbc540), FXP_CAST(0x7fa6bd00)}, +{FXP_CAST(0xc7b00a00), FXP_CAST(0x89be5100), FXP_CAST(0x32a67940)}, {FXP_CAST(0x83896400), FXP_CAST(0x7641af00), FXP_CAST(0xaf2fd200)}, {FXP_CAST(0x0202bc9c), FXP_CAST(0xcf043ac0), FXP_CAST(0x829e6e80)}, +{FXP_CAST(0x7d572e80), FXP_CAST(0xcf043ac0), FXP_CAST(0xdcde6b80)}, {FXP_CAST(0x34ac7700), FXP_CAST(0x7641af00), FXP_CAST(0x5ce4e280)}, {FXP_CAST(0x99a3e880), FXP_CAST(0x89be5100), FXP_CAST(0x79089c00)}, +{FXP_CAST(0x9eab0b80), FXP_CAST(0x30fbc540), FXP_CAST(0x1307ae80)}, {FXP_CAST(0x3be52980), FXP_CAST(0x30fbc540), FXP_CAST(0x98906880)}, {FXP_CAST(0x7b769b00), FXP_CAST(0x89be5100), FXP_CAST(0x8d51b300)}, +{FXP_CAST(0xf9f85f10), FXP_CAST(0x7641af00), FXP_CAST(0xfd62ee24)}, {FXP_CAST(0x81e7ee00), FXP_CAST(0xcf043ac0), FXP_CAST(0x70439680)}, {FXP_CAST(0xcf044580), FXP_CAST(0xcf043ac0), FXP_CAST(0x6a6d9600)}, +{FXP_CAST(0x68b92800), FXP_CAST(0x7641af00), FXP_CAST(0xf2275f80)}}; + +const FIXP_PS aaFractDelayPhaseFactorSerReSubQmf20[NO_SUB_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS] = { +{FXP_CAST(0x7e2df000), FXP_CAST(0x7a7d0580), FXP_CAST(0x7ed03e00)}, {FXP_CAST(0x6fec9a80), FXP_CAST(0x5133cc80), FXP_CAST(0x7573df00)}, {FXP_CAST(0x55063900), FXP_CAST(0x0c8bd360), FXP_CAST(0x636c0400)}, +{FXP_CAST(0x3084ca00), FXP_CAST(0xc3a94580), FXP_CAST(0x4a0d6700)}, {FXP_CAST(0x80000000), FXP_CAST(0x80000000), FXP_CAST(0x80000000)}, {FXP_CAST(0x80000000), FXP_CAST(0x80000000), FXP_CAST(0x80000000)}, +{FXP_CAST(0x6fec9a80), FXP_CAST(0x5133cc80), FXP_CAST(0x7573df00)}, {FXP_CAST(0x7e2df000), FXP_CAST(0x7a7d0580), FXP_CAST(0x7ed03e00)}, {FXP_CAST(0xa4c84280), FXP_CAST(0xb8e31300), FXP_CAST(0xd5af0140)}, +{FXP_CAST(0xf0f488a0), FXP_CAST(0x8275a100), FXP_CAST(0x1a72e360)}, {FXP_CAST(0x80aaa680), FXP_CAST(0x471ced00), FXP_CAST(0x9d2ead80)}, {FXP_CAST(0x9477d100), FXP_CAST(0x7d8a5f00), FXP_CAST(0x8151df80)}}; + +const FIXP_PS aaFractDelayPhaseFactorSerImSubQmf20[NO_SUB_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS] = { +{FXP_CAST(0xea7d08a0), FXP_CAST(0xdad7f3c0), FXP_CAST(0xee9c9f60)}, {FXP_CAST(0xc1e54140), FXP_CAST(0x9d0dfe80), FXP_CAST(0xcd1e7300)}, {FXP_CAST(0xa051a580), FXP_CAST(0x809dc980), FXP_CAST(0xaf61c400)}, +{FXP_CAST(0x898d4e00), FXP_CAST(0x8f1d3400), FXP_CAST(0x97988280)}, {FXP_CAST(0x00000000), FXP_CAST(0x00000000), FXP_CAST(0x00000000)}, {FXP_CAST(0x00000000), FXP_CAST(0x00000000), FXP_CAST(0x00000000)}, +{FXP_CAST(0x3e1abec0), FXP_CAST(0x62f20180), FXP_CAST(0x32e18d00)}, {FXP_CAST(0x1582f760), FXP_CAST(0x25280c40), FXP_CAST(0x116360a0)}, {FXP_CAST(0xa6343800), FXP_CAST(0x6a6d9880), FXP_CAST(0x87327a00)}, +{FXP_CAST(0x80e32200), FXP_CAST(0xe70747c0), FXP_CAST(0x82c32b00)}, {FXP_CAST(0xf2f42420), FXP_CAST(0x6a6d9880), FXP_CAST(0xaea47080)}, {FXP_CAST(0x456eba00), FXP_CAST(0xe70747c0), FXP_CAST(0xedaa8640)}}; + +const FIXP_PS p8_13_20[13] = +{ + FL2FXCONST_PS(0.00746082949812f), FL2FXCONST_PS(0.02270420949825f), FL2FXCONST_PS(0.04546865930473f), FL2FXCONST_PS(0.07266113929591f), + FL2FXCONST_PS(0.09885108575264f), FL2FXCONST_PS(0.11793710567217f), FL2FXCONST_PS(0.125f ), FL2FXCONST_PS(0.11793710567217f), + FL2FXCONST_PS(0.09885108575264f), FL2FXCONST_PS(0.07266113929591f), FL2FXCONST_PS(0.04546865930473f), FL2FXCONST_PS(0.02270420949825f), + FL2FXCONST_PS(0.00746082949812f) +}; + +const FIXP_PS p2_13_20[13] = +{ + FL2FXCONST_PS(0.0f), FL2FXCONST_PS( 0.01899487526049f), FL2FXCONST_PS(0.0f), FL2FXCONST_PS(-0.07293139167538f), + FL2FXCONST_PS(0.0f), FL2FXCONST_PS( 0.30596630545168f), FL2FXCONST_PS(0.5f), FL2FXCONST_PS( 0.30596630545168f), + FL2FXCONST_PS(0.0f), FL2FXCONST_PS(-0.07293139167538f), FL2FXCONST_PS(0.0f), FL2FXCONST_PS( 0.01899487526049f), + FL2FXCONST_PS(0.0f) +}; + + + +const UCHAR aAllpassLinkDelaySer[] = { 3, 4, 5}; + +const UCHAR delayIndexQmf[NO_QMF_CHANNELS] = { + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 +}; + +const UCHAR groupBorders20[NO_IID_GROUPS + 1] = +{ + 6, 7, 0, 1, 2, 3, /* 6 subqmf subbands - 0th qmf subband */ + 9, 8, /* 2 subqmf subbands - 1st qmf subband */ + 10, 11, /* 2 subqmf subbands - 2nd qmf subband */ + 3, 4, 5, 6, 7, 8, + 9, 11, 14, 18, 23, 35, 64 +}; + +const UCHAR groupBorders34[NO_IID_GROUPS_HI_RES + 1] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, /* 12 subqmf subbands - 0th qmf subband */ + 12, 13, 14, 15, 16, 17, 18, 19, /* 8 subqmf subbands - 1st qmf subband */ + 20, 21, 22, 23, /* 4 subqmf subbands - 2nd qmf subband */ + 24, 25, 26, 27, /* 4 subqmf subbands - 3nd qmf subband */ + 28, 29, 30, 31, /* 4 subqmf subbands - 4nd qmf subband */ + 32-27, 33-27, 34-27, 35-27, 36-27, 37-27, 38-27, + 40-27, 42-27, 44-27, 46-27, 48-27, 51-27, 54-27, + 57-27, 60-27, 64-27, 68-27, 91-27 +}; + +const UCHAR bins2groupMap20[NO_IID_GROUPS] = +{ + 1, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 +}; + +const UCHAR quantizedIIDs[NO_IID_STEPS] = +{ + 2, 4, 7, 10, 14, 18, 25 +}; +const UCHAR quantizedIIDsFine[NO_IID_STEPS_FINE] = +{ + 2, 4, 6, 8, 10, 13, 16, 19, 22, 25, 30, 35, 40, 45, 50 +}; + +const UCHAR FDK_sbrDecoder_aNoIidBins[3] = {NO_LOW_RES_IID_BINS, + NO_MID_RES_IID_BINS, + NO_HI_RES_IID_BINS}; + +const UCHAR FDK_sbrDecoder_aNoIccBins[3] = {NO_LOW_RES_ICC_BINS, + NO_MID_RES_ICC_BINS, + NO_HI_RES_ICC_BINS}; + + + +/************************************************************************/ +/*! + \brief Create lookup tables for some arithmetic functions + + The tables would normally be defined as const arrays, + but initialization at run time allows to specify their accuracy. +*/ +/************************************************************************/ + +/* 1/x-table: (example for INV_TABLE_BITS 8) + + The table covers an input range from 0.5 to 1.0 with a step size of 1/512, + starting at 0.5 + 1/512. + Each table entry corresponds to an input interval starting 1/1024 below the + exact value and ending 1/1024 above it. + + The table is actually a 0.5/x-table, so that the output range is again + 0.5...1.0 and the exponent of the result must be increased by 1. + + Input range Index in table result + ------------------------------------------------------------------- + 0.500000...0.500976 - 0.5 / 0.500000 = 1.000000 + 0.500976...0.502930 0 0.5 / 0.501953 = 0.996109 + 0.502930...0.500488 1 0.5 / 0.503906 = 0.992248 + ... + 0.999023...1.000000 255 0.5 / 1.000000 = 0.500000 + + for (i=0; i<INV_TABLE_SIZE; i++) { + d = 0.5f / ( 0.5f+(double)(i+1)/(INV_TABLE_SIZE*2) ) ; + invTable[i] = FL2FX_SGL(d); + } +*/ +const FIXP_SGL FDK_sbrDecoder_invTable[INV_TABLE_SIZE] = +{ + 0x7f80, 0x7f01, 0x7e83, 0x7e07, 0x7d8b, 0x7d11, 0x7c97, 0x7c1e, + 0x7ba6, 0x7b2f, 0x7ab9, 0x7a44, 0x79cf, 0x795c, 0x78e9, 0x7878, + 0x7807, 0x7796, 0x7727, 0x76b9, 0x764b, 0x75de, 0x7572, 0x7506, + 0x749c, 0x7432, 0x73c9, 0x7360, 0x72f9, 0x7292, 0x722c, 0x71c6, + 0x7161, 0x70fd, 0x709a, 0x7037, 0x6fd5, 0x6f74, 0x6f13, 0x6eb3, + 0x6e54, 0x6df5, 0x6d97, 0x6d39, 0x6cdc, 0x6c80, 0x6c24, 0x6bc9, + 0x6b6f, 0x6b15, 0x6abc, 0x6a63, 0x6a0b, 0x69b3, 0x695c, 0x6906, + 0x68b0, 0x685a, 0x6806, 0x67b1, 0x675e, 0x670a, 0x66b8, 0x6666, + 0x6614, 0x65c3, 0x6572, 0x6522, 0x64d2, 0x6483, 0x6434, 0x63e6, + 0x6399, 0x634b, 0x62fe, 0x62b2, 0x6266, 0x621b, 0x61d0, 0x6185, + 0x613b, 0x60f2, 0x60a8, 0x6060, 0x6017, 0x5fcf, 0x5f88, 0x5f41, + 0x5efa, 0x5eb4, 0x5e6e, 0x5e28, 0x5de3, 0x5d9f, 0x5d5a, 0x5d17, + 0x5cd3, 0x5c90, 0x5c4d, 0x5c0b, 0x5bc9, 0x5b87, 0x5b46, 0x5b05, + 0x5ac4, 0x5a84, 0x5a44, 0x5a05, 0x59c6, 0x5987, 0x5949, 0x590a, + 0x58cd, 0x588f, 0x5852, 0x5815, 0x57d9, 0x579d, 0x5761, 0x5725, + 0x56ea, 0x56af, 0x5675, 0x563b, 0x5601, 0x55c7, 0x558e, 0x5555, + 0x551c, 0x54e3, 0x54ab, 0x5473, 0x543c, 0x5405, 0x53ce, 0x5397, + 0x5360, 0x532a, 0x52f4, 0x52bf, 0x5289, 0x5254, 0x521f, 0x51eb, + 0x51b7, 0x5183, 0x514f, 0x511b, 0x50e8, 0x50b5, 0x5082, 0x5050, + 0x501d, 0x4feb, 0x4fba, 0x4f88, 0x4f57, 0x4f26, 0x4ef5, 0x4ec4, + 0x4e94, 0x4e64, 0x4e34, 0x4e04, 0x4dd5, 0x4da6, 0x4d77, 0x4d48, + 0x4d19, 0x4ceb, 0x4cbd, 0x4c8f, 0x4c61, 0x4c34, 0x4c07, 0x4bd9, + 0x4bad, 0x4b80, 0x4b54, 0x4b27, 0x4afb, 0x4acf, 0x4aa4, 0x4a78, + 0x4a4d, 0x4a22, 0x49f7, 0x49cd, 0x49a2, 0x4978, 0x494e, 0x4924, + 0x48fa, 0x48d1, 0x48a7, 0x487e, 0x4855, 0x482d, 0x4804, 0x47dc, + 0x47b3, 0x478b, 0x4763, 0x473c, 0x4714, 0x46ed, 0x46c5, 0x469e, + 0x4677, 0x4651, 0x462a, 0x4604, 0x45de, 0x45b8, 0x4592, 0x456c, + 0x4546, 0x4521, 0x44fc, 0x44d7, 0x44b2, 0x448d, 0x4468, 0x4444, + 0x441f, 0x43fb, 0x43d7, 0x43b3, 0x4390, 0x436c, 0x4349, 0x4325, + 0x4302, 0x42df, 0x42bc, 0x4299, 0x4277, 0x4254, 0x4232, 0x4210, + 0x41ee, 0x41cc, 0x41aa, 0x4189, 0x4167, 0x4146, 0x4125, 0x4104, + 0x40e3, 0x40c2, 0x40a1, 0x4081, 0x4060, 0x4040, 0x4020, 0x4000 +}; + diff --git a/libSBRdec/src/sbr_rom.h b/libSBRdec/src/sbr_rom.h new file mode 100644 index 0000000..62fc8b8 --- /dev/null +++ b/libSBRdec/src/sbr_rom.h @@ -0,0 +1,174 @@ +/**************************************************************************** + + (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 Declaration of constant tables +$Revision: 36841 $ +*/ +#ifndef __rom_H +#define __rom_H + +#include "sbrdecoder.h" +#include "env_extr.h" +#include "qmf.h" + +#define INV_INT_TABLE_SIZE 49 +#define SBR_NF_NO_RANDOM_VAL 512 /*!< Size of random number array for noise floor */ + +/* + Frequency scales +*/ +extern const UCHAR FDK_sbrDecoder_sbr_start_freq_16[16]; +extern const UCHAR FDK_sbrDecoder_sbr_start_freq_22[16]; +extern const UCHAR FDK_sbrDecoder_sbr_start_freq_24[16]; +extern const UCHAR FDK_sbrDecoder_sbr_start_freq_32[16]; +extern const UCHAR FDK_sbrDecoder_sbr_start_freq_40[16]; +extern const UCHAR FDK_sbrDecoder_sbr_start_freq_44[16]; +extern const UCHAR FDK_sbrDecoder_sbr_start_freq_48[16]; + +/* + Low-Power-Profile Transposer +*/ +#define NUM_WHFACTOR_TABLE_ENTRIES 9 +extern const USHORT FDK_sbrDecoder_sbr_whFactorsIndex[NUM_WHFACTOR_TABLE_ENTRIES]; +extern const FIXP_DBL FDK_sbrDecoder_sbr_whFactorsTable[NUM_WHFACTOR_TABLE_ENTRIES][6]; + + + +/* + Envelope Adjustor +*/ +extern const FIXP_SGL FDK_sbrDecoder_sbr_limGains_m[4]; +extern const UCHAR FDK_sbrDecoder_sbr_limGains_e[4]; +extern const FIXP_SGL FDK_sbrDecoder_sbr_limiterBandsPerOctaveDiv4[4]; +extern const FIXP_SGL FDK_sbrDecoder_sbr_smoothFilter[4]; +extern const FIXP_SGL FDK_sbrDecoder_sbr_randomPhase[SBR_NF_NO_RANDOM_VAL][2]; +extern const FIXP_SGL harmonicPhaseX [2][4]; + +/* + Envelope Extractor +*/ +extern const int FDK_sbrDecoder_envelopeTable_8 [8][5]; +extern const int FDK_sbrDecoder_envelopeTable_15 [15][6]; +extern const int FDK_sbrDecoder_envelopeTable_16 [16][6]; + +extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info1_15; +extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info2_15; +extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info4_15; +extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info8_15; + +extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info1_16; +extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info2_16; +extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info4_16; +extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info8_16; + +extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel10T[120][2]; +extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel10F[120][2]; +extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance10T[48][2]; +extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance10F[48][2]; +extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel11T[62][2]; +extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel11F[62][2]; +extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance11T[24][2]; +extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance11F[24][2]; +extern const SCHAR FDK_sbrDecoder_sbr_huffBook_NoiseLevel11T[62][2]; +extern const SCHAR FDK_sbrDecoder_sbr_huffBook_NoiseBalance11T[24][2]; + + +/* + Parametric stereo +*/ + + +extern const FIXP_DBL decayScaleFactTable[NO_QMF_CHANNELS]; + +/* FIX_BORDER can have 0, 1, 2, 4 envelops */ +extern const UCHAR FDK_sbrDecoder_aFixNoEnvDecode[4]; + +/* IID & ICC Huffman codebooks */ +extern const SCHAR aBookPsIidTimeDecode[28][2]; +extern const SCHAR aBookPsIidFreqDecode[28][2]; +extern const SCHAR aBookPsIccTimeDecode[14][2]; +extern const SCHAR aBookPsIccFreqDecode[14][2]; + +/* IID-fine Huffman codebooks */ + +extern const SCHAR aBookPsIidFineTimeDecode[60][2]; +extern const SCHAR aBookPsIidFineFreqDecode[60][2]; + +/* the values of the following 3 tables are shiftet right by 1 ! */ +extern const FIXP_DBL ScaleFactors[NO_IID_LEVELS]; +extern const FIXP_DBL ScaleFactorsFine[NO_IID_LEVELS_FINE]; +extern const FIXP_DBL Alphas[NO_ICC_LEVELS]; + +#if defined(ARCH_PREFER_MULT_32x16) +extern const FIXP_SGL aAllpassLinkDecaySer[NO_SERIAL_ALLPASS_LINKS]; +extern const FIXP_SGL aaFractDelayPhaseFactorReQmf[NO_QMF_CHANNELS]; +extern const FIXP_SGL aaFractDelayPhaseFactorImQmf[NO_QMF_CHANNELS]; +extern const FIXP_SGL aaFractDelayPhaseFactorReSubQmf20[NO_SUB_QMF_CHANNELS]; +extern const FIXP_SGL aaFractDelayPhaseFactorImSubQmf20[NO_SUB_QMF_CHANNELS]; + +extern const FIXP_SGL aaFractDelayPhaseFactorSerReQmf[NO_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS]; +extern const FIXP_SGL aaFractDelayPhaseFactorSerImQmf[NO_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS]; +extern const FIXP_SGL aaFractDelayPhaseFactorSerReSubQmf20[NO_SUB_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS]; +extern const FIXP_SGL aaFractDelayPhaseFactorSerImSubQmf20[NO_SUB_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS]; + +extern const FIXP_SGL p8_13_20[13]; +extern const FIXP_SGL p2_13_20[13]; + +#else +extern const FIXP_DBL aAllpassLinkDecaySer[NO_SERIAL_ALLPASS_LINKS]; +extern const FIXP_DBL aaFractDelayPhaseFactorReQmf[NO_QMF_CHANNELS]; +extern const FIXP_DBL aaFractDelayPhaseFactorImQmf[NO_QMF_CHANNELS]; +extern const FIXP_DBL aaFractDelayPhaseFactorReSubQmf20[NO_SUB_QMF_CHANNELS]; +extern const FIXP_DBL aaFractDelayPhaseFactorImSubQmf20[NO_SUB_QMF_CHANNELS]; + +extern const FIXP_DBL aaFractDelayPhaseFactorSerReQmf[NO_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS]; +extern const FIXP_DBL aaFractDelayPhaseFactorSerImQmf[NO_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS]; +extern const FIXP_DBL aaFractDelayPhaseFactorSerReSubQmf20[NO_SUB_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS]; +extern const FIXP_DBL aaFractDelayPhaseFactorSerImSubQmf20[NO_SUB_QMF_CHANNELS][NO_SERIAL_ALLPASS_LINKS]; + +extern const FIXP_DBL p8_13_20[13]; +extern const FIXP_DBL p2_13_20[13]; +#endif + +extern const UCHAR aAllpassLinkDelaySer[3]; +extern const UCHAR delayIndexQmf[NO_QMF_CHANNELS]; +extern const UCHAR groupBorders20[NO_IID_GROUPS + 1]; +extern const UCHAR groupBorders34[NO_IID_GROUPS_HI_RES + 1]; +extern const UCHAR bins2groupMap20[NO_IID_GROUPS]; +extern const UCHAR quantizedIIDs[NO_IID_STEPS]; +extern const UCHAR quantizedIIDsFine[NO_IID_STEPS_FINE]; +extern const UCHAR FDK_sbrDecoder_aNoIidBins[3]; +extern const UCHAR FDK_sbrDecoder_aNoIccBins[3]; + + +/* Lookup tables for some arithmetic functions */ + +#define INV_TABLE_BITS 8 +#define INV_TABLE_SIZE (1<<INV_TABLE_BITS) +extern const FIXP_SGL FDK_sbrDecoder_invTable[INV_TABLE_SIZE]; + +#endif // __rom_H diff --git a/libSBRdec/src/sbr_scale.h b/libSBRdec/src/sbr_scale.h new file mode 100644 index 0000000..b1614cb --- /dev/null +++ b/libSBRdec/src/sbr_scale.h @@ -0,0 +1,65 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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 Sbr scaling factors, $Revision: 36841 $ +To deal with the dynamic range in the different processing stages, a +fixed point specific code has to rely on scaling factors. A floating +point code carries a scaling factor -- the exponent -- for each value, +so scaling is not necessary there. + +The output of the core decoder (low band) is scaled up to cover as much +as possible bits for each value. As high band and low band are processed +in different algorithm sections, they require their own scaling +factors. In addition, any static buffers, e.g. filter states, require a +separate scaling factor as well. The code takes care to do the proper +adjustment, if scaling factors of a filter state and the time signal differ. + +\sa #QMF_SCALE_FACTOR, \ref documentationOverview +*/ + +#ifndef __SBR_SCALE_H +#define __SBR_SCALE_H + +/*! +\verbatim + scale: + 0 left aligned e.g. |max| >=0.5 + FRACT_BITS-1 zero e.g |max| = 0 +\endverbatim + + Dynamic scaling is used to achieve sufficient accuracy even when the signal + energy is low. The dynamic framing of SBR produces a variable overlap area + where samples from the previous QMF-Analysis are stored. Depending on the + start position and stop position of the current SBR envelopes, the processing + buffer consists of differently scaled regions like illustrated in the below + figure. + + \image html scales.png Scale +*/ + + +#endif diff --git a/libSBRdec/src/sbrdec_drc.cpp b/libSBRdec/src/sbrdec_drc.cpp new file mode 100644 index 0000000..a07f8fe --- /dev/null +++ b/libSBRdec/src/sbrdec_drc.cpp @@ -0,0 +1,450 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (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. + + + $Id$ + Author(s): Christian Griebel + Description: Dynamic range control (DRC) decoder tool for SBR + + 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. + +******************************************************************************/ + +#include "sbrdec_drc.h" + + +/* DRC - Offset table for QMF interpolation. */ +static const int offsetTab[2][16] = +{ + { 0, 4, 8, 12, 16, 20, 24, 28, 0, 0, 0, 0, 0, 0, 0, 0 }, /* 1024 framing */ + { 0, 4, 8, 12, 16, 19, 22, 26, 0, 0, 0, 0, 0, 0, 0, 0 } /* 960 framing */ +}; + +/*! + \brief Initialize DRC QMF factors + + \hDrcData Handle to DRC channel data. + + \return none +*/ +void sbrDecoder_drcInitChannel ( + HANDLE_SBR_DRC_CHANNEL hDrcData ) +{ + int band; + + if (hDrcData == NULL) { + return; + } + + for (band = 0; band < (64); band++) { + hDrcData->prevFact_mag[band] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + } + + for (band = 0; band < SBRDEC_MAX_DRC_BANDS; band++) { + hDrcData->currFact_mag[band] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + hDrcData->nextFact_mag[band] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + } + + hDrcData->prevFact_exp = 0; + hDrcData->currFact_exp = 0; + hDrcData->nextFact_exp = 0; + + hDrcData->numBandsCurr = 0; + hDrcData->numBandsNext = 0; + + hDrcData->winSequenceCurr = 0; + hDrcData->winSequenceNext = 0; + + hDrcData->drcInterpolationSchemeCurr = 0; + hDrcData->drcInterpolationSchemeNext = 0; + + hDrcData->enable = 0; +} + + +/*! + \brief Swap DRC QMF scaling factors after they have been applied. + + \hDrcData Handle to DRC channel data. + + \return none +*/ +void sbrDecoder_drcUpdateChannel ( + HANDLE_SBR_DRC_CHANNEL hDrcData ) +{ + if (hDrcData == NULL) { + return; + } + if (hDrcData->enable != 1) { + return; + } + + /* swap previous data */ + FDKmemcpy( hDrcData->currFact_mag, + hDrcData->nextFact_mag, + SBRDEC_MAX_DRC_BANDS * sizeof(FIXP_DBL) ); + + hDrcData->currFact_exp = hDrcData->nextFact_exp; + + hDrcData->numBandsCurr = hDrcData->numBandsNext; + + FDKmemcpy( hDrcData->bandTopCurr, + hDrcData->bandTopNext, + SBRDEC_MAX_DRC_BANDS * sizeof(USHORT) ); + + hDrcData->drcInterpolationSchemeCurr = hDrcData->drcInterpolationSchemeNext; + + hDrcData->winSequenceCurr = hDrcData->winSequenceNext; +} + + +/*! + \brief Apply DRC factors slot based. + + \hDrcData Handle to DRC channel data. + \qmfRealSlot Pointer to real valued QMF data of one time slot. + \qmfImagSlot Pointer to the imaginary QMF data of one time slot. + \col Number of the time slot. + \numQmfSubSamples Total number of time slots for one frame. + \scaleFactor Pointer to the out scale factor of the time slot. + + \return None. +*/ +void sbrDecoder_drcApplySlot ( + HANDLE_SBR_DRC_CHANNEL hDrcData, + FIXP_DBL *qmfRealSlot, + FIXP_DBL *qmfImagSlot, + int col, + int numQmfSubSamples, + int maxShift + ) +{ + const int *offset; + + int band, bottomMdct, topMdct, bin, useLP; + int indx = numQmfSubSamples - (numQmfSubSamples >> 1) - 10; /* l_border */ + int frameLenFlag = (numQmfSubSamples == 30) ? 1 : 0; + + const FIXP_DBL *fact_mag = NULL; + INT fact_exp = 0; + UINT numBands = 0; + USHORT *bandTop = NULL; + int shortDrc = 0; + + FIXP_DBL alphaValue = FL2FXCONST_DBL(0.0f); + + if (hDrcData == NULL) { + return; + } + if (hDrcData->enable != 1) { + return; + } + + offset = offsetTab[frameLenFlag]; + + useLP = (qmfImagSlot == NULL) ? 1 : 0; + + col += indx; + bottomMdct = 0; + bin = 0; + + /* get respective data and calc interpolation factor */ + if (col < (numQmfSubSamples>>1)) { /* first half of current frame */ + if (hDrcData->winSequenceCurr != 2) { /* long window */ + int j = col + (numQmfSubSamples>>1); + + if (hDrcData->drcInterpolationSchemeCurr == 0) { + INT k = (frameLenFlag) ? 0x4444444 : 0x4000000; + + alphaValue = (FIXP_DBL)(j * k); + } + else { + if (j >= offset[hDrcData->drcInterpolationSchemeCurr - 1]) { + alphaValue = FL2FXCONST_DBL(1.0f); + } + } + } + else { /* short windows */ + shortDrc = 1; + } + + fact_mag = hDrcData->currFact_mag; + fact_exp = hDrcData->currFact_exp; + numBands = hDrcData->numBandsCurr; + bandTop = hDrcData->bandTopCurr; + } + else if (col < numQmfSubSamples) { /* second half of current frame */ + if (hDrcData->winSequenceNext != 2) { /* next: long window */ + int j = col - (numQmfSubSamples>>1); + + if (hDrcData->drcInterpolationSchemeNext == 0) { + INT k = (frameLenFlag) ? 0x4444444 : 0x4000000; + + alphaValue = (FIXP_DBL)(j * k); + } + else { + if (j >= offset[hDrcData->drcInterpolationSchemeNext - 1]) { + alphaValue = FL2FXCONST_DBL(1.0f); + } + } + + fact_mag = hDrcData->nextFact_mag; + fact_exp = hDrcData->nextFact_exp; + numBands = hDrcData->numBandsNext; + bandTop = hDrcData->bandTopNext; + } + else { /* next: short windows */ + if (hDrcData->winSequenceCurr != 2) { /* current: long window */ + alphaValue = (FIXP_DBL)0; + + fact_mag = hDrcData->nextFact_mag; + fact_exp = hDrcData->nextFact_exp; + numBands = hDrcData->numBandsNext; + bandTop = hDrcData->bandTopNext; + } + else { /* current: short windows */ + shortDrc = 1; + + fact_mag = hDrcData->currFact_mag; + fact_exp = hDrcData->currFact_exp; + numBands = hDrcData->numBandsCurr; + bandTop = hDrcData->bandTopCurr; + } + } + } + else { /* first half of next frame */ + if (hDrcData->winSequenceNext != 2) { /* long window */ + int j = col - (numQmfSubSamples>>1); + + if (hDrcData->drcInterpolationSchemeNext == 0) { + INT k = (frameLenFlag) ? 0x4444444 : 0x4000000; + + alphaValue = (FIXP_DBL)(j * k); + } + else { + if (j >= offset[hDrcData->drcInterpolationSchemeNext - 1]) { + alphaValue = FL2FXCONST_DBL(1.0f); + } + } + } + else { /* short windows */ + shortDrc = 1; + } + + fact_mag = hDrcData->nextFact_mag; + fact_exp = hDrcData->nextFact_exp; + numBands = hDrcData->numBandsNext; + bandTop = hDrcData->bandTopNext; + + col -= numQmfSubSamples; + } + + + /* process bands */ + for (band = 0; band < (int)numBands; band++) { + int bottomQmf, topQmf; + + FIXP_DBL drcFact_mag = FL2FXCONST_DBL(1.0f); + + topMdct = (bandTop[band]+1) << 2; + + if (!shortDrc) { /* long window */ + if (frameLenFlag) { + /* 960 framing */ + bottomMdct = 30 * (bottomMdct / 30); + topMdct = 30 * (topMdct / 30); + + bottomQmf = fMultIfloor((FIXP_DBL)0x4444444, bottomMdct); + topQmf = fMultIfloor((FIXP_DBL)0x4444444, topMdct); + } + else { + /* 1024 framing */ + bottomMdct &= ~0x1f; + topMdct &= ~0x1f; + + bottomQmf = bottomMdct >> 5; + topQmf = topMdct >> 5; + } + + if (band == ((int)numBands-1)) { + topQmf = (64); + } + + for (bin = bottomQmf; bin < topQmf; bin++) { + FIXP_DBL drcFact1_mag = hDrcData->prevFact_mag[bin]; + FIXP_DBL drcFact2_mag = fact_mag[band]; + + /* normalize scale factors */ + if (hDrcData->prevFact_exp < maxShift) { + drcFact1_mag >>= maxShift - hDrcData->prevFact_exp; + } + if (fact_exp < maxShift) { + drcFact2_mag >>= maxShift - fact_exp; + } + + /* interpolate */ + drcFact_mag = fMult(alphaValue, drcFact2_mag) + fMult((FL2FXCONST_DBL(1.0f) - alphaValue), drcFact1_mag); + + /* apply scaling */ + qmfRealSlot[bin] = fMult(qmfRealSlot[bin], drcFact_mag); + if (!useLP) { + qmfImagSlot[bin] = fMult(qmfImagSlot[bin], drcFact_mag); + } + + /* save previous factors */ + if (col == (numQmfSubSamples>>1)-1) { + hDrcData->prevFact_mag[bin] = fact_mag[band]; + } + } + } + else { /* short windows */ + int startSample, stopSample; + FIXP_DBL invFrameSizeDiv8 = (frameLenFlag) ? (FIXP_DBL)0x1111111 : (FIXP_DBL)0x1000000; + + if (frameLenFlag) { + /* 960 framing */ + bottomMdct = 30/8 * (bottomMdct*8/30); + topMdct = 30/8 * (topMdct*8/30); + } + else { + /* 1024 framing */ + bottomMdct &= ~0x03; + topMdct &= ~0x03; + } + + /* startSample is truncated to the nearest corresponding start subsample in + the QMF of the short window bottom is present in:*/ + startSample = ((fMultIfloor( invFrameSizeDiv8, bottomMdct ) & 0x7) * numQmfSubSamples) >> 3; + + /* stopSample is rounded upwards to the nearest corresponding stop subsample + in the QMF of the short window top is present in. */ + stopSample = ((fMultIceil( invFrameSizeDiv8, topMdct ) & 0xf) * numQmfSubSamples) >> 3; + + bottomQmf = fMultIfloor( invFrameSizeDiv8, ((bottomMdct%(numQmfSubSamples<<2)) << 5) ); + topQmf = fMultIfloor( invFrameSizeDiv8, ((topMdct%(numQmfSubSamples<<2)) << 5) ); + + /* extend last band */ + if (band == ((int)numBands-1)) { + topQmf = (64); + stopSample = numQmfSubSamples; + } + + if (topQmf == 0) { + topQmf = (64); + } + + /* save previous factors */ + if (stopSample == numQmfSubSamples) { + int tmpBottom = bottomQmf; + + if (((numQmfSubSamples-1) & ~0x03) > startSample) { + tmpBottom = 0; /* band starts in previous short window */ + } + + for (bin = tmpBottom; bin < topQmf; bin++) { + hDrcData->prevFact_mag[bin] = fact_mag[band]; + } + } + + /* apply */ + if ((col >= startSample) && (col < stopSample)) { + if ((col & ~0x03) > startSample) { + bottomQmf = 0; /* band starts in previous short window */ + } + if (col < ((stopSample-1) & ~0x03)) { + topQmf = (64); /* band ends in next short window */ + } + + drcFact_mag = fact_mag[band]; + + /* normalize scale factor */ + if (fact_exp < maxShift) { + drcFact_mag >>= maxShift - fact_exp; + } + + /* apply scaling */ + for (bin = bottomQmf; bin < topQmf; bin++) { + qmfRealSlot[bin] = fMult(qmfRealSlot[bin], drcFact_mag); + if (!useLP) { + qmfImagSlot[bin] = fMult(qmfImagSlot[bin], drcFact_mag); + } + } + } + } + + bottomMdct = topMdct; + } /* end of bands loop */ + + if (col == (numQmfSubSamples>>1)-1) { + hDrcData->prevFact_exp = fact_exp; + } +} + + +/*! + \brief Apply DRC factors frame based. + + \hDrcData Handle to DRC channel data. + \qmfRealSlot Pointer to real valued QMF data of the whole frame. + \qmfImagSlot Pointer to the imaginary QMF data of the whole frame. + \numQmfSubSamples Total number of time slots for one frame. + \scaleFactor Pointer to the out scale factor of the frame. + + \return None. +*/ +void sbrDecoder_drcApply ( + HANDLE_SBR_DRC_CHANNEL hDrcData, + FIXP_DBL **QmfBufferReal, + FIXP_DBL **QmfBufferImag, + int numQmfSubSamples, + int *scaleFactor + ) +{ + int col; + int maxShift = 0; + + /* get max scale factor */ + if (hDrcData->prevFact_exp > maxShift) { + maxShift = hDrcData->prevFact_exp; + } + if (hDrcData->currFact_exp > maxShift) { + maxShift = hDrcData->currFact_exp; + } + if (hDrcData->nextFact_exp > maxShift) { + maxShift = hDrcData->nextFact_exp; + } + + for (col = 0; col < numQmfSubSamples; col++) + { + FIXP_DBL *qmfSlotReal = QmfBufferReal[col]; + FIXP_DBL *qmfSlotImag = (QmfBufferImag == NULL) ? NULL : QmfBufferImag[col]; + + sbrDecoder_drcApplySlot ( + hDrcData, + qmfSlotReal, + qmfSlotImag, + col, + numQmfSubSamples, + maxShift + ); + } + + *scaleFactor += maxShift; +} + diff --git a/libSBRdec/src/sbrdec_drc.h b/libSBRdec/src/sbrdec_drc.h new file mode 100644 index 0000000..a200c47 --- /dev/null +++ b/libSBRdec/src/sbrdec_drc.h @@ -0,0 +1,88 @@ +/***************************** MPEG-4 AAC Decoder ************************** + + (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. + + + $Id$ + Author(s): Christian Griebel + Description: Dynamic range control (DRC) decoder tool for SBR + + 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. + +******************************************************************************/ + +#ifndef _SBRDEC_DRC_H_ +#define _SBRDEC_DRC_H_ + +#include "sbrdecoder.h" + + +#define SBRDEC_MAX_DRC_CHANNELS (6) +#define SBRDEC_MAX_DRC_BANDS ( 16 ) + +typedef struct +{ + FIXP_DBL prevFact_mag[(64)]; + INT prevFact_exp; + + FIXP_DBL currFact_mag[SBRDEC_MAX_DRC_BANDS]; + FIXP_DBL nextFact_mag[SBRDEC_MAX_DRC_BANDS]; + INT currFact_exp; + INT nextFact_exp; + + UINT numBandsCurr; + UINT numBandsNext; + USHORT bandTopCurr[SBRDEC_MAX_DRC_BANDS]; + USHORT bandTopNext[SBRDEC_MAX_DRC_BANDS]; + + SHORT drcInterpolationSchemeCurr; + SHORT drcInterpolationSchemeNext; + + SHORT enable; + + UCHAR winSequenceCurr; + UCHAR winSequenceNext; + +} SBRDEC_DRC_CHANNEL; + +typedef SBRDEC_DRC_CHANNEL * HANDLE_SBR_DRC_CHANNEL; + + +void sbrDecoder_drcInitChannel ( + HANDLE_SBR_DRC_CHANNEL hDrcData ); + +void sbrDecoder_drcUpdateChannel ( + HANDLE_SBR_DRC_CHANNEL hDrcData ); + +void sbrDecoder_drcApplySlot ( + HANDLE_SBR_DRC_CHANNEL hDrcData, + FIXP_DBL *qmfRealSlot, + FIXP_DBL *qmfImagSlot, + int col, + int numQmfSubSamples, + int maxShift ); + +void sbrDecoder_drcApply ( + HANDLE_SBR_DRC_CHANNEL hDrcData, + FIXP_DBL **QmfBufferReal, + FIXP_DBL **QmfBufferImag, + int numQmfSubSamples, + int *scaleFactor ); + + +#endif /* _SBRDEC_DRC_H_ */ diff --git a/libSBRdec/src/sbrdec_freq_sca.cpp b/libSBRdec/src/sbrdec_freq_sca.cpp new file mode 100644 index 0000000..f48c7d0 --- /dev/null +++ b/libSBRdec/src/sbrdec_freq_sca.cpp @@ -0,0 +1,749 @@ +/**************************************************************************** + + (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 Frequency scale calculation $Revision: 36841 $ +*/ + +#include "sbrdec_freq_sca.h" + +#include "transcendent.h" +#include "sbr_rom.h" +#include "env_extr.h" + +#include "genericStds.h" /* need log() for debug-code only */ + +#define MAX_OCTAVE 29 +#define MAX_SECOND_REGION 50 + + +static int numberOfBands(FIXP_SGL bpo_div16, int start, int stop, int warpFlag); +static void CalcBands(UCHAR * diff, UCHAR start, UCHAR stop, UCHAR num_bands); +static SBR_ERROR modifyBands(UCHAR max_band, UCHAR * diff, UCHAR length); +static void cumSum(UCHAR start_value, UCHAR* diff, UCHAR length, UCHAR *start_adress); + + + +/*! + \brief Retrieve QMF-band where the SBR range starts + + Convert startFreq which was read from the bitstream into a + QMF-channel number. + + \return Number of start band +*/ +static UCHAR +getStartBand(UINT fs, /*!< Output sampling frequency */ + UCHAR startFreq, /*!< Index to table of possible start bands */ + UINT headerDataFlags) /*!< Info to SBR mode */ +{ + INT band; + UINT fsMapped; + + fsMapped = fs; + + switch (fsMapped) { + case 48000: + band = FDK_sbrDecoder_sbr_start_freq_48[startFreq]; + break; + case 44100: + band = FDK_sbrDecoder_sbr_start_freq_44[startFreq]; + break; + case 32000: + band = FDK_sbrDecoder_sbr_start_freq_32[startFreq]; + break; + case 24000: + band = FDK_sbrDecoder_sbr_start_freq_24[startFreq]; + break; + case 22050: + band = FDK_sbrDecoder_sbr_start_freq_22[startFreq]; + break; + case 16000: + band = FDK_sbrDecoder_sbr_start_freq_16[startFreq]; + break; + default: + band = 255; + } + + return band; +} + + +/*! + \brief Retrieve QMF-band where the SBR range starts + + Convert startFreq which was read from the bitstream into a + QMF-channel number. + + \return Number of start band +*/ +static UCHAR +getStopBand(UINT fs, /*!< Output sampling frequency */ + UCHAR stopFreq, /*!< Index to table of possible start bands */ + UINT headerDataFlags, /*!< Info to SBR mode */ + UCHAR k0) /*!< Start freq index */ +{ + UCHAR k2; + + if (stopFreq < 14) { + INT stopMin; + UCHAR diff_tot[MAX_OCTAVE + MAX_SECOND_REGION]; + UCHAR *diff0 = diff_tot; + UCHAR *diff1 = diff_tot+MAX_OCTAVE; + + if (fs < 32000) { + stopMin = (((2*6000*2*(64)) / fs) + 1) >> 1; + } + else { + if (fs < 64000) { + stopMin = (((2*8000*2*(64)) / fs) + 1) >> 1; + } + else { + stopMin = (((2*10000*2*(64)) / fs) + 1) >> 1; + } + } + + /* + Choose a stop band between k1 and 64 depending on stopFreq (0..13), + based on a logarithmic scale. + The vectors diff0 and diff1 are used temporarily here. + */ + CalcBands( diff0, stopMin, 64, 13); + shellsort( diff0, 13); + cumSum(stopMin, diff0, 13, diff1); + k2 = diff1[stopFreq]; + } + else if (stopFreq==14) + k2 = 2*k0; + else + k2 = 3*k0; + + /* Limit to Nyquist */ + if (k2 > (64)) + k2 = (64); + + + /* Range checks */ + /* 1 <= difference <= 48; 1 <= fs <= 96000 */ + if ( ((k2 - k0) > MAX_FREQ_COEFFS) || (k2 <= k0) ) { + return 255; + } + + if (headerDataFlags & (SBRDEC_SYNTAX_USAC|SBRDEC_SYNTAX_RSVD50)) { + /* 1 <= difference <= 35; 42000 <= fs <= 96000 */ + if ( (fs >= 42000) && ( (k2 - k0) > MAX_FREQ_COEFFS_FS44100 ) ) { + return 255; + } + /* 1 <= difference <= 32; 46009 <= fs <= 96000 */ + if ( (fs >= 46009) && ( (k2 - k0) > MAX_FREQ_COEFFS_FS48000 ) ) { + return 255; + } + } + else { + /* 1 <= difference <= 35; fs == 44100 */ + if ( (fs == 44100) && ( (k2 - k0) > MAX_FREQ_COEFFS_FS44100 ) ) { + return 255; + } + /* 1 <= difference <= 32; 48000 <= fs <= 96000 */ + if ( (fs >= 48000) && ( (k2 - k0) > MAX_FREQ_COEFFS_FS48000 ) ) { + return 255; + } + } + + return k2; +} + + +/*! + \brief Generates master frequency tables + + Frequency tables are calculated according to the selected domain + (linear/logarithmic) and granularity. + IEC 14496-3 4.6.18.3.2.1 + + \return errorCode, 0 if successful +*/ +SBR_ERROR +sbrdecUpdateFreqScale(UCHAR * v_k_master, /*!< Master table to be created */ + UCHAR *numMaster, /*!< Number of entries in master table */ + UINT fs, /*!< SBR working sampling rate */ + HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Control data from bitstream */ + UINT flags) +{ + FIXP_SGL bpo_div16; /* bands_per_octave divided by 16 */ + INT dk=0; + + /* Internal variables */ + UCHAR k0, k2, i; + UCHAR num_bands0 = 0; + UCHAR num_bands1 = 0; + UCHAR diff_tot[MAX_OCTAVE + MAX_SECOND_REGION]; + UCHAR *diff0 = diff_tot; + UCHAR *diff1 = diff_tot+MAX_OCTAVE; + INT k2_achived; + INT k2_diff; + INT incr=0; + + /* + Determine start band + */ + k0 = getStartBand(fs, hHeaderData->bs_data.startFreq, flags); + if (k0 == 255) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + /* + Determine stop band + */ + k2 = getStopBand(fs, hHeaderData->bs_data.stopFreq, flags, k0); + if (k2 == 255) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + if(hHeaderData->bs_data.freqScale>0) { /* Bark */ + INT k1; + + if(hHeaderData->bs_data.freqScale==1) { + bpo_div16 = FL2FXCONST_SGL(12.0f/16.0f); + } + else if(hHeaderData->bs_data.freqScale==2) { + bpo_div16 = FL2FXCONST_SGL(10.0f/16.0f); + } + else { + bpo_div16 = FL2FXCONST_SGL(8.0f/16.0f); + } + + + if( 1000 * k2 > 2245 * k0 ) { /* Two or more regions */ + k1 = 2*k0; + + num_bands0 = numberOfBands(bpo_div16, k0, k1, 0); + num_bands1 = numberOfBands(bpo_div16, k1, k2, hHeaderData->bs_data.alterScale ); + if ( num_bands0 < 1) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + if ( num_bands1 < 1 ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + CalcBands(diff0, k0, k1, num_bands0); + shellsort( diff0, num_bands0); + if (diff0[0] == 0) { +#ifdef DEBUG_TOOLS +#endif + return SBRDEC_UNSUPPORTED_CONFIG; + } + + cumSum(k0, diff0, num_bands0, v_k_master); + + CalcBands(diff1, k1, k2, num_bands1); + shellsort( diff1, num_bands1); + if(diff0[num_bands0-1] > diff1[0]) { + SBR_ERROR err; + + err = modifyBands(diff0[num_bands0-1],diff1, num_bands1); + if (err) + return SBRDEC_UNSUPPORTED_CONFIG; + } + + /* Add 2nd region */ + cumSum(k1, diff1, num_bands1, &v_k_master[num_bands0]); + *numMaster = num_bands0 + num_bands1; /* Output nr of bands */ + + } + else { /* Only one region */ + k1=k2; + + num_bands0 = numberOfBands(bpo_div16, k0, k1, 0); + if ( num_bands0 < 1) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + CalcBands(diff0, k0, k1, num_bands0); + shellsort(diff0, num_bands0); + if (diff0[0] == 0) { +#ifdef DEBUG_TOOLS +#endif + return SBRDEC_UNSUPPORTED_CONFIG; + } + + cumSum(k0, diff0, num_bands0, v_k_master); + *numMaster = num_bands0; /* Output nr of bands */ + + } + } + else { /* Linear mode */ + if (hHeaderData->bs_data.alterScale==0) { + dk = 1; + /* FLOOR to get to few number of bands (next lower even number) */ + num_bands0 = (k2 - k0) & 254; + } else { + dk = 2; + num_bands0 = ( ((k2 - k0) >> 1) + 1 ) & 254; /* ROUND to the closest fit */ + } + + if (num_bands0 < 1) { + return SBRDEC_UNSUPPORTED_CONFIG; + /* We must return already here because 'i' can become negative below. */ + } + + k2_achived = k0 + num_bands0*dk; + k2_diff = k2 - k2_achived; + + for(i=0;i<num_bands0;i++) + diff_tot[i] = dk; + + /* If linear scale wasn't achieved */ + /* and we got too wide SBR area */ + if (k2_diff < 0) { + incr = 1; + i = 0; + } + + /* If linear scale wasn't achieved */ + /* and we got too small SBR area */ + if (k2_diff > 0) { + incr = -1; + i = num_bands0-1; + } + + /* Adjust diff vector to get sepc. SBR range */ + while (k2_diff != 0) { + diff_tot[i] = diff_tot[i] - incr; + i = i + incr; + k2_diff = k2_diff + incr; + } + + cumSum(k0, diff_tot, num_bands0, v_k_master);/* cumsum */ + *numMaster = num_bands0; /* Output nr of bands */ + } + + if (*numMaster < 1) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + + /* + Print out the calculated table + */ + + return SBRDEC_OK; +} + + +/*! + \brief Calculate frequency ratio of one SBR band + + All SBR bands should span a constant frequency range in the logarithmic + domain. This function calculates the ratio of any SBR band's upper and lower + frequency. + + \return num_band-th root of k_start/k_stop +*/ +static FIXP_SGL calcFactorPerBand(int k_start, int k_stop, int num_bands) +{ +/* Changes CT fract class -> IIS fract class: + * scaled bandfactor and step 1 bit right to avoid overflow + * use CTdbouble data type */ + FIXP_DBL bandfactor = FL2FXCONST_DBL(0.25f); /* Start value */ + FIXP_DBL step = FL2FXCONST_DBL(0.125f); /* Initial increment for factor */ + + int direction = 1; + +/* Changes CT fract class -> IIS fract class: + * because saturation can't be done in INT IIS, + * changed start and stop data type from FIXP_SGL to FIXP_DBL */ + FIXP_DBL start = k_start << (DFRACT_BITS-8); + FIXP_DBL stop = k_stop << (DFRACT_BITS-8); + + FIXP_DBL temp; + + int j, i=0; + + while ( step > FL2FXCONST_DBL(0.0f)) { + i++; + temp = stop; + + /* Calculate temp^num_bands: */ + for (j=0; j<num_bands; j++) + //temp = fMult(temp,bandfactor); + temp = fMultDiv2(temp,bandfactor)<<2; + + if (temp<start) { /* Factor too strong, make it weaker */ + if (direction == 0) + /* Halfen step. Right shift is not done as fract because otherwise the + lowest bit cannot be cleared due to rounding */ + step = (FIXP_DBL)((LONG)step >> 1); + direction = 1; + bandfactor = bandfactor + step; + } + else { /* Factor is too weak: make it stronger */ + if (direction == 1) + step = (FIXP_DBL)((LONG)step >> 1); + direction = 0; + bandfactor = bandfactor - step; + } + + if (i>100) { + step = FL2FXCONST_DBL(0.0f); + } + } + return FX_DBL2FX_SGL(bandfactor<<1); +} + + +/*! + \brief Calculate number of SBR bands between start and stop band + + Given the number of bands per octave, this function calculates how many + bands fit in the given frequency range. + When the warpFlag is set, the 'band density' is decreased by a factor + of 1/1.3 + + \return number of bands +*/ +static int +numberOfBands(FIXP_SGL bpo_div16, /*!< Input: number of bands per octave divided by 16 */ + int start, /*!< First QMF band of SBR frequency range */ + int stop, /*!< Last QMF band of SBR frequency range + 1 */ + int warpFlag) /*!< Stretching flag */ +{ + FIXP_SGL num_bands_div128; + int num_bands; + + num_bands_div128 = FX_DBL2FX_SGL(fMult(FDK_getNumOctavesDiv8(start,stop),bpo_div16)); + + if (warpFlag) { + /* Apply the warp factor of 1.3 to get wider bands. We use a value + of 32768/25200 instead of the exact value to avoid critical cases + of rounding. + */ + num_bands_div128 = FX_DBL2FX_SGL(fMult(num_bands_div128, FL2FXCONST_SGL(25200.0/32768.0))); + } + + /* add scaled 1 for rounding to even numbers: */ + num_bands_div128 = num_bands_div128 + FL2FXCONST_SGL( 1.0f/128.0f ); + /* scale back to right aligned integer and double the value: */ + num_bands = 2 * ((LONG)num_bands_div128 >> (FRACT_BITS - 7)); + + return(num_bands); +} + + +/*! + \brief Calculate width of SBR bands + + Given the desired number of bands within the SBR frequency range, + this function calculates the width of each SBR band in QMF channels. + The bands get wider from start to stop (bark scale). +*/ +static void +CalcBands(UCHAR * diff, /*!< Vector of widths to be calculated */ + UCHAR start, /*!< Lower end of subband range */ + UCHAR stop, /*!< Upper end of subband range */ + UCHAR num_bands) /*!< Desired number of bands */ +{ + int i; + int previous; + int current; + FIXP_SGL exact, temp; + FIXP_SGL bandfactor = calcFactorPerBand(start, stop, num_bands); + + previous = stop; /* Start with highest QMF channel */ + exact = (FIXP_SGL)(stop << (FRACT_BITS-8)); /* Shift left to gain some accuracy */ + + for(i=num_bands-1; i>=0; i--) { + /* Calculate border of next lower sbr band */ + exact = FX_DBL2FX_SGL(fMult(exact,bandfactor)); + + /* Add scaled 0.5 for rounding: + We use a value 128/256 instead of 0.5 to avoid some critical cases of rounding. */ + temp = exact + FL2FXCONST_SGL(128.0/32768.0); + + /* scale back to right alinged integer: */ + current = (LONG)temp >> (FRACT_BITS-8); + + /* Save width of band i */ + diff[i] = previous - current; + previous = current; + } +} + + +/*! + \brief Calculate cumulated sum vector from delta vector +*/ +static void +cumSum(UCHAR start_value, UCHAR* diff, UCHAR length, UCHAR *start_adress) +{ + int i; + start_adress[0]=start_value; + for(i=1; i<=length; i++) + start_adress[i] = start_adress[i-1] + diff[i-1]; +} + + +/*! + \brief Adapt width of frequency bands in the second region + + If SBR spans more than 2 octaves, the upper part of a bark-frequency-scale + is calculated separately. This function tries to avoid that the second region + starts with a band smaller than the highest band of the first region. +*/ +static SBR_ERROR +modifyBands(UCHAR max_band_previous, UCHAR * diff, UCHAR length) +{ + int change = max_band_previous - diff[0]; + + /* Limit the change so that the last band cannot get narrower than the first one */ + if ( change > (diff[length-1]-diff[0])>>1 ) + change = (diff[length-1]-diff[0])>>1; + + diff[0] += change; + diff[length-1] -= change; + shellsort(diff, length); + + return SBRDEC_OK; +} + + +/*! + \brief Update high resolution frequency band table +*/ +static void +sbrdecUpdateHiRes(UCHAR * h_hires, + UCHAR * num_hires, + UCHAR * v_k_master, + UCHAR num_bands, + UCHAR xover_band) +{ + UCHAR i; + + *num_hires = num_bands-xover_band; + + for(i=xover_band; i<=num_bands; i++) { + h_hires[i-xover_band] = v_k_master[i]; + } +} + + +/*! + \brief Build low resolution table out of high resolution table +*/ +static void +sbrdecUpdateLoRes(UCHAR * h_lores, + UCHAR * num_lores, + UCHAR * h_hires, + UCHAR num_hires) +{ + UCHAR i; + + if( (num_hires & 1) == 0) { + /* If even number of hires bands */ + *num_lores = num_hires >> 1; + /* Use every second lores=hires[0,2,4...] */ + for(i=0; i<=*num_lores; i++) + h_lores[i] = h_hires[i*2]; + } + else { + /* Odd number of hires, which means xover is odd */ + *num_lores = (num_hires+1) >> 1; + /* Use lores=hires[0,1,3,5 ...] */ + h_lores[0] = h_hires[0]; + for(i=1; i<=*num_lores; i++) { + h_lores[i] = h_hires[i*2-1]; + } + } +} + + +/*! + \brief Derive a low-resolution frequency-table from the master frequency table +*/ +void +sbrdecDownSampleLoRes(UCHAR *v_result, + UCHAR num_result, + UCHAR *freqBandTableRef, + UCHAR num_Ref) +{ + int step; + int i,j; + int org_length,result_length; + int v_index[MAX_FREQ_COEFFS>>1]; + + /* init */ + org_length = num_Ref; + result_length = num_result; + + v_index[0] = 0; /* Always use left border */ + i=0; + while(org_length > 0) { + /* Create downsample vector */ + i++; + step = org_length / result_length; + org_length = org_length - step; + result_length--; + v_index[i] = v_index[i-1] + step; + } + + for(j=0;j<=i;j++) { + /* Use downsample vector to index LoResolution vector */ + v_result[j]=freqBandTableRef[v_index[j]]; + } + +} + + +/*! + \brief Sorting routine +*/ +void shellsort(UCHAR *in, UCHAR n) +{ + + int i, j, v, w; + int inc = 1; + + do + inc = 3 * inc + 1; + while (inc <= n); + + do { + inc = inc / 3; + for (i = inc; i < n; i++) { + v = in[i]; + j = i; + while ((w=in[j-inc]) > v) { + in[j] = w; + j -= inc; + if (j < inc) + break; + } + in[j] = v; + } + } while (inc > 1); + +} + + + +/*! + \brief Reset frequency band tables + \return errorCode, 0 if successful +*/ +SBR_ERROR +resetFreqBandTables(HANDLE_SBR_HEADER_DATA hHeaderData, const UINT flags) +{ + SBR_ERROR err = SBRDEC_OK; + int k2,kx, lsb, usb; + int intTemp; + UCHAR nBandsLo, nBandsHi; + HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData; + + /* Calculate master frequency function */ + err = sbrdecUpdateFreqScale(hFreq->v_k_master, + &hFreq->numMaster, + hHeaderData->sbrProcSmplRate, + hHeaderData, + flags); + + if ( err || (hHeaderData->bs_info.xover_band > hFreq->numMaster) ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + /* Derive Hiresolution from master frequency function */ + sbrdecUpdateHiRes(hFreq->freqBandTable[1], &nBandsHi, hFreq->v_k_master, hFreq->numMaster, hHeaderData->bs_info.xover_band ); + /* Derive Loresolution from Hiresolution */ + sbrdecUpdateLoRes(hFreq->freqBandTable[0], &nBandsLo, hFreq->freqBandTable[1], nBandsHi); + + + hFreq->nSfb[0] = nBandsLo; + hFreq->nSfb[1] = nBandsHi; + + /* Check index to freqBandTable[0] */ + if ( !(nBandsLo > 0) || (nBandsLo > (MAX_FREQ_COEFFS>>1)) ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + lsb = hFreq->freqBandTable[0][0]; + usb = hFreq->freqBandTable[0][nBandsLo]; + + /* Additional check for lsb */ + if ( (lsb > (32)) || (lsb >= usb) ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + + /* Calculate number of noise bands */ + + k2 = hFreq->freqBandTable[1][nBandsHi]; + kx = hFreq->freqBandTable[1][0]; + + if (hHeaderData->bs_data.noise_bands == 0) + { + hFreq->nNfb = 1; + } + else /* Calculate no of noise bands 1,2 or 3 bands/octave */ + { + /* Fetch number of octaves divided by 32 */ + intTemp = (LONG)FDK_getNumOctavesDiv8(kx,k2) >> 2; + + /* Integer-Multiplication with number of bands: */ + intTemp = intTemp * hHeaderData->bs_data.noise_bands; + + /* Add scaled 0.5 for rounding: */ + intTemp = intTemp + (LONG)FL2FXCONST_SGL(0.5f/32.0f); + + /* Convert to right-aligned integer: */ + intTemp = intTemp >> (FRACT_BITS - 1 /*sign*/ - 5 /* rescale */); + + /* Compare with float calculation */ + FDK_ASSERT( intTemp == (int)((hHeaderData->bs_data.noise_bands * FDKlog( (float)k2/kx) / (float)(FDKlog(2.0)))+0.5) ); + + if( intTemp==0) + intTemp=1; + + hFreq->nNfb = intTemp; + } + + hFreq->nInvfBands = hFreq->nNfb; + + if( hFreq->nNfb > MAX_NOISE_COEFFS ) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + /* Get noise bands */ + sbrdecDownSampleLoRes(hFreq->freqBandTableNoise, + hFreq->nNfb, + hFreq->freqBandTable[0], + nBandsLo); + + + + + hFreq->lowSubband = lsb; + hFreq->highSubband = usb; + + return SBRDEC_OK; +} diff --git a/libSBRdec/src/sbrdec_freq_sca.h b/libSBRdec/src/sbrdec_freq_sca.h new file mode 100644 index 0000000..9df6777 --- /dev/null +++ b/libSBRdec/src/sbrdec_freq_sca.h @@ -0,0 +1,48 @@ +/**************************************************************************** + + (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 Frequency scale prototypes $Revision: 36841 $ +*/ +#ifndef __FREQ_SCA_H +#define __FREQ_SCA_H + +#include "sbrdecoder.h" +#include "env_extr.h" + +int +sbrdecUpdateFreqScale(UCHAR * v_k_master, + UCHAR *numMaster, + HANDLE_SBR_HEADER_DATA headerData); + +void sbrdecDownSampleLoRes(UCHAR *v_result, UCHAR num_result, + UCHAR *freqBandTableRef, UCHAR num_Ref); + +void shellsort(UCHAR *in, UCHAR n); + +SBR_ERROR +resetFreqBandTables(HANDLE_SBR_HEADER_DATA hHeaderData, const UINT flags); + +#endif diff --git a/libSBRdec/src/sbrdecoder.cpp b/libSBRdec/src/sbrdecoder.cpp new file mode 100644 index 0000000..dc824cb --- /dev/null +++ b/libSBRdec/src/sbrdecoder.cpp @@ -0,0 +1,1448 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2005) + 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 SBR decoder frontend $Revision: 36841 $ + This module provides a frontend to the SBR decoder. The function openSBR() is called for + initialization. The function sbrDecoder_Apply() is called for each frame. sbr_Apply() will call the + required functions to decode the raw SBR data (provided by env_extr.cpp), to decode the envelope data and noise floor levels [decodeSbrData()], + and to finally apply SBR to the current frame [sbr_dec()]. + + \sa sbrDecoder_Apply(), \ref documentationOverview +*/ + +/*! + \page documentationOverview Overview of important information resources and source code documentation + + The primary source code documentation is based on generated and cross-referenced HTML files using + <a HREF="http://www.doxygen.org">doxygen</a>. As part of this documentation + you can find more extensive descriptions about key concepts and algorithms at the following locations: + + <h2>Programming</h2> + + \li Buffer management: sbrDecoder_Apply() and sbr_dec() + \li Internal scale factors to maximize SNR on fixed point processors: #QMF_SCALE_FACTOR + \li Special mantissa-exponent format: Created in requantizeEnvelopeData() and used in calculateSbrEnvelope() + + <h2>Algorithmic details</h2> + \li About the SBR data format: \ref SBR_HEADER_ELEMENT and \ref SBR_STANDARD_ELEMENT + \li Details about the bitstream decoder: env_extr.cpp + \li Details about the QMF filterbank and the provided polyphase implementation: qmf_dec.cpp + \li Details about the transposer: lpp_tran.cpp + \li Details about the envelope adjuster: env_calc.cpp + +*/ + +#include "sbrdecoder.h" + +#include "FDK_bitstream.h" + +#include "sbrdec_freq_sca.h" +#include "env_extr.h" +#include "sbr_dec.h" +#include "env_dec.h" +#include "sbr_crc.h" +#include "sbr_ram.h" +#include "sbr_rom.h" +#include "lpp_tran.h" +#include "transcendent.h" + + +#include "sbrdec_drc.h" + +#include "psbitdec.h" + + +/* Decoder library info */ +#define SBRDECODER_LIB_VL0 2 +#define SBRDECODER_LIB_VL1 1 +#define SBRDECODER_LIB_VL2 0 +#define SBRDECODER_LIB_TITLE "SBR Decoder" +#define SBRDECODER_LIB_BUILD_DATE __DATE__ +#define SBRDECODER_LIB_BUILD_TIME __TIME__ + + + + +static UCHAR getHeaderSlot( UCHAR currentSlot, UCHAR hdrSlotUsage[(1)+1] ) +{ + UINT occupied = 0; + int s; + UCHAR slot = hdrSlotUsage[currentSlot]; + + FDK_ASSERT((1)+1 < 32); + + for (s = 0; s < (1)+1; s++) { + if ( (hdrSlotUsage[s] == slot) + && (s != slot) ) { + occupied = 1; + break; + } + } + + if (occupied) { + occupied = 0; + + for (s = 0; s < (1)+1; s++) { + occupied |= 1 << hdrSlotUsage[s]; + } + for (s = 0; s < (1)+1; s++) { + if ( !(occupied & 0x1) ) { + slot = s; + break; + } + occupied >>= 1; + } + } + + return slot; +} + +static void copySbrHeader( HANDLE_SBR_HEADER_DATA hDst, const HANDLE_SBR_HEADER_DATA hSrc ) +{ + /* copy the whole header memory (including pointers) */ + FDKmemcpy( hDst, hSrc, sizeof(SBR_HEADER_DATA) ); + + /* update pointers */ + hDst->freqBandData.freqBandTable[0] = hDst->freqBandData.freqBandTableLo; + hDst->freqBandData.freqBandTable[1] = hDst->freqBandData.freqBandTableHi; +} + + +/*! + \brief Reset SBR decoder. + + Reset should only be called if SBR has been sucessfully detected by + an appropriate checkForPayload() function. + + \return Error code. +*/ +static +SBR_ERROR sbrDecoder_ResetElement ( + HANDLE_SBRDECODER self, + int sampleRateIn, + int sampleRateOut, + int samplesPerFrame, + const MP4_ELEMENT_ID elementID, + const int elementIndex, + const int overlap + ) +{ + SBR_ERROR sbrError = SBRDEC_OK; + HANDLE_SBR_HEADER_DATA hSbrHeader; + UINT qmfFlags = 0; + + int i, synDownsampleFac; + + /* Check in/out samplerates */ + if ( sampleRateIn < 6400 + || sampleRateIn > 24000 + ) + { + sbrError = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + + if ( sampleRateOut > 48000 ) + { + sbrError = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + + /* Set QMF mode flags */ + if (self->flags & SBRDEC_LOW_POWER) + qmfFlags |= QMF_FLAG_LP; + + if (self->coreCodec == AOT_ER_AAC_ELD) { + if (self->flags & SBRDEC_LD_MPS_QMF) { + qmfFlags |= QMF_FLAG_MPSLDFB; + } else { + qmfFlags |= QMF_FLAG_CLDFB; + } + } + + /* Set downsampling factor for synthesis filter bank */ + if (sampleRateOut == 0) + { + /* no single rate mode */ + sampleRateOut = sampleRateIn<<1; /* In case of implicit signalling, assume dual rate SBR */ + } + + if ( sampleRateIn == sampleRateOut ) { + synDownsampleFac = 2; + } else { + synDownsampleFac = 1; + } + + self->synDownsampleFac = synDownsampleFac; + self->sampleRateOut = sampleRateOut; + + { + int i; + + for (i = 0; i < (1)+1; i++) + { + hSbrHeader = &(self->sbrHeader[elementIndex][i]); + + /* init a default header such that we can at least do upsampling later */ + sbrError = initHeaderData( + hSbrHeader, + sampleRateIn, + sampleRateOut, + samplesPerFrame, + self->flags + ); + } + } + + if (sbrError != SBRDEC_OK) { + goto bail; + } + + /* Init SBR channels going to be assigned to a SBR element */ + { + int ch; + + for (ch=0; ch<self->pSbrElement[elementIndex]->nChannels; ch++) + { + /* and create sbrDec */ + sbrError = createSbrDec (self->pSbrElement[elementIndex]->pSbrChannel[ch], + hSbrHeader, + &self->pSbrElement[elementIndex]->transposerSettings, + synDownsampleFac, + qmfFlags, + self->flags, + overlap, + ch ); + + if (sbrError != SBRDEC_OK) { + goto bail; + } + } + } + + //FDKmemclear(sbr_OverlapBuffer, sizeof(sbr_OverlapBuffer)); + + if (self->numSbrElements == 1) { + switch ( self->coreCodec ) { + case AOT_AAC_LC: + case AOT_SBR: + case AOT_PS: + case AOT_ER_AAC_SCAL: + case AOT_DRM_AAC: + case AOT_DRM_SURROUND: + if (CreatePsDec ( &self->hParametricStereoDec, samplesPerFrame )) { + sbrError = SBRDEC_CREATE_ERROR; + goto bail; + } + break; + default: + break; + } + } + + /* Init frame delay slot handling */ + self->pSbrElement[elementIndex]->useFrameSlot = 0; + for (i = 0; i < ((1)+1); i++) { + self->pSbrElement[elementIndex]->useHeaderSlot[i] = i; + } + +bail: + + return sbrError; +} + + +SBR_ERROR sbrDecoder_Open ( HANDLE_SBRDECODER * pSelf ) +{ + HANDLE_SBRDECODER self = NULL; + SBR_ERROR sbrError = SBRDEC_OK; + + /* Get memory for this instance */ + self = GetRam_SbrDecoder(); + if (self == NULL) { + sbrError = SBRDEC_MEM_ALLOC_FAILED; + goto bail; + } + + self->workBuffer1 = GetRam_SbrDecWorkBuffer1(); + self->workBuffer2 = GetRam_SbrDecWorkBuffer2(); + + if ( self->workBuffer1 == NULL + || self->workBuffer2 == NULL ) + { + sbrError = SBRDEC_MEM_ALLOC_FAILED; + goto bail; + } + + /* + Already zero because of calloc + self->numSbrElements = 0; + self->numSbrChannels = 0; + self->codecFrameSize = 0; + */ + + self->numDelayFrames = (1); /* set to the max value by default */ + + *pSelf = self; + +bail: + return sbrError; +} + +/** + * \brief determine if the given core codec AOT can be processed or not. + * \param coreCodec core codec audio object type. + * \return 1 if SBR can be processed, 0 if SBR cannot be processed/applied. + */ +static +int sbrDecoder_isCoreCodecValid(AUDIO_OBJECT_TYPE coreCodec) +{ + switch (coreCodec) { + case AOT_AAC_LC: + case AOT_SBR: + case AOT_PS: + case AOT_ER_AAC_SCAL: + case AOT_ER_AAC_ELD: + return 1; + default: + return 0; + } +} + +static +void sbrDecoder_DestroyElement ( + HANDLE_SBRDECODER self, + const int elementIndex + ) +{ + if (self->pSbrElement[elementIndex] != NULL) { + int ch; + + for (ch=0; ch<SBRDEC_MAX_CH_PER_ELEMENT; ch++) { + if (self->pSbrElement[elementIndex]->pSbrChannel[ch] != NULL) { + deleteSbrDec( self->pSbrElement[elementIndex]->pSbrChannel[ch] ); + FreeRam_SbrDecChannel( &self->pSbrElement[elementIndex]->pSbrChannel[ch] ); + self->numSbrChannels -= 1; + } + } + FreeRam_SbrDecElement( &self->pSbrElement[elementIndex] ); + self->numSbrElements -= 1; + } +} + + +SBR_ERROR sbrDecoder_InitElement ( + HANDLE_SBRDECODER self, + const int sampleRateIn, + const int sampleRateOut, + const int samplesPerFrame, + const AUDIO_OBJECT_TYPE coreCodec, + const MP4_ELEMENT_ID elementID, + const int elementIndex + ) +{ + SBR_ERROR sbrError = SBRDEC_OK; + int chCnt=0; + + /* Check core codec AOT */ + if (! sbrDecoder_isCoreCodecValid(coreCodec) || elementIndex >= (4)) { + sbrError = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + + if ( elementID != ID_SCE && elementID != ID_CPE && elementID != ID_LFE ) + { + sbrError = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + + if ( self->sampleRateIn == sampleRateIn + && self->codecFrameSize == samplesPerFrame + && self->coreCodec == coreCodec + && self->pSbrElement[elementIndex] != NULL + && self->pSbrElement[elementIndex]->elementID == elementID + ) + { + /* Nothing to do */ + return SBRDEC_OK; + } + + self->sampleRateIn = sampleRateIn; + self->codecFrameSize = samplesPerFrame; + self->coreCodec = coreCodec; + + self->flags = 0; + self->flags |= (coreCodec == AOT_ER_AAC_ELD) ? SBRDEC_ELD_GRID : 0; + + /* Init SBR elements */ + { + int elChannels, ch; + + if (self->pSbrElement[elementIndex] == NULL) { + self->pSbrElement[elementIndex] = GetRam_SbrDecElement(elementIndex); + if (self->pSbrElement[elementIndex] == NULL) { + sbrError = SBRDEC_MEM_ALLOC_FAILED; + goto bail; + } + self->numSbrElements ++; + } else { + self->numSbrChannels -= self->pSbrElement[elementIndex]->nChannels; + } + + /* Save element ID for sanity checks and to have a fallback for concealment. */ + self->pSbrElement[elementIndex]->elementID = elementID; + + /* Determine amount of channels for this element */ + switch (elementID) { + case ID_NONE: + case ID_CPE: elChannels=2; + break; + case ID_LFE: + case ID_SCE: elChannels=1; + break; + default: elChannels=0; + break; + } + + /* Handle case of Parametric Stereo */ + if ( elementIndex == 0 && elementID == ID_SCE ) { + switch (coreCodec) { + case AOT_AAC_LC: + case AOT_SBR: + case AOT_PS: + case AOT_ER_AAC_SCAL: + case AOT_DRM_AAC: + case AOT_DRM_SURROUND: + elChannels = 2; + break; + default: + break; + } + } + + self->pSbrElement[elementIndex]->nChannels = elChannels; + + for (ch=0; ch<elChannels; ch++) + { + if (self->pSbrElement[elementIndex]->pSbrChannel[ch] == NULL) { + self->pSbrElement[elementIndex]->pSbrChannel[ch] = GetRam_SbrDecChannel(chCnt); + if (self->pSbrElement[elementIndex]->pSbrChannel[ch] == NULL) { + sbrError = SBRDEC_MEM_ALLOC_FAILED; + goto bail; + } + } + self->numSbrChannels ++; + + sbrDecoder_drcInitChannel( &self->pSbrElement[elementIndex]->pSbrChannel[ch]->SbrDec.sbrDrcChannel ); + + /* Add reference pointer to workbuffers. */ + self->pSbrElement[elementIndex]->pSbrChannel[ch]->SbrDec.WorkBuffer1 = self->workBuffer1; + self->pSbrElement[elementIndex]->pSbrChannel[ch]->SbrDec.WorkBuffer2 = self->workBuffer2; + chCnt++; + } + if (elChannels == 1 && self->pSbrElement[elementIndex]->pSbrChannel[ch] != NULL) { + deleteSbrDec( self->pSbrElement[elementIndex]->pSbrChannel[ch] ); + FreeRam_SbrDecChannel( &self->pSbrElement[elementIndex]->pSbrChannel[ch] ); + } + } + + /* clear error flags for all delay slots */ + FDKmemclear(self->pSbrElement[elementIndex]->frameErrorFlag, ((1)+1)*sizeof(UCHAR)); + + /* Initialize this instance */ + sbrError = sbrDecoder_ResetElement( + self, + sampleRateIn, + sampleRateOut, + samplesPerFrame, + elementID, + elementIndex, + (coreCodec == AOT_ER_AAC_ELD) ? 0 : (6) + ); + + + +bail: + if (sbrError != SBRDEC_OK) { + /* Free the memory allocated for this element */ + sbrDecoder_DestroyElement( self, elementIndex ); + } + + return sbrError; +} + +/** + * \brief Apply decoded SBR header for one element. + * \param self SBR decoder instance handle + * \param hSbrHeader SBR header handle to be processed. + * \param hSbrChannel pointer array to the SBR element channels corresponding to the SBR header. + * \param headerStatus header status value returned from SBR header parser. + * \param numElementChannels amount of channels for the SBR element whos header is to be processed. + */ +static +SBR_ERROR sbrDecoder_HeaderUpdate( + HANDLE_SBRDECODER self, + HANDLE_SBR_HEADER_DATA hSbrHeader, + SBR_HEADER_STATUS headerStatus, + HANDLE_SBR_CHANNEL hSbrChannel[], + const int numElementChannels + ) +{ + SBR_ERROR errorStatus = SBRDEC_OK; + + /* + change of control data, reset decoder + */ + errorStatus = resetFreqBandTables(hSbrHeader, self->flags); + + if (errorStatus == SBRDEC_OK) { + if (hSbrHeader->syncState == UPSAMPLING && headerStatus != HEADER_RESET) + { + /* As the default header would limit the frequency range, + lowSubband and highSubband must be patched. */ + hSbrHeader->freqBandData.lowSubband = hSbrHeader->numberOfAnalysisBands; + hSbrHeader->freqBandData.highSubband = hSbrHeader->numberOfAnalysisBands; + } + + /* Trigger a reset before processing this slot */ + hSbrHeader->status |= SBRDEC_HDR_STAT_RESET; + } + + return errorStatus; +} + +INT sbrDecoder_Header ( + HANDLE_SBRDECODER self, + HANDLE_FDK_BITSTREAM hBs, + const INT sampleRateIn, + const INT sampleRateOut, + const INT samplesPerFrame, + const AUDIO_OBJECT_TYPE coreCodec, + const MP4_ELEMENT_ID elementID, + const INT elementIndex + ) +{ + SBR_HEADER_STATUS headerStatus; + HANDLE_SBR_HEADER_DATA hSbrHeader; + SBR_ERROR sbrError = SBRDEC_OK; + int headerIndex; + + if ( self == NULL || elementIndex > (4) ) + { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + if (! sbrDecoder_isCoreCodecValid(coreCodec)) { + return SBRDEC_UNSUPPORTED_CONFIG; + } + + sbrError = sbrDecoder_InitElement( + self, + sampleRateIn, + sampleRateOut, + samplesPerFrame, + coreCodec, + elementID, + elementIndex + ); + + if (sbrError != SBRDEC_OK) { + goto bail; + } + + headerIndex = getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot, + self->pSbrElement[elementIndex]->useHeaderSlot); + hSbrHeader = &(self->sbrHeader[elementIndex][headerIndex]); + + headerStatus = sbrGetHeaderData ( hSbrHeader, + hBs, + self->flags, + 0); + + + { + SBR_DECODER_ELEMENT *pSbrElement; + + pSbrElement = self->pSbrElement[elementIndex]; + + /* Sanity check */ + if (pSbrElement != NULL) { + if ( (elementID == ID_CPE && pSbrElement->nChannels != 2) + || (elementID != ID_CPE && pSbrElement->nChannels != 1) ) + { + return SBRDEC_UNSUPPORTED_CONFIG; + } + if ( headerStatus == HEADER_RESET ) { + + sbrError = sbrDecoder_HeaderUpdate( + self, + hSbrHeader, + headerStatus, + pSbrElement->pSbrChannel, + pSbrElement->nChannels + ); + + if (sbrError == SBRDEC_OK) { + hSbrHeader->syncState = SBR_HEADER; + hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE; + } + /* else { + Since we already have overwritten the old SBR header the only way out is UPSAMPLING! + This will be prepared in the next step. + } */ + } + } + } +bail: + return sbrError; +} + + +SBR_ERROR sbrDecoder_SetParam (HANDLE_SBRDECODER self, + const SBRDEC_PARAM param, + const INT value ) +{ + SBR_ERROR errorStatus = SBRDEC_OK; + + /* configure the subsystems */ + switch (param) + { + case SBR_SYSTEM_BITSTREAM_DELAY: + if (value < 0 || value > (1)) { + errorStatus = SBRDEC_SET_PARAM_FAIL; + break; + } + if (self == NULL) { + errorStatus = SBRDEC_NOT_INITIALIZED; + } else { + self->numDelayFrames = (UCHAR)value; + } + break; + case SBR_QMF_MODE: + if (self == NULL) { + errorStatus = SBRDEC_NOT_INITIALIZED; + } else { + if (value == 1) { + self->flags |= SBRDEC_LOW_POWER; + } else { + self->flags &= ~SBRDEC_LOW_POWER; + } + } + break; + case SBR_LD_QMF_TIME_ALIGN: + if (self == NULL) { + errorStatus = SBRDEC_NOT_INITIALIZED; + } else { + if (value == 1) { + self->flags |= SBRDEC_LD_MPS_QMF; + } else { + self->flags &= ~SBRDEC_LD_MPS_QMF; + } + } + break; + case SBR_BS_INTERRUPTION: + { + int elementIndex; + /* Loop over SBR elements */ + for (elementIndex = 0; elementIndex < self->numSbrElements; elementIndex++) + { + HANDLE_SBR_HEADER_DATA hSbrHeader; + int headerIndex = getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot, + self->pSbrElement[elementIndex]->useHeaderSlot); + + hSbrHeader = &(self->sbrHeader[elementIndex][headerIndex]); + + /* Set sync state UPSAMPLING for the corresponding slot. + This switches off bitstream parsing until a new header arrives. */ + hSbrHeader->syncState = UPSAMPLING; + hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE; + } + } + break; + default: + errorStatus = SBRDEC_SET_PARAM_FAIL; + break; + } /* switch(param) */ + + return (errorStatus); +} + +static +SBRDEC_DRC_CHANNEL * sbrDecoder_drcGetChannel( const HANDLE_SBRDECODER self, const INT channel ) +{ + SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL; + int elementIndex, elChanIdx=0, numCh=0; + + for (elementIndex = 0; (elementIndex < (4)) && (numCh <= channel); elementIndex++) + { + SBR_DECODER_ELEMENT *pSbrElement = self->pSbrElement[elementIndex]; + int c, elChannels; + + elChanIdx = 0; + if (pSbrElement == NULL) break; + + /* Determine amount of channels for this element */ + switch (pSbrElement->elementID) { + case ID_CPE: elChannels = 2; + break; + case ID_LFE: + case ID_SCE: elChannels = 1; + break; + case ID_NONE: + default: elChannels = 0; + break; + } + + /* Limit with actual allocated element channels */ + elChannels = FDKmin(elChannels, pSbrElement->nChannels); + + for (c = 0; (c < elChannels) && (numCh <= channel); c++) { + if (pSbrElement->pSbrChannel[elChanIdx] != NULL) { + numCh++; + elChanIdx++; + } + } + } + elementIndex -= 1; + elChanIdx -= 1; + + if (elChanIdx < 0 || elementIndex < 0) { + return NULL; + } + + if ( self->pSbrElement[elementIndex] != NULL ) { + if ( self->pSbrElement[elementIndex]->pSbrChannel[elChanIdx] != NULL ) + { + pSbrDrcChannelData = &self->pSbrElement[elementIndex]->pSbrChannel[elChanIdx]->SbrDec.sbrDrcChannel; + } + } + + return (pSbrDrcChannelData); +} + +SBR_ERROR sbrDecoder_drcFeedChannel ( HANDLE_SBRDECODER self, + INT ch, + UINT numBands, + FIXP_DBL *pNextFact_mag, + INT nextFact_exp, + SHORT drcInterpolationScheme, + UCHAR winSequence, + USHORT *pBandTop ) +{ + SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL; + + if (self == NULL) { + return SBRDEC_NOT_INITIALIZED; + } + if (ch > (6) || pNextFact_mag == NULL) { + return SBRDEC_SET_PARAM_FAIL; + } + + /* Find the right SBR channel */ + pSbrDrcChannelData = sbrDecoder_drcGetChannel( self, ch ); + + if ( pSbrDrcChannelData != NULL ) { + int i; + + pSbrDrcChannelData->enable = 1; + pSbrDrcChannelData->numBandsNext = numBands; + + pSbrDrcChannelData->winSequenceNext = winSequence; + pSbrDrcChannelData->drcInterpolationSchemeNext = drcInterpolationScheme; + pSbrDrcChannelData->nextFact_exp = nextFact_exp; + + for (i = 0; i < (int)numBands; i++) { + pSbrDrcChannelData->bandTopNext[i] = pBandTop[i]; + pSbrDrcChannelData->nextFact_mag[i] = pNextFact_mag[i]; + } + } + + return SBRDEC_OK; +} + + +void sbrDecoder_drcDisable ( HANDLE_SBRDECODER self, + INT ch ) +{ + SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL; + + if ( (self == NULL) + || (ch > (6)) + || (self->numSbrElements == 0) + || (self->numSbrChannels == 0) ) { + return; + } + + /* Find the right SBR channel */ + pSbrDrcChannelData = sbrDecoder_drcGetChannel( self, ch ); + + if ( pSbrDrcChannelData != NULL ) { + pSbrDrcChannelData->enable = 0; + } +} + + + +SBR_ERROR sbrDecoder_Parse( + HANDLE_SBRDECODER self, + HANDLE_FDK_BITSTREAM hBs, + int *count, + int bsPayLen, + int crcFlag, + MP4_ELEMENT_ID prevElement, + int elementIndex, + int fGlobalIndependencyFlag + ) +{ + SBR_DECODER_ELEMENT *hSbrElement; + HANDLE_SBR_HEADER_DATA hSbrHeader; + HANDLE_SBR_CHANNEL *pSbrChannel; + + SBR_FRAME_DATA *hFrameDataLeft; + SBR_FRAME_DATA *hFrameDataRight; + + SBR_ERROR errorStatus = SBRDEC_OK; + SBR_SYNC_STATE initialSyncState; + SBR_HEADER_STATUS headerStatus = HEADER_NOT_PRESENT; + + INT startPos; + INT CRCLen = 0; + + int stereo; + int fDoDecodeSbrData = 1; + + int lastSlot, lastHdrSlot = 0, thisHdrSlot; + + /* Remember start position of SBR element */ + startPos = FDKgetValidBits(hBs); + + /* SBR sanity checks */ + if ( self == NULL || self->pSbrElement[elementIndex] == NULL ) { + errorStatus = SBRDEC_NOT_INITIALIZED; + goto bail; + } + + hSbrElement = self->pSbrElement[elementIndex]; + + lastSlot = (hSbrElement->useFrameSlot > 0) ? hSbrElement->useFrameSlot-1 : self->numDelayFrames; + lastHdrSlot = hSbrElement->useHeaderSlot[lastSlot]; + thisHdrSlot = getHeaderSlot( hSbrElement->useFrameSlot, hSbrElement->useHeaderSlot ); /* Get a free header slot not used by frames not processed yet. */ + + /* Assign the free slot to store a new header if there is one. */ + hSbrHeader = &self->sbrHeader[elementIndex][thisHdrSlot]; + + pSbrChannel = hSbrElement->pSbrChannel; + stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0; + + hFrameDataLeft = &self->pSbrElement[elementIndex]->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot]; + hFrameDataRight = &self->pSbrElement[elementIndex]->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot]; + + initialSyncState = hSbrHeader->syncState; + + /* reset PS flag; will be set after PS was found */ + self->flags &= ~SBRDEC_PS_DECODED; + + if (hSbrHeader->status & SBRDEC_HDR_STAT_UPDATE) { + /* Got a new header from extern (e.g. from an ASC) */ + headerStatus = HEADER_OK; + hSbrHeader->status &= ~SBRDEC_HDR_STAT_UPDATE; + } + else if (thisHdrSlot != lastHdrSlot) { + /* Copy the last header into this slot otherwise the + header compare will trigger more HEADER_RESETs than needed. */ + copySbrHeader( hSbrHeader, &self->sbrHeader[elementIndex][lastHdrSlot] ); + } + + /* + Check if bit stream data is valid and matches the element context + */ + if ( ((prevElement != ID_SCE) && (prevElement != ID_CPE)) || prevElement != hSbrElement->elementID) { + /* In case of LFE we also land here, since there is no LFE SBR element (do upsampling only) */ + fDoDecodeSbrData = 0; + } + + if (fDoDecodeSbrData) + { + if ((INT)FDKgetValidBits(hBs) <= 0) { + fDoDecodeSbrData = 0; + } + } + + /* + SBR CRC-check + */ + if (fDoDecodeSbrData) + { + if (crcFlag == 1) { + switch (self->coreCodec) { + case AOT_ER_AAC_ELD: + FDKpushFor (hBs, 10); + /* check sbrcrc later: we don't know the payload length now */ + break; + default: + CRCLen = bsPayLen - 10; /* change: 0 => i */ + if (CRCLen < 0) { + fDoDecodeSbrData = 0; + } else { + fDoDecodeSbrData = SbrCrcCheck (hBs, CRCLen); + } + break; + } + } + } /* if (fDoDecodeSbrData) */ + + /* + Read in the header data and issue a reset if change occured + */ + if (fDoDecodeSbrData) + { + int sbrHeaderPresent; + + { + sbrHeaderPresent = FDKreadBit(hBs); + } + + if ( sbrHeaderPresent ) { + headerStatus = sbrGetHeaderData (hSbrHeader, + hBs, + self->flags, + 1); + } + + if (headerStatus == HEADER_RESET) { + errorStatus = sbrDecoder_HeaderUpdate( + self, + hSbrHeader, + headerStatus, + pSbrChannel, + hSbrElement->nChannels + ); + + if (errorStatus == SBRDEC_OK) { + hSbrHeader->syncState = SBR_HEADER; + } else { + hSbrHeader->syncState = SBR_NOT_INITIALIZED; + } + } + + if (errorStatus != SBRDEC_OK) { + fDoDecodeSbrData = 0; + } + } /* if (fDoDecodeSbrData) */ + + /* + Print debugging output only if state has changed + */ + + /* read frame data */ + if ((hSbrHeader->syncState >= SBR_HEADER) && fDoDecodeSbrData) { + int sbrFrameOk; + /* read the SBR element data */ + if (stereo) { + sbrFrameOk = sbrGetChannelPairElement(hSbrHeader, + hFrameDataLeft, + hFrameDataRight, + hBs, + self->flags, + self->pSbrElement[elementIndex]->transposerSettings.overlap); + } + else { + if (self->hParametricStereoDec != NULL) { + /* update slot index for PS bitstream parsing */ + self->hParametricStereoDec->bsLastSlot = self->hParametricStereoDec->bsReadSlot; + self->hParametricStereoDec->bsReadSlot = hSbrElement->useFrameSlot; + } + sbrFrameOk = sbrGetSingleChannelElement(hSbrHeader, + hFrameDataLeft, + hBs, + self->hParametricStereoDec, + self->flags, + self->pSbrElement[elementIndex]->transposerSettings.overlap); + } + if (!sbrFrameOk) { + fDoDecodeSbrData = 0; + } + else { + INT valBits; + + if (bsPayLen > 0) { + valBits = bsPayLen - ((INT)startPos - (INT)FDKgetValidBits(hBs)); + } else { + valBits = (INT)FDKgetValidBits(hBs); + } + + if ( crcFlag == 1 ) { + switch (self->coreCodec) { + case AOT_ER_AAC_ELD: + { + /* late crc check for eld */ + INT payloadbits = (INT)startPos - (INT)FDKgetValidBits(hBs) - startPos; + INT crcLen = payloadbits - 10; + FDKpushBack(hBs, payloadbits); + fDoDecodeSbrData = SbrCrcCheck (hBs, crcLen); + FDKpushFor(hBs, crcLen); + } + break; + default: + break; + } + } + + /* sanity check of remaining bits */ + if (valBits < 0) { + fDoDecodeSbrData = 0; + } else { + switch (self->coreCodec) { + case AOT_SBR: + case AOT_PS: + case AOT_AAC_LC: + { + /* This sanity check is only meaningful with General Audio bitstreams */ + int alignBits = valBits & 0x7; + + if (valBits > alignBits) { + fDoDecodeSbrData = 0; + } + } + break; + default: + /* No sanity check available */ + break; + } + } + } + } + + if (!fDoDecodeSbrData) { + /* Set error flag for this slot to trigger concealment */ + self->pSbrElement[elementIndex]->frameErrorFlag[hSbrElement->useFrameSlot] = 1; + errorStatus = SBRDEC_PARSE_ERROR; + } else { + /* Everything seems to be ok so clear the error flag */ + self->pSbrElement[elementIndex]->frameErrorFlag[hSbrElement->useFrameSlot] = 0; + } + + if (!stereo) { + /* Turn coupling off explicitely to avoid access to absent right frame data + that might occur with corrupt bitstreams. */ + hFrameDataLeft->coupling = COUPLING_OFF; + } + +bail: + if (errorStatus == SBRDEC_OK) { + if (headerStatus == HEADER_NOT_PRESENT) { + /* Use the old header for this frame */ + hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = lastHdrSlot; + } else { + /* Use the new header for this frame */ + hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = thisHdrSlot; + } + + /* Move frame pointer to the next slot which is up to be decoded/applied next */ + hSbrElement->useFrameSlot = (hSbrElement->useFrameSlot+1) % (self->numDelayFrames+1); + } + + *count -= startPos - FDKgetValidBits(hBs); + + return errorStatus; +} + + +/** + * \brief Render one SBR element into time domain signal. + * \param self SBR decoder handle + * \param timeData pointer to output buffer + * \param interleaved flag indicating interleaved channel output + * \param channelMapping pointer to UCHAR array where next 2 channel offsets are stored. + * \param elementIndex enumerating index of the SBR element to render. + * \param numInChannels number of channels from core coder (reading stride). + * \param numOutChannels pointer to a location to return number of output channels. + * \param psPossible flag indicating if PS is possible or not. + * \return SBRDEC_OK if successfull, else error code + */ +static SBR_ERROR +sbrDecoder_DecodeElement ( + HANDLE_SBRDECODER self, + INT_PCM *timeData, + const int interleaved, + const UCHAR *channelMapping, + const int elementIndex, + const int numInChannels, + int *numOutChannels, + const int psPossible + ) +{ + SBR_DECODER_ELEMENT *hSbrElement = self->pSbrElement[elementIndex]; + HANDLE_SBR_CHANNEL *pSbrChannel = self->pSbrElement[elementIndex]->pSbrChannel; + HANDLE_SBR_HEADER_DATA hSbrHeader = &self->sbrHeader[elementIndex][hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot]]; + HANDLE_PS_DEC h_ps_d = self->hParametricStereoDec; + + /* get memory for frame data from scratch */ + SBR_FRAME_DATA *hFrameDataLeft = &hSbrElement->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot]; + SBR_FRAME_DATA *hFrameDataRight = &hSbrElement->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot]; + + SBR_ERROR errorStatus = SBRDEC_OK; + + + INT strideIn, strideOut, offset0, offset1; + INT codecFrameSize = self->codecFrameSize; + + int stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0; + int numElementChannels = hSbrElement->nChannels; /* Number of channels of the current SBR element */ + + /* Update the header error flag */ + hSbrHeader->frameErrorFlag = hSbrElement->frameErrorFlag[hSbrElement->useFrameSlot]; + + /* + Prepare filterbank for upsampling if no valid bit stream data is available. + */ + if ( hSbrHeader->syncState == SBR_NOT_INITIALIZED ) + { + errorStatus = initHeaderData( + hSbrHeader, + self->sampleRateIn, + self->sampleRateOut, + codecFrameSize, + self->flags + ); + + hSbrHeader->syncState = UPSAMPLING; + + errorStatus = sbrDecoder_HeaderUpdate( + self, + hSbrHeader, + HEADER_NOT_PRESENT, + pSbrChannel, + hSbrElement->nChannels + ); + } + + /* reset */ + if (hSbrHeader->status & SBRDEC_HDR_STAT_RESET) { + int ch; + for (ch = 0 ; ch < numElementChannels; ch++) { + SBR_ERROR errorStatusTmp = SBRDEC_OK; + + errorStatusTmp = resetSbrDec ( + &pSbrChannel[ch]->SbrDec, + hSbrHeader, + &pSbrChannel[ch]->prevFrameData, + self->flags & SBRDEC_LOW_POWER, + self->synDownsampleFac + ); + + if (errorStatusTmp != SBRDEC_OK) { + errorStatus = errorStatusTmp; + } + } + hSbrHeader->status &= ~SBRDEC_HDR_STAT_RESET; + } + + /* decoding */ + if ( (hSbrHeader->syncState == SBR_ACTIVE) + || ((hSbrHeader->syncState == SBR_HEADER) && (hSbrHeader->frameErrorFlag == 0)) ) + { + errorStatus = SBRDEC_OK; + + decodeSbrData (hSbrHeader, + hFrameDataLeft, + &pSbrChannel[0]->prevFrameData, + (stereo) ? hFrameDataRight : NULL, + (stereo) ? &pSbrChannel[1]->prevFrameData : NULL); + + + /* Now we have a full parameter set and can do parameter + based concealment instead of plain upsampling. */ + hSbrHeader->syncState = SBR_ACTIVE; + } + + /* decode PS data if available */ + if (h_ps_d != NULL && psPossible) { + int applyPs = 1; + + /* define which frame delay line slot to process */ + h_ps_d->processSlot = hSbrElement->useFrameSlot; + + applyPs = DecodePs(h_ps_d, hSbrHeader->frameErrorFlag); + self->flags |= (applyPs) ? SBRDEC_PS_DECODED : 0; + } + + /* Set strides for reading and writing */ + if (interleaved) { + strideIn = numInChannels; + if ( psPossible ) + strideOut = (numInChannels < 2) ? 2 : numInChannels; + else + strideOut = numInChannels; + offset0 = channelMapping[0]; + offset1 = channelMapping[1]; + } else { + strideIn = 1; + strideOut = 1; + offset0 = channelMapping[0]*2*codecFrameSize; + offset1 = channelMapping[1]*2*codecFrameSize; + } + + /* use same buffers for left and right channel and apply PS per timeslot */ + /* Process left channel */ +//FDKprintf("self->codecFrameSize %d\t%d\n",self->codecFrameSize,self->sampleRateIn); + sbr_dec (&pSbrChannel[0]->SbrDec, + timeData + offset0, + timeData + offset0, + &pSbrChannel[1]->SbrDec, + timeData + offset1, + strideIn, + strideOut, + hSbrHeader, + hFrameDataLeft, + &pSbrChannel[0]->prevFrameData, + (hSbrHeader->syncState == SBR_ACTIVE), + h_ps_d, + self->flags + ); + + if (stereo) { + /* Process right channel */ + sbr_dec (&pSbrChannel[1]->SbrDec, + timeData + offset1, + timeData + offset1, + NULL, + NULL, + strideIn, + strideOut, + hSbrHeader, + hFrameDataRight, + &pSbrChannel[1]->prevFrameData, + (hSbrHeader->syncState == SBR_ACTIVE), + NULL, + self->flags + ); + } + + if (h_ps_d != NULL) { + /* save PS status for next run */ + h_ps_d->psDecodedPrv = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0 ; + } + + if ( psPossible + ) + { + FDK_ASSERT(strideOut > 1); + if ( !(self->flags & SBRDEC_PS_DECODED) ) { + /* A decoder which is able to decode PS has to produce a stereo output even if no PS data is availble. */ + /* So copy left channel to right channel. */ + if (interleaved) { + INT_PCM *ptr; + INT i; + FDK_ASSERT(strideOut == 2); + + ptr = timeData; + for (i = codecFrameSize; i--; ) + { + INT_PCM tmp; /* This temporal variable is required because some compilers can't do *ptr++ = *ptr++ correctly. */ + tmp = *ptr++; *ptr++ = tmp; + tmp = *ptr++; *ptr++ = tmp; + } + } else { + FDKmemcpy( timeData+2*codecFrameSize, timeData, 2*codecFrameSize*sizeof(INT_PCM) ); + } + } + *numOutChannels = 2; /* Output minimum two channels when PS is enabled. */ + } + + return errorStatus; +} + + +SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self, + INT_PCM *timeData, + int *numChannels, + int *sampleRate, + const UCHAR channelMapping[(6)], + const int interleaved, + const int coreDecodedOk, + UCHAR *psDecoded ) +{ + SBR_ERROR errorStatus = SBRDEC_OK; + + int psPossible = 0; + int sbrElementNum; + int numCoreChannels = *numChannels; + int numSbrChannels = 0; + + psPossible = *psDecoded; + + /* Sanity check of allocated SBR elements. */ + for (sbrElementNum=0; sbrElementNum<self->numSbrElements; sbrElementNum++) { + if (self->pSbrElement[sbrElementNum] == NULL) { + return SBRDEC_CREATE_ERROR; + } + } + + if (self->numSbrElements != 1 || self->pSbrElement[0]->elementID != ID_SCE) { + psPossible = 0; + } + + + /* In case of non-interleaved time domain data and upsampling, make room for bigger SBR output. */ + if (self->synDownsampleFac == 1 && interleaved == 0) { + int c, outputFrameSize; + + outputFrameSize = + self->pSbrElement[0]->pSbrChannel[0]->SbrDec.SynthesisQMF.no_channels + * self->pSbrElement[0]->pSbrChannel[0]->SbrDec.SynthesisQMF.no_col; + + for (c=numCoreChannels-1; c>0; c--) { + FDKmemmove(timeData + c*outputFrameSize, timeData + c*self->codecFrameSize , self->codecFrameSize*sizeof(INT_PCM)); + } + } + + + /* Make sure that even if no SBR data was found/parsed *psDecoded is returned 1 if psPossible was 0. */ + if (psPossible == 0) { + self->flags &= ~SBRDEC_PS_DECODED; + } + + /* Loop over SBR elements */ + for (sbrElementNum = 0; sbrElementNum<self->numSbrElements; sbrElementNum++) + { + int numElementChan; + + if (psPossible && self->pSbrElement[sbrElementNum]->pSbrChannel[1] == NULL) { + errorStatus = SBRDEC_UNSUPPORTED_CONFIG; + goto bail; + } + + numElementChan = (self->pSbrElement[sbrElementNum]->elementID == ID_CPE) ? 2 : 1; + + /* If core signal is bad then force upsampling */ + if ( ! coreDecodedOk ) { + self->pSbrElement[sbrElementNum]->frameErrorFlag[self->pSbrElement[sbrElementNum]->useFrameSlot] = 1; + } + + errorStatus = sbrDecoder_DecodeElement ( + self, + timeData, + interleaved, + channelMapping, + sbrElementNum, + numCoreChannels, + &numElementChan, + psPossible + ); + + if (errorStatus != SBRDEC_OK) { + goto bail; + } + + numSbrChannels += numElementChan; + channelMapping += numElementChan; + + if (numSbrChannels >= numCoreChannels) { + break; + } + } + + /* Update numChannels and samplerate */ + *numChannels = numSbrChannels; + *sampleRate = self->sampleRateOut; + *psDecoded = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0; + + + +bail: + + return errorStatus; +} + + +SBR_ERROR sbrDecoder_Close ( HANDLE_SBRDECODER *pSelf ) +{ + HANDLE_SBRDECODER self = *pSelf; + int i; + + if (self != NULL) + { + if (self->hParametricStereoDec != NULL) { + DeletePsDec ( &self->hParametricStereoDec ); + } + + if (self->workBuffer1 != NULL) { + FreeRam_SbrDecWorkBuffer1(&self->workBuffer1); + } + if (self->workBuffer2 != NULL) { + FreeRam_SbrDecWorkBuffer2(&self->workBuffer2); + } + + for (i = 0; i < (4); i++) { + sbrDecoder_DestroyElement( self, i ); + } + + FreeRam_SbrDecoder(pSelf); + } + + return SBRDEC_OK; +} + + +INT sbrDecoder_GetLibInfo( LIB_INFO *info ) +{ + int i; + + if (info == NULL) { + return -1; + } + + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) + break; + } + if (i == FDK_MODULE_LAST) + return -1; + info += i; + + info->module_id = FDK_SBRDEC; + info->version = LIB_VERSION(SBRDECODER_LIB_VL0, SBRDECODER_LIB_VL1, SBRDECODER_LIB_VL2); + LIB_VERSION_STRING(info); + info->build_date = (char *)SBRDECODER_LIB_BUILD_DATE; + info->build_time = (char *)SBRDECODER_LIB_BUILD_TIME; + info->title = (char *)SBRDECODER_LIB_TITLE; + + /* Set flags */ + info->flags = 0 + | CAPF_SBR_HQ + | CAPF_SBR_LP + | CAPF_SBR_PS_MPEG + | CAPF_SBR_CONCEALMENT + | CAPF_SBR_DRC + ; + /* End of flags */ + + return 0; +} + diff --git a/libSBRdec/src/transcendent.h b/libSBRdec/src/transcendent.h new file mode 100644 index 0000000..fae36d6 --- /dev/null +++ b/libSBRdec/src/transcendent.h @@ -0,0 +1,313 @@ +/**************************************************************************** + + (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 FDK Fixed Point Arithmetic Library Interface $Revision: 36841 $ +*/ + +/*! + \mainpage Fixed Point Arithmetic Library Documentation + + Information in this SDK is subject to change without notice. Companies, + names, and data used in examples herein are fictitious unless otherwise + noted. + + Product and corporate names may be trademarks or registered trademarks + of other companies. They are used for explanation only, with no intent + to infringe. + + No part of this publication may be reproduced or utilized in any form or + by any means, electronic or mechanical, including photocopying and + microfilm, without permission in writing from the publisher. +*/ + +#ifndef __TRANSCENDENT_H +#define __TRANSCENDENT_H + +#include "sbrdecoder.h" +#include "sbr_rom.h" + +/************************************************************************/ +/*! + \brief Get number of octaves between frequencies a and b + + The Result is scaled with 1/8. + The valid range for a and b is 1 to LOG_DUALIS_TABLE_SIZE. + + \return ld(a/b) / 8 +*/ +/************************************************************************/ +static inline FIXP_SGL FDK_getNumOctavesDiv8(INT a, /*!< lower band */ + INT b) /*!< upper band */ +{ + return ( (SHORT)((LONG)(CalcLdInt(b) - CalcLdInt(a))>>(FRACT_BITS-3)) ); +} + + +/************************************************************************/ +/*! + \brief Add two values given by mantissa and exponent. + + Mantissas are in fract format with values between 0 and 1. <br> + The base for exponents is 2. Example: \f$ a = a\_m * 2^{a\_e} \f$<br> +*/ +/************************************************************************/ +inline void FDK_add_MantExp(FIXP_SGL a_m, /*!< Mantissa of 1st operand a */ + SCHAR a_e, /*!< Exponent of 1st operand a */ + FIXP_SGL b_m, /*!< Mantissa of 2nd operand b */ + SCHAR b_e, /*!< Exponent of 2nd operand b */ + FIXP_SGL *ptrSum_m, /*!< Mantissa of result */ + SCHAR *ptrSum_e) /*!< Exponent of result */ +{ + FIXP_DBL accu; + int shift; + int shiftAbs; + + FIXP_DBL shiftedMantissa; + FIXP_DBL otherMantissa; + + /* Equalize exponents of the summands. + For the smaller summand, the exponent is adapted and + for compensation, the mantissa is shifted right. */ + + shift = (int)(a_e - b_e); + + shiftAbs = (shift>0)? shift : -shift; + shiftAbs = (shiftAbs < DFRACT_BITS-1)? shiftAbs : DFRACT_BITS-1; + shiftedMantissa = (shift>0)? (FX_SGL2FX_DBL(b_m) >> shiftAbs) : (FX_SGL2FX_DBL(a_m) >> shiftAbs); + otherMantissa = (shift>0)? FX_SGL2FX_DBL(a_m) : FX_SGL2FX_DBL(b_m); + *ptrSum_e = (shift>0)? a_e : b_e; + + accu = (shiftedMantissa >> 1) + (otherMantissa >> 1); + /* shift by 1 bit to avoid overflow */ + + if ( (accu >= (FL2FXCONST_DBL(0.5f) - (FIXP_DBL)1)) || (accu <= FL2FXCONST_DBL(-0.5f)) ) + *ptrSum_e += 1; + else + accu = (shiftedMantissa + otherMantissa); + + *ptrSum_m = FX_DBL2FX_SGL(accu); + +} + +inline void FDK_add_MantExp(FIXP_DBL a, /*!< Mantissa of 1st operand a */ + SCHAR a_e, /*!< Exponent of 1st operand a */ + FIXP_DBL b, /*!< Mantissa of 2nd operand b */ + SCHAR b_e, /*!< Exponent of 2nd operand b */ + FIXP_DBL *ptrSum, /*!< Mantissa of result */ + SCHAR *ptrSum_e) /*!< Exponent of result */ +{ + FIXP_DBL accu; + int shift; + int shiftAbs; + + FIXP_DBL shiftedMantissa; + FIXP_DBL otherMantissa; + + /* Equalize exponents of the summands. + For the smaller summand, the exponent is adapted and + for compensation, the mantissa is shifted right. */ + + shift = (int)(a_e - b_e); + + shiftAbs = (shift>0)? shift : -shift; + shiftAbs = (shiftAbs < DFRACT_BITS-1)? shiftAbs : DFRACT_BITS-1; + shiftedMantissa = (shift>0)? (b >> shiftAbs) : (a >> shiftAbs); + otherMantissa = (shift>0)? a : b; + *ptrSum_e = (shift>0)? a_e : b_e; + + accu = (shiftedMantissa >> 1) + (otherMantissa >> 1); + /* shift by 1 bit to avoid overflow */ + + if ( (accu >= (FL2FXCONST_DBL(0.5f) - (FIXP_DBL)1)) || (accu <= FL2FXCONST_DBL(-0.5f)) ) + *ptrSum_e += 1; + else + accu = (shiftedMantissa + otherMantissa); + + *ptrSum = accu; + +} + +/************************************************************************/ +/*! + \brief Divide two values given by mantissa and exponent. + + Mantissas are in fract format with values between 0 and 1. <br> + The base for exponents is 2. Example: \f$ a = a\_m * 2^{a\_e} \f$<br> + + For performance reasons, the division is based on a table lookup + which limits accuracy. +*/ +/************************************************************************/ +static inline void FDK_divide_MantExp(FIXP_SGL a_m, /*!< Mantissa of dividend a */ + SCHAR a_e, /*!< Exponent of dividend a */ + FIXP_SGL b_m, /*!< Mantissa of divisor b */ + SCHAR b_e, /*!< Exponent of divisor b */ + FIXP_SGL *ptrResult_m, /*!< Mantissa of quotient a/b */ + SCHAR *ptrResult_e) /*!< Exponent of quotient a/b */ + +{ + int preShift, postShift, index, shift; + FIXP_DBL ratio_m; + FIXP_SGL bInv_m = FL2FXCONST_SGL(0.0f); + + preShift = CntLeadingZeros(FX_SGL2FX_DBL(b_m)); + + /* + Shift b into the range from 0..INV_TABLE_SIZE-1, + + E.g. 10 bits must be skipped for INV_TABLE_BITS 8: + - leave 8 bits as index for table + - skip sign bit, + - skip first bit of mantissa, because this is always the same (>0.5) + + We are dealing with energies, so we need not care + about negative numbers + */ + + /* + The first interval has half width so the lowest bit of the index is + needed for a doubled resolution. + */ + shift = (FRACT_BITS - 2 - INV_TABLE_BITS - preShift); + + index = (shift<0)? (LONG)b_m << (-shift) : (LONG)b_m >> shift; + + + /* The index has INV_TABLE_BITS +1 valid bits here. Clear the other bits. */ + index &= (1 << (INV_TABLE_BITS+1)) - 1; + + /* Remove offset of half an interval */ + index--; + + /* Now the lowest bit is shifted out */ + index = index >> 1; + + /* Fetch inversed mantissa from table: */ + bInv_m = (index<0)? bInv_m : FDK_sbrDecoder_invTable[index]; + + /* Multiply a with the inverse of b: */ + ratio_m = (index<0)? FX_SGL2FX_DBL(a_m >> 1) : fMultDiv2(bInv_m,a_m); + + postShift = CntLeadingZeros(ratio_m)-1; + + *ptrResult_m = FX_DBL2FX_SGL(ratio_m << postShift); + *ptrResult_e = a_e - b_e + 1 + preShift - postShift; +} + +static inline void FDK_divide_MantExp(FIXP_DBL a_m, /*!< Mantissa of dividend a */ + SCHAR a_e, /*!< Exponent of dividend a */ + FIXP_DBL b_m, /*!< Mantissa of divisor b */ + SCHAR b_e, /*!< Exponent of divisor b */ + FIXP_DBL *ptrResult_m, /*!< Mantissa of quotient a/b */ + SCHAR *ptrResult_e) /*!< Exponent of quotient a/b */ + +{ + int preShift, postShift, index, shift; + FIXP_DBL ratio_m; + FIXP_SGL bInv_m = FL2FXCONST_SGL(0.0f); + + preShift = CntLeadingZeros(b_m); + + /* + Shift b into the range from 0..INV_TABLE_SIZE-1, + + E.g. 10 bits must be skipped for INV_TABLE_BITS 8: + - leave 8 bits as index for table + - skip sign bit, + - skip first bit of mantissa, because this is always the same (>0.5) + + We are dealing with energies, so we need not care + about negative numbers + */ + + /* + The first interval has half width so the lowest bit of the index is + needed for a doubled resolution. + */ + shift = (DFRACT_BITS - 2 - INV_TABLE_BITS - preShift); + + index = (shift<0)? (LONG)b_m << (-shift) : (LONG)b_m >> shift; + + + /* The index has INV_TABLE_BITS +1 valid bits here. Clear the other bits. */ + index &= (1 << (INV_TABLE_BITS+1)) - 1; + + /* Remove offset of half an interval */ + index--; + + /* Now the lowest bit is shifted out */ + index = index >> 1; + + /* Fetch inversed mantissa from table: */ + bInv_m = (index<0)? bInv_m : FDK_sbrDecoder_invTable[index]; + + /* Multiply a with the inverse of b: */ + ratio_m = (index<0)? (a_m >> 1) : fMultDiv2(bInv_m,a_m); + + postShift = CntLeadingZeros(ratio_m)-1; + + *ptrResult_m = ratio_m << postShift; + *ptrResult_e = a_e - b_e + 1 + preShift - postShift; +} + +/*! + \brief Calculate the squareroot of a number given by mantissa and exponent + + Mantissa is in fract format with values between 0 and 1. <br> + The base for the exponent is 2. Example: \f$ a = a\_m * 2^{a\_e} \f$<br> + The operand is addressed via pointers and will be overwritten with the result. + + For performance reasons, the square root is based on a table lookup + which limits accuracy. +*/ +static inline void FDK_sqrt_MantExp(FIXP_DBL *mantissa, /*!< Pointer to mantissa */ + SCHAR *exponent, + const SCHAR *destScale) +{ + FIXP_DBL input_m = *mantissa; + int input_e = (int) *exponent; + FIXP_DBL result = FL2FXCONST_DBL(0.0f); + int result_e = -FRACT_BITS; + + /* Call lookup square root, which does internally normalization. */ + result = sqrtFixp_lookup(input_m, &input_e); + result_e = input_e; + + /* Write result */ + if (exponent==destScale) { + *mantissa = result; + *exponent = result_e; + } else { + int shift = result_e - *destScale; + *mantissa = (shift>=0) ? result << (INT)fixMin(DFRACT_BITS-1,shift) + : result >> (INT)fixMin(DFRACT_BITS-1,-shift); + *exponent = *destScale; + } +} + + +#endif |