mirror of https://github.com/mstorsjo/fdk-aac.git
1487 lines
58 KiB
C++
1487 lines
58 KiB
C++
/* -----------------------------------------------------------------------------
|
|
Software License for The Fraunhofer FDK AAC Codec Library for Android
|
|
|
|
© Copyright 1995 - 2019 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
|
|
----------------------------------------------------------------------------- */
|
|
|
|
/**************************** 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:
|
|
|
|
\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 "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;
|
|
|
|
if (keepStatesSynced == KEEP_STATES_SYNCED_NORMAL) {
|
|
slotOffset = noCols - overlap - LPC_ORDER;
|
|
}
|
|
|
|
if (keepStatesSynced == KEEP_STATES_SYNCED_OUTDIFF) {
|
|
ppqmfReal = qmfReal;
|
|
ppqmfImag = qmfImag;
|
|
}
|
|
|
|
for (i = 1; i < MAX_NUM_PATCHES; i++) {
|
|
if (xOverQmf[i] != 0) {
|
|
numPatches++;
|
|
}
|
|
}
|
|
|
|
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];
|
|
|
|
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
|
|
|
|
\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. Due to in-place
|
|
processing, #timeIn and #timeOut point to identical locations.
|
|
|
|
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
|
|
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 */
|
|
LONG *timeIn, /*!< pointer to input time signal */
|
|
LONG *timeOut, /*!< pointer to output time signal */
|
|
HANDLE_SBR_DEC hSbrDecRight, /*!< handle to Decoder channel right */
|
|
LONG *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,
|
|
const INT sbrInDataHeadroom) {
|
|
int i, slot, reserve;
|
|
int saveLbScale;
|
|
int lastSlotOffs;
|
|
FIXP_DBL maxVal;
|
|
|
|
/* temporary pointer / variable for QMF;
|
|
required as we want to use temporary buffer
|
|
creating one frame delay for HBE in LP mode */
|
|
LONG *pTimeInQmf = timeIn;
|
|
|
|
/* Number of QMF timeslots in the overlap buffer: */
|
|
int ov_len = hSbrDec->LppTrans.pSettings->overlap;
|
|
|
|
/* Number of QMF slots per frame */
|
|
int noCols = hHeaderData->numberTimeSlots * hHeaderData->timeStep;
|
|
|
|
/* 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_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];
|
|
}
|
|
|
|
/* 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));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
low band codec signal subband filtering
|
|
*/
|
|
|
|
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 + sbrInDataHeadroom, 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(&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));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Shift spectral data left to gain accuracy in transposer and adjustor
|
|
*/
|
|
/* 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->qmfDomainInCh->scaling.lb_scale);
|
|
|
|
/* If all data is zero, lb_scale could become too large */
|
|
rescaleSubbandSamples(pReal, (flags & SBRDEC_LOW_POWER) ? NULL : pImag, 0,
|
|
hSbrDec->qmfDomainInCh->fb.no_channels, 0, noCols,
|
|
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->qmfDomainInCh->scaling.lb_scale;
|
|
|
|
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. */
|
|
if (flags & SBRDEC_LOW_POWER)
|
|
FDKmemclear(°reeAlias[hHeaderData->freqBandData.lowSubband],
|
|
(hHeaderData->freqBandData.highSubband -
|
|
hHeaderData->freqBandData.lowSubband) *
|
|
sizeof(FIXP_DBL));
|
|
|
|
/*
|
|
Inverse filtering of lowband and transposition into the SBR-frequency
|
|
range
|
|
*/
|
|
|
|
{
|
|
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.
|
|
*/
|
|
|
|
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));
|
|
|
|
#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++) {
|
|
hPrevFrameData->sbr_invf_mode[i] = hFrameData->sbr_invf_mode[i];
|
|
}
|
|
hPrevFrameData->coupling = hFrameData->coupling;
|
|
hPrevFrameData->stopPos = borders[hFrameData->frameInfo.nEnvelopes];
|
|
hPrevFrameData->ampRes = hFrameData->ampResolutionCurrentFrame;
|
|
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;
|
|
}
|
|
|
|
/* 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_SKIP_QMF_SYN)) {
|
|
int outScalefactor = -(8);
|
|
|
|
if (h_ps_d != NULL) {
|
|
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);
|
|
|
|
qmfChangeOutScalefactor(&hSbrDec->qmfDomainOutCh->fb, outScalefactor);
|
|
|
|
{
|
|
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 sdiff;
|
|
INT scaleFactorHighBand, scaleFactorLowBand_ov, scaleFactorLowBand_no_ov;
|
|
|
|
HANDLE_QMF_FILTER_BANK synQmf = &hSbrDec->qmfDomainOutCh->fb;
|
|
HANDLE_QMF_FILTER_BANK synQmfRight = &hSbrDecRight->qmfDomainOutCh->fb;
|
|
|
|
/* adapt scaling */
|
|
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 */
|
|
/* 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);
|
|
qmfChangeOutScalefactor(synQmfRight, -(8));
|
|
FDKmemcpy(synQmfRight->FilterStates, synQmf->FilterStates,
|
|
9 * hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis *
|
|
sizeof(FIXP_QSS));
|
|
}
|
|
|
|
/* 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;
|
|
|
|
int env = 0;
|
|
|
|
{
|
|
#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;
|
|
|
|
if (hSbrDec->sbrDrcChannel.enable != 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;
|
|
|
|
/* qmf timeslot of right channel */
|
|
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);
|
|
env++;
|
|
}
|
|
|
|
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 + sbrInDataHeadroom; /* psDiffScale! (MPEG-PS) */
|
|
}
|
|
|
|
sbrDecoder_drcApplySlot(/* right channel */
|
|
&hSbrDecRight->sbrDrcChannel, rQmfReal,
|
|
rQmfImag, i, synQmfRight->no_col, maxShift);
|
|
|
|
outScalefactorR += maxShift;
|
|
|
|
sbrDecoder_drcApplySlot(/* left channel */
|
|
&hSbrDec->sbrDrcChannel, *(pLowBandReal + i),
|
|
*(pLowBandImag + i), i, synQmf->no_col,
|
|
maxShift);
|
|
|
|
outScalefactorL += maxShift;
|
|
|
|
if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
|
|
qmfChangeOutScalefactor(synQmf, -(8));
|
|
qmfChangeOutScalefactor(synQmfRight, -(8));
|
|
|
|
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 */
|
|
#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);
|
|
|
|
/*
|
|
Update overlap buffer
|
|
Even bands above usb are copied to avoid outdated spectral data in case
|
|
the stop frequency raises.
|
|
*/
|
|
|
|
if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
|
|
{
|
|
FDK_QmfDomain_SaveOverlap(hSbrDec->qmfDomainInCh, 0);
|
|
FDK_ASSERT(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale == saveLbScale);
|
|
}
|
|
}
|
|
|
|
hSbrDec->savedStates = 0;
|
|
|
|
/* Save current frame status */
|
|
hPrevFrameData->frameErrorFlag = hHeaderData->frameErrorFlag;
|
|
hSbrDec->applySbrProc_old = applyProcessing;
|
|
|
|
} /* 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. */
|
|
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 */
|
|
HANDLE_SBR_DEC hs = &(hSbrChannel->SbrDec);
|
|
|
|
#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);
|
|
if (err != SBRDEC_OK) {
|
|
return err;
|
|
}
|
|
|
|
initSbrPrevFrameData(&hSbrChannel->prevFrameData, timeSlots);
|
|
|
|
/*
|
|
create transposer
|
|
*/
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/*!
|
|
\brief Delete sbr decoder structure
|
|
\return errorCode, 0 if successful
|
|
*/
|
|
int deleteSbrDec(SBR_CHANNEL *hSbrChannel) {
|
|
HANDLE_SBR_DEC hs = &hSbrChannel->SbrDec;
|
|
|
|
deleteSbrEnvelopeCalc(&hs->SbrCalculateEnvelope);
|
|
|
|
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->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 downsampleFac,
|
|
const UINT flags, HANDLE_SBR_FRAME_DATA hFrameData) {
|
|
SBR_ERROR sbrError = SBRDEC_OK;
|
|
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;
|
|
|
|
FIXP_DBL **OverlapBufferReal = hSbrDec->qmfDomainInCh->hQmfSlotsReal;
|
|
FIXP_DBL **OverlapBufferImag = hSbrDec->qmfDomainInCh->hQmfSlotsImag;
|
|
|
|
/* 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;
|
|
|
|
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
|
|
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 = 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));
|
|
}
|
|
}
|
|
|
|
/*
|
|
reset LPC filter states
|
|
*/
|
|
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.
|
|
*/
|
|
|
|
/* 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.
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
|
|
startBand = new_lsb;
|
|
stopBand = old_lsb;
|
|
|
|
target_lsb = old_lsb;
|
|
target_usb = old_usb;
|
|
}
|
|
|
|
maxVal =
|
|
maxSubbandSample(OverlapBufferReal, (useLP) ? NULL : OverlapBufferImag,
|
|
startBand, stopBand, 0, startSlot);
|
|
|
|
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? */
|
|
|
|
/* 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;
|
|
}
|
|
|
|
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 (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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
hSbrDec->savedStates = 0;
|
|
|
|
if ((flags & SBRDEC_USAC_HARMONICSBR) && applySbrProc) {
|
|
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;
|
|
}
|