| /* ----------------------------------------------------------------------------- |
| 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; |
| } |