diff options
author | Fraunhofer IIS FDK <audio-fdk@iis.fraunhofer.de> | 2018-02-26 20:17:00 +0100 |
---|---|---|
committer | Jean-Michel Trivi <jmtrivi@google.com> | 2018-04-19 11:21:15 -0700 |
commit | 6cfabd35363c3ef5e3b209b867169a500b3ccc3c (patch) | |
tree | 01c0a19f2735e8b5d2407555fe992d4230d089eb /libSACdec/src | |
parent | 6288a1e34c4dede4c2806beb1736ece6580558c7 (diff) | |
download | fdk-aac-6cfabd35363c3ef5e3b209b867169a500b3ccc3c.tar.gz fdk-aac-6cfabd35363c3ef5e3b209b867169a500b3ccc3c.tar.bz2 fdk-aac-6cfabd35363c3ef5e3b209b867169a500b3ccc3c.zip |
Upgrade to FDKv2
Bug: 71430241
Test: CTS DecoderTest and DecoderTestAacDrc
original-Change-Id: Iaa20f749b8a04d553b20247cfe1a8930ebbabe30
Apply clang-format also on header files.
original-Change-Id: I14de1ef16bbc79ec0283e745f98356a10efeb2e4
Fixes for MPEG-D DRC
original-Change-Id: If1de2d74bbbac84b3f67de3b88b83f6a23b8a15c
Catch unsupported tw_mdct at an early stage
original-Change-Id: Ied9dd00d754162a0e3ca1ae3e6b854315d818afe
Fixing PVC transition frames
original-Change-Id: Ib75725abe39252806c32d71176308f2c03547a4e
Move qmf bands sanity check
original-Change-Id: Iab540c3013c174d9490d2ae100a4576f51d8dbc4
Initialize scaling variable
original-Change-Id: I3c4087101b70e998c71c1689b122b0d7762e0f9e
Add 16 qmf band configuration to getSlotNrgHQ()
original-Change-Id: I49a5d30f703a1b126ff163df9656db2540df21f1
Always apply byte alignment at the end of the AudioMuxElement
original-Change-Id: I42d560287506d65d4c3de8bfe3eb9a4ebeb4efc7
Setup SBR element only if no parse error exists
original-Change-Id: I1915b73704bc80ab882b9173d6bec59cbd073676
Additional array index check in HCR
original-Change-Id: I18cc6e501ea683b5009f1bbee26de8ddd04d8267
Fix fade-in index selection in concealment module
original-Change-Id: Ibf802ed6ed8c05e9257e1f3b6d0ac1162e9b81c1
Enable explicit backward compatible parser for AAC_LD
original-Change-Id: I27e9c678dcb5d40ed760a6d1e06609563d02482d
Skip spatial specific config in explicit backward compatible ASC
original-Change-Id: Iff7cc365561319e886090cedf30533f562ea4d6e
Update flags description in decoder API
original-Change-Id: I9a5b4f8da76bb652f5580cbd3ba9760425c43830
Add QMF domain reset function
original-Change-Id: I4f89a8a2c0277d18103380134e4ed86996e9d8d6
DRC upgrade v2.1.0
original-Change-Id: I5731c0540139dab220094cd978ef42099fc45b74
Fix integer overflow in sqrtFixp_lookup()
original-Change-Id: I429a6f0d19aa2cc957e0f181066f0ca73968c914
Fix integer overflow in invSqrtNorm2()
original-Change-Id: I84de5cbf9fb3adeb611db203fe492fabf4eb6155
Fix integer overflow in GenerateRandomVector()
original-Change-Id: I3118a641008bd9484d479e5b0b1ee2b5d7d44d74
Fix integer overflow in adjustTimeSlot_EldGrid()
original-Change-Id: I29d503c247c5c8282349b79df940416a512fb9d5
Fix integer overflow in FDKsbrEnc_codeEnvelope()
original-Change-Id: I6b34b61ebb9d525b0c651ed08de2befc1f801449
Follow-up on: Fix integer overflow in adjustTimeSlot_EldGrid()
original-Change-Id: I6f8f578cc7089e5eb7c7b93e580b72ca35ad689a
Fix integer overflow in get_pk_v2()
original-Change-Id: I63375bed40d45867f6eeaa72b20b1f33e815938c
Fix integer overflow in Syn_filt_zero()
original-Change-Id: Ie0c02fdfbe03988f9d3b20d10cd9fe4c002d1279
Fix integer overflow in CFac_CalcFacSignal()
original-Change-Id: Id2d767c40066c591b51768e978eb8af3b803f0c5
Fix integer overflow in FDKaacEnc_FDKaacEnc_calcPeNoAH()
original-Change-Id: Idcbd0f4a51ae2550ed106aa6f3d678d1f9724841
Fix integer overflow in sbrDecoder_calculateGainVec()
original-Change-Id: I7081bcbe29c5cede9821b38d93de07c7add2d507
Fix integer overflow in CLpc_SynthesisLattice()
original-Change-Id: I4a95ddc18de150102352d4a1845f06094764c881
Fix integer overflow in Pred_Lt4()
original-Change-Id: I4dbd012b2de7d07c3e70a47b92e3bfae8dbc750a
Fix integer overflow in FDKsbrEnc_InitSbrFastTransientDetector()
original-Change-Id: I788cbec1a4a00f44c2f3a72ad7a4afa219807d04
Fix unsigned integer overflow in FDKaacEnc_WriteBitstream()
original-Change-Id: I68fc75166e7d2cd5cd45b18dbe3d8c2a92f1822a
Fix unsigned integer overflow in FDK_MetadataEnc_Init()
original-Change-Id: Ie8d025f9bcdb2442c704bd196e61065c03c10af4
Fix overflow in pseudo random number generators
original-Change-Id: I3e2551ee01356297ca14e3788436ede80bd5513c
Fix unsigned integer overflow in sbrDecoder_Parse()
original-Change-Id: I3f231b2f437e9c37db4d5b964164686710eee971
Fix unsigned integer overflow in longsub()
original-Change-Id: I73c2bc50415cac26f1f5a29e125bbe75f9180a6e
Fix unsigned integer overflow in CAacDecoder_DecodeFrame()
original-Change-Id: Ifce2db4b1454b46fa5f887e9d383f1cc43b291e4
Fix overflow at CLpdChannelStream_Read()
original-Change-Id: Idb9d822ce3a4272e4794b643644f5434e2d4bf3f
Fix unsigned integer overflow in Hcr_State_BODY_SIGN_ESC__ESC_WORD()
original-Change-Id: I1ccf77c0015684b85534c5eb97162740a870b71c
Fix unsigned integer overflow in UsacConfig_Parse()
original-Change-Id: Ie6d27f84b6ae7eef092ecbff4447941c77864d9f
Fix unsigned integer overflow in aacDecoder_drcParse()
original-Change-Id: I713f28e883eea3d70b6fa56a7b8f8c22bcf66ca0
Fix unsigned integer overflow in aacDecoder_drcReadCompression()
original-Change-Id: Ia34dfeb88c4705c558bce34314f584965cafcf7a
Fix unsigned integer overflow in CDataStreamElement_Read()
original-Change-Id: Iae896cc1d11f0a893d21be6aa90bd3e60a2c25f0
Fix unsigned integer overflow in transportDec_AdjustEndOfAccessUnit()
original-Change-Id: I64cf29a153ee784bb4a16fdc088baabebc0007dc
Fix unsigned integer overflow in transportDec_GetAuBitsRemaining()
original-Change-Id: I975b3420faa9c16a041874ba0db82e92035962e4
Fix unsigned integer overflow in extractExtendedData()
original-Change-Id: I2a59eb09e2053cfb58dfb75fcecfad6b85a80a8f
Fix signed integer overflow in CAacDecoder_ExtPayloadParse()
original-Change-Id: I4ad5ca4e3b83b5d964f1c2f8c5e7b17c477c7929
Fix unsigned integer overflow in CAacDecoder_DecodeFrame()
original-Change-Id: I29a39df77d45c52a0c9c5c83c1ba81f8d0f25090
Follow-up on: Fix integer overflow in CLpc_SynthesisLattice()
original-Change-Id: I8fb194ffc073a3432a380845be71036a272d388f
Fix signed integer overflow in _interpolateDrcGain()
original-Change-Id: I879ec9ab14005069a7c47faf80e8bc6e03d22e60
Fix unsigned integer overflow in FDKreadBits()
original-Change-Id: I1f47a6a8037ff70375aa8844947d5681bb4287ad
Fix unsigned integer overflow in FDKbyteAlign()
original-Change-Id: Id5f3a11a0c9e50fc6f76ed6c572dbd4e9f2af766
Fix unsigned integer overflow in FDK_get32()
original-Change-Id: I9d33b8e97e3d38cbb80629cb859266ca0acdce96
Fix unsigned integer overflow in FDK_pushBack()
original-Change-Id: Ic87f899bc8c6acf7a377a8ca7f3ba74c3a1e1c19
Fix unsigned integer overflow in FDK_pushForward()
original-Change-Id: I3b754382f6776a34be1602e66694ede8e0b8effc
Fix unsigned integer overflow in ReadPsData()
original-Change-Id: I25361664ba8139e32bbbef2ca8c106a606ce9c37
Fix signed integer overflow in E_UTIL_residu()
original-Change-Id: I8c3abd1f437ee869caa8fb5903ce7d3d641b6aad
REVERT: Follow-up on: Integer overflow in CLpc_SynthesisLattice().
original-Change-Id: I3d340099acb0414795c8dfbe6362bc0a8f045f9b
Follow-up on: Fix integer overflow in CLpc_SynthesisLattice()
original-Change-Id: I4aedb8b3a187064e9f4d985175aa55bb99cc7590
Follow-up on: Fix unsigned integer overflow in aacDecoder_drcParse()
original-Change-Id: I2aa2e13916213bf52a67e8b0518e7bf7e57fb37d
Fix integer overflow in acelp
original-Change-Id: Ie6390c136d84055f8b728aefbe4ebef6e029dc77
Fix unsigned integer overflow in aacDecoder_UpdateBitStreamCounters()
original-Change-Id: I391ffd97ddb0b2c184cba76139bfb356a3b4d2e2
Adjust concealment default settings
original-Change-Id: I6a95db935a327c47df348030bcceafcb29f54b21
Saturate estimatedStartPos
original-Change-Id: I27be2085e0ae83ec9501409f65e003f6bcba1ab6
Negative shift exponent in _interpolateDrcGain()
original-Change-Id: I18edb26b26d002aafd5e633d4914960f7a359c29
Negative shift exponent in calculateICC()
original-Change-Id: I3dcd2ae98d2eb70ee0d59750863cbb2a6f4f8aba
Too large shift exponent in FDK_put()
original-Change-Id: Ib7d9aaa434d2d8de4a13b720ca0464b31ca9b671
Too large shift exponent in CalcInvLdData()
original-Change-Id: I43e6e78d4cd12daeb1dcd5d82d1798bdc2550262
Member access within null pointer of type SBR_CHANNEL
original-Change-Id: Idc5e4ea8997810376d2f36bbdf628923b135b097
Member access within null pointer of type CpePersistentData
original-Change-Id: Ib6c91cb0d37882768e5baf63324e429589de0d9d
Member access within null pointer FDKaacEnc_psyMain()
original-Change-Id: I7729b7f4479970531d9dc823abff63ca52e01997
Member access within null pointer FDKaacEnc_GetPnsParam()
original-Change-Id: I9aa3b9f3456ae2e0f7483dbd5b3dde95fc62da39
Member access within null pointer FDKsbrEnc_EnvEncodeFrame()
original-Change-Id: I67936f90ea714e90b3e81bc0dd1472cc713eb23a
Add HCR sanity check
original-Change-Id: I6c1d9732ebcf6af12f50b7641400752f74be39f7
Fix memory issue for HBE edge case with 8:3 SBR
original-Change-Id: I11ea58a61e69fbe8bf75034b640baee3011e63e9
Additional SBR parametrization sanity check for ELD
original-Change-Id: Ie26026fbfe174c2c7b3691f6218b5ce63e322140
Add MPEG-D DRC channel layout check
original-Change-Id: Iea70a74f171b227cce636a9eac4ba662777a2f72
Additional out-of-bounds checks in MPEG-D DRC
original-Change-Id: Ife4a8c3452c6fde8a0a09e941154a39a769777d4
Change-Id: Ic63cb2f628720f54fe9b572b0cb528e2599c624e
Diffstat (limited to 'libSACdec/src')
25 files changed, 13429 insertions, 0 deletions
diff --git a/libSACdec/src/sac_bitdec.cpp b/libSACdec/src/sac_bitdec.cpp new file mode 100644 index 0000000..b2f3b7c --- /dev/null +++ b/libSACdec/src/sac_bitdec.cpp @@ -0,0 +1,2147 @@ +/* ----------------------------------------------------------------------------- +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 Dec bitstream decoder + +*******************************************************************************/ + +#include "sac_bitdec.h" + +#include "sac_dec_errorcodes.h" +#include "nlc_dec.h" +#include "sac_rom.h" +#include "FDK_matrixCalloc.h" +#include "sac_tsd.h" + +enum { + ottVsTotInactiv = 0, + ottVsTotDb1Activ = 1, + ottVsTotDb2Activ = 2, + ottVsTotDb1Db2Activ = 3 +}; + +static SACDEC_ERROR SpatialDecDecodeHelperInfo( + SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, UPMIXTYPE upmixType) { + int i; + UINT syntaxFlags; + + /* Determine bit stream syntax */ + syntaxFlags = 0; + switch (pSpatialSpecificConfig->coreCodec) { + case AOT_ER_AAC_ELD: + case AOT_ER_AAC_LD: + syntaxFlags |= SACDEC_SYNTAX_LD; + break; + case AOT_USAC: + syntaxFlags |= SACDEC_SYNTAX_USAC; + break; + case AOT_NONE: + default: + return MPS_UNSUPPORTED_FORMAT; + } + + pSpatialSpecificConfig->syntaxFlags = syntaxFlags; + + switch (pSpatialSpecificConfig->treeConfig) { + case TREE_212: { + pSpatialSpecificConfig->ottCLDdefault[0] = 0; + } break; + default: + return MPS_INVALID_TREECONFIG; + } + + if (syntaxFlags & SACDEC_SYNTAX_USAC) { + if (pSpatialSpecificConfig->bsOttBandsPhasePresent) { + pSpatialSpecificConfig->numOttBandsIPD = + pSpatialSpecificConfig->bsOttBandsPhase; + } else { + int numParameterBands; + + numParameterBands = pSpatialSpecificConfig->freqRes; + switch (numParameterBands) { + case 4: + case 5: + pSpatialSpecificConfig->numOttBandsIPD = 2; + break; + case 7: + pSpatialSpecificConfig->numOttBandsIPD = 3; + break; + case 10: + pSpatialSpecificConfig->numOttBandsIPD = 5; + break; + case 14: + pSpatialSpecificConfig->numOttBandsIPD = 7; + break; + case 20: + case 28: + pSpatialSpecificConfig->numOttBandsIPD = 10; + break; + default: + return MPS_INVALID_PARAMETERBANDS; + } + } + } else { + pSpatialSpecificConfig->numOttBandsIPD = 0; + } + for (i = 0; i < pSpatialSpecificConfig->nOttBoxes; i++) { + { + pSpatialSpecificConfig->bitstreamOttBands[i] = + pSpatialSpecificConfig->freqRes; + } + { + pSpatialSpecificConfig->numOttBands[i] = + pSpatialSpecificConfig->bitstreamOttBands[i]; + if (syntaxFlags & SACDEC_SYNTAX_USAC && + !pSpatialSpecificConfig->bsOttBandsPhasePresent) { + if (pSpatialSpecificConfig->bResidualCoding && + pSpatialSpecificConfig->ResidualConfig[i].bResidualPresent && + (pSpatialSpecificConfig->numOttBandsIPD < + pSpatialSpecificConfig->ResidualConfig[i].nResidualBands)) { + pSpatialSpecificConfig->numOttBandsIPD = + pSpatialSpecificConfig->ResidualConfig[i].nResidualBands; + } + } + } + } /* i */ + + return MPS_OK; +} + +/******************************************************************************* + Functionname: SpatialDecParseExtensionConfig + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ + +static SACDEC_ERROR SpatialDecParseExtensionConfig( + HANDLE_FDK_BITSTREAM bitstream, SPATIAL_SPECIFIC_CONFIG *config, + int numOttBoxes, int numTttBoxes, int numOutChan, int bitsAvailable) { + SACDEC_ERROR err = MPS_OK; + INT ba = bitsAvailable; + + config->sacExtCnt = 0; + config->bResidualCoding = 0; + + ba = fMin((int)FDKgetValidBits(bitstream), ba); + + while ((ba >= 8) && (config->sacExtCnt < MAX_NUM_EXT_TYPES)) { + int bitsRead, nFillBits; + INT tmp; + UINT sacExtLen; + + config->sacExtType[config->sacExtCnt] = FDKreadBits(bitstream, 4); + ba -= 4; + + sacExtLen = FDKreadBits(bitstream, 4); + ba -= 4; + + if (sacExtLen == 15) { + sacExtLen += FDKreadBits(bitstream, 8); + ba -= 8; + if (sacExtLen == 15 + 255) { + sacExtLen += FDKreadBits(bitstream, 16); + ba -= 16; + } + } + + tmp = (INT)FDKgetValidBits( + bitstream); /* Extension config payload start anchor. */ + if ((tmp <= 0) || (tmp < (INT)sacExtLen * 8) || (ba < (INT)sacExtLen * 8)) { + err = MPS_PARSE_ERROR; + goto bail; + } + + switch (config->sacExtType[config->sacExtCnt]) { + default:; /* unknown extension data => do nothing */ + } + + /* skip remaining extension data */ + bitsRead = tmp - FDKgetValidBits(bitstream); + nFillBits = 8 * sacExtLen - bitsRead; + + if (nFillBits < 0) { + err = MPS_PARSE_ERROR; + goto bail; + } else { + /* Skip fill bits or an unkown extension. */ + FDKpushFor(bitstream, nFillBits); + } + + ba -= 8 * sacExtLen; + config->sacExtCnt++; + } + +bail: + return err; +} + +SACDEC_ERROR SpatialDecParseSpecificConfigHeader( + HANDLE_FDK_BITSTREAM bitstream, + SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, + AUDIO_OBJECT_TYPE coreCodec, SPATIAL_DEC_UPMIX_TYPE upmixType) { + SACDEC_ERROR err = MPS_OK; + INT numFillBits; + int sacHeaderLen = 0; + int sacTimeAlignFlag = 0; + + sacTimeAlignFlag = FDKreadBits(bitstream, 1); + sacHeaderLen = FDKreadBits(bitstream, 7); + + if (sacHeaderLen == 127) { + sacHeaderLen += FDKreadBits(bitstream, 16); + } + numFillBits = FDKgetValidBits(bitstream); + + err = SpatialDecParseSpecificConfig(bitstream, pSpatialSpecificConfig, + sacHeaderLen, coreCodec); + + numFillBits -= + FDKgetValidBits(bitstream); /* the number of read bits (tmpBits) */ + numFillBits = (8 * sacHeaderLen) - numFillBits; + if (numFillBits < 0) { + /* Parsing went wrong */ + err = MPS_PARSE_ERROR; + } + /* Move to the very end of the SSC */ + FDKpushBiDirectional(bitstream, numFillBits); + + if ((err == MPS_OK) && sacTimeAlignFlag) { + /* not supported */ + FDKreadBits(bitstream, 16); + err = MPS_UNSUPPORTED_CONFIG; + } + + /* Derive additional helper variables */ + SpatialDecDecodeHelperInfo(pSpatialSpecificConfig, (UPMIXTYPE)upmixType); + + return err; +} + +SACDEC_ERROR SpatialDecParseMps212Config( + HANDLE_FDK_BITSTREAM bitstream, + SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, int samplingRate, + AUDIO_OBJECT_TYPE coreCodec, INT stereoConfigIndex, + INT coreSbrFrameLengthIndex) { + int i; + + pSpatialSpecificConfig->stereoConfigIndex = stereoConfigIndex; + pSpatialSpecificConfig->coreSbrFrameLengthIndex = coreSbrFrameLengthIndex; + pSpatialSpecificConfig->freqRes = + (SPATIALDEC_FREQ_RES)freqResTable[FDKreadBits(bitstream, 3)]; + if (pSpatialSpecificConfig->freqRes == 0) { + return MPS_PARSE_ERROR; /* reserved value */ + } + + switch (coreCodec) { + case AOT_DRM_USAC: + pSpatialSpecificConfig->bsFixedGainDMX = + (SPATIALDEC_FIXED_GAINS)FDKreadBits(bitstream, 3); + /* tempShapeConfig = (bsTempShapeConfigDrm == 1) ? 3 : 0 */ + pSpatialSpecificConfig->tempShapeConfig = + (SPATIALDEC_TS_CONF)(FDKreadBits(bitstream, 1) * 3); + pSpatialSpecificConfig->decorrConfig = (SPATIALDEC_DECORR_CONF)0; + pSpatialSpecificConfig->bsDecorrType = 0; + break; + case AOT_USAC: + pSpatialSpecificConfig->bsFixedGainDMX = + (SPATIALDEC_FIXED_GAINS)FDKreadBits(bitstream, 3); + pSpatialSpecificConfig->tempShapeConfig = + (SPATIALDEC_TS_CONF)FDKreadBits(bitstream, 2); + pSpatialSpecificConfig->decorrConfig = + (SPATIALDEC_DECORR_CONF)FDKreadBits(bitstream, 2); + if (pSpatialSpecificConfig->decorrConfig > 2) { + return MPS_PARSE_ERROR; /* reserved value */ + } + pSpatialSpecificConfig->bsDecorrType = 0; + break; + default: + return MPS_UNSUPPORTED_FORMAT; + } + pSpatialSpecificConfig->nTimeSlots = (coreSbrFrameLengthIndex == 4) ? 64 : 32; + pSpatialSpecificConfig->bsHighRateMode = (UCHAR)FDKreadBits(bitstream, 1); + + { + pSpatialSpecificConfig->bsPhaseCoding = (UCHAR)FDKreadBits(bitstream, 1); + pSpatialSpecificConfig->bsOttBandsPhasePresent = + (UCHAR)FDKreadBits(bitstream, 1); + if (pSpatialSpecificConfig->bsOttBandsPhasePresent) { + if (MAX_PARAMETER_BANDS < (pSpatialSpecificConfig->bsOttBandsPhase = + FDKreadBits(bitstream, 5))) { + return MPS_PARSE_ERROR; + } + } else { + pSpatialSpecificConfig->bsOttBandsPhase = 0; + } + } + + if (stereoConfigIndex > 1) { /* do residual coding */ + pSpatialSpecificConfig->bResidualCoding = 1; + pSpatialSpecificConfig->ResidualConfig->bResidualPresent = 1; + if (pSpatialSpecificConfig->freqRes < + (pSpatialSpecificConfig->ResidualConfig->nResidualBands = + FDKreadBits(bitstream, 5))) { + return MPS_PARSE_ERROR; + } + pSpatialSpecificConfig->bsOttBandsPhase = + fMax(pSpatialSpecificConfig->bsOttBandsPhase, + pSpatialSpecificConfig->ResidualConfig->nResidualBands); + pSpatialSpecificConfig->bsPseudoLr = (UCHAR)FDKreadBits(bitstream, 1); + + if (pSpatialSpecificConfig->bsPhaseCoding) { + pSpatialSpecificConfig->bsPhaseCoding = 3; + } + } else { + pSpatialSpecificConfig->bResidualCoding = 0; + pSpatialSpecificConfig->ResidualConfig->bResidualPresent = 0; + } + + if (pSpatialSpecificConfig->tempShapeConfig == 2) { + switch (coreCodec) { + case AOT_USAC: + pSpatialSpecificConfig->envQuantMode = FDKreadBits(bitstream, 1); + break; + default: /* added to avoid compiler warning */ + break; /* added to avoid compiler warning */ + } + } + + /* Static parameters */ + + pSpatialSpecificConfig->samplingFreq = + samplingRate; /* wrong for stereoConfigIndex == 3 but value is unused */ + pSpatialSpecificConfig->treeConfig = SPATIALDEC_MODE_RSVD7; + pSpatialSpecificConfig->nOttBoxes = + treePropertyTable[pSpatialSpecificConfig->treeConfig].numOttBoxes; + pSpatialSpecificConfig->nInputChannels = + treePropertyTable[pSpatialSpecificConfig->treeConfig].numInputChannels; + pSpatialSpecificConfig->nOutputChannels = + treePropertyTable[pSpatialSpecificConfig->treeConfig].numOutputChannels; + + pSpatialSpecificConfig->bArbitraryDownmix = 0; + + for (i = 0; i < pSpatialSpecificConfig->nOttBoxes; i++) { + pSpatialSpecificConfig->OttConfig[i].nOttBands = 0; + } + + if (coreCodec == AOT_DRM_USAC) { + /* MPS payload is MPEG conform -> no need for pseudo DRM AOT */ + coreCodec = AOT_USAC; + } + pSpatialSpecificConfig->coreCodec = coreCodec; + + /* Derive additional helper variables */ + SpatialDecDecodeHelperInfo(pSpatialSpecificConfig, UPMIXTYPE_NORMAL); + + return MPS_OK; +} + +SACDEC_ERROR SpatialDecParseSpecificConfig( + HANDLE_FDK_BITSTREAM bitstream, + SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, int sacHeaderLen, + AUDIO_OBJECT_TYPE coreCodec) { + SACDEC_ERROR err = MPS_OK; + int i; + int bsSamplingFreqIndex; + int bsFreqRes, b3DaudioMode = 0; + int numHeaderBits; + int cfgStartPos, bitsAvailable; + + cfgStartPos = FDKgetValidBits(bitstream); + /* It might be that we do not know the SSC length beforehand. */ + if (sacHeaderLen == 0) { + bitsAvailable = cfgStartPos; + } else { + bitsAvailable = 8 * sacHeaderLen; + if (bitsAvailable > cfgStartPos) { + err = MPS_PARSE_ERROR; + goto bail; + } + } + + bsSamplingFreqIndex = FDKreadBits(bitstream, 4); + + if (bsSamplingFreqIndex == 15) { + pSpatialSpecificConfig->samplingFreq = FDKreadBits(bitstream, 24); + } else { + pSpatialSpecificConfig->samplingFreq = + samplingFreqTable[bsSamplingFreqIndex]; + if (pSpatialSpecificConfig->samplingFreq == 0) { + err = MPS_PARSE_ERROR; + goto bail; + } + } + + pSpatialSpecificConfig->nTimeSlots = FDKreadBits(bitstream, 5) + 1; + if ((pSpatialSpecificConfig->nTimeSlots < 1) || + (pSpatialSpecificConfig->nTimeSlots > MAX_TIME_SLOTS)) { + err = MPS_PARSE_ERROR; + goto bail; + } + + bsFreqRes = FDKreadBits(bitstream, 3); + + pSpatialSpecificConfig->freqRes = + (SPATIALDEC_FREQ_RES)freqResTable_LD[bsFreqRes]; + + pSpatialSpecificConfig->treeConfig = + (SPATIALDEC_TREE_CONFIG)FDKreadBits(bitstream, 4); + + if (pSpatialSpecificConfig->treeConfig != SPATIALDEC_MODE_RSVD7) { + err = MPS_UNSUPPORTED_CONFIG; + goto bail; + } + + { + pSpatialSpecificConfig->nOttBoxes = + treePropertyTable[pSpatialSpecificConfig->treeConfig].numOttBoxes; + pSpatialSpecificConfig->nTttBoxes = + treePropertyTable[pSpatialSpecificConfig->treeConfig].numTttBoxes; + pSpatialSpecificConfig->nInputChannels = + treePropertyTable[pSpatialSpecificConfig->treeConfig].numInputChannels; + pSpatialSpecificConfig->nOutputChannels = + treePropertyTable[pSpatialSpecificConfig->treeConfig].numOutputChannels; + } + + pSpatialSpecificConfig->quantMode = + (SPATIALDEC_QUANT_MODE)FDKreadBits(bitstream, 2); + + pSpatialSpecificConfig->bArbitraryDownmix = FDKreadBits(bitstream, 1); + + pSpatialSpecificConfig->bsFixedGainDMX = + (SPATIALDEC_FIXED_GAINS)FDKreadBits(bitstream, 3); + + pSpatialSpecificConfig->tempShapeConfig = + (SPATIALDEC_TS_CONF)FDKreadBits(bitstream, 2); + pSpatialSpecificConfig->decorrConfig = + (SPATIALDEC_DECORR_CONF)FDKreadBits(bitstream, 2); + if (pSpatialSpecificConfig->decorrConfig > 2) { + return MPS_PARSE_ERROR; /* reserved value */ + } + + for (i = 0; i < pSpatialSpecificConfig->nOttBoxes; i++) { + pSpatialSpecificConfig->OttConfig[i].nOttBands = 0; + } + + for (i = 0; i < pSpatialSpecificConfig->nTttBoxes; i++) { + int bTttDualMode = FDKreadBits(bitstream, 1); + FDKreadBits(bitstream, 3); /* not supported */ + + if (bTttDualMode) { + FDKreadBits(bitstream, 8); /* not supported */ + } + } + + if (pSpatialSpecificConfig->tempShapeConfig == 2) { + pSpatialSpecificConfig->envQuantMode = FDKreadBits(bitstream, 1); + } + + if (b3DaudioMode) { + if (FDKreadBits(bitstream, 2) == 0) { /* b3DaudioHRTFset ? */ + int hc; + int HRTFnumBand; + int HRTFfreqRes = FDKreadBits(bitstream, 3); + int HRTFnumChan = FDKreadBits(bitstream, 4); + int HRTFasymmetric = FDKreadBits(bitstream, 1); + + HRTFnumBand = freqResTable_LD[HRTFfreqRes]; + + for (hc = 0; hc < HRTFnumChan; hc++) { + FDKpushFor(bitstream, HRTFnumBand * 6); /* HRTFlevelLeft[hc][hb] */ + if (HRTFasymmetric) { + FDKpushFor(bitstream, HRTFnumBand * 6); /* HRTFlevelRight[hc][hb] */ + } + if (FDKreadBits(bitstream, 1)) { /* HRTFphase[hc] ? */ + FDKpushFor(bitstream, HRTFnumBand * 6); /* HRTFphaseLR[hc][hb] */ + } + if (FDKreadBits(bitstream, 1)) { /* HRTFicc[hc] ? */ + FDKpushFor(bitstream, HRTFnumBand * 6); /* HRTFiccLR[hc][hb] */ + } + } + } + } + + FDKbyteAlign(bitstream, + cfgStartPos); /* ISO/IEC FDIS 23003-1: 5.2. ... byte alignment + with respect to the beginning of the syntactic + element in which ByteAlign() occurs. */ + + numHeaderBits = cfgStartPos - FDKgetValidBits(bitstream); + bitsAvailable -= numHeaderBits; + + pSpatialSpecificConfig->sacExtCnt = 0; + pSpatialSpecificConfig->bResidualCoding = 0; + + if ((err == MPS_OK) && (bitsAvailable > 0)) { + err = SpatialDecParseExtensionConfig( + bitstream, pSpatialSpecificConfig, pSpatialSpecificConfig->nOttBoxes, + pSpatialSpecificConfig->nTttBoxes, + pSpatialSpecificConfig->nOutputChannels, bitsAvailable); + } + + FDKbyteAlign( + bitstream, + cfgStartPos); /* Same alignment anchor as above because + SpatialExtensionConfig() always reads full bytes */ + + pSpatialSpecificConfig->coreCodec = coreCodec; + + SpatialDecDecodeHelperInfo(pSpatialSpecificConfig, UPMIXTYPE_NORMAL); + +bail: + if (sacHeaderLen > 0) { + /* If the config is of known length then assure that the + bitbuffer is exactly at its end when leaving the function. */ + FDKpushBiDirectional( + bitstream, + (sacHeaderLen * 8) - (cfgStartPos - FDKgetValidBits(bitstream))); + } + + return err; +} + +int SpatialDecDefaultSpecificConfig( + SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, + AUDIO_OBJECT_TYPE coreCodec, int samplingFreq, int nTimeSlots, + int sacDecoderLevel, int isBlind, int numCoreChannels) + +{ + int err = MPS_OK; + int i; + + FDK_ASSERT(coreCodec != AOT_NONE); + FDK_ASSERT(nTimeSlots > 0); + FDK_ASSERT(samplingFreq > 0); + + pSpatialSpecificConfig->coreCodec = coreCodec; + pSpatialSpecificConfig->samplingFreq = samplingFreq; + pSpatialSpecificConfig->nTimeSlots = nTimeSlots; + if ((pSpatialSpecificConfig->coreCodec == AOT_ER_AAC_ELD) || + (pSpatialSpecificConfig->coreCodec == AOT_ER_AAC_LD)) + pSpatialSpecificConfig->freqRes = SPATIALDEC_FREQ_RES_23; + else + pSpatialSpecificConfig->freqRes = SPATIALDEC_FREQ_RES_28; + + { + pSpatialSpecificConfig->treeConfig = + SPATIALDEC_MODE_RSVD7; /* 212 configuration */ + } + + { + pSpatialSpecificConfig->nOttBoxes = + treePropertyTable[pSpatialSpecificConfig->treeConfig].numOttBoxes; + pSpatialSpecificConfig->nInputChannels = + treePropertyTable[pSpatialSpecificConfig->treeConfig].numInputChannels; + pSpatialSpecificConfig->nOutputChannels = + treePropertyTable[pSpatialSpecificConfig->treeConfig].numOutputChannels; + } + + pSpatialSpecificConfig->quantMode = SPATIALDEC_QUANT_FINE_DEF; + pSpatialSpecificConfig->bArbitraryDownmix = 0; + pSpatialSpecificConfig->bResidualCoding = 0; + if ((pSpatialSpecificConfig->coreCodec == AOT_ER_AAC_ELD) || + (pSpatialSpecificConfig->coreCodec == AOT_ER_AAC_LD)) + pSpatialSpecificConfig->bsFixedGainDMX = SPATIALDEC_GAIN_RSVD2; + else + pSpatialSpecificConfig->bsFixedGainDMX = SPATIALDEC_GAIN_MODE0; + + pSpatialSpecificConfig->tempShapeConfig = SPATIALDEC_TS_TPNOWHITE; + pSpatialSpecificConfig->decorrConfig = SPATIALDEC_DECORR_MODE0; + + for (i = 0; i < pSpatialSpecificConfig->nOttBoxes; i++) { + pSpatialSpecificConfig->OttConfig[i].nOttBands = 0; + } + + return err; +} + +/******************************************************************************* + Functionname: coarse2fine + ******************************************************************************* + + Description: + Parameter index mapping from coarse to fine quantization + + Arguments: + +Input: + +Output: + +*******************************************************************************/ +static void coarse2fine(SCHAR *data, DATA_TYPE dataType, int startBand, + int numBands) { + int i; + + for (i = startBand; i < startBand + numBands; i++) { + data[i] <<= 1; + } + + if (dataType == t_CLD) { + for (i = startBand; i < startBand + numBands; i++) { + if (data[i] == -14) + data[i] = -15; + else if (data[i] == 14) + data[i] = 15; + } + } +} + +/******************************************************************************* + Functionname: fine2coarse + ******************************************************************************* + + Description: + Parameter index mapping from fine to coarse quantization + + Arguments: + +Input: + +Output: + +*******************************************************************************/ +static void fine2coarse(SCHAR *data, DATA_TYPE dataType, int startBand, + int numBands) { + int i; + + for (i = startBand; i < startBand + numBands; i++) { + /* Note: the if cases below actually make a difference (negative values) */ + if (dataType == t_CLD) + data[i] /= 2; + else + data[i] >>= 1; + } +} + +/******************************************************************************* + Functionname: getStrideMap + ******************************************************************************* + + Description: + Index Mapping accroding to pbStrides + + Arguments: + +Input: + +Output: + +*******************************************************************************/ +static int getStrideMap(int freqResStride, int startBand, int stopBand, + int *aStrides) { + int i, pb, pbStride, dataBands, strOffset; + + pbStride = pbStrideTable[freqResStride]; + dataBands = (stopBand - startBand - 1) / pbStride + 1; + + aStrides[0] = startBand; + for (pb = 1; pb <= dataBands; pb++) { + aStrides[pb] = aStrides[pb - 1] + pbStride; + } + strOffset = 0; + while (aStrides[dataBands] > stopBand) { + if (strOffset < dataBands) strOffset++; + for (i = strOffset; i <= dataBands; i++) { + aStrides[i]--; + } + } + + return dataBands; +} + +/******************************************************************************* + Functionname: ecDataDec + ******************************************************************************* + + Description: + Do delta decoding and dequantization + + Arguments: + +Input: + +Output: + + +*******************************************************************************/ + +static SACDEC_ERROR ecDataDec( + const SPATIAL_BS_FRAME *frame, UINT syntaxFlags, + HANDLE_FDK_BITSTREAM bitstream, LOSSLESSDATA *const llData, + SCHAR (*data)[MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS], SCHAR **lastdata, + int datatype, int boxIdx, int startBand, int stopBand, SCHAR defaultValue) { + SACDEC_ERROR err = MPS_OK; + int i, j, pb, dataSets, setIdx, bsDataPair, dataBands, oldQuantCoarseXXX; + INT aStrides[MAX_PARAMETER_BANDS + 1] = {0}; + + dataSets = 0; + for (i = 0; i < frame->numParameterSets; i++) { + llData->bsXXXDataMode[i] = (SCHAR)FDKreadBits(bitstream, 2); + + if ((frame->bsIndependencyFlag == 1) && (i == 0) && + (llData->bsXXXDataMode[i] == 1 || + llData->bsXXXDataMode[i] == 2)) { /* This check catches bitstreams + generated by older encoder that + cause trouble */ + return MPS_PARSE_ERROR; + } + if ((i >= frame->numParameterSets - 1) && + (llData->bsXXXDataMode[i] == + 2)) { /* The interpolation mode must not be active for the last + parameter set */ + return MPS_PARSE_ERROR; + } + + if (llData->bsXXXDataMode[i] == 3) { + dataSets++; + } + } + + setIdx = 0; + bsDataPair = 0; + oldQuantCoarseXXX = llData->state->bsQuantCoarseXXXprevParse; + + for (i = 0; i < frame->numParameterSets; i++) { + if (llData->bsXXXDataMode[i] == 0) { + for (pb = startBand; pb < stopBand; pb++) { + lastdata[boxIdx][pb] = defaultValue; + } + + oldQuantCoarseXXX = 0; + } + + if (llData->bsXXXDataMode[i] == 3) { + if (bsDataPair) { + bsDataPair = 0; + } else { + bsDataPair = FDKreadBits(bitstream, 1); + llData->bsQuantCoarseXXX[setIdx] = (UCHAR)FDKreadBits(bitstream, 1); + llData->bsFreqResStrideXXX[setIdx] = (UCHAR)FDKreadBits(bitstream, 2); + + if (llData->bsQuantCoarseXXX[setIdx] != oldQuantCoarseXXX) { + if (oldQuantCoarseXXX) { + coarse2fine(lastdata[boxIdx], (DATA_TYPE)datatype, startBand, + stopBand - startBand); + } else { + fine2coarse(lastdata[boxIdx], (DATA_TYPE)datatype, startBand, + stopBand - startBand); + } + } + + dataBands = getStrideMap(llData->bsFreqResStrideXXX[setIdx], startBand, + stopBand, aStrides); + + for (pb = 0; pb < dataBands; pb++) { + lastdata[boxIdx][startBand + pb] = lastdata[boxIdx][aStrides[pb]]; + } + + if (boxIdx > MAX_NUM_OTT) return MPS_INVALID_BOXIDX; + if ((setIdx + bsDataPair) > MAX_PARAMETER_SETS) + return MPS_INVALID_SETIDX; + + /* DECODER_TYPE defined in FDK_tools */ + DECODER_TYPE this_decoder_type = SAC_DECODER; + if (syntaxFlags & (SACDEC_SYNTAX_USAC | SACDEC_SYNTAX_RSVD50)) { + this_decoder_type = USAC_DECODER; + } else if (syntaxFlags & SACDEC_SYNTAX_LD) { + this_decoder_type = SAOC_DECODER; + } + + err = (SACDEC_ERROR)EcDataPairDec( + this_decoder_type, bitstream, data[boxIdx][setIdx + 0], + data[boxIdx][setIdx + 1], lastdata[boxIdx], (DATA_TYPE)datatype, + startBand, dataBands, bsDataPair, llData->bsQuantCoarseXXX[setIdx], + !(frame->bsIndependencyFlag && (i == 0)) || (setIdx > 0)); + if (err != MPS_OK) goto bail; + + if (datatype == t_IPD) { + const SCHAR mask = (llData->bsQuantCoarseXXX[setIdx]) ? 7 : 15; + for (pb = 0; pb < dataBands; pb++) { + for (j = aStrides[pb]; j < aStrides[pb + 1]; j++) { + lastdata[boxIdx][j] = + data[boxIdx][setIdx + bsDataPair][startBand + pb] & mask; + } + } + } else { + for (pb = 0; pb < dataBands; pb++) { + for (j = aStrides[pb]; j < aStrides[pb + 1]; j++) { + lastdata[boxIdx][j] = + data[boxIdx][setIdx + bsDataPair][startBand + pb]; + } + } + } + + oldQuantCoarseXXX = llData->bsQuantCoarseXXX[setIdx]; + + if (bsDataPair) { + llData->bsQuantCoarseXXX[setIdx + 1] = + llData->bsQuantCoarseXXX[setIdx]; + llData->bsFreqResStrideXXX[setIdx + 1] = + llData->bsFreqResStrideXXX[setIdx]; + } + setIdx += bsDataPair + 1; + } /* !bsDataPair */ + } /* llData->bsXXXDataMode[i] == 3 */ + } + + llData->state->bsQuantCoarseXXXprevParse = oldQuantCoarseXXX; + +bail: + return err; +} + +/******************************************************************************* + Functionname: parseArbitraryDownmixData + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +static SACDEC_ERROR parseArbitraryDownmixData( + spatialDec *self, const SPATIAL_SPECIFIC_CONFIG *pSSC, + const UINT syntaxFlags, const SPATIAL_BS_FRAME *frame, + HANDLE_FDK_BITSTREAM bitstream) { + SACDEC_ERROR err = MPS_OK; + int ch; + int offset = pSSC->nOttBoxes; + + /* CLD (arbitrary down-mix gains) */ + for (ch = 0; ch < pSSC->nInputChannels; ch++) { + err = ecDataDec(frame, syntaxFlags, bitstream, + &frame->CLDLosslessData[offset + ch], + frame->cmpArbdmxGainIdx, self->cmpArbdmxGainIdxPrev, t_CLD, + ch, 0, pSSC->freqRes, arbdmxGainDefault); + if (err != MPS_OK) return err; + } + + return err; + +} /* parseArbitraryDownmixData */ + +/******************************************************************************* + Functionname: SpatialDecParseFrame + ******************************************************************************* + + Description: + + Arguments: + + Input: + + Output: + +*******************************************************************************/ + +static int nBitsParamSlot(int i) { + int bitsParamSlot; + + bitsParamSlot = fMax(0, DFRACT_BITS - 1 - fNormz((FIXP_DBL)i)); + if ((1 << bitsParamSlot) < i) { + bitsParamSlot++; + } + FDK_ASSERT((bitsParamSlot >= 0) && (bitsParamSlot <= 32)); + + return bitsParamSlot; +} + +SACDEC_ERROR SpatialDecParseFrameData( + spatialDec_struct *self, SPATIAL_BS_FRAME *frame, + HANDLE_FDK_BITSTREAM bitstream, + const SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, UPMIXTYPE upmixType, + int fGlobalIndependencyFlag) { + SACDEC_ERROR err = MPS_OK; + int bsFramingType, dataBands, ps, pg, i; + int pb; + int numTempShapeChan = 0; + int bsNumOutputChannels = + treePropertyTable[pSpatialSpecificConfig->treeConfig] + .numOutputChannels; /* CAUTION: Maybe different to + pSpatialSpecificConfig->treeConfig in some + modes! */ + int paramSetErr = 0; + UINT alignAnchor = FDKgetValidBits( + bitstream); /* Anchor for ByteAlign() function. See comment below. */ + UINT syntaxFlags; + + syntaxFlags = pSpatialSpecificConfig->syntaxFlags; + + if ((syntaxFlags & (SACDEC_SYNTAX_USAC | SACDEC_SYNTAX_RSVD50)) && + pSpatialSpecificConfig->bsHighRateMode == 0) { + bsFramingType = 0; /* fixed framing */ + frame->numParameterSets = 1; + } else { + bsFramingType = FDKreadBits(bitstream, 1); + if (syntaxFlags & SACDEC_SYNTAX_LD) + frame->numParameterSets = FDKreadBits(bitstream, 1) + 1; + else + frame->numParameterSets = FDKreadBits(bitstream, 3) + 1; + } + + /* Any error after this line shall trigger parameter invalidation at bail + * label. */ + paramSetErr = 1; + + if (frame->numParameterSets >= MAX_PARAMETER_SETS) { + goto bail; + } + + /* Basic config check. */ + if (pSpatialSpecificConfig->nInputChannels <= 0 || + pSpatialSpecificConfig->nOutputChannels <= 0) { + err = MPS_UNSUPPORTED_CONFIG; + goto bail; + } + + if (bsFramingType) { + int prevParamSlot = -1; + int bitsParamSlot; + + { + bitsParamSlot = nBitsParamSlot(pSpatialSpecificConfig->nTimeSlots); + + for (i = 0; i < frame->numParameterSets; i++) { + frame->paramSlot[i] = FDKreadBits(bitstream, bitsParamSlot); + /* Sanity check */ + if ((frame->paramSlot[i] <= prevParamSlot) || + (frame->paramSlot[i] >= pSpatialSpecificConfig->nTimeSlots)) { + err = MPS_PARSE_ERROR; + goto bail; + } + prevParamSlot = frame->paramSlot[i]; + } + } + } else { + for (i = 0; i < frame->numParameterSets; i++) { + frame->paramSlot[i] = ((pSpatialSpecificConfig->nTimeSlots * (i + 1)) / + frame->numParameterSets) - + 1; + } + } + + if ((syntaxFlags & (SACDEC_SYNTAX_USAC | SACDEC_SYNTAX_RSVD50)) && + fGlobalIndependencyFlag) { + frame->bsIndependencyFlag = 1; + } else { + frame->bsIndependencyFlag = (UCHAR)FDKreadBits(bitstream, 1); + } + + /* + * OttData() + */ + for (i = 0; i < pSpatialSpecificConfig->nOttBoxes; i++) { + err = ecDataDec(frame, syntaxFlags, bitstream, &frame->CLDLosslessData[i], + frame->cmpOttCLDidx, self->cmpOttCLDidxPrev, t_CLD, i, 0, + pSpatialSpecificConfig->bitstreamOttBands[i], + pSpatialSpecificConfig->ottCLDdefault[i]); + if (err != MPS_OK) { + goto bail; + } + } /* i < numOttBoxes */ + + { + for (i = 0; i < pSpatialSpecificConfig->nOttBoxes; i++) { + err = ecDataDec(frame, syntaxFlags, bitstream, &frame->ICCLosslessData[i], + frame->cmpOttICCidx, self->cmpOttICCidxPrev, t_ICC, i, 0, + pSpatialSpecificConfig->bitstreamOttBands[i], ICCdefault); + if (err != MPS_OK) { + goto bail; + } + } /* i < numOttBoxes */ + } /* !oneICC */ + + if ((pSpatialSpecificConfig->treeConfig == SPATIALDEC_MODE_RSVD7) && + (pSpatialSpecificConfig->bsPhaseCoding)) { + frame->phaseMode = FDKreadBits(bitstream, 1); + + if (frame->phaseMode == 0) { + for (pb = 0; pb < pSpatialSpecificConfig->numOttBandsIPD; pb++) { + self->cmpOttIPDidxPrev[0][pb] = 0; + for (i = 0; i < frame->numParameterSets; i++) { + frame->cmpOttIPDidx[0][i][pb] = 0; + // frame->ottIPDidx[0][i][pb] = 0; + } + /* self->ottIPDidxPrev[0][pb] = 0; */ + } + frame->OpdSmoothingMode = 0; + } else { + frame->OpdSmoothingMode = FDKreadBits(bitstream, 1); + err = ecDataDec(frame, syntaxFlags, bitstream, &frame->IPDLosslessData[0], + frame->cmpOttIPDidx, self->cmpOttIPDidxPrev, t_IPD, 0, 0, + pSpatialSpecificConfig->numOttBandsIPD, IPDdefault); + if (err != MPS_OK) { + goto bail; + } + } + } + + /* + * SmgData() + */ + + { + if (!pSpatialSpecificConfig->bsHighRateMode && + (syntaxFlags & SACDEC_SYNTAX_USAC)) { + for (ps = 0; ps < frame->numParameterSets; ps++) { + frame->bsSmoothMode[ps] = 0; + } + } else { + for (ps = 0; ps < frame->numParameterSets; ps++) { + frame->bsSmoothMode[ps] = (UCHAR)FDKreadBits(bitstream, 2); + if (frame->bsSmoothMode[ps] >= 2) { + frame->bsSmoothTime[ps] = (UCHAR)FDKreadBits(bitstream, 2); + } + if (frame->bsSmoothMode[ps] == 3) { + frame->bsFreqResStrideSmg[ps] = (UCHAR)FDKreadBits(bitstream, 2); + dataBands = (pSpatialSpecificConfig->freqRes - 1) / + pbStrideTable[frame->bsFreqResStrideSmg[ps]] + + 1; + for (pg = 0; pg < dataBands; pg++) { + frame->bsSmgData[ps][pg] = (UCHAR)FDKreadBits(bitstream, 1); + } + } + } /* ps < numParameterSets */ + } + } + + /* + * TempShapeData() + */ + if ((pSpatialSpecificConfig->tempShapeConfig == 3) && + (syntaxFlags & SACDEC_SYNTAX_USAC)) { + int TsdErr; + TsdErr = TsdRead(bitstream, pSpatialSpecificConfig->nTimeSlots, + &frame->TsdData[0]); + if (TsdErr) { + err = MPS_PARSE_ERROR; + goto bail; + } + } else { + frame->TsdData[0].bsTsdEnable = 0; + } + + for (i = 0; i < bsNumOutputChannels; i++) { + frame->tempShapeEnableChannelSTP[i] = 0; + frame->tempShapeEnableChannelGES[i] = 0; + } + + if ((pSpatialSpecificConfig->tempShapeConfig == 1) || + (pSpatialSpecificConfig->tempShapeConfig == 2)) { + int bsTempShapeEnable = FDKreadBits(bitstream, 1); + if (bsTempShapeEnable) { + numTempShapeChan = + tempShapeChanTable[pSpatialSpecificConfig->tempShapeConfig - 1] + [pSpatialSpecificConfig->treeConfig]; + switch (pSpatialSpecificConfig->tempShapeConfig) { + case 1: /* STP */ + for (i = 0; i < numTempShapeChan; i++) { + int stpEnable = FDKreadBits(bitstream, 1); + frame->tempShapeEnableChannelSTP[i] = stpEnable; + } + break; + case 2: /* GES */ + { + UCHAR gesChannelEnable[MAX_OUTPUT_CHANNELS]; + + for (i = 0; i < numTempShapeChan; i++) { + gesChannelEnable[i] = (UCHAR)FDKreadBits(bitstream, 1); + frame->tempShapeEnableChannelGES[i] = gesChannelEnable[i]; + } + for (i = 0; i < numTempShapeChan; i++) { + if (gesChannelEnable[i]) { + int envShapeData_tmp[MAX_TIME_SLOTS]; + if (huff_dec_reshape(bitstream, envShapeData_tmp, + pSpatialSpecificConfig->nTimeSlots) != 0) { + err = MPS_PARSE_ERROR; + goto bail; + } + for (int ts = 0; ts < pSpatialSpecificConfig->nTimeSlots; ts++) { + if (!(envShapeData_tmp[ts] >= 0) && + (envShapeData_tmp[ts] <= 4)) { + err = MPS_PARSE_ERROR; + goto bail; + } + frame->bsEnvShapeData[i][ts] = (UCHAR)envShapeData_tmp[ts]; + } + } + } + } break; + default: + err = MPS_INVALID_TEMPSHAPE; + goto bail; + } + } /* bsTempShapeEnable */ + } /* pSpatialSpecificConfig->tempShapeConfig != 0 */ + + if (pSpatialSpecificConfig->bArbitraryDownmix != 0) { + err = parseArbitraryDownmixData(self, pSpatialSpecificConfig, syntaxFlags, + frame, bitstream); + if (err != MPS_OK) goto bail; + } + + if (1 && (!(syntaxFlags & (SACDEC_SYNTAX_USAC)))) { + FDKbyteAlign(bitstream, + alignAnchor); /* ISO/IEC FDIS 23003-1: 5.2. ... byte alignment + with respect to the beginning of the syntactic + element in which ByteAlign() occurs. */ + } + +bail: + if (err != MPS_OK && paramSetErr != 0) { + /* Since the parameter set data has already been written to the instance we + * need to ... */ + frame->numParameterSets = 0; /* ... signal that it is corrupt ... */ + } + + return err; + +} /* SpatialDecParseFrame */ + +/******************************************************************************* + Functionname: createMapping + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +static void createMapping(int aMap[MAX_PARAMETER_BANDS + 1], int startBand, + int stopBand, int stride) { + int inBands, outBands, bandsAchived, bandsDiff, incr, k, i; + int vDk[MAX_PARAMETER_BANDS + 1]; + inBands = stopBand - startBand; + outBands = (inBands - 1) / stride + 1; + + if (outBands < 1) { + outBands = 1; + } + + bandsAchived = outBands * stride; + bandsDiff = inBands - bandsAchived; + for (i = 0; i < outBands; i++) { + vDk[i] = stride; + } + + if (bandsDiff > 0) { + incr = -1; + k = outBands - 1; + } else { + incr = 1; + k = 0; + } + + while (bandsDiff != 0) { + vDk[k] = vDk[k] - incr; + k = k + incr; + bandsDiff = bandsDiff + incr; + if (k >= outBands) { + if (bandsDiff > 0) { + k = outBands - 1; + } else if (bandsDiff < 0) { + k = 0; + } + } + } + aMap[0] = startBand; + for (i = 0; i < outBands; i++) { + aMap[i + 1] = aMap[i] + vDk[i]; + } +} /* createMapping */ + +/******************************************************************************* + Functionname: mapFrequency + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +static void mapFrequency(const SCHAR *pInput, /* Input */ + SCHAR *pOutput, /* Output */ + int *pMap, /* Mapping function */ + int dataBands) /* Number of data Bands */ +{ + int i, j; + int startBand0 = pMap[0]; + + for (i = 0; i < dataBands; i++) { + int startBand, stopBand, value; + + value = pInput[i + startBand0]; + + startBand = pMap[i]; + stopBand = pMap[i + 1]; + for (j = startBand; j < stopBand; j++) { + pOutput[j] = value; + } + } +} + +/******************************************************************************* + Functionname: deq + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +static int deqIdx(int value, int paramType) { + int idx = -1; + + switch (paramType) { + case t_CLD: + if (((value + 15) >= 0) && ((value + 15) < 31)) { + idx = (value + 15); + } + break; + + case t_ICC: + if ((value >= 0) && (value < 8)) { + idx = value; + } + break; + + case t_IPD: + /* (+/-)15 * MAX_PARAMETER_BANDS for differential coding in frequency + * domain (according to rbl) */ + if ((value >= -420) && (value <= 420)) { + idx = (value & 0xf); + } + break; + + default: + FDK_ASSERT(0); + } + + return idx; +} + + /******************************************************************************* + Functionname: factorFunct + ******************************************************************************* + + Description: + + Arguments: + + Return: + + *******************************************************************************/ + +#define SF_IDX (7) +#define SF_FACTOR (3) +#define SCALE_FACTOR (1 << SF_FACTOR) +#define SCALE_CLD_C1C2 (1 << SF_CLD_C1C2) + +static FIXP_DBL factorFunct(FIXP_DBL ottVsTotDb, INT quantMode) { + FIXP_DBL factor; + + if (ottVsTotDb > FL2FXCONST_DBL(0.0)) { + ottVsTotDb = FL2FXCONST_DBL(0.0); + } + + ottVsTotDb = -ottVsTotDb; + + switch (quantMode) { + case 0: + factor = FL2FXCONST_DBL(1.0f / SCALE_FACTOR); + break; + case 1: + if (ottVsTotDb >= FL2FXCONST_DBL(21.0f / SCALE_CLD_C1C2)) + factor = FL2FXCONST_DBL(5.0f / SCALE_FACTOR); + else if (ottVsTotDb <= FL2FXCONST_DBL(1.0f / SCALE_CLD_C1C2)) + factor = FL2FXCONST_DBL(1.0f / SCALE_FACTOR); + else + factor = (fMult(FL2FXCONST_DBL(0.2f), ottVsTotDb) + + FL2FXCONST_DBL(0.8f / SCALE_CLD_C1C2)) + << (SF_CLD_C1C2 - SF_FACTOR); + break; + case 2: + if (ottVsTotDb >= FL2FXCONST_DBL(25.0f / SCALE_CLD_C1C2)) { + FDK_ASSERT(SF_FACTOR == 3); + factor = (FIXP_DBL) + MAXVAL_DBL; /* avoid warning: FL2FXCONST_DBL(8.0f/SCALE_FACTOR) */ + } else if (ottVsTotDb <= FL2FXCONST_DBL(1.0f / SCALE_CLD_C1C2)) + factor = FL2FXCONST_DBL(1.0f / SCALE_FACTOR); + else + factor = (fMult(FL2FXCONST_DBL(7.0f / 24.0f), ottVsTotDb) + + FL2FXCONST_DBL((17.0f / 24.0f) / SCALE_CLD_C1C2)) + << (SF_CLD_C1C2 - SF_FACTOR); + break; + default: + factor = FL2FXCONST_DBL(0.0f); + } + + return (factor); +} + +/******************************************************************************* + Functionname: factorCLD + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +static void factorCLD(SCHAR *idx, FIXP_DBL ottVsTotDb, FIXP_DBL *ottVsTotDb1, + FIXP_DBL *ottVsTotDb2, SCHAR ottVsTotDbMode, + INT quantMode) { + FIXP_DBL factor; + FIXP_DBL cldIdxFract; + INT cldIdx; + + factor = factorFunct(ottVsTotDb, quantMode); + + cldIdxFract = + fMult((FIXP_DBL)((*idx) << ((DFRACT_BITS - 1) - SF_IDX)), factor); + cldIdxFract += FL2FXCONST_DBL(15.5f / (1 << (SF_FACTOR + SF_IDX))); + cldIdx = fixp_truncateToInt(cldIdxFract, SF_FACTOR + SF_IDX); + + cldIdx = fMin(cldIdx, 30); + cldIdx = fMax(cldIdx, 0); + + *idx = cldIdx - 15; + + if (ottVsTotDbMode & ottVsTotDb1Activ) + (*ottVsTotDb1) = ottVsTotDb + dequantCLD_c1[cldIdx]; + + if (ottVsTotDbMode & ottVsTotDb2Activ) + (*ottVsTotDb2) = ottVsTotDb + dequantCLD_c1[30 - cldIdx]; +} + +/******************************************************************************* + Functionname: mapIndexData + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +static SACDEC_ERROR mapIndexData( + LOSSLESSDATA *llData, SCHAR ***outputDataIdx, SCHAR ***outputIdxData, + const SCHAR (*cmpIdxData)[MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS], + SCHAR ***diffIdxData, SCHAR xttIdx, SCHAR **idxPrev, int paramIdx, + int paramType, int startBand, int stopBand, SCHAR defaultValue, + int numParameterSets, const int *paramSlot, int extendFrame, int quantMode, + SpatialDecConcealmentInfo *concealmentInfo, SCHAR ottVsTotDbMode, + FIXP_DBL (*pOttVsTotDbIn)[MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS], + FIXP_DBL (*pOttVsTotDb1)[MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS], + FIXP_DBL (*pOttVsTotDb2)[MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS]) { + int aParamSlots[MAX_PARAMETER_SETS]; + int aInterpolate[MAX_PARAMETER_SETS]; + + int dataSets; + int aMap[MAX_PARAMETER_BANDS + 1]; + + int setIdx, i, band, parmSlot; + int dataBands; + int ps, pb; + int i1; + + if (numParameterSets > MAX_PARAMETER_SETS) return MPS_WRONG_PARAMETERSETS; + + dataSets = 0; + for (i = 0; i < numParameterSets; i++) { + if (llData->bsXXXDataMode[i] == 3) { + aParamSlots[dataSets] = i; + dataSets++; + } + } + + setIdx = 0; + + /* Main concealment stage is here: */ + SpatialDecConcealment_Apply( + concealmentInfo, cmpIdxData[xttIdx], + (diffIdxData != NULL) ? diffIdxData[xttIdx] : NULL, idxPrev[xttIdx], + llData->bsXXXDataMode, startBand, stopBand, defaultValue, paramType, + numParameterSets); + + /* Prepare data */ + for (i = 0; i < numParameterSets; i++) { + if (llData->bsXXXDataMode[i] == 0) { + llData->nocmpQuantCoarseXXX[i] = 0; + for (band = startBand; band < stopBand; band++) { + outputIdxData[xttIdx][i][band] = defaultValue; + } + for (band = startBand; band < stopBand; band++) { + idxPrev[xttIdx][band] = outputIdxData[xttIdx][i][band]; + } + /* Because the idxPrev are also set to the defaultValue -> signalize fine + */ + llData->state->bsQuantCoarseXXXprev = 0; + } + + if (llData->bsXXXDataMode[i] == 1) { + for (band = startBand; band < stopBand; band++) { + outputIdxData[xttIdx][i][band] = idxPrev[xttIdx][band]; + } + llData->nocmpQuantCoarseXXX[i] = llData->state->bsQuantCoarseXXXprev; + } + + if (llData->bsXXXDataMode[i] == 2) { + for (band = startBand; band < stopBand; band++) { + outputIdxData[xttIdx][i][band] = idxPrev[xttIdx][band]; + } + llData->nocmpQuantCoarseXXX[i] = llData->state->bsQuantCoarseXXXprev; + aInterpolate[i] = 1; + } else { + aInterpolate[i] = 0; + } + + if (llData->bsXXXDataMode[i] == 3) { + int stride; + + parmSlot = aParamSlots[setIdx]; + stride = pbStrideTable[llData->bsFreqResStrideXXX[setIdx]]; + dataBands = (stopBand - startBand - 1) / stride + 1; + createMapping(aMap, startBand, stopBand, stride); + mapFrequency(&cmpIdxData[xttIdx][setIdx][0], + &outputIdxData[xttIdx][parmSlot][0], aMap, dataBands); + for (band = startBand; band < stopBand; band++) { + idxPrev[xttIdx][band] = outputIdxData[xttIdx][parmSlot][band]; + } + llData->state->bsQuantCoarseXXXprev = llData->bsQuantCoarseXXX[setIdx]; + llData->nocmpQuantCoarseXXX[i] = llData->bsQuantCoarseXXX[setIdx]; + + setIdx++; + } + if (diffIdxData != NULL) { + for (band = startBand; band < stopBand; band++) { + outputIdxData[xttIdx][i][band] += diffIdxData[xttIdx][i][band]; + } + } + } /* for( i = 0 ; i < numParameterSets; i++ ) */ + + /* Map all coarse data to fine */ + for (i = 0; i < numParameterSets; i++) { + if (llData->nocmpQuantCoarseXXX[i] == 1) { + coarse2fine(outputIdxData[xttIdx][i], (DATA_TYPE)paramType, startBand, + stopBand - startBand); + llData->nocmpQuantCoarseXXX[i] = 0; + } + } + + /* Interpolate */ + i1 = 0; + for (i = 0; i < numParameterSets; i++) { + int xi, i2, x1, x2; + + if (aInterpolate[i] != 1) { + i1 = i; + } + i2 = i; + while (aInterpolate[i2] == 1) { + i2++; + } + x1 = paramSlot[i1]; + xi = paramSlot[i]; + x2 = paramSlot[i2]; + + if (aInterpolate[i] == 1) { + if (i2 >= numParameterSets) return MPS_WRONG_PARAMETERSETS; + for (band = startBand; band < stopBand; band++) { + int yi, y1, y2; + y1 = outputIdxData[xttIdx][i1][band]; + y2 = outputIdxData[xttIdx][i2][band]; + if (x1 != x2) { + yi = y1 + (xi - x1) * (y2 - y1) / (x2 - x1); + } else { + yi = y1 /*+ (xi-x1)*(y2-y1)/1e-12*/; + } + outputIdxData[xttIdx][i][band] = yi; + } + } + } /* for( i = 0 ; i < numParameterSets; i++ ) */ + + /* Dequantize data and apply factorCLD if necessary */ + for (ps = 0; ps < numParameterSets; ps++) { + if (quantMode && (paramType == t_CLD)) { + if (pOttVsTotDbIn == 0) return MPS_WRONG_OTT; + if ((pOttVsTotDb1 == 0) && (ottVsTotDbMode == ottVsTotDb1Activ)) + return MPS_WRONG_OTT; + if ((pOttVsTotDb2 == 0) && (ottVsTotDbMode == ottVsTotDb2Activ)) + return MPS_WRONG_OTT; + + for (pb = startBand; pb < stopBand; pb++) { + factorCLD(&(outputIdxData[xttIdx][ps][pb]), (*pOttVsTotDbIn)[ps][pb], + (pOttVsTotDb1 != NULL) ? &((*pOttVsTotDb1)[ps][pb]) : NULL, + (pOttVsTotDb2 != NULL) ? &((*pOttVsTotDb2)[ps][pb]) : NULL, + ottVsTotDbMode, quantMode); + } + } + + /* Dequantize data */ + for (band = startBand; band < stopBand; band++) { + outputDataIdx[xttIdx][ps][band] = + deqIdx(outputIdxData[xttIdx][ps][band], paramType); + if (outputDataIdx[xttIdx][ps][band] == -1) { + outputDataIdx[xttIdx][ps][band] = defaultValue; + } + } + } /* for( i = 0 ; i < numParameterSets; i++ ) */ + + if (extendFrame) { + for (band = startBand; band < stopBand; band++) { + outputDataIdx[xttIdx][numParameterSets][band] = + outputDataIdx[xttIdx][numParameterSets - 1][band]; + } + } + + return MPS_OK; +} + +/******************************************************************************* + Functionname: decodeAndMapFrameOtt + ******************************************************************************* + + Description: + Do delta decoding and dequantization + + Arguments: + +Input: + +Output: + +*******************************************************************************/ +static SACDEC_ERROR decodeAndMapFrameOtt(HANDLE_SPATIAL_DEC self, + SPATIAL_BS_FRAME *pCurBs) { + int i, ottIdx; + int numOttBoxes; + + SACDEC_ERROR err = MPS_OK; + + numOttBoxes = self->numOttBoxes; + + switch (self->treeConfig) { + default: { + if (self->quantMode != 0) { + goto bail; + } + } + for (i = 0; i < numOttBoxes; i++) { + err = mapIndexData( + &pCurBs->CLDLosslessData[i], /* LOSSLESSDATA *llData,*/ + self->ottCLD__FDK, self->outIdxData, + pCurBs + ->cmpOttCLDidx, /* int + cmpIdxData[MAX_NUM_OTT][MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS], + */ + NULL, /* no differential data */ + i, /* int xttIdx, Which ott/ttt index to use for input and + output buffers */ + self->ottCLDidxPrev, /* int + idxPrev[MAX_NUM_OTT][MAX_PARAMETER_BANDS], + */ + i, t_CLD, 0, /* int startBand, */ + self->pConfigCurrent->bitstreamOttBands[i], /* int stopBand, */ + self->pConfigCurrent->ottCLDdefault[i], /* int defaultValue, */ + pCurBs->numParameterSets, /* int numParameterSets) */ + pCurBs->paramSlot, self->extendFrame, self->quantMode, + &(self->concealInfo), ottVsTotInactiv, NULL, NULL, NULL); + if (err != MPS_OK) goto bail; + + } /* for(i = 0; i < numOttBoxes ; i++ ) */ + break; + } /* case */ + + for (ottIdx = 0; ottIdx < numOttBoxes; ottIdx++) { + /* Read ICC */ + err = mapIndexData( + &pCurBs->ICCLosslessData[ottIdx], /* LOSSLESSDATA *llData,*/ + self->ottICC__FDK, self->outIdxData, + pCurBs + ->cmpOttICCidx, /* int + cmpIdxData[MAX_NUM_OTT][MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS], + */ + self->ottICCdiffidx, /* differential data */ + ottIdx, /* int xttIdx, Which ott/ttt index to use for input and + output buffers */ + self->ottICCidxPrev, /* int idxPrev[MAX_NUM_OTT][MAX_PARAMETER_BANDS], + */ + ottIdx, t_ICC, 0, /* int startBand, */ + self->pConfigCurrent->bitstreamOttBands[ottIdx], /* int stopBand, */ + ICCdefault, /* int defaultValue, */ + pCurBs->numParameterSets, /* int numParameterSets) */ + pCurBs->paramSlot, self->extendFrame, self->quantMode, + &(self->concealInfo), ottVsTotInactiv, NULL, NULL, NULL); + if (err != MPS_OK) goto bail; + } /* ottIdx */ + + if ((self->treeConfig == TREE_212) && (self->phaseCoding)) { + if (pCurBs->phaseMode == 0) { + for (int pb = 0; pb < self->pConfigCurrent->numOttBandsIPD; pb++) { + self->ottIPDidxPrev[0][pb] = 0; + } + } + for (ottIdx = 0; ottIdx < numOttBoxes; ottIdx++) { + err = mapIndexData( + &pCurBs->IPDLosslessData[ottIdx], self->ottIPD__FDK, self->outIdxData, + pCurBs->cmpOttIPDidx, NULL, ottIdx, self->ottIPDidxPrev, ottIdx, + t_IPD, 0, self->numOttBandsIPD, IPDdefault, pCurBs->numParameterSets, + pCurBs->paramSlot, self->extendFrame, self->quantMode, + &(self->concealInfo), ottVsTotInactiv, NULL, NULL, NULL); + } + } + +bail: + + return MPS_OK; + +} /* decodeAndMapFrameOtt */ + +/******************************************************************************* + Functionname: decodeAndMapFrameSmg + ******************************************************************************* + + Description: + Decode smoothing flags + + Arguments: + +Input: + +Output: + + +*******************************************************************************/ +static SACDEC_ERROR decodeAndMapFrameSmg(HANDLE_SPATIAL_DEC self, + const SPATIAL_BS_FRAME *frame) { + int ps, pb, pg, pbStride, dataBands, pbStart, pbStop, + aGroupToBand[MAX_PARAMETER_BANDS + 1]; + + if (frame->numParameterSets > MAX_PARAMETER_SETS) + return MPS_WRONG_PARAMETERSETS; + if (self->bitstreamParameterBands > MAX_PARAMETER_BANDS) + return MPS_WRONG_PARAMETERBANDS; + + for (ps = 0; ps < frame->numParameterSets; ps++) { + switch (frame->bsSmoothMode[ps]) { + case 0: + self->smgTime[ps] = 256; + FDKmemclear(self->smgData[ps], + self->bitstreamParameterBands * sizeof(UCHAR)); + break; + + case 1: + if (ps > 0) { + self->smgTime[ps] = self->smgTime[ps - 1]; + FDKmemcpy(self->smgData[ps], self->smgData[ps - 1], + self->bitstreamParameterBands * sizeof(UCHAR)); + } else { + self->smgTime[ps] = self->smoothState->prevSmgTime; + FDKmemcpy(self->smgData[ps], self->smoothState->prevSmgData, + self->bitstreamParameterBands * sizeof(UCHAR)); + } + break; + + case 2: + self->smgTime[ps] = smgTimeTable[frame->bsSmoothTime[ps]]; + for (pb = 0; pb < self->bitstreamParameterBands; pb++) { + self->smgData[ps][pb] = 1; + } + break; + + case 3: + self->smgTime[ps] = smgTimeTable[frame->bsSmoothTime[ps]]; + pbStride = pbStrideTable[frame->bsFreqResStrideSmg[ps]]; + dataBands = (self->bitstreamParameterBands - 1) / pbStride + 1; + createMapping(aGroupToBand, 0, self->bitstreamParameterBands, pbStride); + for (pg = 0; pg < dataBands; pg++) { + pbStart = aGroupToBand[pg]; + pbStop = aGroupToBand[pg + 1]; + for (pb = pbStart; pb < pbStop; pb++) { + self->smgData[ps][pb] = frame->bsSmgData[ps][pg]; + } + } + break; + } + } + + self->smoothState->prevSmgTime = self->smgTime[frame->numParameterSets - 1]; + FDKmemcpy(self->smoothState->prevSmgData, + self->smgData[frame->numParameterSets - 1], + self->bitstreamParameterBands * sizeof(UCHAR)); + + if (self->extendFrame) { + self->smgTime[frame->numParameterSets] = + self->smgTime[frame->numParameterSets - 1]; + FDKmemcpy(self->smgData[frame->numParameterSets], + self->smgData[frame->numParameterSets - 1], + self->bitstreamParameterBands * sizeof(UCHAR)); + } + + return MPS_OK; +} + +/******************************************************************************* + Functionname: decodeAndMapFrameArbdmx + ******************************************************************************* + + Description: + Do delta decoding and dequantization + + Arguments: + +Input: + +Output: + +*******************************************************************************/ +static SACDEC_ERROR decodeAndMapFrameArbdmx(HANDLE_SPATIAL_DEC self, + const SPATIAL_BS_FRAME *frame) { + SACDEC_ERROR err = MPS_OK; + int ch; + int offset = self->numOttBoxes; + + for (ch = 0; ch < self->numInputChannels; ch++) { + err = mapIndexData(&frame->CLDLosslessData[offset + ch], + self->arbdmxGain__FDK, self->outIdxData, + frame->cmpArbdmxGainIdx, NULL, /* no differential data */ + ch, self->arbdmxGainIdxPrev, offset + ch, t_CLD, 0, + self->bitstreamParameterBands, + 0 /*self->arbdmxGainDefault*/, frame->numParameterSets, + frame->paramSlot, self->extendFrame, 0, + &(self->concealInfo), ottVsTotInactiv, NULL, NULL, NULL); + if (err != MPS_OK) goto bail; + } + +bail: + return err; +} /* decodeAndMapFrameArbdmx */ + +/******************************************************************************* + Functionname: SpatialDecDecodeFrame + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +SACDEC_ERROR SpatialDecDecodeFrame(spatialDec *self, SPATIAL_BS_FRAME *frame) { + SACDEC_ERROR err = MPS_OK; + + self->extendFrame = 0; + if (frame->paramSlot[frame->numParameterSets - 1] != self->timeSlots - 1) { + self->extendFrame = 1; + } + + self->TsdTs = 0; + + /****** DTDF and MAP DATA ********/ + if ((err = decodeAndMapFrameOtt(self, frame)) != MPS_OK) goto bail; + + if ((err = decodeAndMapFrameSmg(self, frame)) != MPS_OK) goto bail; + + if (self->arbitraryDownmix != 0) { + if ((err = decodeAndMapFrameArbdmx(self, frame)) != MPS_OK) goto bail; + } + + if (self->extendFrame) { + frame->numParameterSets = + fixMin(MAX_PARAMETER_SETS, frame->numParameterSets + 1); + frame->paramSlot[frame->numParameterSets - 1] = self->timeSlots - 1; + } + +bail: + return err; +} /* SpatialDecDecodeFrame() */ + +/******************************************************************************* + Functionname: SpatialDecodeHeader + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ + +SACDEC_ERROR SpatialDecDecodeHeader( + spatialDec *self, SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig) { + SACDEC_ERROR err = MPS_OK; + int i; + + self->samplingFreq = pSpatialSpecificConfig->samplingFreq; + self->timeSlots = pSpatialSpecificConfig->nTimeSlots; + self->frameLength = self->timeSlots * self->qmfBands; + self->bitstreamParameterBands = pSpatialSpecificConfig->freqRes; + + if (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD) + self->hybridBands = self->qmfBands; + else + self->hybridBands = SacGetHybridSubbands(self->qmfBands); + self->tp_hybBandBorder = 12; + + self->numParameterBands = self->bitstreamParameterBands; + + if (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD) { + switch (self->numParameterBands) { + case 4: + self->kernels = kernels_4_to_64; + break; + case 5: + self->kernels = kernels_5_to_64; + break; + case 7: + self->kernels = kernels_7_to_64; + break; + case 9: + self->kernels = kernels_9_to_64; + break; + case 12: + self->kernels = kernels_12_to_64; + break; + case 15: + self->kernels = kernels_15_to_64; + break; + case 23: + self->kernels = kernels_23_to_64; + break; + default: + return MPS_INVALID_PARAMETERBANDS; /* unsupported numParameterBands */ + } + } else { + switch (self->numParameterBands) { + case 4: + self->kernels = kernels_4_to_71; + break; + case 5: + self->kernels = kernels_5_to_71; + break; + case 7: + self->kernels = kernels_7_to_71; + break; + case 10: + self->kernels = kernels_10_to_71; + break; + case 14: + self->kernels = kernels_14_to_71; + break; + case 20: + self->kernels = kernels_20_to_71; + break; + case 28: + self->kernels = kernels_28_to_71; + break; + default: + return MPS_INVALID_PARAMETERBANDS; /* unsupported numParameterBands */ + } + } + + /* create param to hyb band table */ + FDKmemclear(self->param2hyb, (MAX_PARAMETER_BANDS + 1) * sizeof(int)); + for (i = 0; i < self->hybridBands; i++) { + self->param2hyb[self->kernels[i] + 1] = i + 1; + } + { + int pb = self->kernels[i - 1] + 2; + for (; pb < (MAX_PARAMETER_BANDS + 1); pb++) { + self->param2hyb[pb] = i; + } + for (pb = 0; pb < MAX_PARAMETER_BANDS; pb += 1) { + self->kernels_width[pb] = self->param2hyb[pb + 1] - self->param2hyb[pb]; + } + } + + self->treeConfig = pSpatialSpecificConfig->treeConfig; + + self->numOttBoxes = pSpatialSpecificConfig->nOttBoxes; + + self->numInputChannels = pSpatialSpecificConfig->nInputChannels; + + self->numOutputChannels = pSpatialSpecificConfig->nOutputChannels; + + self->quantMode = pSpatialSpecificConfig->quantMode; + + self->arbitraryDownmix = pSpatialSpecificConfig->bArbitraryDownmix; + + self->numM2rows = self->numOutputChannels; + + { + self->residualCoding = 0; + if (self->arbitraryDownmix == 2) + self->arbitraryDownmix = 1; /* no arbitrary downmix residuals */ + } + if ((self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_USAC)) { + self->residualCoding = pSpatialSpecificConfig->bResidualCoding; + } + + self->clipProtectGain__FDK = + FX_CFG2FX_DBL(clipGainTable__FDK[pSpatialSpecificConfig->bsFixedGainDMX]); + self->clipProtectGainSF__FDK = + clipGainSFTable__FDK[pSpatialSpecificConfig->bsFixedGainDMX]; + + self->tempShapeConfig = pSpatialSpecificConfig->tempShapeConfig; + + self->decorrConfig = pSpatialSpecificConfig->decorrConfig; + + if (self->upmixType == UPMIXTYPE_BYPASS) { + self->numOutputChannels = self->numInputChannels; + } + + self->numOutputChannelsAT = self->numOutputChannels; + + self->numOttBandsIPD = pSpatialSpecificConfig->numOttBandsIPD; + self->phaseCoding = pSpatialSpecificConfig->bsPhaseCoding; + for (i = 0; i < self->numOttBoxes; i++) { + { + self->pConfigCurrent->bitstreamOttBands[i] = + self->bitstreamParameterBands; + } + self->numOttBands[i] = self->pConfigCurrent->bitstreamOttBands[i]; + } /* i */ + + if (self->residualCoding) { + int numBoxes = self->numOttBoxes; + for (i = 0; i < numBoxes; i++) { + self->residualPresent[i] = + pSpatialSpecificConfig->ResidualConfig[i].bResidualPresent; + + if (self->residualPresent[i]) { + self->residualBands[i] = + pSpatialSpecificConfig->ResidualConfig[i].nResidualBands; + /* conversion from hybrid bands to qmf bands */ + self->residualQMFBands[i] = + fMax(self->param2hyb[self->residualBands[i]] + 3 - 10, + 3); /* simplification for the lowest 10 hybrid bands */ + } else { + self->residualBands[i] = 0; + self->residualQMFBands[i] = 0; + } + } + } /* self->residualCoding */ + else { + int boxes = self->numOttBoxes; + for (i = 0; i < boxes; i += 1) { + self->residualPresent[i] = 0; + self->residualBands[i] = 0; + } + } + + switch (self->treeConfig) { + case TREE_212: + self->numDirektSignals = 1; + self->numDecorSignals = 1; + self->numXChannels = 1; + if (self->arbitraryDownmix == 2) { + self->numXChannels += 1; + } + self->numVChannels = self->numDirektSignals + self->numDecorSignals; + break; + default: + return MPS_INVALID_TREECONFIG; + } + + self->highRateMode = pSpatialSpecificConfig->bsHighRateMode; + self->decorrType = pSpatialSpecificConfig->bsDecorrType; + + SpatialDecDecodeHelperInfo(pSpatialSpecificConfig, UPMIXTYPE_NORMAL); + + return err; +} + +/******************************************************************************* + Functionname: SpatialDecCreateBsFrame + ******************************************************************************* + + Description: Create spatial bitstream structure + + Arguments: spatialDec* self + const SPATIAL_BS_FRAME **bsFrame + + Return: - + +*******************************************************************************/ +SACDEC_ERROR SpatialDecCreateBsFrame(SPATIAL_BS_FRAME *bsFrame, + BS_LL_STATE *llState) { + SPATIAL_BS_FRAME *pBs = bsFrame; + + const int maxNumOtt = MAX_NUM_OTT; + const int maxNumInputChannels = MAX_INPUT_CHANNELS; + + FDK_ALLOCATE_MEMORY_1D_P( + pBs->cmpOttIPDidx, maxNumOtt * MAX_PARAMETER_SETS * MAX_PARAMETER_BANDS, + SCHAR, SCHAR(*)[MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS]) + + /* Arbitrary Downmix */ + FDK_ALLOCATE_MEMORY_1D_P( + pBs->cmpArbdmxGainIdx, + maxNumInputChannels * MAX_PARAMETER_SETS * MAX_PARAMETER_BANDS, SCHAR, + SCHAR(*)[MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS]) + + /* Lossless control */ + FDK_ALLOCATE_MEMORY_1D(pBs->CLDLosslessData, MAX_NUM_PARAMETERS, LOSSLESSDATA) + FDK_ALLOCATE_MEMORY_1D(pBs->ICCLosslessData, MAX_NUM_PARAMETERS, LOSSLESSDATA) + + FDK_ALLOCATE_MEMORY_1D(pBs->IPDLosslessData, MAX_NUM_PARAMETERS, LOSSLESSDATA) + + pBs->newBsData = 0; + pBs->numParameterSets = 1; + + /* Link lossless states */ + for (int x = 0; x < MAX_NUM_PARAMETERS; x++) { + pBs->CLDLosslessData[x].state = &llState->CLDLosslessState[x]; + pBs->ICCLosslessData[x].state = &llState->ICCLosslessState[x]; + + pBs->IPDLosslessData[x].state = &llState->IPDLosslessState[x]; + } + + return MPS_OK; + +bail: + return MPS_OUTOFMEMORY; +} + +/******************************************************************************* + Functionname: SpatialDecCloseBsFrame + ******************************************************************************* + + Description: Close spatial bitstream structure + + Arguments: spatialDec* self + + Return: - + +*******************************************************************************/ +void SpatialDecCloseBsFrame(SPATIAL_BS_FRAME *pBs) { + if (pBs != NULL) { + /* These arrays contain the compact indices, only one value per pbstride, + * only paramsets actually containing data. */ + + FDK_FREE_MEMORY_1D(pBs->cmpOttIPDidx); + + /* Arbitrary Downmix */ + FDK_FREE_MEMORY_1D(pBs->cmpArbdmxGainIdx); + + /* Lossless control */ + FDK_FREE_MEMORY_1D(pBs->IPDLosslessData); + FDK_FREE_MEMORY_1D(pBs->CLDLosslessData); + FDK_FREE_MEMORY_1D(pBs->ICCLosslessData); + } +} diff --git a/libSACdec/src/sac_bitdec.h b/libSACdec/src/sac_bitdec.h new file mode 100644 index 0000000..cb0c7d2 --- /dev/null +++ b/libSACdec/src/sac_bitdec.h @@ -0,0 +1,161 @@ +/* ----------------------------------------------------------------------------- +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 Dec bitstream decoder + +*******************************************************************************/ + +/*! + \file + \brief Spatial Audio bitstream decoder +*/ + +#ifndef SAC_BITDEC_H +#define SAC_BITDEC_H + +#include "sac_dec.h" + +typedef struct { + SCHAR numInputChannels; + SCHAR numOutputChannels; + SCHAR numOttBoxes; + SCHAR numTttBoxes; + SCHAR ottModeLfe[MAX_NUM_OTT]; +} TREEPROPERTIES; + +enum { TREE_212 = 7, TREE_DUMMY = 255 }; + +enum { QUANT_FINE = 0, QUANT_EBQ1 = 1, QUANT_EBQ2 = 2 }; + +SACDEC_ERROR SpatialDecParseSpecificConfigHeader( + HANDLE_FDK_BITSTREAM bitstream, + SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, + AUDIO_OBJECT_TYPE coreCodec, SPATIAL_DEC_UPMIX_TYPE upmixType); + +SACDEC_ERROR SpatialDecParseMps212Config( + HANDLE_FDK_BITSTREAM bitstream, + SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, int samplingRate, + AUDIO_OBJECT_TYPE coreCodec, INT stereoConfigIndex, + INT coreSbrFrameLengthIndex); + +SACDEC_ERROR SpatialDecParseSpecificConfig( + HANDLE_FDK_BITSTREAM bitstream, + SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, int sacHeaderLen, + AUDIO_OBJECT_TYPE coreCodec); + +int SpatialDecDefaultSpecificConfig( + SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, + AUDIO_OBJECT_TYPE coreCodec, int samplingFreq, int nTimeSlots, + int sacDecoderLevel, int isBlind, int coreChannels); + +SACDEC_ERROR SpatialDecCreateBsFrame(SPATIAL_BS_FRAME *bsFrame, + BS_LL_STATE *llState); + +void SpatialDecCloseBsFrame(SPATIAL_BS_FRAME *bsFrame); + +SACDEC_ERROR SpatialDecParseFrameData( + spatialDec *self, SPATIAL_BS_FRAME *frame, HANDLE_FDK_BITSTREAM bitstream, + const SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, UPMIXTYPE upmixType, + int fGlobalIndependencyFlag); + +SACDEC_ERROR SpatialDecDecodeFrame(spatialDec *self, SPATIAL_BS_FRAME *frame); + +SACDEC_ERROR SpatialDecDecodeHeader( + spatialDec *self, SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig); + +#endif diff --git a/libSACdec/src/sac_calcM1andM2.cpp b/libSACdec/src/sac_calcM1andM2.cpp new file mode 100644 index 0000000..6e5a145 --- /dev/null +++ b/libSACdec/src/sac_calcM1andM2.cpp @@ -0,0 +1,848 @@ +/* ----------------------------------------------------------------------------- +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 Dec M1 and M2 calculation + +*******************************************************************************/ + +#include "sac_calcM1andM2.h" +#include "sac_bitdec.h" +#include "sac_process.h" +#include "sac_rom.h" +#include "sac_smoothing.h" +#include "FDK_trigFcts.h" + +/* assorted definitions and constants */ + +#define ABS_THR2 1.0e-9 +#define SQRT2_FDK \ + ((FIXP_DBL)FL2FXCONST_DBL(0.70710678118f)) /* FDKsqrt(2.0) scaled by 0.5 */ + +static void param2UMX_PS__FDK(spatialDec* self, + FIXP_DBL H11[MAX_PARAMETER_BANDS], + FIXP_DBL H12[MAX_PARAMETER_BANDS], + FIXP_DBL H21[MAX_PARAMETER_BANDS], + FIXP_DBL H22[MAX_PARAMETER_BANDS], + FIXP_DBL c_l[MAX_PARAMETER_BANDS], + FIXP_DBL c_r[MAX_PARAMETER_BANDS], int ottBoxIndx, + int parameterSetIndx, int resBands); + +static void param2UMX_PS_Core__FDK( + const SCHAR cld[MAX_PARAMETER_BANDS], const SCHAR icc[MAX_PARAMETER_BANDS], + const int numOttBands, const int resBands, + FIXP_DBL H11[MAX_PARAMETER_BANDS], FIXP_DBL H12[MAX_PARAMETER_BANDS], + FIXP_DBL H21[MAX_PARAMETER_BANDS], FIXP_DBL H22[MAX_PARAMETER_BANDS], + FIXP_DBL c_l[MAX_PARAMETER_BANDS], FIXP_DBL c_r[MAX_PARAMETER_BANDS]); + +static void param2UMX_PS_IPD_OPD__FDK( + spatialDec* self, const SPATIAL_BS_FRAME* frame, + FIXP_DBL H11re[MAX_PARAMETER_BANDS], FIXP_DBL H12re[MAX_PARAMETER_BANDS], + FIXP_DBL H21re[MAX_PARAMETER_BANDS], FIXP_DBL H22re[MAX_PARAMETER_BANDS], + FIXP_DBL c_l[MAX_PARAMETER_BANDS], FIXP_DBL c_r[MAX_PARAMETER_BANDS], + int ottBoxIndx, int parameterSetIndx, int residualBands); + +static void param2UMX_Prediction__FDK( + spatialDec* self, FIXP_DBL H11re[MAX_PARAMETER_BANDS], + FIXP_DBL H11im[MAX_PARAMETER_BANDS], FIXP_DBL H12re[MAX_PARAMETER_BANDS], + FIXP_DBL H12im[MAX_PARAMETER_BANDS], FIXP_DBL H21re[MAX_PARAMETER_BANDS], + FIXP_DBL H21im[MAX_PARAMETER_BANDS], FIXP_DBL H22re[MAX_PARAMETER_BANDS], + FIXP_DBL H22im[MAX_PARAMETER_BANDS], int ottBoxIndx, int parameterSetIndx, + int resBands); + +/* static void SpatialDecCalculateM0(spatialDec* self,int ps); */ +static SACDEC_ERROR SpatialDecCalculateM1andM2_212( + spatialDec* self, int ps, const SPATIAL_BS_FRAME* frame); + +/******************************************************************************* + Functionname: SpatialDecGetResidualIndex + ******************************************************************************* + + Description: + + Arguments: + + Input: + + Output: + +*******************************************************************************/ +int SpatialDecGetResidualIndex(spatialDec* self, int row) { + return row2residual[self->treeConfig][row]; +} + +/******************************************************************************* + Functionname: UpdateAlpha + ******************************************************************************* + + Description: + + Arguments: + + Input: + + Output: + +*******************************************************************************/ +static void updateAlpha(spatialDec* self) { + int nChIn = self->numInputChannels; + int ch; + + for (ch = 0; ch < nChIn; ch++) { + FIXP_DBL alpha = /* FL2FXCONST_DBL(1.0f) */ (FIXP_DBL)MAXVAL_DBL; + + self->arbdmxAlphaPrev__FDK[ch] = self->arbdmxAlpha__FDK[ch]; + + self->arbdmxAlpha__FDK[ch] = alpha; + } +} + +/******************************************************************************* + Functionname: SpatialDecCalculateM1andM2 + ******************************************************************************* + Description: + Arguments: +*******************************************************************************/ +SACDEC_ERROR SpatialDecCalculateM1andM2(spatialDec* self, int ps, + const SPATIAL_BS_FRAME* frame) { + SACDEC_ERROR err = MPS_OK; + + if ((self->arbitraryDownmix != 0) && (ps == 0)) { + updateAlpha(self); + } + + self->pActivM2ParamBands = NULL; + + switch (self->upmixType) { + case UPMIXTYPE_BYPASS: + case UPMIXTYPE_NORMAL: + switch (self->treeConfig) { + case TREE_212: + err = SpatialDecCalculateM1andM2_212(self, ps, frame); + break; + default: + err = MPS_WRONG_TREECONFIG; + }; + break; + + default: + err = MPS_WRONG_TREECONFIG; + } + + if (err != MPS_OK) { + goto bail; + } + +bail: + return err; +} + +/******************************************************************************* + Functionname: SpatialDecCalculateM1andM2_212 + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +static SACDEC_ERROR SpatialDecCalculateM1andM2_212( + spatialDec* self, int ps, const SPATIAL_BS_FRAME* frame) { + SACDEC_ERROR err = MPS_OK; + int pb; + + FIXP_DBL H11re[MAX_PARAMETER_BANDS] = {FL2FXCONST_DBL(0.0f)}; + FIXP_DBL H12re[MAX_PARAMETER_BANDS] = {FL2FXCONST_DBL(0.0f)}; + FIXP_DBL H21re[MAX_PARAMETER_BANDS] = {FL2FXCONST_DBL(0.0f)}; + FIXP_DBL H22re[MAX_PARAMETER_BANDS] = {FL2FXCONST_DBL(0.0f)}; + FIXP_DBL H11im[MAX_PARAMETER_BANDS] = {FL2FXCONST_DBL(0.0f)}; + FIXP_DBL H21im[MAX_PARAMETER_BANDS] = {FL2FXCONST_DBL(0.0f)}; + + INT phaseCoding = self->phaseCoding; + + switch (phaseCoding) { + case 1: + /* phase coding: yes; residuals: no */ + param2UMX_PS_IPD_OPD__FDK(self, frame, H11re, H12re, H21re, H22re, NULL, + NULL, 0, ps, self->residualBands[0]); + break; + case 3: + /* phase coding: yes; residuals: yes */ + param2UMX_Prediction__FDK(self, H11re, H11im, H12re, NULL, H21re, H21im, + H22re, NULL, 0, ps, self->residualBands[0]); + break; + default: + if (self->residualCoding) { + /* phase coding: no; residuals: yes */ + param2UMX_Prediction__FDK(self, H11re, NULL, H12re, NULL, H21re, NULL, + H22re, NULL, 0, ps, self->residualBands[0]); + } else { + /* phase coding: no; residuals: no */ + param2UMX_PS__FDK(self, H11re, H12re, H21re, H22re, NULL, NULL, 0, ps, + 0); + } + break; + } + + for (pb = 0; pb < self->numParameterBands; pb++) { + self->M2Real__FDK[0][0][pb] = (H11re[pb]); + self->M2Real__FDK[0][1][pb] = (H12re[pb]); + + self->M2Real__FDK[1][0][pb] = (H21re[pb]); + self->M2Real__FDK[1][1][pb] = (H22re[pb]); + } + if (phaseCoding == 3) { + for (pb = 0; pb < self->numParameterBands; pb++) { + self->M2Imag__FDK[0][0][pb] = (H11im[pb]); + self->M2Imag__FDK[1][0][pb] = (H21im[pb]); + self->M2Imag__FDK[0][1][pb] = (FIXP_DBL)0; // H12im[pb]; + self->M2Imag__FDK[1][1][pb] = (FIXP_DBL)0; // H22im[pb]; + } + } + + if (self->phaseCoding == 1) { + SpatialDecSmoothOPD( + self, frame, + ps); /* INPUT: PhaseLeft, PhaseRight, (opdLeftState, opdRightState) */ + } + + return err; +} + +/******************************************************************************* + Functionname: param2UMX_PS_Core + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +static void param2UMX_PS_Core__FDK( + const SCHAR cld[MAX_PARAMETER_BANDS], const SCHAR icc[MAX_PARAMETER_BANDS], + const int numOttBands, const int resBands, + FIXP_DBL H11[MAX_PARAMETER_BANDS], FIXP_DBL H12[MAX_PARAMETER_BANDS], + FIXP_DBL H21[MAX_PARAMETER_BANDS], FIXP_DBL H22[MAX_PARAMETER_BANDS], + FIXP_DBL c_l[MAX_PARAMETER_BANDS], FIXP_DBL c_r[MAX_PARAMETER_BANDS]) { + int band; + + if ((c_l != NULL) && (c_r != NULL)) { + for (band = 0; band < numOttBands; band++) { + SpatialDequantGetCLDValues(cld[band], &c_l[band], &c_r[band]); + } + } + + band = 0; + FDK_ASSERT(resBands == 0); + for (; band < numOttBands; band++) { + /* compute mixing variables: */ + const int idx1 = cld[band]; + const int idx2 = icc[band]; + H11[band] = FX_CFG2FX_DBL(H11_nc[idx1][idx2]); + H21[band] = FX_CFG2FX_DBL(H11_nc[30 - idx1][idx2]); + H12[band] = FX_CFG2FX_DBL(H12_nc[idx1][idx2]); + H22[band] = FX_CFG2FX_DBL(-H12_nc[30 - idx1][idx2]); + } +} + +/******************************************************************************* + Functionname: param2UMX_PS + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +static void param2UMX_PS__FDK(spatialDec* self, + FIXP_DBL H11[MAX_PARAMETER_BANDS], + FIXP_DBL H12[MAX_PARAMETER_BANDS], + FIXP_DBL H21[MAX_PARAMETER_BANDS], + FIXP_DBL H22[MAX_PARAMETER_BANDS], + FIXP_DBL c_l[MAX_PARAMETER_BANDS], + FIXP_DBL c_r[MAX_PARAMETER_BANDS], int ottBoxIndx, + int parameterSetIndx, int residualBands) { + int band; + param2UMX_PS_Core__FDK(self->ottCLD__FDK[ottBoxIndx][parameterSetIndx], + self->ottICC__FDK[ottBoxIndx][parameterSetIndx], + self->numOttBands[ottBoxIndx], residualBands, H11, H12, + H21, H22, c_l, c_r); + + for (band = self->numOttBands[ottBoxIndx]; band < self->numParameterBands; + band++) { + H11[band] = H21[band] = H12[band] = H22[band] = FL2FXCONST_DBL(0.f); + } +} + +#define N_CLD (31) +#define N_IPD (16) + +static const FIXP_DBL sinIpd_tab[N_IPD] = { + FIXP_DBL(0x00000000), FIXP_DBL(0x30fbc54e), FIXP_DBL(0x5a827999), + FIXP_DBL(0x7641af3d), FIXP_DBL(0x7fffffff), FIXP_DBL(0x7641af3d), + FIXP_DBL(0x5a82799a), FIXP_DBL(0x30fbc54d), FIXP_DBL(0xffffffff), + FIXP_DBL(0xcf043ab3), FIXP_DBL(0xa57d8666), FIXP_DBL(0x89be50c3), + FIXP_DBL(0x80000000), FIXP_DBL(0x89be50c3), FIXP_DBL(0xa57d8666), + FIXP_DBL(0xcf043ab2), +}; + +/* cosIpd[i] = sinIpd[(i+4)&15] */ +#define SIN_IPD(a) (sinIpd_tab[(a)]) +#define COS_IPD(a) (sinIpd_tab[((a) + 4) & 15]) //(cosIpd_tab[(a)]) + +static const FIXP_SGL sqrt_one_minus_ICC2[8] = { + FL2FXCONST_SGL(0.0f), + FL2FXCONST_SGL(0.349329357483736f), + FL2FXCONST_SGL(0.540755219669676f), + FL2FXCONST_SGL(0.799309172723546f), + FL2FXCONST_SGL(0.929968187843004f), + FX_DBL2FXCONST_SGL(MAXVAL_DBL), + FL2FXCONST_SGL(0.80813303360276f), + FL2FXCONST_SGL(0.141067359796659f), +}; + +/* exponent of sqrt(CLD) */ +static const SCHAR sqrt_CLD_e[N_CLD] = { + -24, -7, -6, -5, -4, -4, -3, -3, -2, -2, -1, -1, 0, 0, 0, 1, + 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 25}; + +static const FIXP_DBL sqrt_CLD_m[N_CLD] = { + FL2FXCONST_DBL(0.530542153566195f), + FL2FXCONST_DBL(0.719796896243647f), + FL2FXCONST_DBL(0.64f), + FL2FXCONST_DBL(0.569049411212455f), + FL2FXCONST_DBL(0.505964425626941f), + FL2FXCONST_DBL(0.899746120304559f), + FL2FXCONST_DBL(0.635462587779425f), + FL2FXCONST_DBL(0.897614763441571f), + FL2FXCONST_DBL(0.633957276984445f), + FL2FXCONST_DBL(0.895488455427336f), + FL2FXCONST_DBL(0.632455532033676f), + FL2FXCONST_DBL(0.796214341106995f), + FL2FXCONST_DBL(0.501187233627272f), + FL2FXCONST_DBL(0.630957344480193f), + FL2FXCONST_DBL(0.794328234724281f), + FL2FXCONST_DBL(0.5f), + FL2FXCONST_DBL(0.629462705897084f), + FL2FXCONST_DBL(0.792446596230557f), + FL2FXCONST_DBL(0.99763115748444f), + FL2FXCONST_DBL(0.627971607877395f), + FL2FXCONST_DBL(0.790569415042095f), + FL2FXCONST_DBL(0.558354490188704f), + FL2FXCONST_DBL(0.788696680600242f), + FL2FXCONST_DBL(0.557031836333591f), + FL2FXCONST_DBL(0.786828382371355f), + FL2FXCONST_DBL(0.555712315637163f), + FL2FXCONST_DBL(0.988211768802619f), + FL2FXCONST_DBL(0.87865832060992f), + FL2FXCONST_DBL(0.78125f), + FL2FXCONST_DBL(0.694640394546454f), + FL2FXCONST_DBL(0.942432183077448f), +}; + +static const FIXP_DBL CLD_m[N_CLD] = { + FL2FXCONST_DBL(0.281474976710656f), + FL2FXCONST_DBL(0.518107571841987f), + FL2FXCONST_DBL(0.4096f), + FL2FXCONST_DBL(0.323817232401242f), + FL2FXCONST_DBL(0.256f), + FL2FXCONST_DBL(0.809543081003105f), + FL2FXCONST_DBL(0.403812700467324f), + FL2FXCONST_DBL(0.805712263548267f), + FL2FXCONST_DBL(0.401901829041533f), + FL2FXCONST_DBL(0.801899573803636f), + FL2FXCONST_DBL(0.4f), + FL2FXCONST_DBL(0.633957276984445f), + FL2FXCONST_DBL(0.251188643150958f), + FL2FXCONST_DBL(0.398107170553497f), + FL2FXCONST_DBL(0.630957344480193f), + FL2FXCONST_DBL(0.25f), + FL2FXCONST_DBL(0.396223298115278f), + FL2FXCONST_DBL(0.627971607877395f), + FL2FXCONST_DBL(0.995267926383743f), + FL2FXCONST_DBL(0.394348340300121f), + FL2FXCONST_DBL(0.625f), + FL2FXCONST_DBL(0.311759736713887f), + FL2FXCONST_DBL(0.62204245398984f), + FL2FXCONST_DBL(0.310284466689172f), + FL2FXCONST_DBL(0.619098903305123f), + FL2FXCONST_DBL(0.308816177750818f), + FL2FXCONST_DBL(0.9765625f), + FL2FXCONST_DBL(0.772040444377046f), + FL2FXCONST_DBL(0.6103515625f), + FL2FXCONST_DBL(0.482525277735654f), + FL2FXCONST_DBL(0.888178419700125), +}; + +static FIXP_DBL dequantIPD_CLD_ICC_splitAngle__FDK_Function(INT ipdIdx, + INT cldIdx, + INT iccIdx) { + FIXP_DBL cld; + SpatialDequantGetCLD2Values(cldIdx, &cld); + + /*const FIXP_DBL one_m = (FIXP_DBL)MAXVAL_DBL; + const int one_e = 0;*/ + const FIXP_DBL one_m = FL2FXCONST_DBL(0.5f); + const int one_e = 1; + /* iidLin = sqrt(cld); */ + FIXP_DBL iidLin_m = sqrt_CLD_m[cldIdx]; + int iidLin_e = sqrt_CLD_e[cldIdx]; + /* iidLin2 = cld; */ + FIXP_DBL iidLin2_m = CLD_m[cldIdx]; + int iidLin2_e = sqrt_CLD_e[cldIdx] << 1; + /* iidLin21 = iidLin2 + 1.0f; */ + int iidLin21_e; + FIXP_DBL iidLin21_m = + fAddNorm(iidLin2_m, iidLin2_e, one_m, one_e, &iidLin21_e); + /* iidIcc2 = iidLin * icc * 2.0f; */ + FIXP_CFG icc = dequantICC__FDK[iccIdx]; + FIXP_DBL temp1_m, temp1c_m; + int temp1_e, temp1c_e; + temp1_m = fMult(iidLin_m, icc); + temp1_e = iidLin_e + 1; + + FIXP_DBL cosIpd, sinIpd; + cosIpd = COS_IPD(ipdIdx); + sinIpd = SIN_IPD(ipdIdx); + + temp1c_m = fMult(temp1_m, cosIpd); + temp1c_e = temp1_e; //+cosIpd_e; + + int temp2_e, temp3_e, inv_temp3_e, ratio_e; + FIXP_DBL temp2_m = + fAddNorm(iidLin21_m, iidLin21_e, temp1c_m, temp1c_e, &temp2_e); + FIXP_DBL temp3_m = + fAddNorm(iidLin21_m, iidLin21_e, temp1_m, temp1_e, &temp3_e); + /* calculate 1/temp3 needed later */ + inv_temp3_e = temp3_e; + FIXP_DBL inv_temp3_m = invFixp(temp3_m, &inv_temp3_e); + FIXP_DBL ratio_m = + fAddNorm(fMult(inv_temp3_m, temp2_m), (inv_temp3_e + temp2_e), + FL2FXCONST_DBL(1e-9f), 0, &ratio_e); + + int weight2_e, tempb_atan2_e; + FIXP_DBL weight2_m = + fPow(ratio_m, ratio_e, FL2FXCONST_DBL(0.5f), -1, &weight2_e); + /* atan2(w2*sinIpd, w1*iidLin + w2*cosIpd) = atan2(w2*sinIpd, (2 - w2)*iidLin + * + w2*cosIpd) = atan2(w2*sinIpd, 2*iidLin + w2*(cosIpd - iidLin)); */ + /* tmpa_atan2 = w2*sinIpd; tmpb_atan2 = 2*iidLin + w2*(cosIpd - iidLin); */ + FIXP_DBL tempb_atan2_m = iidLin_m; + tempb_atan2_e = iidLin_e + 1; + int add_tmp1_e = 0; + FIXP_DBL add_tmp1_m = fAddNorm(cosIpd, 0, -iidLin_m, iidLin_e, &add_tmp1_e); + FIXP_DBL add_tmp2_m = fMult(add_tmp1_m, weight2_m); + int add_tmp2_e = add_tmp1_e + weight2_e; + tempb_atan2_m = fAddNorm(tempb_atan2_m, tempb_atan2_e, add_tmp2_m, add_tmp2_e, + &tempb_atan2_e); + + FIXP_DBL tempa_atan2_m = fMult(weight2_m, sinIpd); + int tempa_atan2_e = weight2_e; // + sinIpd_e; + + if (tempa_atan2_e > tempb_atan2_e) { + tempb_atan2_m = (tempb_atan2_m >> (tempa_atan2_e - tempb_atan2_e)); + tempb_atan2_e = tempa_atan2_e; + } else if (tempb_atan2_e > tempa_atan2_e) { + tempa_atan2_m = (tempa_atan2_m >> (tempb_atan2_e - tempa_atan2_e)); + } + + return fixp_atan2(tempa_atan2_m, tempb_atan2_m); +} + +static void calculateOpd(spatialDec* self, INT ottBoxIndx, INT parameterSetIndx, + FIXP_DBL opd[MAX_PARAMETER_BANDS]) { + INT band; + + for (band = 0; band < self->numOttBandsIPD; band++) { + INT idxCld = self->ottCLD__FDK[ottBoxIndx][parameterSetIndx][band]; + INT idxIpd = self->ottIPD__FDK[ottBoxIndx][parameterSetIndx][band]; + INT idxIcc = self->ottICC__FDK[ottBoxIndx][parameterSetIndx][band]; + FIXP_DBL cld, ipd; + + ipd = FX_CFG2FX_DBL(dequantIPD__FDK[idxIpd]); + + SpatialDequantGetCLD2Values(idxCld, &cld); + + /* ipd(idxIpd==8) == PI */ + if ((cld == FL2FXCONST_DBL(0.0f)) && (idxIpd == 8)) { + opd[2 * band] = FL2FXCONST_DBL(0.0f); + } else { + opd[2 * band] = (dequantIPD_CLD_ICC_splitAngle__FDK_Function( + idxIpd, idxCld, idxIcc) >> + (IPD_SCALE - AT2O_SF)); + } + opd[2 * band + 1] = opd[2 * band] - ipd; + } +} + +/* wrap phase in rad to the range of 0 <= x < 2*pi */ +static FIXP_DBL wrapPhase(FIXP_DBL phase) { + while (phase < (FIXP_DBL)0) phase += PIx2__IPD; + while (phase >= PIx2__IPD) phase -= PIx2__IPD; + FDK_ASSERT((phase >= (FIXP_DBL)0) && (phase < PIx2__IPD)); + + return phase; +} + +/******************************************************************************* + Functionname: param2UMX_PS_IPD + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +static void param2UMX_PS_IPD_OPD__FDK( + spatialDec* self, const SPATIAL_BS_FRAME* frame, + FIXP_DBL H11[MAX_PARAMETER_BANDS], FIXP_DBL H12[MAX_PARAMETER_BANDS], + FIXP_DBL H21[MAX_PARAMETER_BANDS], FIXP_DBL H22[MAX_PARAMETER_BANDS], + FIXP_DBL c_l[MAX_PARAMETER_BANDS], FIXP_DBL c_r[MAX_PARAMETER_BANDS], + int ottBoxIndx, int parameterSetIndx, int residualBands) { + INT band; + FIXP_DBL opd[2 * MAX_PARAMETER_BANDS]; + INT numOttBands = self->numOttBands[ottBoxIndx]; + INT numIpdBands; + + numIpdBands = frame->phaseMode ? self->numOttBandsIPD : 0; + + FDK_ASSERT(self->residualCoding == 0); + + param2UMX_PS_Core__FDK(self->ottCLD__FDK[ottBoxIndx][parameterSetIndx], + self->ottICC__FDK[ottBoxIndx][parameterSetIndx], + self->numOttBands[ottBoxIndx], residualBands, H11, H12, + H21, H22, c_l, c_r); + + for (band = self->numOttBands[ottBoxIndx]; band < self->numParameterBands; + band++) { + H11[band] = H21[band] = H12[band] = H22[band] = FL2FXCONST_DBL(0.f); + } + + if (frame->phaseMode) { + calculateOpd(self, ottBoxIndx, parameterSetIndx, opd); + + for (band = 0; band < numIpdBands; band++) { + self->PhaseLeft__FDK[band] = wrapPhase(opd[2 * band]); + self->PhaseRight__FDK[band] = wrapPhase(opd[2 * band + 1]); + } + } + + for (band = numIpdBands; band < numOttBands; band++) { + self->PhaseLeft__FDK[band] = FL2FXCONST_DBL(0.0f); + self->PhaseRight__FDK[band] = FL2FXCONST_DBL(0.0f); + } +} + +FDK_INLINE void param2UMX_Prediction_Core__FDK( + FIXP_DBL* H11re, FIXP_DBL* H11im, FIXP_DBL* H12re, FIXP_DBL* H12im, + FIXP_DBL* H21re, FIXP_DBL* H21im, FIXP_DBL* H22re, FIXP_DBL* H22im, + int cldIdx, int iccIdx, int ipdIdx, int band, int numOttBandsIPD, + int resBands) { +#define MAX_WEIGHT (1.2f) + FDK_ASSERT((H12im == NULL) && (H22im == NULL)); /* always == 0 */ + + if ((band < numOttBandsIPD) && (cldIdx == 15) && (iccIdx == 0) && + (ipdIdx == 8)) { + const FIXP_DBL gain = + FL2FXCONST_DBL(0.5f / MAX_WEIGHT) >> SCALE_PARAM_M2_212_PRED; + + *H11re = gain; + if (band < resBands) { + *H21re = gain; + *H12re = gain; + *H22re = -gain; + } else { + *H21re = -gain; + *H12re = (FIXP_DBL)0; + *H22re = (FIXP_DBL)0; + } + if ((H11im != NULL) && + (H21im != NULL) /*&& (H12im!=NULL) && (H22im!=NULL)*/) { + *H11im = (FIXP_DBL)0; + *H21im = (FIXP_DBL)0; + /* *H12im = (FIXP_DBL)0; */ + /* *H22im = (FIXP_DBL)0; */ + } + } else { + const FIXP_DBL one_m = (FIXP_DBL)MAXVAL_DBL; + const int one_e = 0; + /* iidLin = sqrt(cld); */ + FIXP_DBL iidLin_m = sqrt_CLD_m[cldIdx]; + int iidLin_e = sqrt_CLD_e[cldIdx]; + /* iidLin2 = cld; */ + FIXP_DBL iidLin2_m = CLD_m[cldIdx]; + int iidLin2_e = sqrt_CLD_e[cldIdx] << 1; + /* iidLin21 = iidLin2 + 1.0f; */ + int iidLin21_e; + FIXP_DBL iidLin21_m = + fAddNorm(iidLin2_m, iidLin2_e, one_m, one_e, &iidLin21_e); + /* iidIcc2 = iidLin * icc * 2.0f; */ + FIXP_CFG icc = dequantICC__FDK[iccIdx]; + int iidIcc2_e = iidLin_e + 1; + FIXP_DBL iidIcc2_m = fMult(iidLin_m, icc); + FIXP_DBL temp_m, sqrt_temp_m, inv_temp_m, weight_m; + int temp_e, sqrt_temp_e, inv_temp_e, weight_e, scale; + FIXP_DBL cosIpd, sinIpd; + + cosIpd = COS_IPD((band < numOttBandsIPD) ? ipdIdx : 0); + sinIpd = SIN_IPD((band < numOttBandsIPD) ? ipdIdx : 0); + + /* temp = iidLin21 + iidIcc2 * cosIpd; */ + temp_m = fAddNorm(iidLin21_m, iidLin21_e, fMult(iidIcc2_m, cosIpd), + iidIcc2_e, &temp_e); + + /* calculate 1/temp needed later */ + inv_temp_e = temp_e; + inv_temp_m = invFixp(temp_m, &inv_temp_e); + + /* 1/weight = sqrt(temp) * 1/sqrt(iidLin21) */ + if (temp_e & 1) { + sqrt_temp_m = temp_m >> 1; + sqrt_temp_e = (temp_e + 1) >> 1; + } else { + sqrt_temp_m = temp_m; + sqrt_temp_e = temp_e >> 1; + } + sqrt_temp_m = sqrtFixp(sqrt_temp_m); + if (iidLin21_e & 1) { + iidLin21_e += 1; + iidLin21_m >>= 1; + } + /* weight_[m,e] is actually 1/weight in the next few lines */ + weight_m = invSqrtNorm2(iidLin21_m, &weight_e); + weight_e -= iidLin21_e >> 1; + weight_m = fMult(sqrt_temp_m, weight_m); + weight_e += sqrt_temp_e; + scale = fNorm(weight_m); + weight_m = scaleValue(weight_m, scale); + weight_e -= scale; + /* weight = 0.5 * max(1/weight, 1/maxWeight) */ + if ((weight_e < 0) || + ((weight_e == 0) && (weight_m < FL2FXCONST_DBL(1.f / MAX_WEIGHT)))) { + weight_m = FL2FXCONST_DBL(1.f / MAX_WEIGHT); + weight_e = 0; + } + weight_e -= 1; + + { + FIXP_DBL alphaRe_m, alphaIm_m, accu_m; + int alphaRe_e, alphaIm_e, accu_e; + /* alphaRe = (1.0f - iidLin2) / temp; */ + alphaRe_m = fAddNorm(one_m, one_e, -iidLin2_m, iidLin2_e, &alphaRe_e); + alphaRe_m = fMult(alphaRe_m, inv_temp_m); + alphaRe_e += inv_temp_e; + + /* H11re = weight - alphaRe * weight; */ + /* H21re = weight + alphaRe * weight; */ + accu_m = fMult(alphaRe_m, weight_m); + accu_e = alphaRe_e + weight_e; + { + int accu2_e; + FIXP_DBL accu2_m; + accu2_m = fAddNorm(weight_m, weight_e, -accu_m, accu_e, &accu2_e); + *H11re = scaleValue(accu2_m, accu2_e - SCALE_PARAM_M2_212_PRED); + accu2_m = fAddNorm(weight_m, weight_e, accu_m, accu_e, &accu2_e); + *H21re = scaleValue(accu2_m, accu2_e - SCALE_PARAM_M2_212_PRED); + } + + if ((H11im != NULL) && + (H21im != NULL) /*&& (H12im != NULL) && (H22im != NULL)*/) { + /* alphaIm = -iidIcc2 * sinIpd / temp; */ + alphaIm_m = fMult(-iidIcc2_m, sinIpd); + alphaIm_m = fMult(alphaIm_m, inv_temp_m); + alphaIm_e = iidIcc2_e + inv_temp_e; + /* H11im = -alphaIm * weight; */ + /* H21im = alphaIm * weight; */ + accu_m = fMult(alphaIm_m, weight_m); + accu_e = alphaIm_e + weight_e; + accu_m = scaleValue(accu_m, accu_e - SCALE_PARAM_M2_212_PRED); + *H11im = -accu_m; + *H21im = accu_m; + + /* *H12im = (FIXP_DBL)0; */ + /* *H22im = (FIXP_DBL)0; */ + } + } + if (band < resBands) { + FIXP_DBL weight = + scaleValue(weight_m, weight_e - SCALE_PARAM_M2_212_PRED); + *H12re = weight; + *H22re = -weight; + } else { + /* beta = 2.0f * iidLin * (float) sqrt(1.0f - icc * icc) * weight / temp; + */ + FIXP_DBL beta_m; + int beta_e; + beta_m = FX_SGL2FX_DBL(sqrt_one_minus_ICC2[iccIdx]); + beta_e = 1; /* multipication with 2.0f */ + beta_m = fMult(beta_m, weight_m); + beta_e += weight_e; + beta_m = fMult(beta_m, iidLin_m); + beta_e += iidLin_e; + beta_m = fMult(beta_m, inv_temp_m); + beta_e += inv_temp_e; + + beta_m = scaleValue(beta_m, beta_e - SCALE_PARAM_M2_212_PRED); + *H12re = beta_m; + *H22re = -beta_m; + } + } +} + +static void param2UMX_Prediction__FDK(spatialDec* self, FIXP_DBL* H11re, + FIXP_DBL* H11im, FIXP_DBL* H12re, + FIXP_DBL* H12im, FIXP_DBL* H21re, + FIXP_DBL* H21im, FIXP_DBL* H22re, + FIXP_DBL* H22im, int ottBoxIndx, + int parameterSetIndx, int resBands) { + int band; + FDK_ASSERT((H12im == NULL) && (H22im == NULL)); /* always == 0 */ + + for (band = 0; band < self->numParameterBands; band++) { + int cldIdx = self->ottCLD__FDK[ottBoxIndx][parameterSetIndx][band]; + int iccIdx = self->ottICC__FDK[ottBoxIndx][parameterSetIndx][band]; + int ipdIdx = self->ottIPD__FDK[ottBoxIndx][parameterSetIndx][band]; + + param2UMX_Prediction_Core__FDK( + &H11re[band], (H11im ? &H11im[band] : NULL), &H12re[band], NULL, + &H21re[band], (H21im ? &H21im[band] : NULL), &H22re[band], NULL, cldIdx, + iccIdx, ipdIdx, band, self->numOttBandsIPD, resBands); + } +} + +/******************************************************************************* + Functionname: initM1andM2 + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ + +SACDEC_ERROR initM1andM2(spatialDec* self, int initStatesFlag, + int configChanged) { + SACDEC_ERROR err = MPS_OK; + + self->bOverwriteM1M2prev = (configChanged && !initStatesFlag) ? 1 : 0; + + { self->numM2rows = self->numOutputChannels; } + + if (initStatesFlag) { + int i, j, k; + + for (i = 0; i < self->numM2rows; i++) { + for (j = 0; j < self->numVChannels; j++) { + for (k = 0; k < MAX_PARAMETER_BANDS; k++) { + self->M2Real__FDK[i][j][k] = FL2FXCONST_DBL(0); + self->M2RealPrev__FDK[i][j][k] = FL2FXCONST_DBL(0); + } + } + } + } + + return err; +} diff --git a/libSACdec/src/sac_calcM1andM2.h b/libSACdec/src/sac_calcM1andM2.h new file mode 100644 index 0000000..996238d --- /dev/null +++ b/libSACdec/src/sac_calcM1andM2.h @@ -0,0 +1,129 @@ +/* ----------------------------------------------------------------------------- +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 Dec M1 and M2 calculation + +*******************************************************************************/ + +/* sa_calcM1andM2.h */ + +#ifndef SAC_CALCM1ANDM2_H +#define SAC_CALCM1ANDM2_H + +#include "sac_dec.h" + +#define SCALE_PARAM_M1 3 + +/* Scaling of M2 matrix, but only for binaural upmix type. */ +#define SCALE_PARAM_CALC_M2 (3) +#define SCALE_PARAM_M2_515X (3) +#define SCALE_PARAM_M2_525 (SCALE_PARAM_M1 + HRG_SF + 1 - SCALE_PARAM_CALC_M2) +#define SCALE_PARAM_M2_212_PRED (3) +/* Scaling of spectral data after applying M2 matrix, but only for binaural + upmix type Scaling is compensated later in synthesis qmf filterbank */ +#define SCALE_DATA_APPLY_M2 (1) + +SACDEC_ERROR initM1andM2(spatialDec* self, int initStatesFlag, + int configChanged); + +int SpatialDecGetResidualIndex(spatialDec* self, int row); + +SACDEC_ERROR SpatialDecCalculateM1andM2(spatialDec* self, int ps, + const SPATIAL_BS_FRAME* frame); + +#endif /* SAC_CALCM1ANDM2_H */ 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; +} diff --git a/libSACdec/src/sac_dec.h b/libSACdec/src/sac_dec.h new file mode 100644 index 0000000..992acad --- /dev/null +++ b/libSACdec/src/sac_dec.h @@ -0,0 +1,539 @@ +/* ----------------------------------------------------------------------------- +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 structures + +*******************************************************************************/ + +#ifndef SAC_DEC_H +#define SAC_DEC_H + +#include "common_fix.h" + +#include "sac_dec_interface.h" /* library interface in ../include */ + +#include "FDK_qmf_domain.h" +#include "sac_qmf.h" +#include "FDK_bitstream.h" /* mp4 bitbuffer */ +#include "sac_calcM1andM2.h" +#include "FDK_hybrid.h" +#include "FDK_decorrelate.h" +#include "sac_reshapeBBEnv.h" + +#include "sac_dec_conceal.h" + +#include "sac_tsd.h" + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#define ICCdefault 0 +#define IPDdefault 0 +#define arbdmxGainDefault 0 +#define CPCdefault 10 +#define tttCLD1default 15 +#define tttCLD2default 0 + +#define IS_HQ_ONLY(aot) \ + ((aot) == AOT_ER_AAC_LD || (aot) == AOT_ER_AAC_ELD || (aot) == AOT_USAC || \ + (aot) == AOT_RSVD50) + +#define SCONST(x) FL2FXCONST_DBL(x) + +#define PC_NUM_BANDS (8) +#define PC_NUM_HYB_BANDS (PC_NUM_BANDS - 3 + 10) +#define ABS_THR (1e-9f * 32768 * 32768) + +#define MAX_HYBRID_BANDS (MAX_NUM_QMF_BANDS - 3 + 10) +#define HYBRID_FILTER_DELAY (6) + +#define MAX_RESIDUAL_FRAMES (4) +#define MAX_RESIDUAL_BISTREAM \ + (836) /* 48000 bps * 3 res / (8 * 44100 / 2048 ) */ +#define MAX_MDCT_COEFFS (1024) +#define SACDEC_RESIDUAL_BS_BUF_SIZE \ + (1024) /* used to setup and check residual bitstream buffer */ + +#define MAX_NUM_PARAMS (MAX_NUM_OTT + 4 * MAX_NUM_TTT + MAX_INPUT_CHANNELS) +#define MAX_NUM_PARAMETERS (MAX(MAX_NUM_PARAMS, MAX_NUM_OTT)) + +#define MAX_PARAMETER_SETS (9) + +#define MAX_M2_INPUT (MAX_OUTPUT_CHANNELS) /* 3 direct + 5 diffuse */ + +#define MAX_QMF_BANDS_TO_HYBRID \ + (3) /* 3 bands are filtered again in "40 bands" case */ +#define PROTO_LEN (13) +#define BUFFER_LEN_LF (PROTO_LEN) +#define BUFFER_LEN_HF ((PROTO_LEN - 1) / 2) + +#define MAX_NO_DECORR_CHANNELS (MAX_OUTPUT_CHANNELS) +#define HRTF_AZIMUTHS (5) + +#define MAX_NUM_OTT_AT 0 + +/* left out */ + +typedef enum { + UPMIXTYPE_BYPASS = -1, /*just bypass the input channels without processing*/ + UPMIXTYPE_NORMAL = 0 /*multichannel loudspeaker upmix with spatial data*/ +} UPMIXTYPE; + +static inline int isTwoChMode(UPMIXTYPE upmixType) { + int retval = 0; + return retval; +} + + /* left out end */ + +#define MPEGS_BYPASSMODE (0x00000001) +#define MPEGS_CONCEAL (0x00000002) + +typedef struct STP_DEC *HANDLE_STP_DEC; + +typedef struct { + SCHAR bsQuantCoarseXXXprev; + SCHAR bsQuantCoarseXXXprevParse; +} LOSSLESSSTATE; + +typedef struct { + SCHAR bsXXXDataMode[MAX_PARAMETER_SETS]; + SCHAR bsQuantCoarseXXX[MAX_PARAMETER_SETS]; + SCHAR bsFreqResStrideXXX[MAX_PARAMETER_SETS]; + SCHAR nocmpQuantCoarseXXX[MAX_PARAMETER_SETS]; + LOSSLESSSTATE *state; /* Link to persistent state information */ +} LOSSLESSDATA; + +struct SPATIAL_BS_FRAME_struct { + UCHAR bsIndependencyFlag; + UCHAR newBsData; + UCHAR numParameterSets; + + /* + If bsFramingType == 0, then the paramSlot[ps] for 0 <= ps < numParamSets is + calculated as follows: paramSlot[ps] = ceil(numSlots*(ps+1)/numParamSets) - 1 + Otherwise, it is + paramSlot[ps] = bsParamSlot[ps] + */ + INT paramSlot[MAX_PARAMETER_SETS]; + + /* These arrays contain the compact indices, only one value per pbstride, only + * paramsets actually containing data. */ + /* These values are written from the parser in ecDataDec() and read during + * decode in mapIndexData() */ + SCHAR cmpOttCLDidx[MAX_NUM_OTT + MAX_NUM_OTT_AT][MAX_PARAMETER_SETS] + [MAX_PARAMETER_BANDS]; + SCHAR cmpOttICCidx[MAX_NUM_OTT][MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS]; + + /* Smoothing */ + UCHAR bsSmoothMode[MAX_PARAMETER_SETS]; + UCHAR bsSmoothTime[MAX_PARAMETER_SETS]; + UCHAR bsFreqResStrideSmg[MAX_PARAMETER_SETS]; + UCHAR bsSmgData[MAX_PARAMETER_SETS] + [MAX_PARAMETER_BANDS]; /* smoothing flags, one if band is + smoothed, otherwise zero */ + + /* Arbitrary Downmix */ + SCHAR (*cmpArbdmxGainIdx)[MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS]; + + /* Lossless control */ + LOSSLESSDATA *CLDLosslessData; + LOSSLESSDATA *ICCLosslessData; + /* LOSSLESSDATA *ADGLosslessData; -> is stored in CLDLosslessData[offset] */ + + LOSSLESSDATA *IPDLosslessData; + SCHAR (*cmpOttIPDidx)[MAX_PARAMETER_SETS][MAX_PARAMETER_BANDS]; + int phaseMode; + int OpdSmoothingMode; + + UCHAR tempShapeEnableChannelGES[MAX_OUTPUT_CHANNELS]; /*!< GES side info. */ + UCHAR bsEnvShapeData[MAX_OUTPUT_CHANNELS] + [MAX_TIME_SLOTS]; /*!< GES side info (quantized). */ + + UCHAR tempShapeEnableChannelSTP[MAX_OUTPUT_CHANNELS]; /*!< STP side info. */ + + TSD_DATA TsdData[1]; /*!< TSD data structure. */ +}; + +typedef struct { + /* Lossless state */ + LOSSLESSSTATE CLDLosslessState[MAX_NUM_PARAMETERS]; + LOSSLESSSTATE ICCLosslessState[MAX_NUM_PARAMETERS]; + LOSSLESSSTATE IPDLosslessState[MAX_NUM_PARAMETERS]; +} BS_LL_STATE; + +typedef struct { + int prevParamSlot; + int prevSmgTime; + UCHAR prevSmgData[MAX_PARAMETER_BANDS]; + + FIXP_DBL opdLeftState__FDK[MAX_PARAMETER_BANDS]; + FIXP_DBL opdRightState__FDK[MAX_PARAMETER_BANDS]; + +} SMOOTHING_STATE; + +typedef struct { + FIXP_DBL alpha__FDK; + FIXP_DBL beta__FDK; + FIXP_DBL partNrgPrev__FDK[2 * MAX_OUTPUT_CHANNELS + MAX_INPUT_CHANNELS] + [BB_ENV_SIZE]; + FIXP_DBL normNrgPrev__FDK[2 * MAX_OUTPUT_CHANNELS + MAX_INPUT_CHANNELS]; + FIXP_DBL frameNrgPrev__FDK[2 * MAX_OUTPUT_CHANNELS + MAX_INPUT_CHANNELS]; + INT partNrgPrevSF[2 * MAX_OUTPUT_CHANNELS + MAX_INPUT_CHANNELS]; + INT partNrgPrev2SF[2 * MAX_OUTPUT_CHANNELS + MAX_INPUT_CHANNELS]; + INT normNrgPrevSF[2 * MAX_OUTPUT_CHANNELS + MAX_INPUT_CHANNELS]; + INT frameNrgPrevSF[2 * MAX_OUTPUT_CHANNELS + MAX_INPUT_CHANNELS]; +} RESHAPE_BBENV_STATE; + +typedef struct { + int maxNumInputChannels; + int maxNumOutputChannels; + int maxNumQmfBands; + int maxNumHybridBands; + int maxNumXChannels; + int maxNumVChannels; + int maxNumDecorChannels; + int maxNumCmplxQmfBands; + int maxNumCmplxHybBands; + int maxNumResChannels; + int bProcResidual; /* process residual */ + int maxNumResidualChannels; + int maxNumOttBoxes; + int maxNumParams; + +} SACDEC_CREATION_PARAMS; + +struct spatialDec_struct { + SACDEC_ERROR + errInt; /* Field to store internal errors. + Will be clear at the very beginning of each process call. */ + int staticDecScale; /* static scale of decoder */ + + /* GENERAL */ + int samplingFreq; /* [Hz] */ + CFG_LEVEL decoderLevel; /* 0..5 */ + CFG_EXTENT decoderMode; + CFG_BINAURAL binauralMode; + + SACDEC_CREATION_PARAMS createParams; + + int numComplexProcessingBands; + + int treeConfig; /* TREE_5151 = 5151, TREE_5152 = 5152, TREE_525 = 525, defined + in sac_bitdec.h */ + + int numInputChannels; /* 1 (M) or 2 (L,R) */ + int numOutputChannels; /* 6 for 3/2.1 (FL,FR,FC,LF,BL,BR) */ + int numOttBoxes; /* number of ott boxes */ + int numM2rows; + + int numOutputChannelsAT; /* Number of output channels after arbitrary tree + processing */ + + int quantMode; /* QUANT_FINE, QUANT_EBQ1, QUANT_EBQ2, defined in sac_bitdec.h + */ + int arbitraryDownmix; /* (arbitraryDownmix != 0) 1 arbitrary downmix data + present, 2 arbitrary downmix residual data present*/ + int residualCoding; /* (residualCoding != 0) => residual coding data present + */ + UCHAR nrResidualFrame; + UCHAR nrArbDownmixResidualFrame; + FDK_BITSTREAM **hResidualBitstreams; + int tempShapeConfig; /* */ + int decorrType; /* Indicates to use PS or none PS decorrelator. */ + int decorrConfig; /* chosen decorrelator */ + int envQuantMode; /* quantization mode of envelope reshaping data */ + + FIXP_DBL clipProtectGain__FDK; /* global gain for upmix */ + char clipProtectGainSF__FDK; /* global gain for upmix */ + + /* Currently ignoring center decorr + numVChannels = numDirektSignals + numDecorSignals */ + int numDirektSignals; /* needed for W, Number of direkt signals 515 -> 1 525 + -> 3 */ + int wStartResidualIdx; /* Where to start read residuals for W, = 0 for 515, = + 1 for 525 since one residual is used in V */ + int numDecorSignals; /* needed for W, Number of residual and decorrelated + signals, = 2, 3 for center deccorelation*/ + int numVChannels; /* direct signals + decorelator signals */ + int numXChannels; /* direct input signals + TTT-residuals */ + + int timeSlots; /* length of spatial frame in QMF samples */ + int curTimeSlot; /* pointer to the current time slot used for hyperframing */ + int prevTimeSlot; /* */ + int curPs; + int frameLength; /* number of output waveform samples/channel/frame */ + UPMIXTYPE upmixType; + int partiallyComplex; + int useFDreverb; + + int bShareDelayWithSBR; + + int tp_hybBandBorder; /* Hybrid band indicating the HP filter cut-off. */ + + /* FREQUENCY MAPPING */ + int qmfBands; + int hybridBands; + const SCHAR *kernels; /* Mapping hybrid band to parameter band. */ + + int TsdTs; /**< TSD QMF slot counter 0<= ts < numSlots */ + + int *param2hyb; /* Mapping parameter bands to hybrid bands */ + int kernels_width[MAX_PARAMETER_BANDS]; /* Mapping parmeter band to hybrid + band offsets. */ + + /* Residual coding */ + int residualSamplingFreq; + UCHAR residualPresent[MAX_NUM_OTT + MAX_NUM_TTT]; + UCHAR residualBands[MAX_NUM_OTT + MAX_NUM_TTT]; /* 0, if no residual data + present for this box */ + UCHAR residualQMFBands[MAX_NUM_OTT + MAX_NUM_TTT]; /* needed for optimized + mdct2qmf calculation */ + SPATIAL_SPECIFIC_CONFIG *pConfigCurrent; + + int arbdmxFramesPerSpatialFrame; + int arbdmxUpdQMF; + + int numParameterBands; /* Number of parameter bands 40, 28, 20, 14, 10, ... + .*/ + int bitstreamParameterBands; + int *numOttBands; /* number of bands for each ott, is != numParameterBands for + LFEs */ + + /* 1 MAPPING */ + UCHAR extendFrame; + UCHAR numParameterSetsPrev; + + int *smgTime; + UCHAR **smgData; + + /* PARAMETER DATA decoded and dequantized */ + + /* Last parameters from prev frame required during decode in mapIndexData() + * and not touched during parse */ + SCHAR **ottCLDidxPrev; + SCHAR **ottICCidxPrev; + SCHAR **arbdmxGainIdxPrev; + SCHAR **ottIPDidxPrev; + SCHAR ***outIdxData; /* is this really persistent memory ? */ + + /* State mem required during parse in SpatialDecParseFrameData() */ + SCHAR **cmpOttCLDidxPrev; + SCHAR **cmpOttICCidxPrev; + SCHAR ***ottICCdiffidx; + SCHAR **cmpOttIPDidxPrev; + + /* State mem required in parseArbitraryDownmixData */ + SCHAR **cmpArbdmxGainIdxPrev; + + SCHAR ***ottCLD__FDK; + SCHAR ***ottICC__FDK; + + SCHAR ***arbdmxGain__FDK; /* Holds the artistic downmix correction index.*/ + + FIXP_DBL *arbdmxAlpha__FDK; + FIXP_DBL *arbdmxAlphaPrev__FDK; + + UCHAR stereoConfigIndex; + int highRateMode; + + int phaseCoding; + + SCHAR ***ottIPD__FDK; + + FIXP_DBL PhaseLeft__FDK[MAX_PARAMETER_BANDS]; + FIXP_DBL PhaseRight__FDK[MAX_PARAMETER_BANDS]; + FIXP_DBL PhasePrevLeft__FDK[MAX_PARAMETER_BANDS]; + FIXP_DBL PhasePrevRight__FDK[MAX_PARAMETER_BANDS]; + int numOttBandsIPD; + + /* GAIN MATRICIES FOR CURRENT and PREVIOUS PARMATER SET(s)*/ + FIXP_DBL ***M2Real__FDK; + FIXP_DBL ***M2Imag__FDK; + FIXP_DBL ***M2RealPrev__FDK; + FIXP_DBL ***M2ImagPrev__FDK; + + /* INPUT SIGNALS */ + FIXP_DBL ***qmfInputRealDelayBuffer__FDK; + FIXP_DBL ***qmfInputImagDelayBuffer__FDK; + + int pc_filterdelay; /* additional delay to align HQ with LP before hybird + analysis */ + int qmfInputDelayBufPos; + FIXP_DBL **qmfInputReal__FDK; + FIXP_DBL **qmfInputImag__FDK; + + FIXP_DBL **hybInputReal__FDK; + FIXP_DBL **hybInputImag__FDK; + + FIXP_DBL **binInputReverb; + + FIXP_DBL binGain, reverbGain; + FIXP_DBL binCenterGain, reverbCenterGain; + + /* RESIDUAL SIGNALS */ + + FIXP_DBL ***qmfResidualReal__FDK; + FIXP_DBL ***qmfResidualImag__FDK; + + FIXP_DBL **hybResidualReal__FDK; + FIXP_DBL **hybResidualImag__FDK; + + int qmfOutputRealDryDelayBufPos; + FIXP_DBL ***qmfOutputRealDryDelayBuffer__FDK; + FIXP_DBL ***qmfOutputImagDryFilterBuffer__FDK; + FIXP_DBL *qmfOutputImagDryFilterBufferBase__FDK; + + /* TEMPORARY SIGNALS */ + + FIXP_DBL **wReal__FDK; + FIXP_DBL **wImag__FDK; + + /* OUTPUT SIGNALS */ + FIXP_DBL **hybOutputRealDry__FDK; + FIXP_DBL **hybOutputImagDry__FDK; + FIXP_DBL **hybOutputRealWet__FDK; + FIXP_DBL **hybOutputImagWet__FDK; + PCM_MPS *timeOut__FDK; + + HANDLE_FDK_QMF_DOMAIN pQmfDomain; + + FDK_ANA_HYB_FILTER + *hybridAnalysis; /*!< pointer Analysis hybrid filterbank array. */ + FDK_SYN_HYB_FILTER + *hybridSynthesis; /*!< pointer Synthesis hybrid filterbank array. */ + FIXP_DBL ** + pHybridAnaStatesLFdmx; /*!< pointer to analysis hybrid filter states LF */ + FIXP_DBL ** + pHybridAnaStatesHFdmx; /*!< pointer to analysis hybrid filter states HF */ + FIXP_DBL ** + pHybridAnaStatesLFres; /*!< pointer to analysis hybrid filter states LF */ + FIXP_DBL ** + pHybridAnaStatesHFres; /*!< pointer to analysis hybrid filter states HF */ + + DECORR_DEC *apDecor; /*!< pointer decorrelator array. */ + FIXP_DBL **pDecorBufferCplx; + + SMOOTHING_STATE *smoothState; /*!< Pointer to smoothing states. */ + + RESHAPE_BBENV_STATE *reshapeBBEnvState; /*!< GES handle. */ + SCHAR row2channelDmxGES[MAX_OUTPUT_CHANNELS]; + + HANDLE_STP_DEC hStpDec; /*!< STP handle. */ + + const UCHAR *pActivM2ParamBands; + + int bOverwriteM1M2prev; /* Overwrite previous M2/M2 params with first set of + new frame after SSC change (aka + decodeAfterConfigHasChangedFlag). */ + SpatialDecConcealmentInfo concealInfo; +}; + +#define SACDEC_SYNTAX_MPS 1 +#define SACDEC_SYNTAX_USAC 2 +#define SACDEC_SYNTAX_RSVD50 4 +#define SACDEC_SYNTAX_L2 8 +#define SACDEC_SYNTAX_L3 16 +#define SACDEC_SYNTAX_LD 32 + +static inline int GetProcBand(spatialDec_struct *self, int qs) { + return self->kernels[qs]; +} + +#endif /* SAC_DEC_H */ diff --git a/libSACdec/src/sac_dec_conceal.cpp b/libSACdec/src/sac_dec_conceal.cpp new file mode 100644 index 0000000..dfeef7b --- /dev/null +++ b/libSACdec/src/sac_dec_conceal.cpp @@ -0,0 +1,392 @@ +/* ----------------------------------------------------------------------------- +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): Christian Ertel, Christian Griebel + + Description: SAC Dec error concealment + +*******************************************************************************/ + +#include "sac_dec_conceal.h" + +void SpatialDecConcealment_Init(SpatialDecConcealmentInfo *info, + const UINT resetFlags) { + FDK_ASSERT(info != NULL); + + if (resetFlags & MPEGS_CONCEAL_RESET_STATE) { + info->concealState = SpatialDecConcealState_Init; + /* Frame counters will be initialized implicitely in function + * SpatialDecConcealment_UpdateState(). */ + } + + if (resetFlags & MPEGS_CONCEAL_RESET_PARAMETER) { + /* Set default params */ + info->concealParams.method = MPEGS_CONCEAL_DEFAULT_METHOD; + info->concealParams.numKeepFrames = MPEGS_CONCEAL_DEFAULT_NUM_KEEP_FRAMES; + info->concealParams.numFadeOutFrames = + MPEGS_CONCEAL_DEFAULT_FADE_OUT_SLOPE_LENGTH; + info->concealParams.numFadeInFrames = + MPEGS_CONCEAL_DEFAULT_FADE_IN_SLOPE_LENGTH; + info->concealParams.numReleaseFrames = + MPEGS_CONCEAL_DEFAULT_NUM_RELEASE_FRAMES; + } + + return; +} + +int SpatialDecConcealment_Apply( + SpatialDecConcealmentInfo *info, + const SCHAR (*cmpIdxData)[MAX_PARAMETER_BANDS], SCHAR **diffIdxData, + SCHAR * + idxPrev, /* char + idxPrev[SPATIALDEC_MAX_NUM_OTT][SPATIALDEC_MAX_PARAMETER_BANDS], + */ + SCHAR *bsXXXDataMode, const int startBand, const int stopBand, + const SCHAR defaultValue, const int paramType, const int numParamSets) { + int appliedProcessing = 0; + int band, dataMode = -1; + + FDK_ASSERT(info != NULL); + FDK_ASSERT(cmpIdxData != NULL); + FDK_ASSERT(idxPrev != NULL); + FDK_ASSERT(bsXXXDataMode != NULL); + + /* Processing depends only on the internal state */ + switch (info->concealState) { + case SpatialDecConcealState_Init: + dataMode = 0; /* default */ + break; + + case SpatialDecConcealState_Ok: + /* Nothing to do */ + break; + + case SpatialDecConcealState_Keep: + dataMode = 1; /* keep */ + break; + + case SpatialDecConcealState_FadeToDefault: { + /* Start simple fade out */ + FIXP_DBL fac = fDivNorm(info->cntStateFrames + 1, + info->concealParams.numFadeOutFrames + 1); + + for (band = startBand; band < stopBand; band += 1) { + /* idxPrev = fac * defaultValue + (1-fac) * idxPrev; */ + idxPrev[band] = + fMultI(fac, defaultValue - idxPrev[band]) + idxPrev[band]; + } + dataMode = 1; /* keep */ + appliedProcessing = 1; + } break; + + case SpatialDecConcealState_Default: + for (band = startBand; band < stopBand; band += 1) { + idxPrev[band] = defaultValue; + } + dataMode = 1; /* keep */ + appliedProcessing = 1; + break; + + case SpatialDecConcealState_FadeFromDefault: { + FIXP_DBL fac = fDivNorm(info->cntValidFrames + 1, + info->concealParams.numFadeInFrames + 1); + + for (band = startBand; band < stopBand; band += 1) { + /* idxPrev = fac * cmpIdxData + (1-fac) * defaultValue; */ + idxPrev[band] = + fMultI(fac, cmpIdxData[numParamSets - 1][band] - defaultValue) + + defaultValue; + } + dataMode = 1; /* keep */ + appliedProcessing = 1; + } break; + + default: + FDK_ASSERT(0); /* All valid states shall be handled above. */ + break; + } + + if (dataMode >= 0) { + int i; + for (i = 0; i < numParamSets; i += 1) { + bsXXXDataMode[i] = dataMode; + if (diffIdxData != NULL) { + for (band = startBand; band < stopBand; band += 1) { + diffIdxData[i][band] = 0; + } + } + } + } + + return appliedProcessing; +} + +void SpatialDecConcealment_UpdateState(SpatialDecConcealmentInfo *info, + const int frameOk) { + FDK_ASSERT(info != NULL); + + if (frameOk) { + info->cntValidFrames += 1; + } else { + info->cntValidFrames = 0; + } + + switch (info->concealState) { + case SpatialDecConcealState_Init: + if (frameOk) { + /* NEXT STATE: Ok */ + info->concealState = SpatialDecConcealState_Ok; + info->cntStateFrames = 0; + } + break; + + case SpatialDecConcealState_Ok: + if (!frameOk) { + /* NEXT STATE: Keep */ + info->concealState = SpatialDecConcealState_Keep; + info->cntStateFrames = 0; + } + break; + + case SpatialDecConcealState_Keep: + info->cntStateFrames += 1; + if (frameOk) { + /* NEXT STATE: Ok */ + info->concealState = SpatialDecConcealState_Ok; + } else { + if (info->cntStateFrames >= info->concealParams.numKeepFrames) { + if (info->concealParams.numFadeOutFrames == 0) { + /* NEXT STATE: Default */ + info->concealState = SpatialDecConcealState_Default; + } else { + /* NEXT STATE: Fade to default */ + info->concealState = SpatialDecConcealState_FadeToDefault; + info->cntStateFrames = 0; + } + } + } + break; + + case SpatialDecConcealState_FadeToDefault: + info->cntStateFrames += 1; + if (info->cntValidFrames > 0) { + /* NEXT STATE: Fade in from default */ + info->concealState = SpatialDecConcealState_FadeFromDefault; + info->cntStateFrames = 0; + } else { + if (info->cntStateFrames >= info->concealParams.numFadeOutFrames) { + /* NEXT STATE: Default */ + info->concealState = SpatialDecConcealState_Default; + } + } + break; + + case SpatialDecConcealState_Default: + if (info->cntValidFrames > 0) { + if (info->concealParams.numFadeInFrames == 0) { + /* NEXT STATE: Ok */ + info->concealState = SpatialDecConcealState_Ok; + } else { + /* NEXT STATE: Fade in from default */ + info->concealState = SpatialDecConcealState_FadeFromDefault; + info->cntValidFrames = 0; + } + } + break; + + case SpatialDecConcealState_FadeFromDefault: + info->cntValidFrames += 1; + if (frameOk) { + if (info->cntValidFrames >= info->concealParams.numFadeInFrames) { + /* NEXT STATE: Ok */ + info->concealState = SpatialDecConcealState_Ok; + } + } else { + /* NEXT STATE: Fade to default */ + info->concealState = SpatialDecConcealState_FadeToDefault; + info->cntStateFrames = 0; + } + break; + + default: + FDK_ASSERT(0); /* All valid states should be handled above! */ + break; + } +} + +SACDEC_ERROR SpatialDecConcealment_SetParam(SpatialDecConcealmentInfo *self, + const SAC_DEC_CONCEAL_PARAM param, + const INT value) { + SACDEC_ERROR err = MPS_OK; + + switch (param) { + case SAC_DEC_CONCEAL_METHOD: + switch ((SpatialDecConcealmentMethod)value) { + case SAC_DEC_CONCEAL_WITH_ZERO_VALUED_OUTPUT: + case SAC_DEC_CONCEAL_BY_FADING_PARAMETERS: + break; + default: + err = MPS_INVALID_PARAMETER; + goto bail; + } + if (self != NULL) { + /* store parameter value */ + self->concealParams.method = (SpatialDecConcealmentMethod)value; + } else { + err = MPS_INVALID_HANDLE; + goto bail; + } + break; + case SAC_DEC_CONCEAL_NUM_KEEP_FRAMES: + if (value < 0) { + err = MPS_INVALID_PARAMETER; + goto bail; + } + if (self != NULL) { + /* store parameter value */ + self->concealParams.numKeepFrames = (UINT)value; + } else { + err = MPS_INVALID_HANDLE; + goto bail; + } + break; + case SAC_DEC_CONCEAL_FADE_OUT_SLOPE_LENGTH: + if (value < 0) { + err = MPS_INVALID_PARAMETER; + goto bail; + } + if (self != NULL) { + /* store parameter value */ + self->concealParams.numFadeOutFrames = (UINT)value; + } else { + err = MPS_INVALID_HANDLE; + goto bail; + } + break; + case SAC_DEC_CONCEAL_FADE_IN_SLOPE_LENGTH: + if (value < 0) { + err = MPS_INVALID_PARAMETER; + goto bail; + } + if (self != NULL) { + /* store parameter value */ + self->concealParams.numFadeInFrames = (UINT)value; + } else { + err = MPS_INVALID_HANDLE; + goto bail; + } + break; + case SAC_DEC_CONCEAL_NUM_RELEASE_FRAMES: + if (value < 0) { + err = MPS_INVALID_PARAMETER; + goto bail; + } + if (self != NULL) { + /* store parameter value */ + self->concealParams.numReleaseFrames = (UINT)value; + } else { + err = MPS_INVALID_HANDLE; + goto bail; + } + break; + default: + err = MPS_INVALID_PARAMETER; + goto bail; + } + +bail: + return err; +} diff --git a/libSACdec/src/sac_dec_conceal.h b/libSACdec/src/sac_dec_conceal.h new file mode 100644 index 0000000..27f5249 --- /dev/null +++ b/libSACdec/src/sac_dec_conceal.h @@ -0,0 +1,187 @@ +/* ----------------------------------------------------------------------------- +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): Christian Ertel, Christian Griebel + + Description: SAC Dec error concealment + +*******************************************************************************/ + +#ifndef SAC_DEC_CONCEAL_H +#define SAC_DEC_CONCEAL_H + +#include "sac_dec_interface.h" + +/* Modules dynamic parameters: */ +typedef enum { + SAC_DEC_CONCEAL_METHOD = 0, + SAC_DEC_CONCEAL_NUM_KEEP_FRAMES, + SAC_DEC_CONCEAL_FADE_OUT_SLOPE_LENGTH, + SAC_DEC_CONCEAL_FADE_IN_SLOPE_LENGTH, + SAC_DEC_CONCEAL_NUM_RELEASE_FRAMES + +} SAC_DEC_CONCEAL_PARAM; + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* sac_dec_interface.h */ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ +typedef enum { + SAC_DEC_CONCEAL_WITH_ZERO_VALUED_OUTPUT = 0, + SAC_DEC_CONCEAL_BY_FADING_PARAMETERS = 1 + +} SpatialDecConcealmentMethod; +/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* Default dynamic parameter values: */ +#define MPEGS_CONCEAL_DEFAULT_METHOD SAC_DEC_CONCEAL_BY_FADING_PARAMETERS +#define MPEGS_CONCEAL_DEFAULT_NUM_KEEP_FRAMES (10) +#define MPEGS_CONCEAL_DEFAULT_FADE_OUT_SLOPE_LENGTH (5) +#define MPEGS_CONCEAL_DEFAULT_FADE_IN_SLOPE_LENGTH (5) +#define MPEGS_CONCEAL_DEFAULT_NUM_RELEASE_FRAMES (3) + +typedef enum { + SpatialDecConcealState_Init = 0, + SpatialDecConcealState_Ok, + SpatialDecConcealState_Keep, + SpatialDecConcealState_FadeToDefault, + SpatialDecConcealState_Default, + SpatialDecConcealState_FadeFromDefault + +} SpatialDecConcealmentState; + +typedef struct { + SpatialDecConcealmentMethod method; + + UINT numKeepFrames; + UINT numFadeOutFrames; + UINT numFadeInFrames; + UINT numReleaseFrames; + +} SpatialDecConcealmentParams; + +typedef struct { + SpatialDecConcealmentParams concealParams; /* User set params */ + SpatialDecConcealmentState + concealState; /* State of internal state machine (fade-in/out etc) */ + + UINT cntStateFrames; /* Counter for fade-in/out handling */ + UINT cntValidFrames; /* Counter for the number of consecutive good frames*/ + +} SpatialDecConcealmentInfo; + +/* Module reset flags */ +#define MPEGS_CONCEAL_RESET_STATE (0x01) +#define MPEGS_CONCEAL_RESET_PARAMETER (0x02) +#define MPEGS_CONCEAL_RESET_ALL (0xFF) + +void SpatialDecConcealment_Init(SpatialDecConcealmentInfo *info, + const UINT resetFlags); + +int SpatialDecConcealment_Apply(SpatialDecConcealmentInfo *info, + const SCHAR (*cmpIdxData)[MAX_PARAMETER_BANDS], + SCHAR **diffIdxData, SCHAR *idxPrev, + SCHAR *bsXXXDataMode, const int startBand, + const int stopBand, const SCHAR defaultValue, + const int paramType, const int numParamSets); + +void SpatialDecConcealment_UpdateState(SpatialDecConcealmentInfo *info, + const int frameOk); + +SACDEC_ERROR SpatialDecConcealment_SetParam(SpatialDecConcealmentInfo *info, + const SAC_DEC_CONCEAL_PARAM param, + const INT value); + +#endif /* SAC_DEC_CONCEAL_H */ diff --git a/libSACdec/src/sac_dec_interface.h b/libSACdec/src/sac_dec_interface.h new file mode 100644 index 0000000..a2eea92 --- /dev/null +++ b/libSACdec/src/sac_dec_interface.h @@ -0,0 +1,335 @@ +/* ----------------------------------------------------------------------------- +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 Interface + +*******************************************************************************/ + +#ifndef SAC_DEC_INTERFACE_H +#define SAC_DEC_INTERFACE_H + +#include "common_fix.h" +#include "FDK_audio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sac_dec_errorcodes.h" +#include "sac_dec_ssc_struct.h" + +/** + * \brief Baseline MPEG-Surround profile Level 1-5. + */ +typedef enum { + DECODER_LEVEL_0 = 0, /*!< Level 0: dummy level; 212 only */ + DECODER_LEVEL_6 = 6 /*!< Level 6: no support */ +} CFG_LEVEL; + +/* + * \brief Number of output channels restriction. + */ +typedef enum { + OUTPUT_CHANNELS_DEFAULT, /*!< Default configuration depending on Decoder Level + */ + OUTPUT_CHANNELS_2_0, /*!< Limitation to stereo output */ + OUTPUT_CHANNELS_5_1 /*!< Limitation to 5.1 output */ +} CFG_RESTRICTION; + +/* + * \brief Supported decoder mode. + */ +typedef enum { + EXT_HQ_ONLY = 0, /*!< High Quality processing only */ + EXT_LP_ONLY = 1, /*!< Low Power procesing only */ + EXT_HQ_AND_LP = 2 /*!< Support both HQ and LP processing */ +} CFG_EXTENT; + +/* + * \brief Supported binaural mode. + */ +typedef enum { + BINAURAL_NONE = -1 /*!< No binaural procesing supported */ +} CFG_BINAURAL; + +/** + * \brief Decoder configuration structure. + * + * These structure contains all parameters necessary for decoder open function. + * The configuration specifies the functional range of the decoder instance. + */ +typedef struct { + CFG_LEVEL decoderLevel; + CFG_EXTENT decoderMode; + CFG_RESTRICTION maxNumOutputChannels; + CFG_BINAURAL binauralMode; + +} SPATIAL_DEC_CONFIG; + +typedef enum { + INPUTMODE_QMF = 1000, + INPUTMODE_QMF_SBR = 1001, + INPUTMODE_TIME = 1002 +} SPATIALDEC_INPUT_MODE; + +/** + * \brief MPEG Surround upmix type mode. + **/ +typedef enum { + UPMIX_TYPE_BYPASS = + -1, /*!< Bypass the downmix channels from the core decoder. */ + UPMIX_TYPE_NORMAL = 0 /*!< Multi channel output. */ + +} SPATIAL_DEC_UPMIX_TYPE; + +/** + * \brief Dynamic decoder parameters. + */ +typedef struct { + /* Basics */ + UCHAR outputMode; + UCHAR blindEnable; + UCHAR bypassMode; + + /* Error concealment */ + UCHAR concealMethod; + UINT concealNumKeepFrames; + UINT concealFadeOutSlopeLength; + UINT concealFadeInSlopeLength; + UINT concealNumReleaseFrames; + +} SPATIALDEC_PARAM; + +/** + * \brief Flags which control the initialization + **/ +typedef enum { + MPEGS_INIT_NONE = 0x00000000, /*!< Indicates no initialization */ + + MPEGS_INIT_CONFIG = 0x00000010, /*!< Indicates a configuration change due to + SSC value changes */ + + MPEGS_INIT_STATES_ANA_QMF_FILTER = + 0x00000100, /*!< Controls the initialization of the analysis qmf filter + states */ + MPEGS_INIT_STATES_SYN_QMF_FILTER = + 0x00000200, /*!< Controls the initialization of the synthesis qmf filter + states */ + MPEGS_INIT_STATES_ANA_HYB_FILTER = 0x00000400, /*!< Controls the + initialization of the + analysis hybrid filter + states */ + MPEGS_INIT_STATES_DECORRELATOR = + 0x00000800, /*!< Controls the initialization of the decorrelator states */ + MPEGS_INIT_STATES_M1M2 = 0x00002000, /*!< Controls the initialization of the + history in m1 and m2 parameter + calculation */ + MPEGS_INIT_STATES_GES = 0x00004000, /*!< Controls the initialization of the + history in the ges calculation */ + MPEGS_INIT_STATES_REVERB = + 0x00008000, /*!< Controls the initialization of the reverb states */ + MPEGS_INIT_STATES_PARAM = + 0x00020000, /*!< Controls the initialization of the history of all other + parameter */ + MPEGS_INIT_STATES_ERROR_CONCEALMENT = + 0x00080000, /*!< Controls the initialization of the error concealment + module state */ + MPEGS_INIT_PARAMS_ERROR_CONCEALMENT = 0x00200000 /*!< Controls the + initialization of the + whole error concealment + parameter set */ + +} MPEGS_INIT_CTRL_FLAGS; + +#define MASK_MPEGS_INIT_ALL_STATES (0x000FFF00) +#define MASK_MPEGS_INIT_ALL_PARAMS (0x00F00000) + +typedef struct spatialDec_struct spatialDec, *HANDLE_SPATIAL_DEC; + +typedef struct SPATIAL_BS_FRAME_struct SPATIAL_BS_FRAME; + +typedef struct { + UINT sizePersistent; /* persistent memory */ + UINT sizeFastPersistent; /* fast persistent memory */ + +} MEM_REQUIREMENTS; + +#define PCM_MPS INT_PCM +#define PCM_MPSF FIXP_PCM + +#define FIXP_DBL2PCM_MPS(x) ((INT_PCM)FX_DBL2FX_PCM(x)) + +/* exposed functions (library interface) */ + +int FDK_SpatialDecCompareSpatialSpecificConfigHeader( + SPATIAL_SPECIFIC_CONFIG *pSsc1, SPATIAL_SPECIFIC_CONFIG *pSsc2); + +int FDK_SpatialDecInitDefaultSpatialSpecificConfig( + SPATIAL_SPECIFIC_CONFIG *pSpatialSpecificConfig, + AUDIO_OBJECT_TYPE coreCodec, int coreChannels, int samplingFreq, + int nTimeSlots, int decoderLevel, int isBlind); + +spatialDec *FDK_SpatialDecOpen(const SPATIAL_DEC_CONFIG *config, + int stereoConfigIndex); + +/** + * \brief Initialize state variables of the MPS parser + */ +void SpatialDecInitParserContext(spatialDec *self); + +/** + * \brief Initialize state of MPS decoder. This may happen after the first parse + * operation. + */ +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 /* MPEGS_INIT_CTRL_FLAGS */ +); + +/** + * \brief Apply decoded MPEG Surround parameters to time domain or QMF down mix + * data. + * \param self spatial decoder handle. + * \param inData Pointer to time domain input down mix data if any. + * \param qmfInDataReal Pointer array of QMF domain down mix input data (real + * part). + * \param qmfInDataImag Pointer array of QMF domain down mix input data + * (imaginary part). + * \param pcmOutBuf Pointer to a time domain buffer were the upmixed output data + * will be stored into. + * \param nSamples Amount of audio samples per channel of down mix input data + * (frame length). + * \param pControlFlags pointer to control flags field; input/output. + * \param numInputChannels amount of down mix input channels. Might not match + * the current tree config, useful for internal sanity checks and bypass mode. + * \param channelMapping array containing the desired output channel ordering to + * transform MPEG PCE style ordering to any other channel ordering. First + * dimension is the total channel count. + */ +SACDEC_ERROR SpatialDecApplyFrame( + spatialDec *self, SPATIAL_BS_FRAME *frame, SPATIALDEC_INPUT_MODE inputMode, + PCM_MPS *inData, /* Time domain input */ + FIXP_DBL **qmfInDataReal, /* interleaved l/r */ + FIXP_DBL **qmfInDataImag, /* interleaved 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); + +/** + * \brief Fill given arrays with audio channel types and indices. + * \param self spatial decoder handle. + * \param channelType array where corresponding channel types fr each output + * channels are stored into. + * \param channelIndices array where corresponding channel type indices fr each + * output channels are stored into. + */ +void SpatialDecChannelProperties(spatialDec *self, + AUDIO_CHANNEL_TYPE channelType[], + UCHAR channelIndices[], + const FDK_channelMapDescr *const mapDescr); + +void FDK_SpatialDecClose(spatialDec *self); + +#ifdef __cplusplus +} +#endif + +#endif /* SAC_DEC_INTERFACE_H */ diff --git a/libSACdec/src/sac_dec_lib.cpp b/libSACdec/src/sac_dec_lib.cpp new file mode 100644 index 0000000..56d8693 --- /dev/null +++ b/libSACdec/src/sac_dec_lib.cpp @@ -0,0 +1,1912 @@ +/* ----------------------------------------------------------------------------- +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 Interface + +*******************************************************************************/ + +#include "sac_dec_lib.h" +#include "sac_dec_interface.h" +#include "sac_dec.h" +#include "sac_bitdec.h" +#include "FDK_matrixCalloc.h" + +#define MPS_DATA_BUFFER_SIZE (2048) + +/** + * \brief MPEG Surround data indication. + **/ +typedef enum { + MPEGS_ANCTYPE_FRAME = 0, /*!< MPEG Surround frame, see ISO/IEC 23003-1 */ + MPEGS_ANCTYPE_HEADER_AND_FRAME = 1, /*!< MPEG Surround header and MPEG + Surround frame, see ISO/IEC 23003-1 */ + MPEGS_ANCTYPE_RESERVED_1 = 2, /*!< reserved, see ISO/IEC 23003-1 */ + MPEGS_ANCTYPE_RESERVED_2 = 3 /*!< reserved, see ISO/IEC 23003-1*/ +} MPEGS_ANCTYPE; + +/** + * \brief MPEG Surround data segment indication. + **/ +typedef enum { + MPEGS_CONTINUE = 0, /*!< Indicates if data segment continues a data block. */ + MPEGS_STOP = 1, /*!< Indicates if data segment ends a data block. */ + MPEGS_START = 2, /*!< Indicates if data segment begins a data block. */ + MPEGS_START_STOP = + 3 /*!< Indicates if data segment begins and ends a data block. */ +} MPEGS_ANCSTARTSTOP; + +/** + * \brief MPEG Surround synchronizaiton state. + * + * CAUTION: Changing the enumeration values can break the sync mechanism + *because it is based on comparing the state values. + **/ +typedef enum { + MPEGS_SYNC_LOST = + 0, /*!< Indicates lost sync because of current discontinuity. */ + MPEGS_SYNC_FOUND = 1, /*!< Parsed a valid header and (re)intialization was + successfully completed. */ + MPEGS_SYNC_COMPLETE = 2 /*!< In sync and continuous. Found an independent + frame in addition to MPEGS_SYNC_FOUND. + Precondition: MPEGS_SYNC_FOUND. */ +} MPEGS_SYNCSTATE; + +/** + * \brief MPEG Surround operation mode. + **/ +typedef enum { + MPEGS_OPMODE_EMM = 0, /*!< Mode: Enhanced Matrix Mode (Blind) */ + MPEGS_OPMODE_MPS_PAYLOAD = 1, /*!< Mode: Normal, Stereo or Binaural */ + MPEGS_OPMODE_NO_MPS_PAYLOAD = 2 /*!< Mode: no MPEG Surround payload */ +} MPEGS_OPMODE; + +/** + * \brief MPEG Surround init flags. + **/ +typedef enum { + MPEGS_INIT_OK = 0x00000000, /*!< indicate correct initialization */ + MPEGS_INIT_ENFORCE_REINIT = + 0x00000001, /*!< indicate complete initialization */ + + MPEGS_INIT_CHANGE_OUTPUT_MODE = + 0x00000010, /*!< indicate change of the output mode */ + MPEGS_INIT_CHANGE_PARTIALLY_COMPLEX = + 0x00000020, /*!< indicate change of low power/high quality */ + MPEGS_INIT_CHANGE_TIME_FREQ_INTERFACE = + 0x00000040, /*!< indicate change of qmf/time interface */ + MPEGS_INIT_CHANGE_HEADER = 0x00000080, /*!< indicate change of header */ + + MPEGS_INIT_ERROR_PAYLOAD = + 0x00000100, /*!< indicate payload/ancType/ancStartStop error */ + + MPEGS_INIT_BS_INTERRUPTION = + 0x00001000, /*!< indicate bitstream interruption */ + MPEGS_INIT_CLEAR_HISTORY = + 0x00002000, /*!< indicate that all states shall be cleared */ + + /* Re-initialization of submodules */ + + MPEGS_INIT_CHANGE_CONCEAL_PARAMS = 0x00100000, /*!< indicate a change of at + least one error concealment + param */ + + /* No re-initialization needed, currently not used */ + MPEGS_INIT_CHANGE_BYPASS_MODE = + 0x01000000, /*!< indicate change of bypass mode */ + + /* Re-initialization needed, currently not used */ + MPEGS_INIT_ERROR_ANC_TYPE = 0x10000000, /*!< indicate ancType error*/ + MPEGS_INIT_ERROR_ANC_STARTSTOP = + 0x20000000 /*!< indicate ancStartStop error */ +} MPEGS_INIT_FLAGS; + +struct MpegSurroundDecoder { + HANDLE_FDK_QMF_DOMAIN pQmfDomain; + UCHAR mpsData[MPS_DATA_BUFFER_SIZE]; /* Buffer for MPS payload accross more + than one segment */ + INT mpsDataBits; /* Amount of bits in mpsData */ + /* MPEG Surround decoder */ + SPATIAL_SPECIFIC_CONFIG spatialSpecificConfig[1]; /* SSC delay line which is + used during decoding */ + spatialDec *pSpatialDec; + SPATIAL_SPECIFIC_CONFIG + spatialSpecificConfigBackup; /* SSC used while parsing */ + + /* Creation parameter */ + UCHAR mpegSurroundDecoderLevel; + /* Run-time parameter */ + UCHAR mpegSurroundSscIsGlobalCfg; /* Flag telling that the SSC + (::spatialSpecificConfig) is a + out-of-band configuration. */ + UCHAR mpegSurroundUseTimeInterface; + + SPATIAL_BS_FRAME + bsFrames[1]; /* Bitstream Structs that contain data read from the + SpatialFrame() bitstream element */ + BS_LL_STATE llState; /* Bit stream parser state memory */ + UCHAR bsFrameParse; /* Current parse frame context index */ + UCHAR bsFrameDecode; /* Current decode/apply frame context index */ + UCHAR bsFrameDelay; /* Amount of frames delay between parsing and processing. + Required i.e. for interpolation error concealment. */ + + /* User prameters */ + SPATIALDEC_PARAM mpegSurroundUserParams; + + /* Internal flags */ + SPATIAL_DEC_UPMIX_TYPE upmixType; + int initFlags[1]; + MPEGS_ANCSTARTSTOP ancStartStopPrev; + MPEGS_SYNCSTATE fOnSync[1]; + + /* Inital decoder configuration */ + SPATIAL_DEC_CONFIG decConfig; +}; + +static SACDEC_ERROR sscParseCheck(const SPATIAL_SPECIFIC_CONFIG *pSsc); + +/** + * \brief Get the number of QMF bands from the sampling frequency (in Hz) + **/ +static int mpegSurroundDecoder_GetNrOfQmfBands( + const SPATIAL_SPECIFIC_CONFIG *pSsc, UINT sampleRate) { + UINT samplingFrequency = sampleRate; + int qmfBands = 64; + + if (pSsc != NULL) { + switch (pSsc->coreCodec) { + case AOT_USAC: + if ((pSsc->stereoConfigIndex == 3)) { + static const UCHAR mapIdx2QmfBands[3] = {24, 32, 16}; + FDK_ASSERT((pSsc->coreSbrFrameLengthIndex >= 2) && + (pSsc->coreSbrFrameLengthIndex <= 4)); + qmfBands = mapIdx2QmfBands[pSsc->coreSbrFrameLengthIndex - 2]; + } + return qmfBands; + default: + samplingFrequency = pSsc->samplingFreq; + break; + } + } + + /* number of QMF bands depend on sampling frequency, see FDIS 23003-1:2006 + * Chapter 6.3.3 */ + if (samplingFrequency < 27713) { + qmfBands = 32; + } + if (samplingFrequency > 55426) { + qmfBands = 128; + } + + return qmfBands; +} + +/** + * \brief Analyse init flags + **/ +static int mpegSurroundDecoder_CalcInitFlags(SPATIAL_SPECIFIC_CONFIG *pSsc1, + SPATIAL_SPECIFIC_CONFIG *pSsc2, + int upmixTypeFlag, + int binauralQualityFlag, + int partiallyComplexFlag, + int *ctrlFlags) { + /* Analyse core coder */ + if (pSsc1->coreCodec != pSsc2->coreCodec) { + *ctrlFlags |= MASK_MPEGS_INIT_ALL_STATES; + *ctrlFlags |= MASK_MPEGS_INIT_ALL_PARAMS; + } else { + /* Analyse elements for initialization of space analysis qmf filterbank */ + if ((partiallyComplexFlag) || (pSsc1->treeConfig != pSsc2->treeConfig) || + (pSsc1->samplingFreq != pSsc2->samplingFreq)) { + *ctrlFlags |= MPEGS_INIT_STATES_ANA_QMF_FILTER; + *ctrlFlags |= MPEGS_INIT_STATES_ANA_HYB_FILTER; + } + + /* Analyse elements for initialization of space synthesis qmf filterbank */ + if ((upmixTypeFlag) || (partiallyComplexFlag) || + (pSsc1->treeConfig != pSsc2->treeConfig) || + (pSsc1->samplingFreq != pSsc2->samplingFreq) || + (pSsc1->bsFixedGainDMX != pSsc2->bsFixedGainDMX)) { + *ctrlFlags |= MPEGS_INIT_STATES_SYN_QMF_FILTER; + } + + /* Analyse elements for initialization of decorrelator */ + if ((upmixTypeFlag) || (partiallyComplexFlag) || + (pSsc1->treeConfig != pSsc2->treeConfig) || + (pSsc1->samplingFreq != pSsc2->samplingFreq) || + (pSsc1->decorrConfig != pSsc2->decorrConfig)) { + *ctrlFlags |= MPEGS_INIT_STATES_DECORRELATOR; + } + + /* Analyse elements for initialization of m1 and m2 calculation */ + if ((upmixTypeFlag) || (binauralQualityFlag) || + (pSsc1->treeConfig != pSsc2->treeConfig) || + (pSsc1->samplingFreq != pSsc2->samplingFreq)) + + { + *ctrlFlags |= MPEGS_INIT_STATES_M1M2; + } + + /* Analyse elements for initialization of GES */ + if ((upmixTypeFlag) || (pSsc1->treeConfig != pSsc2->treeConfig) || + (pSsc1->tempShapeConfig != pSsc2->tempShapeConfig)) { + *ctrlFlags |= MPEGS_INIT_STATES_GES; + } + + /* Analyse elements for initialization of FDreverb */ + if ((upmixTypeFlag) || (binauralQualityFlag) || (partiallyComplexFlag) || + (pSsc1->samplingFreq != pSsc2->samplingFreq) || + (pSsc1->nTimeSlots != pSsc2->nTimeSlots)) { + *ctrlFlags |= MPEGS_INIT_STATES_REVERB; + } + + /* Reset previous frame data whenever the config changes */ + if (*ctrlFlags & MPEGS_INIT_CONFIG) { + *ctrlFlags |= MPEGS_INIT_STATES_PARAM; + } + } + + return MPS_OK; +} + +/** + * \brief Reset MPEG Surround status info + **/ +static void updateMpegSurroundDecoderStatus( + CMpegSurroundDecoder *pMpegSurroundDecoder, int initFlags, + MPEGS_SYNCSTATE fOnSync, MPEGS_ANCSTARTSTOP ancStartStopPrev) { + pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |= + initFlags; + if ((pMpegSurroundDecoder->mpegSurroundSscIsGlobalCfg != 0) && + (pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] >= + MPEGS_SYNC_FOUND) && + (fOnSync < MPEGS_SYNC_FOUND)) { + pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] = + MPEGS_SYNC_FOUND; + } else { + pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] = + fOnSync; + } + pMpegSurroundDecoder->ancStartStopPrev = ancStartStopPrev; +} + +static SACDEC_ERROR mpegSurroundDecoder_Create( + CMpegSurroundDecoder **pMpegSurroundDecoder, int stereoConfigIndex, + HANDLE_FDK_QMF_DOMAIN pQmfDomain); + +SAC_INSTANCE_AVAIL +mpegSurroundDecoder_IsFullMpegSurroundDecoderInstanceAvailable( + CMpegSurroundDecoder *pMpegSurroundDecoder) { + SAC_INSTANCE_AVAIL instanceAvailable = SAC_INSTANCE_NOT_FULL_AVAILABLE; + + if (pMpegSurroundDecoder->pSpatialDec != NULL) { + instanceAvailable = SAC_INSTANCE_FULL_AVAILABLE; + } + + return instanceAvailable; +} + +SACDEC_ERROR mpegSurroundDecoder_Open( + CMpegSurroundDecoder **pMpegSurroundDecoder, int stereoConfigIndex, + HANDLE_FDK_QMF_DOMAIN pQmfDomain) { + SACDEC_ERROR error; + + error = mpegSurroundDecoder_Create(pMpegSurroundDecoder, stereoConfigIndex, + pQmfDomain); + + return error; +} + +/** + * \brief Renamed function from getUpmixType to check_UParam_Build_DecConfig. + * This function checks if user params, decoder config and SSC are valid + * and if the decoder build can handle all this settings. + * The upmix type may be modified by this function. + * It is called in initMpegSurroundDecoder() after the ssc parse check, + * to have all checks in one place and to ensure these checks are always + * performed if config changes (inband and out-of-band). + * + * \param pUserParams User data handle. + * \param pDecConfig decoder config handle. + * \param pSsc spatial specific config handle. + * \param pUpmixType upmix type which is set by this function + * + * \return MPS_OK on sucess, and else on failure. + */ +static SACDEC_ERROR check_UParam_Build_DecConfig( + SPATIALDEC_PARAM const *pUserParams, SPATIAL_DEC_CONFIG const *pDecConfig, + const SPATIAL_SPECIFIC_CONFIG *pSsc, SPATIAL_DEC_UPMIX_TYPE *pUpmixType) { + int dmxChannels, outChannels, maxNumOutChannels; + + FDK_ASSERT(pUserParams != NULL); + FDK_ASSERT(pUpmixType != NULL); + + /* checks if implementation can handle the Ssc */ + + switch (pSsc->treeConfig) { + case SPATIALDEC_MODE_RSVD7: /* 212 */ + dmxChannels = 1; + outChannels = 2; + break; + default: + return MPS_UNSUPPORTED_CONFIG; + } + + /* ------------------------------------------- */ + + /* Analyse pDecConfig params */ + switch (pDecConfig->binauralMode) { + case BINAURAL_NONE: + break; + default: + return MPS_UNSUPPORTED_CONFIG; + } + + switch (pDecConfig->decoderMode) { + case EXT_HQ_ONLY: + break; + default: + return MPS_UNSUPPORTED_CONFIG; + } + + switch (pDecConfig->maxNumOutputChannels) { + case OUTPUT_CHANNELS_DEFAULT: + /* No special restrictions -> Get the level restriction: */ + switch (pDecConfig->decoderLevel) { + case DECODER_LEVEL_0: + maxNumOutChannels = 2; + break; + default: + return MPS_UNSUPPORTED_CONFIG; + } + break; + case OUTPUT_CHANNELS_2_0: + maxNumOutChannels = 2; + break; + default: + return MPS_UNSUPPORTED_CONFIG; + } + /* ------------------------- */ + + /* check if we can handle user params */ + if (pUserParams->blindEnable == 1) { + return MPS_UNSUPPORTED_CONFIG; + } + { + switch ((SAC_DEC_OUTPUT_MODE)pUserParams->outputMode) { + case SACDEC_OUT_MODE_NORMAL: + if (maxNumOutChannels >= outChannels) { + *pUpmixType = UPMIX_TYPE_NORMAL; + } else { + { *pUpmixType = UPMIX_TYPE_BYPASS; } + } + break; + case SACDEC_OUT_MODE_STEREO: + if (dmxChannels == 1) { + if (outChannels == 2) { + *pUpmixType = UPMIX_TYPE_NORMAL; + } + } else { + *pUpmixType = UPMIX_TYPE_BYPASS; + } + break; + case SACDEC_OUT_MODE_6CHANNEL: + if (outChannels > 6) { + { *pUpmixType = UPMIX_TYPE_BYPASS; } + } else { + *pUpmixType = UPMIX_TYPE_NORMAL; + } + break; + default: + return MPS_UNSUPPORTED_CONFIG; + } + } + + return MPS_OK; +} + +/** + * \brief Init MPEG Surround decoder. + **/ +static SACDEC_ERROR initMpegSurroundDecoder( + CMpegSurroundDecoder *pMpegSurroundDecoder) { + SACDEC_ERROR err; + int initFlags = MPEGS_INIT_NONE, initFlagsDec; + int upmixTypeCurr = pMpegSurroundDecoder->upmixType; + + FDK_ASSERT(pMpegSurroundDecoder != NULL); + + SPATIAL_SPECIFIC_CONFIG *const pSSCinput = + &pMpegSurroundDecoder->spatialSpecificConfigBackup; + SPATIAL_SPECIFIC_CONFIG *const pSSCtarget = + &pMpegSurroundDecoder + ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameDecode]; + initFlagsDec = + pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode]; + + if (pSSCinput->coreCodec != AOT_USAC) { + /* here we check if we have a valid Ssc */ + err = sscParseCheck(pSSCinput); + if (err != MPS_OK) goto bail; + } + + /* here we check if Ssc matches build; also check UParams and DecConfig */ + /* if desired upmixType is changes */ + err = check_UParam_Build_DecConfig( + &pMpegSurroundDecoder->mpegSurroundUserParams, + &pMpegSurroundDecoder->decConfig, pSSCinput, + &pMpegSurroundDecoder->upmixType); + if (err != MPS_OK) goto bail; + + /* init config */ + if (initFlagsDec & MPEGS_INIT_CHANGE_HEADER) { + initFlags |= MPEGS_INIT_CONFIG; + } + /* init all states */ + if (initFlagsDec & MPEGS_INIT_CLEAR_HISTORY) { + initFlags |= MASK_MPEGS_INIT_ALL_STATES; + } + if (initFlagsDec & MPEGS_INIT_CHANGE_CONCEAL_PARAMS) { + initFlags |= MPEGS_INIT_PARAMS_ERROR_CONCEALMENT; + } + + if (initFlagsDec & MPEGS_INIT_ENFORCE_REINIT) { + /* init all states */ + initFlags |= MASK_MPEGS_INIT_ALL_STATES; + initFlags |= MASK_MPEGS_INIT_ALL_PARAMS; + } else { + /* analyse states which have to be initialized */ + mpegSurroundDecoder_CalcInitFlags( + pSSCtarget, pSSCinput, + (upmixTypeCurr != + pMpegSurroundDecoder->upmixType), /* upmixType changed */ + 0, (initFlagsDec & MPEGS_INIT_CHANGE_PARTIALLY_COMPLEX) ? 1 : 0, + &initFlags); + } + + { + int nrOfQmfBands; + FDKmemcpy(pSSCtarget, pSSCinput, sizeof(SPATIAL_SPECIFIC_CONFIG)); + + nrOfQmfBands = mpegSurroundDecoder_GetNrOfQmfBands( + pSSCtarget, pSSCtarget->samplingFreq); + err = FDK_SpatialDecInit( + pMpegSurroundDecoder->pSpatialDec, + &pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameDecode], + pSSCtarget, nrOfQmfBands, pMpegSurroundDecoder->upmixType, + &pMpegSurroundDecoder->mpegSurroundUserParams, initFlags); + + if (err != MPS_OK) goto bail; + + /* Signal that we got a header and can go on decoding */ + if (err == MPS_OK) { + initFlagsDec = MPEGS_INIT_OK; + { + pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] = + MPEGS_SYNC_FOUND; + } + } + } + +bail: + pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] = + initFlagsDec; + return err; +} + +/** + * \brief Init MPEG Surround decoder. + **/ +SACDEC_ERROR mpegSurroundDecoder_Init( + CMpegSurroundDecoder *pMpegSurroundDecoder) { + SACDEC_ERROR err = MPS_OK; + + if (pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode]) { + err = initMpegSurroundDecoder(pMpegSurroundDecoder); + } + return err; +} + +/** + * \brief Open MPEG Surround decoder. + **/ +static SACDEC_ERROR mpegSurroundDecoder_Create( + CMpegSurroundDecoder **pMpegSurroundDecoder, int stereoConfigIndex, + HANDLE_FDK_QMF_DOMAIN pQmfDomain) { + SACDEC_ERROR err = MPS_OK; + CMpegSurroundDecoder *sacDec = NULL; + spatialDec *self = NULL; + + /* decoderLevel decoderMode maxNumOutputChannels binauralMode */ + static const SPATIAL_DEC_CONFIG decConfig = { + (CFG_LEVEL)(0), EXT_HQ_ONLY, OUTPUT_CHANNELS_DEFAULT, BINAURAL_NONE}; + + if (*pMpegSurroundDecoder == NULL) { + FDK_ALLOCATE_MEMORY_1D(*pMpegSurroundDecoder, 1, CMpegSurroundDecoder) + + for (int i = 0; i < 1; i++) { + err = SpatialDecCreateBsFrame(&(*pMpegSurroundDecoder)->bsFrames[i], + &(*pMpegSurroundDecoder)->llState); + if (err != MPS_OK) { + sacDec = *pMpegSurroundDecoder; + goto bail; + } + } + (*pMpegSurroundDecoder)->pQmfDomain = pQmfDomain; + + (*pMpegSurroundDecoder)->bsFrameDelay = 1; + (*pMpegSurroundDecoder)->bsFrameParse = 0; + (*pMpegSurroundDecoder)->bsFrameDecode = 0; + + return err; + } else { + sacDec = *pMpegSurroundDecoder; + } + + if (sacDec->pSpatialDec == NULL) { + if ((self = FDK_SpatialDecOpen(&decConfig, stereoConfigIndex)) == NULL) { + err = MPS_OUTOFMEMORY; + goto bail; + } + } else { + self = sacDec->pSpatialDec; + } + + self->pQmfDomain = sacDec->pQmfDomain; + + sacDec->pSpatialDec = self; + + /* default parameter set */ + sacDec->mpegSurroundUserParams.outputMode = SACDEC_OUT_MODE_NORMAL; + sacDec->mpegSurroundUserParams.blindEnable = 0; + sacDec->mpegSurroundUserParams.bypassMode = 0; + sacDec->mpegSurroundUserParams.concealMethod = 1; + sacDec->mpegSurroundUserParams.concealNumKeepFrames = 10; + sacDec->mpegSurroundUserParams.concealFadeOutSlopeLength = 5; + sacDec->mpegSurroundUserParams.concealFadeInSlopeLength = 5; + sacDec->mpegSurroundUserParams.concealNumReleaseFrames = 3; + sacDec->mpegSurroundSscIsGlobalCfg = 0; + sacDec->mpegSurroundUseTimeInterface = 1; + sacDec->mpegSurroundDecoderLevel = decConfig.decoderLevel; + + sacDec->upmixType = UPMIX_TYPE_NORMAL; + + /* signalize spatial decoder re-initalization */ + updateMpegSurroundDecoderStatus(sacDec, MPEGS_INIT_ENFORCE_REINIT, + MPEGS_SYNC_LOST, MPEGS_STOP); + + /* return decoder instance */ + *pMpegSurroundDecoder = sacDec; + sacDec->decConfig = decConfig; + + SpatialDecInitParserContext(sacDec->pSpatialDec); + + return err; + +bail: + if (sacDec != NULL) { + mpegSurroundDecoder_Close(sacDec); + } + *pMpegSurroundDecoder = NULL; + if (err == MPS_OK) { + return MPS_OUTOFMEMORY; + } else { + return err; + } +} + +/** + * \brief Config MPEG Surround decoder. + **/ +SACDEC_ERROR mpegSurroundDecoder_Config( + CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs, + AUDIO_OBJECT_TYPE coreCodec, INT samplingRate, INT stereoConfigIndex, + INT coreSbrFrameLengthIndex, INT configBytes, const UCHAR configMode, + UCHAR *configChanged) { + SACDEC_ERROR err = MPS_OK; + + switch (coreCodec) { + case AOT_DRM_USAC: + case AOT_USAC: + if (configMode == AC_CM_DET_CFG_CHANGE) { + /* In config detection mode write spatial specific config parameters + * into temporarily allocated structure */ + SPATIAL_SPECIFIC_CONFIG spatialSpecificConfig; + err = SpatialDecParseMps212Config( + hBs, &spatialSpecificConfig, samplingRate, coreCodec, + stereoConfigIndex, coreSbrFrameLengthIndex); + } else { + err = SpatialDecParseMps212Config( + hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup, + samplingRate, coreCodec, stereoConfigIndex, + coreSbrFrameLengthIndex); + } + break; + case AOT_ER_AAC_ELD: + case AOT_ER_AAC_LD: + err = SpatialDecParseSpecificConfig( + hBs, &pMpegSurroundDecoder->spatialSpecificConfigBackup, configBytes, + coreCodec); + break; + default: + err = MPS_UNSUPPORTED_FORMAT; + break; + } + + if (err != MPS_OK) { + goto bail; + } + + if (configMode & AC_CM_DET_CFG_CHANGE) { + return err; + } + + if (configMode & AC_CM_ALLOC_MEM) { + if (*configChanged) { + if ((err = mpegSurroundDecoder_Open(&pMpegSurroundDecoder, + stereoConfigIndex, NULL))) { + return err; + } + } + } + + { + SPATIAL_SPECIFIC_CONFIG *sscParse = + &pMpegSurroundDecoder + ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameParse]; + + if (FDK_SpatialDecCompareSpatialSpecificConfigHeader( + &pMpegSurroundDecoder->spatialSpecificConfigBackup, sscParse)) { + pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameParse] |= + MPEGS_INIT_CHANGE_HEADER; + /* Error resilience code */ + if (pMpegSurroundDecoder->pSpatialDec == NULL) { + err = MPS_NOTOK; + goto bail; + } + SpatialDecInitParserContext(pMpegSurroundDecoder->pSpatialDec); + pMpegSurroundDecoder->pSpatialDec->pConfigCurrent = + &pMpegSurroundDecoder + ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameDecode]; + } + } + + if (err == MPS_OK) { + /* We got a valid out-of-band configuration so label it accordingly. */ + pMpegSurroundDecoder->mpegSurroundSscIsGlobalCfg = 1; + } + +bail: + return err; +} + +/** + * \brief Determine MPEG Surround operation mode. + **/ +static MPEGS_OPMODE mpegSurroundOperationMode( + CMpegSurroundDecoder *pMpegSurroundDecoder, int mpsDataBits) { + MPEGS_OPMODE mode; + + { + if ((mpsDataBits > 0) && + (pMpegSurroundDecoder->mpegSurroundUserParams.blindEnable == 0)) { + mode = MPEGS_OPMODE_MPS_PAYLOAD; /* Mode: Normal, Stereo or Binaural */ + } else { + mode = MPEGS_OPMODE_NO_MPS_PAYLOAD; /* Mode: No MPEG Surround Payload */ + updateMpegSurroundDecoderStatus(pMpegSurroundDecoder, + MPEGS_INIT_ERROR_PAYLOAD, MPEGS_SYNC_LOST, + MPEGS_STOP); + } + } + + return (mode); +} + +/** + * \brief Check ssc for parse errors. + * This one is called in initMpegSurroundDecoder() + * to ensure checking of inband and out-of-band mps configs. + * Only parse errors checked here! Check for valid config is done + * in check_UParam_Build_DecConfig()! + * + * \param pSsc spatial specific config handle. + * + * \return MPS_OK on sucess, and else on parse error. + */ +static SACDEC_ERROR sscParseCheck(const SPATIAL_SPECIFIC_CONFIG *pSsc) { + SACDEC_ERROR err = MPS_OK; + + if (pSsc->samplingFreq > 96000) return MPS_PARSE_ERROR; + if (pSsc->samplingFreq < 8000) return MPS_PARSE_ERROR; + + switch (pSsc->freqRes) { + case SPATIALDEC_FREQ_RES_28: + case SPATIALDEC_FREQ_RES_20: + case SPATIALDEC_FREQ_RES_14: + case SPATIALDEC_FREQ_RES_10: + case SPATIALDEC_FREQ_RES_23: + case SPATIALDEC_FREQ_RES_15: + case SPATIALDEC_FREQ_RES_12: + case SPATIALDEC_FREQ_RES_9: + case SPATIALDEC_FREQ_RES_7: + case SPATIALDEC_FREQ_RES_5: + case SPATIALDEC_FREQ_RES_4: + break; + case SPATIALDEC_FREQ_RES_40: /* 40 doesn't exist in ISO/IEC 23003-1 */ + default: + return MPS_PARSE_ERROR; + } + + if ((pSsc->treeConfig < 0) || (pSsc->treeConfig > 7)) { + return MPS_PARSE_ERROR; + } + + if ((pSsc->quantMode < 0) || (pSsc->quantMode > 2)) { + return MPS_PARSE_ERROR; + } + + if (pSsc->tempShapeConfig == 3) { + return MPS_PARSE_ERROR; + } + + if (pSsc->decorrConfig == 3) { + return MPS_PARSE_ERROR; + } + + /* now we are sure there were no parsing errors */ + + return err; +} + +/** + * \brief Check number of time slots + * + * Basically the mps frame length must be a multiple of the core coder frame + * length. The below table shows all valid configurations in detail. See ISO/IEC + * 23003-1: "Table 4A - Allowed values for bsFrameLength in the Baseline MPEG + * Surround Profile" + * + * Downmix Coder Downmix Code Allowed values for bsFrameLength + * Allowed frame sizes for normal, downsampled and upsampled MPS Framelength + * (QMF Samples) + * + * AAC 1024 16 15, 31, 47, 63 1024 2048 3072 4096 + * downsampled MPS 32 31, 63 1024 2048 upsampled MPS + * 8 7, 15, 23, 31, 39, 47, 55, 63, 71 1024 2048 3072 4096 + * 5120 6144 7168 8192 9216 + * + * AAC 960 15 14, 29, 44, 59 960 1920 2880 3840 + * downsampled MPS 30 29, 59 960 1920 upsampled MPS + * 7,5 14, 29, 44, 59 1920 3840 5760 7680 + * + * HE-AAC 1024/2048 32 31, 63 2048 4096 downsampled MPS + * 64 63 2048 upsampled MPS + * 16 15, 31, 47, 63 2048 4096 6144 8192 + * + * HE-AAC 960/1920 30 29, 59 1920 3840 downsampled MPS + * 60 59 1920 upsampled MPS + * 15 14, 29, 44, 59 1920 3840 5760 7680 + * + * BSAC 16 15, 31, 47, 63 1024 2048 3072 4096 + * downsampled MPS 32 31, 63 1024 2048 upsampled MPS + * 8 7, 15, 23, 31, 39, 47, 55, 63, 71 1024 2048 3072 4096 + * 5120 6144 7168 8192 9216 + * + * BSAC with SBR 32 31, 63 2048 4096 downsampled MPS + * 64 63 2048 upsampled MPS + * 16 15, 31, 47, 63 2048 4096 6144 8192 + * + * AAC LD 512 8 7, 15, 23, 31, 39, 47, 55, 63, 71 + * 512 1024 1536 2048 2560 3072 3584 4096 4608 downsampled MPS + * 16 15, 31, 47, 63 512 1024 1536 2048 + * + * AAC ELD 512 8 7, 15, 23, 31, 39, 47, 55, 63, 71 + * 512 1024 1536 2048 2560 3072 3584 4096 4608 downsampled MPS + * 16 15, 31, 47, 63 512 1024 1536 2048 + * + * AAC ELD with SBR 512/1024 16 15, 31, 47, 63 1024 2048 3072 4096 + * downsampled MPS 32 31, 63 1024 2048 upsampled MPS + * 8 7, 15, 23, 31, 39, 47, 55, 63, 71 1024 2048 3072 4096 + * 5120 6144 7168 8192 9216 + * + * MPEG1/2 Layer II 18 17, 35, 53, 71 1152 2304 3456 4608 + * downsampled MPS 36 35, 71 1152 2304 + * + * MPEG1/2 Layer III 18 17, 35, 53, 71 1152 2304 3456 4608 + * downsampled MPS 36 35, 71 1152 2304 + * + * \param frameLength + * \param qmfBands + * \param timeSlots + * + * \return error code + */ +SACDEC_ERROR checkTimeSlots(int frameLength, int qmfBands, int timeSlots) { + int len; + int maxFrameLength; + + if (qmfBands == 64) { + /* normal MPEG Surround */ + switch (frameLength) { + case 960: + case 1920: + maxFrameLength = 3840; + break; + case 1024: + case 2048: + maxFrameLength = 4096; + break; + case 512: + case 1152: + maxFrameLength = 4608; + break; + default: + return MPS_PARSE_ERROR; + } + } else if (qmfBands == 32) { + /* downsampled MPEG Surround */ + switch (frameLength) { + case 960: + case 1920: + maxFrameLength = 1920; + break; + case 512: + case 1024: + case 2048: + maxFrameLength = 2048; + break; + case 1152: + maxFrameLength = 2304; + break; + default: + return MPS_PARSE_ERROR; + } + } else if (qmfBands == 128) { + /* upsampled MPEG Surround */ + switch (frameLength) { + case 1920: + maxFrameLength = 7680; + break; + case 1024: + maxFrameLength = 9216; + break; + case 2048: + maxFrameLength = 8192; + break; + case 512: + case 960: + case 1152: + /* no break, no support for upsampled MPEG Surround */ + default: + return MPS_PARSE_ERROR; + } + } else { + return MPS_PARSE_ERROR; + } + + len = frameLength; + + while (len <= maxFrameLength) { + if (len == timeSlots * qmfBands) { + return MPS_OK; + } + len += frameLength; + } + return MPS_PARSE_ERROR; +} + +/** + * \brief Check ssc for consistency (e.g. bit errors could cause trouble) + * First of currently two ssc-checks. + * This (old) one is called in mpegSurroundDecoder_Apply() + * only if inband mps config is contained in stream. + * + * New ssc check is split in two functions sscParseCheck() and + * check_UParam_Build_DecConfig(). sscParseCheck() checks only for correct + * parsing. check_UParam_Build_DecConfig() is used to check if we have a + * valid config. Both are called in initMpegSurroundDecoder() to ensure + * checking of inband and out-of-band mps configs. + * + * If this function can be integrated into the new functions. + * We can remove this one. + * + * \param pSsc spatial specific config handle. + * \param frameLength + * \param sampleRate + * + * \return MPS_OK on sucess, and else on failure. + */ +static SACDEC_ERROR sscCheckInBand(SPATIAL_SPECIFIC_CONFIG *pSsc, + int frameLength, int sampleRate) { + SACDEC_ERROR err = MPS_OK; + int qmfBands; + + FDK_ASSERT(pSsc != NULL); + + /* core fs and mps fs must match */ + if (pSsc->samplingFreq != sampleRate) { + err = MPS_PARSE_ERROR /* MPEGSDEC_SSC_PARSE_ERROR */; + } + + qmfBands = mpegSurroundDecoder_GetNrOfQmfBands(pSsc, pSsc->samplingFreq); + + if (checkTimeSlots(frameLength, qmfBands, pSsc->nTimeSlots) != MPS_OK) { + err = MPS_PARSE_ERROR; + } + + return err; +} + +SACDEC_ERROR +mpegSurroundDecoder_ConfigureQmfDomain( + CMpegSurroundDecoder *pMpegSurroundDecoder, + SAC_INPUT_CONFIG sac_dec_interface, UINT coreSamplingRate, + AUDIO_OBJECT_TYPE coreCodec) { + SACDEC_ERROR err = MPS_OK; + FDK_QMF_DOMAIN_GC *pGC = NULL; + + if (pMpegSurroundDecoder == NULL) { + return MPS_INVALID_HANDLE; + } + + FDK_ASSERT(pMpegSurroundDecoder->pSpatialDec); + + pGC = &pMpegSurroundDecoder->pQmfDomain->globalConf; + if (pMpegSurroundDecoder->mpegSurroundSscIsGlobalCfg) { + SPATIAL_SPECIFIC_CONFIG *pSSC = + &pMpegSurroundDecoder->spatialSpecificConfigBackup; + if (sac_dec_interface == SAC_INTERFACE_TIME) { + /* For SAC_INTERFACE_QMF these parameters are set by SBR. */ + pGC->nBandsAnalysis_requested = mpegSurroundDecoder_GetNrOfQmfBands( + pSSC, coreSamplingRate); /* coreSamplingRate == outputSamplingRate for + SAC_INTERFACE_TIME */ + pGC->nBandsSynthesis_requested = pGC->nBandsAnalysis_requested; + pGC->nInputChannels_requested = + fMax((UINT)pSSC->nInputChannels, (UINT)pGC->nInputChannels_requested); + } + pGC->nOutputChannels_requested = + fMax((UINT)pSSC->nOutputChannels, (UINT)pGC->nOutputChannels_requested); + } else { + if (sac_dec_interface == SAC_INTERFACE_TIME) { + /* For SAC_INTERFACE_QMF these parameters are set by SBR. */ + pGC->nBandsAnalysis_requested = mpegSurroundDecoder_GetNrOfQmfBands( + NULL, coreSamplingRate); /* coreSamplingRate == outputSamplingRate for + SAC_INTERFACE_TIME */ + pGC->nBandsSynthesis_requested = pGC->nBandsAnalysis_requested; + pGC->nInputChannels_requested = + pMpegSurroundDecoder->pSpatialDec->createParams.maxNumInputChannels; + } + pGC->nOutputChannels_requested = + pMpegSurroundDecoder->pSpatialDec->createParams.maxNumOutputChannels; + } + pGC->nQmfProcBands_requested = 64; + pGC->nQmfProcChannels_requested = + fMin((INT)pGC->nInputChannels_requested, + pMpegSurroundDecoder->pSpatialDec->createParams.maxNumInputChannels); + + if (coreCodec == AOT_ER_AAC_ELD) { + pGC->flags_requested |= QMF_FLAG_MPSLDFB; + } + + return err; +} + +/** + * \brief Decode MPEG Surround frame. + **/ +int mpegSurroundDecoder_ParseNoHeader( + CMpegSurroundDecoder *pMpegSurroundDecoder, HANDLE_FDK_BITSTREAM hBs, + int *pMpsDataBits, int fGlobalIndependencyFlag) { + SACDEC_ERROR err = MPS_OK; + SPATIAL_SPECIFIC_CONFIG *sscParse; + int bitsAvail, numSacBits; + + if (pMpegSurroundDecoder == NULL || hBs == NULL) { + return MPS_INVALID_HANDLE; + } + + sscParse = &pMpegSurroundDecoder + ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameParse]; + + bitsAvail = FDKgetValidBits(hBs); + + /* First spatial specific config is parsed into spatialSpecificConfigBackup, + * second spatialSpecificConfigBackup is copied into + * spatialSpecificConfig[bsFrameDecode] */ + if (pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameParse]) { + FDKmemcpy(sscParse, &pMpegSurroundDecoder->spatialSpecificConfigBackup, + sizeof(SPATIAL_SPECIFIC_CONFIG)); + pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameParse] = + MPEGS_SYNC_FOUND; + } + + if (bitsAvail <= 0) { + err = MPS_PARSE_ERROR; + } else { + err = SpatialDecParseFrameData( + pMpegSurroundDecoder->pSpatialDec, + &pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameParse], + hBs, sscParse, (UPMIXTYPE)pMpegSurroundDecoder->upmixType, + fGlobalIndependencyFlag); + if (err == MPS_OK) { + pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameParse] + .newBsData = 1; + } + } + + numSacBits = bitsAvail - (INT)FDKgetValidBits(hBs); + + if (numSacBits > bitsAvail) { + pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameParse] + .newBsData = 0; + err = MPS_PARSE_ERROR; + } + + *pMpsDataBits -= numSacBits; + + return err; +} + +/** + * \brief Check, if ancType is valid. + **/ +static int isValidAncType(CMpegSurroundDecoder *pMpegSurroundDecoder, + int ancType) { + int ret = 1; + + if ((ancType != MPEGS_ANCTYPE_HEADER_AND_FRAME) && + (ancType != MPEGS_ANCTYPE_FRAME)) { + ret = 0; + } + + if (ret == 0) { + updateMpegSurroundDecoderStatus(pMpegSurroundDecoder, + MPEGS_INIT_ERROR_PAYLOAD, MPEGS_SYNC_LOST, + MPEGS_STOP); + } + + return (ret); +} + +/** + * \brief Check, if ancStartStop is valid. + **/ +static int isValidAncStartStop(CMpegSurroundDecoder *pMpegSurroundDecoder, + int ancStartStop) { + int ret = 1; + + switch (ancStartStop) { + case MPEGS_START: + /* Sequence start - start and continue - start not allowed */ + if ((pMpegSurroundDecoder->ancStartStopPrev == MPEGS_START) || + (pMpegSurroundDecoder->ancStartStopPrev == MPEGS_CONTINUE)) { + ret = 0; + } + break; + + case MPEGS_STOP: + /* MPS payload of the previous frame must be valid if current type is stop + Sequence startstop - stop and stop - stop not allowed + Sequence startstop - continue and stop - continue are allowed */ + if ((pMpegSurroundDecoder->ancStartStopPrev == MPEGS_STOP) || + (pMpegSurroundDecoder->ancStartStopPrev == MPEGS_START_STOP)) { + ret = 0; + } + break; + + case MPEGS_CONTINUE: + case MPEGS_START_STOP: + /* No error detection possible for this states */ + break; + } + + if (ret == 0) { + updateMpegSurroundDecoderStatus(pMpegSurroundDecoder, + MPEGS_INIT_ERROR_PAYLOAD, MPEGS_SYNC_LOST, + MPEGS_STOP); + } else { + pMpegSurroundDecoder->ancStartStopPrev = (MPEGS_ANCSTARTSTOP)ancStartStop; + } + + return (ret); +} + +int mpegSurroundDecoder_Parse(CMpegSurroundDecoder *pMpegSurroundDecoder, + HANDLE_FDK_BITSTREAM hBs, int *pMpsDataBits, + AUDIO_OBJECT_TYPE coreCodec, int sampleRate, + int frameSize, int fGlobalIndependencyFlag) { + SACDEC_ERROR err = MPS_OK; + SPATIAL_SPECIFIC_CONFIG *sscParse; + SPATIAL_BS_FRAME *bsFrame; + HANDLE_FDK_BITSTREAM hMpsBsData = NULL; + FDK_BITSTREAM mpsBsData; + int mpsDataBits = *pMpsDataBits; + int mpsBsBits; + MPEGS_ANCTYPE ancType; + MPEGS_ANCSTARTSTOP ancStartStop; + + if (pMpegSurroundDecoder == NULL) { + return MPS_INVALID_HANDLE; + } + + FDK_ASSERT(pMpegSurroundDecoder->pSpatialDec); + + mpsBsBits = FDKgetValidBits(hBs); + + sscParse = &pMpegSurroundDecoder + ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameParse]; + bsFrame = &pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameParse]; + + /* + Find operation mode of mpeg surround decoder: + - MPEGS_OPMODE_EMM: Mode: Enhanced Matrix Mode (Blind) + - MPEGS_OPMODE_MPS_PAYLOAD: Mode: Normal, Stereo or Binaural + - MPEGS_OPMODE_NO_MPS_PAYLOAD: Mode: No MpegSurround Payload + */ + { + /* Parse ancType and ancStartStop */ + ancType = (MPEGS_ANCTYPE)FDKreadBits(hBs, 2); + ancStartStop = (MPEGS_ANCSTARTSTOP)FDKreadBits(hBs, 2); + mpsDataBits -= 4; + + /* Set valid anc type flag, if ancType signals a payload with either header + * and frame or frame */ + if (isValidAncType(pMpegSurroundDecoder, ancType)) { + /* Set valid anc startstop flag, if transmitted sequence is not illegal */ + if (isValidAncStartStop(pMpegSurroundDecoder, ancStartStop)) { + switch (ancStartStop) { + case MPEGS_START: + /* Assuming that core coder frame size (AAC) is smaller than MPS + coder frame size. Save audio data for next frame. */ + if (mpsDataBits > MPS_DATA_BUFFER_SIZE * 8) { + err = MPS_NOTOK; + goto bail; + } + for (int i = 0; i < mpsDataBits / 8; i++) { + pMpegSurroundDecoder->mpsData[i] = FDKreadBits(hBs, 8); + } + pMpegSurroundDecoder->mpsDataBits = mpsDataBits; + break; + + case MPEGS_CONTINUE: + case MPEGS_STOP: + /* Assuming that core coder frame size (AAC) is smaller than MPS + coder frame size. Save audio data for next frame. */ + if ((pMpegSurroundDecoder->mpsDataBits + mpsDataBits) > + MPS_DATA_BUFFER_SIZE * 8) { + err = MPS_NOTOK; + goto bail; + } + for (int i = 0; i < mpsDataBits / 8; i++) { + pMpegSurroundDecoder + ->mpsData[(pMpegSurroundDecoder->mpsDataBits / 8) + i] = + FDKreadBits(hBs, 8); + } + pMpegSurroundDecoder->mpsDataBits += mpsDataBits; + FDKinitBitStream(&mpsBsData, pMpegSurroundDecoder->mpsData, + MAX_BUFSIZE_BYTES, + pMpegSurroundDecoder->mpsDataBits, BS_READER); + hMpsBsData = &mpsBsData; + break; + + case MPEGS_START_STOP: + pMpegSurroundDecoder->mpsDataBits = mpsDataBits; + hMpsBsData = hBs; + break; + + default: + FDK_ASSERT(0); + } + + if ((ancStartStop == MPEGS_STOP) || + (ancStartStop == MPEGS_START_STOP)) { + switch (ancType) { + case MPEGS_ANCTYPE_HEADER_AND_FRAME: { + int parseResult, bitsRead; + SPATIAL_SPECIFIC_CONFIG spatialSpecificConfigTmp = + pMpegSurroundDecoder->spatialSpecificConfigBackup; + + /* Parse spatial specific config */ + bitsRead = FDKgetValidBits(hMpsBsData); + + err = SpatialDecParseSpecificConfigHeader( + hMpsBsData, + &pMpegSurroundDecoder->spatialSpecificConfigBackup, coreCodec, + pMpegSurroundDecoder->upmixType); + + bitsRead = (bitsRead - FDKgetValidBits(hMpsBsData)); + parseResult = ((err == MPS_OK) ? bitsRead : -bitsRead); + + if (parseResult < 0) { + parseResult = -parseResult; + err = MPS_PARSE_ERROR; + } else if (err == MPS_OK) { + /* Check SSC for consistency (e.g. bit errors could cause + * trouble) */ + err = sscCheckInBand( + &pMpegSurroundDecoder->spatialSpecificConfigBackup, + frameSize, sampleRate); + } + if (err != MPS_OK) { + pMpegSurroundDecoder->spatialSpecificConfigBackup = + spatialSpecificConfigTmp; + break; + } + + pMpegSurroundDecoder->mpsDataBits -= parseResult; + + /* Initiate re-initialization, if header has changed */ + if (FDK_SpatialDecCompareSpatialSpecificConfigHeader( + &pMpegSurroundDecoder->spatialSpecificConfigBackup, + sscParse) == MPS_UNEQUAL_SSC) { + pMpegSurroundDecoder + ->initFlags[pMpegSurroundDecoder->bsFrameParse] |= + MPEGS_INIT_CHANGE_HEADER; + SpatialDecInitParserContext(pMpegSurroundDecoder->pSpatialDec); + /* We found a valid in-band configuration. Therefore any + * previous config is invalid now. */ + pMpegSurroundDecoder->mpegSurroundSscIsGlobalCfg = 0; + } + } + case MPEGS_ANCTYPE_FRAME: + + if (pMpegSurroundDecoder + ->initFlags[pMpegSurroundDecoder->bsFrameParse] & + MPEGS_INIT_ERROR_PAYLOAD) { + err = MPS_PARSE_ERROR; + break; + } + + /* First spatial specific config is parsed into + * spatialSpecificConfigBackup, second spatialSpecificConfigBackup + * is copied into spatialSpecificConfig[bsFrameDecode] */ + if (pMpegSurroundDecoder + ->initFlags[pMpegSurroundDecoder->bsFrameParse]) { + FDKmemcpy(sscParse, + &pMpegSurroundDecoder->spatialSpecificConfigBackup, + sizeof(SPATIAL_SPECIFIC_CONFIG)); + pMpegSurroundDecoder + ->fOnSync[pMpegSurroundDecoder->bsFrameParse] = + MPEGS_SYNC_FOUND; + } + + if (pMpegSurroundDecoder + ->fOnSync[pMpegSurroundDecoder->bsFrameParse] >= + MPEGS_SYNC_FOUND) { + int nbits = 0, bitsAvail; + + if (err != MPS_OK) { + break; + } + + bitsAvail = FDKgetValidBits(hMpsBsData); + + if (bitsAvail <= 0) { + err = MPS_PARSE_ERROR; + } else { + err = SpatialDecParseFrameData( + pMpegSurroundDecoder->pSpatialDec, bsFrame, hMpsBsData, + sscParse, (UPMIXTYPE)pMpegSurroundDecoder->upmixType, + fGlobalIndependencyFlag); + if (err == MPS_OK) { + bsFrame->newBsData = 1; + } + } + + nbits = bitsAvail - (INT)FDKgetValidBits(hMpsBsData); + + if ((nbits > bitsAvail) || + (nbits > pMpegSurroundDecoder->mpsDataBits) || + (pMpegSurroundDecoder->mpsDataBits > nbits + 7 && + !IS_LOWDELAY(coreCodec))) { + bsFrame->newBsData = 0; + err = MPS_PARSE_ERROR; + break; + } + pMpegSurroundDecoder->mpsDataBits -= nbits; + } + break; + + default: /* added to avoid compiler warning */ + err = MPS_NOTOK; + break; /* added to avoid compiler warning */ + } /* switch (ancType) */ + + if (err == MPS_OK) { + pMpegSurroundDecoder->ancStartStopPrev = ancStartStop; + } else { + updateMpegSurroundDecoderStatus(pMpegSurroundDecoder, + MPEGS_INIT_ERROR_PAYLOAD, + MPEGS_SYNC_LOST, MPEGS_STOP); + pMpegSurroundDecoder->mpsDataBits = 0; + } + } /* (ancStartStop == MPEGS_STOP) || (ancStartStop == MPEGS_START_STOP) + */ + } /* validAncStartStop */ + } /* validAncType */ + } + +bail: + + *pMpsDataBits -= (mpsBsBits - FDKgetValidBits(hBs)); + + return err; +} + +int mpegSurroundDecoder_Apply(CMpegSurroundDecoder *pMpegSurroundDecoder, + INT_PCM *input, PCM_MPS *pTimeData, + const int timeDataSize, int timeDataFrameSize, + int *nChannels, int *frameSize, int sampleRate, + AUDIO_OBJECT_TYPE coreCodec, + AUDIO_CHANNEL_TYPE channelType[], + UCHAR channelIndices[], + const FDK_channelMapDescr *const mapDescr) { + SACDEC_ERROR err = MPS_OK; + PCM_MPS *pTimeOut = pTimeData; + UINT initControlFlags = 0, controlFlags = 0; + int timeDataRequiredSize = 0; + int newData; + + if (pMpegSurroundDecoder == NULL) { + return MPS_INVALID_HANDLE; + } + + FDK_ASSERT(pMpegSurroundDecoder->pSpatialDec); + + if (!FDK_chMapDescr_isValid(mapDescr)) { + return MPS_INVALID_HANDLE; + } + + if ((*nChannels <= 0) || (*nChannels > 2)) { + return MPS_NOTOK; + } + + pMpegSurroundDecoder->pSpatialDec->pConfigCurrent = + &pMpegSurroundDecoder + ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameDecode]; + newData = pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameParse] + .newBsData; + + switch (mpegSurroundOperationMode(pMpegSurroundDecoder, 1000)) { + case MPEGS_OPMODE_MPS_PAYLOAD: + if (pMpegSurroundDecoder + ->initFlags[pMpegSurroundDecoder->bsFrameDecode]) { + err = initMpegSurroundDecoder(pMpegSurroundDecoder); + } + + if (err == MPS_OK) { + if ((pMpegSurroundDecoder + ->fOnSync[pMpegSurroundDecoder->bsFrameDecode] != + MPEGS_SYNC_COMPLETE) && + (pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameDecode] + .bsIndependencyFlag == 1)) { + /* We got a valid header and independently decodeable frame data. + -> Go to the next sync level and start processing. */ + pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] = + MPEGS_SYNC_COMPLETE; + } + } else { + /* We got a valid config header but found an error while parsing the + bitstream. Wait for the next independent frame and apply error + conealment in the meantime. */ + pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] = + MPEGS_SYNC_FOUND; + controlFlags |= MPEGS_CONCEAL; + err = MPS_OK; + } + /* + Concealment: + - Bitstream is available, no sync found during bitstream processing + - Bitstream is available, sync lost due to corrupted bitstream + - Bitstream is available, sync found but no independent frame + */ + if (pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] != + MPEGS_SYNC_COMPLETE) { + controlFlags |= MPEGS_CONCEAL; + } + break; + + case MPEGS_OPMODE_NO_MPS_PAYLOAD: + /* Concealment: No bitstream is available */ + controlFlags |= MPEGS_CONCEAL; + break; + + default: + err = MPS_NOTOK; + } + + if (err != MPS_OK) { + goto bail; + } + + /* + * Force BypassMode if choosen by user + */ + if (pMpegSurroundDecoder->mpegSurroundUserParams.bypassMode) { + controlFlags |= MPEGS_BYPASSMODE; + } + + if (pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode]) { + int startWithDfltCfg = 0; + /* + * Init with a default configuration if we came here and are still not + * initialized. + */ + if (pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] & + MPEGS_INIT_ENFORCE_REINIT) { + /* Get default spatial specific config */ + if (FDK_SpatialDecInitDefaultSpatialSpecificConfig( + &pMpegSurroundDecoder->spatialSpecificConfigBackup, coreCodec, + *nChannels, sampleRate, + *frameSize / + mpegSurroundDecoder_GetNrOfQmfBands(NULL, sampleRate), + pMpegSurroundDecoder->mpegSurroundDecoderLevel, + pMpegSurroundDecoder->mpegSurroundUserParams.blindEnable)) { + err = MPS_NOTOK; + goto bail; + } + + /* Initiate re-initialization, if header has changed */ + if (FDK_SpatialDecCompareSpatialSpecificConfigHeader( + &pMpegSurroundDecoder->spatialSpecificConfigBackup, + &pMpegSurroundDecoder->spatialSpecificConfig + [pMpegSurroundDecoder->bsFrameDecode]) == MPS_UNEQUAL_SSC) { + pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |= + MPEGS_INIT_CHANGE_HEADER; + SpatialDecInitParserContext(pMpegSurroundDecoder->pSpatialDec); + } + + startWithDfltCfg = 1; + } + + /* First spatial specific config is parsed into spatialSpecificConfigBackup, + * second spatialSpecificConfigBackup is copied into spatialSpecificConfig + */ + err = initMpegSurroundDecoder(pMpegSurroundDecoder); + + if (startWithDfltCfg) { + /* initialized with default config, but no sync found */ + /* maybe use updateMpegSurroundDecoderStatus later on */ + pMpegSurroundDecoder->fOnSync[pMpegSurroundDecoder->bsFrameDecode] = + MPEGS_SYNC_LOST; + } + + /* Since we do not have state MPEGS_SYNC_COMPLETE apply concealment */ + controlFlags |= MPEGS_CONCEAL; + + if (err != MPS_OK) { + goto bail; + } + } + + /* + * Process MPEG Surround Audio + */ + initControlFlags = controlFlags; + + /* Check that provided output buffer is large enough. */ + timeDataRequiredSize = + (timeDataFrameSize * + pMpegSurroundDecoder->pSpatialDec->numOutputChannelsAT * + pMpegSurroundDecoder->pQmfDomain->globalConf.nBandsSynthesis) / + pMpegSurroundDecoder->pQmfDomain->globalConf.nBandsAnalysis; + if (timeDataSize < timeDataRequiredSize) { + err = MPS_OUTPUT_BUFFER_TOO_SMALL; + goto bail; + } + + if ((pMpegSurroundDecoder->pSpatialDec->pConfigCurrent->syntaxFlags & + SACDEC_SYNTAX_USAC) && + (pMpegSurroundDecoder->pSpatialDec->stereoConfigIndex > 1)) { + FDK_ASSERT(timeDataRequiredSize >= timeDataFrameSize * *nChannels); + /* Place samples comprising QMF time slots spaced at QMF output Band raster + * to allow slot wise processing */ + int timeDataFrameSizeOut = + (timeDataFrameSize * + pMpegSurroundDecoder->pQmfDomain->globalConf.nBandsSynthesis) / + pMpegSurroundDecoder->pQmfDomain->globalConf.nBandsAnalysis; + pMpegSurroundDecoder->pQmfDomain->globalConf.TDinput = + pTimeData + timeDataFrameSizeOut - timeDataFrameSize; + for (int i = *nChannels - 1; i >= 0; i--) { + FDKmemmove(pTimeData + (i + 1) * timeDataFrameSizeOut - timeDataFrameSize, + pTimeData + timeDataFrameSize * i, + sizeof(PCM_MPS) * timeDataFrameSize); + FDKmemclear(pTimeData + i * timeDataFrameSizeOut, + sizeof(PCM_MPS) * (timeDataFrameSizeOut - timeDataFrameSize)); + } + } else { + if (pMpegSurroundDecoder->mpegSurroundUseTimeInterface) { + FDKmemcpy(input, pTimeData, + sizeof(INT_PCM) * (*nChannels) * (*frameSize)); + pMpegSurroundDecoder->pQmfDomain->globalConf.TDinput = input; + } + } + + /* + * Process MPEG Surround Audio + */ + err = SpatialDecApplyFrame( + pMpegSurroundDecoder->pSpatialDec, + &pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameDecode], + pMpegSurroundDecoder->mpegSurroundUseTimeInterface ? INPUTMODE_TIME + : INPUTMODE_QMF_SBR, + pMpegSurroundDecoder->pQmfDomain->globalConf.TDinput, NULL, NULL, + pTimeOut, *frameSize, &controlFlags, *nChannels, mapDescr); + *nChannels = pMpegSurroundDecoder->pSpatialDec->numOutputChannelsAT; + + if (err != + MPS_OK) { /* A fatal error occured. Go back to start and try again: */ + updateMpegSurroundDecoderStatus(pMpegSurroundDecoder, + MPEGS_INIT_ENFORCE_REINIT, MPEGS_SYNC_LOST, + MPEGS_STOP); + *frameSize = + 0; /* Declare that framework can not use the data in pTimeOut. */ + } else { + if (((controlFlags & MPEGS_CONCEAL) && + !(initControlFlags & MPEGS_CONCEAL)) || + (pMpegSurroundDecoder->pSpatialDec->errInt != + MPS_OK)) { /* Account for errors that occured in + SpatialDecApplyFrame(): */ + updateMpegSurroundDecoderStatus(pMpegSurroundDecoder, + MPEGS_INIT_ERROR_PAYLOAD, MPEGS_SYNC_LOST, + MPEGS_STOP); + } + } + + if ((err == MPS_OK) && !(controlFlags & MPEGS_BYPASSMODE) && + !(pMpegSurroundDecoder->upmixType == UPMIX_TYPE_BYPASS)) { + SpatialDecChannelProperties(pMpegSurroundDecoder->pSpatialDec, channelType, + channelIndices, mapDescr); + } + +bail: + + if (newData) { + /* numParameterSetsPrev shall only be read in the decode process, because of + that we can update this state variable here */ + pMpegSurroundDecoder->pSpatialDec->numParameterSetsPrev = + pMpegSurroundDecoder->bsFrames[pMpegSurroundDecoder->bsFrameDecode] + .numParameterSets; + } + + return (err); +} + +/** + * \brief Free config dependent MPEG Surround memory. + **/ +SACDEC_ERROR mpegSurroundDecoder_FreeMem( + CMpegSurroundDecoder *pMpegSurroundDecoder) { + SACDEC_ERROR err = MPS_OK; + + if (pMpegSurroundDecoder != NULL) { + FDK_SpatialDecClose(pMpegSurroundDecoder->pSpatialDec); + pMpegSurroundDecoder->pSpatialDec = NULL; + } + + return err; +} + +/** + * \brief Close MPEG Surround decoder. + **/ +void mpegSurroundDecoder_Close(CMpegSurroundDecoder *pMpegSurroundDecoder) { + if (pMpegSurroundDecoder != NULL) { + FDK_SpatialDecClose(pMpegSurroundDecoder->pSpatialDec); + pMpegSurroundDecoder->pSpatialDec = NULL; + + for (int i = 0; i < 1; i++) { + SpatialDecCloseBsFrame(&pMpegSurroundDecoder->bsFrames[i]); + } + + FDK_FREE_MEMORY_1D(pMpegSurroundDecoder); + } +} + +#define SACDEC_VL0 2 +#define SACDEC_VL1 0 +#define SACDEC_VL2 0 + +int mpegSurroundDecoder_GetLibInfo(LIB_INFO *info) { + int i; + + if (info == NULL) { + return -1; + } + + /* search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) return -1; + + info += i; + + info->module_id = FDK_MPSDEC; +#ifdef __ANDROID__ + info->build_date = ""; + info->build_time = ""; +#else + info->build_date = __DATE__; + info->build_time = __TIME__; +#endif + info->title = "MPEG Surround Decoder"; + info->version = LIB_VERSION(SACDEC_VL0, SACDEC_VL1, SACDEC_VL2); + LIB_VERSION_STRING(info); + info->flags = 0 | CAPF_MPS_LD | CAPF_MPS_USAC | CAPF_MPS_HQ | + CAPF_MPS_1CH_IN | CAPF_MPS_2CH_OUT; /* end flags */ + + return 0; +} + +SACDEC_ERROR mpegSurroundDecoder_SetParam( + CMpegSurroundDecoder *pMpegSurroundDecoder, const SACDEC_PARAM param, + const INT value) { + SACDEC_ERROR err = MPS_OK; + SPATIALDEC_PARAM *pUserParams = NULL; + + /* check decoder handle */ + if (pMpegSurroundDecoder != NULL) { + /* init local shortcuts */ + pUserParams = &pMpegSurroundDecoder->mpegSurroundUserParams; + } else { + err = MPS_INVALID_HANDLE; + /* check the parameter values before exiting. */ + } + + /* apply param value */ + switch (param) { + case SACDEC_OUTPUT_MODE: + switch ((SAC_DEC_OUTPUT_MODE)value) { + case SACDEC_OUT_MODE_NORMAL: + case SACDEC_OUT_MODE_STEREO: + break; + default: + err = MPS_INVALID_PARAMETER; + } + if (err == MPS_OK) { + if (0) { + err = MPS_INVALID_PARAMETER; + } else if (pUserParams->outputMode != (UCHAR)value) { + pUserParams->outputMode = (UCHAR)value; + pMpegSurroundDecoder + ->initFlags[pMpegSurroundDecoder->bsFrameDecode] |= + MPEGS_INIT_CHANGE_OUTPUT_MODE; + } + } + break; + + case SACDEC_INTERFACE: + if (value < 0 || value > 1) { + err = MPS_INVALID_PARAMETER; + } + if (err != MPS_OK) { + goto bail; + } + if (pMpegSurroundDecoder->mpegSurroundUseTimeInterface != (UCHAR)value) { + pMpegSurroundDecoder->mpegSurroundUseTimeInterface = (UCHAR)value; + pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |= + MPEGS_INIT_CHANGE_TIME_FREQ_INTERFACE; + } + break; + + case SACDEC_BS_INTERRUPTION: + if ((err == MPS_OK) && (value != 0)) { + updateMpegSurroundDecoderStatus(pMpegSurroundDecoder, + MPEGS_INIT_BS_INTERRUPTION, + MPEGS_SYNC_LOST, MPEGS_STOP); + } + break; + + case SACDEC_CLEAR_HISTORY: + if ((err == MPS_OK) && (value != 0)) { + /* Just reset the states and go on. */ + updateMpegSurroundDecoderStatus(pMpegSurroundDecoder, + MPEGS_INIT_CLEAR_HISTORY, + MPEGS_SYNC_LOST, MPEGS_STOP); + } + break; + + case SACDEC_CONCEAL_NUM_KEEP_FRAMES: + if (value < 0) { /* Check valid value range */ + err = MPS_INVALID_PARAMETER; + } + if (err != MPS_OK) { + goto bail; + } + if (pUserParams->concealNumKeepFrames != (UINT)value) { + pUserParams->concealNumKeepFrames = (UINT)value; + pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |= + MPEGS_INIT_CHANGE_CONCEAL_PARAMS; + } + break; + + case SACDEC_CONCEAL_FADE_OUT_SLOPE_LENGTH: + if (value < 0) { /* Check valid value range */ + err = MPS_INVALID_PARAMETER; + } + if (err != MPS_OK) { + goto bail; + } + if (pUserParams->concealFadeOutSlopeLength != (UINT)value) { + pUserParams->concealFadeOutSlopeLength = (UINT)value; + pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |= + MPEGS_INIT_CHANGE_CONCEAL_PARAMS; + } + break; + + case SACDEC_CONCEAL_FADE_IN_SLOPE_LENGTH: + if (value < 0) { /* Check valid value range */ + err = MPS_INVALID_PARAMETER; + } + if (err != MPS_OK) { + goto bail; + } + if (pUserParams->concealFadeInSlopeLength != (UINT)value) { + pUserParams->concealFadeInSlopeLength = (UINT)value; + pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |= + MPEGS_INIT_CHANGE_CONCEAL_PARAMS; + } + break; + + case SACDEC_CONCEAL_NUM_RELEASE_FRAMES: + if (value < 0) { /* Check valid value range */ + err = MPS_INVALID_PARAMETER; + } + if (err != MPS_OK) { + goto bail; + } + if (pUserParams->concealNumReleaseFrames != (UINT)value) { + pUserParams->concealNumReleaseFrames = (UINT)value; + pMpegSurroundDecoder->initFlags[pMpegSurroundDecoder->bsFrameDecode] |= + MPEGS_INIT_CHANGE_CONCEAL_PARAMS; + } + break; + + default: + err = MPS_INVALID_PARAMETER; + break; + } /* switch(param) */ + +bail: + return err; +} + +SACDEC_ERROR mpegSurroundDecoder_IsPseudoLR( + CMpegSurroundDecoder *pMpegSurroundDecoder, int *bsPseudoLr) { + if (pMpegSurroundDecoder != NULL) { + const SPATIAL_SPECIFIC_CONFIG *sscDecode = + &pMpegSurroundDecoder + ->spatialSpecificConfig[pMpegSurroundDecoder->bsFrameDecode]; + *bsPseudoLr = (int)sscDecode->bsPseudoLr; + return MPS_OK; + } else + return MPS_INVALID_HANDLE; +} + +/** + * \brief Get the signal delay caused by the MPEG Surround decoder module. + **/ +UINT mpegSurroundDecoder_GetDelay(const CMpegSurroundDecoder *self) { + INT outputDelay = 0; + + if (self != NULL) { + const SPATIAL_SPECIFIC_CONFIG *sscDecode = + &self->spatialSpecificConfig[self->bsFrameDecode]; + AUDIO_OBJECT_TYPE coreCodec = sscDecode->coreCodec; + + /* See chapter 4.5 (delay and synchronization) of ISO/IEC FDIS 23003-1 and + chapter 5.4.3 of ISO/IEC FDIS 23003-2 for details on the following + figures. */ + + if (coreCodec > AOT_NULL_OBJECT) { + if (IS_LOWDELAY(coreCodec)) { + /* All low delay variants (ER-AAC-(E)LD): */ + outputDelay += 256; + } else if (!IS_USAC(coreCodec)) { + /* By the method of elimination this is the GA (AAC-LC, HE-AAC, ...) + * branch: */ + outputDelay += 320 + 257; /* cos to exp delay + QMF synthesis */ + if (self->mpegSurroundUseTimeInterface) { + outputDelay += 320 + 384; /* QMF and hybrid analysis */ + } + } + } + } + + return (outputDelay); +} diff --git a/libSACdec/src/sac_dec_ssc_struct.h b/libSACdec/src/sac_dec_ssc_struct.h new file mode 100644 index 0000000..b67b465 --- /dev/null +++ b/libSACdec/src/sac_dec_ssc_struct.h @@ -0,0 +1,283 @@ +/* ----------------------------------------------------------------------------- +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: interface - spatial specific config struct + +*******************************************************************************/ + +#ifndef SAC_DEC_SSC_STRUCT_H +#define SAC_DEC_SSC_STRUCT_H + +#include "FDK_audio.h" + +#define MAX_NUM_QMF_BANDS (128) +#define MAX_TIME_SLOTS 64 +#define MAX_INPUT_CHANNELS 1 +#define MAX_OUTPUT_CHANNELS \ + 2 /* CAUTION: This does NOT restrict the number of \ + output channels exclusively! In addition it \ + affects the max number of bitstream and residual channels! */ +#define MAX_NUM_OTT (5) +#define MAX_NUM_TTT (0) +#define MAX_NUM_EXT_TYPES (8) +#define MAX_PARAMETER_BANDS (28) +#define MAX_PARAMETER_BANDS_LD (23) + +#define MAX_NUM_XCHANNELS (6) + +#define MAX_ARBITRARY_TREE_LEVELS (0) + +typedef enum { + /* CAUTION: Do not change enum values! */ + SPATIALDEC_FREQ_RES_40 = 40, + SPATIALDEC_FREQ_RES_28 = 28, + SPATIALDEC_FREQ_RES_23 = 23, + SPATIALDEC_FREQ_RES_20 = 20, + SPATIALDEC_FREQ_RES_15 = 15, + SPATIALDEC_FREQ_RES_14 = 14, + SPATIALDEC_FREQ_RES_12 = 12, + SPATIALDEC_FREQ_RES_10 = 10, + SPATIALDEC_FREQ_RES_9 = 9, + SPATIALDEC_FREQ_RES_7 = 7, + SPATIALDEC_FREQ_RES_5 = 5, + SPATIALDEC_FREQ_RES_4 = 4 + +} SPATIALDEC_FREQ_RES; + +typedef enum { + + SPATIALDEC_QUANT_FINE_DEF = 0, + SPATIALDEC_QUANT_EDQ1 = 1, + SPATIALDEC_QUANT_EDQ2 = 2, + SPATIALDEC_QUANT_RSVD3 = 3, + SPATIALDEC_QUANT_RSVD4 = 4, + SPATIALDEC_QUANT_RSVD5 = 5, + SPATIALDEC_QUANT_RSVD6 = 6, + SPATIALDEC_QUANT_RSVD7 = 7 + +} SPATIALDEC_QUANT_MODE; + +typedef enum { SPATIALDEC_MODE_RSVD7 = 7 } SPATIALDEC_TREE_CONFIG; + +typedef enum { + + SPATIALDEC_GAIN_MODE0 = 0, + SPATIALDEC_GAIN_RSVD1 = 1, + SPATIALDEC_GAIN_RSVD2 = 2, + SPATIALDEC_GAIN_RSVD3 = 3, + SPATIALDEC_GAIN_RSVD4 = 4, + SPATIALDEC_GAIN_RSVD5 = 5, + SPATIALDEC_GAIN_RSVD6 = 6, + SPATIALDEC_GAIN_RSVD7 = 7, + SPATIALDEC_GAIN_RSVD8 = 8, + SPATIALDEC_GAIN_RSVD9 = 9, + SPATIALDEC_GAIN_RSVD10 = 10, + SPATIALDEC_GAIN_RSVD11 = 11, + SPATIALDEC_GAIN_RSVD12 = 12, + SPATIALDEC_GAIN_RSVD13 = 13, + SPATIALDEC_GAIN_RSVD14 = 14, + SPATIALDEC_GAIN_RSVD15 = 15 + +} SPATIALDEC_FIXED_GAINS; + +typedef enum { + + SPATIALDEC_TS_TPNOWHITE = 0, + SPATIALDEC_TS_TPWHITE = 1, + SPATIALDEC_TS_TES = 2, + SPATIALDEC_TS_NOTS = 3, + SPATIALDEC_TS_RSVD4 = 4, + SPATIALDEC_TS_RSVD5 = 5, + SPATIALDEC_TS_RSVD6 = 6, + SPATIALDEC_TS_RSVD7 = 7, + SPATIALDEC_TS_RSVD8 = 8, + SPATIALDEC_TS_RSVD9 = 9, + SPATIALDEC_TS_RSVD10 = 10, + SPATIALDEC_TS_RSVD11 = 11, + SPATIALDEC_TS_RSVD12 = 12, + SPATIALDEC_TS_RSVD13 = 13, + SPATIALDEC_TS_RSVD14 = 14, + SPATIALDEC_TS_RSVD15 = 15 + +} SPATIALDEC_TS_CONF; + +typedef enum { + + SPATIALDEC_DECORR_MODE0 = 0, + SPATIALDEC_DECORR_MODE1 = 1, + SPATIALDEC_DECORR_MODE2 = 2, + SPATIALDEC_DECORR_RSVD3 = 3, + SPATIALDEC_DECORR_RSVD4 = 4, + SPATIALDEC_DECORR_RSVD5 = 5, + SPATIALDEC_DECORR_RSVD6 = 6, + SPATIALDEC_DECORR_RSVD7 = 7, + SPATIALDEC_DECORR_RSVD8 = 8, + SPATIALDEC_DECORR_RSVD9 = 9, + SPATIALDEC_DECORR_RSVD10 = 10, + SPATIALDEC_DECORR_RSVD11 = 11, + SPATIALDEC_DECORR_RSVD12 = 12, + SPATIALDEC_DECORR_RSVD13 = 13, + SPATIALDEC_DECORR_RSVD14 = 14, + SPATIALDEC_DECORR_RSVD15 = 15 + +} SPATIALDEC_DECORR_CONF; + +typedef struct T_SPATIALDEC_OTT_CONF { + int nOttBands; + +} SPATIALDEC_OTT_CONF; + +typedef struct T_SPATIALDEC_RESIDUAL_CONF { + int bResidualPresent; + int nResidualBands; + +} SPATIALDEC_RESIDUAL_CONF; + +typedef struct T_SPATIAL_SPECIFIC_CONFIG { + UINT syntaxFlags; + int samplingFreq; + int nTimeSlots; + SPATIALDEC_FREQ_RES freqRes; + SPATIALDEC_TREE_CONFIG treeConfig; + SPATIALDEC_QUANT_MODE quantMode; + int bArbitraryDownmix; + + int bResidualCoding; + SPATIALDEC_FIXED_GAINS bsFixedGainDMX; + + SPATIALDEC_TS_CONF tempShapeConfig; + SPATIALDEC_DECORR_CONF decorrConfig; + + int nInputChannels; /* derived from treeConfig */ + int nOutputChannels; /* derived from treeConfig */ + + /* ott config */ + int nOttBoxes; /* derived from treeConfig */ + SPATIALDEC_OTT_CONF OttConfig[MAX_NUM_OTT]; /* dimension nOttBoxes */ + + /* ttt config */ + int nTttBoxes; /* derived from treeConfig */ + + /* residual config */ + SPATIALDEC_RESIDUAL_CONF + ResidualConfig[MAX_NUM_OTT + + MAX_NUM_TTT]; /* dimension (nOttBoxes + nTttBoxes) */ + + int sacExtCnt; + int sacExtType[MAX_NUM_EXT_TYPES]; + int envQuantMode; + + AUDIO_OBJECT_TYPE coreCodec; + + UCHAR stereoConfigIndex; + UCHAR coreSbrFrameLengthIndex; /* Table 70 in ISO/IEC FDIS 23003-3:2011 */ + UCHAR bsHighRateMode; + UCHAR bsDecorrType; + UCHAR bsPseudoLr; + UCHAR bsPhaseCoding; + UCHAR bsOttBandsPhasePresent; + int bsOttBandsPhase; + + SCHAR ottCLDdefault[MAX_NUM_OTT]; + UCHAR numOttBandsIPD; + UCHAR bitstreamOttBands[MAX_NUM_OTT]; + UCHAR numOttBands[MAX_NUM_OTT]; + +} SPATIAL_SPECIFIC_CONFIG; + +#endif diff --git a/libSACdec/src/sac_process.cpp b/libSACdec/src/sac_process.cpp new file mode 100644 index 0000000..56c72ad --- /dev/null +++ b/libSACdec/src/sac_process.cpp @@ -0,0 +1,1066 @@ +/* ----------------------------------------------------------------------------- +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 Processing + +*******************************************************************************/ + +/* data structures and interfaces for spatial audio reference software */ +#include "sac_process.h" + +#include "sac_bitdec.h" +#include "sac_calcM1andM2.h" +#include "sac_smoothing.h" +#include "sac_rom.h" + +#include "sac_dec_errorcodes.h" + +#include "FDK_trigFcts.h" +#include "FDK_decorrelate.h" + +/** + * \brief Linear interpolation between two parameter values. + * a*alpha + b*(1-alpha) + * = a*alpha + b - b*alpha + * + * \param alpha Weighting factor. + * \param a Parameter a. + * \param b Parameter b. + * + * \return Interpolated parameter value. + */ +FDK_INLINE FIXP_DBL interpolateParameter(const FIXP_SGL alpha, const FIXP_DBL a, + const FIXP_DBL b) { + return (b - fMult(alpha, b) + fMult(alpha, a)); +} + +/** + * \brief Map MPEG Surround channel indices to MPEG 4 PCE like channel indices. + * \param self Spatial decoder handle. + * \param ch MPEG Surround channel index. + * \return MPEG 4 PCE style channel index, corresponding to the given MPEG + * Surround channel index. + */ +static UINT mapChannel(spatialDec *self, UINT ch) { + static const UCHAR chanelIdx[][8] = { + {0, 1, 2, 3, 4, 5, 6, 7}, /* binaural, TREE_212, arbitrary tree */ + }; + + int idx = 0; + + return (chanelIdx[idx][ch]); +} + +FIXP_DBL getChGain(spatialDec *self, UINT ch, INT *scale) { + /* init no gain modifier */ + FIXP_DBL gain = 0x80000000; + *scale = 0; + + if ((!isTwoChMode(self->upmixType)) && + (self->upmixType != UPMIXTYPE_BYPASS)) { + if ((ch == 0) || (ch == 1) || (ch == 2)) { + /* no modifier */ + } + } + + return gain; +} + +SACDEC_ERROR SpatialDecQMFAnalysis(spatialDec *self, const PCM_MPS *inData, + const INT ts, const INT bypassMode, + FIXP_DBL **qmfReal, FIXP_DBL **qmfImag, + const int numInputChannels) { + SACDEC_ERROR err = MPS_OK; + int ch, offset; + + offset = self->pQmfDomain->globalConf.nBandsSynthesis * + self->pQmfDomain->globalConf.nQmfTimeSlots; + + { + for (ch = 0; ch < numInputChannels; ch++) { + const PCM_MPS *inSamples = + &inData[ts * self->pQmfDomain->globalConf.nBandsAnalysis]; + FIXP_DBL *pQmfRealAnalysis = qmfReal[ch]; /* no delay in blind mode */ + FIXP_DBL *pQmfImagAnalysis = qmfImag[ch]; + + CalculateSpaceAnalysisQmf(&self->pQmfDomain->QmfDomainIn[ch].fb, + inSamples + (ch * offset), pQmfRealAnalysis, + pQmfImagAnalysis); + + if (!isTwoChMode(self->upmixType) && !bypassMode) { + int i; + for (i = 0; i < self->qmfBands; i++) { + qmfReal[ch][i] = fMult(qmfReal[ch][i], self->clipProtectGain__FDK); + qmfImag[ch][i] = fMult(qmfImag[ch][i], self->clipProtectGain__FDK); + } + } + } + } + + self->qmfInputDelayBufPos = + (self->qmfInputDelayBufPos + 1) % self->pc_filterdelay; + + return err; +} + +SACDEC_ERROR SpatialDecFeedQMF(spatialDec *self, FIXP_DBL **qmfInDataReal, + FIXP_DBL **qmfInDataImag, const INT ts, + const INT bypassMode, FIXP_DBL **qmfReal__FDK, + FIXP_DBL **qmfImag__FDK, + const INT numInputChannels) { + SACDEC_ERROR err = MPS_OK; + int ch; + + { + for (ch = 0; ch < numInputChannels; ch++) { + FIXP_DBL *pQmfRealAnalysis = + qmfReal__FDK[ch]; /* no delay in blind mode */ + FIXP_DBL *pQmfImagAnalysis = qmfImag__FDK[ch]; + + /* Write Input data to pQmfRealAnalysis. */ + if (self->bShareDelayWithSBR) { + FDK_QmfDomain_GetSlot( + &self->pQmfDomain->QmfDomainIn[ch], ts + HYBRID_FILTER_DELAY, 0, + MAX_QMF_BANDS_TO_HYBRID, pQmfRealAnalysis, pQmfImagAnalysis, 15); + FDK_QmfDomain_GetSlot(&self->pQmfDomain->QmfDomainIn[ch], ts, + MAX_QMF_BANDS_TO_HYBRID, self->qmfBands, + pQmfRealAnalysis, pQmfImagAnalysis, 15); + } else { + FDK_QmfDomain_GetSlot(&self->pQmfDomain->QmfDomainIn[ch], ts, 0, + self->qmfBands, pQmfRealAnalysis, + pQmfImagAnalysis, 15); + } + if (ts == self->pQmfDomain->globalConf.nQmfTimeSlots - 1) { + /* Is currently also needed in case we dont have any overlap. We need to + * save lb_scale to ov_lb_scale */ + FDK_QmfDomain_SaveOverlap(&self->pQmfDomain->QmfDomainIn[ch], 0); + } + + /* Apply clip protection to output. */ + if (!isTwoChMode(self->upmixType) && !bypassMode) { + int i; + for (i = 0; i < self->qmfBands; i++) { + qmfReal__FDK[ch][i] = + fMult(qmfReal__FDK[ch][i], self->clipProtectGain__FDK); + qmfImag__FDK[ch][i] = + fMult(qmfImag__FDK[ch][i], self->clipProtectGain__FDK); + } + } + + } /* End of loop over numInputChannels */ + } + + self->qmfInputDelayBufPos = + (self->qmfInputDelayBufPos + 1) % self->pc_filterdelay; + + return err; +} + +/******************************************************************************* + Functionname: SpatialDecHybridAnalysis + ******************************************************************************* + + Description: + + Arguments: + + Input: + float** pointers[4] leftReal, leftIm, rightReal, rightIm + + Output: + float self->qmfInputReal[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_QMF_BANDS]; + float self->qmfInputImag[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_QMF_BANDS]; + + float +self->hybInputReal[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_HYBRID_BANDS]; float +self->hybInputImag[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_HYBRID_BANDS]; + + +*******************************************************************************/ +SACDEC_ERROR SpatialDecHybridAnalysis(spatialDec *self, FIXP_DBL **qmfInputReal, + FIXP_DBL **qmfInputImag, + FIXP_DBL **hybOutputReal, + FIXP_DBL **hybOutputImag, const INT ts, + const INT numInputChannels) { + SACDEC_ERROR err = MPS_OK; + int ch; + + for (ch = 0; ch < numInputChannels; + ch++) /* hybrid filtering for down-mix signals */ + { + if (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD) { + int k; + /* No hybrid filtering. Just copy the QMF data. */ + for (k = 0; k < self->hybridBands; k += 1) { + hybOutputReal[ch][k] = qmfInputReal[ch][k]; + hybOutputImag[ch][k] = qmfInputImag[ch][k]; + } + } else { + self->hybridAnalysis[ch].hfMode = self->bShareDelayWithSBR; + + if (self->stereoConfigIndex == 3) + FDK_ASSERT(self->hybridAnalysis[ch].hfMode == 0); + FDKhybridAnalysisApply(&self->hybridAnalysis[ch], qmfInputReal[ch], + qmfInputImag[ch], hybOutputReal[ch], + hybOutputImag[ch]); + } + } + + if ((self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_USAC) && + self->residualCoding) { + self->hybridAnalysis[numInputChannels].hfMode = 0; + FDKhybridAnalysisApply( + &self->hybridAnalysis[numInputChannels], + self->qmfResidualReal__FDK[0][0], self->qmfResidualImag__FDK[0][0], + self->hybResidualReal__FDK[0], self->hybResidualImag__FDK[0]); + } + + return err; +} + +SACDEC_ERROR SpatialDecCreateX(spatialDec *self, FIXP_DBL **hybInputReal, + FIXP_DBL **hybInputImag, FIXP_DBL **pxReal, + FIXP_DBL **pxImag) { + SACDEC_ERROR err = MPS_OK; + int row; + + /* Creating wDry */ + for (row = 0; row < self->numInputChannels; row++) { + /* pointer to direct signals */ + pxReal[row] = hybInputReal[row]; + pxImag[row] = hybInputImag[row]; + } + + return err; +} + +static void M2ParamToKernelMult(FIXP_SGL *RESTRICT pKernel, + FIXP_DBL *RESTRICT Mparam, + FIXP_DBL *RESTRICT MparamPrev, + int *RESTRICT pWidth, FIXP_SGL alpha__FDK, + int nBands) { + int pb; + + for (pb = 0; pb < nBands; pb++) { + FIXP_SGL tmp = FX_DBL2FX_SGL( + interpolateParameter(alpha__FDK, Mparam[pb], MparamPrev[pb])); + + int i = pWidth[pb]; + if (i & 1) *pKernel++ = tmp; + if (i & 2) { + *pKernel++ = tmp; + *pKernel++ = tmp; + } + for (i >>= 2; i--;) { + *pKernel++ = tmp; + *pKernel++ = tmp; + *pKernel++ = tmp; + *pKernel++ = tmp; + } + } +} + +SACDEC_ERROR SpatialDecApplyM1_CreateW_Mode212( + spatialDec *self, const SPATIAL_BS_FRAME *frame, FIXP_DBL **xReal, + FIXP_DBL **xImag, FIXP_DBL **vReal, FIXP_DBL **vImag) { + SACDEC_ERROR err = MPS_OK; + int res; + FIXP_DBL *decorrInReal = vReal[0]; + FIXP_DBL *decorrInImag = vImag[0]; + + /* M1 does not do anything in 212 mode, so use simplified processing */ + FDK_ASSERT(self->numVChannels == 2); + FDK_ASSERT(self->numDirektSignals == 1); + FDK_ASSERT(self->numDecorSignals == 1); + FDKmemcpy(vReal[0], xReal[0], self->hybridBands * sizeof(FIXP_DBL)); + FDKmemcpy(vImag[0], xImag[0], self->hybridBands * sizeof(FIXP_DBL)); + + if (isTsdActive(frame->TsdData)) { + /* Generate v_{x,nonTr} as input for allpass based decorrelator */ + TsdGenerateNonTr(self->hybridBands, frame->TsdData, self->TsdTs, vReal[0], + vImag[0], vReal[1], vImag[1], &decorrInReal, + &decorrInImag); + } + /* - Decorrelate */ + res = SpatialDecGetResidualIndex(self, 1); + if (FDKdecorrelateApply(&self->apDecor[0], decorrInReal, decorrInImag, + vReal[1], vImag[1], + self->param2hyb[self->residualBands[res]])) { + return MPS_NOTOK; + } + if (isTsdActive(frame->TsdData)) { + /* Generate v_{x,Tr}, apply transient decorrelator and add to allpass based + * decorrelator output */ + TsdApply(self->hybridBands, frame->TsdData, &self->TsdTs, + vReal[0], /* input: v_x */ + vImag[0], + vReal[1], /* input: d_{x,nonTr}; output: d_{x,nonTr} + d_{x,Tr} */ + vImag[1]); + } + + /* Write residual signal in approriate parameter bands */ + if (self->residualBands[res] > 0) { + int stopBand = self->param2hyb[self->residualBands[res]]; + FDKmemcpy(vReal[1], self->hybResidualReal__FDK[res], + fixMin(stopBand, self->hybridBands) * sizeof(FIXP_DBL)); + FDKmemcpy(vImag[1], self->hybResidualImag__FDK[res], + fixMin(stopBand, self->hybridBands) * sizeof(FIXP_DBL)); + } /* (self->residualBands[res]>0) */ + + return err; +} + +SACDEC_ERROR SpatialDecApplyM2_Mode212(spatialDec *self, INT ps, + const FIXP_SGL alpha, FIXP_DBL **wReal, + FIXP_DBL **wImag, + FIXP_DBL **hybOutputRealDry, + FIXP_DBL **hybOutputImagDry) { + SACDEC_ERROR err = MPS_OK; + INT row; + + INT *pWidth = self->kernels_width; + /* for stereoConfigIndex == 3 case hybridBands is < 71 */ + INT pb_max = self->kernels[self->hybridBands - 1] + 1; + INT max_row = self->numOutputChannels; + + INT M2_exp = 0; + if (self->residualCoding) M2_exp = 3; + + for (row = 0; row < max_row; row++) // 2 times + { + FIXP_DBL *Mparam0 = self->M2Real__FDK[row][0]; + FIXP_DBL *Mparam1 = self->M2Real__FDK[row][1]; + FIXP_DBL *MparamPrev0 = self->M2RealPrev__FDK[row][0]; + FIXP_DBL *MparamPrev1 = self->M2RealPrev__FDK[row][1]; + + FIXP_DBL *RESTRICT pHybOutRealDry = hybOutputRealDry[row]; + FIXP_DBL *RESTRICT pHybOutImagDry = hybOutputImagDry[row]; + + FIXP_DBL *RESTRICT pWReal0 = wReal[0]; + FIXP_DBL *RESTRICT pWReal1 = wReal[1]; + FIXP_DBL *RESTRICT pWImag0 = wImag[0]; + FIXP_DBL *RESTRICT pWImag1 = wImag[1]; + for (INT pb = 0; pb < pb_max; pb++) { + FIXP_DBL tmp0, tmp1; + + tmp0 = interpolateParameter(alpha, Mparam0[pb], MparamPrev0[pb]); + tmp1 = interpolateParameter(alpha, Mparam1[pb], MparamPrev1[pb]); + + INT i = pWidth[pb]; + + do // about 3-4 times + { + FIXP_DBL var0, var1, real, imag; + + var0 = *pWReal0++; + var1 = *pWReal1++; + real = fMultDiv2(var0, tmp0); + var0 = *pWImag0++; + real = fMultAddDiv2(real, var1, tmp1); + var1 = *pWImag1++; + imag = fMultDiv2(var0, tmp0); + *pHybOutRealDry++ = real << (1 + M2_exp); + imag = fMultAddDiv2(imag, var1, tmp1); + *pHybOutImagDry++ = imag << (1 + M2_exp); + } while (--i != 0); + } + } + return err; +} + +SACDEC_ERROR SpatialDecApplyM2_Mode212_ResidualsPlusPhaseCoding( + spatialDec *self, INT ps, const FIXP_SGL alpha, FIXP_DBL **wReal, + FIXP_DBL **wImag, FIXP_DBL **hybOutputRealDry, + FIXP_DBL **hybOutputImagDry) { + SACDEC_ERROR err = MPS_OK; + INT row; + INT scale_param_m2; + INT *pWidth = self->kernels_width; + INT pb_max = self->kernels[self->hybridBands - 1] + 1; + + scale_param_m2 = SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2; + + for (row = 0; row < self->numM2rows; row++) { + INT qs, pb; + + FIXP_DBL *RESTRICT pWReal0 = wReal[0]; + FIXP_DBL *RESTRICT pWImag0 = wImag[0]; + FIXP_DBL *RESTRICT pWReal1 = wReal[1]; + FIXP_DBL *RESTRICT pWImag1 = wImag[1]; + + FIXP_DBL *MReal0 = self->M2Real__FDK[row][0]; + FIXP_DBL *MImag0 = self->M2Imag__FDK[row][0]; + FIXP_DBL *MReal1 = self->M2Real__FDK[row][1]; + FIXP_DBL *MRealPrev0 = self->M2RealPrev__FDK[row][0]; + FIXP_DBL *MImagPrev0 = self->M2ImagPrev__FDK[row][0]; + FIXP_DBL *MRealPrev1 = self->M2RealPrev__FDK[row][1]; + + FIXP_DBL *RESTRICT pHybOutRealDry = hybOutputRealDry[row]; + FIXP_DBL *RESTRICT pHybOutImagDry = hybOutputImagDry[row]; + + FDK_ASSERT(!(self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD)); + FDK_ASSERT((pWidth[0] + pWidth[1]) >= 3); + + for (pb = 0, qs = 3; pb < 2; pb++) { + INT s; + FIXP_DBL maxVal; + FIXP_SGL mReal1; + FIXP_SGL mReal0, mImag0; + FIXP_DBL iReal0, iImag0, iReal1; + + iReal0 = interpolateParameter(alpha, MReal0[pb], MRealPrev0[pb]); + iImag0 = -interpolateParameter(alpha, MImag0[pb], MImagPrev0[pb]); + iReal1 = interpolateParameter(alpha, MReal1[pb], MRealPrev1[pb]); + + maxVal = fAbs(iReal0) | fAbs(iImag0); + maxVal |= fAbs(iReal1); + + s = fMax(CntLeadingZeros(maxVal) - 1, 0); + s = fMin(s, scale_param_m2); + + mReal0 = FX_DBL2FX_SGL(iReal0 << s); + mImag0 = FX_DBL2FX_SGL(iImag0 << s); + mReal1 = FX_DBL2FX_SGL(iReal1 << s); + + s = scale_param_m2 - s; + + INT i = pWidth[pb]; + + do { + FIXP_DBL real, imag, wReal0, wImag0, wReal1, wImag1; + + wReal0 = *pWReal0++; + wImag0 = *pWImag0++; + wReal1 = *pWReal1++; + wImag1 = *pWImag1++; + + cplxMultDiv2(&real, &imag, wReal0, wImag0, mReal0, mImag0); + + *pHybOutRealDry++ = fMultAddDiv2(real, wReal1, mReal1) << s; + *pHybOutImagDry++ = fMultAddDiv2(imag, wImag1, mReal1) << s; + + if (qs > 0) { + mImag0 = -mImag0; + qs--; + } + } while (--i != 0); + } + + for (; pb < pb_max; pb++) { + INT s; + FIXP_DBL maxVal; + FIXP_SGL mReal1; + FIXP_SGL mReal0, mImag0; + FIXP_DBL iReal0, iImag0, iReal1; + + iReal0 = interpolateParameter(alpha, MReal0[pb], MRealPrev0[pb]); + iImag0 = interpolateParameter(alpha, MImag0[pb], MImagPrev0[pb]); + iReal1 = interpolateParameter(alpha, MReal1[pb], MRealPrev1[pb]); + + maxVal = fAbs(iReal0) | fAbs(iImag0); + maxVal |= fAbs(iReal1); + + s = fMax(CntLeadingZeros(maxVal) - 1, 0); + s = fMin(s, scale_param_m2); + + mReal0 = FX_DBL2FX_SGL(iReal0 << s); + mImag0 = FX_DBL2FX_SGL(iImag0 << s); + mReal1 = FX_DBL2FX_SGL(iReal1 << s); + + s = scale_param_m2 - s; + + INT i = pWidth[pb]; + + do { + FIXP_DBL real, imag, wReal0, wImag0, wReal1, wImag1; + + wReal0 = *pWReal0++; + wImag0 = *pWImag0++; + wReal1 = *pWReal1++; + wImag1 = *pWImag1++; + + cplxMultDiv2(&real, &imag, wReal0, wImag0, mReal0, mImag0); + + *pHybOutRealDry++ = fMultAddDiv2(real, wReal1, mReal1) << s; + *pHybOutImagDry++ = fMultAddDiv2(imag, wImag1, mReal1) << s; + } while (--i != 0); + } + } + + return err; +} + +SACDEC_ERROR SpatialDecApplyM2(spatialDec *self, INT ps, const FIXP_SGL alpha, + FIXP_DBL **wReal, FIXP_DBL **wImag, + FIXP_DBL **hybOutputRealDry, + FIXP_DBL **hybOutputImagDry, + FIXP_DBL **hybOutputRealWet, + FIXP_DBL **hybOutputImagWet) { + SACDEC_ERROR err = MPS_OK; + + { + int qs, row, col; + int complexHybBands; + int complexParBands; + int scale_param_m2 = 0; + int toolsDisabled; + + UCHAR activParamBands; + FIXP_DBL *RESTRICT pWReal, *RESTRICT pWImag, *RESTRICT pHybOutRealDry, + *RESTRICT pHybOutImagDry, *RESTRICT pHybOutRealWet, + *RESTRICT pHybOutImagWet; + C_ALLOC_SCRATCH_START(pKernel, FIXP_SGL, MAX_HYBRID_BANDS); + + /* The wet signal is added to the dry signal directly in applyM2 if GES and + * STP are disabled */ + toolsDisabled = + ((self->tempShapeConfig == 1) || (self->tempShapeConfig == 2)) ? 0 : 1; + + { + complexHybBands = self->hybridBands; + complexParBands = self->numParameterBands; + } + + FDKmemclear(hybOutputImagDry[0], + self->createParams.maxNumOutputChannels * + self->createParams.maxNumCmplxHybBands * sizeof(FIXP_DBL)); + FDKmemclear(hybOutputRealDry[0], self->createParams.maxNumOutputChannels * + self->createParams.maxNumHybridBands * + sizeof(FIXP_DBL)); + + if (!toolsDisabled) { + FDKmemclear(hybOutputRealWet[0], + self->createParams.maxNumOutputChannels * + self->createParams.maxNumHybridBands * sizeof(FIXP_DBL)); + FDKmemclear(hybOutputImagWet[0], + self->createParams.maxNumOutputChannels * + self->createParams.maxNumCmplxHybBands * + sizeof(FIXP_DBL)); + } + + if (self->phaseCoding == 3) { + /* + SCALE_DATA_APPLY_M2 to compensate for Div2 below ?! */ + scale_param_m2 = SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2; + } + + for (row = 0; row < self->numM2rows; row++) { + pHybOutRealDry = hybOutputRealDry[row]; + pHybOutImagDry = hybOutputImagDry[row]; + + if (toolsDisabled) { + pHybOutRealWet = hybOutputRealDry[row]; + pHybOutImagWet = hybOutputImagDry[row]; + } else { + pHybOutRealWet = hybOutputRealWet[row]; + pHybOutImagWet = hybOutputImagWet[row]; + } + + for (col = 0; col < self->numDirektSignals; col++) { + if (self->pActivM2ParamBands == + 0) { /* default setting, calculate all rows and columns */ + activParamBands = 1; + } else { + if (self->pActivM2ParamBands[MAX_M2_INPUT * row + + col]) /* table with activ and inactiv + bands exists for current + configuration */ + activParamBands = 1; + else + activParamBands = 0; + } + if (activParamBands) { + pWReal = wReal[col]; + pWImag = wImag[col]; + + M2ParamToKernelMult(pKernel, self->M2Real__FDK[row][col], + self->M2RealPrev__FDK[row][col], + self->kernels_width, alpha, + self->numParameterBands); + + if (1 && (self->phaseCoding != 3)) { + /* direct signals */ + { + /* only one sample will be assigned to each row, hence + * accumulation is not neccessary; that is valid for all + * configurations */ + for (qs = 0; qs < complexHybBands; qs++) { + pHybOutRealDry[qs] = fMult(pWReal[qs], pKernel[qs]); + pHybOutImagDry[qs] = fMult(pWImag[qs], pKernel[qs]); + } + } + } else { /* isBinauralMode(self->upmixType) */ + + for (qs = 0; qs < complexHybBands; qs++) { + pHybOutRealDry[qs] += fMultDiv2(pWReal[qs], pKernel[qs]) + << (scale_param_m2); + pHybOutImagDry[qs] += fMultDiv2(pWImag[qs], pKernel[qs]) + << (scale_param_m2); + } + + M2ParamToKernelMult(pKernel, self->M2Imag__FDK[row][col], + self->M2ImagPrev__FDK[row][col], + self->kernels_width, alpha, complexParBands); + + /* direct signals sign is -1 for qs = 0,2 */ + pHybOutRealDry[0] += fMultDiv2(pWImag[0], pKernel[0]) + << (scale_param_m2); + pHybOutImagDry[0] -= fMultDiv2(pWReal[0], pKernel[0]) + << (scale_param_m2); + + pHybOutRealDry[2] += fMultDiv2(pWImag[2], pKernel[2]) + << (scale_param_m2); + pHybOutImagDry[2] -= fMultDiv2(pWReal[2], pKernel[2]) + << (scale_param_m2); + + /* direct signals sign is +1 for qs = 1,3,4,5,...,complexHybBands */ + pHybOutRealDry[1] -= fMultDiv2(pWImag[1], pKernel[1]) + << (scale_param_m2); + pHybOutImagDry[1] += fMultDiv2(pWReal[1], pKernel[1]) + << (scale_param_m2); + + for (qs = 3; qs < complexHybBands; qs++) { + pHybOutRealDry[qs] -= fMultDiv2(pWImag[qs], pKernel[qs]) + << (scale_param_m2); + pHybOutImagDry[qs] += fMultDiv2(pWReal[qs], pKernel[qs]) + << (scale_param_m2); + } + } /* self->upmixType */ + } /* if (activParamBands) */ + } /* self->numDirektSignals */ + + for (; col < self->numVChannels; col++) { + if (self->pActivM2ParamBands == + 0) { /* default setting, calculate all rows and columns */ + activParamBands = 1; + } else { + if (self->pActivM2ParamBands[MAX_M2_INPUT * row + + col]) /* table with activ and inactiv + bands exists for current + configuration */ + activParamBands = 1; + else + activParamBands = 0; + } + + if (activParamBands) { + int resBandIndex; + int resHybIndex; + + resBandIndex = + self->residualBands[SpatialDecGetResidualIndex(self, col)]; + resHybIndex = self->param2hyb[resBandIndex]; + + pWReal = wReal[col]; + pWImag = wImag[col]; + + M2ParamToKernelMult(pKernel, self->M2Real__FDK[row][col], + self->M2RealPrev__FDK[row][col], + self->kernels_width, alpha, + self->numParameterBands); + + if (1 && (self->phaseCoding != 3)) { + /* residual signals */ + for (qs = 0; qs < resHybIndex; qs++) { + pHybOutRealDry[qs] += fMult(pWReal[qs], pKernel[qs]); + pHybOutImagDry[qs] += fMult(pWImag[qs], pKernel[qs]); + } + /* decor signals */ + for (; qs < complexHybBands; qs++) { + pHybOutRealWet[qs] += fMult(pWReal[qs], pKernel[qs]); + pHybOutImagWet[qs] += fMult(pWImag[qs], pKernel[qs]); + } + } else { /* self->upmixType */ + /* residual signals */ + FIXP_DBL *RESTRICT pHybOutReal; + FIXP_DBL *RESTRICT pHybOutImag; + + for (qs = 0; qs < resHybIndex; qs++) { + pHybOutRealDry[qs] += fMultDiv2(pWReal[qs], pKernel[qs]) + << (scale_param_m2); + pHybOutImagDry[qs] += fMultDiv2(pWImag[qs], pKernel[qs]) + << (scale_param_m2); + } + /* decor signals */ + for (; qs < complexHybBands; qs++) { + pHybOutRealWet[qs] += fMultDiv2(pWReal[qs], pKernel[qs]) + << (scale_param_m2); + pHybOutImagWet[qs] += fMultDiv2(pWImag[qs], pKernel[qs]) + << (scale_param_m2); + } + + M2ParamToKernelMult(pKernel, self->M2Imag__FDK[row][col], + self->M2ImagPrev__FDK[row][col], + self->kernels_width, alpha, complexParBands); + + /* direct signals sign is -1 for qs = 0,2 */ + /* direct signals sign is +1 for qs = 1,3.. */ + if (toolsDisabled) { + pHybOutRealDry[0] += fMultDiv2(pWImag[0], pKernel[0]) + << (scale_param_m2); + pHybOutImagDry[0] -= fMultDiv2(pWReal[0], pKernel[0]) + << (scale_param_m2); + + pHybOutRealDry[1] -= fMultDiv2(pWImag[1], pKernel[1]) + << (scale_param_m2); + pHybOutImagDry[1] += fMultDiv2(pWReal[1], pKernel[1]) + << (scale_param_m2); + + pHybOutRealDry[2] += fMultDiv2(pWImag[2], pKernel[2]) + << (scale_param_m2); + pHybOutImagDry[2] -= fMultDiv2(pWReal[2], pKernel[2]) + << (scale_param_m2); + } else { + pHybOutReal = &pHybOutRealDry[0]; + pHybOutImag = &pHybOutImagDry[0]; + if (0 == resHybIndex) { + pHybOutReal = &pHybOutRealWet[0]; + pHybOutImag = &pHybOutImagWet[0]; + } + pHybOutReal[0] += fMultDiv2(pWImag[0], pKernel[0]) + << (scale_param_m2); + pHybOutImag[0] -= fMultDiv2(pWReal[0], pKernel[0]) + << (scale_param_m2); + + if (1 == resHybIndex) { + pHybOutReal = &pHybOutRealWet[0]; + pHybOutImag = &pHybOutImagWet[0]; + } + pHybOutReal[1] -= fMultDiv2(pWImag[1], pKernel[1]) + << (scale_param_m2); + pHybOutImag[1] += fMultDiv2(pWReal[1], pKernel[1]) + << (scale_param_m2); + + if (2 == resHybIndex) { + pHybOutReal = &pHybOutRealWet[0]; + pHybOutImag = &pHybOutImagWet[0]; + } + pHybOutReal[2] += fMultDiv2(pWImag[2], pKernel[2]) + << (scale_param_m2); + pHybOutImag[2] -= fMultDiv2(pWReal[2], pKernel[2]) + << (scale_param_m2); + } + + for (qs = 3; qs < resHybIndex; qs++) { + pHybOutRealDry[qs] -= fMultDiv2(pWImag[qs], pKernel[qs]) + << (scale_param_m2); + pHybOutImagDry[qs] += fMultDiv2(pWReal[qs], pKernel[qs]) + << (scale_param_m2); + } + /* decor signals */ + for (; qs < complexHybBands; qs++) { + pHybOutRealWet[qs] -= fMultDiv2(pWImag[qs], pKernel[qs]) + << (scale_param_m2); + pHybOutImagWet[qs] += fMultDiv2(pWReal[qs], pKernel[qs]) + << (scale_param_m2); + } + } /* self->upmixType */ + } /* if (activParamBands) { */ + } /* self->numVChannels */ + } + + C_ALLOC_SCRATCH_END(pKernel, FIXP_SGL, MAX_HYBRID_BANDS); + } + + return err; +} + +SACDEC_ERROR SpatialDecSynthesis(spatialDec *self, const INT ts, + FIXP_DBL **hybOutputReal, + FIXP_DBL **hybOutputImag, PCM_MPS *timeOut, + const INT numInputChannels, + const FDK_channelMapDescr *const mapDescr) { + SACDEC_ERROR err = MPS_OK; + + int ch; + int stride, offset; + + stride = self->numOutputChannelsAT; + offset = 1; + + PCM_MPS *pTimeOut__FDK = + &timeOut[stride * self->pQmfDomain->globalConf.nBandsSynthesis * ts]; + C_ALLOC_SCRATCH_START(pQmfReal, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS); + C_ALLOC_SCRATCH_START(pQmfImag, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS); + + for (ch = 0; ch < self->numOutputChannelsAT; ch++) { + if (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD) { + int k; + /* No hybrid filtering. Just copy the QMF data. */ + for (k = 0; k < self->hybridBands; k += 1) { + pQmfReal[k] = hybOutputReal[ch][k]; + pQmfImag[k] = hybOutputImag[ch][k]; + } + } else { + FDKhybridSynthesisApply(&self->hybridSynthesis[ch], hybOutputReal[ch], + hybOutputImag[ch], pQmfReal, pQmfImag); + } + + /* Map channel indices from MPEG Surround -> PCE style -> channelMapping[] + */ + FDK_ASSERT(self->numOutputChannelsAT <= 6); + int outCh = FDK_chMapDescr_getMapValue(mapDescr, mapChannel(self, ch), + self->numOutputChannelsAT); + + { + if (self->stereoConfigIndex == 3) { + /* MPS -> SBR */ + int i; + FIXP_DBL *pWorkBufReal, *pWorkBufImag; + FDK_ASSERT((self->pQmfDomain->QmfDomainOut[outCh].fb.outGain_m == + (FIXP_DBL)0x80000000) && + (self->pQmfDomain->QmfDomainOut[outCh].fb.outGain_e == 0)); + FDK_QmfDomain_GetWorkBuffer(&self->pQmfDomain->QmfDomainIn[outCh], ts, + &pWorkBufReal, &pWorkBufImag); + FDK_ASSERT(self->qmfBands <= + self->pQmfDomain->QmfDomainIn[outCh].workBuf_nBands); + for (i = 0; i < self->qmfBands; i++) { + pWorkBufReal[i] = pQmfReal[i]; + pWorkBufImag[i] = pQmfImag[i]; + } + self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale = + -7; /*-ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK;*/ + self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -= + self->pQmfDomain->QmfDomainIn[outCh].fb.filterScale; + self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -= + self->clipProtectGainSF__FDK; + + } else { + /* Call the QMF synthesis for dry. */ + err = CalculateSpaceSynthesisQmf(&self->pQmfDomain->QmfDomainOut[outCh], + pQmfReal, pQmfImag, stride, + pTimeOut__FDK + (offset * outCh)); + } + if (err != MPS_OK) goto bail; + } + } /* ch loop */ + +bail: + C_ALLOC_SCRATCH_END(pQmfImag, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS); + C_ALLOC_SCRATCH_END(pQmfReal, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS); + + return err; +} + +void SpatialDecBufferMatrices(spatialDec *self) { + int row, col; + int complexParBands; + complexParBands = self->numParameterBands; + + /* + buffer matrices M2 + */ + for (row = 0; row < self->numM2rows; row++) { + for (col = 0; col < self->numVChannels; col++) { + FDKmemcpy(self->M2RealPrev__FDK[row][col], self->M2Real__FDK[row][col], + self->numParameterBands * sizeof(FIXP_DBL)); + if (0 || (self->phaseCoding == 3)) { + FDKmemcpy(self->M2ImagPrev__FDK[row][col], self->M2Imag__FDK[row][col], + complexParBands * sizeof(FIXP_DBL)); + } + } + } + + /* buffer phase */ + FDKmemcpy(self->PhasePrevLeft__FDK, self->PhaseLeft__FDK, + self->numParameterBands * sizeof(FIXP_DBL)); + FDKmemcpy(self->PhasePrevRight__FDK, self->PhaseRight__FDK, + self->numParameterBands * sizeof(FIXP_DBL)); +} + +#define PHASE_SCALE 2 + +#ifndef P_PI +#define P_PI 3.1415926535897932 +#endif + +/* For better precision, PI (pi_x2) is already doubled */ +static FIXP_DBL interp_angle__FDK(FIXP_DBL angle1, FIXP_DBL angle2, + FIXP_SGL alpha, FIXP_DBL pi_x2) { + if (angle2 - angle1 > (pi_x2 >> 1)) angle2 -= pi_x2; + + if (angle1 - angle2 > (pi_x2 >> 1)) angle1 -= pi_x2; + + return interpolateParameter(alpha, angle2, angle1); +} + +/* + * + */ +void SpatialDecApplyPhase(spatialDec *self, FIXP_SGL alpha__FDK, + int lastSlotOfParamSet) { + int pb, qs; + FIXP_DBL ppb[MAX_PARAMETER_BANDS * + 4]; /* left real, imag - right real, imag interleaved */ + + const FIXP_DBL pi_x2 = PIx2__IPD; + for (pb = 0; pb < self->numParameterBands; pb++) { + FIXP_DBL pl, pr; + + pl = interp_angle__FDK(self->PhasePrevLeft__FDK[pb], + self->PhaseLeft__FDK[pb], alpha__FDK, pi_x2); + pr = interp_angle__FDK(self->PhasePrevRight__FDK[pb], + self->PhaseRight__FDK[pb], alpha__FDK, pi_x2); + + inline_fixp_cos_sin(pl, pr, IPD_SCALE, &ppb[4 * pb]); + } + + /* sign is -1 for qs = 0,2 and +1 for qs = 1 */ + + const SCHAR *kernels = &self->kernels[0]; + + FIXP_DBL *Dry_real0 = &self->hybOutputRealDry__FDK[0][0]; + FIXP_DBL *Dry_imag0 = &self->hybOutputImagDry__FDK[0][0]; + FIXP_DBL *Dry_real1 = &self->hybOutputRealDry__FDK[1][0]; + FIXP_DBL *Dry_imag1 = &self->hybOutputImagDry__FDK[1][0]; + + for (qs = 2; qs >= 0; qs--) { + FIXP_DBL out_re, out_im; + + pb = *kernels++; + if (qs == 1) /* sign[qs] >= 0 */ + { + cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0], + ppb[4 * pb + 1]); + out_re <<= PHASE_SCALE - 1; + out_im <<= PHASE_SCALE - 1; + *Dry_real0++ = out_re; + *Dry_imag0++ = out_im; + + cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2], + ppb[4 * pb + 3]); + out_re <<= PHASE_SCALE - 1; + out_im <<= PHASE_SCALE - 1; + *Dry_real1++ = out_re; + *Dry_imag1++ = out_im; + } else { + cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0], + -ppb[4 * pb + 1]); + out_re <<= PHASE_SCALE - 1; + out_im <<= PHASE_SCALE - 1; + *Dry_real0++ = out_re; + *Dry_imag0++ = out_im; + + cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2], + -ppb[4 * pb + 3]); + out_re <<= PHASE_SCALE - 1; + out_im <<= PHASE_SCALE - 1; + *Dry_real1++ = out_re; + *Dry_imag1++ = out_im; + } + } + + /* sign is +1 for qs >=3 */ + for (qs = self->hybridBands - 3; qs--;) { + FIXP_DBL out_re, out_im; + + pb = *kernels++; + cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0], + ppb[4 * pb + 1]); + out_re <<= PHASE_SCALE - 1; + out_im <<= PHASE_SCALE - 1; + *Dry_real0++ = out_re; + *Dry_imag0++ = out_im; + + cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2], + ppb[4 * pb + 3]); + out_re <<= PHASE_SCALE - 1; + out_im <<= PHASE_SCALE - 1; + *Dry_real1++ = out_re; + *Dry_imag1++ = out_im; + } +} diff --git a/libSACdec/src/sac_process.h b/libSACdec/src/sac_process.h new file mode 100644 index 0000000..ee2f2fe --- /dev/null +++ b/libSACdec/src/sac_process.h @@ -0,0 +1,297 @@ +/* ----------------------------------------------------------------------------- +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 Processing + +*******************************************************************************/ + +/*! + \file + \brief Polyphase Filterbank +*/ + +#ifndef SAC_PROCESS_H +#define SAC_PROCESS_H + +#include "sac_dec.h" + +void SpatialDecApplyPhase(spatialDec *self, FIXP_SGL alpha, + int lastSlotOfParamSet); + +/** + * \brief Apply QMF Analysis Filterbank. + * + * Calculates qmf data on downmix input time data. + * Delaylines will be applied if necessaray. + * + * \param self A spatial decoder handle. + * \param inData Downmix channel time data as input. + * \param ts Signals time slot offset for input buffer. + * \param qmfReal Downmix channel qmf output data. + * \param qmfImag Downmix channel qmf output data. + * + * \return Error status. + */ +SACDEC_ERROR SpatialDecQMFAnalysis(spatialDec *self, const PCM_MPS *inData, + const INT ts, const INT bypassMode, + FIXP_DBL **qmfReal, FIXP_DBL **qmfImag, + const int numInputChannels); + +/** + * \brief Feed spatial decoder with external qmf data. + * + * \param self A spatial decoder handle. + * \param qmfInDataReal External qmf downmix data as input. + * \param qmfInDataImag External qmf downmix data as input. + * \param ts Signals time slot in input buffer to process. + * \param qmfReal Downmix channel qmf output data. + * \param qmfImag Downmix channel qmf output data. + * \param numInputChannels Number of input channels. Might differ from + * self->numInputChannels. + * + * \return Error status. + */ +SACDEC_ERROR SpatialDecFeedQMF(spatialDec *self, FIXP_DBL **qmfInDataReal, + FIXP_DBL **qmfInDataImag, const INT ts, + const INT bypassMode, FIXP_DBL **qmfReal, + FIXP_DBL **qmfImag, const INT numInputChannels); + +/** + * \brief Apply Hybrdid Analysis Filterbank. + * + * Calculates hybrid data on downmix input data. + * Residual hybrid signals will also be calculated on current slot if available. + * + * \param self A spatial decoder handle. + * \param qmfInputReal Downmix channel qmf data as input. + * \param qmfInputImag Downmix channel qmf data as input. + * \param hybOutputReal Downmix channel hybrid output data. + * \param hybOutputImag Downmix channel hybrid output data. + * \param ts Signals time slot in spatial frame to process. + * \param numInputChannels Number of input channels. Might differ from + * self->numInputChannels. + * + * \return Error status. + */ +SACDEC_ERROR SpatialDecHybridAnalysis(spatialDec *self, FIXP_DBL **qmfInputReal, + FIXP_DBL **qmfInputImag, + FIXP_DBL **hybOutputReal, + FIXP_DBL **hybOutputImag, const INT ts, + const INT numInputChannels); + +/** + * \brief Create X data. + * + * Returns a pointer list over Xchannels pointing to downmix input channels + * and to residual channels when provided. + * + * \param self A spatial decoder handle. + * \param hybInputReal Downmix channel hybrid data as input. + * \param hybInputImag Downmix channel hybrid data as input. + * \param pxReal Pointer to hybrid and residual data as output. + * \param pxImag Pointer to hybrid and residual data as output. + * + * \return Error status. + */ +SACDEC_ERROR SpatialDecCreateX(spatialDec *self, FIXP_DBL **hybInputReal, + FIXP_DBL **hybInputImag, FIXP_DBL **pxReal, + FIXP_DBL **pxImag); + +/** + * \brief MPS212 combined version of apply M1 parameters and create wet signal + * + * \param self A spatial decoder handle. + * \param xReal Downmix and residual X data as input. + * \param xImag Downmix and residual X data as input. + * \param vReal output data: [0] direct signal (V); [1] wet signal + * (W). + * \param vImag output data: [0] direct signal (V); [1] wet signal + * (W). + * + * \return Error status. + */ +SACDEC_ERROR SpatialDecApplyM1_CreateW_Mode212( + spatialDec *self, const SPATIAL_BS_FRAME *frame, FIXP_DBL **xReal, + FIXP_DBL **xImag, FIXP_DBL **vReal, FIXP_DBL **vImag); + +/** + * \brief Apply M2 parameters. + * + * \param self A spatial decoder handle. + * \param ps Signals parameter band from where M2 parameter to + * use. + * \param alpha Smoothing factor between current and previous + * parameter band. Rangeability between 0.f and 1.f. + * \param wReal Wet input data. + * \param wImag Wet input data. + * \param hybOutputRealDry Dry output data. + * \param hybOutputImagDry Dry output data. + * \param hybOutputRealWet Wet output data. + * \param hybOutputImagWet Wet output data. + * + * \return Error status. + */ +SACDEC_ERROR SpatialDecApplyM2(spatialDec *self, INT ps, const FIXP_SGL alpha, + FIXP_DBL **wReal, FIXP_DBL **wImag, + FIXP_DBL **hybOutputRealDry, + FIXP_DBL **hybOutputImagDry, + FIXP_DBL **hybOutputRealWet, + FIXP_DBL **hybOutputImagWet); + +/** + * \brief Apply M2 parameter for 212 mode with residualCoding and phaseCoding. + * + * \param self [i] A spatial decoder handle. + * \param ps [i] Signals parameter band from where M2 parameter + * to use. + * \param alpha [i] Smoothing factor between current and previous + * parameter band. Rangeability between 0.f and 1.f. + * \param wReal [i] Wet input data. + * \param wImag [i] Wet input data. + * \param hybOutputRealDry [o] Dry output data. + * \param hybOutputImagDry [o] Dry output data. + * + * \return error + */ +SACDEC_ERROR SpatialDecApplyM2_Mode212_ResidualsPlusPhaseCoding( + spatialDec *self, INT ps, const FIXP_SGL alpha, FIXP_DBL **wReal, + FIXP_DBL **wImag, FIXP_DBL **hybOutputRealDry, FIXP_DBL **hybOutputImagDry); + +/** + * \brief Apply M2 parameter for 212 mode, upmix from mono to stereo. + * + * \param self [i] A spatial decoder handle. + * \param ps [i] Signals parameter band from where M2 parameter + * to use. + * \param alpha [i] Smoothing factor between current and previous + * parameter band. Rangeability between 0.f and 1.f. + * \param wReal [i] Wet input data. + * \param wImag [i] Wet input data. + * \param hybOutputRealDry [o] Dry output data. + * \param hybOutputImagDry [o] Dry output data. + * + * \return error + */ +SACDEC_ERROR SpatialDecApplyM2_Mode212(spatialDec *self, INT ps, + const FIXP_SGL alpha, FIXP_DBL **wReal, + FIXP_DBL **wImag, + FIXP_DBL **hybOutputRealDry, + FIXP_DBL **hybOutputImagDry); + +/** + * \brief Convert Hybrid input to output audio data. + * + * \param hSpaceSynthesisQmf A spatial decoder handle. + * \param ts Signals time slot in spatial frame to process. + * \param hybOutputReal Hybrid data as input. + * \param hybOutputImag Hybrid data as input. + * \param timeOut audio output data. + * + * \return Error status. + */ +SACDEC_ERROR SpatialDecSynthesis(spatialDec *self, const INT ts, + FIXP_DBL **hybOutputReal, + FIXP_DBL **hybOutputImag, PCM_MPS *timeOut, + const INT numInputChannels, + const FDK_channelMapDescr *const mapDescr); + +void SpatialDecBufferMatrices(spatialDec *self); + +FIXP_DBL getChGain(spatialDec *self, UINT ch, INT *scale); + +#endif diff --git a/libSACdec/src/sac_qmf.cpp b/libSACdec/src/sac_qmf.cpp new file mode 100644 index 0000000..a075490 --- /dev/null +++ b/libSACdec/src/sac_qmf.cpp @@ -0,0 +1,156 @@ +/* ----------------------------------------------------------------------------- +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 Dec QMF processing + +*******************************************************************************/ + +#include "sac_qmf.h" + +#include "FDK_matrixCalloc.h" +#include "sac_dec_interface.h" +#include "sac_rom.h" + +#include "qmf.h" + +SACDEC_ERROR CalculateSpaceSynthesisQmf( + const HANDLE_FDK_QMF_DOMAIN_OUT hQmfDomainOutCh, const FIXP_DBL *Sr, + const FIXP_DBL *Si, const INT stride, INT_PCM *timeSig) { + SACDEC_ERROR err = MPS_OK; + + if (hQmfDomainOutCh == NULL) { + err = MPS_INVALID_HANDLE; + } else { + HANDLE_SPACE_SYNTHESIS_QMF hSpaceSynthesisQmf = &hQmfDomainOutCh->fb; +#if (QMF_MAX_SYNTHESIS_BANDS <= 64) + C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, + (QMF_MAX_SYNTHESIS_BANDS << 1)); +#else + C_AALLOC_STACK_START(pWorkBuffer, FIXP_DBL, (QMF_MAX_SYNTHESIS_BANDS << 1)); +#endif + + qmfSynthesisFilteringSlot(hSpaceSynthesisQmf, Sr, Si, 0, 0, timeSig, stride, + pWorkBuffer); + +#if (QMF_MAX_SYNTHESIS_BANDS <= 64) + C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, (QMF_MAX_SYNTHESIS_BANDS << 1)); +#else + C_AALLOC_STACK_END(pWorkBuffer, FIXP_DBL, (QMF_MAX_SYNTHESIS_BANDS << 1)); +#endif + } + + return err; +} + +SACDEC_ERROR CalculateSpaceAnalysisQmf( + HANDLE_SPACE_ANALYSIS_QMF hSpaceAnalysisQmf, const PCM_MPS *timeSig, + FIXP_DBL *Sr, FIXP_DBL *Si) { + SACDEC_ERROR err = MPS_OK; + + if (hSpaceAnalysisQmf == NULL) { + err = MPS_INVALID_HANDLE; + } else { + C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, (64 << 1)); + + qmfAnalysisFilteringSlot(hSpaceAnalysisQmf, Sr, Si, timeSig, 1, + pWorkBuffer); + C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, (64 << 1)); + } + + return err; +} diff --git a/libSACdec/src/sac_qmf.h b/libSACdec/src/sac_qmf.h new file mode 100644 index 0000000..d1dc837 --- /dev/null +++ b/libSACdec/src/sac_qmf.h @@ -0,0 +1,143 @@ +/* ----------------------------------------------------------------------------- +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 Dec QMF processing + +*******************************************************************************/ + +#ifndef SAC_QMF_H +#define SAC_QMF_H + +#include "common_fix.h" + +#include "sac_dec_interface.h" + +#include "FDK_qmf_domain.h" +#define HANDLE_SPACE_ANALYSIS_QMF HANDLE_QMF_FILTER_BANK +#define HANDLE_SPACE_SYNTHESIS_QMF HANDLE_QMF_FILTER_BANK + +/** + * \brief Convert Qmf input to output audio data. + * + * \param hSpaceSynthesisQmf A Qmf Synthesis Filterbank handle. + * \param Sr Pointer to Qmf input buffer. + * \param Si Pointer to Qmf input buffer. + * \param stride Stride factor for output data, 1 if none. + * \param timeSig (None-)Interleaved audio output data. + * + * \return Error status. + */ +SACDEC_ERROR CalculateSpaceSynthesisQmf( + const HANDLE_FDK_QMF_DOMAIN_OUT hQmfDomainOutCh, const FIXP_DBL *Sr, + const FIXP_DBL *Si, const INT stride, INT_PCM *timeSig); + +/** + * \brief Convert audio input data to qmf representation. + * + * \param hSpaceAnalysisQmf A Qmf Analysis Filterbank handle. + * \param timeSig (None-)Interleavd audio input data. + * \param Sr Pointer to Qmf output buffer. + * \param Si Pointer to Qmf output buffer. + * + * \return Error status. + */ +SACDEC_ERROR CalculateSpaceAnalysisQmf( + HANDLE_SPACE_ANALYSIS_QMF hSpaceAnalysisQmf, const PCM_MPS *timeSig, + FIXP_DBL *Sr, FIXP_DBL *Si); + +#endif /* SAC_QMF_H */ diff --git a/libSACdec/src/sac_reshapeBBEnv.cpp b/libSACdec/src/sac_reshapeBBEnv.cpp new file mode 100644 index 0000000..87c0ac6 --- /dev/null +++ b/libSACdec/src/sac_reshapeBBEnv.cpp @@ -0,0 +1,680 @@ +/* ----------------------------------------------------------------------------- +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 Dec guided envelope shaping + +*******************************************************************************/ + +#include "sac_reshapeBBEnv.h" + +#include "sac_dec.h" +#include "sac_bitdec.h" +#include "sac_calcM1andM2.h" +#include "sac_reshapeBBEnv.h" +#include "sac_rom.h" + +#define INP_DRY_WET 0 +#define INP_DMX 1 + +#define SF_SHAPE 1 +#define SF_DIV32 6 +#define SF_FACTOR_SLOT 5 + +#define START_BB_ENV 0 /* 10 */ +#define END_BB_ENV 9 /* 18 */ + +#define SF_ALPHA1 8 +#define SF_BETA1 4 + +void initBBEnv(spatialDec *self, int initStatesFlag) { + INT ch, k; + + for (ch = 0; ch < self->numOutputChannels; ch++) { + k = row2channelGES[self->treeConfig][ch]; + self->row2channelDmxGES[ch] = k; + if (k == -1) continue; + + switch (self->treeConfig) { + case TREE_212: + self->row2channelDmxGES[ch] = 0; + break; + default:; + } + } + + if (initStatesFlag) { + for (k = 0; k < 2 * MAX_OUTPUT_CHANNELS + MAX_INPUT_CHANNELS; k++) { + self->reshapeBBEnvState->normNrgPrev__FDK[k] = + FL2FXCONST_DBL(0.5f); /* 32768.f*32768.f */ + self->reshapeBBEnvState->normNrgPrevSF[k] = DFRACT_BITS - 1; + self->reshapeBBEnvState->partNrgPrevSF[k] = 0; + self->reshapeBBEnvState->partNrgPrev2SF[k] = 0; + self->reshapeBBEnvState->frameNrgPrevSF[k] = 0; + } + } + + self->reshapeBBEnvState->alpha__FDK = + FL2FXCONST_DBL(0.99637845575f); /* FDKexp(-64 / (0.4f * 44100)) */ + self->reshapeBBEnvState->beta__FDK = + FL2FXCONST_DBL(0.96436909488f); /* FDKexp(-64 / (0.04f * 44100)) */ +} + +static inline void getSlotNrgHQ(FIXP_DBL *RESTRICT pReal, + FIXP_DBL *RESTRICT pImag, + FIXP_DBL *RESTRICT slotNrg, INT maxValSF, + INT hybBands) { + INT qs; + FIXP_DBL nrg; + + /* qs = 12, 13, 14 */ + slotNrg[0] = ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + slotNrg[1] = ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + slotNrg[2] = ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + /* qs = 15 */ + slotNrg[3] = ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + /* qs = 16, 17 */ + nrg = ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + slotNrg[4] = nrg + ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + /* qs = 18, 19, 20 */ + nrg = ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + nrg += ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + slotNrg[5] = nrg + ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + /* qs = 21, 22 */ + nrg = ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + slotNrg[6] = nrg + ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + /* qs = 23, 24 */ + if (hybBands > 23) { + slotNrg[6] += ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + slotNrg[6] += ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + /* qs = 25, 26, 29, 28, 29 */ + nrg = ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + nrg += ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + nrg += ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + nrg += ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + slotNrg[7] = nrg + ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + /* qs = 30 ... min(41,hybBands-1) */ + nrg = ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + for (qs = 31; qs < hybBands; qs++) { + nrg += ((fPow2Div2((*pReal++) << maxValSF) + + fPow2Div2((*pImag++) << maxValSF)) >> + (SF_FACTOR_SLOT - 1)); + } + slotNrg[8] = nrg; + } else { + slotNrg[7] = (FIXP_DBL)0; + slotNrg[8] = (FIXP_DBL)0; + } +} + +static inline INT getMaxValDmx(FIXP_DBL *RESTRICT pReal, + FIXP_DBL *RESTRICT pImag, INT cplxBands, + INT hybBands) { + INT qs, clz; + FIXP_DBL maxVal = FL2FXCONST_DBL(0.0f); + + for (qs = 12; qs < cplxBands; qs++) { + maxVal |= fAbs(pReal[qs]); + maxVal |= fAbs(pImag[qs]); + } + for (; qs < hybBands; qs++) { + maxVal |= fAbs(pReal[qs]); + } + + clz = fixMax(0, CntLeadingZeros(maxVal) - 1); + + return (clz); +} + +static inline INT getMaxValDryWet(FIXP_DBL *RESTRICT pReal, + FIXP_DBL *RESTRICT pImag, + FIXP_DBL *RESTRICT pHybOutputRealDry, + FIXP_DBL *RESTRICT pHybOutputImagDry, + FIXP_DBL *RESTRICT pHybOutputRealWet, + FIXP_DBL *RESTRICT pHybOutputImagWet, + INT cplxBands, INT hybBands) { + INT qs, clz; + FIXP_DBL maxVal = FL2FXCONST_DBL(0.0f); + + for (qs = 12; qs < cplxBands; qs++) { + pReal[qs] = pHybOutputRealDry[qs] + pHybOutputRealWet[qs]; + maxVal |= fAbs(pReal[qs]); + pImag[qs] = pHybOutputImagDry[qs] + pHybOutputImagWet[qs]; + maxVal |= fAbs(pImag[qs]); + } + for (; qs < hybBands; qs++) { + pReal[qs] = pHybOutputRealDry[qs] + pHybOutputRealWet[qs]; + maxVal |= fAbs(pReal[qs]); + } + + clz = fixMax(0, CntLeadingZeros(maxVal) - 1); + + return (clz); +} + +static inline void slotAmp(FIXP_DBL *RESTRICT slotAmp_dry, + FIXP_DBL *RESTRICT slotAmp_wet, + FIXP_DBL *RESTRICT pHybOutputRealDry, + FIXP_DBL *RESTRICT pHybOutputImagDry, + FIXP_DBL *RESTRICT pHybOutputRealWet, + FIXP_DBL *RESTRICT pHybOutputImagWet, INT cplxBands, + INT hybBands) { + INT qs; + FIXP_DBL dry, wet; + + dry = wet = FL2FXCONST_DBL(0.0f); + for (qs = 0; qs < cplxBands; qs++) { + dry = fAddSaturate(dry, fPow2Div2(pHybOutputRealDry[qs]) + + fPow2Div2(pHybOutputImagDry[qs])); + wet = fAddSaturate(wet, fPow2Div2(pHybOutputRealWet[qs]) + + fPow2Div2(pHybOutputImagWet[qs])); + } + for (; qs < hybBands; qs++) { + dry = fAddSaturate(dry, fPow2Div2(pHybOutputRealDry[qs])); + wet = fAddSaturate(wet, fPow2Div2(pHybOutputRealWet[qs])); + } + *slotAmp_dry = dry; + *slotAmp_wet = wet; +} + +#if defined(__aarch64__) +__attribute__((noinline)) +#endif +static void +shapeBBEnv(FIXP_DBL *pHybOutputRealDry, FIXP_DBL *pHybOutputImagDry, + FIXP_DBL dryFac, INT scale, INT cplxBands, INT hybBands) { + INT qs; + + if (scale == 0) { + for (qs = 0; qs < cplxBands; qs++) { + pHybOutputRealDry[qs] = fMultDiv2(pHybOutputRealDry[qs], dryFac); + pHybOutputImagDry[qs] = fMultDiv2(pHybOutputImagDry[qs], dryFac); + } + for (; qs < hybBands; qs++) { + pHybOutputRealDry[qs] = fMultDiv2(pHybOutputRealDry[qs], dryFac); + } + } else { + for (qs = 0; qs < cplxBands; qs++) { + pHybOutputRealDry[qs] = fMultDiv2(pHybOutputRealDry[qs], dryFac) << scale; + pHybOutputImagDry[qs] = fMultDiv2(pHybOutputImagDry[qs], dryFac) << scale; + } + for (; qs < hybBands; qs++) { + pHybOutputRealDry[qs] = fMultDiv2(pHybOutputRealDry[qs], dryFac) << scale; + } + } +} + +static void extractBBEnv(spatialDec *self, INT inp, INT start, INT channels, + FIXP_DBL *pEnv, const SPATIAL_BS_FRAME *frame) { + INT ch, pb, prevChOffs; + INT clz, scale, scale_min, envSF; + INT scaleCur, scalePrev, commonScale; + INT slotNrgSF, partNrgSF, frameNrgSF; + INT *pPartNrgPrevSF, *pFrameNrgPrevSF; + INT *pNormNrgPrevSF, *pPartNrgPrev2SF; + + FIXP_DBL maxVal, env, frameNrg, normNrg; + FIXP_DBL *pReal, *pImag; + FIXP_DBL *partNrg, *partNrgPrev; + + C_ALLOC_SCRATCH_START(pScratchBuffer, FIXP_DBL, + (2 * 42 + MAX_PARAMETER_BANDS)); + C_ALLOC_SCRATCH_START(resPb, FIXP_DBL, (END_BB_ENV - START_BB_ENV)); + C_ALLOC_SCRATCH_START(resPbSF, INT, (END_BB_ENV - START_BB_ENV)); + + FIXP_DBL *slotNrg = pScratchBuffer + (2 * 42); + + RESHAPE_BBENV_STATE *pBBEnvState = self->reshapeBBEnvState; + + FIXP_DBL alpha = pBBEnvState->alpha__FDK; + /*FIXP_DBL alpha1 = (FL2FXCONST_DBL(1.0f) - alpha) << SF_ALPHA1;*/ + FIXP_DBL alpha1 = ((FIXP_DBL)MAXVAL_DBL - alpha) << SF_ALPHA1; + FIXP_DBL beta = pBBEnvState->beta__FDK; + /*FIXP_DBL beta1 = (FL2FXCONST_DBL(1.0f) - beta) << SF_BETA1;*/ + FIXP_DBL beta1 = ((FIXP_DBL)MAXVAL_DBL - beta) << SF_BETA1; + + INT shapeActiv = 1; + INT hybBands = fixMin(42, self->hybridBands); + INT staticScale = self->staticDecScale; + INT cplxBands; + cplxBands = fixMin(42, self->hybridBands); + + for (ch = start; ch < channels; ch++) { + if (inp == INP_DRY_WET) { + INT ch2 = row2channelGES[self->treeConfig][ch]; + if (ch2 == -1) { + continue; + } else { + if (frame->tempShapeEnableChannelGES[ch2]) { + shapeActiv = 1; + } else { + shapeActiv = 0; + } + } + prevChOffs = ch; + pReal = pScratchBuffer; + pImag = pScratchBuffer + 42; + clz = getMaxValDryWet( + pReal, pImag, self->hybOutputRealDry__FDK[ch], + self->hybOutputImagDry__FDK[ch], self->hybOutputRealWet__FDK[ch], + self->hybOutputImagWet__FDK[ch], cplxBands, hybBands); + } else { + prevChOffs = ch + self->numOutputChannels; + pReal = self->hybInputReal__FDK[ch]; + pImag = self->hybInputImag__FDK[ch]; + clz = getMaxValDmx(pReal, pImag, cplxBands, hybBands); + } + + partNrg = partNrgPrev = pBBEnvState->partNrgPrev__FDK[prevChOffs]; + pPartNrgPrevSF = &pBBEnvState->partNrgPrevSF[prevChOffs]; + pFrameNrgPrevSF = &pBBEnvState->frameNrgPrevSF[prevChOffs]; + pNormNrgPrevSF = &pBBEnvState->normNrgPrevSF[prevChOffs]; + pPartNrgPrev2SF = &pBBEnvState->partNrgPrev2SF[prevChOffs]; + + /* calculate slot energy */ + { + getSlotNrgHQ(&pReal[12], &pImag[12], slotNrg, clz, + fixMin(42, self->hybridBands)); /* scale slotNrg: + 2*(staticScale-clz) + + SF_FACTOR_SLOT */ + } + + slotNrgSF = 2 * (staticScale - clz) + SF_FACTOR_SLOT; + frameNrgSF = 2 * (staticScale - clz) + SF_FACTOR_SLOT; + + partNrgSF = fixMax(slotNrgSF - SF_ALPHA1 + 1, + pPartNrgPrevSF[0] - pPartNrgPrev2SF[0] + 1); + scalePrev = fixMax(fixMin(partNrgSF - pPartNrgPrevSF[0], DFRACT_BITS - 1), + -(DFRACT_BITS - 1)); + scaleCur = + fixMax(fixMin(partNrgSF - slotNrgSF + SF_ALPHA1, DFRACT_BITS - 1), + -(DFRACT_BITS - 1)); + + maxVal = FL2FXCONST_DBL(0.0f); + frameNrg = FL2FXCONST_DBL(0.0f); + if ((scaleCur < 0) && (scalePrev < 0)) { + scaleCur = -scaleCur; + scalePrev = -scalePrev; + for (pb = START_BB_ENV; pb < END_BB_ENV; pb++) { + partNrg[pb] = ((fMultDiv2(alpha1, slotNrg[pb]) << scaleCur) + + (fMultDiv2(alpha, partNrgPrev[pb]) << scalePrev)) + << 1; + maxVal |= partNrg[pb]; + frameNrg += slotNrg[pb] >> 3; + } + } else if ((scaleCur >= 0) && (scalePrev >= 0)) { + for (pb = START_BB_ENV; pb < END_BB_ENV; pb++) { + partNrg[pb] = ((fMultDiv2(alpha1, slotNrg[pb]) >> scaleCur) + + (fMultDiv2(alpha, partNrgPrev[pb]) >> scalePrev)) + << 1; + maxVal |= partNrg[pb]; + frameNrg += slotNrg[pb] >> 3; + } + } else if ((scaleCur < 0) && (scalePrev >= 0)) { + scaleCur = -scaleCur; + for (pb = START_BB_ENV; pb < END_BB_ENV; pb++) { + partNrg[pb] = ((fMultDiv2(alpha1, slotNrg[pb]) << scaleCur) + + (fMultDiv2(alpha, partNrgPrev[pb]) >> scalePrev)) + << 1; + maxVal |= partNrg[pb]; + frameNrg += slotNrg[pb] >> 3; + } + } else { /* if ( (scaleCur >= 0) && (scalePrev < 0) ) */ + scalePrev = -scalePrev; + for (pb = START_BB_ENV; pb < END_BB_ENV; pb++) { + partNrg[pb] = ((fMultDiv2(alpha1, slotNrg[pb]) >> scaleCur) + + (fMultDiv2(alpha, partNrgPrev[pb]) << scalePrev)) + << 1; + maxVal |= partNrg[pb]; + frameNrg += slotNrg[pb] >> 3; + } + } + + /* frameNrg /= (END_BB_ENV - START_BB_ENV); 0.88888888888f = + * (1/(END_BB_ENV-START_BB_ENV)<<3; shift with 3 is compensated in loop + * above */ + frameNrg = fMult(frameNrg, FL2FXCONST_DBL(0.88888888888f)); + + /* store scalefactor and headroom for part nrg prev */ + pPartNrgPrevSF[0] = partNrgSF; + pPartNrgPrev2SF[0] = fixMax(0, CntLeadingZeros(maxVal) - 1); + + commonScale = fixMax(frameNrgSF - SF_ALPHA1 + 1, pFrameNrgPrevSF[0] + 1); + scalePrev = fixMin(commonScale - pFrameNrgPrevSF[0], DFRACT_BITS - 1); + scaleCur = fixMin(commonScale - frameNrgSF + SF_ALPHA1, DFRACT_BITS - 1); + frameNrgSF = commonScale; + + frameNrg = ((fMultDiv2(alpha1, frameNrg) >> scaleCur) + + (fMultDiv2(alpha, pBBEnvState->frameNrgPrev__FDK[prevChOffs]) >> + scalePrev)) + << 1; + + clz = fixMax(0, CntLeadingZeros(frameNrg) - 1); + pBBEnvState->frameNrgPrev__FDK[prevChOffs] = frameNrg << clz; + pFrameNrgPrevSF[0] = frameNrgSF - clz; + + env = FL2FXCONST_DBL(0.0f); + scale = clz + partNrgSF - frameNrgSF; + scale_min = DFRACT_BITS - 1; + for (pb = START_BB_ENV; pb < END_BB_ENV; pb++) { + if ((partNrg[pb] | slotNrg[pb]) != FL2FXCONST_DBL(0.0f)) { + INT s; + INT sc = 0; + INT sn = fixMax(0, CntLeadingZeros(slotNrg[pb]) - 1); + FIXP_DBL inv_sqrt = invSqrtNorm2(partNrg[pb], &sc); + FIXP_DBL res = fMult(slotNrg[pb] << sn, fPow2(inv_sqrt)); + + s = fixMax(0, CntLeadingZeros(res) - 1); + res = res << s; + + sc = scale - (2 * sc - sn - s); + scale_min = fixMin(scale_min, sc); + + resPb[pb] = res; + resPbSF[pb] = sc; + } else { + resPb[pb] = (FIXP_DBL)0; + resPbSF[pb] = 0; + } + } + + scale_min = 4 - scale_min; + + for (pb = START_BB_ENV; pb < END_BB_ENV; pb++) { + INT sc = fixMax(fixMin(resPbSF[pb] + scale_min, DFRACT_BITS - 1), + -(DFRACT_BITS - 1)); + + if (sc < 0) { + env += resPb[pb] << (-sc); + } else { + env += resPb[pb] >> (sc); + } + } + + env = fMultDiv2(env, pBBEnvState->frameNrgPrev__FDK[prevChOffs]); + envSF = slotNrgSF + scale_min + 1; + + commonScale = fixMax(envSF - SF_BETA1 + 1, pNormNrgPrevSF[0] + 1); + scalePrev = fixMin(commonScale - pNormNrgPrevSF[0], DFRACT_BITS - 1); + scaleCur = fixMin(commonScale - envSF + SF_BETA1, DFRACT_BITS - 1); + + normNrg = ((fMultDiv2(beta1, env) >> scaleCur) + + (fMultDiv2(beta, pBBEnvState->normNrgPrev__FDK[prevChOffs]) >> + scalePrev)) + << 1; + + clz = fixMax(0, CntLeadingZeros(normNrg) - 1); + pBBEnvState->normNrgPrev__FDK[prevChOffs] = normNrg << clz; + pNormNrgPrevSF[0] = commonScale - clz; + + if (shapeActiv) { + if ((env | normNrg) != FL2FXCONST_DBL(0.0f)) { + INT sc, se, sn; + se = fixMax(0, CntLeadingZeros(env) - 1); + sc = commonScale + SF_DIV32 - envSF + se; + env = fMult(sqrtFixp((env << se) >> (sc & 0x1)), + invSqrtNorm2(normNrg, &sn)); + + sc = fixMin((sc >> 1) - sn, DFRACT_BITS - 1); + if (sc < 0) { + env <<= (-sc); + } else { + env >>= (sc); + } + } + /* env is scaled by SF_DIV32/2 bits */ + } + pEnv[ch] = env; + } + + C_ALLOC_SCRATCH_END(resPbSF, INT, (END_BB_ENV - START_BB_ENV)); + C_ALLOC_SCRATCH_END(resPb, FIXP_DBL, (END_BB_ENV - START_BB_ENV)); + C_ALLOC_SCRATCH_END(pScratchBuffer, FIXP_DBL, (2 * 42 + MAX_PARAMETER_BANDS)); +} + +void SpatialDecReshapeBBEnv(spatialDec *self, const SPATIAL_BS_FRAME *frame, + INT ts) { + INT ch, scale; + INT dryFacSF, slotAmpSF; + FIXP_DBL tmp, dryFac, envShape; + FIXP_DBL slotAmp_dry, slotAmp_wet, slotAmp_ratio; + FIXP_DBL envDry[MAX_OUTPUT_CHANNELS], envDmx[2]; + + INT cplxBands; + INT hybBands = self->hybridBands - 6; + + cplxBands = self->hybridBands - 6; + + /* extract downmix envelope(s) */ + switch (self->treeConfig) { + default: + extractBBEnv(self, INP_DMX, 0, fMin(self->numInputChannels, 2), envDmx, + frame); + } + + /* extract dry and wet envelopes */ + extractBBEnv(self, INP_DRY_WET, 0, self->numOutputChannels, envDry, frame); + + for (ch = 0; ch < self->numOutputChannels; ch++) { + INT ch2; + + ch2 = row2channelGES[self->treeConfig][ch]; + + if (ch2 == -1) continue; + + if (frame->tempShapeEnableChannelGES[ch2]) { + INT sc; + + /* reshape dry and wet signals according to transmitted envelope */ + + /* De-quantize GES data */ + FDK_ASSERT((frame->bsEnvShapeData[ch2][ts] >= 0) && + (frame->bsEnvShapeData[ch2][ts] <= 4)); + FDK_ASSERT((self->envQuantMode == 0) || (self->envQuantMode == 1)); + envShape = + FX_CFG2FX_DBL(envShapeDataTable__FDK[frame->bsEnvShapeData[ch2][ts]] + [self->envQuantMode]); + + /* get downmix channel */ + ch2 = self->row2channelDmxGES[ch]; + + /* multiply ratio with dmx envelope; tmp is scaled by SF_DIV32/2+SF_SHAPE + * bits */ + if (ch2 == 2) { + tmp = fMultDiv2(envShape, envDmx[0]) + fMultDiv2(envShape, envDmx[1]); + } else { + tmp = fMult(envShape, envDmx[ch2]); + } + + /* weighting factors */ + dryFacSF = slotAmpSF = 0; + dryFac = slotAmp_ratio = FL2FXCONST_DBL(0.0f); + + /* dryFac will be scaled by dryFacSF bits */ + if (envDry[ch] != FL2FXCONST_DBL(0.0f)) { + envDry[ch] = invSqrtNorm2(envDry[ch], &dryFacSF); + dryFac = fMultDiv2(tmp, fPow2Div2(envDry[ch])) << 2; + dryFacSF = SF_SHAPE + 2 * dryFacSF; + } + + /* calculate slotAmp_dry and slotAmp_wet */ + slotAmp(&slotAmp_dry, &slotAmp_wet, &self->hybOutputRealDry__FDK[ch][6], + &self->hybOutputImagDry__FDK[ch][6], + &self->hybOutputRealWet__FDK[ch][6], + &self->hybOutputImagWet__FDK[ch][6], cplxBands, hybBands); + + /* slotAmp_ratio will be scaled by slotAmpSF bits */ + if (slotAmp_dry != FL2FXCONST_DBL(0.0f)) { + sc = fixMax(0, CntLeadingZeros(slotAmp_wet) - 1); + sc = sc - (sc & 1); + + slotAmp_wet = sqrtFixp(slotAmp_wet << sc); + slotAmp_dry = invSqrtNorm2(slotAmp_dry, &slotAmpSF); + + slotAmp_ratio = fMult(slotAmp_wet, slotAmp_dry); + slotAmpSF = slotAmpSF - (sc >> 1); + } + + /* calculate common scale factor */ + scale = + fixMax(3, fixMax(dryFacSF, slotAmpSF)); /* scale is at least with 3 + bits to avoid overflows + when calculating dryFac */ + dryFac = dryFac >> (scale - dryFacSF); + slotAmp_ratio = slotAmp_ratio >> (scale - slotAmpSF); + + /* limit dryFac */ + dryFac = fixMax( + FL2FXCONST_DBL(0.25f) >> (INT)fixMin(2 * scale, DFRACT_BITS - 1), + fMult(dryFac, slotAmp_ratio) - (slotAmp_ratio >> scale) + + (dryFac >> scale)); + dryFac = fixMin( + FL2FXCONST_DBL(0.50f) >> (INT)fixMin(2 * scale - 3, DFRACT_BITS - 1), + dryFac); /* reduce shift bits by 3, because upper + limit 4.0 is scaled with 3 bits */ + scale = 2 * scale + 1; + + /* improve precision for dryFac */ + sc = fixMax(0, CntLeadingZeros(dryFac) - 1); + dryFac = dryFac << (INT)fixMin(scale, sc); + scale = scale - fixMin(scale, sc); + + /* shaping */ + shapeBBEnv(&self->hybOutputRealDry__FDK[ch][6], + &self->hybOutputImagDry__FDK[ch][6], dryFac, scale, cplxBands, + hybBands); + } + } +} diff --git a/libSACdec/src/sac_reshapeBBEnv.h b/libSACdec/src/sac_reshapeBBEnv.h new file mode 100644 index 0000000..1658530 --- /dev/null +++ b/libSACdec/src/sac_reshapeBBEnv.h @@ -0,0 +1,114 @@ +/* ----------------------------------------------------------------------------- +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 Dec guided envelope shaping + +*******************************************************************************/ + +#ifndef SAC_RESHAPEBBENV_H +#define SAC_RESHAPEBBENV_H + +#include "sac_dec_interface.h" + +#define BB_ENV_SIZE 9 /* END_BB_ENV - START_BB_ENV */ + +void initBBEnv(spatialDec *self, int initStatesFlag); +void SpatialDecReshapeBBEnv(spatialDec *self, const SPATIAL_BS_FRAME *frame, + int ts); + +#endif diff --git a/libSACdec/src/sac_rom.cpp b/libSACdec/src/sac_rom.cpp new file mode 100644 index 0000000..4285b65 --- /dev/null +++ b/libSACdec/src/sac_rom.cpp @@ -0,0 +1,709 @@ +/* ----------------------------------------------------------------------------- +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 Dec tables + +*******************************************************************************/ + +#include "sac_rom.h" +#include "sac_calcM1andM2.h" + +#define SCALE_CPC(a) (FL2FXCONST_CFG(a / (float)(1 << SCALE_PARAM_M1))) +const FIXP_CFG dequantCPC__FDK[] = { + SCALE_CPC(-2.0f), SCALE_CPC(-1.9f), SCALE_CPC(-1.8f), SCALE_CPC(-1.7f), + SCALE_CPC(-1.6f), SCALE_CPC(-1.5f), SCALE_CPC(-1.4f), SCALE_CPC(-1.3f), + SCALE_CPC(-1.2f), SCALE_CPC(-1.1f), SCALE_CPC(-1.0f), SCALE_CPC(-0.9f), + SCALE_CPC(-0.8f), SCALE_CPC(-0.7f), SCALE_CPC(-0.6f), SCALE_CPC(-0.5f), + SCALE_CPC(-0.4f), SCALE_CPC(-0.3f), SCALE_CPC(-0.2f), SCALE_CPC(-0.1f), + SCALE_CPC(0.0f), SCALE_CPC(0.1f), SCALE_CPC(0.2f), SCALE_CPC(0.3f), + SCALE_CPC(0.4f), SCALE_CPC(0.5f), SCALE_CPC(0.6f), SCALE_CPC(0.7f), + SCALE_CPC(0.8f), SCALE_CPC(0.9f), SCALE_CPC(1.0f), SCALE_CPC(1.1f), + SCALE_CPC(1.2f), SCALE_CPC(1.3f), SCALE_CPC(1.4f), SCALE_CPC(1.5f), + SCALE_CPC(1.6f), SCALE_CPC(1.7f), SCALE_CPC(1.8f), SCALE_CPC(1.9f), + SCALE_CPC(2.0f), SCALE_CPC(2.1f), SCALE_CPC(2.2f), SCALE_CPC(2.3f), + SCALE_CPC(2.4f), SCALE_CPC(2.5f), SCALE_CPC(2.6f), SCALE_CPC(2.7f), + SCALE_CPC(2.8f), SCALE_CPC(2.9f), SCALE_CPC(3.0f)}; + +#define SCALE_ICC(a) (FL2FXCONST_CFG(a)) +const FIXP_CFG dequantICC__FDK[8] = { + /*SCALE_ICC(1.00000f)*/ FX_DBL2FX_CFG(MAXVAL_DBL), + SCALE_ICC(0.9370f), + SCALE_ICC(0.84118f), + SCALE_ICC(0.60092f), + SCALE_ICC(0.36764f), + SCALE_ICC(0.0000f), + SCALE_ICC(-0.58900f), + SCALE_ICC(-0.9900f)}; + +#define SCALE_CLD2(a) (FL2FXCONST_CFG(a / (float)(1 << 8))) +const FIXP_CFG dequantCLD__FDK[31] = { + SCALE_CLD2(-150.0f), SCALE_CLD2(-45.0f), SCALE_CLD2(-40.0f), + SCALE_CLD2(-35.0f), SCALE_CLD2(-30.0f), SCALE_CLD2(-25.0f), + SCALE_CLD2(-22.0f), SCALE_CLD2(-19.0f), SCALE_CLD2(-16.0f), + SCALE_CLD2(-13.0f), SCALE_CLD2(-10.0f), SCALE_CLD2(-8.0f), + SCALE_CLD2(-6.0f), SCALE_CLD2(-4.0f), SCALE_CLD2(-2.0f), + SCALE_CLD2(0.0f), SCALE_CLD2(2.0f), SCALE_CLD2(4.0f), + SCALE_CLD2(6.0f), SCALE_CLD2(8.0f), SCALE_CLD2(10.0f), + SCALE_CLD2(13.0f), SCALE_CLD2(16.0f), SCALE_CLD2(19.0f), + SCALE_CLD2(22.0f), SCALE_CLD2(25.0f), SCALE_CLD2(30.0f), + SCALE_CLD2(35.0f), SCALE_CLD2(40.0f), SCALE_CLD2(45.0f), + SCALE_CLD2(150.0f)}; + +#define SCALE_IPD(a) (FL2FXCONST_CFG(a / (float)(1 << IPD_SCALE))) +const FIXP_CFG dequantIPD__FDK[16] = { + /* SCALE_IPD(0.000000000f), SCALE_IPD(0.392699082f), + SCALE_IPD(0.785398163f), SCALE_IPD(1.178097245f), + SCALE_IPD(1.570796327f), SCALE_IPD(1.963495408f), + SCALE_IPD(2.356194490f), SCALE_IPD(2.748893572f), + SCALE_IPD(3.141592654f), SCALE_IPD(3.534291735f), + SCALE_IPD(3.926990817f), SCALE_IPD(4.319689899f), + SCALE_IPD(4.712388980f), SCALE_IPD(5.105088062f), + SCALE_IPD(5.497787144f), SCALE_IPD(5.890486225f) */ + SCALE_IPD(0.00000000000000f), SCALE_IPD(0.392699082f), + SCALE_IPD(0.78539816339745f), SCALE_IPD(1.178097245f), + SCALE_IPD(1.57079632679490f), SCALE_IPD(1.963495408f), + SCALE_IPD(2.35619449019234f), SCALE_IPD(2.748893572f), + SCALE_IPD(3.14159265358979f), SCALE_IPD(3.534291735f), + SCALE_IPD(3.92699081698724f), SCALE_IPD(4.319689899f), + SCALE_IPD(4.71238898038469f), SCALE_IPD(5.105088062f), + SCALE_IPD(5.49778714378214f), SCALE_IPD(5.890486225f)}; + +#define SCALE_SPLIT_ANGLE(a) (FL2FXCONST_CFG(a / (float)(1 << IPD_SCALE))) +/* + Generate table dequantIPD_CLD_ICC_splitAngle__FDK[16][31][8]: + + #define ABS_THR ( 1e-9f * 32768 * 32768 ) + + float dequantICC[] = + {1.0000f,0.9370f,0.84118f,0.60092f,0.36764f,0.0f,-0.5890f,-0.9900f}; float + dequantCLD[] = + {-150.0,-45.0,-40.0,-35.0,-30.0,-25.0,-22.0,-19.0,-16.0,-13.0,-10.0, -8.0, + -6.0, -4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, + 10.0, 13.0, 16.0, 19.0, 22.0, 25.0, 30.0, 35.0, 40.0, 45.0, 150.0 }; float + dequantIPD[] = + {0.f,0.392699082f,0.785398163f,1.178097245f,1.570796327f,1.963495408f, + 2.35619449f,2.748893572f,3.141592654f,3.534291735f,3.926990817f, + 4.319689899f,4.71238898f,5.105088062f,5.497787144f,5.890486225f}; + + for (ipdIdx=0; ipdIdx<16; ipdIdx++) + for (cldIdx=0; cldIdx<31; cldIdx++) + for (iccIdx=0; iccIdx<8; iccIdx++) { + ipd = dequantIPD[ipdIdx]; + cld = dequantCLD[cldIdx]; + icc = dequantICC[iccIdx]; + iidLin = (float) pow(10.0f, cld / 20.0f); + iidLin2 = iidLin * iidLin; + iidLin21 = iidLin2 + 1.0f; + sinIpd = (float) sin(ipd); + cosIpd = (float) cos(ipd); + temp1 = 2.0f * icc * iidLin; + temp1c = temp1 * cosIpd; + ratio = (iidLin21 + temp1c) / (iidLin21 + temp1) + ABS_THR; + w2 = (float) pow(ratio, 0.25f); + w1 = 2.0f - w2; + dequantIPD_CLD_ICC_splitAngle__FDK[ipdIdx][cldIdx][iccIdx] = (float) + atan2(w2 * sinIpd, w1 * iidLin + w2 * cosIpd); + } +*/ + +#define SCALE_CLD(a) (FL2FXCONST_CFG(a)) + +const FIXP_CFG dequantCLD_c_l[31] = { + SCALE_CLD(0.0000000316f), + SCALE_CLD(0.0056233243f), + SCALE_CLD(0.0099994997f), + SCALE_CLD(0.0177799836f), + SCALE_CLD(0.0316069759f), + SCALE_CLD(0.0561454296f), + SCALE_CLD(0.0791834071f), + SCALE_CLD(0.1115021780f), + SCALE_CLD(0.1565355062f), + SCALE_CLD(0.2184644639f), + SCALE_CLD(0.3015113473f), + SCALE_CLD(0.3698741496f), + SCALE_CLD(0.4480624795f), + SCALE_CLD(0.5336171389f), + SCALE_CLD(0.6219832301f), + SCALE_CLD(0.7071067691f), + SCALE_CLD(0.7830305696f), + SCALE_CLD(0.8457261920f), + SCALE_CLD(0.8940021992f), + SCALE_CLD(0.9290818572f), + SCALE_CLD(0.9534626007f), + SCALE_CLD(0.9758449197f), + SCALE_CLD(0.9876723289f), + SCALE_CLD(0.9937641621f), + SCALE_CLD(0.9968600869f), + SCALE_CLD(0.9984226227f), + SCALE_CLD(0.9995003939f), + SCALE_CLD(0.9998419285f), + SCALE_CLD(0.9999499917f), + SCALE_CLD(0.9999842048f), + /*SCALE_CLD(1.0000000000f)*/ FX_DBL2FX_CFG(MAXVAL_DBL)}; + +#define SC_H(a) (FL2FXCONST_CFG(a)) +#define DATA_TYPE_H FIXP_CFG + +/* not correlated tables */ +const DATA_TYPE_H H11_nc[31][8] = { + {SC_H(0.0000000316f), SC_H(0.0000000296f), SC_H(0.0000000266f), + SC_H(0.0000000190f), SC_H(0.0000000116f), SC_H(0.0000000000f), + SC_H(-0.0000000186f), SC_H(-0.0000000313f)}, + {SC_H(0.0056233243f), SC_H(0.0052728835f), SC_H(0.0047394098f), + SC_H(0.0033992692f), SC_H(0.0020946222f), SC_H(0.0000316215f), + SC_H(-0.0032913829f), SC_H(-0.0055664564f)}, + {SC_H(0.0099994997f), SC_H(0.0093815643f), SC_H(0.0084402543f), + SC_H(0.0060722125f), SC_H(0.0037622179f), SC_H(0.0000999898f), + SC_H(-0.0058238208f), SC_H(-0.0098974844f)}, + {SC_H(0.0177799836f), SC_H(0.0166974831f), SC_H(0.0150465844f), + SC_H(0.0108831404f), SC_H(0.0068073822f), SC_H(0.0003161267f), + SC_H(-0.0102626514f), SC_H(-0.0175957214f)}, + {SC_H(0.0316069759f), SC_H(0.0297324844f), SC_H(0.0268681273f), + SC_H(0.0196138974f), SC_H(0.0124691967f), SC_H(0.0009989988f), + SC_H(-0.0179452803f), SC_H(-0.0312700421f)}, + {SC_H(0.0561454296f), SC_H(0.0529650487f), SC_H(0.0480896905f), + SC_H(0.0356564634f), SC_H(0.0232860073f), SC_H(0.0031523081f), + SC_H(-0.0309029408f), SC_H(-0.0555154830f)}, + {SC_H(0.0791834071f), SC_H(0.0748842582f), SC_H(0.0682762116f), + SC_H(0.0513241664f), SC_H(0.0343080349f), SC_H(0.0062700072f), + SC_H(-0.0422340371f), SC_H(-0.0782499388f)}, + {SC_H(0.1115021780f), SC_H(0.1057924852f), SC_H(0.0969873071f), + SC_H(0.0742305145f), SC_H(0.0511277616f), SC_H(0.0124327289f), + SC_H(-0.0566596612f), SC_H(-0.1100896299f)}, + {SC_H(0.1565355062f), SC_H(0.1491366178f), SC_H(0.1376826316f), + SC_H(0.1078186408f), SC_H(0.0770794004f), SC_H(0.0245033558f), + SC_H(-0.0735980421f), SC_H(-0.1543303132f)}, + {SC_H(0.2184644639f), SC_H(0.2091979682f), SC_H(0.1947948188f), + SC_H(0.1568822265f), SC_H(0.1172478944f), SC_H(0.0477267131f), + SC_H(-0.0899507254f), SC_H(-0.2148526460f)}, + {SC_H(0.3015113473f), SC_H(0.2904391289f), SC_H(0.2731673419f), + SC_H(0.2273024023f), SC_H(0.1786239147f), SC_H(0.0909090787f), + SC_H(-0.0964255333f), SC_H(-0.2951124907f)}, + {SC_H(0.3698741496f), SC_H(0.3578284085f), SC_H(0.3390066922f), + SC_H(0.2888108492f), SC_H(0.2351117432f), SC_H(0.1368068755f), + SC_H(-0.0850296095f), SC_H(-0.3597966135f)}, + {SC_H(0.4480624795f), SC_H(0.4354025424f), SC_H(0.4156077504f), + SC_H(0.3627120256f), SC_H(0.3058823943f), SC_H(0.2007599771f), + SC_H(-0.0484020934f), SC_H(-0.4304940701f)}, + {SC_H(0.5336171389f), SC_H(0.5208471417f), SC_H(0.5008935928f), + SC_H(0.4476420581f), SC_H(0.3905044496f), SC_H(0.2847472429f), + SC_H(0.0276676007f), SC_H(-0.4966579080f)}, + {SC_H(0.6219832301f), SC_H(0.6096963882f), SC_H(0.5905415416f), + SC_H(0.5396950245f), SC_H(0.4856070578f), SC_H(0.3868631124f), + SC_H(0.1531652957f), SC_H(-0.5045361519f)}, + {SC_H(0.7071067691f), SC_H(0.6958807111f), SC_H(0.6784504056f), + SC_H(0.6326373219f), SC_H(0.5847306848f), SC_H(0.4999999702f), + SC_H(0.3205464482f), SC_H(0.0500000045f)}, + {SC_H(0.7830305696f), SC_H(0.7733067870f), SC_H(0.7582961321f), + SC_H(0.7194055915f), SC_H(0.6797705293f), SC_H(0.6131368876f), + SC_H(0.4997332692f), SC_H(0.6934193969f)}, + {SC_H(0.8457261920f), SC_H(0.8377274871f), SC_H(0.8254694939f), + SC_H(0.7942851782f), SC_H(0.7635439038f), SC_H(0.7152527571f), + SC_H(0.6567122936f), SC_H(0.8229061961f)}, + {SC_H(0.8940021992f), SC_H(0.8877248168f), SC_H(0.8781855106f), + SC_H(0.8544237614f), SC_H(0.8318918347f), SC_H(0.7992399335f), + SC_H(0.7751275301f), SC_H(0.8853276968f)}, + {SC_H(0.9290818572f), SC_H(0.9243524075f), SC_H(0.9172304869f), + SC_H(0.8998877406f), SC_H(0.8841174841f), SC_H(0.8631930947f), + SC_H(0.8565139771f), SC_H(0.9251161218f)}, + {SC_H(0.9534626007f), SC_H(0.9500193000f), SC_H(0.9448821545f), + SC_H(0.9326565266f), SC_H(0.9220023751f), SC_H(0.9090909362f), + SC_H(0.9096591473f), SC_H(0.9514584541f)}, + {SC_H(0.9758449197f), SC_H(0.9738122821f), SC_H(0.9708200693f), + SC_H(0.9639287591f), SC_H(0.9582763910f), SC_H(0.9522733092f), + SC_H(0.9553207159f), SC_H(0.9750427008f)}, + {SC_H(0.9876723289f), SC_H(0.9865267277f), SC_H(0.9848603010f), + SC_H(0.9811310172f), SC_H(0.9782302976f), SC_H(0.9754966497f), + SC_H(0.9779621363f), SC_H(0.9873252511f)}, + {SC_H(0.9937641621f), SC_H(0.9931397438f), SC_H(0.9922404289f), + SC_H(0.9902750254f), SC_H(0.9888116717f), SC_H(0.9875672460f), + SC_H(0.9891131520f), SC_H(0.9936066866f)}, + {SC_H(0.9968600869f), SC_H(0.9965277910f), SC_H(0.9960530400f), + SC_H(0.9950347543f), SC_H(0.9943022728f), SC_H(0.9937300086f), + SC_H(0.9946073294f), SC_H(0.9967863560f)}, + {SC_H(0.9984226227f), SC_H(0.9982488155f), SC_H(0.9980020523f), + SC_H(0.9974802136f), SC_H(0.9971146584f), SC_H(0.9968476892f), + SC_H(0.9973216057f), SC_H(0.9983873963f)}, + {SC_H(0.9995003939f), SC_H(0.9994428754f), SC_H(0.9993617535f), + SC_H(0.9991930723f), SC_H(0.9990783334f), SC_H(0.9990010262f), + SC_H(0.9991616607f), SC_H(0.9994897842f)}, + {SC_H(0.9998419285f), SC_H(0.9998232722f), SC_H(0.9997970462f), + SC_H(0.9997430444f), SC_H(0.9997069836f), SC_H(0.9996838570f), + SC_H(0.9997364879f), SC_H(0.9998386502f)}, + {SC_H(0.9999499917f), SC_H(0.9999440312f), SC_H(0.9999356270f), + SC_H(0.9999184012f), SC_H(0.9999070764f), SC_H(0.9998999834f), + SC_H(0.9999169707f), SC_H(0.9999489784f)}, + {SC_H(0.9999842048f), SC_H(0.9999822974f), SC_H(0.9999796152f), + SC_H(0.9999741912f), SC_H(0.9999706149f), SC_H(0.9999684095f), + SC_H(0.9999738336f), SC_H(0.9999839067f)}, + /* { SC_H( 1.0000000000f), SC_H( 1.0000000000f), SC_H( 1.0000000000f), + SC_H( 1.0000000000f), SC_H( 1.0000000000f), SC_H( 1.0000000000f), + SC_H( 1.0000000000f), SC_H( 1.0000000000f)} */ + {FX_DBL2FX_CFG(MAXVAL_DBL), FX_DBL2FX_CFG(MAXVAL_DBL), + FX_DBL2FX_CFG(MAXVAL_DBL), FX_DBL2FX_CFG(MAXVAL_DBL), + FX_DBL2FX_CFG(MAXVAL_DBL), FX_DBL2FX_CFG(MAXVAL_DBL), + FX_DBL2FX_CFG(MAXVAL_DBL), FX_DBL2FX_CFG(MAXVAL_DBL)}}; +const DATA_TYPE_H H12_nc[31][8] = { + {SC_H(0.0000000000f), SC_H(0.0000000110f), SC_H(0.0000000171f), + SC_H(0.0000000253f), SC_H(0.0000000294f), SC_H(0.0000000316f), + SC_H(0.0000000256f), SC_H(0.0000000045f)}, + {SC_H(0.0000000000f), SC_H(0.0019540924f), SC_H(0.0030265113f), + SC_H(0.0044795922f), SC_H(0.0052186525f), SC_H(0.0056232354f), + SC_H(0.0045594489f), SC_H(0.0007977085f)}, + {SC_H(0.0000000000f), SC_H(0.0034606720f), SC_H(0.0053620986f), + SC_H(0.0079446984f), SC_H(0.0092647560f), SC_H(0.0099989995f), + SC_H(0.0081285369f), SC_H(0.0014247064f)}, + {SC_H(0.0000000000f), SC_H(0.0061091618f), SC_H(0.0094724922f), + SC_H(0.0140600521f), SC_H(0.0164252054f), SC_H(0.0177771728f), + SC_H(0.0145191532f), SC_H(0.0025531140f)}, + {SC_H(0.0000000000f), SC_H(0.0107228858f), SC_H(0.0166464616f), + SC_H(0.0247849934f), SC_H(0.0290434174f), SC_H(0.0315911844f), + SC_H(0.0260186065f), SC_H(0.0046027615f)}, + {SC_H(0.0000000000f), SC_H(0.0186282862f), SC_H(0.0289774220f), + SC_H(0.0433696397f), SC_H(0.0510888547f), SC_H(0.0560568646f), + SC_H(0.0468755551f), SC_H(0.0083869267f)}, + {SC_H(0.0000000000f), SC_H(0.0257363543f), SC_H(0.0401044972f), + SC_H(0.0602979437f), SC_H(0.0713650510f), SC_H(0.0789347738f), + SC_H(0.0669798329f), SC_H(0.0121226767f)}, + {SC_H(0.0000000000f), SC_H(0.0352233723f), SC_H(0.0550108925f), + SC_H(0.0832019597f), SC_H(0.0990892947f), SC_H(0.1108068749f), + SC_H(0.0960334241f), SC_H(0.0176920593f)}, + {SC_H(0.0000000000f), SC_H(0.0475566536f), SC_H(0.0744772255f), + SC_H(0.1134835035f), SC_H(0.1362429112f), SC_H(0.1546057910f), + SC_H(0.1381545961f), SC_H(0.0261824392f)}, + {SC_H(0.0000000000f), SC_H(0.0629518181f), SC_H(0.0989024863f), + SC_H(0.1520351619f), SC_H(0.1843357086f), SC_H(0.2131874412f), + SC_H(0.1990868896f), SC_H(0.0395608991f)}, + {SC_H(0.0000000000f), SC_H(0.0809580907f), SC_H(0.1276271492f), + SC_H(0.1980977356f), SC_H(0.2429044843f), SC_H(0.2874797881f), + SC_H(0.2856767476f), SC_H(0.0617875643f)}, + {SC_H(0.0000000000f), SC_H(0.0936254337f), SC_H(0.1479234397f), + SC_H(0.2310739607f), SC_H(0.2855334580f), SC_H(0.3436433673f), + SC_H(0.3599678576f), SC_H(0.0857512727f)}, + {SC_H(0.0000000000f), SC_H(0.1057573780f), SC_H(0.1674221754f), + SC_H(0.2630588412f), SC_H(0.3274079263f), SC_H(0.4005688727f), + SC_H(0.4454404712f), SC_H(0.1242370531f)}, + {SC_H(0.0000000000f), SC_H(0.1160409302f), SC_H(0.1839915067f), + SC_H(0.2904545665f), SC_H(0.3636667728f), SC_H(0.4512939751f), + SC_H(0.5328993797f), SC_H(0.1951362640f)}, + {SC_H(0.0000000000f), SC_H(0.1230182052f), SC_H(0.1952532977f), + SC_H(0.3091802597f), SC_H(0.3886501491f), SC_H(0.4870318770f), + SC_H(0.6028295755f), SC_H(0.3637395203f)}, + {SC_H(0.0000000000f), SC_H(0.1254990250f), SC_H(0.1992611140f), + SC_H(0.3158638775f), SC_H(0.3976053298f), SC_H(0.5000000000f), + SC_H(0.6302776933f), SC_H(0.7053368092f)}, + {SC_H(0.0000000000f), SC_H(0.1230182052f), SC_H(0.1952533126f), + SC_H(0.3091802597f), SC_H(0.3886501491f), SC_H(0.4870319068f), + SC_H(0.6028295755f), SC_H(0.3637394905f)}, + {SC_H(0.0000000000f), SC_H(0.1160409302f), SC_H(0.1839915216f), + SC_H(0.2904545665f), SC_H(0.3636668026f), SC_H(0.4512939751f), + SC_H(0.5328993797f), SC_H(0.1951362044f)}, + {SC_H(0.0000000000f), SC_H(0.1057573855f), SC_H(0.1674221754f), + SC_H(0.2630588710f), SC_H(0.3274079263f), SC_H(0.4005688727f), + SC_H(0.4454405010f), SC_H(0.1242370382f)}, + {SC_H(0.0000000000f), SC_H(0.0936254337f), SC_H(0.1479234397f), + SC_H(0.2310739607f), SC_H(0.2855334580f), SC_H(0.3436433673f), + SC_H(0.3599678576f), SC_H(0.0857512653f)}, + {SC_H(0.0000000000f), SC_H(0.0809580907f), SC_H(0.1276271492f), + SC_H(0.1980977207f), SC_H(0.2429044843f), SC_H(0.2874797881f), + SC_H(0.2856767476f), SC_H(0.0617875606f)}, + {SC_H(0.0000000000f), SC_H(0.0629518107f), SC_H(0.0989024863f), + SC_H(0.1520351619f), SC_H(0.1843357235f), SC_H(0.2131874412f), + SC_H(0.1990868896f), SC_H(0.0395609401f)}, + {SC_H(0.0000000000f), SC_H(0.0475566462f), SC_H(0.0744772255f), + SC_H(0.1134835184f), SC_H(0.1362429112f), SC_H(0.1546057761f), + SC_H(0.1381545961f), SC_H(0.0261824802f)}, + {SC_H(0.0000000000f), SC_H(0.0352233797f), SC_H(0.0550108962f), + SC_H(0.0832019448f), SC_H(0.0990892798f), SC_H(0.1108068526f), + SC_H(0.0960334465f), SC_H(0.0176920686f)}, + {SC_H(0.0000000000f), SC_H(0.0257363524f), SC_H(0.0401044935f), + SC_H(0.0602979474f), SC_H(0.0713650808f), SC_H(0.0789347589f), + SC_H(0.0669797957f), SC_H(0.0121226516f)}, + {SC_H(0.0000000000f), SC_H(0.0186282881f), SC_H(0.0289774258f), + SC_H(0.0433696248f), SC_H(0.0510888547f), SC_H(0.0560568906f), + SC_H(0.0468755886f), SC_H(0.0083869714f)}, + {SC_H(0.0000000000f), SC_H(0.0107228830f), SC_H(0.0166464727f), + SC_H(0.0247849822f), SC_H(0.0290434249f), SC_H(0.0315911621f), + SC_H(0.0260186475f), SC_H(0.0046027377f)}, + {SC_H(0.0000000000f), SC_H(0.0061091576f), SC_H(0.0094724894f), + SC_H(0.0140600465f), SC_H(0.0164251942f), SC_H(0.0177771524f), + SC_H(0.0145191504f), SC_H(0.0025530567f)}, + {SC_H(0.0000000000f), SC_H(0.0034606743f), SC_H(0.0053620976f), + SC_H(0.0079446994f), SC_H(0.0092647672f), SC_H(0.0099990256f), + SC_H(0.0081285043f), SC_H(0.0014247177f)}, + {SC_H(0.0000000000f), SC_H(0.0019540912f), SC_H(0.0030265225f), + SC_H(0.0044795908f), SC_H(0.0052186381f), SC_H(0.0056232223f), + SC_H(0.0045594289f), SC_H(0.0007977359f)}, + {SC_H(0.0000000000f), SC_H(0.0000000149f), SC_H(0.0000000298f), + SC_H(0.0000000298f), SC_H(0.0000000000f), SC_H(0.0000000596f), + SC_H(0.0000000000f), SC_H(0.0000000000f)}}; + +/* + for (i=0; i<31; i++) { + cld = dequantCLD[i]; + val = (float)(FDKexp(cld/dbe)/(1+FDKexp(cld/dbe))); + val = (float)(dbe*FDKlog(val)); + } +*/ +#define SCALE_CLD_C1C2(a) (FL2FXCONST_DBL(a / (float)(1 << SF_CLD_C1C2))) +const FIXP_DBL dequantCLD_c1[31] = {SCALE_CLD_C1C2(-1.5000000000000000e+002f), + SCALE_CLD_C1C2(-4.5000137329101563e+001f), + SCALE_CLD_C1C2(-4.0000434875488281e+001f), + SCALE_CLD_C1C2(-3.5001373291015625e+001f), + SCALE_CLD_C1C2(-3.0004341125488281e+001f), + SCALE_CLD_C1C2(-2.5013711929321289e+001f), + SCALE_CLD_C1C2(-2.2027315139770508e+001f), + SCALE_CLD_C1C2(-1.9054332733154297e+001f), + SCALE_CLD_C1C2(-1.6107742309570313e+001f), + SCALE_CLD_C1C2(-1.3212384223937988e+001f), + SCALE_CLD_C1C2(-1.0413927078247070e+001f), + SCALE_CLD_C1C2(-8.6389207839965820e+000f), + SCALE_CLD_C1C2(-6.9732279777526855e+000f), + SCALE_CLD_C1C2(-5.4554042816162109e+000f), + SCALE_CLD_C1C2(-4.1244258880615234e+000f), + SCALE_CLD_C1C2(-3.0102999210357666e+000f), + SCALE_CLD_C1C2(-2.1244258880615234e+000f), + SCALE_CLD_C1C2(-1.4554045200347900e+000f), + SCALE_CLD_C1C2(-9.7322785854339600e-001f), + SCALE_CLD_C1C2(-6.3892036676406860e-001f), + SCALE_CLD_C1C2(-4.1392669081687927e-001f), + SCALE_CLD_C1C2(-2.1238386631011963e-001f), + SCALE_CLD_C1C2(-1.0774217545986176e-001f), + SCALE_CLD_C1C2(-5.4333221167325974e-002f), + SCALE_CLD_C1C2(-2.7315950021147728e-002f), + SCALE_CLD_C1C2(-1.3711934909224510e-002f), + SCALE_CLD_C1C2(-4.3406565673649311e-003f), + SCALE_CLD_C1C2(-1.3732088264077902e-003f), + SCALE_CLD_C1C2(-4.3438826105557382e-004f), + SCALE_CLD_C1C2(-1.3745666365139186e-004f), + SCALE_CLD_C1C2(0.0000000000000000e+000f)}; + +/* sac_stp */ +/* none scaled */ +const FIXP_CFG BP__FDK[] = {FL2FXCONST_CFG(0.73919999599457), + FL2FXCONST_CFG(0.97909998893738), + FL2FXCONST_CFG(0.99930000305176)}; + +/* scaled with 26 bits */ +const FIXP_CFG BP_GF__FDK[] = { + FL2FXCONST_CFG(0.00000000643330), FL2FXCONST_CFG(0.00004396850232), + FL2FXCONST_CFG(0.00087456948552), FL2FXCONST_CFG(0.00474648220243), + FL2FXCONST_CFG(0.01717987244800), FL2FXCONST_CFG(0.04906742491073), + FL2FXCONST_CFG(0.10569518656729), FL2FXCONST_CFG(0.21165767592653), + FL2FXCONST_CFG(0.36036762478024), FL2FXCONST_CFG(0.59894182766948), + FL2FXCONST_CFG(0.81641678929129), FL2FXCONST_CFG(0.97418481133397), + FL2FXCONST_CFG(0.99575411610845), FL2FXCONST_CFG(0.88842666281361), + FL2FXCONST_CFG(0.79222317063736), FL2FXCONST_CFG(0.70828604318604), + FL2FXCONST_CFG(0.66395054816338), FL2FXCONST_CFG(0.64633739516952), + FL2FXCONST_CFG(0.66098278185255)}; + +/* sac_bitdec */ +const INT samplingFreqTable[16] = {96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000, + 7350, 0, 0, 0}; + +const UCHAR freqResTable[] = {0, 28, 20, 14, 10, 7, 5, 4}; + +const UCHAR freqResTable_LD[] = {0, 23, 15, 12, 9, 7, 5, 4}; + +const UCHAR tempShapeChanTable[][8] = {{5, 5, 4, 6, 6, 4, 4, 2}, + {5, 5, 5, 7, 7, 4, 4, 2}}; + +const TREEPROPERTIES treePropertyTable[] = { + {1, 6, 5, 0, {0, 0, 0, 0, 1}}, {1, 6, 5, 0, {0, 0, 1, 0, 0}}, + {2, 6, 3, 1, {1, 0, 0, 0, 0}}, {2, 8, 5, 1, {1, 0, 0, 0, 0}}, + {2, 8, 5, 1, {1, 0, 0, 0, 0}}, {6, 8, 2, 0, {0, 0, 0, 0, 0}}, + {6, 8, 2, 0, {0, 0, 0, 0, 0}}, {1, 2, 1, 0, {0, 0, 0, 0, 0}}}; + +const SCHAR kernels_4_to_71[MAX_HYBRID_BANDS] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; + +const SCHAR kernels_5_to_71[MAX_HYBRID_BANDS] = { + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; + +const SCHAR kernels_7_to_71[MAX_HYBRID_BANDS] = { + 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}; + +const SCHAR kernels_10_to_71[MAX_HYBRID_BANDS] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; + +const SCHAR kernels_14_to_71[MAX_HYBRID_BANDS] = { + 0, 0, 0, 0, 1, 1, 2, 3, 4, 4, 5, 6, 6, 7, 7, 8, 8, + 8, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; + +const SCHAR kernels_20_to_71[MAX_HYBRID_BANDS] = { + 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19}; + +const SCHAR kernels_28_to_71[MAX_HYBRID_BANDS] = { + 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 21, 22, 22, 22, 23, + 23, 23, 23, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27}; + +const SCHAR kernels_4_to_64[MAX_HYBRID_BANDS] = { + 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; + +const SCHAR kernels_5_to_64[MAX_HYBRID_BANDS] = { + 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; + +const SCHAR kernels_7_to_64[MAX_HYBRID_BANDS] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}; + +const SCHAR kernels_9_to_64[MAX_HYBRID_BANDS] = { + 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; + +const SCHAR kernels_12_to_64[MAX_HYBRID_BANDS] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8, 9, + 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}; + +const SCHAR kernels_15_to_64[MAX_HYBRID_BANDS] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12, + 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14}; + +const SCHAR kernels_23_to_64[MAX_HYBRID_BANDS] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 13, 13, 14, 14, 15, + 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 19, 20, 20, 20, + 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22}; + +const UCHAR mapping_15_to_23[MAX_PARAMETER_BANDS_LD] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14}; + +const UCHAR mapping_12_to_23[MAX_PARAMETER_BANDS_LD] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11}; + +const UCHAR mapping_9_to_23[MAX_PARAMETER_BANDS_LD] = { + 0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8}; + +const UCHAR mapping_7_to_23[MAX_PARAMETER_BANDS_LD] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6}; + +const UCHAR mapping_5_to_23[MAX_PARAMETER_BANDS_LD] = { + 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4}; + +const UCHAR mapping_4_to_23[MAX_PARAMETER_BANDS_LD] = { + 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3}; + +const FIXP_CFG clipGainTable__FDK[] = { + /*CLIP_PROTECT_GAIN_0(1.000000f)*/ FX_DBL2FX_CFG(MAXVAL_DBL), + CLIP_PROTECT_GAIN_1(1.189207f), + CLIP_PROTECT_GAIN_1(1.414213f), + CLIP_PROTECT_GAIN_1(1.681792f), + /*CLIP_PROTECT_GAIN_1(2.000000f)*/ FX_DBL2FX_CFG(MAXVAL_DBL), + CLIP_PROTECT_GAIN_2(2.378414f), + CLIP_PROTECT_GAIN_2(2.828427f), + /*CLIP_PROTECT_GAIN_2(4.000000f)*/ FX_DBL2FX_CFG(MAXVAL_DBL)}; + +const UCHAR clipGainSFTable__FDK[] = {0, 1, 1, 1, 1, 2, 2, 2}; + +const UCHAR pbStrideTable[] = {1, 2, 5, 28}; + +const int smgTimeTable[] = {64, 128, 256, 512}; + +/* table is scaled by factor 0.5 */ +const FIXP_CFG envShapeDataTable__FDK[5][2] = { + {FL2FXCONST_CFG(0.25000000000000f), FL2FXCONST_CFG(0.25000000000000f)}, + {FL2FXCONST_CFG(0.35355339059327f), FL2FXCONST_CFG(0.31498026247372f)}, + {FL2FXCONST_CFG(0.50000000000000f), FL2FXCONST_CFG(0.39685026299205f)}, + {FL2FXCONST_CFG(0.70710678118655f), FL2FXCONST_CFG(0.50000000000000f)}, + {/*FL2FXCONST_CFG( 1.00000000000000f)*/ FX_DBL2FX_CFG(MAXVAL_DBL), + FL2FXCONST_CFG(0.62996052494744f)}}; + +/* sac_calcM1andM2 */ +const SCHAR row2channelSTP[][MAX_M2_INPUT] = {{0, 1}, {0, 3}, {0, 2}, {0, 4}, + {0, 4}, {0, 2}, {-1, 2}, {0, 1}}; + +const SCHAR row2channelGES[][MAX_M2_INPUT] = {{0, 1}, {0, 3}, {0, 3}, {0, 5}, + {0, 5}, {0, 2}, {-1, 2}, {0, 1}}; + +const SCHAR row2residual[][MAX_M2_INPUT] = {{-1, 0}, {-1, 0}, {-1, -1}, + {-1, -1}, {-1, -1}, {-1, -1}, + {-1, -1}, {-1, 0}}; + +/******************************************************************************* + Functionname: sac_getCLDValues + ******************************************************************************* + + Description: Get CLD values from table index. + + Arguments: + index: Table index + *cu, *cl : Pointer to locations where resulting values will be written to. + + Return: nothing + +*******************************************************************************/ +void SpatialDequantGetCLDValues(int index, FIXP_DBL* cu, FIXP_DBL* cl) { + *cu = FX_CFG2FX_DBL(dequantCLD_c_l[index]); + *cl = FX_CFG2FX_DBL(dequantCLD_c_l[31 - 1 - index]); +} + +void SpatialDequantGetCLD2Values(int idx, FIXP_DBL* x) { + *x = FX_CFG2FX_DBL(dequantCLD__FDK[idx]); +} diff --git a/libSACdec/src/sac_rom.h b/libSACdec/src/sac_rom.h new file mode 100644 index 0000000..d366fb6 --- /dev/null +++ b/libSACdec/src/sac_rom.h @@ -0,0 +1,230 @@ +/* ----------------------------------------------------------------------------- +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 Dec tables + +*******************************************************************************/ + +#ifndef SAC_ROM_H +#define SAC_ROM_H + +#include "FDK_archdef.h" +#include "sac_dec_interface.h" + +#include "huff_nodes.h" +#include "sac_bitdec.h" +#include "machine_type.h" + +/* Global ROM table data type: */ +#ifndef ARCH_PREFER_MULT_32x32 +#define FIXP_CFG FIXP_SGL +#define FX_CFG2FX_DBL FX_SGL2FX_DBL +#define FX_CFG2FX_SGL +#define CFG(a) (FX_DBL2FXCONST_SGL(a)) +#define FL2FXCONST_CFG FL2FXCONST_SGL +#define FX_DBL2FX_CFG(x) FX_DBL2FX_SGL((FIXP_DBL)(x)) +#else +#define FIXP_CFG FIXP_DBL +#define FX_CFG2FX_DBL +#define FX_CFG2FX_SGL FX_DBL2FX_SGL +#define CFG(a) FIXP_DBL(a) +#define FL2FXCONST_CFG FL2FXCONST_DBL +#define FX_DBL2FX_CFG(x) ((FIXP_DBL)(x)) +#endif + +/* others */ +#define SCALE_INV_ICC (2) +#define G_dd_SCALE (2) + +#define QCC_SCALE 1 +#define M1M2_DATA FIXP_DBL +#ifndef ARCH_PREFER_MULT_32x32 +#define M1M2_CDATA FIXP_SGL +#define M1M2_CDATA2FX_DBL(a) FX_SGL2FX_DBL(a) +#define FX_DBL2M1M2_CDATA(a) FX_DBL2FX_SGL(a) +#else +#define M1M2_CDATA FIXP_DBL +#define M1M2_CDATA2FX_DBL(a) (a) +#define FX_DBL2M1M2_CDATA(a) (a) +#endif + +#define CLIP_PROTECT_GAIN_0(x) FL2FXCONST_CFG(((x) / (float)(1 << 0))) +#define CLIP_PROTECT_GAIN_1(x) FL2FXCONST_CFG(((x) / (float)(1 << 1))) +#define CLIP_PROTECT_GAIN_2(x) FL2FXCONST_CFG(((x) / (float)(1 << 2))) + +#define SF_CLD_C1C2 (8) + +extern const FIXP_CFG dequantCPC__FDK[]; +extern const FIXP_CFG dequantICC__FDK[8]; +extern const FIXP_CFG dequantCLD__FDK[31]; + +#define IPD_SCALE (5) +#define PI__IPD (FL2FXCONST_DBL(3.1415926535897932f / (float)(1 << IPD_SCALE))) +/* Define for PI*2 for better precision in SpatialDecApplyPhase() */ +#define PIx2__IPD \ + (FL2FXCONST_DBL(3.1415926535897932f / (float)(1 << (IPD_SCALE - 1)))) + +extern const FIXP_CFG dequantIPD__FDK[16]; + +extern const FIXP_CFG H11_nc[31][8]; +extern const FIXP_CFG H12_nc[31][8]; + +extern const FIXP_DBL dequantCLD_c1[31]; + +extern const FIXP_CFG BP__FDK[]; +extern const FIXP_CFG BP_GF__FDK[]; +extern const SCHAR row2channelSTP[][MAX_M2_INPUT]; + +/* sac_bitdec */ +extern const INT samplingFreqTable[16]; +extern const UCHAR freqResTable[]; +extern const UCHAR freqResTable_LD[]; +extern const UCHAR tempShapeChanTable[2][8]; +extern const TREEPROPERTIES treePropertyTable[]; + +extern const SCHAR kernels_4_to_71[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_5_to_71[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_7_to_71[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_10_to_71[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_14_to_71[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_20_to_71[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_28_to_71[MAX_HYBRID_BANDS]; + +extern const UCHAR mapping_4_to_28[MAX_PARAMETER_BANDS]; +extern const UCHAR mapping_5_to_28[MAX_PARAMETER_BANDS]; +extern const UCHAR mapping_7_to_28[MAX_PARAMETER_BANDS]; +extern const UCHAR mapping_10_to_28[MAX_PARAMETER_BANDS]; +extern const UCHAR mapping_14_to_28[MAX_PARAMETER_BANDS]; +extern const UCHAR mapping_20_to_28[MAX_PARAMETER_BANDS]; +extern const SCHAR kernels_4_to_64[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_5_to_64[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_7_to_64[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_9_to_64[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_12_to_64[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_15_to_64[MAX_HYBRID_BANDS]; +extern const SCHAR kernels_23_to_64[MAX_HYBRID_BANDS]; + +extern const UCHAR mapping_15_to_23[MAX_PARAMETER_BANDS_LD]; +extern const UCHAR mapping_12_to_23[MAX_PARAMETER_BANDS_LD]; +extern const UCHAR mapping_9_to_23[MAX_PARAMETER_BANDS_LD]; +extern const UCHAR mapping_7_to_23[MAX_PARAMETER_BANDS_LD]; +extern const UCHAR mapping_5_to_23[MAX_PARAMETER_BANDS_LD]; +extern const UCHAR mapping_4_to_23[MAX_PARAMETER_BANDS_LD]; + +extern const FIXP_CFG clipGainTable__FDK[]; +extern const UCHAR clipGainSFTable__FDK[]; + +extern const UCHAR pbStrideTable[]; +extern const int smgTimeTable[]; + +extern const FIXP_CFG envShapeDataTable__FDK[5][2]; +extern const SCHAR row2channelGES[][MAX_M2_INPUT]; + +/* sac_calcM1andM2 */ +extern const SCHAR row2residual[][MAX_M2_INPUT]; + +void SpatialDequantGetCLDValues(int index, FIXP_DBL* cu, FIXP_DBL* cl); + +void SpatialDequantGetCLD2Values(int index, FIXP_DBL* x); + +/* External helper functions */ +static inline int SacGetHybridSubbands(int qmfSubbands) { + return qmfSubbands - MAX_QMF_BANDS_TO_HYBRID + 10; +} + +#endif /* SAC_ROM_H */ diff --git a/libSACdec/src/sac_smoothing.cpp b/libSACdec/src/sac_smoothing.cpp new file mode 100644 index 0000000..bee6551 --- /dev/null +++ b/libSACdec/src/sac_smoothing.cpp @@ -0,0 +1,295 @@ +/* ----------------------------------------------------------------------------- +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 Dec parameter smoothing + +*******************************************************************************/ + +#include "sac_dec.h" +#include "sac_bitdec.h" +#include "sac_smoothing.h" +#include "sac_rom.h" + +/******************************************************************************* + Functionname: calcFilterCoeff + ******************************************************************************* + + Description: + + Arguments: + + Input: + + Output: + + +*******************************************************************************/ +static FIXP_DBL calcFilterCoeff__FDK(spatialDec *self, int ps, + const SPATIAL_BS_FRAME *frame) { + int dSlots; + FIXP_DBL delta; + + dSlots = frame->paramSlot[ps] - self->smoothState->prevParamSlot; + + if (dSlots <= 0) { + dSlots += self->timeSlots; + } + + delta = fDivNorm(dSlots, self->smgTime[ps]); + + return delta; +} + +/******************************************************************************* + Functionname: getSmoothOnOff + ******************************************************************************* + + Description: + + Arguments: + + Input: + + Output: + + +*******************************************************************************/ +static int getSmoothOnOff(spatialDec *self, int ps, int pb) { + int smoothBand = 0; + + smoothBand = self->smgData[ps][pb]; + + return smoothBand; +} + +void SpatialDecSmoothM1andM2(spatialDec *self, const SPATIAL_BS_FRAME *frame, + int ps) { + FIXP_DBL delta__FDK; + FIXP_DBL one_minus_delta__FDK; + + int pb, row, col; + int residualBands = 0; + + if (self->residualCoding) { + int i; + int boxes = self->numOttBoxes; + for (i = 0; i < boxes; i++) { + if (self->residualBands[i] > residualBands) { + residualBands = self->residualBands[i]; + } + } + } + + delta__FDK = calcFilterCoeff__FDK(self, ps, frame); + if (delta__FDK == /*FL2FXCONST_DBL(1.0f)*/ (FIXP_DBL)MAXVAL_DBL) + one_minus_delta__FDK = FL2FXCONST_DBL(0.0f); + else if (delta__FDK == FL2FXCONST_DBL(0.0f)) + one_minus_delta__FDK = /*FL2FXCONST_DBL(1.0f)*/ (FIXP_DBL)MAXVAL_DBL; + else + one_minus_delta__FDK = (FL2FXCONST_DBL(0.5f) - (delta__FDK >> 1)) << 1; + + for (pb = 0; pb < self->numParameterBands; pb++) { + int smoothBand; + + smoothBand = getSmoothOnOff(self, ps, pb); + + if (smoothBand && (pb >= residualBands)) { + for (row = 0; row < self->numM2rows; row++) { + for (col = 0; col < self->numVChannels; col++) { + self->M2Real__FDK[row][col][pb] = + ((fMultDiv2(delta__FDK, self->M2Real__FDK[row][col][pb]) + + fMultDiv2(one_minus_delta__FDK, + self->M2RealPrev__FDK[row][col][pb])) + << 1); + if (0 || (self->phaseCoding == 3)) { + self->M2Imag__FDK[row][col][pb] = + ((fMultDiv2(delta__FDK, self->M2Imag__FDK[row][col][pb]) + + fMultDiv2(one_minus_delta__FDK, + self->M2ImagPrev__FDK[row][col][pb])) + << 1); + } + } + } + } + } + self->smoothState->prevParamSlot = frame->paramSlot[ps]; +} + +/* init states */ +void initParameterSmoothing(spatialDec *self) { + self->smoothState->prevParamSlot = 0; +} + +void SpatialDecSmoothOPD(spatialDec *self, const SPATIAL_BS_FRAME *frame, + int ps) { + int pb; + int dSlots; + FIXP_DBL delta__FDK; + FIXP_DBL one_minus_delta__FDK; + FIXP_DBL *phaseLeftSmooth__FDK = self->smoothState->opdLeftState__FDK; + FIXP_DBL *phaseRightSmooth__FDK = self->smoothState->opdRightState__FDK; + int quantCoarse; + + quantCoarse = frame->IPDLosslessData[0].bsQuantCoarseXXX[ps]; + + if (frame->OpdSmoothingMode == 0) { + FDKmemcpy(phaseLeftSmooth__FDK, self->PhaseLeft__FDK, + self->numParameterBands * sizeof(FIXP_DBL)); + FDKmemcpy(phaseRightSmooth__FDK, self->PhaseRight__FDK, + self->numParameterBands * sizeof(FIXP_DBL)); + } else { + if (ps == 0) { + dSlots = frame->paramSlot[ps] + 1; + } else { + dSlots = frame->paramSlot[ps] - frame->paramSlot[ps - 1]; + } + + delta__FDK = (FIXP_DBL)((INT)(FL2FXCONST_DBL(0.0078125f)) * dSlots); + + if (delta__FDK == (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/) + one_minus_delta__FDK = FL2FXCONST_DBL(0.0f); + else if (delta__FDK == FL2FXCONST_DBL(0.0f)) + one_minus_delta__FDK = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/; + else + one_minus_delta__FDK = (FL2FXCONST_DBL(0.5f) - (delta__FDK >> 1)) << 1; + + for (pb = 0; pb < self->numParameterBands; pb++) { + FIXP_DBL tmpL, tmpR, tmp; + + tmpL = self->PhaseLeft__FDK[pb]; + tmpR = self->PhaseRight__FDK[pb]; + + while (tmpL > phaseLeftSmooth__FDK[pb] + PI__IPD) tmpL -= PI__IPD << 1; + while (tmpL < phaseLeftSmooth__FDK[pb] - PI__IPD) tmpL += PI__IPD << 1; + while (tmpR > phaseRightSmooth__FDK[pb] + PI__IPD) tmpR -= PI__IPD << 1; + while (tmpR < phaseRightSmooth__FDK[pb] - PI__IPD) tmpR += PI__IPD << 1; + + phaseLeftSmooth__FDK[pb] = + fMult(delta__FDK, tmpL) + + fMult(one_minus_delta__FDK, phaseLeftSmooth__FDK[pb]); + phaseRightSmooth__FDK[pb] = + fMult(delta__FDK, tmpR) + + fMult(one_minus_delta__FDK, phaseRightSmooth__FDK[pb]); + + tmp = (((tmpL >> 1) - (tmpR >> 1)) - ((phaseLeftSmooth__FDK[pb] >> 1) - + (phaseRightSmooth__FDK[pb] >> 1))) + << 1; + while (tmp > PI__IPD) tmp -= PI__IPD << 1; + while (tmp < -PI__IPD) tmp += PI__IPD << 1; + if (fixp_abs(tmp) > fMult((quantCoarse ? FL2FXCONST_DBL(50.f / 180.f) + : FL2FXCONST_DBL(25.f / 180.f)), + PI__IPD)) { + phaseLeftSmooth__FDK[pb] = tmpL; + phaseRightSmooth__FDK[pb] = tmpR; + } + + while (phaseLeftSmooth__FDK[pb] > PI__IPD << 1) + phaseLeftSmooth__FDK[pb] -= PI__IPD << 1; + while (phaseLeftSmooth__FDK[pb] < (FIXP_DBL)0) + phaseLeftSmooth__FDK[pb] += PI__IPD << 1; + while (phaseRightSmooth__FDK[pb] > PI__IPD << 1) + phaseRightSmooth__FDK[pb] -= PI__IPD << 1; + while (phaseRightSmooth__FDK[pb] < (FIXP_DBL)0) + phaseRightSmooth__FDK[pb] += PI__IPD << 1; + + self->PhaseLeft__FDK[pb] = phaseLeftSmooth__FDK[pb]; + self->PhaseRight__FDK[pb] = phaseRightSmooth__FDK[pb]; + } + } + return; +} diff --git a/libSACdec/src/sac_smoothing.h b/libSACdec/src/sac_smoothing.h new file mode 100644 index 0000000..fdf3f5b --- /dev/null +++ b/libSACdec/src/sac_smoothing.h @@ -0,0 +1,114 @@ +/* ----------------------------------------------------------------------------- +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 Dec parameter smoothing + +*******************************************************************************/ + +#ifndef SAC_SMOOTHING_H +#define SAC_SMOOTHING_H + +#include "sac_dec.h" + +void initParameterSmoothing(spatialDec *self); +void SpatialDecSmoothM1andM2(spatialDec *self, const SPATIAL_BS_FRAME *frame, + int ps); +void SpatialDecSmoothOPD(spatialDec *self, const SPATIAL_BS_FRAME *frame, + int ps); + +#endif diff --git a/libSACdec/src/sac_stp.cpp b/libSACdec/src/sac_stp.cpp new file mode 100644 index 0000000..818e9df --- /dev/null +++ b/libSACdec/src/sac_stp.cpp @@ -0,0 +1,548 @@ +/* ----------------------------------------------------------------------------- +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 Dec subband processing + +*******************************************************************************/ + +#include "sac_stp.h" +#include "sac_calcM1andM2.h" +#include "sac_bitdec.h" +#include "FDK_matrixCalloc.h" +#include "sac_rom.h" + +#define BP_GF_START 6 +#define BP_GF_SIZE 25 +#define HP_SIZE 9 +#define STP_UPDATE_ENERGY_RATE 32 + +#define SF_WET 5 +#define SF_DRY \ + 3 /* SF_DRY == 2 would produce good conformance test results as well */ +#define SF_PRODUCT_BP_GF 13 +#define SF_PRODUCT_BP_GF_GF 26 +#define SF_SCALE 2 + +#define SF_SCALE_LD64 FL2FXCONST_DBL(0.03125) /* LD64((1<<SF_SCALE))*/ +#define STP_LPF_COEFF1__FDK FL2FXCONST_DBL(0.950f) /* 0.95 */ +#define ONE_MINUS_STP_LPF_COEFF1__FDK FL2FXCONST_DBL(0.05f) /* 1.0 - 0.95 */ +#define STP_LPF_COEFF2__FDK FL2FXCONST_DBL(0.450f) /* 0.45 */ +#define ONE_MINUS_STP_LPF_COEFF2__FDK \ + FL2FXCONST_DBL(1.0f - 0.450f) /* 1.0 - 0.45 */ +#define STP_SCALE_LIMIT__FDK \ + FL2FXCONST_DBL(2.82f / (float)(1 << SF_SCALE)) /* scaled by SF_SCALE */ +#define ONE_DIV_STP_SCALE_LIMIT__FDK \ + FL2FXCONST_DBL(1.0f / 2.82f / (float)(1 << SF_SCALE)) /* scaled by SF_SCALE \ + */ +#define ABS_THR__FDK \ + FL2FXCONST_DBL(ABS_THR / \ + ((float)(1 << (22 + 22 - 26)))) /* scaled by 18 bits */ +#define ABS_THR2__FDK \ + FL2FXCONST_DBL(ABS_THR * 32.0f * 32.0f / \ + ((float)(1 << (22 + 22 - 26)))) /* scaled by 10 bits */ +#define STP_SCALE_LIMIT_HI \ + FL2FXCONST_DBL(3.02222222222 / (1 << SF_SCALE)) /* see 4. below */ +#define STP_SCALE_LIMIT_LO \ + FL2FXCONST_DBL(0.28289992119 / (1 << SF_SCALE)) /* see 4. below */ +#define STP_SCALE_LIMIT_HI_LD64 \ + FL2FXCONST_DBL(0.04986280452) /* see 4. below \ + */ +#define STP_SCALE_LIMIT_LO_LD64 \ + FL2FXCONST_DBL(0.05692613500) /* see 4. below \ + */ + +/* Scale factor calculation for the diffuse signal needs adapted thresholds + for STP_SCALE_LIMIT and 1/STP_SCALE_LIMIT: + + 1. scale = sqrt(DryNrg/WetNrg) + + 2. Damping of scale factor + scale2 = 0.1 + 0.9 * scale + + 3. Limiting of scale factor + STP_SCALE_LIMIT >= scale2 >= 1/STP_SCALE_LIMIT + => STP_SCALE_LIMIT >= (0.1 + 0.9 * scale) >= 1/STP_SCALE_LIMIT + => (STP_SCALE_LIMIT-0.1)/0.9 >= scale >= + (1/STP_SCALE_LIMIT-0.1)/0.9 + + 3. Limiting of scale factor before sqrt calculation + ((STP_SCALE_LIMIT-0.1)/0.9)^2 >= (scale^2) >= + ((1/STP_SCALE_LIMIT-0.1)/0.9)^2 (STP_SCALE_LIMIT_HI)^2 >= (scale^2) >= + (STP_SCALE_LIMIT_LO)^2 + + 4. Thresholds for limiting of scale factor + STP_SCALE_LIMIT_HI = ((2.82-0.1)/0.9) + STP_SCALE_LIMIT_LO = (((1.0/2.82)-0.1)/0.9) + STP_SCALE_LIMIT_HI_LD64 = LD64(STP_SCALE_LIMIT_HI*STP_SCALE_LIMIT_HI) + STP_SCALE_LIMIT_LO_LD64 = LD64(STP_SCALE_LIMIT_LO*STP_SCALE_LIMIT_LO) +*/ + +#define DRY_ENER_WEIGHT(DryEner) DryEner = DryEner >> dry_scale_dmx + +#define WET_ENER_WEIGHT(WetEner) WetEner = WetEner << wet_scale_dmx + +#define DRY_ENER_SUM_REAL(DryEner, dmxReal, n) \ + DryEner += \ + fMultDiv2(fPow2Div2(dmxReal << SF_DRY), pBP[n]) >> ((2 * SF_DRY) - 2) + +#define DRY_ENER_SUM_CPLX(DryEner, dmxReal, dmxImag, n) \ + DryEner += fMultDiv2( \ + fPow2Div2(dmxReal << SF_DRY) + fPow2Div2(dmxImag << SF_DRY), pBP[n]) + +#define CALC_WET_SCALE(dryIdx, wetIdx) \ + if ((DryEnerLD64[dryIdx] - STP_SCALE_LIMIT_HI_LD64) > WetEnerLD64[wetIdx]) { \ + scale[wetIdx] = STP_SCALE_LIMIT_HI; \ + } else if (DryEnerLD64[dryIdx] < \ + (WetEnerLD64[wetIdx] - STP_SCALE_LIMIT_LO_LD64)) { \ + scale[wetIdx] = STP_SCALE_LIMIT_LO; \ + } else { \ + tmp = ((DryEnerLD64[dryIdx] - WetEnerLD64[wetIdx]) >> 1) - SF_SCALE_LD64; \ + scale[wetIdx] = CalcInvLdData(tmp); \ + } + +struct STP_DEC { + FIXP_DBL runDryEner[MAX_INPUT_CHANNELS]; + FIXP_DBL runWetEner[MAX_OUTPUT_CHANNELS]; + FIXP_DBL oldDryEnerLD64[MAX_INPUT_CHANNELS]; + FIXP_DBL oldWetEnerLD64[MAX_OUTPUT_CHANNELS]; + FIXP_DBL prev_tp_scale[MAX_OUTPUT_CHANNELS]; + const FIXP_CFG *BP; + const FIXP_CFG *BP_GF; + int update_old_ener; +}; + +inline void combineSignalReal(FIXP_DBL *hybOutputRealDry, + FIXP_DBL *hybOutputRealWet, int bands) { + int n; + + for (n = bands - 1; n >= 0; n--) { + *hybOutputRealDry = *hybOutputRealDry + *hybOutputRealWet; + hybOutputRealDry++, hybOutputRealWet++; + } +} + +inline void combineSignalRealScale1(FIXP_DBL *hybOutputRealDry, + FIXP_DBL *hybOutputRealWet, FIXP_DBL scaleX, + int bands) { + int n; + + for (n = bands - 1; n >= 0; n--) { + *hybOutputRealDry = + *hybOutputRealDry + + (fMultDiv2(*hybOutputRealWet, scaleX) << (SF_SCALE + 1)); + hybOutputRealDry++, hybOutputRealWet++; + } +} + +inline void combineSignalCplx(FIXP_DBL *hybOutputRealDry, + FIXP_DBL *hybOutputImagDry, + FIXP_DBL *hybOutputRealWet, + FIXP_DBL *hybOutputImagWet, int bands) { + int n; + + for (n = bands - 1; n >= 0; n--) { + *hybOutputRealDry = *hybOutputRealDry + *hybOutputRealWet; + *hybOutputImagDry = *hybOutputImagDry + *hybOutputImagWet; + hybOutputRealDry++, hybOutputRealWet++; + hybOutputImagDry++, hybOutputImagWet++; + } +} + +inline void combineSignalCplxScale1(FIXP_DBL *hybOutputRealDry, + FIXP_DBL *hybOutputImagDry, + FIXP_DBL *hybOutputRealWet, + FIXP_DBL *hybOutputImagWet, + const FIXP_CFG *pBP, FIXP_DBL scaleX, + int bands) { + int n; + FIXP_DBL scaleY; + for (n = bands - 1; n >= 0; n--) { + scaleY = fMultDiv2(scaleX, *pBP); + *hybOutputRealDry = + *hybOutputRealDry + + (fMultDiv2(*hybOutputRealWet, scaleY) << (SF_SCALE + 2)); + *hybOutputImagDry = + *hybOutputImagDry + + (fMultDiv2(*hybOutputImagWet, scaleY) << (SF_SCALE + 2)); + hybOutputRealDry++, hybOutputRealWet++; + hybOutputImagDry++, hybOutputImagWet++; + pBP++; + } +} + +inline void combineSignalCplxScale2(FIXP_DBL *hybOutputRealDry, + FIXP_DBL *hybOutputImagDry, + FIXP_DBL *hybOutputRealWet, + FIXP_DBL *hybOutputImagWet, FIXP_DBL scaleX, + int bands) { + int n; + + for (n = bands - 1; n >= 0; n--) { + *hybOutputRealDry = + *hybOutputRealDry + + (fMultDiv2(*hybOutputRealWet, scaleX) << (SF_SCALE + 1)); + *hybOutputImagDry = + *hybOutputImagDry + + (fMultDiv2(*hybOutputImagWet, scaleX) << (SF_SCALE + 1)); + hybOutputRealDry++, hybOutputRealWet++; + hybOutputImagDry++, hybOutputImagWet++; + } +} + +/******************************************************************************* + Functionname: subbandTPCreate + ******************************************************************************/ +SACDEC_ERROR subbandTPCreate(HANDLE_STP_DEC *hStpDec) { + HANDLE_STP_DEC self = NULL; + FDK_ALLOCATE_MEMORY_1D(self, 1, struct STP_DEC) + if (hStpDec != NULL) { + *hStpDec = self; + } + + return MPS_OK; +bail: + return MPS_OUTOFMEMORY; +} + +SACDEC_ERROR subbandTPInit(HANDLE_STP_DEC self) { + SACDEC_ERROR err = MPS_OK; + int ch; + + for (ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) { + self->prev_tp_scale[ch] = FL2FXCONST_DBL(1.0f / (1 << SF_SCALE)); + self->oldWetEnerLD64[ch] = + FL2FXCONST_DBL(0.34375f); /* 32768.0*32768.0/2^(44-26-10) */ + } + for (ch = 0; ch < MAX_INPUT_CHANNELS; ch++) { + self->oldDryEnerLD64[ch] = + FL2FXCONST_DBL(0.1875f); /* 32768.0*32768.0/2^(44-26) */ + } + + self->BP = BP__FDK; + self->BP_GF = BP_GF__FDK; + + self->update_old_ener = 0; + + return err; +} + +/******************************************************************************* + Functionname: subbandTPDestroy + ******************************************************************************/ +void subbandTPDestroy(HANDLE_STP_DEC *hStpDec) { + if (hStpDec != NULL) { + FDK_FREE_MEMORY_1D(*hStpDec); + } +} + +/******************************************************************************* + Functionname: subbandTPApply + ******************************************************************************/ +SACDEC_ERROR subbandTPApply(spatialDec *self, const SPATIAL_BS_FRAME *frame) { + FIXP_DBL *qmfOutputRealDry[MAX_OUTPUT_CHANNELS]; + FIXP_DBL *qmfOutputImagDry[MAX_OUTPUT_CHANNELS]; + FIXP_DBL *qmfOutputRealWet[MAX_OUTPUT_CHANNELS]; + FIXP_DBL *qmfOutputImagWet[MAX_OUTPUT_CHANNELS]; + + FIXP_DBL DryEner[MAX_INPUT_CHANNELS]; + FIXP_DBL scale[MAX_OUTPUT_CHANNELS]; + + FIXP_DBL DryEnerLD64[MAX_INPUT_CHANNELS]; + FIXP_DBL WetEnerLD64[MAX_OUTPUT_CHANNELS]; + + FIXP_DBL DryEner0 = FL2FXCONST_DBL(0.0f); + FIXP_DBL WetEnerX, damp, tmp; + FIXP_DBL dmxReal0, dmxImag0; + int skipChannels[MAX_OUTPUT_CHANNELS]; + int n, ch, cplxBands, cplxHybBands; + int dry_scale_dmx, wet_scale_dmx; + int i_LF, i_RF; + HANDLE_STP_DEC hStpDec; + const FIXP_CFG *pBP; + + int nrgScale = (2 * self->clipProtectGainSF__FDK); + + hStpDec = self->hStpDec; + + /* set scalefactor and loop counter */ + FDK_ASSERT(SF_DRY >= 1); + { + cplxBands = BP_GF_SIZE; + cplxHybBands = self->hybridBands; + dry_scale_dmx = (2 * SF_DRY) - 2; + wet_scale_dmx = 2; + } + + /* setup pointer for forming the direct downmix signal */ + for (ch = 0; ch < self->numOutputChannels; ch++) { + qmfOutputRealDry[ch] = &self->hybOutputRealDry__FDK[ch][7]; + qmfOutputRealWet[ch] = &self->hybOutputRealWet__FDK[ch][7]; + qmfOutputImagDry[ch] = &self->hybOutputImagDry__FDK[ch][7]; + qmfOutputImagWet[ch] = &self->hybOutputImagWet__FDK[ch][7]; + } + + /* clear skipping flag for all output channels */ + FDKmemset(skipChannels, 0, self->numOutputChannels * sizeof(int)); + + /* set scale values to zero */ + FDKmemset(scale, 0, self->numOutputChannels * sizeof(FIXP_DBL)); + + /* update normalisation energy with latest smoothed energy */ + if (hStpDec->update_old_ener == STP_UPDATE_ENERGY_RATE) { + hStpDec->update_old_ener = 1; + for (ch = 0; ch < self->numInputChannels; ch++) { + hStpDec->oldDryEnerLD64[ch] = + CalcLdData(hStpDec->runDryEner[ch] + ABS_THR__FDK); + } + for (ch = 0; ch < self->numOutputChannels; ch++) { + hStpDec->oldWetEnerLD64[ch] = + CalcLdData(hStpDec->runWetEner[ch] + ABS_THR2__FDK); + } + } else { + hStpDec->update_old_ener++; + } + + /* get channel configuration */ + switch (self->treeConfig) { + case TREE_212: + i_LF = 0; + i_RF = 1; + break; + default: + return MPS_WRONG_TREECONFIG; + } + + /* form the 'direct' downmix signal */ + pBP = hStpDec->BP_GF - BP_GF_START; + switch (self->treeConfig) { + case TREE_212: + for (n = BP_GF_START; n < cplxBands; n++) { + dmxReal0 = qmfOutputRealDry[i_LF][n] + qmfOutputRealDry[i_RF][n]; + dmxImag0 = qmfOutputImagDry[i_LF][n] + qmfOutputImagDry[i_RF][n]; + DRY_ENER_SUM_CPLX(DryEner0, dmxReal0, dmxImag0, n); + } + DRY_ENER_WEIGHT(DryEner0); + break; + default:; + } + DryEner[0] = DryEner0; + + /* normalise the 'direct' signals */ + for (ch = 0; ch < self->numInputChannels; ch++) { + DryEner[ch] = DryEner[ch] << (nrgScale); + hStpDec->runDryEner[ch] = + fMult(STP_LPF_COEFF1__FDK, hStpDec->runDryEner[ch]) + + fMult(ONE_MINUS_STP_LPF_COEFF1__FDK, DryEner[ch]); + if (DryEner[ch] != FL2FXCONST_DBL(0.0f)) { + DryEnerLD64[ch] = + fixMax((CalcLdData(DryEner[ch]) - hStpDec->oldDryEnerLD64[ch]), + FL2FXCONST_DBL(-0.484375f)); + } else { + DryEnerLD64[ch] = FL2FXCONST_DBL(-0.484375f); + } + } + if (self->treeConfig == TREE_212) { + for (; ch < MAX_INPUT_CHANNELS; ch++) { + DryEnerLD64[ch] = FL2FXCONST_DBL(-0.484375f); + } + } + + /* normalise the 'diffuse' signals */ + pBP = hStpDec->BP_GF - BP_GF_START; + for (ch = 0; ch < self->numOutputChannels; ch++) { + if (skipChannels[ch]) { + continue; + } + + WetEnerX = FL2FXCONST_DBL(0.0f); + for (n = BP_GF_START; n < cplxBands; n++) { + tmp = fPow2Div2(qmfOutputRealWet[ch][n] << SF_WET); + tmp += fPow2Div2(qmfOutputImagWet[ch][n] << SF_WET); + WetEnerX += fMultDiv2(tmp, pBP[n]); + } + WET_ENER_WEIGHT(WetEnerX); + + WetEnerX = WetEnerX << (nrgScale); + hStpDec->runWetEner[ch] = + fMult(STP_LPF_COEFF1__FDK, hStpDec->runWetEner[ch]) + + fMult(ONE_MINUS_STP_LPF_COEFF1__FDK, WetEnerX); + + if (WetEnerX == FL2FXCONST_DBL(0.0f)) { + WetEnerLD64[ch] = FL2FXCONST_DBL(-0.484375f); + } else { + WetEnerLD64[ch] = + fixMax((CalcLdData(WetEnerX) - hStpDec->oldWetEnerLD64[ch]), + FL2FXCONST_DBL(-0.484375f)); + } + } + + /* compute scale factor for the 'diffuse' signals */ + switch (self->treeConfig) { + case TREE_212: + if (DryEner[0] != FL2FXCONST_DBL(0.0f)) { + CALC_WET_SCALE(0, i_LF); + CALC_WET_SCALE(0, i_RF); + } + break; + default:; + } + + damp = FL2FXCONST_DBL(0.1f / (1 << SF_SCALE)); + for (ch = 0; ch < self->numOutputChannels; ch++) { + /* damp the scaling factor */ + scale[ch] = damp + fMult(FL2FXCONST_DBL(0.9f), scale[ch]); + + /* limiting the scale factor */ + if (scale[ch] > STP_SCALE_LIMIT__FDK) { + scale[ch] = STP_SCALE_LIMIT__FDK; + } + if (scale[ch] < ONE_DIV_STP_SCALE_LIMIT__FDK) { + scale[ch] = ONE_DIV_STP_SCALE_LIMIT__FDK; + } + + /* low pass filter the scaling factor */ + scale[ch] = + fMult(STP_LPF_COEFF2__FDK, scale[ch]) + + fMult(ONE_MINUS_STP_LPF_COEFF2__FDK, hStpDec->prev_tp_scale[ch]); + hStpDec->prev_tp_scale[ch] = scale[ch]; + } + + /* combine 'direct' and scaled 'diffuse' signal */ + FDK_ASSERT((HP_SIZE - 3 + 10 - 1) == PC_NUM_HYB_BANDS); + const SCHAR *channlIndex = row2channelSTP[self->treeConfig]; + + for (ch = 0; ch < self->numOutputChannels; ch++) { + int no_scaling; + + no_scaling = !frame->tempShapeEnableChannelSTP[channlIndex[ch]]; + if (no_scaling) { + combineSignalCplx( + &self->hybOutputRealDry__FDK[ch][self->tp_hybBandBorder], + &self->hybOutputImagDry__FDK[ch][self->tp_hybBandBorder], + &self->hybOutputRealWet__FDK[ch][self->tp_hybBandBorder], + &self->hybOutputImagWet__FDK[ch][self->tp_hybBandBorder], + cplxHybBands - self->tp_hybBandBorder); + + } else { + FIXP_DBL scaleX; + scaleX = scale[ch]; + pBP = hStpDec->BP - self->tp_hybBandBorder; + /* Band[HP_SIZE-3+10-1] needs not to be processed in + combineSignalCplxScale1(), because pB[HP_SIZE-3+10-1] would be 1.0 */ + combineSignalCplxScale1( + &self->hybOutputRealDry__FDK[ch][self->tp_hybBandBorder], + &self->hybOutputImagDry__FDK[ch][self->tp_hybBandBorder], + &self->hybOutputRealWet__FDK[ch][self->tp_hybBandBorder], + &self->hybOutputImagWet__FDK[ch][self->tp_hybBandBorder], + &pBP[self->tp_hybBandBorder], scaleX, + (HP_SIZE - 3 + 10 - 1) - self->tp_hybBandBorder); + + { + combineSignalCplxScale2( + &self->hybOutputRealDry__FDK[ch][HP_SIZE - 3 + 10 - 1], + &self->hybOutputImagDry__FDK[ch][HP_SIZE - 3 + 10 - 1], + &self->hybOutputRealWet__FDK[ch][HP_SIZE - 3 + 10 - 1], + &self->hybOutputImagWet__FDK[ch][HP_SIZE - 3 + 10 - 1], scaleX, + cplxHybBands - (HP_SIZE - 3 + 10 - 1)); + } + } + } + + return (SACDEC_ERROR)MPS_OK; + ; +} diff --git a/libSACdec/src/sac_stp.h b/libSACdec/src/sac_stp.h new file mode 100644 index 0000000..18471bd --- /dev/null +++ b/libSACdec/src/sac_stp.h @@ -0,0 +1,115 @@ +/* ----------------------------------------------------------------------------- +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 Dec subband processing + +*******************************************************************************/ + +#ifndef SAC_STP_H +#define SAC_STP_H + +#include "sac_dec.h" + +SACDEC_ERROR subbandTPCreate(HANDLE_STP_DEC *hStpDec); + +SACDEC_ERROR subbandTPInit(HANDLE_STP_DEC self); + +SACDEC_ERROR subbandTPApply(spatialDec *self, const SPATIAL_BS_FRAME *frame); +void subbandTPDestroy(HANDLE_STP_DEC *hStpDec); + +#endif diff --git a/libSACdec/src/sac_tsd.cpp b/libSACdec/src/sac_tsd.cpp new file mode 100644 index 0000000..30acca8 --- /dev/null +++ b/libSACdec/src/sac_tsd.cpp @@ -0,0 +1,353 @@ +/* ----------------------------------------------------------------------------- +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): Matthias Hildenbrand + + Description: USAC MPS212 Transient Steering Decorrelator (TSD) + +*******************************************************************************/ + +#include "sac_tsd.h" + +#define TSD_START_BAND (7) +#define SIZE_S (4) +#define SIZE_C (5) + +/*** Tables ***/ +RAM_ALIGN +LNK_SECTION_CONSTDATA +static const UCHAR nBitsTsdCW_32slots[32] = { + 5, 9, 13, 16, 18, 20, 22, 24, 25, 26, 27, 28, 29, 29, 30, 30, + 30, 29, 29, 28, 27, 26, 25, 24, 22, 20, 18, 16, 13, 9, 5, 0}; + +RAM_ALIGN +LNK_SECTION_CONSTDATA +static const UCHAR nBitsTsdCW_64slots[64] = { + 6, 11, 16, 20, 23, 27, 30, 33, 35, 38, 40, 42, 44, 46, 48, 49, + 51, 52, 53, 55, 56, 57, 58, 58, 59, 60, 60, 60, 61, 61, 61, 61, + 61, 61, 61, 60, 60, 60, 59, 58, 58, 57, 56, 55, 53, 52, 51, 49, + 48, 46, 44, 42, 40, 38, 35, 33, 30, 27, 23, 20, 16, 11, 6, 0}; + +RAM_ALIGN +LNK_SECTION_CONSTDATA +static const FIXP_STP phiTsd[8] = { + STCP(0x7fffffff, 0x00000000), STCP(0x5a82799a, 0x5a82799a), + STCP(0x00000000, 0x7fffffff), STCP(0xa57d8666, 0x5a82799a), + STCP(0x80000000, 0x00000000), STCP(0xa57d8666, 0xa57d8666), + STCP(0x00000000, 0x80000000), STCP(0x5a82799a, 0xa57d8666), +}; + +/*** Static Functions ***/ +static void longmult1(USHORT a[], USHORT b, USHORT d[], int len) { + int k; + ULONG tmp; + ULONG b0 = (ULONG)b; + + tmp = ((ULONG)a[0]) * b0; + d[0] = (USHORT)tmp; + + for (k = 1; k < len; k++) { + tmp = (tmp >> 16) + ((ULONG)a[k]) * b0; + d[k] = (USHORT)tmp; + } +} + +static void longdiv(USHORT b[], USHORT a, USHORT d[], USHORT *pr, int len) { + ULONG r; + ULONG tmp; + int k; + + FDK_ASSERT(a != 0); + + r = 0; + + for (k = len - 1; k >= 0; k--) { + tmp = ((ULONG)b[k]) + (r << 16); + + if (tmp) { + d[k] = (USHORT)(tmp / a); + r = tmp - d[k] * a; + } else { + d[k] = 0; + } + } + *pr = (USHORT)r; +} + +static void longsub(USHORT a[], USHORT b[], int lena, int lenb) { + int h; + LONG carry = 0; + + FDK_ASSERT(lena >= lenb); + for (h = 0; h < lenb; h++) { + carry += ((LONG)a[h]) - ((LONG)b[h]); + a[h] = (USHORT)carry; + carry = carry >> 16; + } + + for (; h < lena; h++) { + carry = ((LONG)a[h]) + carry; + a[h] = (USHORT)carry; + carry = carry >> 16; + } + + FDK_ASSERT(carry == + 0); /* carry != 0 indicates subtraction underflow, e.g. b > a */ + return; +} + +static int longcompare(USHORT a[], USHORT b[], int len) { + int i; + + for (i = len - 1; i > 0; i--) { + if (a[i] != b[i]) break; + } + return (a[i] >= b[i]) ? 1 : 0; +} + +FDK_INLINE int isTrSlot(const TSD_DATA *pTsdData, const int ts) { + return (pTsdData->bsTsdTrPhaseData[ts] >= 0); +} + +/*** Public Functions ***/ +int TsdRead(HANDLE_FDK_BITSTREAM hBs, const int numSlots, TSD_DATA *pTsdData) { + int nBitsTrSlots = 0; + int bsTsdNumTrSlots; + const UCHAR *nBitsTsdCW_tab = NULL; + + switch (numSlots) { + case 32: + nBitsTrSlots = 4; + nBitsTsdCW_tab = nBitsTsdCW_32slots; + break; + case 64: + nBitsTrSlots = 5; + nBitsTsdCW_tab = nBitsTsdCW_64slots; + break; + default: + return 1; + } + + /*** Read TempShapeData for bsTempShapeConfig == 3 ***/ + pTsdData->bsTsdEnable = FDKreadBit(hBs); + if (!pTsdData->bsTsdEnable) { + return 0; + } + + /*** Parse/Decode TsdData() ***/ + pTsdData->numSlots = numSlots; + + bsTsdNumTrSlots = FDKreadBits(hBs, nBitsTrSlots); + + /* Decode transient slot positions */ + { + int nBitsTsdCW = (int)nBitsTsdCW_tab[bsTsdNumTrSlots]; + SCHAR *phaseData = pTsdData->bsTsdTrPhaseData; + int p = bsTsdNumTrSlots + 1; + int k, h; + USHORT s[SIZE_S] = {0}; + USHORT c[SIZE_C] = {0}; + USHORT r[1]; + + /* Init with TsdSepData[k] = 0 */ + for (k = 0; k < numSlots; k++) { + phaseData[k] = -1; /* means TsdSepData[] = 0 */ + } + + for (h = (SIZE_S - 1); h >= 0; h--) { + if (nBitsTsdCW > h * 16) { + s[h] = (USHORT)FDKreadBits(hBs, nBitsTsdCW - h * 16); + nBitsTsdCW = h * 16; + } + } + + /* c = prod_{h=1}^{p} (k-p+h)/h */ + k = numSlots - 1; + c[0] = k - p + 1; + for (h = 2; h <= p; h++) { + longmult1(c, (k - p + h), c, 5); /* c *= k - p + h; */ + longdiv(c, h, c, r, 5); /* c /= h; */ + FDK_ASSERT(*r == 0); + } + + /* go through all slots */ + for (; k >= 0; k--) { + if (p > k) { + for (; k >= 0; k--) { + phaseData[k] = 1; /* means TsdSepData[] = 1 */ + } + break; + } + if (longcompare(s, c, 4)) { /* (s >= c) */ + longsub(s, c, 4, 4); /* s -= c; */ + phaseData[k] = 1; /* means TsdSepData[] = 1 */ + if (p == 1) { + break; + } + /* Update c for next iteration: c_new = c_old * p / k */ + longmult1(c, p, c, 5); + p--; + } else { + /* Update c for next iteration: c_new = c_old * (k-p) / k */ + longmult1(c, (k - p), c, 5); + } + longdiv(c, k, c, r, 5); + FDK_ASSERT(*r == 0); + } + + /* Read phase data */ + for (k = 0; k < numSlots; k++) { + if (phaseData[k] == 1) { + phaseData[k] = FDKreadBits(hBs, 3); + } + } + } + + return 0; +} + +void TsdGenerateNonTr(const int numHybridBands, const TSD_DATA *pTsdData, + const int ts, FIXP_DBL *pVdirectReal, + FIXP_DBL *pVdirectImag, FIXP_DBL *pVnonTrReal, + FIXP_DBL *pVnonTrImag, FIXP_DBL **ppDecorrInReal, + FIXP_DBL **ppDecorrInImag) { + int k = 0; + + if (!isTrSlot(pTsdData, ts)) { + /* Let allpass based decorrelator read from direct input. */ + *ppDecorrInReal = pVdirectReal; + *ppDecorrInImag = pVdirectImag; + return; + } + + /* Generate nonTr input signal for allpass based decorrelator */ + for (; k < TSD_START_BAND; k++) { + pVnonTrReal[k] = pVdirectReal[k]; + pVnonTrImag[k] = pVdirectImag[k]; + } + for (; k < numHybridBands; k++) { + pVnonTrReal[k] = (FIXP_DBL)0; + pVnonTrImag[k] = (FIXP_DBL)0; + } + *ppDecorrInReal = pVnonTrReal; + *ppDecorrInImag = pVnonTrImag; +} + +void TsdApply(const int numHybridBands, const TSD_DATA *pTsdData, int *pTsdTs, + const FIXP_DBL *pVdirectReal, const FIXP_DBL *pVdirectImag, + FIXP_DBL *pDnonTrReal, FIXP_DBL *pDnonTrImag) { + const int ts = *pTsdTs; + + if (isTrSlot(pTsdData, ts)) { + int k; + const FIXP_STP *phi = &phiTsd[pTsdData->bsTsdTrPhaseData[ts]]; + FDK_ASSERT((pTsdData->bsTsdTrPhaseData[ts] >= 0) && + (pTsdData->bsTsdTrPhaseData[ts] < 8)); + + /* d = d_nonTr + v_direct * exp(j * bsTsdTrPhaseData[ts]/4 * pi ) */ + for (k = TSD_START_BAND; k < numHybridBands; k++) { + FIXP_DBL tempReal, tempImag; + cplxMult(&tempReal, &tempImag, pVdirectReal[k], pVdirectImag[k], *phi); + pDnonTrReal[k] += tempReal; + pDnonTrImag[k] += tempImag; + } + } + + /* The modulo MAX_TSD_TIME_SLOTS operation is to avoid illegal memory accesses + * in case of errors. */ + *pTsdTs = (ts + 1) & (MAX_TSD_TIME_SLOTS - 1); + return; +} diff --git a/libSACdec/src/sac_tsd.h b/libSACdec/src/sac_tsd.h new file mode 100644 index 0000000..2521e27 --- /dev/null +++ b/libSACdec/src/sac_tsd.h @@ -0,0 +1,167 @@ +/* ----------------------------------------------------------------------------- +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): Matthias Hildenbrand + + Description: USAC MPS212 Transient Steering Decorrelator (TSD) + +*******************************************************************************/ + +#ifndef SAC_TSD_H +#define SAC_TSD_H + +#include "FDK_bitstream.h" +#include "common_fix.h" + +#define MAX_TSD_TIME_SLOTS (64) + +/** Structure which holds the data needed to apply TSD to current frame. */ +typedef struct { + UCHAR bsTsdEnable; /**< for current frame TSD is (0:disabled, 1:enabled) */ + UCHAR numSlots; /**< total number of QMF slots per frame */ + SCHAR + bsTsdTrPhaseData[MAX_TSD_TIME_SLOTS]; /**< -1 => TsdSepData[ts]=0; 0-7: + values of bsTsdTrPhaseData[ts] + and TsdSepData[ts]=1 */ +} TSD_DATA; + +FDK_INLINE int isTsdActive(const TSD_DATA *pTsdData) { + return (int)pTsdData->bsTsdEnable; +} + +/** + * \brief Parse and Decode TSD data. + * \param[in] hBs bitstream handle to read data from. + * \param[in] numSlots number of QMF slots per frame. + * \param[out] pTsdData pointer to TSD data structure. + * \return 0 on succes, 1 on error. + */ +int TsdRead(HANDLE_FDK_BITSTREAM hBs, const int numSlots, TSD_DATA *pTsdData); + +/** + * \brief Perform transient seperation (v_{x,nonTr} signal). + * \param[in] numHybridBands number of hybrid bands. + * \param[in] pTsdData pointer to TSD data structure. + * \param[in] pVdirectReal pointer to array with direct signal. + * \param[in] pVdirectImag pointer to array with direct signal. + * \param[out] pVnonTrReal pointer to array with nonTr signal. + * \param[out] pVnonTrImag pointer to array with nonTr signal. + * \param[out] ppDecorrInReal handle to array where allpass based decorrelator + * should read from (modified by this function). + * \param[out] ppDecorrInImag handle to array where allpass based decorrelator + * should read from (modified by this function). + */ +void TsdGenerateNonTr(const int numHybridBands, const TSD_DATA *pTsdData, + const int ts, FIXP_DBL *pVdirectReal, + FIXP_DBL *pVdirectImag, FIXP_DBL *pVnonTrReal, + FIXP_DBL *pVnonTrImag, FIXP_DBL **ppDecorrInReal, + FIXP_DBL **ppDecorrInImag); + +/** + * \brief Generate d_{x,Tr} signal and add to d_{x,nonTr} signal + * \param[in] numHybridBands + * \param[in,out] pTsdData + * \param pTsdTs pointer to persistent time slot counter + * \param[in] pVdirectReal + * \param[in] pVdirectImag + * \param[out] pDnonTrReal + * \param[out] pDnonTrImag + */ +void TsdApply(const int numHybridBands, const TSD_DATA *pTsdData, int *pTsdTs, + const FIXP_DBL *pVdirectReal, const FIXP_DBL *pVdirectImag, + FIXP_DBL *pDnonTrReal, FIXP_DBL *pDnonTrImag); + +#endif /* #ifndef SAC_TSD_H */ |