summaryrefslogtreecommitdiffstats
path: root/libSBRdec/src/sbr_dec.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2012-07-11 10:15:24 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2012-07-11 10:15:24 -0700
commit2228e360595641dd906bf1773307f43d304f5b2e (patch)
tree57f3d390ebb0782cc0de0fb984c8ea7e45b4f386 /libSBRdec/src/sbr_dec.cpp
downloadfdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.tar.gz
fdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.tar.bz2
fdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.zip
Snapshot 2bda038c163298531d47394bc2c09e1409c5d0db
Change-Id: If584e579464f28b97d50e51fc76ba654a5536c54
Diffstat (limited to 'libSBRdec/src/sbr_dec.cpp')
-rw-r--r--libSBRdec/src/sbr_dec.cpp1046
1 files changed, 1046 insertions, 0 deletions
diff --git a/libSBRdec/src/sbr_dec.cpp b/libSBRdec/src/sbr_dec.cpp
new file mode 100644
index 0000000..208120c
--- /dev/null
+++ b/libSBRdec/src/sbr_dec.cpp
@@ -0,0 +1,1046 @@
+
+/* -----------------------------------------------------------------------------------------------------------
+Software License for The Fraunhofer FDK AAC Codec Library for Android
+
+© Copyright 1995 - 2012 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
+ All rights reserved.
+
+ 1. INTRODUCTION
+The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
+the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
+This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
+
+AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
+audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
+independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
+of the MPEG specifications.
+
+Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
+may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
+individually for the purpose of encoding or decoding bit streams in products that are compliant with
+the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
+these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
+software may already be covered under those patent licenses when it is used for those licensed purposes only.
+
+Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
+are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
+applications information and documentation.
+
+2. COPYRIGHT LICENSE
+
+Redistribution and use in source and binary forms, with or without modification, are permitted without
+payment of copyright license fees provided that you satisfy the following conditions:
+
+You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
+your modifications thereto in source code form.
+
+You must retain the complete text of this software license in the documentation and/or other materials
+provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
+You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
+modifications thereto to recipients of copies in binary form.
+
+The name of Fraunhofer may not be used to endorse or promote products derived from this library without
+prior written permission.
+
+You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
+software or your modifications thereto.
+
+Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
+and the date of any change. For modified versions of the FDK AAC Codec, the term
+"Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
+"Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
+
+3. NO PATENT LICENSE
+
+NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
+ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
+respect to this software.
+
+You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
+by appropriate patent licenses.
+
+4. DISCLAIMER
+
+This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
+"AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
+of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
+including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
+or business interruption, however caused and on any theory of liability, whether in contract, strict
+liability, or tort (including negligence), arising in any way out of the use of this software, even if
+advised of the possibility of such damage.
+
+5. CONTACT INFORMATION
+
+Fraunhofer Institute for Integrated Circuits IIS
+Attention: Audio and Multimedia Departments - FDK AAC LL
+Am Wolfsmantel 33
+91058 Erlangen, Germany
+
+www.iis.fraunhofer.de/amm
+amm-info@iis.fraunhofer.de
+----------------------------------------------------------------------------------------------------------- */
+
+/*!
+ \file
+ \brief Sbr decoder
+ 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(&degreeAlias[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;
+ }
+
+ /* copy DRC data to right channel (with PS both channels use the same DRC gains) */
+ FDKmemcpy(&hSbrDecRight->sbrDrcChannel, &hSbrDec->sbrDrcChannel, sizeof(SBRDEC_DRC_CHANNEL));
+
+ 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 */
+ &hSbrDecRight->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;
+}