aboutsummaryrefslogtreecommitdiffstats
path: root/libSBRdec/src/sbr_dec.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libSBRdec/src/sbr_dec.cpp')
-rw-r--r--libSBRdec/src/sbr_dec.cpp1854
1 files changed, 1118 insertions, 736 deletions
diff --git a/libSBRdec/src/sbr_dec.cpp b/libSBRdec/src/sbr_dec.cpp
index 0864348..2e18e6c 100644
--- a/libSBRdec/src/sbr_dec.cpp
+++ b/libSBRdec/src/sbr_dec.cpp
@@ -1,74 +1,85 @@
-
-/* -----------------------------------------------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
Software License for The Fraunhofer FDK AAC Codec Library for Android
-© Copyright 1995 - 2015 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
- All rights reserved.
+© Copyright 1995 - 2018 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.
+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:
+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 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
+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.
+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.
+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."
+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.
+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.
+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.
+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
@@ -79,19 +90,28 @@ Am Wolfsmantel 33
www.iis.fraunhofer.de/amm
amm-info@iis.fraunhofer.de
------------------------------------------------------------------------------------------------------------ */
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
/*!
\file
- \brief Sbr decoder
- This module provides the actual decoder implementation. The SBR data (side information) is already
- decoded. Only three functions are provided:
+ \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].
+ \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
*/
@@ -102,178 +122,90 @@ amm-info@iis.fraunhofer.de
#include "env_extr.h"
#include "env_calc.h"
#include "scale.h"
+#include "FDK_matrixCalloc.h"
+#include "hbe.h"
#include "genericStds.h"
#include "sbrdec_drc.h"
+static void copyHarmonicSpectrum(int *xOverQmf, FIXP_DBL **qmfReal,
+ FIXP_DBL **qmfImag, int noCols, int overlap,
+ KEEP_STATES_SYNCED_MODE keepStatesSynced) {
+ int patchBands;
+ int patch, band, col, target, sourceBands, i;
+ int numPatches = 0;
+ int slotOffset = 0;
+ FIXP_DBL **ppqmfReal = qmfReal + overlap;
+ FIXP_DBL **ppqmfImag = qmfImag + overlap;
-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);
+ if (keepStatesSynced == KEEP_STATES_SYNCED_NORMAL) {
+ slotOffset = noCols - overlap - LPC_ORDER;
}
-}
-
-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 );
+ if (keepStatesSynced == KEEP_STATES_SYNCED_OUTDIFF) {
+ ppqmfReal = qmfReal;
+ ppqmfImag = qmfImag;
}
-}
-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;
+ for (i = 1; i < MAX_NUM_PATCHES; i++) {
+ if (xOverQmf[i] != 0) {
+ numPatches++;
}
}
- if (resetAnaQmf) {
- QMF_FILTER_BANK prvAnaQmf;
- int qmfErr;
-
- /* Store current configuration */
- FDKmemcpy(&prvAnaQmf, &hSbrDec->AnalysiscQMF, sizeof(QMF_FILTER_BANK));
-
- /* Reset analysis QMF */
- 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) {
- /* Restore old configuration of analysis QMF */
- FDKmemcpy(&hSbrDec->AnalysiscQMF, &prvAnaQmf, sizeof(QMF_FILTER_BANK));
- }
- }
+ for (patch = (MAX_STRETCH_HBE - 1); patch < numPatches; patch++) {
+ patchBands = xOverQmf[patch + 1] - xOverQmf[patch];
+ target = xOverQmf[patch];
+ sourceBands = xOverQmf[MAX_STRETCH_HBE - 1] - xOverQmf[MAX_STRETCH_HBE - 2];
- if (resetSynQmf) {
- QMF_FILTER_BANK prvSynQmf;
- int qmfErr;
-
- /* Store current configuration */
- FDKmemcpy(&prvSynQmf, &hSbrDec->SynthesisQMF, sizeof(QMF_FILTER_BANK));
-
- /* Reset synthesis QMF */
- 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) {
- /* Restore old configuration of synthesis QMF */
- FDKmemcpy(&hSbrDec->SynthesisQMF, &prvSynQmf, sizeof(QMF_FILTER_BANK));
+ while (patchBands > 0) {
+ int numBands = sourceBands;
+ int startBand = xOverQmf[MAX_STRETCH_HBE - 1] - 1;
+ if (target + numBands >= xOverQmf[patch + 1]) {
+ numBands = xOverQmf[patch + 1] - target;
+ }
+ if ((((target + numBands - 1) % 2) +
+ ((xOverQmf[MAX_STRETCH_HBE - 1] - 1) % 2)) %
+ 2) {
+ if (numBands == sourceBands) {
+ numBands--;
+ } else {
+ startBand--;
+ }
+ }
+ if (keepStatesSynced == KEEP_STATES_SYNCED_OUTDIFF) {
+ for (col = slotOffset; col < overlap + LPC_ORDER; col++) {
+ i = 0;
+ for (band = numBands; band > 0; band--) {
+ if ((target + band - 1 < 64) &&
+ (target + band - 1 < xOverQmf[patch + 1])) {
+ ppqmfReal[col][target + band - 1] = ppqmfReal[col][startBand - i];
+ ppqmfImag[col][target + band - 1] = ppqmfImag[col][startBand - i];
+ i++;
+ }
+ }
+ }
+ } else {
+ for (col = slotOffset; col < noCols; col++) {
+ i = 0;
+ for (band = numBands; band > 0; band--) {
+ if ((target + band - 1 < 64) &&
+ (target + band - 1 < xOverQmf[patch + 1])) {
+ ppqmfReal[col][target + band - 1] = ppqmfReal[col][startBand - i];
+ ppqmfImag[col][target + band - 1] = ppqmfImag[col][startBand - i];
+ i++;
+ }
+ }
+ }
+ }
+ target += numBands;
+ patchBands -= numBands;
}
}
}
-
/*!
\brief SBR decoder core function for one channel
@@ -283,26 +215,26 @@ static void changeQmfType( HANDLE_SBR_DEC hSbrDec, /*!< hand
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
+ static overlap buffer is required for each channel. Due 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
+ The spectral data is organized in so-called slots. Each slot
+ contains 64 bands of complex data. The number of slots per frame
+ depends 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
+ 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
+ 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
+ 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.
@@ -325,73 +257,77 @@ static void changeQmfType( HANDLE_SBR_DEC hSbrDec, /*!< hand
*/
-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,
- const int codecFrameSize
- )
-{
+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 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, const int codecFrameSize) {
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;
+ /* temporary pointer / variable for QMF;
+ required as we want to use temporary buffer
+ creating one frame delay for HBE in LP mode */
+ INT_PCM *pTimeInQmf = timeIn;
- /* Number of QMF timeslots in the overlap buffer: */
- ov_len = hSbrDec->LppTrans.pSettings->overlap;
+ /* Number of QMF timeslots in the overlap buffer: */
+ int ov_len = hSbrDec->LppTrans.pSettings->overlap;
- /* Number of QMF slots per frame */
+ /* 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);
+ /* create pointer array for data to use for HBE and legacy sbr */
+ FIXP_DBL *pLowBandReal[(3 * 4) + 2 * ((1024) / (32) * (4) / 2)];
+ FIXP_DBL *pLowBandImag[(3 * 4) + 2 * ((1024) / (32) * (4) / 2)];
+
+ /* set pReal to where QMF analysis writes in case of legacy SBR */
+ FIXP_DBL **pReal = pLowBandReal + ov_len;
+ FIXP_DBL **pImag = pLowBandImag + ov_len;
+
+ /* map QMF buffer to pointer array (Overlap + Frame)*/
+ for (i = 0; i < noCols + ov_len; i++) {
+ pLowBandReal[i] = hSbrDec->qmfDomainInCh->hQmfSlotsReal[i];
+ pLowBandImag[i] = hSbrDec->qmfDomainInCh->hQmfSlotsImag[i];
}
- if (flags & SBRDEC_ELD_GRID) {
- /* Choose the right low delay filter bank */
- changeQmfType( hSbrDec, (flags & SBRDEC_LD_MPS_QMF) ? 1 : 0 );
+ if ((flags & SBRDEC_USAC_HARMONICSBR)) {
+ /* in case of harmonic SBR and no HBE_LP map additional buffer for
+ one more frame to pointer arry */
+ for (i = 0; i < noCols; i++) {
+ pLowBandReal[i + noCols + ov_len] = hSbrDec->hQmfHBESlotsReal[i];
+ pLowBandImag[i + noCols + ov_len] = hSbrDec->hQmfHBESlotsImag[i];
+ }
- /* If the LD-MPS QMF is not available delay the signal by (96-48*ldSbrSamplingRate)
- * samples according to ISO/IEC 14496-3:2009/FDAM 2:2010(E) chapter 4.5.2.13. */
- if ( (flags & SBRDEC_LD_MPS_QMF)
- && (hSbrDec->AnalysiscQMF.flags & QMF_FLAG_CLDFB) )
- {
- INT_PCM *pDlyBuf = hSbrDec->coreDelayBuf; /* DLYBUF */
- int smpl, delay = 96 >> (!(flags & SBRDEC_DOWNSAMPLE) ? 1 : 0);
- /* Create TMPBUF */
- C_AALLOC_SCRATCH_START(pcmTemp, INT_PCM, (96));
- /* Copy delay samples from INBUF to TMPBUF */
- for (smpl = 0; smpl < delay; smpl += 1) {
- pcmTemp[smpl] = timeIn[(codecFrameSize-delay+smpl)*strideIn];
- }
- /* Move input signal remainder to the very end of INBUF */
- for (smpl = (codecFrameSize-delay-1)*strideIn; smpl >= 0; smpl -= strideIn) {
- timeIn[smpl+delay] = timeIn[smpl];
- }
- /* Copy delayed samples from last frame from DLYBUF to the very beginning of INBUF */
- for (smpl = 0; smpl < delay; smpl += 1) {
- timeIn[smpl*strideIn] = pDlyBuf[smpl];
+ /* shift scale values according to buffer */
+ hSbrDec->scale_ov = hSbrDec->scale_lb;
+ hSbrDec->scale_lb = hSbrDec->scale_hbe;
+
+ /* set pReal to where QMF analysis writes in case of HBE */
+ pReal += noCols;
+ pImag += noCols;
+ if (flags & SBRDEC_SKIP_QMF_ANA) {
+ /* stereoCfgIndex3 with HBE */
+ FDK_QmfDomain_QmfData2HBE(hSbrDec->qmfDomainInCh,
+ hSbrDec->hQmfHBESlotsReal,
+ hSbrDec->hQmfHBESlotsImag);
+ } else {
+ /* We have to move old hbe frame data to lb area of buffer */
+ for (i = 0; i < noCols; i++) {
+ FDKmemcpy(pLowBandReal[ov_len + i], hSbrDec->hQmfHBESlotsReal[i],
+ hHeaderData->numberOfAnalysisBands * sizeof(FIXP_DBL));
+ FDKmemcpy(pLowBandImag[ov_len + i], hSbrDec->hQmfHBESlotsImag[i],
+ hHeaderData->numberOfAnalysisBands * sizeof(FIXP_DBL));
}
- /* Copy TMPBUF to DLYBUF */
- FDKmemcpy(pDlyBuf, pcmTemp, delay*sizeof(INT_PCM));
- /* Destory TMPBUF */
- C_AALLOC_SCRATCH_END(pcmTemp, INT_PCM, (96));
}
}
@@ -399,234 +335,437 @@ sbr_dec ( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */
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));
+ if (flags & SBRDEC_SKIP_QMF_ANA) {
+ if (!(flags & SBRDEC_USAC_HARMONICSBR)) /* stereoCfgIndex3 w/o HBE */
+ FDK_QmfDomain_WorkBuffer2ProcChannel(hSbrDec->qmfDomainInCh);
+ } else {
+ C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2 * (64));
+ qmfAnalysisFiltering(&hSbrDec->qmfDomainInCh->fb, pReal, pImag,
+ &hSbrDec->qmfDomainInCh->scaling, pTimeInQmf, 0, 1,
+ qmfTemp);
+
+ C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2 * (64));
}
/*
Clear upper half of spectrum
*/
- {
+ if (!((flags & SBRDEC_USAC_HARMONICSBR) &&
+ (hFrameData->sbrPatchingMode == 0))) {
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));
+ if (!(flags & SBRDEC_LOW_POWER)) {
+ for (slot = ov_len; slot < noCols + ov_len; slot++) {
+ FDKmemclear(&pLowBandReal[slot][nAnalysisBands],
+ ((64) - nAnalysisBands) * sizeof(FIXP_DBL));
+ FDKmemclear(&pLowBandImag[slot][nAnalysisBands],
+ ((64) - nAnalysisBands) * sizeof(FIXP_DBL));
+ }
+ } else {
+ for (slot = ov_len; slot < noCols + ov_len; slot++) {
+ FDKmemclear(&pLowBandReal[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 );
+ /* Range was increased from lsb to no_channels because in some cases (e.g.
+ USAC conf eSbr_4_Pvc.mp4 and some HBE cases) it could be observed that the
+ signal between lsb and no_channels is used for the patching process.
+ */
+ maxVal = maxSubbandSample(pReal, (flags & SBRDEC_LOW_POWER) ? NULL : pImag, 0,
+ hSbrDec->qmfDomainInCh->fb.no_channels, 0, noCols);
- reserve = fixMax(0,CntLeadingZeros(maxVal)-1) ;
- reserve = fixMin(reserve,DFRACT_BITS-1-hSbrDec->sbrScaleFactor.lb_scale);
+ reserve = fixMax(0, CntLeadingZeros(maxVal) - 1);
+ reserve = fixMin(reserve,
+ DFRACT_BITS - 1 - hSbrDec->qmfDomainInCh->scaling.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);
+ rescaleSubbandSamples(pReal, (flags & SBRDEC_LOW_POWER) ? NULL : pImag, 0,
+ hSbrDec->qmfDomainInCh->fb.no_channels, 0, noCols,
+ reserve);
- hSbrDec->sbrScaleFactor.lb_scale += reserve;
+ hSbrDec->qmfDomainInCh->scaling.lb_scale += reserve;
+ if ((flags & SBRDEC_USAC_HARMONICSBR)) {
+ /* actually this is our hbe_scale */
+ hSbrDec->scale_hbe = hSbrDec->qmfDomainInCh->scaling.lb_scale;
+ /* the real lb_scale is stored in scale_lb from sbr */
+ hSbrDec->qmfDomainInCh->scaling.lb_scale = hSbrDec->scale_lb;
+ }
/*
save low band scale, wavecoding or parametric stereo may modify it
*/
- saveLbScale = hSbrDec->sbrScaleFactor.lb_scale;
+ saveLbScale = hSbrDec->qmfDomainInCh->scaling.lb_scale;
-
- if (applyProcessing)
- {
- UCHAR * borders = hFrameData->frameInfo.borders;
- lastSlotOffs = borders[hFrameData->frameInfo.nEnvelopes] - hHeaderData->numberTimeSlots;
+ if (applyProcessing) {
+ UCHAR *borders = hFrameData->frameInfo.borders;
+ lastSlotOffs = borders[hFrameData->frameInfo.nEnvelopes] -
+ hHeaderData->numberTimeSlots;
FIXP_DBL degreeAlias[(64)];
+ PVC_DYNAMIC_DATA pvcDynamicData;
+ pvcInitFrame(
+ &hSbrDec->PvcStaticData, &pvcDynamicData,
+ (hHeaderData->frameErrorFlag ? 0 : hHeaderData->bs_info.pvc_mode),
+ hFrameData->ns, hHeaderData->timeStep,
+ hHeaderData->freqBandData.lowSubband,
+ hFrameData->frameInfo.pvcBorders[0], hFrameData->pvcID);
+
+ if (!hHeaderData->frameErrorFlag && (hHeaderData->bs_info.pvc_mode > 0)) {
+ pvcDecodeFrame(&hSbrDec->PvcStaticData, &pvcDynamicData, pLowBandReal,
+ pLowBandImag, ov_len,
+ SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale),
+ SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.lb_scale));
+ }
+ pvcEndFrame(&hSbrDec->PvcStaticData, &pvcDynamicData);
/* The transposer will override most values in degreeAlias[].
- The array needs to be cleared at least from lowSubband to highSubband before. */
+ 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));
+ 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
+ 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 );
+ {
+ KEEP_STATES_SYNCED_MODE keepStatesSyncedMode =
+ ((flags & SBRDEC_USAC_HARMONICSBR) &&
+ (hFrameData->sbrPatchingMode != 0))
+ ? KEEP_STATES_SYNCED_NORMAL
+ : KEEP_STATES_SYNCED_OFF;
+
+ if (flags & SBRDEC_USAC_HARMONICSBR) {
+ if (flags & SBRDEC_QUAD_RATE) {
+ pReal -= 32;
+ pImag -= 32;
+ }
+
+ if ((hSbrDec->savedStates == 0) && (hFrameData->sbrPatchingMode == 1)) {
+ /* copy saved states from previous frame to legacy SBR lpc filterstate
+ * buffer */
+ for (i = 0; i < LPC_ORDER + ov_len; i++) {
+ FDKmemcpy(
+ hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
+ hSbrDec->codecQMFBufferReal[noCols - LPC_ORDER - ov_len + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ FDKmemcpy(
+ hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i],
+ hSbrDec->codecQMFBufferImag[noCols - LPC_ORDER - ov_len + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ }
+ }
+
+ /* saving unmodified QMF states in case we are switching from legacy SBR
+ * to HBE */
+ for (i = 0; i < hSbrDec->hHBE->noCols; i++) {
+ FDKmemcpy(hSbrDec->codecQMFBufferReal[i], pLowBandReal[ov_len + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ FDKmemcpy(hSbrDec->codecQMFBufferImag[i], pLowBandImag[ov_len + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ }
+
+ QmfTransposerApply(
+ hSbrDec->hHBE, pReal, pImag, noCols, pLowBandReal, pLowBandImag,
+ hSbrDec->LppTrans.lpcFilterStatesRealHBE,
+ hSbrDec->LppTrans.lpcFilterStatesImagHBE,
+ hFrameData->sbrPitchInBins, hSbrDec->scale_lb, hSbrDec->scale_hbe,
+ &hSbrDec->qmfDomainInCh->scaling.hb_scale, hHeaderData->timeStep,
+ borders[0], ov_len, keepStatesSyncedMode);
+
+ if (flags & SBRDEC_QUAD_RATE) {
+ int *xOverQmf = GetxOverBandQmfTransposer(hSbrDec->hHBE);
+
+ copyHarmonicSpectrum(xOverQmf, pLowBandReal, pLowBandImag, noCols,
+ ov_len, keepStatesSyncedMode);
+ }
+ }
+ }
+ if ((flags & SBRDEC_USAC_HARMONICSBR) &&
+ (hFrameData->sbrPatchingMode == 0)) {
+ hSbrDec->prev_frame_lSbr = 0;
+ hSbrDec->prev_frame_hbeSbr = 1;
+ lppTransposerHBE(
+ &hSbrDec->LppTrans, hSbrDec->hHBE, &hSbrDec->qmfDomainInCh->scaling,
+ pLowBandReal, pLowBandImag, hHeaderData->timeStep, borders[0],
+ lastSlotOffs, hHeaderData->freqBandData.nInvfBands,
+ hFrameData->sbr_invf_mode, hPrevFrameData->sbr_invf_mode);
+ } else {
+ if (flags & SBRDEC_USAC_HARMONICSBR) {
+ for (i = 0; i < LPC_ORDER + hSbrDec->LppTrans.pSettings->overlap; i++) {
+ /*
+ Store the unmodified qmf Slots values for upper part of spectrum
+ (required for LPC filtering) required if next frame is a HBE frame
+ */
+ FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesRealHBE[i],
+ hSbrDec->qmfDomainInCh
+ ->hQmfSlotsReal[hSbrDec->hHBE->noCols - LPC_ORDER + i],
+ (64) * sizeof(FIXP_DBL));
+ FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesImagHBE[i],
+ hSbrDec->qmfDomainInCh
+ ->hQmfSlotsImag[hSbrDec->hHBE->noCols - LPC_ORDER + i],
+ (64) * sizeof(FIXP_DBL));
+ }
+ }
+ {
+ hSbrDec->prev_frame_lSbr = 1;
+ hSbrDec->prev_frame_hbeSbr = 0;
+ }
+ lppTransposer(
+ &hSbrDec->LppTrans, &hSbrDec->qmfDomainInCh->scaling, pLowBandReal,
+ degreeAlias, // only used if useLP = 1
+ pLowBandImag, flags & SBRDEC_LOW_POWER,
+ hHeaderData->bs_info.sbr_preprocessing,
+ hHeaderData->freqBandData.v_k_master[0], 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,
+ if ((hFrameData->sbrPatchingMode !=
+ hSbrDec->SbrCalculateEnvelope.sbrPatchingMode)) {
+ 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,
+ hFrameData->sbrPatchingMode,
+ (flags & SBRDEC_USAC_HARMONICSBR) &&
+ (hFrameData->sbrPatchingMode == 0)
+ ? GetxOverBandQmfTransposer(hSbrDec->hHBE)
+ : NULL,
+ Get41SbrQmfTransposer(hSbrDec->hHBE));
+
+ hSbrDec->SbrCalculateEnvelope.sbrPatchingMode =
+ hFrameData->sbrPatchingMode;
+ }
+
+ calculateSbrEnvelope(
+ &hSbrDec->qmfDomainInCh->scaling, &hSbrDec->SbrCalculateEnvelope,
+ hHeaderData, hFrameData, &pvcDynamicData, pLowBandReal, pLowBandImag,
+ flags & SBRDEC_LOW_POWER,
- degreeAlias,
- flags,
- (hHeaderData->frameErrorFlag || hPrevFrameData->frameErrorFlag));
+ degreeAlias, flags,
+ (hHeaderData->frameErrorFlag || hPrevFrameData->frameErrorFlag));
+#if (SBRDEC_MAX_HB_FADE_FRAMES > 0)
+ /* Avoid hard onsets of high band */
+ if (hHeaderData->frameErrorFlag) {
+ if (hSbrDec->highBandFadeCnt < SBRDEC_MAX_HB_FADE_FRAMES) {
+ hSbrDec->highBandFadeCnt += 1;
+ }
+ } else {
+ if (hSbrDec->highBandFadeCnt >
+ 0) { /* Manipulate high band scale factor to get a smooth fade-in */
+ hSbrDec->qmfDomainInCh->scaling.hb_scale += hSbrDec->highBandFadeCnt;
+ hSbrDec->qmfDomainInCh->scaling.hb_scale =
+ fMin(hSbrDec->qmfDomainInCh->scaling.hb_scale, DFRACT_BITS - 1);
+ hSbrDec->highBandFadeCnt -= 1;
+ }
+ }
+#endif
/*
Update hPrevFrameData (to be used in the next frame)
*/
- for (i=0; i<hHeaderData->freqBandData.nInvfBands; i++) {
+ 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;
+ hPrevFrameData->prevSbrPitchInBins = hFrameData->sbrPitchInBins;
+ /* could be done in extractFrameInfo_pvc() but hPrevFrameData is not
+ * available there */
+ FDKmemcpy(&hPrevFrameData->prevFrameInfo, &hFrameData->frameInfo,
+ sizeof(FRAME_INFO));
+ } else {
+ /* rescale from lsb to nAnalysisBands in order to compensate scaling with
+ * hb_scale in this area, done by synthesisFiltering*/
+ int rescale;
+ int lsb;
+ int length;
+
+ /* Reset hb_scale if no highband is present, because hb_scale is considered
+ * in the QMF-synthesis */
+ hSbrDec->qmfDomainInCh->scaling.hb_scale = saveLbScale;
+
+ rescale = hSbrDec->qmfDomainInCh->scaling.hb_scale -
+ hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
+ lsb = hSbrDec->qmfDomainOutCh->fb.lsb;
+ length = (hSbrDec->qmfDomainInCh->fb.no_channels - lsb);
+
+ if ((rescale < 0) && (length > 0)) {
+ if (!(flags & SBRDEC_LOW_POWER)) {
+ for (i = 0; i < ov_len; i++) {
+ scaleValues(&pLowBandReal[i][lsb], length, rescale);
+ scaleValues(&pLowBandImag[i][lsb], length, rescale);
+ }
+ } else {
+ for (i = 0; i < ov_len; i++) {
+ scaleValues(&pLowBandReal[i][lsb], length, rescale);
+ }
+ }
+ }
}
+ if (!(flags & SBRDEC_USAC_HARMONICSBR)) {
+ int length = hSbrDec->qmfDomainInCh->fb.lsb;
+ if (flags & SBRDEC_SYNTAX_USAC) {
+ length = hSbrDec->qmfDomainInCh->fb.no_channels;
+ }
- 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));
+ /* in case of legacy sbr saving of filter states here */
+ for (i = 0; i < LPC_ORDER + ov_len; i++) {
+ /*
+ Store the unmodified qmf Slots values (required for LPC filtering)
+ */
+ if (!(flags & SBRDEC_LOW_POWER)) {
+ FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
+ pLowBandReal[noCols - LPC_ORDER + i],
+ length * sizeof(FIXP_DBL));
+ FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i],
+ pLowBandImag[noCols - LPC_ORDER + i],
+ length * sizeof(FIXP_DBL));
+ } else
+ FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
+ pLowBandReal[noCols - LPC_ORDER + i],
+ length * sizeof(FIXP_DBL));
+ }
}
/*
Synthesis subband filtering.
*/
- if ( ! (flags & SBRDEC_PS_DECODED) ) {
-
- {
+ if (!(flags & SBRDEC_PS_DECODED)) {
+ if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
int outScalefactor = 0;
if (h_ps_d != NULL) {
- h_ps_d->procFrameBased = 1; /* we here do frame based processing */
+ h_ps_d->procFrameBased = 1; /* we here do frame based processing */
}
+ sbrDecoder_drcApply(&hSbrDec->sbrDrcChannel, pLowBandReal,
+ (flags & SBRDEC_LOW_POWER) ? NULL : pLowBandImag,
+ hSbrDec->qmfDomainOutCh->fb.no_col, &outScalefactor);
- sbrDecoder_drcApply(&hSbrDec->sbrDrcChannel,
- QmfBufferReal,
- (flags & SBRDEC_LOW_POWER) ? NULL : QmfBufferImag,
- hSbrDec->SynthesisQMF.no_col,
- &outScalefactor
- );
-
-
-
- qmfChangeOutScalefactor(&hSbrDec->SynthesisQMF, outScalefactor );
+ qmfChangeOutScalefactor(&hSbrDec->qmfDomainOutCh->fb, 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));
+ HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData;
+ int save_usb = hSbrDec->qmfDomainOutCh->fb.usb;
+
+#if (QMF_MAX_SYNTHESIS_BANDS <= 64)
+ C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#else
+ C_AALLOC_STACK_START(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#endif
+ if (hSbrDec->qmfDomainOutCh->fb.usb < hFreq->ov_highSubband) {
+ /* we need to patch usb for this frame as overlap may contain higher
+ frequency range if headerchange occured; fb. usb is always limited
+ to maximum fb.no_channels; In case of wrongly decoded headers it
+ might be that ov_highSubband is higher than the number of synthesis
+ channels (fb.no_channels), which is forbidden, therefore we need to
+ limit ov_highSubband with fMin function to avoid not allowed usb in
+ synthesis filterbank. */
+ hSbrDec->qmfDomainOutCh->fb.usb =
+ fMin((UINT)hFreq->ov_highSubband,
+ (UINT)hSbrDec->qmfDomainOutCh->fb.no_channels);
+ }
+ {
+ qmfSynthesisFiltering(
+ &hSbrDec->qmfDomainOutCh->fb, pLowBandReal,
+ (flags & SBRDEC_LOW_POWER) ? NULL : pLowBandImag,
+ &hSbrDec->qmfDomainInCh->scaling,
+ hSbrDec->LppTrans.pSettings->overlap, timeOut, strideOut,
+ qmfTemp);
+ }
+ /* restore saved value */
+ hSbrDec->qmfDomainOutCh->fb.usb = save_usb;
+ hFreq->ov_highSubband = save_usb;
+#if (QMF_MAX_SYNTHESIS_BANDS <= 64)
+ C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#else
+ C_AALLOC_STACK_END(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#endif
}
-
}
} else { /* (flags & SBRDEC_PS_DECODED) */
- INT i, sdiff, outScalefactor, scaleFactorLowBand, scaleFactorHighBand;
- SCHAR scaleFactorLowBand_ov, scaleFactorLowBand_no_ov;
+ INT sdiff;
+ INT scaleFactorHighBand, scaleFactorLowBand_ov, scaleFactorLowBand_no_ov;
- HANDLE_QMF_FILTER_BANK synQmf = &hSbrDec->SynthesisQMF;
- HANDLE_QMF_FILTER_BANK synQmfRight = &hSbrDecRight->SynthesisQMF;
+ HANDLE_QMF_FILTER_BANK synQmf = &hSbrDec->qmfDomainOutCh->fb;
+ HANDLE_QMF_FILTER_BANK synQmfRight = &hSbrDecRight->qmfDomainOutCh->fb;
/* 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 */
+ sdiff = hSbrDec->qmfDomainInCh->scaling.lb_scale -
+ reserve; /* Scaling difference */
+ scaleFactorHighBand = sdiff - hSbrDec->qmfDomainInCh->scaling.hb_scale;
+ scaleFactorLowBand_ov = sdiff - hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
+ scaleFactorLowBand_no_ov = sdiff - hSbrDec->qmfDomainInCh->scaling.lb_scale;
+
+ /* Scale of low band overlapping QMF data */
+ scaleFactorLowBand_ov =
+ fMin(DFRACT_BITS - 1, fMax(-(DFRACT_BITS - 1), scaleFactorLowBand_ov));
+ /* Scale of low band current QMF data */
+ scaleFactorLowBand_no_ov = fMin(
+ DFRACT_BITS - 1, fMax(-(DFRACT_BITS - 1), scaleFactorLowBand_no_ov));
+ /* Scale of current high band */
+ scaleFactorHighBand =
+ fMin(DFRACT_BITS - 1, fMax(-(DFRACT_BITS - 1), scaleFactorHighBand));
+
+ 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));
+ /* was ((640)-(64))*sizeof(FIXP_QSS)
+ flexible amount of synthesis bands needed for QMF based resampling
+ */
+ FDK_ASSERT(hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis <=
+ QMF_MAX_SYNTHESIS_BANDS);
+ FDKmemcpy(synQmfRight->FilterStates, synQmf->FilterStates,
+ 9 * hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis *
+ 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);
+ /* Feed delaylines when parametric stereo is switched on. */
+ PreparePsProcessing(h_ps_d, pLowBandReal, pLowBandImag,
+ scaleFactorLowBand_ov);
/* 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;
+ synQmfRight->lsb = synQmf->lsb;
+ synQmfRight->usb = synQmf->usb;
- int env=0;
-
- outScalefactor += (SCAL_HEADROOM+1); /* psDiffScale! */
+ int env = 0;
{
- C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 2*(64));
+#if (QMF_MAX_SYNTHESIS_BANDS <= 64)
+ C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL,
+ 2 * QMF_MAX_SYNTHESIS_BANDS);
+#else
+ C_AALLOC_STACK_START(pWorkBuffer, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#endif
int maxShift = 0;
@@ -642,99 +781,80 @@ sbr_dec ( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */
}
}
- /* copy DRC data to right channel (with PS both channels use the same DRC gains) */
- FDKmemcpy(&hSbrDecRight->sbrDrcChannel, &hSbrDec->sbrDrcChannel, sizeof(SBRDEC_DRC_CHANNEL));
+ /* 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 ----- */
+ 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;
-
+ FIXP_DBL *rQmfReal = pWorkBuffer;
+ FIXP_DBL *rQmfImag = pWorkBuffer + synQmf->no_channels;
{
- if ( i == h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env] ) {
- initSlotBasedRotation( h_ps_d, env, hHeaderData->freqBandData.highSubband );
+ 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 */
+ ApplyPsSlot(
+ h_ps_d, /* parametric stereo decoder handle */
+ (pLowBandReal + i), /* one timeslot of left/mono channel */
+ (pLowBandImag + i), /* one timeslot of left/mono channel */
+ rQmfReal, /* one timeslot or right channel */
+ rQmfImag, /* one timeslot or right channel */
+ scaleFactorLowBand_no_ov,
+ (i < hSbrDec->LppTrans.pSettings->overlap)
+ ? scaleFactorLowBand_ov
+ : scaleFactorLowBand_no_ov,
+ scaleFactorHighBand, synQmf->lsb, synQmf->usb);
+
+ outScalefactorL = outScalefactorR = 1; /* psDiffScale! (MPEG-PS) */
}
-
- scaleFactorLowBand = (i<(6)) ? scaleFactorLowBand_ov : scaleFactorLowBand_no_ov;
-
-
- sbrDecoder_drcApplySlot ( /* right channel */
- &hSbrDecRight->sbrDrcChannel,
- rQmfReal,
- rQmfImag,
- i,
- synQmfRight->no_col,
- maxShift
- );
+ 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
- );
+ sbrDecoder_drcApplySlot(/* left channel */
+ &hSbrDec->sbrDrcChannel, *(pLowBandReal + i),
+ *(pLowBandImag + 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);
-
+ if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
+ qmfSynthesisFilteringSlot(
+ synQmfRight, rQmfReal, /* QMF real buffer */
+ rQmfImag, /* QMF imag buffer */
+ outScalefactorL, outScalefactorL,
+ timeOutRight + (i * synQmf->no_channels * strideOut), strideOut,
+ pWorkBuffer);
+
+ qmfSynthesisFilteringSlot(
+ synQmf, *(pLowBandReal + i), /* QMF real buffer */
+ *(pLowBandImag + i), /* QMF imag buffer */
+ outScalefactorR, outScalefactorR,
+ 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_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 2*(64));
+#if (QMF_MAX_SYNTHESIS_BANDS <= 64)
+ C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#else
+ C_AALLOC_STACK_END(pWorkBuffer, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#endif
}
}
- sbrDecoder_drcUpdateChannel( &hSbrDec->sbrDrcChannel );
-
+ sbrDecoder_drcUpdateChannel(&hSbrDec->sbrDrcChannel);
/*
Update overlap buffer
@@ -742,150 +862,127 @@ sbr_dec ( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */
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));
- }
+ if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
+ {
+ FDK_QmfDomain_SaveOverlap(hSbrDec->qmfDomainInCh, 0);
+ FDK_ASSERT(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale == saveLbScale);
+ }
}
- hSbrDec->sbrScaleFactor.ov_lb_scale = saveLbScale;
+ hSbrDec->savedStates = 0;
/* Save current frame status */
hPrevFrameData->frameErrorFlag = hHeaderData->frameErrorFlag;
+ hSbrDec->applySbrProc_old = applyProcessing;
-} // sbr_dec()
-
+} /* 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. */
+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. */
+ int codecFrameSize)
{
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 */
+ 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;
+#if (SBRDEC_MAX_HB_FADE_FRAMES > 0)
+ hs->highBandFadeCnt = SBRDEC_MAX_HB_FADE_FRAMES;
+
+#endif
+ hs->scale_hbe = 15;
+ hs->scale_lb = 15;
+ hs->scale_ov = 15;
+ hs->prev_frame_lSbr = 0;
+ hs->prev_frame_hbeSbr = 0;
+
+ hs->codecFrameSize = codecFrameSize;
/*
create envelope calculator
*/
- err = createSbrEnvelopeCalc (&hs->SbrCalculateEnvelope,
- hHeaderData,
- chan,
- flags);
+ err = createSbrEnvelopeCalc(&hs->SbrCalculateEnvelope, hHeaderData, chan,
+ flags);
if (err != SBRDEC_OK) {
return err;
}
- /*
- create QMF filter banks
- */
- {
- int qmfErr;
- /* Adapted QMF analysis post-twiddles for down-sampled HQ SBR */
- const UINT downSampledFlag = (flags & SBRDEC_DOWNSAMPLE) ? QMF_FLAG_DOWNSAMPLED : 0;
-
- qmfErr = qmfInitAnalysisFilterBank (
- &hs->AnalysiscQMF,
- hs->anaQmfStates,
- noCols,
- hHeaderData->freqBandData.lowSubband,
- hHeaderData->freqBandData.highSubband,
- hHeaderData->numberOfAnalysisBands,
- (qmfFlags & (~QMF_FLAG_KEEP_STATES)) | downSampledFlag
- );
- 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);
+ 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 );
+ err = createLppTransposer(
+ &hs->LppTrans, pSettings, hHeaderData->freqBandData.lowSubband,
+ hHeaderData->freqBandData.v_k_master, hHeaderData->freqBandData.numMaster,
+ hHeaderData->freqBandData.highSubband, timeSlots, noCols,
+ 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)
- );
+ if (flags & SBRDEC_USAC_HARMONICSBR) {
+ int noChannels, bSbr41 = flags & SBRDEC_QUAD_RATE ? 1 : 0;
+
+ noChannels =
+ QMF_SYNTH_CHANNELS /
+ ((bSbr41 + 1) * 2); /* 32 for (32:64 and 24:64) and 16 for 16:64 */
+
+ /* shared memory between hbeLightTimeDelayBuffer and hQmfHBESlotsReal if
+ * SBRDEC_HBE_ENABLE */
+ hSbrChannel->SbrDec.tmp_memory = (FIXP_DBL **)fdkCallocMatrix2D_aligned(
+ noCols, noChannels, sizeof(FIXP_DBL));
+ if (hSbrChannel->SbrDec.tmp_memory == NULL) {
+ return SBRDEC_MEM_ALLOC_FAILED;
}
- }
- /* Clear input delay line */
- FDKmemclear(hs->coreDelayBuf, (96)*sizeof(INT_PCM));
+ hSbrChannel->SbrDec.hQmfHBESlotsReal = hSbrChannel->SbrDec.tmp_memory;
+ hSbrChannel->SbrDec.hQmfHBESlotsImag =
+ (FIXP_DBL **)fdkCallocMatrix2D_aligned(noCols, noChannels,
+ sizeof(FIXP_DBL));
+ if (hSbrChannel->SbrDec.hQmfHBESlotsImag == NULL) {
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
- /* assign qmf time slots */
- assignTimeSlots( &hSbrChannel->SbrDec, hHeaderData->numberTimeSlots * hHeaderData->timeStep, qmfFlags & QMF_FLAG_LP);
+ /* buffers containing unmodified qmf data; required when switching from
+ * legacy SBR to HBE */
+ /* buffer can be used as LPCFilterstates buffer because legacy SBR needs
+ * exactly these values for LPC filtering */
+ hSbrChannel->SbrDec.codecQMFBufferReal =
+ (FIXP_DBL **)fdkCallocMatrix2D_aligned(noCols, noChannels,
+ sizeof(FIXP_DBL));
+ if (hSbrChannel->SbrDec.codecQMFBufferReal == NULL) {
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ hSbrChannel->SbrDec.codecQMFBufferImag =
+ (FIXP_DBL **)fdkCallocMatrix2D_aligned(noCols, noChannels,
+ sizeof(FIXP_DBL));
+ if (hSbrChannel->SbrDec.codecQMFBufferImag == NULL) {
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ err = QmfTransposerCreate(&hs->hHBE, codecFrameSize, 0, bSbr41);
+ if (err != SBRDEC_OK) {
+ return err;
+ }
+ }
return err;
}
@@ -894,65 +991,88 @@ createSbrDec (SBR_CHANNEL * hSbrChannel,
\brief Delete sbr decoder structure
\return errorCode, 0 if successful
*/
-int
-deleteSbrDec (SBR_CHANNEL * hSbrChannel)
-{
+int deleteSbrDec(SBR_CHANNEL *hSbrChannel) {
HANDLE_SBR_DEC hs = &hSbrChannel->SbrDec;
- deleteSbrEnvelopeCalc (&hs->SbrCalculateEnvelope);
+ deleteSbrEnvelopeCalc(&hs->SbrCalculateEnvelope);
- /* delete QMF filter states */
- if (hs->pSynQmfStates != NULL) {
- FreeRam_sbr_QmfStatesSynthesis(&hs->pSynQmfStates);
+ if (hs->tmp_memory != NULL) {
+ FDK_FREE_MEMORY_2D_ALIGNED(hs->tmp_memory);
}
+ /* modify here */
+ FDK_FREE_MEMORY_2D_ALIGNED(hs->hQmfHBESlotsImag);
+
+ if (hs->hHBE != NULL) QmfTransposerClose(hs->hHBE);
+
+ if (hs->codecQMFBufferReal != NULL) {
+ FDK_FREE_MEMORY_2D_ALIGNED(hs->codecQMFBufferReal);
+ }
- if (hs->pSbrOverlapBuffer != NULL) {
- FreeRam_sbr_OverlapBuffer(&hs->pSbrOverlapBuffer);
+ if (hs->codecQMFBufferImag != NULL) {
+ FDK_FREE_MEMORY_2D_ALIGNED(hs->codecQMFBufferImag);
}
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
- )
-{
+resetSbrDec(HANDLE_SBR_DEC hSbrDec, HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, const int downsampleFac,
+ const UINT flags, HANDLE_SBR_FRAME_DATA hFrameData) {
SBR_ERROR sbrError = SBRDEC_OK;
-
- int old_lsb = hSbrDec->SynthesisQMF.lsb;
+ int i;
+ FIXP_DBL *pLowBandReal[128];
+ FIXP_DBL *pLowBandImag[128];
+ int useLP = flags & SBRDEC_LOW_POWER;
+
+ int old_lsb = hSbrDec->qmfDomainInCh->fb.lsb;
+ int old_usb = hSbrDec->qmfDomainInCh->fb.usb;
int new_lsb = hHeaderData->freqBandData.lowSubband;
+ /* int new_usb = hHeaderData->freqBandData.highSubband; */
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);
-
-
+ FIXP_DBL **OverlapBufferReal = hSbrDec->qmfDomainInCh->hQmfSlotsReal;
+ FIXP_DBL **OverlapBufferImag = hSbrDec->qmfDomainInCh->hQmfSlotsImag;
- resetSbrEnvelopeCalc (&hSbrDec->SbrCalculateEnvelope);
-
- hSbrDec->SynthesisQMF.lsb = hHeaderData->freqBandData.lowSubband;
- hSbrDec->SynthesisQMF.usb = fixMin((INT)hSbrDec->SynthesisQMF.no_channels, (INT)hHeaderData->freqBandData.highSubband);
+ /* in case the previous frame was not active in terms of SBR processing, the
+ full band from 0 to no_channels was rescaled and not overwritten. Thats why
+ the scaling factor lb_scale can be seen as assigned to all bands from 0 to
+ no_channels in the previous frame. The same states for the current frame if
+ the current frame is not active in terms of SBR processing
+ */
+ int applySbrProc = (hHeaderData->syncState == SBR_ACTIVE ||
+ (hHeaderData->frameErrorFlag == 0 &&
+ hHeaderData->syncState == SBR_HEADER));
+ int applySbrProc_old = hSbrDec->applySbrProc_old;
- hSbrDec->AnalysiscQMF.lsb = hSbrDec->SynthesisQMF.lsb;
- hSbrDec->AnalysiscQMF.usb = hSbrDec->SynthesisQMF.usb;
+ if (!applySbrProc) {
+ new_lsb = (hSbrDec->qmfDomainInCh->fb).no_channels;
+ }
+ if (!applySbrProc_old) {
+ old_lsb = (hSbrDec->qmfDomainInCh->fb).no_channels;
+ old_usb = old_lsb;
+ }
+ resetSbrEnvelopeCalc(&hSbrDec->SbrCalculateEnvelope);
+
+ /* Change lsb and usb */
+ /* Synthesis */
+ FDK_ASSERT(hSbrDec->qmfDomainOutCh != NULL);
+ hSbrDec->qmfDomainOutCh->fb.lsb =
+ fixMin((INT)hSbrDec->qmfDomainOutCh->fb.no_channels,
+ (INT)hHeaderData->freqBandData.lowSubband);
+ hSbrDec->qmfDomainOutCh->fb.usb =
+ fixMin((INT)hSbrDec->qmfDomainOutCh->fb.no_channels,
+ (INT)hHeaderData->freqBandData.highSubband);
+ /* Analysis */
+ FDK_ASSERT(hSbrDec->qmfDomainInCh != NULL);
+ hSbrDec->qmfDomainInCh->fb.lsb = hSbrDec->qmfDomainOutCh->fb.lsb;
+ hSbrDec->qmfDomainInCh->fb.usb = hSbrDec->qmfDomainOutCh->fb.usb;
/*
The following initialization of spectral data in the overlap buffer
@@ -964,135 +1084,397 @@ resetSbrDec (HANDLE_SBR_DEC hSbrDec,
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));
+ stopBand = new_lsb;
+ startSlot = fMax(0, hHeaderData->timeStep * (hPrevFrameData->stopPos -
+ hHeaderData->numberTimeSlots));
+ size = fMax(0, stopBand - startBand);
+
+ /* in case of USAC we don't want to zero out the memory, as this can lead to
+ holes in the spectrum; fix shall only be applied for USAC not for MPEG-4
+ SBR, in this case setting zero remains */
+ if (!(flags & SBRDEC_SYNTAX_USAC)) {
+ /* 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));
+ }
}
- } 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));
+ */
+ startBand = fixMin(old_lsb, new_lsb);
+ stopBand = fixMax(old_lsb, new_lsb);
+ size = fixMax(0, stopBand - startBand);
+
+ FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[0][startBand],
+ size * sizeof(FIXP_DBL));
+ FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[1][startBand],
+ size * sizeof(FIXP_DBL));
+ if (!useLP) {
+ FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[0][startBand],
+ size * sizeof(FIXP_DBL));
+ FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[1][startBand],
+ size * sizeof(FIXP_DBL));
+ }
}
+ if (startSlot != 0) {
+ int source_exp, target_exp, delta_exp, target_lsb, target_usb, reserve;
+ FIXP_DBL maxVal;
- /*
- 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;
- }
+ /*
+ 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.
+ */
+
+ /* We have four relevant transitions to cover:
+ 1. old_usb is lower than new_lsb; old SBR area is completely below new SBR
+ area.
+ -> entire old area was highband and belongs to lowband now
+ and has to be rescaled.
+ 2. old_lsb is higher than new_usb; new SBR area is completely below old SBR
+ area.
+ -> old area between new_lsb and old_lsb was lowband and belongs to
+ highband now and has to be rescaled to match new highband scale.
+ 3. old_lsb is lower and old_usb is higher than new_lsb; old and new SBR
+ areas overlap.
+ -> old area between old_lsb and new_lsb was highband and belongs to
+ lowband now and has to be rescaled to match new lowband scale.
+ 4. new_lsb is lower and new_usb_is higher than old_lsb; old and new SBR
+ areas overlap.
+ -> old area between new_lsb and old_usb was lowband and belongs to
+ highband now and has to be rescaled to match new highband scale.
+ */
- /* 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! */
+ if (new_lsb > old_lsb) {
+ /* case 1 and 3 */
+ source_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_hb_scale);
+ target_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale);
+
+ startBand = old_lsb;
+
+ if (new_lsb >= old_usb) {
+ /* case 1 */
+ stopBand = old_usb;
+ } else {
+ /* case 3 */
+ stopBand = new_lsb;
+ }
- maxVal = maxSubbandSample( OverlapBufferReal,
- (useLP) ? NULL : OverlapBufferImag,
- startBand,
- stopBand,
- 0,
- startSlot);
+ target_lsb = 0;
+ target_usb = old_lsb;
+ } else {
+ /* case 2 and 4 */
+ source_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale);
+ target_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_hb_scale);
- reserve = CntLeadingZeros(maxVal)-1;
- reserve = fixMin(reserve,DFRACT_BITS-1-source_scale);
+ startBand = new_lsb;
+ stopBand = old_lsb;
- rescaleSubbandSamples( OverlapBufferReal,
- (useLP) ? NULL : OverlapBufferImag,
- startBand,
- stopBand,
- 0,
- startSlot,
- reserve);
- source_scale += reserve;
+ target_lsb = old_lsb;
+ target_usb = old_usb;
+ }
- delta_scale = target_scale - source_scale;
+ maxVal =
+ maxSubbandSample(OverlapBufferReal, (useLP) ? NULL : OverlapBufferImag,
+ startBand, stopBand, 0, startSlot);
- if (delta_scale > 0) { /* x-over-area is dominant */
- delta_scale = -delta_scale;
- startBand = target_lsb;
- stopBand = target_usb;
+ reserve = ((LONG)maxVal != 0 ? CntLeadingZeros(maxVal) - 1 : 0);
+ reserve = fixMin(
+ reserve,
+ DFRACT_BITS - 1 -
+ EXP2SCALE(
+ source_exp)); /* what is this line for, why do we need it? */
- 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;
+ /* process only if x-over-area is not dominant after rescale;
+ otherwise I'm not sure if all buffers are scaled correctly;
+ */
+ if (target_exp - (source_exp - reserve) >= 0) {
+ rescaleSubbandSamples(OverlapBufferReal,
+ (useLP) ? NULL : OverlapBufferImag, startBand,
+ stopBand, 0, startSlot, reserve);
+ source_exp -= reserve;
}
- }
- FDK_ASSERT(startBand <= stopBand);
+ delta_exp = target_exp - source_exp;
+
+ if (delta_exp < 0) { /* x-over-area is dominant */
+ startBand = target_lsb;
+ stopBand = target_usb;
+ delta_exp = -delta_exp;
- if (!useLP) {
- for (l=0; l<startSlot; l++) {
- scaleValues( OverlapBufferReal[l] + startBand, stopBand-startBand, delta_scale );
- scaleValues( OverlapBufferImag[l] + startBand, stopBand-startBand, delta_scale );
+ if (new_lsb > old_lsb) {
+ /* The lowband has to be rescaled */
+ hSbrDec->qmfDomainInCh->scaling.ov_lb_scale = EXP2SCALE(source_exp);
+ } else {
+ /* The highband has to be rescaled */
+ hSbrDec->qmfDomainInCh->scaling.ov_hb_scale = EXP2SCALE(source_exp);
+ }
}
- } else
- for (l=0; l<startSlot; l++) {
- scaleValues( OverlapBufferReal[l] + startBand, stopBand-startBand, delta_scale );
- }
+ FDK_ASSERT(startBand <= stopBand);
+
+ if (!useLP) {
+ for (l = 0; l < startSlot; l++) {
+ scaleValues(OverlapBufferReal[l] + startBand, stopBand - startBand,
+ -delta_exp);
+ scaleValues(OverlapBufferImag[l] + startBand, stopBand - startBand,
+ -delta_exp);
+ }
+ } else
+ for (l = 0; l < startSlot; l++) {
+ scaleValues(OverlapBufferReal[l] + startBand, stopBand - startBand,
+ -delta_exp);
+ }
+ } /* startSlot != 0 */
/*
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);
+ 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;
+
+ hSbrDec->savedStates = 0;
+
+ if (flags & SBRDEC_USAC_HARMONICSBR) {
+ sbrError = QmfTransposerReInit(hSbrDec->hHBE,
+ hHeaderData->freqBandData.freqBandTable,
+ hHeaderData->freqBandData.nSfb);
+ if (sbrError != SBRDEC_OK) return sbrError;
+
+ /* copy saved states from previous frame to legacy SBR lpc filterstate
+ * buffer */
+ for (i = 0; i < LPC_ORDER + hSbrDec->LppTrans.pSettings->overlap; i++) {
+ FDKmemcpy(
+ hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
+ hSbrDec->codecQMFBufferReal[hSbrDec->hHBE->noCols - LPC_ORDER -
+ hSbrDec->LppTrans.pSettings->overlap + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ FDKmemcpy(
+ hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i],
+ hSbrDec->codecQMFBufferImag[hSbrDec->hHBE->noCols - LPC_ORDER -
+ hSbrDec->LppTrans.pSettings->overlap + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ }
+ hSbrDec->savedStates = 1;
+
+ {
+ /* map QMF buffer to pointer array (Overlap + Frame)*/
+ for (i = 0; i < hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER; i++) {
+ pLowBandReal[i] = hSbrDec->LppTrans.lpcFilterStatesRealHBE[i];
+ pLowBandImag[i] = hSbrDec->LppTrans.lpcFilterStatesImagHBE[i];
+ }
+
+ /* map QMF buffer to pointer array (Overlap + Frame)*/
+ for (i = 0; i < hSbrDec->hHBE->noCols; i++) {
+ pLowBandReal[i + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->codecQMFBufferReal[i];
+ pLowBandImag[i + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->codecQMFBufferImag[i];
+ }
+
+ if (flags & SBRDEC_QUAD_RATE) {
+ if (hFrameData->sbrPatchingMode == 0) {
+ int *xOverQmf = GetxOverBandQmfTransposer(hSbrDec->hHBE);
+
+ /* in case of harmonic SBR and no HBE_LP map additional buffer for
+ one more frame to pointer arry */
+ for (i = 0; i < hSbrDec->hHBE->noCols / 2; i++) {
+ pLowBandReal[i + hSbrDec->hHBE->noCols +
+ hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->hQmfHBESlotsReal[i];
+ pLowBandImag[i + hSbrDec->hHBE->noCols +
+ hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->hQmfHBESlotsImag[i];
+ }
+
+ QmfTransposerApply(
+ hSbrDec->hHBE,
+ pLowBandReal + hSbrDec->LppTrans.pSettings->overlap +
+ hSbrDec->hHBE->noCols / 2 + LPC_ORDER,
+ pLowBandImag + hSbrDec->LppTrans.pSettings->overlap +
+ hSbrDec->hHBE->noCols / 2 + LPC_ORDER,
+ hSbrDec->hHBE->noCols, pLowBandReal, pLowBandImag,
+ hSbrDec->LppTrans.lpcFilterStatesRealHBE,
+ hSbrDec->LppTrans.lpcFilterStatesImagHBE,
+ hPrevFrameData->prevSbrPitchInBins, hSbrDec->scale_lb,
+ hSbrDec->scale_hbe, &hSbrDec->qmfDomainInCh->scaling.hb_scale,
+ hHeaderData->timeStep, hFrameData->frameInfo.borders[0],
+ hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_OUTDIFF);
+
+ copyHarmonicSpectrum(
+ xOverQmf, pLowBandReal, pLowBandImag, hSbrDec->hHBE->noCols,
+ hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_OUTDIFF);
+ }
+ } else {
+ /* in case of harmonic SBR and no HBE_LP map additional buffer for
+ one more frame to pointer arry */
+ for (i = 0; i < hSbrDec->hHBE->noCols; i++) {
+ pLowBandReal[i + hSbrDec->hHBE->noCols +
+ hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->hQmfHBESlotsReal[i];
+ pLowBandImag[i + hSbrDec->hHBE->noCols +
+ hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->hQmfHBESlotsImag[i];
+ }
+
+ if (hFrameData->sbrPatchingMode == 0) {
+ QmfTransposerApply(
+ hSbrDec->hHBE,
+ pLowBandReal + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER,
+ pLowBandImag + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER,
+ hSbrDec->hHBE->noCols, pLowBandReal, pLowBandImag,
+ hSbrDec->LppTrans.lpcFilterStatesRealHBE,
+ hSbrDec->LppTrans.lpcFilterStatesImagHBE,
+ 0 /* not required for keeping states updated in this frame*/,
+ hSbrDec->scale_lb, hSbrDec->scale_lb,
+ &hSbrDec->qmfDomainInCh->scaling.hb_scale, hHeaderData->timeStep,
+ hFrameData->frameInfo.borders[0],
+ hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_NOOUT);
+ }
+
+ QmfTransposerApply(
+ hSbrDec->hHBE,
+ pLowBandReal + hSbrDec->LppTrans.pSettings->overlap +
+ hSbrDec->hHBE->noCols + LPC_ORDER,
+ pLowBandImag + hSbrDec->LppTrans.pSettings->overlap +
+ hSbrDec->hHBE->noCols + LPC_ORDER,
+ hSbrDec->hHBE->noCols, pLowBandReal, pLowBandImag,
+ hSbrDec->LppTrans.lpcFilterStatesRealHBE,
+ hSbrDec->LppTrans.lpcFilterStatesImagHBE,
+ hPrevFrameData->prevSbrPitchInBins, hSbrDec->scale_lb,
+ hSbrDec->scale_hbe, &hSbrDec->qmfDomainInCh->scaling.hb_scale,
+ hHeaderData->timeStep, hFrameData->frameInfo.borders[0],
+ hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_OUTDIFF);
+ }
+
+ if (hFrameData->sbrPatchingMode == 0) {
+ for (i = startSlot; i < hSbrDec->LppTrans.pSettings->overlap; i++) {
+ /*
+ Store the unmodified qmf Slots values for upper part of spectrum
+ (required for LPC filtering) required if next frame is a HBE frame
+ */
+ FDKmemcpy(hSbrDec->qmfDomainInCh->hQmfSlotsReal[i],
+ hSbrDec->LppTrans.lpcFilterStatesRealHBE[i + LPC_ORDER],
+ (64) * sizeof(FIXP_DBL));
+ FDKmemcpy(hSbrDec->qmfDomainInCh->hQmfSlotsImag[i],
+ hSbrDec->LppTrans.lpcFilterStatesImagHBE[i + LPC_ORDER],
+ (64) * sizeof(FIXP_DBL));
+ }
+
+ for (i = startSlot; i < hSbrDec->LppTrans.pSettings->overlap; i++) {
+ /*
+ Store the unmodified qmf Slots values for upper part of spectrum
+ (required for LPC filtering) required if next frame is a HBE frame
+ */
+ FDKmemcpy(
+ hSbrDec->qmfDomainInCh->hQmfSlotsReal[i],
+ hSbrDec->codecQMFBufferReal[hSbrDec->hHBE->noCols -
+ hSbrDec->LppTrans.pSettings->overlap +
+ i],
+ new_lsb * sizeof(FIXP_DBL));
+ FDKmemcpy(
+ hSbrDec->qmfDomainInCh->hQmfSlotsImag[i],
+ hSbrDec->codecQMFBufferImag[hSbrDec->hHBE->noCols -
+ hSbrDec->LppTrans.pSettings->overlap +
+ i],
+ new_lsb * sizeof(FIXP_DBL));
+ }
+ }
+ }
+ }
+
+ {
+ int adapt_lb = 0, diff = 0,
+ new_scale = hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
+
+ if ((hSbrDec->qmfDomainInCh->scaling.ov_lb_scale !=
+ hSbrDec->qmfDomainInCh->scaling.lb_scale) &&
+ startSlot != 0) {
+ /* we need to adapt spectrum to have equal scale factor, always larger
+ * than zero */
+ diff = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale) -
+ SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.lb_scale);
+
+ if (diff > 0) {
+ adapt_lb = 1;
+ diff = -diff;
+ new_scale = hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
+ }
+
+ stopBand = new_lsb;
+ }
+
+ if (hFrameData->sbrPatchingMode == 1) {
+ /* scale states from LegSBR filterstates buffer */
+ for (i = 0; i < hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER; i++) {
+ scaleValues(hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i], new_lsb,
+ diff);
+ if (!useLP) {
+ scaleValues(hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i], new_lsb,
+ diff);
+ }
+ }
+
+ if (flags & SBRDEC_SYNTAX_USAC) {
+ /* get missing states between old and new x_over from LegSBR
+ * filterstates buffer */
+ /* in case of legacy SBR we leave these values zeroed out */
+ for (i = startSlot; i < hSbrDec->LppTrans.pSettings->overlap; i++) {
+ FDKmemcpy(&OverlapBufferReal[i][old_lsb],
+ &hSbrDec->LppTrans
+ .lpcFilterStatesRealLegSBR[LPC_ORDER + i][old_lsb],
+ fMax(new_lsb - old_lsb, 0) * sizeof(FIXP_DBL));
+ if (!useLP) {
+ FDKmemcpy(&OverlapBufferImag[i][old_lsb],
+ &hSbrDec->LppTrans
+ .lpcFilterStatesImagLegSBR[LPC_ORDER + i][old_lsb],
+ fMax(new_lsb - old_lsb, 0) * sizeof(FIXP_DBL));
+ }
+ }
+ }
+
+ if (new_lsb > old_lsb) {
+ stopBand = old_lsb;
+ }
+ }
+ if ((adapt_lb == 1) && (stopBand > startBand)) {
+ for (l = startSlot; l < hSbrDec->LppTrans.pSettings->overlap; l++) {
+ scaleValues(OverlapBufferReal[l] + startBand, stopBand - startBand,
+ diff);
+ if (!useLP) {
+ scaleValues(OverlapBufferImag[l] + startBand, stopBand - startBand,
+ diff);
+ }
+ }
+ }
+ hSbrDec->qmfDomainInCh->scaling.ov_lb_scale = new_scale;
+ }
+ 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,
+ hFrameData->sbrPatchingMode,
+ GetxOverBandQmfTransposer(hSbrDec->hHBE),
+ Get41SbrQmfTransposer(hSbrDec->hHBE));
+
+ hSbrDec->SbrCalculateEnvelope.sbrPatchingMode = hFrameData->sbrPatchingMode;
return sbrError;
}