aboutsummaryrefslogtreecommitdiffstats
path: root/libSACdec/src/sac_dec.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libSACdec/src/sac_dec.cpp')
-rw-r--r--libSACdec/src/sac_dec.cpp1509
1 files changed, 1509 insertions, 0 deletions
diff --git a/libSACdec/src/sac_dec.cpp b/libSACdec/src/sac_dec.cpp
new file mode 100644
index 0000000..4537d6e
--- /dev/null
+++ b/libSACdec/src/sac_dec.cpp
@@ -0,0 +1,1509 @@
+/* -----------------------------------------------------------------------------
+Software License for The Fraunhofer FDK AAC Codec Library for Android
+
+© 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.
+
+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
+----------------------------------------------------------------------------- */
+
+/*********************** MPEG surround decoder library *************************
+
+ Author(s):
+
+ Description: SAC Decoder Library
+
+*******************************************************************************/
+
+#include "sac_dec_errorcodes.h"
+#include "sac_dec.h"
+
+#include "sac_process.h"
+#include "sac_bitdec.h"
+#include "sac_smoothing.h"
+#include "sac_calcM1andM2.h"
+#include "sac_reshapeBBEnv.h"
+#include "sac_stp.h"
+#include "sac_rom.h"
+
+#include "FDK_decorrelate.h"
+
+#include "FDK_trigFcts.h"
+#include "FDK_matrixCalloc.h"
+
+/* static int pbStrideTable[] = {1, 2, 5, 28}; see sac_rom.cpp */
+
+enum {
+ APPLY_M2_NONE = 0, /* init value */
+ APPLY_M2 = 1, /* apply m2 fallback implementation */
+ APPLY_M2_MODE212 = 2, /* apply m2 for 212 mode */
+ APPLY_M2_MODE212_Res_PhaseCoding =
+ 3 /* apply m2 for 212 mode with residuals and phase coding */
+};
+
+/******************************************************************************************/
+/* function: FDK_SpatialDecInitDefaultSpatialSpecificConfig */
+/* output: struct of type SPATIAL_SPECIFIC_CONFIG */
+/* input: core coder audio object type */
+/* input: nr of core channels */
+/* input: sampling rate */
+/* input: nr of time slots */
+/* input: decoder level */
+/* input: flag indicating upmix type blind */
+/* */
+/* returns: error code */
+/******************************************************************************************/
+int FDK_SpatialDecInitDefaultSpatialSpecificConfig(
+ SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig,
+ AUDIO_OBJECT_TYPE coreCodec, int coreChannels, int samplingFreq,
+ int nTimeSlots, int decoderLevel, int isBlind) {
+ return SpatialDecDefaultSpecificConfig(pSpatialSpecificConfig, coreCodec,
+ samplingFreq, nTimeSlots, decoderLevel,
+ isBlind, coreChannels);
+}
+
+/******************************************************************************************/
+/* function: FDK_SpatialDecCompareSpatialSpecificConfigHeader */
+/* input: 2 pointers to a ssc */
+/* */
+/* output: - */
+/* returns: error code (0 = equal, <>0 unequal) */
+/******************************************************************************************/
+int FDK_SpatialDecCompareSpatialSpecificConfigHeader(
+ SPATIAL_SPECIFIC_CONFIG *pSsc1, SPATIAL_SPECIFIC_CONFIG *pSsc2) {
+ int result = MPS_OK;
+
+ /* we assume: every bit must be equal */
+ if (FDKmemcmp(pSsc1, pSsc2, sizeof(SPATIAL_SPECIFIC_CONFIG)) != 0) {
+ result = MPS_UNEQUAL_SSC;
+ }
+ return result;
+}
+
+/*******************************************************************************
+ Functionname: SpatialDecClearFrameData
+ *******************************************************************************
+
+ Description: Clear/Fake frame data to avoid misconfiguration and allow proper
+ error concealment.
+ Arguments:
+ Input: self (frame data)
+ Output: No return value.
+
+*******************************************************************************/
+static void SpatialDecClearFrameData(
+ spatialDec *self, /* Shall be removed */
+ SPATIAL_BS_FRAME *bsFrame, const SACDEC_CREATION_PARAMS *const setup) {
+ int i;
+
+ FDK_ASSERT(self != NULL);
+ FDK_ASSERT(bsFrame != NULL);
+ FDK_ASSERT(setup != NULL);
+
+ /* do not apply shaping tools (GES or STP) */
+ for (i = 0; i < setup->maxNumOutputChannels;
+ i += 1) { /* MAX_OUTPUT_CHANNELS */
+ bsFrame->tempShapeEnableChannelSTP[i] = 0;
+ bsFrame->tempShapeEnableChannelGES[i] = 0;
+ }
+
+ bsFrame->TsdData->bsTsdEnable = 0;
+
+ /* use only 1 parameter set at the end of the frame */
+ bsFrame->numParameterSets = 1;
+ bsFrame->paramSlot[0] = self->timeSlots - 1;
+
+ /* parameter smoothing tool set to off */
+ bsFrame->bsSmoothMode[0] = 0;
+
+ /* reset residual data */
+ {
+ int resQmfBands, resTimeSlots = (1);
+
+ resQmfBands = setup->maxNumQmfBands;
+
+ for (i = 0; i < setup->bProcResidual
+ ? fMin(setup->maxNumResChannels,
+ setup->maxNumOttBoxes + setup->maxNumInputChannels)
+ : 0;
+ i += 1) {
+ for (int j = 0; j < resTimeSlots; j += 1) {
+ for (int k = 0; k < resQmfBands; k += 1) {
+ self->qmfResidualReal__FDK[i][j][k] = FL2FXCONST_DBL(0.0f);
+ self->qmfResidualImag__FDK[i][j][k] = FL2FXCONST_DBL(0.0f);
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ Functionname: FDK_SpatialDecOpen
+ *******************************************************************************
+
+ Description:
+
+ Arguments:
+
+ Return:
+
+*******************************************************************************/
+spatialDec *FDK_SpatialDecOpen(const SPATIAL_DEC_CONFIG *config,
+ int stereoConfigIndex) {
+ int i;
+ int lfSize, hfSize;
+ spatialDec *self = NULL;
+ SACDEC_CREATION_PARAMS setup;
+
+ switch (config->decoderLevel) {
+ case DECODER_LEVEL_0: /* 212 maxNumOutputChannels== 2 */
+ setup.maxNumInputChannels = 1;
+ setup.maxNumOutputChannels = 2;
+ setup.maxNumQmfBands = 64;
+ setup.maxNumXChannels = 2;
+ setup.maxNumVChannels = 2;
+ setup.maxNumDecorChannels = 1;
+ setup.bProcResidual = 1;
+ setup.maxNumResidualChannels = 0;
+ setup.maxNumOttBoxes = 1;
+ setup.maxNumParams = setup.maxNumInputChannels + setup.maxNumOttBoxes;
+ break;
+ default:
+ return NULL;
+ }
+
+ setup.maxNumResChannels = 1;
+
+ {
+ switch (config->maxNumOutputChannels) {
+ case OUTPUT_CHANNELS_2_0:
+ setup.maxNumOutputChannels = fMin(setup.maxNumOutputChannels, 2);
+ break;
+ case OUTPUT_CHANNELS_DEFAULT:
+ default:
+ break;
+ }
+ }
+
+ setup.maxNumHybridBands = SacGetHybridSubbands(setup.maxNumQmfBands);
+
+ switch (config->decoderMode) {
+ case EXT_HQ_ONLY:
+ setup.maxNumCmplxQmfBands = setup.maxNumQmfBands;
+ setup.maxNumCmplxHybBands = setup.maxNumHybridBands;
+ break;
+ default:
+ setup.maxNumCmplxQmfBands = fixMax(PC_NUM_BANDS, setup.maxNumQmfBands);
+ setup.maxNumCmplxHybBands =
+ fixMax(PC_NUM_HYB_BANDS, setup.maxNumHybridBands);
+ break;
+ } /* switch config->decoderMode */
+
+ FDK_ALLOCATE_MEMORY_1D_INT(self, 1, spatialDec, SECT_DATA_L2)
+
+ self->createParams = setup;
+
+ FDK_ALLOCATE_MEMORY_1D(self->param2hyb, MAX_PARAMETER_BANDS + 1, int)
+
+ FDK_ALLOCATE_MEMORY_1D(self->numOttBands, setup.maxNumOttBoxes, int)
+
+ /* allocate arrays */
+
+ FDK_ALLOCATE_MEMORY_1D(self->smgTime, MAX_PARAMETER_SETS, int)
+ FDK_ALLOCATE_MEMORY_2D(self->smgData, MAX_PARAMETER_SETS, MAX_PARAMETER_BANDS,
+ UCHAR)
+
+ FDK_ALLOCATE_MEMORY_3D(self->ottCLD__FDK, setup.maxNumOttBoxes,
+ MAX_PARAMETER_SETS, MAX_PARAMETER_BANDS, SCHAR)
+ FDK_ALLOCATE_MEMORY_3D(self->ottICC__FDK, setup.maxNumOttBoxes,
+ MAX_PARAMETER_SETS, MAX_PARAMETER_BANDS, SCHAR)
+ FDK_ALLOCATE_MEMORY_3D(self->ottIPD__FDK, setup.maxNumOttBoxes,
+ MAX_PARAMETER_SETS, MAX_PARAMETER_BANDS, SCHAR)
+
+ /* Last parameters from prev frame */
+ FDK_ALLOCATE_MEMORY_2D(self->ottCLDidxPrev, setup.maxNumOttBoxes,
+ MAX_PARAMETER_BANDS, SCHAR)
+ FDK_ALLOCATE_MEMORY_2D(self->ottICCidxPrev, setup.maxNumOttBoxes,
+ MAX_PARAMETER_BANDS, SCHAR)
+ FDK_ALLOCATE_MEMORY_3D(self->ottICCdiffidx, setup.maxNumOttBoxes,
+ MAX_PARAMETER_SETS, MAX_PARAMETER_BANDS, SCHAR)
+ FDK_ALLOCATE_MEMORY_2D(self->ottIPDidxPrev, setup.maxNumOttBoxes,
+ MAX_PARAMETER_BANDS, SCHAR)
+ FDK_ALLOCATE_MEMORY_2D(self->arbdmxGainIdxPrev, setup.maxNumInputChannels,
+ MAX_PARAMETER_BANDS, SCHAR)
+ FDK_ALLOCATE_MEMORY_2D(self->cmpOttCLDidxPrev, setup.maxNumOttBoxes,
+ MAX_PARAMETER_BANDS, SCHAR)
+ FDK_ALLOCATE_MEMORY_2D(self->cmpOttICCidxPrev, setup.maxNumOttBoxes,
+ MAX_PARAMETER_BANDS, SCHAR)
+ FDK_ALLOCATE_MEMORY_3D(self->outIdxData, setup.maxNumOttBoxes,
+ MAX_PARAMETER_SETS, MAX_PARAMETER_BANDS, SCHAR)
+
+ FDK_ALLOCATE_MEMORY_3D(self->arbdmxGain__FDK, setup.maxNumInputChannels,
+ MAX_PARAMETER_SETS, MAX_PARAMETER_BANDS, SCHAR)
+ FDK_ALLOCATE_MEMORY_1D(self->arbdmxAlpha__FDK, setup.maxNumInputChannels,
+ FIXP_DBL)
+ FDK_ALLOCATE_MEMORY_1D(self->arbdmxAlphaPrev__FDK, setup.maxNumInputChannels,
+ FIXP_DBL)
+ FDK_ALLOCATE_MEMORY_2D(self->cmpArbdmxGainIdxPrev, setup.maxNumInputChannels,
+ MAX_PARAMETER_BANDS, SCHAR)
+
+ FDK_ALLOCATE_MEMORY_2D(self->cmpOttIPDidxPrev, setup.maxNumOttBoxes,
+ MAX_PARAMETER_BANDS, SCHAR)
+
+ FDK_ALLOCATE_MEMORY_3D_INT(self->M2Real__FDK, setup.maxNumOutputChannels,
+ setup.maxNumVChannels, MAX_PARAMETER_BANDS,
+ FIXP_DBL, SECT_DATA_L2)
+ FDK_ALLOCATE_MEMORY_3D(self->M2Imag__FDK, setup.maxNumOutputChannels,
+ setup.maxNumVChannels, MAX_PARAMETER_BANDS, FIXP_DBL)
+
+ FDK_ALLOCATE_MEMORY_3D_INT(self->M2RealPrev__FDK, setup.maxNumOutputChannels,
+ setup.maxNumVChannels, MAX_PARAMETER_BANDS,
+ FIXP_DBL, SECT_DATA_L2)
+ FDK_ALLOCATE_MEMORY_3D(self->M2ImagPrev__FDK, setup.maxNumOutputChannels,
+ setup.maxNumVChannels, MAX_PARAMETER_BANDS, FIXP_DBL)
+
+ FDK_ALLOCATE_MEMORY_2D_INT_ALIGNED(
+ self->qmfInputReal__FDK, setup.maxNumInputChannels, setup.maxNumQmfBands,
+ FIXP_DBL, SECT_DATA_L2)
+ FDK_ALLOCATE_MEMORY_2D_INT_ALIGNED(
+ self->qmfInputImag__FDK, setup.maxNumInputChannels,
+ setup.maxNumCmplxQmfBands, FIXP_DBL, SECT_DATA_L2)
+
+ FDK_ALLOCATE_MEMORY_2D_INT(self->hybInputReal__FDK, setup.maxNumInputChannels,
+ setup.maxNumHybridBands, FIXP_DBL, SECT_DATA_L2)
+ FDK_ALLOCATE_MEMORY_2D_INT(self->hybInputImag__FDK, setup.maxNumInputChannels,
+ setup.maxNumCmplxHybBands, FIXP_DBL, SECT_DATA_L2)
+
+ if (setup.bProcResidual) {
+ FDK_ALLOCATE_MEMORY_1D(self->qmfResidualReal__FDK, setup.maxNumResChannels,
+ FIXP_DBL **)
+ FDK_ALLOCATE_MEMORY_1D(self->qmfResidualImag__FDK, setup.maxNumResChannels,
+ FIXP_DBL **)
+
+ FDK_ALLOCATE_MEMORY_1D(self->hybResidualReal__FDK, setup.maxNumResChannels,
+ FIXP_DBL *)
+ FDK_ALLOCATE_MEMORY_1D(self->hybResidualImag__FDK, setup.maxNumResChannels,
+ FIXP_DBL *)
+
+ for (i = 0; i < setup.maxNumResChannels; i++) {
+ int resQmfBands = (config->decoderMode == EXT_LP_ONLY)
+ ? PC_NUM_BANDS
+ : setup.maxNumQmfBands;
+ int resHybBands = (config->decoderMode == EXT_LP_ONLY)
+ ? PC_NUM_HYB_BANDS
+ : setup.maxNumHybridBands;
+ /* Alignment is needed for USAC residuals because QMF analysis directly
+ * writes to this buffer. */
+ FDK_ALLOCATE_MEMORY_2D_INT_ALIGNED(self->qmfResidualReal__FDK[i], (1),
+ resQmfBands, FIXP_DBL, SECT_DATA_L1)
+ FDK_ALLOCATE_MEMORY_2D_INT_ALIGNED(self->qmfResidualImag__FDK[i], (1),
+ resQmfBands, FIXP_DBL, SECT_DATA_L1)
+
+ FDK_ALLOCATE_MEMORY_1D(self->hybResidualReal__FDK[i],
+ setup.maxNumHybridBands, FIXP_DBL)
+ FDK_ALLOCATE_MEMORY_1D(self->hybResidualImag__FDK[i], resHybBands,
+ FIXP_DBL)
+ }
+ } /* if (setup.bProcResidual) */
+
+ FDK_ALLOCATE_MEMORY_2D_INT(self->wReal__FDK, setup.maxNumVChannels,
+ setup.maxNumHybridBands, FIXP_DBL, SECT_DATA_L2)
+ FDK_ALLOCATE_MEMORY_2D_INT(self->wImag__FDK, setup.maxNumVChannels,
+ setup.maxNumCmplxHybBands, FIXP_DBL, SECT_DATA_L2)
+
+ FDK_ALLOCATE_MEMORY_2D_INT(self->hybOutputRealDry__FDK,
+ setup.maxNumOutputChannels,
+ setup.maxNumHybridBands, FIXP_DBL, SECT_DATA_L2)
+ FDK_ALLOCATE_MEMORY_2D_INT(self->hybOutputImagDry__FDK,
+ setup.maxNumOutputChannels,
+ setup.maxNumCmplxHybBands, FIXP_DBL, SECT_DATA_L2)
+
+ FDK_ALLOCATE_MEMORY_2D_INT(self->hybOutputRealWet__FDK,
+ setup.maxNumOutputChannels,
+ setup.maxNumHybridBands, FIXP_DBL, SECT_DATA_L2)
+ FDK_ALLOCATE_MEMORY_2D_INT(self->hybOutputImagWet__FDK,
+ setup.maxNumOutputChannels,
+ setup.maxNumCmplxHybBands, FIXP_DBL, SECT_DATA_L2)
+
+ FDK_ALLOCATE_MEMORY_1D(self->hybridSynthesis, setup.maxNumOutputChannels,
+ FDK_SYN_HYB_FILTER)
+
+ FDK_ALLOCATE_MEMORY_1D(
+ self->hybridAnalysis,
+ setup.bProcResidual ? setup.maxNumInputChannels + setup.maxNumResChannels
+ : setup.maxNumInputChannels,
+ FDK_ANA_HYB_FILTER)
+
+ lfSize = 2 * BUFFER_LEN_LF * MAX_QMF_BANDS_TO_HYBRID;
+ {
+ hfSize =
+ BUFFER_LEN_HF * ((setup.maxNumQmfBands - MAX_QMF_BANDS_TO_HYBRID) +
+ (setup.maxNumCmplxQmfBands - MAX_QMF_BANDS_TO_HYBRID));
+ }
+
+ FDK_ALLOCATE_MEMORY_2D_INT(self->pHybridAnaStatesLFdmx,
+ setup.maxNumInputChannels, lfSize, FIXP_DBL,
+ SECT_DATA_L2) {
+ FDK_ALLOCATE_MEMORY_2D(self->pHybridAnaStatesHFdmx,
+ setup.maxNumInputChannels, hfSize, FIXP_DBL)
+ }
+
+ for (i = 0; i < setup.maxNumInputChannels; i++) {
+ FIXP_DBL *pHybridAnaStatesHFdmx;
+
+ pHybridAnaStatesHFdmx = self->pHybridAnaStatesHFdmx[i];
+
+ FDKhybridAnalysisOpen(&self->hybridAnalysis[i],
+ self->pHybridAnaStatesLFdmx[i],
+ lfSize * sizeof(FIXP_DBL), pHybridAnaStatesHFdmx,
+ hfSize * sizeof(FIXP_DBL));
+ }
+ if (setup.bProcResidual) {
+ lfSize = 2 * BUFFER_LEN_LF * MAX_QMF_BANDS_TO_HYBRID;
+ hfSize = BUFFER_LEN_HF *
+ ((((config->decoderMode == EXT_LP_ONLY) ? PC_NUM_BANDS
+ : setup.maxNumQmfBands) -
+ MAX_QMF_BANDS_TO_HYBRID) +
+ (setup.maxNumCmplxQmfBands - MAX_QMF_BANDS_TO_HYBRID));
+
+ FDK_ALLOCATE_MEMORY_2D_INT(self->pHybridAnaStatesLFres,
+ setup.maxNumResChannels, lfSize, FIXP_DBL,
+ SECT_DATA_L2)
+ FDK_ALLOCATE_MEMORY_2D(self->pHybridAnaStatesHFres, setup.maxNumResChannels,
+ hfSize, FIXP_DBL)
+
+ for (i = setup.maxNumInputChannels;
+ i < (setup.maxNumInputChannels + setup.maxNumResChannels); i++) {
+ FDKhybridAnalysisOpen(
+ &self->hybridAnalysis[i],
+ self->pHybridAnaStatesLFres[i - setup.maxNumInputChannels],
+ lfSize * sizeof(FIXP_DBL),
+ self->pHybridAnaStatesHFres[i - setup.maxNumInputChannels],
+ hfSize * sizeof(FIXP_DBL));
+ }
+ }
+
+ FDK_ALLOCATE_MEMORY_1D(self->smoothState, 1, SMOOTHING_STATE)
+ FDK_ALLOCATE_MEMORY_1D(self->reshapeBBEnvState, 1, RESHAPE_BBENV_STATE)
+
+ FDK_ALLOCATE_MEMORY_1D(self->apDecor, setup.maxNumDecorChannels, DECORR_DEC)
+ FDK_ALLOCATE_MEMORY_2D_INT(self->pDecorBufferCplx, setup.maxNumDecorChannels,
+ (2 * ((825) + (373))), FIXP_DBL, SECT_DATA_L2)
+
+ for (i = 0; i < setup.maxNumDecorChannels; i++) {
+ if (FDKdecorrelateOpen(&self->apDecor[i], self->pDecorBufferCplx[i],
+ (2 * ((825) + (373))))) {
+ goto bail;
+ }
+ }
+
+ if (subbandTPCreate(&self->hStpDec) != MPS_OK) {
+ goto bail;
+ }
+
+ /* save general decoder configuration */
+ self->decoderLevel = config->decoderLevel;
+ self->decoderMode = config->decoderMode;
+ self->binauralMode = config->binauralMode;
+
+ /* preinitialize configuration */
+ self->partiallyComplex = (config->decoderMode != EXT_HQ_ONLY) ? 1 : 0;
+
+ /* Set to default state */
+ SpatialDecConcealment_Init(&self->concealInfo, MPEGS_CONCEAL_RESET_ALL);
+
+ /* Everything is fine so return the handle */
+ return self;
+
+bail:
+ /* Collector for all errors.
+ Deallocate all memory and return a invalid handle. */
+ FDK_SpatialDecClose(self);
+
+ return NULL;
+}
+
+/*******************************************************************************
+ Functionname: isValidConfig
+ *******************************************************************************
+
+ Description: Validate if configuration is supported in present instance
+
+ Arguments:
+
+ Return: 1: all okay
+ 0: configuration not supported
+*******************************************************************************/
+static int isValidConfig(spatialDec const *const self,
+ const SPATIAL_DEC_UPMIX_TYPE upmixType,
+ SPATIALDEC_PARAM const *const pUserParams,
+ const AUDIO_OBJECT_TYPE coreAot) {
+ UPMIXTYPE nUpmixType;
+
+ FDK_ASSERT(self != NULL);
+ FDK_ASSERT(pUserParams != NULL);
+
+ nUpmixType = (UPMIXTYPE)upmixType;
+
+ switch (nUpmixType) {
+ case UPMIXTYPE_BYPASS: /* UPMIX_TYPE_BYPASS */
+ break;
+ case UPMIXTYPE_NORMAL: /* UPMIX_TYPE_NORMAL */
+ break;
+ default:
+ return 0; /* unsupported upmixType */
+ }
+
+ return 1; /* upmixType supported */
+}
+
+static SACDEC_ERROR CheckLevelTreeUpmixType(
+ const SACDEC_CREATION_PARAMS *const pCreateParams,
+ const SPATIAL_SPECIFIC_CONFIG *const pSsc, const int decoderLevel,
+ const UPMIXTYPE upmixType) {
+ SACDEC_ERROR err = MPS_OK;
+ int nOutputChannels, treeConfig;
+
+ FDK_ASSERT(pCreateParams != NULL);
+ FDK_ASSERT(pSsc != NULL);
+
+ treeConfig = pSsc->treeConfig;
+
+ switch (decoderLevel) {
+ case 0: {
+ if (treeConfig != SPATIALDEC_MODE_RSVD7) {
+ err = MPS_INVALID_TREECONFIG;
+ goto bail;
+ }
+ break;
+ }
+ default:
+ err = MPS_INVALID_PARAMETER /* MPS_UNIMPLEMENTED */;
+ goto bail;
+ }
+
+ switch (upmixType) {
+ case UPMIXTYPE_BYPASS:
+ nOutputChannels = pSsc->nInputChannels;
+ break;
+ default:
+ nOutputChannels = pSsc->nOutputChannels;
+ break;
+ }
+
+ /* Is sufficient memory allocated. */
+ if ((pSsc->nInputChannels > pCreateParams->maxNumInputChannels) ||
+ (nOutputChannels > pCreateParams->maxNumOutputChannels) ||
+ (pSsc->nOttBoxes > pCreateParams->maxNumOttBoxes)) {
+ err = MPS_INVALID_PARAMETER;
+ }
+
+bail:
+ return err;
+}
+
+void SpatialDecInitParserContext(spatialDec *self) {
+ int i, j;
+
+ for (i = 0; i < self->createParams.maxNumOttBoxes; i += 1) {
+ for (j = 0; j < MAX_PARAMETER_BANDS; j++) {
+ self->ottCLDidxPrev[i][j] = 0;
+ self->ottICCidxPrev[i][j] = 0;
+ self->cmpOttCLDidxPrev[i][j] = 0;
+ self->cmpOttICCidxPrev[i][j] = 0;
+ }
+ }
+ for (i = 0; i < self->createParams.maxNumInputChannels; i++) {
+ for (j = 0; j < MAX_PARAMETER_BANDS; j++) {
+ self->arbdmxGainIdxPrev[i][j] = 0;
+ self->cmpArbdmxGainIdxPrev[i][j] = 0;
+ }
+ }
+}
+
+/*******************************************************************************
+ Functionname: FDK_SpatialDecInit
+ *******************************************************************************
+
+ Description:
+
+ Arguments:
+
+ Return:
+
+*******************************************************************************/
+
+SACDEC_ERROR FDK_SpatialDecInit(spatialDec *self, SPATIAL_BS_FRAME *frame,
+ SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig,
+ int nQmfBands,
+ SPATIAL_DEC_UPMIX_TYPE const upmixType,
+ SPATIALDEC_PARAM *pUserParams, UINT initFlags) {
+ SACDEC_ERROR err = MPS_OK;
+ int nCh, i, j, k;
+ int maxQmfBands;
+ int bypassMode = 0;
+
+ self->useFDreverb = 0;
+
+ /* check configuration parameter */
+ if (!isValidConfig(self, upmixType, pUserParams,
+ pSpatialSpecificConfig->coreCodec)) {
+ return MPS_INVALID_PARAMETER;
+ }
+
+ /* check tree configuration */
+ err = CheckLevelTreeUpmixType(&self->createParams, pSpatialSpecificConfig,
+ self->decoderLevel, (UPMIXTYPE)upmixType);
+ if (err != MPS_OK) {
+ goto bail;
+ }
+
+ /* Store and update instance after all checks passed successfully: */
+ self->upmixType = (UPMIXTYPE)upmixType;
+
+ if (initFlags & MPEGS_INIT_PARAMS_ERROR_CONCEALMENT) { /* At least one error
+ concealment
+ parameter changed */
+ err = SpatialDecConcealment_SetParam(
+ &self->concealInfo, SAC_DEC_CONCEAL_METHOD, pUserParams->concealMethod);
+ if (err != MPS_OK) {
+ goto bail;
+ }
+ err = SpatialDecConcealment_SetParam(&self->concealInfo,
+ SAC_DEC_CONCEAL_NUM_KEEP_FRAMES,
+ pUserParams->concealNumKeepFrames);
+ if (err != MPS_OK) {
+ goto bail;
+ }
+ err = SpatialDecConcealment_SetParam(
+ &self->concealInfo, SAC_DEC_CONCEAL_FADE_OUT_SLOPE_LENGTH,
+ pUserParams->concealFadeOutSlopeLength);
+ if (err != MPS_OK) {
+ goto bail;
+ }
+ err = SpatialDecConcealment_SetParam(&self->concealInfo,
+ SAC_DEC_CONCEAL_FADE_IN_SLOPE_LENGTH,
+ pUserParams->concealFadeInSlopeLength);
+ if (err != MPS_OK) {
+ goto bail;
+ }
+ err = SpatialDecConcealment_SetParam(&self->concealInfo,
+ SAC_DEC_CONCEAL_NUM_RELEASE_FRAMES,
+ pUserParams->concealNumReleaseFrames);
+ if (err != MPS_OK) {
+ goto bail;
+ }
+ }
+
+ if (initFlags &
+ MPEGS_INIT_STATES_ERROR_CONCEALMENT) { /* Set to default state */
+ SpatialDecConcealment_Init(&self->concealInfo, MPEGS_CONCEAL_RESET_STATE);
+ }
+
+ /* determine bypass mode */
+ bypassMode |= pUserParams->bypassMode;
+ bypassMode |= ((self->upmixType == UPMIXTYPE_BYPASS) ? 1 : 0);
+
+ /* static decoder scale depends on number of qmf bands */
+ switch (nQmfBands) {
+ case 16:
+ case 24:
+ case 32:
+ self->staticDecScale = 21;
+ break;
+ case 64:
+ self->staticDecScale = 22;
+ break;
+ default:
+ return MPS_INVALID_PARAMETER;
+ }
+
+ self->numParameterSetsPrev = 1;
+
+ self->qmfBands = nQmfBands;
+ /* self->hybridBands will be updated in SpatialDecDecodeHeader() below. */
+
+ self->bShareDelayWithSBR = 0;
+
+ err = SpatialDecDecodeHeader(self, pSpatialSpecificConfig);
+ if (err != MPS_OK) {
+ goto bail;
+ }
+
+ self->stereoConfigIndex = pSpatialSpecificConfig->stereoConfigIndex;
+
+ if (initFlags & MPEGS_INIT_STATES_ANA_QMF_FILTER) {
+ self->qmfInputDelayBufPos = 0;
+ self->pc_filterdelay = 1; /* Division by 0 not possible */
+ }
+
+ maxQmfBands = self->qmfBands;
+
+ /* init residual decoder */
+
+ /* init tonality smoothing */
+ if (initFlags & MPEGS_INIT_STATES_PARAM) {
+ initParameterSmoothing(self);
+ }
+
+ /* init GES */
+ initBBEnv(self, (initFlags & MPEGS_INIT_STATES_GES) ? 1 : 0);
+
+ /* Clip protection is applied only for normal processing. */
+ if (!isTwoChMode(self->upmixType) && !bypassMode) {
+ self->staticDecScale += self->clipProtectGainSF__FDK;
+ }
+
+ {
+ UINT flags = 0;
+ INT initStatesFlag = (initFlags & MPEGS_INIT_STATES_ANA_QMF_FILTER) ? 1 : 0;
+ INT useLdFilter =
+ (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD) ? 1 : 0;
+
+ flags = self->pQmfDomain->globalConf.flags_requested;
+ flags &= (~(UINT)QMF_FLAG_LP);
+
+ if (initStatesFlag)
+ flags &= ~QMF_FLAG_KEEP_STATES;
+ else
+ flags |= QMF_FLAG_KEEP_STATES;
+
+ if (useLdFilter)
+ flags |= QMF_FLAG_MPSLDFB;
+ else
+ flags &= ~QMF_FLAG_MPSLDFB;
+
+ self->pQmfDomain->globalConf.flags_requested = flags;
+ FDK_QmfDomain_Configure(self->pQmfDomain);
+
+ /* output scaling */
+ for (nCh = 0; nCh < self->numOutputChannelsAT; nCh++) {
+ int outputScale = 0, outputGain_e = 0, scale = 0;
+ FIXP_DBL outputGain_m = getChGain(self, nCh, &outputGain_e);
+
+ if (!isTwoChMode(self->upmixType) && !bypassMode) {
+ outputScale +=
+ self->clipProtectGainSF__FDK; /* consider clip protection scaling at
+ synthesis qmf */
+ }
+
+ scale = outputScale;
+
+ qmfChangeOutScalefactor(&self->pQmfDomain->QmfDomainOut[nCh].fb, scale);
+ qmfChangeOutGain(&self->pQmfDomain->QmfDomainOut[nCh].fb, outputGain_m,
+ outputGain_e);
+ }
+ }
+
+ for (nCh = 0; nCh < self->numOutputChannelsAT; nCh++) {
+ FDKhybridSynthesisInit(&self->hybridSynthesis[nCh], THREE_TO_TEN,
+ self->qmfBands, maxQmfBands);
+ }
+
+ /* for input, residual channels and arbitrary down-mix residual channels */
+ for (nCh = 0; nCh < self->createParams.maxNumInputChannels; nCh++) {
+ FDKhybridAnalysisInit(
+ &self->hybridAnalysis[nCh], THREE_TO_TEN, self->qmfBands, maxQmfBands,
+ (initFlags & MPEGS_INIT_STATES_ANA_HYB_FILTER) ? 1 : 0);
+ }
+ for (; nCh < (self->createParams.bProcResidual
+ ? (self->createParams.maxNumInputChannels +
+ self->createParams.maxNumResChannels)
+ : self->createParams.maxNumInputChannels);
+ nCh++) {
+ FDKhybridAnalysisInit(&self->hybridAnalysis[nCh], THREE_TO_TEN, maxQmfBands,
+ maxQmfBands, 0);
+ }
+
+ {
+ for (k = 0; k < self->numDecorSignals; k++) {
+ int errCode, idec;
+ FDK_DECORR_TYPE decorrType = DECORR_PS;
+ decorrType = DECORR_LD;
+ if (self->pConfigCurrent->syntaxFlags &
+ (SACDEC_SYNTAX_USAC | SACDEC_SYNTAX_RSVD50)) {
+ decorrType =
+ ((self->treeConfig == TREE_212) && (self->decorrType == DECORR_PS))
+ ? DECORR_PS
+ : DECORR_USAC;
+ }
+ {
+ idec = k;
+ if (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD) {
+ if (self->treeConfig == TREE_212 && k == 0) {
+ idec = 2;
+ }
+ }
+ }
+ errCode = FDKdecorrelateInit(
+ &self->apDecor[k], self->hybridBands, decorrType, DUCKER_AUTOMATIC,
+ self->decorrConfig, idec, 0, /* self->partiallyComplex */
+ 0, 0, /* isLegacyPS */
+ (initFlags & MPEGS_INIT_STATES_DECORRELATOR) ? 1 : 0);
+ if (errCode) return MPS_NOTOK;
+ }
+ } /* !self->partiallyComplex */
+
+ err = initM1andM2(self, (initFlags & MPEGS_INIT_STATES_M1M2) ? 1 : 0,
+ (initFlags & MPEGS_INIT_CONFIG) ? 1 : 0);
+ if (err != MPS_OK) return err;
+
+ /* Initialization of previous frame data */
+ if (initFlags & MPEGS_INIT_STATES_PARAM) {
+ for (i = 0; i < self->createParams.maxNumOttBoxes; i += 1) {
+ /* reset icc diff data */
+ for (k = 0; k < MAX_PARAMETER_SETS; k += 1) {
+ for (j = 0; j < MAX_PARAMETER_BANDS; j += 1) {
+ self->ottICCdiffidx[i][k][j] = 0;
+ }
+ }
+ }
+ /* Parameter Smoothing */
+ /* robustness: init with one of the values of smgTimeTable[] = {64, 128,
+ 256, 512} to avoid division by zero in calcFilterCoeff__FDK() */
+ self->smoothState->prevSmgTime = smgTimeTable[2]; /* == 256 */
+ FDKmemclear(self->smoothState->prevSmgData,
+ MAX_PARAMETER_BANDS * sizeof(UCHAR));
+ FDKmemclear(self->smoothState->opdLeftState__FDK,
+ MAX_PARAMETER_BANDS * sizeof(FIXP_DBL));
+ FDKmemclear(self->smoothState->opdRightState__FDK,
+ MAX_PARAMETER_BANDS * sizeof(FIXP_DBL));
+ }
+
+ self->prevTimeSlot = -1;
+ self->curTimeSlot =
+ MAX_TIME_SLOTS + 1; /* Initialize with a invalid value to trigger
+ concealment if first frame has no valid data. */
+ self->curPs = 0;
+
+ subbandTPInit(self->hStpDec);
+
+bail:
+ return err;
+}
+
+void SpatialDecChannelProperties(spatialDec *self,
+ AUDIO_CHANNEL_TYPE channelType[],
+ UCHAR channelIndices[],
+ const FDK_channelMapDescr *const mapDescr) {
+ if ((self == NULL) || (channelType == NULL) || (channelIndices == NULL) ||
+ (mapDescr == NULL)) {
+ return; /* no extern buffer to be filled */
+ }
+
+ if (self->numOutputChannelsAT !=
+ treePropertyTable[self->treeConfig].numOutputChannels) {
+ int ch;
+ /* Declare all channels to be front channels: */
+ for (ch = 0; ch < self->numOutputChannelsAT; ch += 1) {
+ channelType[ch] = ACT_FRONT;
+ channelIndices[ch] = ch;
+ }
+ } else {
+ /* ISO/IEC FDIS 23003-1:2006(E), page 46, Table 40 bsTreeConfig */
+ switch (self->treeConfig) {
+ case TREE_212:
+ channelType[0] = ACT_FRONT;
+ channelIndices[0] = 0;
+ channelType[1] = ACT_FRONT;
+ channelIndices[1] = 1;
+ break;
+ default:;
+ }
+ }
+}
+
+/*******************************************************************************
+ Functionname: FDK_SpatialDecClose
+ *******************************************************************************
+
+ Description:
+
+ Arguments:
+
+ Return:
+
+*******************************************************************************/
+
+void FDK_SpatialDecClose(spatialDec *self) {
+ if (self) {
+ int k;
+
+ if (self->apDecor != NULL) {
+ for (k = 0; k < self->createParams.maxNumDecorChannels; k++) {
+ FDKdecorrelateClose(&(self->apDecor[k]));
+ }
+ FDK_FREE_MEMORY_1D(self->apDecor);
+ }
+ if (self->pDecorBufferCplx != NULL) {
+ FDK_FREE_MEMORY_2D(self->pDecorBufferCplx);
+ }
+
+ subbandTPDestroy(&self->hStpDec);
+
+ FDK_FREE_MEMORY_1D(self->reshapeBBEnvState);
+ FDK_FREE_MEMORY_1D(self->smoothState);
+
+ FDK_FREE_MEMORY_2D(self->pHybridAnaStatesLFdmx);
+ FDK_FREE_MEMORY_2D(self->pHybridAnaStatesHFdmx);
+ FDK_FREE_MEMORY_2D(self->pHybridAnaStatesLFres);
+ FDK_FREE_MEMORY_2D(self->pHybridAnaStatesHFres);
+ FDK_FREE_MEMORY_1D(self->hybridAnalysis);
+
+ FDK_FREE_MEMORY_1D(self->hybridSynthesis);
+
+ /* The time buffer is passed to the decoder from outside to avoid copying
+ * (zero copy). */
+ /* FDK_FREE_MEMORY_2D(self->timeOut__FDK); */
+
+ FDK_FREE_MEMORY_2D(self->hybOutputImagWet__FDK);
+ FDK_FREE_MEMORY_2D(self->hybOutputRealWet__FDK);
+
+ FDK_FREE_MEMORY_2D(self->hybOutputImagDry__FDK);
+ FDK_FREE_MEMORY_2D(self->hybOutputRealDry__FDK);
+
+ FDK_FREE_MEMORY_2D(self->wImag__FDK);
+ FDK_FREE_MEMORY_2D(self->wReal__FDK);
+
+ if (self->createParams.bProcResidual) {
+ int i;
+
+ for (i = 0; i < self->createParams.maxNumResChannels; i++) {
+ if (self->hybResidualImag__FDK != NULL)
+ FDK_FREE_MEMORY_1D(self->hybResidualImag__FDK[i]);
+ if (self->hybResidualReal__FDK != NULL)
+ FDK_FREE_MEMORY_1D(self->hybResidualReal__FDK[i]);
+ if (self->qmfResidualImag__FDK != NULL)
+ FDK_FREE_MEMORY_2D_ALIGNED(self->qmfResidualImag__FDK[i]);
+ if (self->qmfResidualReal__FDK != NULL)
+ FDK_FREE_MEMORY_2D_ALIGNED(self->qmfResidualReal__FDK[i]);
+ }
+
+ FDK_FREE_MEMORY_1D(self->hybResidualImag__FDK);
+ FDK_FREE_MEMORY_1D(self->hybResidualReal__FDK);
+
+ FDK_FREE_MEMORY_1D(self->qmfResidualImag__FDK);
+ FDK_FREE_MEMORY_1D(self->qmfResidualReal__FDK);
+
+ } /* self->createParams.bProcResidual */
+
+ FDK_FREE_MEMORY_2D(self->hybInputImag__FDK);
+ FDK_FREE_MEMORY_2D(self->hybInputReal__FDK);
+
+ FDK_FREE_MEMORY_2D_ALIGNED(self->qmfInputImag__FDK);
+ FDK_FREE_MEMORY_2D_ALIGNED(self->qmfInputReal__FDK);
+
+ FDK_FREE_MEMORY_3D(self->M2ImagPrev__FDK);
+
+ FDK_FREE_MEMORY_3D(self->M2RealPrev__FDK);
+
+ FDK_FREE_MEMORY_3D(self->M2Imag__FDK);
+
+ FDK_FREE_MEMORY_3D(self->M2Real__FDK);
+
+ FDK_FREE_MEMORY_1D(self->arbdmxAlphaPrev__FDK);
+ FDK_FREE_MEMORY_1D(self->arbdmxAlpha__FDK);
+
+ FDK_FREE_MEMORY_3D(self->arbdmxGain__FDK);
+
+ FDK_FREE_MEMORY_3D(self->ottIPD__FDK);
+ FDK_FREE_MEMORY_3D(self->ottICC__FDK);
+ FDK_FREE_MEMORY_3D(self->ottCLD__FDK);
+
+ /* Last parameters from prev frame */
+ FDK_FREE_MEMORY_2D(self->ottCLDidxPrev);
+ FDK_FREE_MEMORY_2D(self->ottICCidxPrev);
+ FDK_FREE_MEMORY_3D(self->ottICCdiffidx);
+ FDK_FREE_MEMORY_2D(self->ottIPDidxPrev);
+ FDK_FREE_MEMORY_2D(self->arbdmxGainIdxPrev);
+
+ FDK_FREE_MEMORY_2D(self->cmpOttCLDidxPrev);
+ FDK_FREE_MEMORY_2D(self->cmpOttICCidxPrev);
+ FDK_FREE_MEMORY_3D(self->outIdxData);
+ FDK_FREE_MEMORY_2D(self->cmpOttIPDidxPrev);
+ FDK_FREE_MEMORY_2D(self->cmpArbdmxGainIdxPrev);
+
+ FDK_FREE_MEMORY_2D(self->smgData);
+ FDK_FREE_MEMORY_1D(self->smgTime);
+
+ FDK_FREE_MEMORY_1D(self->numOttBands);
+
+ FDK_FREE_MEMORY_1D(self->param2hyb);
+
+ FDK_FREE_MEMORY_1D(self);
+ }
+
+ return;
+}
+
+/**
+ * \brief Apply Surround bypass buffer copies
+ * \param self spatialDec handle
+ * \param hybInputReal
+ * \param hybInputImag
+ * \param hybOutputReal
+ * \param hybOutputImag
+ * \param numInputChannels amount if input channels available in hybInputReal
+ * and hybInputImag, which may differ from self->numInputChannels.
+ */
+static void SpatialDecApplyBypass(spatialDec *self, FIXP_DBL **hybInputReal,
+ FIXP_DBL **hybInputImag,
+ FIXP_DBL **hybOutputReal,
+ FIXP_DBL **hybOutputImag,
+ const int numInputChannels) {
+ int complexHybBands;
+
+ complexHybBands = self->hybridBands;
+
+ {
+ int ch;
+ int rf = -1, lf = -1, cf = -1; /* Right Front, Left Front, Center Front */
+
+ /* Determine output channel indices according to tree config */
+ switch (self->treeConfig) {
+ case TREE_212: /* 212 */
+ lf = 0;
+ rf = 1;
+ break;
+ default:;
+ }
+
+ /* Note: numInputChannels might not match the tree config ! */
+ switch (numInputChannels) {
+ case 1:
+ if (cf > 0) {
+ FDKmemcpy(hybOutputReal[cf], hybInputReal[0],
+ self->hybridBands * sizeof(FIXP_DBL));
+ FDKmemcpy(hybOutputImag[cf], hybInputImag[0],
+ complexHybBands * sizeof(FIXP_DBL));
+ } else {
+ FDKmemcpy(hybOutputReal[lf], hybInputReal[0],
+ self->hybridBands * sizeof(FIXP_DBL));
+ FDKmemcpy(hybOutputReal[rf], hybInputReal[0],
+ self->hybridBands * sizeof(FIXP_DBL));
+ FDKmemcpy(hybOutputImag[lf], hybInputImag[0],
+ complexHybBands * sizeof(FIXP_DBL));
+ FDKmemcpy(hybOutputImag[rf], hybInputImag[0],
+ complexHybBands * sizeof(FIXP_DBL));
+ }
+ break;
+ case 2:
+ FDK_ASSERT(lf != -1);
+ FDK_ASSERT(rf != -1);
+ FDKmemcpy(hybOutputReal[lf], hybInputReal[0],
+ self->hybridBands * sizeof(FIXP_DBL));
+ FDKmemcpy(hybOutputReal[rf], hybInputReal[1],
+ self->hybridBands * sizeof(FIXP_DBL));
+ FDKmemcpy(hybOutputImag[lf], hybInputImag[0],
+ complexHybBands * sizeof(FIXP_DBL));
+ FDKmemcpy(hybOutputImag[rf], hybInputImag[1],
+ complexHybBands * sizeof(FIXP_DBL));
+ break;
+ }
+ for (ch = 0; ch < self->numOutputChannelsAT; ch++) {
+ if (ch == lf || ch == rf || ch == cf) {
+ continue; /* Skip bypassed channels */
+ }
+ FDKmemclear(hybOutputReal[ch], self->hybridBands * sizeof(FIXP_DBL));
+ FDKmemclear(hybOutputImag[ch], complexHybBands * sizeof(FIXP_DBL));
+ }
+ }
+}
+
+/*******************************************************************************
+ Functionname: SpatialDecApplyParameterSets
+ *******************************************************************************
+
+ Description:
+
+ Arguments:
+
+ Return:
+
+*******************************************************************************/
+static SACDEC_ERROR SpatialDecApplyParameterSets(
+ spatialDec *self, const SPATIAL_BS_FRAME *frame, SPATIALDEC_INPUT_MODE mode,
+ PCM_MPS *inData, /* Time domain input */
+ FIXP_DBL **qmfInDataReal, /* QMF domain data l/r */
+ FIXP_DBL **qmfInDataImag, /* QMF domain data l/r */
+ UINT nSamples, UINT controlFlags, int numInputChannels,
+ const FDK_channelMapDescr *const mapDescr) {
+ SACDEC_ERROR err = MPS_OK;
+
+ FIXP_SGL alpha;
+
+ int ts;
+ int ch;
+ int hyb;
+
+ int prevSlot = self->prevTimeSlot;
+ int ps = self->curPs;
+ int ts_io = 0; /* i/o dependent slot */
+ int bypassMode = (controlFlags & MPEGS_BYPASSMODE) ? 1 : 0;
+
+ /* Bypass can be triggered by the upmixType, too. */
+ bypassMode |= ((self->upmixType == UPMIXTYPE_BYPASS) ? 1 : 0);
+
+ /*
+ * Decode available slots
+ */
+ for (ts = self->curTimeSlot;
+ ts <= fixMin(self->curTimeSlot + (int)nSamples / self->qmfBands - 1,
+ self->timeSlots - 1);
+ ts++, ts_io++) {
+ int currSlot = frame->paramSlot[ps];
+
+ /*
+ * Get new parameter set
+ */
+ if (ts == prevSlot + 1) {
+ err = SpatialDecCalculateM1andM2(self, ps,
+ frame); /* input: ottCLD, ottICC, ... */
+ /* output: M1param(Real/Imag), M2(Real/Imag) */
+ if (err != MPS_OK) {
+ bypassMode = 1;
+ if (self->errInt == MPS_OK) {
+ /* store internal error befor it gets overwritten */
+ self->errInt = err;
+ }
+ err = MPS_OK;
+ }
+
+ if ((ps == 0) && (self->bOverwriteM1M2prev != 0)) {
+ /* copy matrix entries of M1/M2 of the first parameter set to the
+ previous matrices (of the last frame). This avoids the interpolation
+ of incompatible values. E.g. for residual bands the coefficients are
+ calculated differently compared to non-residual bands.
+ */
+ SpatialDecBufferMatrices(self); /* input: M(1/2)param(Real/Imag) */
+ /* output: M(1/2)param(Real/Imag)Prev */
+ self->bOverwriteM1M2prev = 0;
+ }
+
+ SpatialDecSmoothM1andM2(
+ self, frame,
+ ps); /* input: M1param(Real/Imag)(Prev), M2(Real/Imag)(Prev) */
+ /* output: M1param(Real/Imag), M2(Real/Imag) */
+ }
+
+ alpha = FX_DBL2FX_SGL(fDivNorm(ts - prevSlot, currSlot - prevSlot));
+
+ switch (mode) {
+ case INPUTMODE_QMF_SBR:
+ if (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD)
+ self->bShareDelayWithSBR = 0; /* We got no hybrid delay */
+ else
+ self->bShareDelayWithSBR = 1;
+ SpatialDecFeedQMF(self, qmfInDataReal, qmfInDataImag, ts_io, bypassMode,
+ self->qmfInputReal__FDK, self->qmfInputImag__FDK,
+ self->numInputChannels);
+ break;
+ case INPUTMODE_TIME:
+ self->bShareDelayWithSBR = 0;
+ SpatialDecQMFAnalysis(self, inData, ts_io, bypassMode,
+ self->qmfInputReal__FDK, self->qmfInputImag__FDK,
+ self->numInputChannels);
+ break;
+ default:
+ break;
+ }
+
+ if ((self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_USAC) &&
+ self->residualCoding) {
+ int offset;
+ ch = 1;
+
+ offset = self->pQmfDomain->globalConf.nBandsSynthesis *
+ self->pQmfDomain->globalConf.nQmfTimeSlots;
+
+ {
+ const PCM_MPS *inSamples =
+ &inData[ts * self->pQmfDomain->globalConf.nBandsAnalysis];
+
+ CalculateSpaceAnalysisQmf(
+ &self->pQmfDomain->QmfDomainIn[ch].fb, inSamples + (ch * offset),
+ self->qmfResidualReal__FDK[0][0], self->qmfResidualImag__FDK[0][0]);
+
+ if (!isTwoChMode(self->upmixType) && !bypassMode) {
+ int i;
+ FIXP_DBL *RESTRICT self_qmfResidualReal__FDK_0_0 =
+ &self->qmfResidualReal__FDK[0][0][0];
+ FIXP_DBL *RESTRICT self_qmfResidualImag__FDK_0_0 =
+ &self->qmfResidualImag__FDK[0][0][0];
+
+ if ((self->pQmfDomain->globalConf.nBandsAnalysis == 24) &&
+ !(self->stereoConfigIndex == 3)) {
+ for (i = 0; i < self->qmfBands; i++) {
+ self_qmfResidualReal__FDK_0_0[i] =
+ fMult(self_qmfResidualReal__FDK_0_0[i] << 1,
+ self->clipProtectGain__FDK);
+ self_qmfResidualImag__FDK_0_0[i] =
+ fMult(self_qmfResidualImag__FDK_0_0[i] << 1,
+ self->clipProtectGain__FDK);
+ }
+ } else {
+ for (i = 0; i < self->qmfBands; i++) {
+ self_qmfResidualReal__FDK_0_0[i] = fMult(
+ self_qmfResidualReal__FDK_0_0[i], self->clipProtectGain__FDK);
+ self_qmfResidualImag__FDK_0_0[i] = fMult(
+ self_qmfResidualImag__FDK_0_0[i], self->clipProtectGain__FDK);
+ }
+ }
+ }
+ }
+ }
+
+ SpatialDecHybridAnalysis(
+ self, /* input: qmfInput(Real/Imag), qmfResidual(Real/Imag) */
+ self->qmfInputReal__FDK, self->qmfInputImag__FDK,
+ self->hybInputReal__FDK, self->hybInputImag__FDK, ts, numInputChannels);
+
+ if (bypassMode) {
+ SpatialDecApplyBypass(
+ self, self->hybInputReal__FDK, /* input: hybInput(Real/Imag) */
+ self->hybInputImag__FDK,
+ self->hybOutputRealDry__FDK, /* output: hybOutput(Real/Imag)Dry */
+ self->hybOutputImagDry__FDK, numInputChannels);
+ } else /* !bypassMode */
+ {
+ FIXP_DBL *pxReal[MAX_NUM_XCHANNELS] = {NULL};
+ FIXP_DBL *pxImag[MAX_NUM_XCHANNELS] = {NULL};
+
+ SpatialDecCreateX(self,
+ self->hybInputReal__FDK, /* input: hybInput(Real/Imag),
+ hybResidual(Real/Imag) */
+ self->hybInputImag__FDK, pxReal, pxImag);
+
+ {
+ SpatialDecApplyM1_CreateW_Mode212(
+ self, frame, pxReal, pxImag,
+ self->wReal__FDK, /* output: w(Real/Imag) */
+ self->wImag__FDK);
+ }
+ if (err != MPS_OK) goto bail;
+
+ int applyM2Config = APPLY_M2_NONE;
+
+ applyM2Config = APPLY_M2;
+ if ((self->pConfigCurrent->syntaxFlags &
+ (SACDEC_SYNTAX_USAC | SACDEC_SYNTAX_RSVD50)) &&
+ (self->tempShapeConfig != 1) && (self->tempShapeConfig != 2)) {
+ if (self->phaseCoding == 3)
+ applyM2Config = APPLY_M2_MODE212_Res_PhaseCoding;
+ else
+ applyM2Config = APPLY_M2_MODE212;
+ }
+
+ switch (applyM2Config) {
+ case APPLY_M2_MODE212: {
+ err = SpatialDecApplyM2_Mode212(
+ self, ps, alpha, self->wReal__FDK, self->wImag__FDK,
+ self->hybOutputRealDry__FDK, self->hybOutputImagDry__FDK);
+ } break;
+ case APPLY_M2_MODE212_Res_PhaseCoding:
+ err = SpatialDecApplyM2_Mode212_ResidualsPlusPhaseCoding(
+ self, ps, alpha, self->wReal__FDK, self->wImag__FDK,
+ self->hybOutputRealDry__FDK, self->hybOutputImagDry__FDK);
+ break;
+ case APPLY_M2:
+ err = SpatialDecApplyM2(
+ self, ps, alpha, self->wReal__FDK, self->wImag__FDK,
+ self->hybOutputRealDry__FDK, self->hybOutputImagDry__FDK,
+ self->hybOutputRealWet__FDK, self->hybOutputImagWet__FDK);
+ break;
+ default:
+ err = MPS_APPLY_M2_ERROR;
+ goto bail;
+ }
+
+ if (err != MPS_OK) goto bail;
+
+ if ((self->tempShapeConfig == 2) && (!isTwoChMode(self->upmixType))) {
+ SpatialDecReshapeBBEnv(self, frame,
+ ts); /* input: reshapeBBEnvState,
+ hybOutput(Real/Imag)(Dry/Wet),
+ hybInput(Real/Imag) */
+ } /* output: hybOutput(Real/Imag)Dry */
+
+ /* Merge parts of the dry and wet QMF buffers. */
+ if ((self->tempShapeConfig == 1) && (!isTwoChMode(self->upmixType))) {
+ for (ch = 0; ch < self->numOutputChannels; ch++) {
+ for (hyb = 0; hyb < self->tp_hybBandBorder; hyb++) {
+ self->hybOutputRealDry__FDK[ch][hyb] +=
+ self->hybOutputRealWet__FDK[ch][hyb];
+ self->hybOutputImagDry__FDK[ch][hyb] +=
+ self->hybOutputImagWet__FDK[ch][hyb];
+ } /* loop hyb */
+ } /* loop ch */
+ err = subbandTPApply(
+ self, frame); /* input: hStpDec, hybOutput(Real/Imag)Dry/Wet */
+ /* output: hStpDec, hybOutput(Real/Imag)Dry */
+ if (err != MPS_OK) goto bail;
+ } /* (self->tempShapeConfig == 1) */
+ else {
+ /* The wet signal is added to the dry signal in applyM2 if GES and STP
+ * are disabled */
+ if ((self->tempShapeConfig == 1) || (self->tempShapeConfig == 2)) {
+ int nHybBands;
+ nHybBands = self->hybridBands;
+
+ for (ch = 0; ch < self->numOutputChannels; ch++) {
+ FIXP_DBL *RESTRICT pRealDry = self->hybOutputRealDry__FDK[ch];
+ FIXP_DBL *RESTRICT pImagDry = self->hybOutputImagDry__FDK[ch];
+ FIXP_DBL *RESTRICT pRealWet = self->hybOutputRealWet__FDK[ch];
+ FIXP_DBL *RESTRICT pImagWet = self->hybOutputImagWet__FDK[ch];
+ for (hyb = 0; hyb < nHybBands; hyb++) {
+ pRealDry[hyb] += pRealWet[hyb];
+ pImagDry[hyb] += pImagWet[hyb];
+ } /* loop hyb */
+ for (; hyb < self->hybridBands; hyb++) {
+ pRealDry[hyb] += pRealWet[hyb];
+ } /* loop hyb */
+ } /* loop ch */
+ } /* ( self->tempShapeConfig == 1 ) || ( self->tempShapeConfig == 2 ) */
+ } /* !self->tempShapeConfig == 1 */
+ } /* !bypassMode */
+
+ if (self->phaseCoding == 1) {
+ /* only if bsPhaseCoding == 1 and bsResidualCoding == 0 */
+
+ SpatialDecApplyPhase(
+ self, alpha, (ts == currSlot) /* signal the last slot of the set */
+ );
+ }
+
+ /*
+ * Synthesis Filtering
+ */
+
+ err = SpatialDecSynthesis(
+ self, ts_io,
+ self->hybOutputRealDry__FDK, /* input: hybOutput(Real/Imag)Dry */
+ self->hybOutputImagDry__FDK, self->timeOut__FDK, /* output: timeOut */
+ numInputChannels, mapDescr);
+
+ if (err != MPS_OK) goto bail;
+
+ /*
+ * Update parameter buffer
+ */
+ if (ts == currSlot) {
+ SpatialDecBufferMatrices(self); /* input: M(1/2)param(Real/Imag) */
+ /* output: M(1/2)param(Real/Imag)Prev */
+
+ prevSlot = currSlot;
+ ps++;
+ } /* if (ts==currSlot) */
+
+ } /* ts loop */
+
+ /*
+ * Save parameter states
+ */
+ self->prevTimeSlot = prevSlot;
+ self->curTimeSlot = ts;
+ self->curPs = ps;
+
+bail:
+
+ return err;
+}
+
+SACDEC_ERROR SpatialDecApplyFrame(
+ spatialDec *self,
+ SPATIAL_BS_FRAME *frame, /* parsed frame data to be applied */
+ SPATIALDEC_INPUT_MODE inputMode, PCM_MPS *inData, /* Time domain input */
+ FIXP_DBL **qmfInDataReal, /* QMF domain data l/r */
+ FIXP_DBL **qmfInDataImag, /* QMF domain data l/r */
+ PCM_MPS *pcmOutBuf, /* MAX_OUTPUT_CHANNELS*MAX_TIME_SLOTS*NUM_QMF_BANDS] */
+ UINT nSamples, UINT *pControlFlags, int numInputChannels,
+ const FDK_channelMapDescr *const mapDescr) {
+ SACDEC_ERROR err = MPS_OK;
+
+ int fDecAndMapFrameData;
+ int controlFlags;
+
+ FDK_ASSERT(self != NULL);
+ FDK_ASSERT(pControlFlags != NULL);
+ FDK_ASSERT(pcmOutBuf != NULL);
+
+ self->errInt = err; /* Init internal error */
+
+ controlFlags = *pControlFlags;
+
+ if ((self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_USAC) &&
+ (self->stereoConfigIndex > 1)) {
+ numInputChannels =
+ 1; /* Do not count residual channel as input channel. It is handled
+ seperately. */
+ }
+
+ /* Check if input amount of channels is consistent */
+ if (numInputChannels != self->numInputChannels) {
+ controlFlags |= MPEGS_CONCEAL;
+ if (numInputChannels > self->createParams.maxNumInputChannels) {
+ return MPS_INVALID_PARAMETER;
+ }
+ }
+
+ self->timeOut__FDK = pcmOutBuf;
+
+ /* Determine local function control flags */
+ fDecAndMapFrameData = frame->newBsData;
+
+ if (((fDecAndMapFrameData ==
+ 0) /* assures that conceal flag will not be set for blind mode */
+ && (self->curTimeSlot + (int)nSamples / self->qmfBands >
+ self->timeSlots)) ||
+ (frame->numParameterSets ==
+ 0)) { /* New input samples but missing side info */
+ fDecAndMapFrameData = 1;
+ controlFlags |= MPEGS_CONCEAL;
+ }
+
+ if ((fDecAndMapFrameData == 0) &&
+ (frame->paramSlot[fMax(0, frame->numParameterSets - 1)] !=
+ (self->timeSlots - 1) ||
+ self->curTimeSlot >
+ frame->paramSlot[self->curPs])) { /* Detected faulty parameter slot
+ data. */
+ fDecAndMapFrameData = 1;
+ controlFlags |= MPEGS_CONCEAL;
+ }
+
+ /* Update concealment state machine */
+ SpatialDecConcealment_UpdateState(
+ &self->concealInfo,
+ (controlFlags & MPEGS_CONCEAL)
+ ? 0
+ : 1); /* convert from conceal flag to frame ok flag */
+
+ if (fDecAndMapFrameData) {
+ /* Reset spatial framing control vars */
+ frame->newBsData = 0;
+ self->prevTimeSlot = -1;
+ self->curTimeSlot = 0;
+ self->curPs = 0;
+
+ if (controlFlags & MPEGS_CONCEAL) {
+ /* Reset frame data to avoid misconfiguration. */
+ SpatialDecClearFrameData(self, frame, &self->createParams);
+ }
+
+ {
+ err = SpatialDecDecodeFrame(self, frame); /* input: ... */
+ /* output: decodeAndMapFrameDATA */
+ }
+
+ if (err != MPS_OK) {
+ /* Rescue strategy is to apply bypass mode in order
+ to keep at least the downmix channels continuous. */
+ controlFlags |= MPEGS_CONCEAL;
+ if (self->errInt == MPS_OK) {
+ /* store internal error befor it gets overwritten */
+ self->errInt = err;
+ }
+ }
+ }
+
+ err = SpatialDecApplyParameterSets(
+ self, frame, inputMode, inData, qmfInDataReal, qmfInDataImag, nSamples,
+ controlFlags | ((err == MPS_OK) ? 0 : MPEGS_BYPASSMODE), numInputChannels,
+ mapDescr);
+ if (err != MPS_OK) {
+ goto bail;
+ }
+
+bail:
+
+ *pControlFlags = controlFlags;
+
+ return err;
+}