aboutsummaryrefslogtreecommitdiffstats
path: root/fdk-aac/libSBRdec
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2020-03-31 10:03:58 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2020-03-31 10:03:58 +0200
commita1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d (patch)
tree2b4790eec8f47fb086e645717f07c53b30ace919 /fdk-aac/libSBRdec
parent2f84a54ec1d10b10293c7b1f4ab9fee31f3c6327 (diff)
parentc6a73c219dbfdfe639372d9922f4eb512f06fa2f (diff)
downloadODR-AudioEnc-a1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d.tar.gz
ODR-AudioEnc-a1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d.tar.bz2
ODR-AudioEnc-a1eb6cf861d3c1cbd4e6c016be3cbd2a1e3d797d.zip
Merge GStreamer into next
Diffstat (limited to 'fdk-aac/libSBRdec')
-rw-r--r--fdk-aac/libSBRdec/include/sbrdecoder.h401
-rw-r--r--fdk-aac/libSBRdec/src/HFgen_preFlat.cpp993
-rw-r--r--fdk-aac/libSBRdec/src/HFgen_preFlat.h132
-rw-r--r--fdk-aac/libSBRdec/src/arm/lpp_tran_arm.cpp159
-rw-r--r--fdk-aac/libSBRdec/src/env_calc.cpp3158
-rw-r--r--fdk-aac/libSBRdec/src/env_calc.h182
-rw-r--r--fdk-aac/libSBRdec/src/env_dec.cpp873
-rw-r--r--fdk-aac/libSBRdec/src/env_dec.h119
-rw-r--r--fdk-aac/libSBRdec/src/env_extr.cpp1728
-rw-r--r--fdk-aac/libSBRdec/src/env_extr.h415
-rw-r--r--fdk-aac/libSBRdec/src/hbe.cpp2202
-rw-r--r--fdk-aac/libSBRdec/src/hbe.h200
-rw-r--r--fdk-aac/libSBRdec/src/huff_dec.cpp137
-rw-r--r--fdk-aac/libSBRdec/src/huff_dec.h117
-rw-r--r--fdk-aac/libSBRdec/src/lpp_tran.cpp1471
-rw-r--r--fdk-aac/libSBRdec/src/lpp_tran.h275
-rw-r--r--fdk-aac/libSBRdec/src/psbitdec.cpp594
-rw-r--r--fdk-aac/libSBRdec/src/psbitdec.h116
-rw-r--r--fdk-aac/libSBRdec/src/psdec.cpp722
-rw-r--r--fdk-aac/libSBRdec/src/psdec.h333
-rw-r--r--fdk-aac/libSBRdec/src/psdec_drm.cpp108
-rw-r--r--fdk-aac/libSBRdec/src/psdec_drm.h113
-rw-r--r--fdk-aac/libSBRdec/src/psdecrom_drm.cpp108
-rw-r--r--fdk-aac/libSBRdec/src/pvc_dec.cpp683
-rw-r--r--fdk-aac/libSBRdec/src/pvc_dec.h238
-rw-r--r--fdk-aac/libSBRdec/src/sbr_crc.cpp192
-rw-r--r--fdk-aac/libSBRdec/src/sbr_crc.h138
-rw-r--r--fdk-aac/libSBRdec/src/sbr_deb.cpp108
-rw-r--r--fdk-aac/libSBRdec/src/sbr_deb.h113
-rw-r--r--fdk-aac/libSBRdec/src/sbr_dec.cpp1480
-rw-r--r--fdk-aac/libSBRdec/src/sbr_dec.h204
-rw-r--r--fdk-aac/libSBRdec/src/sbr_ram.cpp191
-rw-r--r--fdk-aac/libSBRdec/src/sbr_ram.h186
-rw-r--r--fdk-aac/libSBRdec/src/sbr_rom.cpp1705
-rw-r--r--fdk-aac/libSBRdec/src/sbr_rom.h216
-rw-r--r--fdk-aac/libSBRdec/src/sbrdec_drc.cpp528
-rw-r--r--fdk-aac/libSBRdec/src/sbrdec_drc.h149
-rw-r--r--fdk-aac/libSBRdec/src/sbrdec_freq_sca.cpp835
-rw-r--r--fdk-aac/libSBRdec/src/sbrdec_freq_sca.h127
-rw-r--r--fdk-aac/libSBRdec/src/sbrdecoder.cpp2023
-rw-r--r--fdk-aac/libSBRdec/src/transcendent.h372
41 files changed, 24144 insertions, 0 deletions
diff --git a/fdk-aac/libSBRdec/include/sbrdecoder.h b/fdk-aac/libSBRdec/include/sbrdecoder.h
new file mode 100644
index 0000000..cc55572
--- /dev/null
+++ b/fdk-aac/libSBRdec/include/sbrdecoder.h
@@ -0,0 +1,401 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description: SBR decoder front-end prototypes and definitions.
+
+*******************************************************************************/
+
+#ifndef SBRDECODER_H
+#define SBRDECODER_H
+
+#include "common_fix.h"
+
+#include "FDK_bitstream.h"
+#include "FDK_audio.h"
+
+#include "FDK_qmf_domain.h"
+
+#define SBR_DEBUG_EXTHLP \
+ "\
+--- SBR ---\n\
+ 0x00000010 Ancillary data and SBR-Header\n\
+ 0x00000020 SBR-Side info\n\
+ 0x00000040 Decoded SBR-bitstream data, e.g. envelope data\n\
+ 0x00000080 SBR-Bitstream statistics\n\
+ 0x00000100 Miscellaneous SBR-messages\n\
+ 0x00000200 SBR-Energies and gains in the adjustor\n\
+ 0x00000400 Fatal SBR errors\n\
+ 0x00000800 Transposer coefficients for inverse filtering\n\
+"
+
+/* Capability flags */
+#define CAPF_SBR_LP \
+ 0x00000001 /*!< Flag indicating library's capability of Low Power mode. */
+#define CAPF_SBR_HQ \
+ 0x00000002 /*!< Flag indicating library's capability of High Quality mode. \
+ */
+#define CAPF_SBR_DRM_BS \
+ 0x00000004 /*!< Flag indicating library's capability to decode DRM SBR data. \
+ */
+#define CAPF_SBR_CONCEALMENT \
+ 0x00000008 /*!< Flag indicating library's capability to conceal erroneous \
+ frames. */
+#define CAPF_SBR_DRC \
+ 0x00000010 /*!< Flag indicating library's capability for Dynamic Range \
+ Control. */
+#define CAPF_SBR_PS_MPEG \
+ 0x00000020 /*!< Flag indicating library's capability to do MPEG Parametric \
+ Stereo. */
+#define CAPF_SBR_PS_DRM \
+ 0x00000040 /*!< Flag indicating library's capability to do DRM Parametric \
+ Stereo. */
+#define CAPF_SBR_ELD_DOWNSCALE \
+ 0x00000080 /*!< Flag indicating library's capability to do ELD decoding in \
+ downscaled mode */
+#define CAPF_SBR_HBEHQ \
+ 0x00000100 /*!< Flag indicating library's capability to do HQ Harmonic \
+ transposing */
+
+typedef enum {
+ SBRDEC_OK = 0, /*!< All fine. */
+ /* SBRDEC_CONCEAL, */
+ /* SBRDEC_NOSYNCH, */
+ /* SBRDEC_ILLEGAL_PROGRAM, */
+ /* SBRDEC_ILLEGAL_TAG, */
+ /* SBRDEC_ILLEGAL_CHN_CONFIG, */
+ /* SBRDEC_ILLEGAL_SECTION, */
+ /* SBRDEC_ILLEGAL_SCFACTORS, */
+ /* SBRDEC_ILLEGAL_PULSE_DATA, */
+ /* SBRDEC_MAIN_PROFILE_NOT_IMPLEMENTED, */
+ /* SBRDEC_GC_NOT_IMPLEMENTED, */
+ /* SBRDEC_ILLEGAL_PLUS_ELE_ID, */
+ SBRDEC_INVALID_ARGUMENT, /*!< */
+ SBRDEC_CREATE_ERROR, /*!< */
+ SBRDEC_NOT_INITIALIZED, /*!< */
+ SBRDEC_MEM_ALLOC_FAILED, /*!< Memory allocation failed. Probably not enough
+ memory available. */
+ SBRDEC_PARSE_ERROR, /*!< */
+ SBRDEC_UNSUPPORTED_CONFIG, /*!< */
+ SBRDEC_SET_PARAM_FAIL, /*!< */
+ SBRDEC_OUTPUT_BUFFER_TOO_SMALL /*!< */
+} SBR_ERROR;
+
+typedef enum {
+ SBR_SYSTEM_BITSTREAM_DELAY, /*!< System: Switch to enable an additional SBR
+ bitstream delay of one frame. */
+ SBR_QMF_MODE, /*!< Set QMF mode, either complex or low power. */
+ SBR_LD_QMF_TIME_ALIGN, /*!< Set QMF type, either LD-MPS or CLDFB. Relevant for
+ ELD streams only. */
+ SBR_FLUSH_DATA, /*!< Set internal state to flush the decoder with the next
+ process call. */
+ SBR_CLEAR_HISTORY, /*!< Clear all internal states (delay lines, QMF states,
+ ...). */
+ SBR_BS_INTERRUPTION /*!< Signal bit stream interruption. Value is ignored. */
+ ,
+ SBR_SKIP_QMF /*!< Enable skipping of QMF step: 1 skip analysis, 2 skip
+ synthesis */
+} SBRDEC_PARAM;
+
+typedef struct SBR_DECODER_INSTANCE *HANDLE_SBRDECODER;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Allocates and initializes one SBR decoder instance.
+ * \param pSelf Pointer to where a SBR decoder handle is copied into.
+ * \param pQmfDomain Pointer to QMF domain data structure.
+ *
+ * \return Error code.
+ */
+SBR_ERROR sbrDecoder_Open(HANDLE_SBRDECODER *pSelf,
+ HANDLE_FDK_QMF_DOMAIN pQmfDomain);
+
+/**
+ * \brief Initialize a SBR decoder runtime instance. Must be called before
+ * decoding starts.
+ *
+ * \param self Handle to a SBR decoder instance.
+ * \param sampleRateIn Input samplerate of the SBR decoder instance.
+ * \param sampleRateOut Output samplerate of the SBR decoder instance.
+ * \param samplesPerFrame Number of samples per frames.
+ * \param coreCodec Audio Object Type (AOT) of the core codec.
+ * \param elementID Table with MPEG-4 element Ids in canonical order.
+ * \param elementIndex SBR element index
+ * \param harmonicSBR
+ * \param stereoConfigIndex
+ * \param downscaleFactor ELD downscale factor
+ * \param configMode Table with MPEG-4 element Ids in canonical order.
+ * \param configChanged Flag that enforces a complete decoder reset.
+ *
+ * \return Error code.
+ */
+SBR_ERROR sbrDecoder_InitElement(
+ HANDLE_SBRDECODER self, const int sampleRateIn, const int sampleRateOut,
+ const int samplesPerFrame, const AUDIO_OBJECT_TYPE coreCodec,
+ const MP4_ELEMENT_ID elementID, const int elementIndex,
+ const UCHAR harmonicSBR, const UCHAR stereoConfigIndex,
+ const UCHAR configMode, UCHAR *configChanged, const INT downscaleFactor);
+
+/**
+ * \brief Free config dependent SBR memory.
+ * \param self SBR decoder instance handle
+ */
+SBR_ERROR sbrDecoder_FreeMem(HANDLE_SBRDECODER *self);
+
+/**
+ * \brief pass out of band SBR header to SBR decoder
+ *
+ * \param self Handle to a SBR decoder instance.
+ * \param hBs bit stream handle data source.
+ * \param sampleRateIn SBR input sampling rate
+ * \param sampleRateOut SBR output sampling rate
+ * \param samplesPerFrame frame length
+ * \param elementID SBR element ID.
+ * \param elementIndex SBR element index.
+ * \param harmonicSBR
+ * \param stereoConfigIndex
+ * \param downscaleFactor ELD downscale factor
+ *
+ * \return Error code.
+ */
+INT sbrDecoder_Header(HANDLE_SBRDECODER self, HANDLE_FDK_BITSTREAM hBs,
+ const INT sampleRateIn, const INT sampleRateOut,
+ const INT samplesPerFrame,
+ const AUDIO_OBJECT_TYPE coreCodec,
+ const MP4_ELEMENT_ID elementID, const INT elementIndex,
+ const UCHAR harmonicSBR, const UCHAR stereoConfigIndex,
+ const UCHAR configMode, UCHAR *configChanged,
+ const INT downscaleFactor);
+
+/**
+ * \brief Set a parameter of the SBR decoder runtime instance.
+ * \param self SBR decoder handle.
+ * \param param Parameter which will be set if successfull.
+ * \param value New parameter value.
+ * \return Error code.
+ */
+SBR_ERROR sbrDecoder_SetParam(HANDLE_SBRDECODER self, const SBRDEC_PARAM param,
+ const INT value);
+
+/**
+ * \brief Feed DRC channel data into a SBR decoder runtime instance.
+ *
+ * \param self SBR decoder handle.
+ * \param ch Channel number to which the DRC data is
+ * associated to.
+ * \param numBands Number of DRC bands.
+ * \param pNextFact_mag Pointer to a table with the DRC factor
+ * magnitudes.
+ * \param nextFact_exp Exponent for all DRC factors.
+ * \param drcInterpolationScheme DRC interpolation scheme.
+ * \param winSequence Window sequence from core coder (eight short
+ * or one long window).
+ * \param pBandTop Pointer to a table with the top borders for
+ * all DRC bands.
+ *
+ * \return Error code.
+ */
+SBR_ERROR sbrDecoder_drcFeedChannel(HANDLE_SBRDECODER self, INT ch,
+ UINT numBands, FIXP_DBL *pNextFact_mag,
+ INT nextFact_exp,
+ SHORT drcInterpolationScheme,
+ UCHAR winSequence, USHORT *pBandTop);
+
+/**
+ * \brief Disable SBR DRC for a certain channel.
+ *
+ * \param hSbrDecoder SBR decoder handle.
+ * \param ch Number of the channel that has to be disabled.
+ *
+ * \return None.
+ */
+void sbrDecoder_drcDisable(HANDLE_SBRDECODER self, INT ch);
+
+/**
+ * \brief Parse one SBR element data extension data block. The bit stream
+ * position will be placed at the end of the SBR payload block. The remaining
+ * bits will be returned into *count if a payload length is given
+ * (byPayLen > 0). If no SBR payload length is given (bsPayLen < 0) then
+ * the bit stream position on return will be random after this function
+ * call in case of errors, and any further decoding will be completely
+ * pointless. This function accepts either normal ordered SBR data or reverse
+ * ordered DRM SBR data.
+ *
+ * \param self SBR decoder handle.
+ * \param hBs Bit stream handle as data source.
+ * \param count Pointer to an integer where the amount of parsed SBR
+ * payload bits is stored into.
+ * \param bsPayLen If > 0 this value is the SBR payload length. If < 0,
+ * the SBR payload length is unknown.
+ * \param flags CRC flag (0: EXT_SBR_DATA; 1: EXT_SBR_DATA_CRC)
+ * \param prev_element Previous MPEG-4 element ID.
+ * \param element_index Index of the current element.
+ * \param acFlags Audio codec flags
+ *
+ * \return Error code.
+ */
+SBR_ERROR sbrDecoder_Parse(HANDLE_SBRDECODER self, HANDLE_FDK_BITSTREAM hBs,
+ UCHAR *pDrmBsBuffer, USHORT drmBsBufferSize,
+ int *count, int bsPayLen, int crcFlag,
+ MP4_ELEMENT_ID prev_element, int element_index,
+ UINT acFlags, UINT acElFlags[]);
+
+/**
+ * \brief This function decodes the given SBR bitstreams and applies SBR to the
+ * given time data.
+ *
+ * SBR-processing works InPlace. I.e. the calling function has to provide
+ * a time domain buffer timeData which can hold the completely decoded
+ * result.
+ *
+ * Left and right channel are read and stored according to the
+ * interleaving flag, frame length and number of channels.
+ *
+ * \param self Handle of an open SBR decoder instance.
+ * \param hSbrBs SBR Bitstream handle.
+ * \param input Pointer to input data.
+ * \param timeData Pointer to upsampled output data.
+ * \param timeDataSize Size of timeData.
+ * \param numChannels Pointer to a buffer holding the number of channels in
+ * time data buffer.
+ * \param sampleRate Output samplerate.
+ * \param channelMapping Channel mapping indices.
+ * \param coreDecodedOk Flag indicating if the core decoder did not find any
+ * error (0: core decoder found errors, 1: no errors).
+ * \param psDecoded Pointer to a buffer holding a flag. Input: PS is
+ * possible, Output: PS has been rendered.
+ *
+ * \return Error code.
+ */
+SBR_ERROR sbrDecoder_Apply(HANDLE_SBRDECODER self, INT_PCM *input,
+ INT_PCM *timeData, const int timeDataSize,
+ int *numChannels, int *sampleRate,
+ const FDK_channelMapDescr *const mapDescr,
+ const int mapIdx, const int coreDecodedOk,
+ UCHAR *psDecoded);
+
+/**
+ * \brief Close SBR decoder instance and free memory.
+ * \param self SBR decoder handle.
+ * \return Error Code.
+ */
+SBR_ERROR sbrDecoder_Close(HANDLE_SBRDECODER *self);
+
+/**
+ * \brief Get SBR decoder library information.
+ * \param info Pointer to a LIB_INFO struct, where library information is
+ * written to.
+ * \return 0 on success, -1 if invalid handle or if no free element is
+ * available to write information to.
+ */
+INT sbrDecoder_GetLibInfo(LIB_INFO *info);
+
+/**
+ * \brief Determine the modules output signal delay in samples.
+ * \param self SBR decoder handle.
+ * \return The number of samples signal delay added by the module.
+ */
+UINT sbrDecoder_GetDelay(const HANDLE_SBRDECODER self);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/fdk-aac/libSBRdec/src/HFgen_preFlat.cpp b/fdk-aac/libSBRdec/src/HFgen_preFlat.cpp
new file mode 100644
index 0000000..96adbb9
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/HFgen_preFlat.cpp
@@ -0,0 +1,993 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s): Oliver Moser, Manuel Jander, Matthias Hildenbrand
+
+ Description: QMF frequency pre-whitening for SBR.
+ In the documentation the terms "scale factor" and "exponent"
+ mean the same. Variables containing such information have
+ the suffix "_sf".
+
+*******************************************************************************/
+
+#include "HFgen_preFlat.h"
+
+#define POLY_ORDER 3
+#define MAXLOWBANDS 32
+#define LOG10FAC 0.752574989159953f /* == 10/log2(10) * 2^-2 */
+#define LOG10FAC_INV 0.664385618977472f /* == log2(10)/20 * 2^2 */
+
+#define FIXP_CHB FIXP_SGL /* STB sinus Tab used in transformation */
+#define CHC(a) (FX_DBL2FXCONST_SGL(a))
+#define FX_CHB2FX_DBL(a) FX_SGL2FX_DBL(a)
+
+typedef struct backsubst_data {
+ FIXP_CHB Lnorm1d[3]; /*!< Normalized L matrix */
+ SCHAR Lnorm1d_sf[3];
+ FIXP_CHB Lnormii
+ [3]; /*!< The diagonal data points [i][i] of the normalized L matrix */
+ SCHAR Lnormii_sf[3];
+ FIXP_CHB Bmul0
+ [4]; /*!< To normalize L*x=b, Bmul0 is what we need to multiply b with. */
+ SCHAR Bmul0_sf[4];
+ FIXP_CHB LnormInv1d[6]; /*!< Normalized inverted L matrix (L') */
+ SCHAR LnormInv1d_sf[6];
+ FIXP_CHB
+ Bmul1[4]; /*!< To normalize L'*x=b, Bmul1 is what we need to multiply b
+ with. */
+ SCHAR Bmul1_sf[4];
+} backsubst_data;
+
+/* for each element n do, f(n) = trunc(log2(n))+1 */
+const UCHAR getLog2[32] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
+
+/** \def BSD_IDX_OFFSET
+ *
+ * bsd[] begins at index 0 with data for numBands=5. The correct bsd[] is
+ * indexed like bsd[numBands-BSD_IDX_OFFSET].
+ */
+#define BSD_IDX_OFFSET 5
+
+#define N_NUMBANDS \
+ MAXLOWBANDS - BSD_IDX_OFFSET + \
+ 1 /*!< Number of backsubst_data elements in bsd */
+
+const backsubst_data bsd[N_NUMBANDS] = {
+ {
+ /* numBands=5 */
+ {CHC(0x66c85a52), CHC(0x4278e587), CHC(0x697dcaff)},
+ {-1, 0, 0},
+ {CHC(0x66a61789), CHC(0x5253b8e3), CHC(0x5addad81)},
+ {3, 4, 1},
+ {CHC(0x7525ee90), CHC(0x6e2a1210), CHC(0x6523bb40), CHC(0x59822ead)},
+ {-6, -4, -2, 0},
+ {CHC(0x609e4cad), CHC(0x59c7e312), CHC(0x681eecac), CHC(0x440ea893),
+ CHC(0x4a214bb3), CHC(0x53c345a1)},
+ {1, 0, -1, -1, -3, -5},
+ {CHC(0x7525ee90), CHC(0x58587936), CHC(0x410d0b38), CHC(0x7f1519d6)},
+ {-6, -1, 2, 0},
+ },
+ {
+ /* numBands=6 */
+ {CHC(0x68943285), CHC(0x4841d2c3), CHC(0x6a6214c7)},
+ {-1, 0, 0},
+ {CHC(0x63c5923e), CHC(0x4e906e18), CHC(0x6285af8a)},
+ {3, 4, 1},
+ {CHC(0x7263940b), CHC(0x424a69a5), CHC(0x4ae8383a), CHC(0x517b7730)},
+ {-7, -4, -2, 0},
+ {CHC(0x518aee5f), CHC(0x4823a096), CHC(0x43764a39), CHC(0x6e6faf23),
+ CHC(0x61bba44f), CHC(0x59d8b132)},
+ {1, 0, -1, -2, -4, -6},
+ {CHC(0x7263940b), CHC(0x6757bff2), CHC(0x5bf40fe0), CHC(0x7d6f4292)},
+ {-7, -2, 1, 0},
+ },
+ {
+ /* numBands=7 */
+ {CHC(0x699b4c3c), CHC(0x4b8b702f), CHC(0x6ae51a4f)},
+ {-1, 0, 0},
+ {CHC(0x623a7f49), CHC(0x4ccc91fc), CHC(0x68f048dd)},
+ {3, 4, 1},
+ {CHC(0x7e6ebe18), CHC(0x5701daf2), CHC(0x74a8198b), CHC(0x4b399aa1)},
+ {-8, -5, -3, 0},
+ {CHC(0x464a64a6), CHC(0x78e42633), CHC(0x5ee174ba), CHC(0x5d0008c8),
+ CHC(0x455cff0f), CHC(0x6b9100e7)},
+ {1, -1, -2, -2, -4, -7},
+ {CHC(0x7e6ebe18), CHC(0x42c52efe), CHC(0x45fe401f), CHC(0x7b5808ef)},
+ {-8, -2, 1, 0},
+ },
+ {
+ /* numBands=8 */
+ {CHC(0x6a3fd9b4), CHC(0x4d99823f), CHC(0x6b372a94)},
+ {-1, 0, 0},
+ {CHC(0x614c6ef7), CHC(0x4bd06699), CHC(0x6e59cfca)},
+ {3, 4, 1},
+ {CHC(0x4c389cc5), CHC(0x79686681), CHC(0x5e2544c2), CHC(0x46305b43)},
+ {-8, -6, -3, 0},
+ {CHC(0x7b4ca7c6), CHC(0x68270ac5), CHC(0x467c644c), CHC(0x505c1b0f),
+ CHC(0x67a14778), CHC(0x45801767)},
+ {0, -1, -2, -2, -5, -7},
+ {CHC(0x4c389cc5), CHC(0x5c499ceb), CHC(0x6f863c9f), CHC(0x79059bfc)},
+ {-8, -3, 0, 0},
+ },
+ {
+ /* numBands=9 */
+ {CHC(0x6aad9988), CHC(0x4ef8ac18), CHC(0x6b6df116)},
+ {-1, 0, 0},
+ {CHC(0x60b159b0), CHC(0x4b33f772), CHC(0x72f5573d)},
+ {3, 4, 1},
+ {CHC(0x6206cb18), CHC(0x58a7d8dc), CHC(0x4e0b2d0b), CHC(0x4207ad84)},
+ {-9, -6, -3, 0},
+ {CHC(0x6dadadae), CHC(0x5b8b2cfc), CHC(0x6cf61db2), CHC(0x46c3c90b),
+ CHC(0x506314ea), CHC(0x5f034acd)},
+ {0, -1, -3, -2, -5, -8},
+ {CHC(0x6206cb18), CHC(0x42f8b8de), CHC(0x5bb4776f), CHC(0x769acc79)},
+ {-9, -3, 0, 0},
+ },
+ {
+ /* numBands=10 */
+ {CHC(0x6afa7252), CHC(0x4feed3ed), CHC(0x6b94504d)},
+ {-1, 0, 0},
+ {CHC(0x60467899), CHC(0x4acbafba), CHC(0x76eb327f)},
+ {3, 4, 1},
+ {CHC(0x42415b15), CHC(0x431080da), CHC(0x420f1c32), CHC(0x7d0c1aeb)},
+ {-9, -6, -3, -1},
+ {CHC(0x62b2c7a4), CHC(0x51b040a6), CHC(0x56caddb4), CHC(0x7e74a2c8),
+ CHC(0x4030adf5), CHC(0x43d1dc4f)},
+ {0, -1, -3, -3, -5, -8},
+ {CHC(0x42415b15), CHC(0x64e299b3), CHC(0x4d33b5e8), CHC(0x742cee5f)},
+ {-9, -4, 0, 0},
+ },
+ {
+ /* numBands=11 */
+ {CHC(0x6b3258bb), CHC(0x50a21233), CHC(0x6bb03c19)},
+ {-1, 0, 0},
+ {CHC(0x5ff997c6), CHC(0x4a82706e), CHC(0x7a5aae36)},
+ {3, 4, 1},
+ {CHC(0x5d2fb4fb), CHC(0x685bddd8), CHC(0x71b5e983), CHC(0x7708c90b)},
+ {-10, -7, -4, -1},
+ {CHC(0x59aceea2), CHC(0x49c428a0), CHC(0x46ca5527), CHC(0x724be884),
+ CHC(0x68e586da), CHC(0x643485b6)},
+ {0, -1, -3, -3, -6, -9},
+ {CHC(0x5d2fb4fb), CHC(0x4e3fad1a), CHC(0x42310ba2), CHC(0x71c8b3ce)},
+ {-10, -4, 0, 0},
+ },
+ {
+ /* numBands=12 */
+ {CHC(0x6b5c4726), CHC(0x5128a4a8), CHC(0x6bc52ee1)},
+ {-1, 0, 0},
+ {CHC(0x5fc06618), CHC(0x4a4ce559), CHC(0x7d5c16e9)},
+ {3, 4, 1},
+ {CHC(0x43af8342), CHC(0x531533d3), CHC(0x633660a6), CHC(0x71ce6052)},
+ {-10, -7, -4, -1},
+ {CHC(0x522373d7), CHC(0x434150cb), CHC(0x75b58afc), CHC(0x68474f2d),
+ CHC(0x575348a5), CHC(0x4c20973f)},
+ {0, -1, -4, -3, -6, -9},
+ {CHC(0x43af8342), CHC(0x7c4d3d11), CHC(0x732e13db), CHC(0x6f756ac4)},
+ {-10, -5, -1, 0},
+ },
+ {
+ /* numBands=13 */
+ {CHC(0x6b7c8953), CHC(0x51903fcd), CHC(0x6bd54d2e)},
+ {-1, 0, 0},
+ {CHC(0x5f94abf0), CHC(0x4a2480fa), CHC(0x40013553)},
+ {3, 4, 2},
+ {CHC(0x6501236e), CHC(0x436b9c4e), CHC(0x578d7881), CHC(0x6d34f92e)},
+ {-11, -7, -4, -1},
+ {CHC(0x4bc0e2b2), CHC(0x7b9d12ac), CHC(0x636c1c1b), CHC(0x5fe15c2b),
+ CHC(0x49d54879), CHC(0x7662cfa5)},
+ {0, -2, -4, -3, -6, -10},
+ {CHC(0x6501236e), CHC(0x64b059fe), CHC(0x656d8359), CHC(0x6d370900)},
+ {-11, -5, -1, 0},
+ },
+ {
+ /* numBands=14 */
+ {CHC(0x6b95e276), CHC(0x51e1b637), CHC(0x6be1f7ed)},
+ {-1, 0, 0},
+ {CHC(0x5f727a1c), CHC(0x4a053e9c), CHC(0x412e528c)},
+ {3, 4, 2},
+ {CHC(0x4d178bd4), CHC(0x6f33b4e8), CHC(0x4e028f7f), CHC(0x691ee104)},
+ {-11, -8, -4, -1},
+ {CHC(0x46473d3f), CHC(0x725bd0a6), CHC(0x55199885), CHC(0x58bcc56b),
+ CHC(0x7e7e6288), CHC(0x5ddef6eb)},
+ {0, -2, -4, -3, -7, -10},
+ {CHC(0x4d178bd4), CHC(0x52ebd467), CHC(0x5a395a6e), CHC(0x6b0f724f)},
+ {-11, -5, -1, 0},
+ },
+ {
+ /* numBands=15 */
+ {CHC(0x6baa2a22), CHC(0x5222eb91), CHC(0x6bec1a86)},
+ {-1, 0, 0},
+ {CHC(0x5f57393b), CHC(0x49ec8934), CHC(0x423b5b58)},
+ {3, 4, 2},
+ {CHC(0x77fd2486), CHC(0x5cfbdf2c), CHC(0x46153bd1), CHC(0x65757ed9)},
+ {-12, -8, -4, -1},
+ {CHC(0x41888ee6), CHC(0x6a661db3), CHC(0x49abc8c8), CHC(0x52965848),
+ CHC(0x6d9301b7), CHC(0x4bb04721)},
+ {0, -2, -4, -3, -7, -10},
+ {CHC(0x77fd2486), CHC(0x45424c68), CHC(0x50f33cc6), CHC(0x68ff43f0)},
+ {-12, -5, -1, 0},
+ },
+ {
+ /* numBands=16 */
+ {CHC(0x6bbaa499), CHC(0x5257ed94), CHC(0x6bf456e4)},
+ {-1, 0, 0},
+ {CHC(0x5f412594), CHC(0x49d8a766), CHC(0x432d1dbd)},
+ {3, 4, 2},
+ {CHC(0x5ef5cfde), CHC(0x4eafcd2d), CHC(0x7ed36893), CHC(0x62274b45)},
+ {-12, -8, -5, -1},
+ {CHC(0x7ac438f5), CHC(0x637aab21), CHC(0x4067617a), CHC(0x4d3c6ec7),
+ CHC(0x5fd6e0dd), CHC(0x7bd5f024)},
+ {-1, -2, -4, -3, -7, -11},
+ {CHC(0x5ef5cfde), CHC(0x751d0d4f), CHC(0x492b3c41), CHC(0x67065409)},
+ {-12, -6, -1, 0},
+ },
+ {
+ /* numBands=17 */
+ {CHC(0x6bc836c9), CHC(0x5283997e), CHC(0x6bfb1f5e)},
+ {-1, 0, 0},
+ {CHC(0x5f2f02b6), CHC(0x49c868e9), CHC(0x44078151)},
+ {3, 4, 2},
+ {CHC(0x4c43b65a), CHC(0x4349dcf6), CHC(0x73799e2d), CHC(0x5f267274)},
+ {-12, -8, -5, -1},
+ {CHC(0x73726394), CHC(0x5d68511a), CHC(0x7191bbcc), CHC(0x48898c70),
+ CHC(0x548956e1), CHC(0x66981ce8)},
+ {-1, -2, -5, -3, -7, -11},
+ {CHC(0x4c43b65a), CHC(0x64131116), CHC(0x429028e2), CHC(0x65240211)},
+ {-12, -6, -1, 0},
+ },
+ {
+ /* numBands=18 */
+ {CHC(0x6bd3860d), CHC(0x52a80156), CHC(0x6c00c68d)},
+ {-1, 0, 0},
+ {CHC(0x5f1fed86), CHC(0x49baf636), CHC(0x44cdb9dc)},
+ {3, 4, 2},
+ {CHC(0x7c189389), CHC(0x742666d8), CHC(0x69b8c776), CHC(0x5c67e27d)},
+ {-13, -9, -5, -1},
+ {CHC(0x6cf1ea76), CHC(0x58095703), CHC(0x64e351a9), CHC(0x4460da90),
+ CHC(0x4b1f8083), CHC(0x55f2d3e1)},
+ {-1, -2, -5, -3, -7, -11},
+ {CHC(0x7c189389), CHC(0x5651792a), CHC(0x79cb9b3d), CHC(0x635769c0)},
+ {-13, -6, -2, 0},
+ },
+ {
+ /* numBands=19 */
+ {CHC(0x6bdd0c40), CHC(0x52c6abf6), CHC(0x6c058950)},
+ {-1, 0, 0},
+ {CHC(0x5f133f88), CHC(0x49afb305), CHC(0x45826d73)},
+ {3, 4, 2},
+ {CHC(0x6621a164), CHC(0x6512528e), CHC(0x61449fc8), CHC(0x59e2a0c0)},
+ {-13, -9, -5, -1},
+ {CHC(0x6721cadb), CHC(0x53404cd4), CHC(0x5a389e91), CHC(0x40abcbd2),
+ CHC(0x43332f01), CHC(0x48b82e46)},
+ {-1, -2, -5, -3, -7, -11},
+ {CHC(0x6621a164), CHC(0x4b12cc28), CHC(0x6ffd4df8), CHC(0x619f835e)},
+ {-13, -6, -2, 0},
+ },
+ {
+ /* numBands=20 */
+ {CHC(0x6be524c5), CHC(0x52e0beb3), CHC(0x6c099552)},
+ {-1, 0, 0},
+ {CHC(0x5f087c68), CHC(0x49a62bb5), CHC(0x4627d175)},
+ {3, 4, 2},
+ {CHC(0x54ec6afe), CHC(0x58991a42), CHC(0x59e23e8c), CHC(0x578f4ef4)},
+ {-13, -9, -5, -1},
+ {CHC(0x61e78f6f), CHC(0x4ef5e1e9), CHC(0x5129c3b8), CHC(0x7ab0f7b2),
+ CHC(0x78efb076), CHC(0x7c2567ea)},
+ {-1, -2, -5, -4, -8, -12},
+ {CHC(0x54ec6afe), CHC(0x41c7812c), CHC(0x676f6f8d), CHC(0x5ffb383f)},
+ {-13, -6, -2, 0},
+ },
+ {
+ /* numBands=21 */
+ {CHC(0x6bec1542), CHC(0x52f71929), CHC(0x6c0d0d5e)},
+ {-1, 0, 0},
+ {CHC(0x5eff45c5), CHC(0x499e092d), CHC(0x46bfc0c9)},
+ {3, 4, 2},
+ {CHC(0x47457a78), CHC(0x4e2d99b3), CHC(0x53637ea5), CHC(0x5567d0e9)},
+ {-13, -9, -5, -1},
+ {CHC(0x5d2dc61b), CHC(0x4b1760c8), CHC(0x4967cf39), CHC(0x74b113d8),
+ CHC(0x6d6676b6), CHC(0x6ad114e9)},
+ {-1, -2, -5, -4, -8, -12},
+ {CHC(0x47457a78), CHC(0x740accaa), CHC(0x5feb6609), CHC(0x5e696f95)},
+ {-13, -7, -2, 0},
+ },
+ {
+ /* numBands=22 */
+ {CHC(0x6bf21387), CHC(0x530a683c), CHC(0x6c100c59)},
+ {-1, 0, 0},
+ {CHC(0x5ef752ea), CHC(0x499708c6), CHC(0x474bcd1b)},
+ {3, 4, 2},
+ {CHC(0x78a21ab7), CHC(0x45658aec), CHC(0x4da3c4fe), CHC(0x5367094b)},
+ {-14, -9, -5, -1},
+ {CHC(0x58e2df6a), CHC(0x4795990e), CHC(0x42b5e0f7), CHC(0x6f408c64),
+ CHC(0x6370bebf), CHC(0x5c91ca85)},
+ {-1, -2, -5, -4, -8, -12},
+ {CHC(0x78a21ab7), CHC(0x66f951d6), CHC(0x594605bb), CHC(0x5ce91657)},
+ {-14, -7, -2, 0},
+ },
+ {
+ /* numBands=23 */
+ {CHC(0x6bf749b2), CHC(0x531b3348), CHC(0x6c12a750)},
+ {-1, 0, 0},
+ {CHC(0x5ef06b17), CHC(0x4990f6c9), CHC(0x47cd4c5b)},
+ {3, 4, 2},
+ {CHC(0x66dede36), CHC(0x7bdf90a9), CHC(0x4885b2b9), CHC(0x5188a6b7)},
+ {-14, -10, -5, -1},
+ {CHC(0x54f85812), CHC(0x446414ae), CHC(0x79c8d519), CHC(0x6a4c2f31),
+ CHC(0x5ac8325f), CHC(0x50bf9200)},
+ {-1, -2, -6, -4, -8, -12},
+ {CHC(0x66dede36), CHC(0x5be0d90e), CHC(0x535cc453), CHC(0x5b7923f0)},
+ {-14, -7, -2, 0},
+ },
+ {
+ /* numBands=24 */
+ {CHC(0x6bfbd91d), CHC(0x5329e580), CHC(0x6c14eeed)},
+ {-1, 0, 0},
+ {CHC(0x5eea6179), CHC(0x498baa90), CHC(0x4845635d)},
+ {3, 4, 2},
+ {CHC(0x58559b7e), CHC(0x6f1b231f), CHC(0x43f1789b), CHC(0x4fc8fcb8)},
+ {-14, -10, -5, -1},
+ {CHC(0x51621775), CHC(0x417881a3), CHC(0x6f9ba9b6), CHC(0x65c412b2),
+ CHC(0x53352c61), CHC(0x46db9caf)},
+ {-1, -2, -6, -4, -8, -12},
+ {CHC(0x58559b7e), CHC(0x52636003), CHC(0x4e13b316), CHC(0x5a189cdf)},
+ {-14, -7, -2, 0},
+ },
+ {
+ /* numBands=25 */
+ {CHC(0x6bffdc73), CHC(0x5336d4af), CHC(0x6c16f084)},
+ {-1, 0, 0},
+ {CHC(0x5ee51249), CHC(0x498703cc), CHC(0x48b50e4f)},
+ {3, 4, 2},
+ {CHC(0x4c5616cf), CHC(0x641b9fad), CHC(0x7fa735e0), CHC(0x4e24e57a)},
+ {-14, -10, -6, -1},
+ {CHC(0x4e15f47a), CHC(0x7d9481d6), CHC(0x66a82f8a), CHC(0x619ae971),
+ CHC(0x4c8b2f5f), CHC(0x7d09ec11)},
+ {-1, -3, -6, -4, -8, -13},
+ {CHC(0x4c5616cf), CHC(0x4a3770fb), CHC(0x495402de), CHC(0x58c693fa)},
+ {-14, -7, -2, 0},
+ },
+ {
+ /* numBands=26 */
+ {CHC(0x6c036943), CHC(0x53424625), CHC(0x6c18b6dc)},
+ {-1, 0, 0},
+ {CHC(0x5ee060aa), CHC(0x4982e88a), CHC(0x491d277f)},
+ {3, 4, 2},
+ {CHC(0x425ada5b), CHC(0x5a9368ac), CHC(0x78380a42), CHC(0x4c99aa05)},
+ {-14, -10, -6, -1},
+ {CHC(0x4b0b569c), CHC(0x78a420da), CHC(0x5ebdf203), CHC(0x5dc57e63),
+ CHC(0x46a650ff), CHC(0x6ee13fb8)},
+ {-1, -3, -6, -4, -8, -13},
+ {CHC(0x425ada5b), CHC(0x4323073c), CHC(0x450ae92b), CHC(0x57822ad5)},
+ {-14, -7, -2, 0},
+ },
+ {
+ /* numBands=27 */
+ {CHC(0x6c06911a), CHC(0x534c7261), CHC(0x6c1a4aba)},
+ {-1, 0, 0},
+ {CHC(0x5edc3524), CHC(0x497f43c0), CHC(0x497e6cd8)},
+ {3, 4, 2},
+ {CHC(0x73fb550e), CHC(0x5244894f), CHC(0x717aad78), CHC(0x4b24ef6c)},
+ {-15, -10, -6, -1},
+ {CHC(0x483aebe4), CHC(0x74139116), CHC(0x57b58037), CHC(0x5a3a4f3c),
+ CHC(0x416950fe), CHC(0x62c7f4f2)},
+ {-1, -3, -6, -4, -8, -13},
+ {CHC(0x73fb550e), CHC(0x79efb994), CHC(0x4128cab7), CHC(0x564a919a)},
+ {-15, -8, -2, 0},
+ },
+ {
+ /* numBands=28 */
+ {CHC(0x6c096264), CHC(0x535587cd), CHC(0x6c1bb355)},
+ {-1, 0, 0},
+ {CHC(0x5ed87c76), CHC(0x497c0439), CHC(0x49d98452)},
+ {3, 4, 2},
+ {CHC(0x65dec5bf), CHC(0x4afd1ba3), CHC(0x6b58b4b3), CHC(0x49c4a7b0)},
+ {-15, -10, -6, -1},
+ {CHC(0x459e6eb1), CHC(0x6fd850b7), CHC(0x516e7be9), CHC(0x56f13d05),
+ CHC(0x79785594), CHC(0x58617de7)},
+ {-1, -3, -6, -4, -9, -13},
+ {CHC(0x65dec5bf), CHC(0x6f2168aa), CHC(0x7b41310f), CHC(0x551f0692)},
+ {-15, -8, -3, 0},
+ },
+ {
+ /* numBands=29 */
+ {CHC(0x6c0be913), CHC(0x535dacd5), CHC(0x6c1cf6a3)},
+ {-1, 0, 0},
+ {CHC(0x5ed526b4), CHC(0x49791bc5), CHC(0x4a2eff99)},
+ {3, 4, 2},
+ {CHC(0x59e44afe), CHC(0x44949ada), CHC(0x65bf36f5), CHC(0x487705a0)},
+ {-15, -10, -6, -1},
+ {CHC(0x43307779), CHC(0x6be959c4), CHC(0x4bce2122), CHC(0x53e34d89),
+ CHC(0x7115ff82), CHC(0x4f6421a1)},
+ {-1, -3, -6, -4, -9, -13},
+ {CHC(0x59e44afe), CHC(0x659eab7d), CHC(0x74cea459), CHC(0x53fed574)},
+ {-15, -8, -3, 0},
+ },
+ {
+ /* numBands=30 */
+ {CHC(0x6c0e2f17), CHC(0x53650181), CHC(0x6c1e199d)},
+ {-1, 0, 0},
+ {CHC(0x5ed2269f), CHC(0x49767e9e), CHC(0x4a7f5f0b)},
+ {3, 4, 2},
+ {CHC(0x4faa4ae6), CHC(0x7dd3bf11), CHC(0x609e2732), CHC(0x473a72e9)},
+ {-15, -11, -6, -1},
+ {CHC(0x40ec57c6), CHC(0x683ee147), CHC(0x46be261d), CHC(0x510a7983),
+ CHC(0x698a84cb), CHC(0x4794a927)},
+ {-1, -3, -6, -4, -9, -13},
+ {CHC(0x4faa4ae6), CHC(0x5d3615ad), CHC(0x6ee74773), CHC(0x52e956a1)},
+ {-15, -8, -3, 0},
+ },
+ {
+ /* numBands=31 */
+ {CHC(0x6c103cc9), CHC(0x536ba0ac), CHC(0x6c1f2070)},
+ {-1, 0, 0},
+ {CHC(0x5ecf711e), CHC(0x497422ea), CHC(0x4acb1438)},
+ {3, 4, 2},
+ {CHC(0x46e322ad), CHC(0x73c32f3c), CHC(0x5be7d172), CHC(0x460d8800)},
+ {-15, -11, -6, -1},
+ {CHC(0x7d9bf8ad), CHC(0x64d22351), CHC(0x422bdc81), CHC(0x4e6184aa),
+ CHC(0x62ba2375), CHC(0x40c325de)},
+ {-2, -3, -6, -4, -9, -13},
+ {CHC(0x46e322ad), CHC(0x55bef2a3), CHC(0x697b3135), CHC(0x51ddee4d)},
+ {-15, -8, -3, 0},
+ },
+ {
+ // numBands=32
+ {CHC(0x6c121933), CHC(0x5371a104), CHC(0x6c200ea0)},
+ {-1, 0, 0},
+ {CHC(0x5eccfcd3), CHC(0x49720060), CHC(0x4b1283f0)},
+ {3, 4, 2},
+ {CHC(0x7ea12a52), CHC(0x6aca3303), CHC(0x579072bf), CHC(0x44ef056e)},
+ {-16, -11, -6, -1},
+ {CHC(0x79a3a9ab), CHC(0x619d38fc), CHC(0x7c0f0734), CHC(0x4be3dd5d),
+ CHC(0x5c8d7163), CHC(0x7591065f)},
+ {-2, -3, -7, -4, -9, -14},
+ {CHC(0x7ea12a52), CHC(0x4f1782a6), CHC(0x647cbcb2), CHC(0x50dc0bb1)},
+ {-16, -8, -3, 0},
+ },
+};
+
+/** \def SUM_SAFETY
+ *
+ * SUM_SAFTEY defines the bits needed to right-shift every summand in
+ * order to be overflow-safe. In the two backsubst functions we sum up 4
+ * values. Since one of which is definitely not MAXVAL_DBL (the L[x][y]),
+ * we spare just 2 safety bits instead of 3.
+ */
+#define SUM_SAFETY 2
+
+/**
+ * \brief Solves L*x=b via backsubstitution according to the following
+ * structure:
+ *
+ * x[0] = b[0];
+ * x[1] = (b[1] - x[0]) / L[1][1];
+ * x[2] = (b[2] - x[1]*L[2][1] - x[0]) / L[2][2];
+ * x[3] = (b[3] - x[2]*L[3][2] - x[1]*L[3][1] - x[0]) / L[3][3];
+ *
+ * \param[in] numBands SBR crossover band index
+ * \param[in] b the b in L*x=b (one-dimensional)
+ * \param[out] x output polynomial coefficients (mantissa)
+ * \param[out] x_sf exponents of x[]
+ */
+static void backsubst_fw(const int numBands, const FIXP_DBL *const b,
+ FIXP_DBL *RESTRICT x, int *RESTRICT x_sf) {
+ int i, k;
+ int m; /* the trip counter that indexes incrementally through Lnorm1d[] */
+
+ const FIXP_CHB *RESTRICT pLnorm1d = bsd[numBands - BSD_IDX_OFFSET].Lnorm1d;
+ const SCHAR *RESTRICT pLnorm1d_sf = bsd[numBands - BSD_IDX_OFFSET].Lnorm1d_sf;
+ const FIXP_CHB *RESTRICT pLnormii = bsd[numBands - BSD_IDX_OFFSET].Lnormii;
+ const SCHAR *RESTRICT pLnormii_sf = bsd[numBands - BSD_IDX_OFFSET].Lnormii_sf;
+
+ x[0] = b[0];
+
+ for (i = 1, m = 0; i <= POLY_ORDER; ++i) {
+ FIXP_DBL sum = b[i] >> SUM_SAFETY;
+ int sum_sf = x_sf[i];
+ for (k = i - 1; k > 0; --k, ++m) {
+ int e;
+ FIXP_DBL mult = fMultNorm(FX_CHB2FX_DBL(pLnorm1d[m]), x[k], &e);
+ int mult_sf = pLnorm1d_sf[m] + x_sf[k] + e;
+
+ /* check if the new summand mult has a different sf than the sum currently
+ * has */
+ int diff = mult_sf - sum_sf;
+
+ if (diff > 0) {
+ /* yes, and it requires the sum to be adjusted (scaled down) */
+ sum >>= diff;
+ sum_sf = mult_sf;
+ } else if (diff < 0) {
+ /* yes, but here mult needs to be scaled down */
+ mult >>= -diff;
+ }
+ sum -= (mult >> SUM_SAFETY);
+ }
+
+ /* - x[0] */
+ if (x_sf[0] > sum_sf) {
+ sum >>= (x_sf[0] - sum_sf);
+ sum_sf = x_sf[0];
+ }
+ sum -= (x[0] >> (sum_sf - x_sf[0] + SUM_SAFETY));
+
+ /* instead of the division /L[i][i], we multiply by the inverse */
+ int e;
+ x[i] = fMultNorm(sum, FX_CHB2FX_DBL(pLnormii[i - 1]), &e);
+ x_sf[i] = sum_sf + pLnormii_sf[i - 1] + e + SUM_SAFETY;
+ }
+}
+
+/**
+ * \brief Solves L*x=b via backsubstitution according to the following
+ * structure:
+ *
+ * x[3] = b[3];
+ * x[2] = b[2] - L[2][3]*x[3];
+ * x[1] = b[1] - L[1][2]*x[2] - L[1][3]*x[3];
+ * x[0] = b[0] - L[0][1]*x[1] - L[0][2]*x[2] - L[0][3]*x[3];
+ *
+ * \param[in] numBands SBR crossover band index
+ * \param[in] b the b in L*x=b (one-dimensional)
+ * \param[out] x solution vector
+ * \param[out] x_sf exponents of x[]
+ */
+static void backsubst_bw(const int numBands, const FIXP_DBL *const b,
+ FIXP_DBL *RESTRICT x, int *RESTRICT x_sf) {
+ int i, k;
+ int m; /* the trip counter that indexes incrementally through LnormInv1d[] */
+
+ const FIXP_CHB *RESTRICT pLnormInv1d =
+ bsd[numBands - BSD_IDX_OFFSET].LnormInv1d;
+ const SCHAR *RESTRICT pLnormInv1d_sf =
+ bsd[numBands - BSD_IDX_OFFSET].LnormInv1d_sf;
+
+ x[POLY_ORDER] = b[POLY_ORDER];
+
+ for (i = POLY_ORDER - 1, m = 0; i >= 0; i--) {
+ FIXP_DBL sum = b[i] >> SUM_SAFETY;
+ int sum_sf = x_sf[i]; /* sum's sf but disregarding SUM_SAFETY (added at the
+ iteration's end) */
+
+ for (k = i + 1; k <= POLY_ORDER; ++k, ++m) {
+ int e;
+ FIXP_DBL mult = fMultNorm(FX_CHB2FX_DBL(pLnormInv1d[m]), x[k], &e);
+ int mult_sf = pLnormInv1d_sf[m] + x_sf[k] + e;
+
+ /* check if the new summand mult has a different sf than sum currently has
+ */
+ int diff = mult_sf - sum_sf;
+
+ if (diff > 0) {
+ /* yes, and it requires the sum v to be adjusted (scaled down) */
+ sum >>= diff;
+ sum_sf = mult_sf;
+ } else if (diff < 0) {
+ /* yes, but here mult needs to be scaled down */
+ mult >>= -diff;
+ }
+
+ /* mult has now the same sf than what it is about to be added to. */
+ /* scale mult down additionally so that building the sum is overflow-safe.
+ */
+ sum -= (mult >> SUM_SAFETY);
+ }
+
+ x_sf[i] = sum_sf + SUM_SAFETY;
+ x[i] = sum;
+ }
+}
+
+/**
+ * \brief Solves a system of linear equations (L*x=b) with the Cholesky
+ * algorithm.
+ *
+ * \param[in] numBands SBR crossover band index
+ * \param[in,out] b input: vector b, output: solution vector p.
+ * \param[in,out] b_sf input: exponent of b; output: exponent of solution
+ * p.
+ */
+static void choleskySolve(const int numBands, FIXP_DBL *RESTRICT b,
+ int *RESTRICT b_sf) {
+ int i, e;
+
+ const FIXP_CHB *RESTRICT pBmul0 = bsd[numBands - BSD_IDX_OFFSET].Bmul0;
+ const SCHAR *RESTRICT pBmul0_sf = bsd[numBands - BSD_IDX_OFFSET].Bmul0_sf;
+ const FIXP_CHB *RESTRICT pBmul1 = bsd[numBands - BSD_IDX_OFFSET].Bmul1;
+ const SCHAR *RESTRICT pBmul1_sf = bsd[numBands - BSD_IDX_OFFSET].Bmul1_sf;
+
+ /* normalize b */
+ FIXP_DBL bnormed[POLY_ORDER + 1];
+ for (i = 0; i <= POLY_ORDER; ++i) {
+ bnormed[i] = fMultNorm(b[i], FX_CHB2FX_DBL(pBmul0[i]), &e);
+ b_sf[i] += pBmul0_sf[i] + e;
+ }
+
+ backsubst_fw(numBands, bnormed, b, b_sf);
+
+ /* normalize b again */
+ for (i = 0; i <= POLY_ORDER; ++i) {
+ bnormed[i] = fMultNorm(b[i], FX_CHB2FX_DBL(pBmul1[i]), &e);
+ b_sf[i] += pBmul1_sf[i] + e;
+ }
+
+ backsubst_bw(numBands, bnormed, b, b_sf);
+}
+
+/**
+ * \brief Find polynomial approximation of vector y with implicit abscisas
+ * x=0,1,2,3..n-1
+ *
+ * The problem (V^T * V * p = V^T * y) is solved with Cholesky.
+ * V is the Vandermode Matrix constructed with x = 0...n-1;
+ * A = V^T * V; b = V^T * y;
+ *
+ * \param[in] numBands SBR crossover band index (BSD_IDX_OFFSET <= numBands <=
+ * MAXLOWBANDS)
+ * \param[in] y input vector (mantissa)
+ * \param[in] y_sf exponents of y[]
+ * \param[out] p output polynomial coefficients (mantissa)
+ * \param[out] p_sf exponents of p[]
+ */
+static void polyfit(const int numBands, const FIXP_DBL *const y, const int y_sf,
+ FIXP_DBL *RESTRICT p, int *RESTRICT p_sf) {
+ int i, k;
+ LONG v[POLY_ORDER + 1];
+ int sum_saftey = getLog2[numBands - 1];
+
+ FDK_ASSERT((numBands >= BSD_IDX_OFFSET) && (numBands <= MAXLOWBANDS));
+
+ /* construct vector b[] temporarily stored in array p[] */
+ FDKmemclear(p, (POLY_ORDER + 1) * sizeof(FIXP_DBL));
+
+ /* p[] are the sums over n values and each p[i] has its own sf */
+ for (i = 0; i <= POLY_ORDER; ++i) p_sf[i] = 1 - DFRACT_BITS;
+
+ for (k = 0; k < numBands; k++) {
+ v[0] = (LONG)1;
+ for (i = 1; i <= POLY_ORDER; i++) {
+ v[i] = k * v[i - 1];
+ }
+
+ for (i = 0; i <= POLY_ORDER; i++) {
+ if (v[POLY_ORDER - i] != 0 && y[k] != FIXP_DBL(0)) {
+ int e;
+ FIXP_DBL mult = fMultNorm((FIXP_DBL)v[POLY_ORDER - i], y[k], &e);
+ int sf = DFRACT_BITS - 1 + y_sf + e;
+
+ /* check if the new summand has a different sf than the sum p[i]
+ * currently has */
+ int diff = sf - p_sf[i];
+
+ if (diff > 0) {
+ /* yes, and it requires the sum p[i] to be adjusted (scaled down) */
+ p[i] >>= fMin(DFRACT_BITS - 1, diff);
+ p_sf[i] = sf;
+ } else if (diff < 0) {
+ /* yes, but here mult needs to be scaled down */
+ mult >>= -diff;
+ }
+
+ /* mult has now the same sf than what it is about to be added to.
+ scale mult down additionally so that building the sum is
+ overflow-safe. */
+ p[i] += mult >> sum_saftey;
+ }
+ }
+ }
+
+ p_sf[0] += sum_saftey;
+ p_sf[1] += sum_saftey;
+ p_sf[2] += sum_saftey;
+ p_sf[3] += sum_saftey;
+
+ choleskySolve(numBands, p, p_sf);
+}
+
+/**
+ * \brief Calculates the output of a POLY_ORDER-degree polynomial function
+ * with Horner scheme:
+ *
+ * y(x) = p3 + p2*x + p1*x^2 + p0*x^3
+ * = p3 + x*(p2 + x*(p1 + x*p0))
+ *
+ * The for loop iterates through the mult/add parts in y(x) as above,
+ * during which regular upscaling ensures a stable exponent of the
+ * result.
+ *
+ * \param[in] p coefficients as in y(x)
+ * \param[in] p_sf exponents of p[]
+ * \param[in] x_int non-fractional integer representation of x as in y(x)
+ * \param[out] out_sf exponent of return value
+ *
+ * \return result y(x)
+ */
+static FIXP_DBL polyval(const FIXP_DBL *const p, const int *const p_sf,
+ const int x_int, int *out_sf) {
+ FDK_ASSERT(x_int <= 31); /* otherwise getLog2[] needs more elements */
+
+ int k, x_sf;
+ int result_sf; /* working space to compute return value *out_sf */
+ FIXP_DBL x; /* fractional value of x_int */
+ FIXP_DBL result; /* return value */
+
+ /* if x == 0, then y(x) is just p3 */
+ if (x_int != 0) {
+ x_sf = getLog2[x_int];
+ x = (FIXP_DBL)x_int << (DFRACT_BITS - 1 - x_sf);
+ } else {
+ *out_sf = p_sf[3];
+ return p[3];
+ }
+
+ result = p[0];
+ result_sf = p_sf[0];
+
+ for (k = 1; k <= POLY_ORDER; ++k) {
+ FIXP_DBL mult = fMult(x, result);
+ int mult_sf = x_sf + result_sf;
+
+ int room = CountLeadingBits(mult);
+ mult <<= room;
+ mult_sf -= room;
+
+ FIXP_DBL pp = p[k];
+ int pp_sf = p_sf[k];
+
+ /* equalize the shift factors of pp and mult so that we can sum them up */
+ int diff = pp_sf - mult_sf;
+
+ if (diff > 0) {
+ diff = fMin(diff, DFRACT_BITS - 1);
+ mult >>= diff;
+ } else if (diff < 0) {
+ diff = fMax(diff, 1 - DFRACT_BITS);
+ pp >>= -diff;
+ }
+
+ /* downshift by 1 to ensure safe summation */
+ mult >>= 1;
+ mult_sf++;
+ pp >>= 1;
+ pp_sf++;
+
+ result_sf = fMax(pp_sf, mult_sf);
+
+ result = mult + pp;
+ /* rarely, mult and pp happen to be almost equal except their sign,
+ and then upon summation, result becomes so small, that it is within
+ the inaccuracy range of a few bits, and then the relative error
+ produced by this function may become HUGE */
+ }
+
+ *out_sf = result_sf;
+ return result;
+}
+
+void sbrDecoder_calculateGainVec(FIXP_DBL **sourceBufferReal,
+ FIXP_DBL **sourceBufferImag,
+ int sourceBuf_e_overlap,
+ int sourceBuf_e_current, int overlap,
+ FIXP_DBL *RESTRICT GainVec, int *GainVec_exp,
+ int numBands, const int startSample,
+ const int stopSample) {
+ FIXP_DBL p[POLY_ORDER + 1];
+ FIXP_DBL meanNrg;
+ FIXP_DBL LowEnv[MAXLOWBANDS];
+ FIXP_DBL invNumBands = GetInvInt(numBands);
+ FIXP_DBL invNumSlots = GetInvInt(stopSample - startSample);
+ int i, loBand, exp, scale_nrg, scale_nrg_ov;
+ int sum_scale = 5, sum_scale_ov = 3;
+
+ if (overlap > 8) {
+ FDK_ASSERT(overlap <= 16);
+ sum_scale_ov += 1;
+ sum_scale += 1;
+ }
+
+ /* exponents of energy values */
+ sourceBuf_e_overlap = sourceBuf_e_overlap * 2 + sum_scale_ov;
+ sourceBuf_e_current = sourceBuf_e_current * 2 + sum_scale;
+ exp = fMax(sourceBuf_e_overlap, sourceBuf_e_current);
+ scale_nrg = sourceBuf_e_current - exp;
+ scale_nrg_ov = sourceBuf_e_overlap - exp;
+
+ meanNrg = (FIXP_DBL)0;
+ /* Calculate the spectral envelope in dB over the current copy-up frame. */
+ for (loBand = 0; loBand < numBands; loBand++) {
+ FIXP_DBL nrg_ov, nrg;
+ INT reserve = 0, exp_new;
+ FIXP_DBL maxVal = FL2FX_DBL(0.0f);
+
+ for (i = startSample; i < stopSample; i++) {
+ maxVal |=
+ (FIXP_DBL)((LONG)(sourceBufferReal[i][loBand]) ^
+ ((LONG)sourceBufferReal[i][loBand] >> (SAMPLE_BITS - 1)));
+ maxVal |=
+ (FIXP_DBL)((LONG)(sourceBufferImag[i][loBand]) ^
+ ((LONG)sourceBufferImag[i][loBand] >> (SAMPLE_BITS - 1)));
+ }
+
+ if (maxVal != FL2FX_DBL(0.0f)) {
+ reserve = fixMax(0, CntLeadingZeros(maxVal) - 2);
+ }
+
+ nrg_ov = nrg = (FIXP_DBL)0;
+ if (scale_nrg_ov > -31) {
+ for (i = startSample; i < overlap; i++) {
+ nrg_ov += (fPow2Div2(sourceBufferReal[i][loBand] << reserve) +
+ fPow2Div2(sourceBufferImag[i][loBand] << reserve)) >>
+ sum_scale_ov;
+ }
+ } else {
+ scale_nrg_ov = 0;
+ }
+ if (scale_nrg > -31) {
+ for (i = overlap; i < stopSample; i++) {
+ nrg += (fPow2Div2(sourceBufferReal[i][loBand] << reserve) +
+ fPow2Div2(sourceBufferImag[i][loBand] << reserve)) >>
+ sum_scale;
+ }
+ } else {
+ scale_nrg = 0;
+ }
+
+ nrg = (scaleValue(nrg_ov, scale_nrg_ov) >> 1) +
+ (scaleValue(nrg, scale_nrg) >> 1);
+ nrg = fMult(nrg, invNumSlots);
+
+ exp_new =
+ exp - (2 * reserve) +
+ 2; /* +1 for addition directly above, +1 for fPow2Div2 in loops above */
+
+ /* LowEnv = 10*log10(nrg) = log2(nrg) * 10/log2(10) */
+ /* exponent of logarithmic energy is 8 */
+ if (nrg > (FIXP_DBL)0) {
+ int exp_log2;
+ nrg = CalcLog2(nrg, exp_new, &exp_log2);
+ nrg = scaleValue(nrg, exp_log2 - 6);
+ nrg = fMult(FL2FXCONST_SGL(LOG10FAC), nrg);
+ } else {
+ nrg = (FIXP_DBL)0;
+ }
+ LowEnv[loBand] = nrg;
+ meanNrg += fMult(nrg, invNumBands);
+ }
+ exp = 6 + 2; /* exponent of LowEnv: +2 is exponent of LOG10FAC */
+
+ /* subtract mean before polynomial approximation to reduce dynamic of p[] */
+ for (loBand = 0; loBand < numBands; loBand++) {
+ LowEnv[loBand] = meanNrg - LowEnv[loBand];
+ }
+
+ /* For numBands < BSD_IDX_OFFSET (== POLY_ORDER+2) we dont get an
+ overdetermined equation system. The calculated polynomial will exactly fit
+ the input data and evaluating the polynomial will lead to the same vector
+ than the original input vector: lowEnvSlope[] == lowEnv[]
+ */
+ if (numBands > POLY_ORDER + 1) {
+ /* Find polynomial approximation of LowEnv */
+ int p_sf[POLY_ORDER + 1];
+
+ polyfit(numBands, LowEnv, exp, p, p_sf);
+
+ for (i = 0; i < numBands; i++) {
+ int sf;
+
+ /* lowBandEnvSlope[i] = tmp; */
+ FIXP_DBL tmp = polyval(p, p_sf, i, &sf);
+
+ /* GainVec = 10^((mean(y)-y)/20) = 2^( (mean(y)-y) * log2(10)/20 ) */
+ tmp = fMult(tmp, FL2FXCONST_SGL(LOG10FAC_INV));
+ GainVec[i] = f2Pow(tmp, sf - 2,
+ &GainVec_exp[i]); /* -2 is exponent of LOG10FAC_INV */
+ }
+ } else { /* numBands <= POLY_ORDER+1 */
+ for (i = 0; i < numBands; i++) {
+ int sf = exp; /* exponent of LowEnv[] */
+
+ /* lowBandEnvSlope[i] = LowEnv[i]; */
+ FIXP_DBL tmp = LowEnv[i];
+
+ /* GainVec = 10^((mean(y)-y)/20) = 2^( (mean(y)-y) * log2(10)/20 ) */
+ tmp = fMult(tmp, FL2FXCONST_SGL(LOG10FAC_INV));
+ GainVec[i] = f2Pow(tmp, sf - 2,
+ &GainVec_exp[i]); /* -2 is exponent of LOG10FAC_INV */
+ }
+ }
+}
diff --git a/fdk-aac/libSBRdec/src/HFgen_preFlat.h b/fdk-aac/libSBRdec/src/HFgen_preFlat.h
new file mode 100644
index 0000000..c1fc49d
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/HFgen_preFlat.h
@@ -0,0 +1,132 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s): Manuel Jander, Matthias Hildenbrand
+
+ Description: QMF frequency pre whitening for SBR
+
+*******************************************************************************/
+
+#include "common_fix.h"
+
+#ifndef HFGEN_PREFLAT_H
+#define HFGEN_PREFLAT_H
+
+#define GAIN_VEC_EXP 6 /* exponent of GainVec[] */
+
+/**
+ * \brief Find gain vector to flatten the QMF frequency bands whithout loosing
+ * the fine structure.
+ * \param[in] sourceBufferReal real part of QMF domain data.
+ * \param[in] sourceBufferImag imaginary part of QMF domain data.
+ * \param[in] sourceBuffer_e_overlap exponent of sourceBufferReal.
+ * \param[in] sourceBuffer_e_current exponent of sourceBufferImag.
+ * \param[in] overlap number of overlap samples.
+ * \param[out] GainVec array of gain values (one for each QMF band).
+ * \param[out] GainVec_exp exponents of GainVec (one for each QMF band).
+ * \param[in] numBands number of low bands (k_0).
+ * \param[in] startSample time slot start.
+ * \param[in] stopSample time slot stop.
+ */
+void sbrDecoder_calculateGainVec(FIXP_DBL **sourceBufferReal,
+ FIXP_DBL **sourceBufferImag,
+ int sourceBuffer_e_overlap,
+ int sourceBuffer_e_current, int overlap,
+ FIXP_DBL GainVec[], int GainVec_exp[],
+ const int numBands, const int startSample,
+ const int stopSample);
+
+#endif /* __HFGEN_PREFLAT_H */
diff --git a/fdk-aac/libSBRdec/src/arm/lpp_tran_arm.cpp b/fdk-aac/libSBRdec/src/arm/lpp_tran_arm.cpp
new file mode 100644
index 0000000..db1948f
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/arm/lpp_tran_arm.cpp
@@ -0,0 +1,159 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s): Arthur Tritthart
+
+ Description: (ARM optimised) LPP transposer subroutines
+
+*******************************************************************************/
+
+#if defined(__arm__)
+
+#define FUNCTION_LPPTRANSPOSER_func1
+
+#ifdef FUNCTION_LPPTRANSPOSER_func1
+
+/* Note: This code requires only 43 cycles per iteration instead of 61 on
+ * ARM926EJ-S */
+static void lppTransposer_func1(FIXP_DBL *lowBandReal, FIXP_DBL *lowBandImag,
+ FIXP_DBL **qmfBufferReal,
+ FIXP_DBL **qmfBufferImag, int loops, int hiBand,
+ int dynamicScale, int descale, FIXP_SGL a0r,
+ FIXP_SGL a0i, FIXP_SGL a1r, FIXP_SGL a1i,
+ const int fPreWhitening,
+ FIXP_DBL preWhiteningGain,
+ int preWhiteningGains_sf) {
+ FIXP_DBL real1, real2, imag1, imag2, accu1, accu2;
+
+ real2 = lowBandReal[-2];
+ real1 = lowBandReal[-1];
+ imag2 = lowBandImag[-2];
+ imag1 = lowBandImag[-1];
+ for (int i = 0; i < loops; i++) {
+ accu1 = fMultDiv2(a0r, real1);
+ accu2 = fMultDiv2(a0i, imag1);
+ accu1 = fMultAddDiv2(accu1, a1r, real2);
+ accu2 = fMultAddDiv2(accu2, a1i, imag2);
+ real2 = fMultDiv2(a1i, real2);
+ accu1 = accu1 - accu2;
+ accu1 = accu1 >> dynamicScale;
+
+ accu2 = fMultAddDiv2(real2, a1r, imag2);
+ real2 = real1;
+ imag2 = imag1;
+ accu2 = fMultAddDiv2(accu2, a0i, real1);
+ real1 = lowBandReal[i];
+ accu2 = fMultAddDiv2(accu2, a0r, imag1);
+ imag1 = lowBandImag[i];
+ accu2 = accu2 >> dynamicScale;
+
+ accu1 <<= 1;
+ accu2 <<= 1;
+ accu1 += (real1 >> descale);
+ accu2 += (imag1 >> descale);
+ if (fPreWhitening) {
+ accu1 = scaleValueSaturate(fMultDiv2(accu1, preWhiteningGain),
+ preWhiteningGains_sf);
+ accu2 = scaleValueSaturate(fMultDiv2(accu2, preWhiteningGain),
+ preWhiteningGains_sf);
+ }
+ qmfBufferReal[i][hiBand] = accu1;
+ qmfBufferImag[i][hiBand] = accu2;
+ }
+}
+#endif /* #ifdef FUNCTION_LPPTRANSPOSER_func1 */
+
+#endif /* __arm__ */
diff --git a/fdk-aac/libSBRdec/src/env_calc.cpp b/fdk-aac/libSBRdec/src/env_calc.cpp
new file mode 100644
index 0000000..cb1474f
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/env_calc.cpp
@@ -0,0 +1,3158 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Envelope calculation
+
+ The envelope adjustor compares the energies present in the transposed
+ highband to the reference energies conveyed with the bitstream.
+ The highband is amplified (sometimes) or attenuated (mostly) to the
+ desired level.
+
+ The spectral shape of the reference energies can be changed several times per
+ frame if necessary. Each set of energy values corresponding to a certain range
+ in time will be called an <em>envelope</em> here.
+ The bitstream supports several frequency scales and two resolutions. Normally,
+ one or more QMF-subbands are grouped to one SBR-band. An envelope contains
+ reference energies for each SBR-band.
+ In addition to the energy envelopes, noise envelopes are transmitted that
+ define the ratio of energy which is generated by adding noise instead of
+ transposing the lowband. The noise envelopes are given in a coarser time
+ and frequency resolution.
+ If a signal contains strong tonal components, synthetic sines can be
+ generated in individual SBR bands.
+
+ An overlap buffer of 6 QMF-timeslots is used to allow a more
+ flexible alignment of the envelopes in time that is not restricted to the
+ core codec's frame borders.
+ Therefore the envelope adjustor has access to the spectral data of the
+ current frame as well as the last 6 QMF-timeslots of the previous frame.
+ However, in average only the data of 1 frame is being processed as
+ the adjustor is called once per frame.
+
+ Depending on the frequency range set in the bitstream, only QMF-subbands
+ between <em>lowSubband</em> and <em>highSubband</em> are adjusted.
+
+ Scaling of spectral data to maximize SNR (see #QMF_SCALE_FACTOR) as well as a
+ special Mantissa-Exponent format ( see calculateSbrEnvelope() ) are being
+ used. The main entry point for this modules is calculateSbrEnvelope().
+
+ \sa sbr_scale.h, #QMF_SCALE_FACTOR, calculateSbrEnvelope(), \ref
+ documentationOverview
+*/
+
+#include "env_calc.h"
+
+#include "sbrdec_freq_sca.h"
+#include "env_extr.h"
+#include "transcendent.h"
+#include "sbr_ram.h"
+#include "sbr_rom.h"
+
+#include "genericStds.h" /* need FDKpow() for debug outputs */
+
+typedef struct {
+ FIXP_DBL nrgRef[MAX_FREQ_COEFFS];
+ FIXP_DBL nrgEst[MAX_FREQ_COEFFS];
+ FIXP_DBL nrgGain[MAX_FREQ_COEFFS];
+ FIXP_DBL noiseLevel[MAX_FREQ_COEFFS];
+ FIXP_DBL nrgSine[MAX_FREQ_COEFFS];
+
+ SCHAR nrgRef_e[MAX_FREQ_COEFFS];
+ SCHAR nrgEst_e[MAX_FREQ_COEFFS];
+ SCHAR nrgGain_e[MAX_FREQ_COEFFS];
+ SCHAR noiseLevel_e[MAX_FREQ_COEFFS];
+ SCHAR nrgSine_e[MAX_FREQ_COEFFS];
+ /* yet another exponent [0]: for ts < no_cols; [1]: for ts >= no_cols */
+ SCHAR exponent[2];
+} ENV_CALC_NRGS;
+
+static void equalizeFiltBufferExp(FIXP_DBL *filtBuffer, SCHAR *filtBuffer_e,
+ FIXP_DBL *NrgGain, SCHAR *NrgGain_e,
+ int subbands);
+
+static void calcNrgPerSubband(FIXP_DBL **analysBufferReal,
+ FIXP_DBL **analysBufferImag, int lowSubband,
+ int highSubband, int start_pos, int next_pos,
+ SCHAR frameExp, FIXP_DBL *nrgEst,
+ SCHAR *nrgEst_e);
+
+static void calcNrgPerSfb(FIXP_DBL **analysBufferReal,
+ FIXP_DBL **analysBufferImag, int nSfb,
+ UCHAR *freqBandTable, int start_pos, int next_pos,
+ SCHAR input_e, FIXP_DBL *nrg_est, SCHAR *nrg_est_e);
+
+static void calcSubbandGain(FIXP_DBL nrgRef, SCHAR nrgRef_e,
+ ENV_CALC_NRGS *nrgs, int c, FIXP_DBL tmpNoise,
+ SCHAR tmpNoise_e, UCHAR sinePresentFlag,
+ UCHAR sineMapped, int noNoiseFlag);
+
+static void calcAvgGain(ENV_CALC_NRGS *nrgs, int lowSubband, int highSubband,
+ FIXP_DBL *sumRef_m, SCHAR *sumRef_e,
+ FIXP_DBL *ptrAvgGain_m, SCHAR *ptrAvgGain_e);
+
+static void adjustTimeSlot_EldGrid(FIXP_DBL *ptrReal, ENV_CALC_NRGS *nrgs,
+ UCHAR *ptrHarmIndex, int lowSubbands,
+ int noSubbands, int scale_change,
+ int noNoiseFlag, int *ptrPhaseIndex,
+ int scale_diff_low);
+
+static void adjustTimeSlotLC(FIXP_DBL *ptrReal, ENV_CALC_NRGS *nrgs,
+ UCHAR *ptrHarmIndex, int lowSubbands,
+ int noSubbands, int scale_change, int noNoiseFlag,
+ int *ptrPhaseIndex);
+
+/**
+ * \brief Variant of adjustTimeSlotHQ() which only regards gain and noise but no
+ * additional harmonics
+ */
+static void adjustTimeSlotHQ_GainAndNoise(
+ FIXP_DBL *ptrReal, FIXP_DBL *ptrImag,
+ HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
+ int lowSubbands, int noSubbands, int scale_change, FIXP_SGL smooth_ratio,
+ int noNoiseFlag, int filtBufferNoiseShift);
+/**
+ * \brief Variant of adjustTimeSlotHQ() which only adds the additional harmonics
+ */
+static void adjustTimeSlotHQ_AddHarmonics(
+ FIXP_DBL *ptrReal, FIXP_DBL *ptrImag,
+ HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
+ int lowSubbands, int noSubbands, int scale_change);
+
+static void adjustTimeSlotHQ(FIXP_DBL *ptrReal, FIXP_DBL *ptrImag,
+ HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env,
+ ENV_CALC_NRGS *nrgs, int lowSubbands,
+ int noSubbands, int scale_change,
+ FIXP_SGL smooth_ratio, int noNoiseFlag,
+ int filtBufferNoiseShift);
+
+/*!
+ \brief Map sine flags from bitstream to QMF bands
+
+ The bitstream carries only 1 sine flag per band (Sfb) and frame.
+ This function maps every sine flag from the bitstream to a specific QMF
+ subband and to a specific envelope where the sine shall start. The result is
+ stored in the vector sineMapped which contains one entry per QMF subband. The
+ value of an entry specifies the envelope where a sine shall start. A value of
+ 32 indicates that no sine is present in the subband. The missing harmonics
+ flags from the previous frame (harmFlagsPrev) determine if a sine starts at
+ the beginning of the frame or at the transient position. Additionally, the
+ flags in harmFlagsPrev are being updated by this function for the next frame.
+*/
+static void mapSineFlags(
+ UCHAR *freqBandTable, /*!< Band borders (there's only 1 flag per band) */
+ int nSfb, /*!< Number of bands in the table */
+ ULONG *addHarmonics, /*!< Packed addHarmonics of current frame (aligned to
+ the MSB) */
+ ULONG *harmFlagsPrev, /*!< Packed addHarmonics of previous frame (aligned to
+ the LSB) */
+ ULONG *harmFlagsPrevActive, /*!< Packed sineMapped of previous frame
+ (aligned to the LSB) */
+ int tranEnv, /*!< Transient position */
+ SCHAR *sineMapped) /*!< Resulting vector of sine start positions for each
+ QMF band */
+
+{
+ int i;
+ int bitcount = 31;
+ ULONG harmFlagsQmfBands[ADD_HARMONICS_FLAGS_SIZE] = {0};
+ ULONG *curFlags = addHarmonics;
+
+ /*
+ Format of addHarmonics (aligned to MSB):
+
+ Up to MAX_FREQ_COEFFS sfb bands can be flagged for a sign.
+ first word = flags for lowest 32 sfb bands in use
+ second word = flags for higest 32 sfb bands (if present)
+
+ Format of harmFlagsPrev (aligned to LSB):
+
+ Index is absolute (not relative to lsb) so it is correct even if lsb
+ changes first word = flags for lowest 32 qmf bands (0...31) second word =
+ flags for next higher 32 qmf bands (32...63)
+
+ */
+
+ /* Reset the output vector first */
+ FDKmemset(sineMapped, 32,
+ MAX_FREQ_COEFFS * sizeof(SCHAR)); /* 32 means 'no sine' */
+ FDKmemclear(harmFlagsPrevActive, ADD_HARMONICS_FLAGS_SIZE * sizeof(ULONG));
+ for (i = 0; i < nSfb; i++) {
+ ULONG maskSfb =
+ 1 << bitcount; /* mask to extract addHarmonics flag of current Sfb */
+
+ if (*curFlags & maskSfb) { /* There is a sine in this band */
+ const int lsb = freqBandTable[0]; /* start of sbr range */
+ /* qmf band to which sine should be added */
+ const int qmfBand = (freqBandTable[i] + freqBandTable[i + 1]) >> 1;
+ const int qmfBandDiv32 = qmfBand >> 5;
+ const int maskQmfBand =
+ 1 << (qmfBand &
+ 31); /* mask to extract harmonic flag from prevFlags */
+
+ /* mapping of sfb with sine to a certain qmf band -> for harmFlagsPrev */
+ harmFlagsQmfBands[qmfBandDiv32] |= maskQmfBand;
+
+ /*
+ If there was a sine in the last frame, let it continue from the first
+ envelope on else start at the transient position. Indexing of sineMapped
+ starts relative to lsb.
+ */
+ sineMapped[qmfBand - lsb] =
+ (harmFlagsPrev[qmfBandDiv32] & maskQmfBand) ? 0 : tranEnv;
+ if (sineMapped[qmfBand - lsb] < PVC_NTIMESLOT) {
+ harmFlagsPrevActive[qmfBandDiv32] |= maskQmfBand;
+ }
+ }
+
+ if (bitcount-- == 0) {
+ bitcount = 31;
+ curFlags++;
+ }
+ }
+ FDKmemcpy(harmFlagsPrev, harmFlagsQmfBands,
+ sizeof(ULONG) * ADD_HARMONICS_FLAGS_SIZE);
+}
+
+/*!
+ \brief Restore sineMapped of previous frame
+
+ For PVC it might happen that the PVC framing (always 0) is out of sync with
+ the SBR framing. The adding of additional harmonics is done based on the SBR
+ framing. If the SBR framing is trailing the PVC framing the sine mapping of
+ the previous SBR frame needs to be used for the overlapping time slots.
+*/
+/*static*/ void mapSineFlagsPvc(
+ UCHAR *freqBandTable, /*!< Band borders (there's only 1 flag per
+ band) */
+ int nSfb, /*!< Number of bands in the table */
+ ULONG *harmFlagsPrev, /*!< Packed addHarmonics of previous frame
+ (aligned to the MSB) */
+ ULONG *harmFlagsPrevActive, /*!< Packed sineMapped of previous
+ frame (aligned to the LSB) */
+ SCHAR *sineMapped, /*!< Resulting vector of sine start positions
+ for each QMF band */
+ int sinusoidalPos, /*!< sinusoidal position */
+ SCHAR *sinusoidalPosPrev, /*!< sinusoidal position of previous
+ frame */
+ int trailingSbrFrame) /*!< indication if the SBR framing is
+ trailing the PVC framing */
+{
+ /* Reset the output vector first */
+ FDKmemset(sineMapped, 32, MAX_FREQ_COEFFS); /* 32 means 'no sine' */
+
+ if (trailingSbrFrame) {
+ /* restore sineMapped[] of previous frame */
+ int i;
+ const int lsb = freqBandTable[0];
+ const int usb = freqBandTable[nSfb];
+ for (i = lsb; i < usb; i++) {
+ const int qmfBandDiv32 = i >> 5;
+ const int maskQmfBand =
+ 1 << (i & 31); /* mask to extract harmonic flag from prevFlags */
+
+ /* Two cases need to be distinguished ... */
+ if (harmFlagsPrevActive[qmfBandDiv32] & maskQmfBand) {
+ /* the sine mapping already started last PVC frame -> seamlessly
+ * continue */
+ sineMapped[i - lsb] = 0;
+ } else if (harmFlagsPrev[qmfBandDiv32] & maskQmfBand) {
+ /* sinusoidalPos of prev PVC frame was >= PVC_NTIMESLOT -> sine starts
+ * in this frame */
+ sineMapped[i - lsb] =
+ *sinusoidalPosPrev - PVC_NTIMESLOT; /* we are 16 sbr time slots
+ ahead of last frame now */
+ }
+ }
+ }
+ *sinusoidalPosPrev = sinusoidalPos;
+}
+
+/*!
+ \brief Reduce gain-adjustment induced aliasing for real valued filterbank.
+*/
+/*static*/ void aliasingReduction(
+ FIXP_DBL *degreeAlias, /*!< estimated aliasing for each QMF
+ channel */
+ ENV_CALC_NRGS *nrgs,
+ UCHAR *useAliasReduction, /*!< synthetic sine energy for each
+ subband, used as flag */
+ int noSubbands) /*!< number of QMF channels to process */
+{
+ FIXP_DBL *nrgGain = nrgs->nrgGain; /*!< subband gains to be modified */
+ SCHAR *nrgGain_e =
+ nrgs->nrgGain_e; /*!< subband gains to be modified (exponents) */
+ FIXP_DBL *nrgEst = nrgs->nrgEst; /*!< subband energy before amplification */
+ SCHAR *nrgEst_e =
+ nrgs->nrgEst_e; /*!< subband energy before amplification (exponents) */
+ int grouping = 0, index = 0, noGroups, k;
+ int groupVector[MAX_FREQ_COEFFS];
+
+ /* Calculate grouping*/
+ for (k = 0; k < noSubbands - 1; k++) {
+ if ((degreeAlias[k + 1] != FL2FXCONST_DBL(0.0f)) && useAliasReduction[k]) {
+ if (grouping == 0) {
+ groupVector[index++] = k;
+ grouping = 1;
+ } else {
+ if (groupVector[index - 1] + 3 == k) {
+ groupVector[index++] = k + 1;
+ grouping = 0;
+ }
+ }
+ } else {
+ if (grouping) {
+ if (useAliasReduction[k])
+ groupVector[index++] = k + 1;
+ else
+ groupVector[index++] = k;
+ grouping = 0;
+ }
+ }
+ }
+
+ if (grouping) {
+ groupVector[index++] = noSubbands;
+ }
+ noGroups = index >> 1;
+
+ /*Calculate new gain*/
+ for (int group = 0; group < noGroups; group++) {
+ FIXP_DBL nrgOrig = FL2FXCONST_DBL(
+ 0.0f); /* Original signal energy in current group of bands */
+ SCHAR nrgOrig_e = 0;
+ FIXP_DBL nrgAmp = FL2FXCONST_DBL(
+ 0.0f); /* Amplified signal energy in group (using current gains) */
+ SCHAR nrgAmp_e = 0;
+ FIXP_DBL nrgMod = FL2FXCONST_DBL(
+ 0.0f); /* Signal energy in group when applying modified gains */
+ SCHAR nrgMod_e = 0;
+ FIXP_DBL groupGain; /* Total energy gain in group */
+ SCHAR groupGain_e;
+ FIXP_DBL compensation; /* Compensation factor for the energy change when
+ applying modified gains */
+ SCHAR compensation_e;
+
+ int startGroup = groupVector[2 * group];
+ int stopGroup = groupVector[2 * group + 1];
+
+ /* Calculate total energy in group before and after amplification with
+ * current gains: */
+ for (k = startGroup; k < stopGroup; k++) {
+ /* Get original band energy */
+ FIXP_DBL tmp = nrgEst[k];
+ SCHAR tmp_e = nrgEst_e[k];
+
+ FDK_add_MantExp(tmp, tmp_e, nrgOrig, nrgOrig_e, &nrgOrig, &nrgOrig_e);
+
+ /* Multiply band energy with current gain */
+ tmp = fMult(tmp, nrgGain[k]);
+ tmp_e = tmp_e + nrgGain_e[k];
+
+ FDK_add_MantExp(tmp, tmp_e, nrgAmp, nrgAmp_e, &nrgAmp, &nrgAmp_e);
+ }
+
+ /* Calculate total energy gain in group */
+ FDK_divide_MantExp(nrgAmp, nrgAmp_e, nrgOrig, nrgOrig_e, &groupGain,
+ &groupGain_e);
+
+ for (k = startGroup; k < stopGroup; k++) {
+ FIXP_DBL tmp;
+ SCHAR tmp_e;
+
+ FIXP_DBL alpha = degreeAlias[k];
+ if (k < noSubbands - 1) {
+ if (degreeAlias[k + 1] > alpha) alpha = degreeAlias[k + 1];
+ }
+
+ /* Modify gain depending on the degree of aliasing */
+ FDK_add_MantExp(
+ fMult(alpha, groupGain), groupGain_e,
+ fMult(/*FL2FXCONST_DBL(1.0f)*/ (FIXP_DBL)MAXVAL_DBL - alpha,
+ nrgGain[k]),
+ nrgGain_e[k], &nrgGain[k], &nrgGain_e[k]);
+
+ /* Apply modified gain to original energy */
+ tmp = fMult(nrgGain[k], nrgEst[k]);
+ tmp_e = nrgGain_e[k] + nrgEst_e[k];
+
+ /* Accumulate energy with modified gains applied */
+ FDK_add_MantExp(tmp, tmp_e, nrgMod, nrgMod_e, &nrgMod, &nrgMod_e);
+ }
+
+ /* Calculate compensation factor to retain the energy of the amplified
+ * signal */
+ FDK_divide_MantExp(nrgAmp, nrgAmp_e, nrgMod, nrgMod_e, &compensation,
+ &compensation_e);
+
+ /* Apply compensation factor to all gains of the group */
+ for (k = startGroup; k < stopGroup; k++) {
+ nrgGain[k] = fMult(nrgGain[k], compensation);
+ nrgGain_e[k] = nrgGain_e[k] + compensation_e;
+ }
+ }
+}
+
+#define INTER_TES_SF_CHANGE 3
+
+typedef struct {
+ FIXP_DBL subsample_power_low[(((1024) / (32) * (4) / 2) + (3 * (4)))];
+ FIXP_DBL subsample_power_high[(((1024) / (32) * (4) / 2) + (3 * (4)))];
+ FIXP_DBL gain[(((1024) / (32) * (4) / 2) + (3 * (4)))];
+ SCHAR subsample_power_low_sf[(((1024) / (32) * (4) / 2) + (3 * (4)))];
+ SCHAR subsample_power_high_sf[(((1024) / (32) * (4) / 2) + (3 * (4)))];
+} ITES_TEMP;
+
+static void apply_inter_tes(FIXP_DBL **qmfReal, FIXP_DBL **qmfImag,
+ const QMF_SCALE_FACTOR *sbrScaleFactor,
+ const SCHAR exp[2], const int RATE,
+ const int startPos, const int stopPos,
+ const int lowSubband, const int nbSubband,
+ const UCHAR gamma_idx) {
+ int highSubband = lowSubband + nbSubband;
+ FIXP_DBL *subsample_power_high, *subsample_power_low;
+ SCHAR *subsample_power_high_sf, *subsample_power_low_sf;
+ FIXP_DBL total_power_high = (FIXP_DBL)0;
+ FIXP_DBL total_power_low = (FIXP_DBL)0;
+ FIXP_DBL *gain;
+ int gain_sf[(((1024) / (32) * (4) / 2) + (3 * (4)))];
+
+ /* gamma[gamma_idx] = {0.0f, 1.0f, 2.0f, 4.0f} */
+ int gamma_sf =
+ (int)gamma_idx - 1; /* perhaps +1 to save one bit? (0.99999f vs 1.f) */
+
+ int nbSubsample = stopPos - startPos;
+ int i, j;
+
+ C_ALLOC_SCRATCH_START(pTmp, ITES_TEMP, 1);
+ subsample_power_high = pTmp->subsample_power_high;
+ subsample_power_low = pTmp->subsample_power_low;
+ subsample_power_high_sf = pTmp->subsample_power_high_sf;
+ subsample_power_low_sf = pTmp->subsample_power_low_sf;
+ gain = pTmp->gain;
+
+ if (gamma_idx > 0) {
+ int preShift2 = 32 - fNormz((FIXP_DBL)nbSubsample);
+ int total_power_low_sf = 1 - DFRACT_BITS;
+ int total_power_high_sf = 1 - DFRACT_BITS;
+
+ for (i = 0; i < nbSubsample; ++i) {
+ FIXP_DBL bufferReal[(((1024) / (32) * (4) / 2) + (3 * (4)))];
+ FIXP_DBL bufferImag[(((1024) / (32) * (4) / 2) + (3 * (4)))];
+ FIXP_DBL maxVal = (FIXP_DBL)0;
+
+ int ts = startPos + i;
+
+ int low_sf = (ts < 3 * RATE) ? sbrScaleFactor->ov_lb_scale
+ : sbrScaleFactor->lb_scale;
+ low_sf = 15 - low_sf;
+
+ for (j = 0; j < lowSubband; ++j) {
+ bufferImag[j] = qmfImag[startPos + i][j];
+ maxVal |= (FIXP_DBL)((LONG)(bufferImag[j]) ^
+ ((LONG)bufferImag[j] >> (DFRACT_BITS - 1)));
+ bufferReal[j] = qmfReal[startPos + i][j];
+ maxVal |= (FIXP_DBL)((LONG)(bufferReal[j]) ^
+ ((LONG)bufferReal[j] >> (DFRACT_BITS - 1)));
+ }
+
+ subsample_power_low[i] = (FIXP_DBL)0;
+ subsample_power_low_sf[i] = 0;
+
+ if (maxVal != FL2FXCONST_DBL(0.f)) {
+ /* multiply first, then shift for safe summation */
+ int preShift = 1 - CntLeadingZeros(maxVal);
+ int postShift = 32 - fNormz((FIXP_DBL)lowSubband);
+
+ /* reduce preShift because otherwise we risk to square -1.f */
+ if (preShift != 0) preShift++;
+
+ subsample_power_low_sf[i] += (low_sf + preShift) * 2 + postShift + 1;
+
+ scaleValues(bufferReal, lowSubband, -preShift);
+ scaleValues(bufferImag, lowSubband, -preShift);
+ for (j = 0; j < lowSubband; ++j) {
+ FIXP_DBL addme;
+ addme = fPow2Div2(bufferReal[j]);
+ subsample_power_low[i] += addme >> postShift;
+ addme = fPow2Div2(bufferImag[j]);
+ subsample_power_low[i] += addme >> postShift;
+ }
+ }
+
+ /* now get high */
+
+ maxVal = (FIXP_DBL)0;
+
+ int high_sf = exp[(ts < 16 * RATE) ? 0 : 1];
+
+ for (j = lowSubband; j < highSubband; ++j) {
+ bufferImag[j] = qmfImag[startPos + i][j];
+ maxVal |= (FIXP_DBL)((LONG)(bufferImag[j]) ^
+ ((LONG)bufferImag[j] >> (DFRACT_BITS - 1)));
+ bufferReal[j] = qmfReal[startPos + i][j];
+ maxVal |= (FIXP_DBL)((LONG)(bufferReal[j]) ^
+ ((LONG)bufferReal[j] >> (DFRACT_BITS - 1)));
+ }
+
+ subsample_power_high[i] = (FIXP_DBL)0;
+ subsample_power_high_sf[i] = 0;
+
+ if (maxVal != FL2FXCONST_DBL(0.f)) {
+ int preShift = 1 - CntLeadingZeros(maxVal);
+ /* reduce preShift because otherwise we risk to square -1.f */
+ if (preShift != 0) preShift++;
+
+ int postShift = 32 - fNormz((FIXP_DBL)(highSubband - lowSubband));
+ subsample_power_high_sf[i] += (high_sf + preShift) * 2 + postShift + 1;
+
+ scaleValues(&bufferReal[lowSubband], highSubband - lowSubband,
+ -preShift);
+ scaleValues(&bufferImag[lowSubband], highSubband - lowSubband,
+ -preShift);
+ for (j = lowSubband; j < highSubband; j++) {
+ subsample_power_high[i] += fPow2Div2(bufferReal[j]) >> postShift;
+ subsample_power_high[i] += fPow2Div2(bufferImag[j]) >> postShift;
+ }
+ }
+
+ /* sum all together */
+ FIXP_DBL new_summand = subsample_power_low[i];
+ int new_summand_sf = subsample_power_low_sf[i];
+
+ /* make sure the current sum, and the new summand have the same SF */
+ if (new_summand_sf > total_power_low_sf) {
+ int diff = fMin(DFRACT_BITS - 1, new_summand_sf - total_power_low_sf);
+ total_power_low >>= diff;
+ total_power_low_sf = new_summand_sf;
+ } else if (new_summand_sf < total_power_low_sf) {
+ new_summand >>=
+ fMin(DFRACT_BITS - 1, total_power_low_sf - new_summand_sf);
+ }
+
+ total_power_low += (new_summand >> preShift2);
+
+ new_summand = subsample_power_high[i];
+ new_summand_sf = subsample_power_high_sf[i];
+ if (new_summand_sf > total_power_high_sf) {
+ total_power_high >>=
+ fMin(DFRACT_BITS - 1, new_summand_sf - total_power_high_sf);
+ total_power_high_sf = new_summand_sf;
+ } else if (new_summand_sf < total_power_high_sf) {
+ new_summand >>=
+ fMin(DFRACT_BITS - 1, total_power_high_sf - new_summand_sf);
+ }
+
+ total_power_high += (new_summand >> preShift2);
+ }
+
+ total_power_low_sf += preShift2;
+ total_power_high_sf += preShift2;
+
+ /* gain[i] = e_LOW[i] */
+ for (i = 0; i < nbSubsample; ++i) {
+ int sf2;
+ FIXP_DBL mult =
+ fMultNorm(subsample_power_low[i], (FIXP_DBL)nbSubsample, &sf2);
+ int mult_sf = subsample_power_low_sf[i] + DFRACT_BITS - 1 + sf2;
+
+ if (total_power_low != FIXP_DBL(0)) {
+ gain[i] = fDivNorm(mult, total_power_low, &sf2);
+ gain_sf[i] = mult_sf - total_power_low_sf + sf2;
+ gain[i] = sqrtFixp_lookup(gain[i], &gain_sf[i]);
+ if (gain_sf[i] < 0) {
+ gain[i] >>= -gain_sf[i];
+ gain_sf[i] = 0;
+ }
+ } else {
+ if (mult == FIXP_DBL(0)) {
+ gain[i] = FIXP_DBL(0);
+ gain_sf[i] = 0;
+ } else {
+ gain[i] = (FIXP_DBL)MAXVAL_DBL;
+ gain_sf[i] = 0;
+ }
+ }
+ }
+
+ FIXP_DBL total_power_high_after = (FIXP_DBL)0;
+ int total_power_high_after_sf = 1 - DFRACT_BITS;
+
+ /* gain[i] = g_inter[i] */
+ for (i = 0; i < nbSubsample; ++i) {
+ if (gain_sf[i] < 0) {
+ gain[i] >>= -gain_sf[i];
+ gain_sf[i] = 0;
+ }
+
+ /* calculate: gain[i] = 1.0f + gamma * (gain[i] - 1.0f); */
+ FIXP_DBL one = (FIXP_DBL)MAXVAL_DBL >>
+ gain_sf[i]; /* to substract this from gain[i] */
+
+ /* gamma is actually always 1 according to the table, so skip the
+ * fMultDiv2 */
+ FIXP_DBL mult = (gain[i] - one) >> 1;
+ int mult_sf = gain_sf[i] + gamma_sf;
+
+ one = FL2FXCONST_DBL(0.5f) >> mult_sf;
+ gain[i] = one + mult;
+ gain_sf[i] += gamma_sf + 1; /* +1 because of fMultDiv2() */
+
+ /* set gain to at least 0.2f */
+ FIXP_DBL point_two = FL2FXCONST_DBL(0.8f); /* scaled up by 2 */
+ int point_two_sf = -2;
+
+ FIXP_DBL tmp = gain[i];
+ if (point_two_sf < gain_sf[i]) {
+ point_two >>= gain_sf[i] - point_two_sf;
+ } else {
+ tmp >>= point_two_sf - gain_sf[i];
+ }
+
+ /* limit and calculate gain[i]^2 too */
+ FIXP_DBL gain_pow2;
+ int gain_pow2_sf;
+ if (tmp < point_two) {
+ gain[i] = FL2FXCONST_DBL(0.8f);
+ gain_sf[i] = -2;
+ gain_pow2 = FL2FXCONST_DBL(0.64f);
+ gain_pow2_sf = -4;
+ } else {
+ /* this upscaling seems quite important */
+ int r = CountLeadingBits(gain[i]);
+ gain[i] <<= r;
+ gain_sf[i] -= r;
+
+ gain_pow2 = fPow2(gain[i]);
+ gain_pow2_sf = gain_sf[i] << 1;
+ }
+
+ int room;
+ subsample_power_high[i] =
+ fMultNorm(subsample_power_high[i], gain_pow2, &room);
+ subsample_power_high_sf[i] =
+ subsample_power_high_sf[i] + gain_pow2_sf + room;
+
+ int new_summand_sf = subsample_power_high_sf[i]; /* + gain_pow2_sf; */
+ if (new_summand_sf > total_power_high_after_sf) {
+ total_power_high_after >>=
+ fMin(DFRACT_BITS - 1, new_summand_sf - total_power_high_after_sf);
+ total_power_high_after_sf = new_summand_sf;
+ } else if (new_summand_sf < total_power_high_after_sf) {
+ subsample_power_high[i] >>= total_power_high_after_sf - new_summand_sf;
+ }
+ total_power_high_after += subsample_power_high[i] >> preShift2;
+ }
+
+ total_power_high_after_sf += preShift2;
+
+ int sf2 = 0;
+ FIXP_DBL gain_adj_2 = FL2FX_DBL(0.5f);
+ int gain_adj_2_sf = 1;
+
+ if ((total_power_high != (FIXP_DBL)0) &&
+ (total_power_high_after != (FIXP_DBL)0)) {
+ gain_adj_2 = fDivNorm(total_power_high, total_power_high_after, &sf2);
+ gain_adj_2_sf = total_power_high_sf - total_power_high_after_sf + sf2;
+ }
+
+ FIXP_DBL gain_adj = sqrtFixp_lookup(gain_adj_2, &gain_adj_2_sf);
+ int gain_adj_sf = gain_adj_2_sf;
+
+ for (i = 0; i < nbSubsample; ++i) {
+ gain[i] = fMult(gain[i], gain_adj);
+ gain_sf[i] += gain_adj_sf;
+
+ /* limit gain */
+ if (gain_sf[i] > INTER_TES_SF_CHANGE) {
+ gain[i] = (FIXP_DBL)MAXVAL_DBL;
+ gain_sf[i] = INTER_TES_SF_CHANGE;
+ }
+ }
+
+ for (i = 0; i < nbSubsample; ++i) {
+ /* equalize gain[]'s scale factors */
+ gain[i] >>= INTER_TES_SF_CHANGE - gain_sf[i];
+
+ for (j = lowSubband; j < highSubband; j++) {
+ qmfReal[startPos + i][j] = fMult(qmfReal[startPos + i][j], gain[i]);
+ qmfImag[startPos + i][j] = fMult(qmfImag[startPos + i][j], gain[i]);
+ }
+ }
+ } else { /* gamma_idx == 0 */
+ /* Inter-TES is not active. Still perform the scale change to have a
+ * consistent scaling for all envelopes of this frame. */
+ for (i = 0; i < nbSubsample; ++i) {
+ for (j = lowSubband; j < highSubband; j++) {
+ qmfReal[startPos + i][j] >>= INTER_TES_SF_CHANGE;
+ qmfImag[startPos + i][j] >>= INTER_TES_SF_CHANGE;
+ }
+ }
+ }
+ C_ALLOC_SCRATCH_END(pTmp, ITES_TEMP, 1);
+}
+
+/*!
+ \brief Apply spectral envelope to subband samples
+
+ This function is called from sbr_dec.cpp in each frame.
+
+ To enhance accuracy and due to the usage of tables for squareroots and
+ inverse, some calculations are performed with the operands being split
+ into mantissa and exponent. The variable names in the source code carry
+ the suffixes <em>_m</em> and <em>_e</em> respectively. The control data
+ in #hFrameData containts envelope data which is represented by this format but
+ stored in single words. (See requantizeEnvelopeData() for details). This data
+ is unpacked within calculateSbrEnvelope() to follow the described suffix
+ convention.
+
+ The actual value (comparable to the corresponding float-variable in the
+ research-implementation) of a mantissa/exponent-pair can be calculated as
+
+ \f$ value = value\_m * 2^{value\_e} \f$
+
+ All energies and noise levels decoded from the bitstream suit for an
+ original signal magnitude of \f$\pm 32768 \f$ rather than \f$ \pm 1\f$.
+ Therefore, the scale factor <em>hb_scale</em> passed into this function will
+ be converted to an 'input exponent' (#input_e), which fits the internal
+ representation.
+
+ Before the actual processing, an exponent #adj_e for resulting adjusted
+ samples is derived from the maximum reference energy.
+
+ Then, for each envelope, the following steps are performed:
+
+ \li Calculate energy in the signal to be adjusted. Depending on the the value
+ of #interpolFreq (interpolation mode), this is either done seperately for each
+ QMF-subband or for each SBR-band. The resulting energies are stored in
+ #nrgEst_m[#MAX_FREQ_COEFFS] (mantissas) and #nrgEst_e[#MAX_FREQ_COEFFS]
+ (exponents). \li Calculate gain and noise level for each subband:<br> \f$ gain
+ = \sqrt{ \frac{nrgRef}{nrgEst} \cdot (1 - noiseRatio) } \hspace{2cm} noise =
+ \sqrt{ nrgRef \cdot noiseRatio } \f$<br> where <em>noiseRatio</em> and
+ <em>nrgRef</em> are extracted from the bitstream and <em>nrgEst</em> is the
+ subband energy before adjustment. The resulting gains are stored in
+ #nrgGain_m[#MAX_FREQ_COEFFS] (mantissas) and #nrgGain_e[#MAX_FREQ_COEFFS]
+ (exponents), the noise levels are stored in #noiseLevel_m[#MAX_FREQ_COEFFS]
+ and #noiseLevel_e[#MAX_FREQ_COEFFS] (exponents). The sine levels are stored in
+ #nrgSine_m[#MAX_FREQ_COEFFS] and #nrgSine_e[#MAX_FREQ_COEFFS]. \li Noise
+ limiting: The gain for each subband is limited both absolutely and relatively
+ compared to the total gain over all subbands. \li Boost gain: Calculate and
+ apply boost factor for each limiter band in order to compensate for the energy
+ loss imposed by the limiting. \li Apply gains and add noise: The gains and
+ noise levels are applied to all timeslots of the current envelope. A short
+ FIR-filter (length 4 QMF-timeslots) can be used to smooth the sudden change at
+ the envelope borders. Each complex subband sample of the current timeslot is
+ multiplied by the smoothed gain, then random noise with the calculated level
+ is added.
+
+ \note
+ To reduce the stack size, some of the local arrays could be located within
+ the time output buffer. Of the 512 samples temporarily available there,
+ about half the size is already used by #SBR_FRAME_DATA. A pointer to the
+ remaining free memory could be supplied by an additional argument to
+ calculateSbrEnvelope() in sbr_dec:
+
+ \par
+ \code
+ calculateSbrEnvelope (&hSbrDec->sbrScaleFactor,
+ &hSbrDec->SbrCalculateEnvelope,
+ hHeaderData,
+ hFrameData,
+ QmfBufferReal,
+ QmfBufferImag,
+ timeOutPtr + sizeof(SBR_FRAME_DATA)/sizeof(Float) +
+ 1); \endcode
+
+ \par
+ Within calculateSbrEnvelope(), some pointers could be defined instead of the
+ arrays #nrgRef_m, #nrgRef_e, #nrgEst_m, #nrgEst_e, #noiseLevel_m:
+
+ \par
+ \code
+ fract* nrgRef_m = timeOutPtr;
+ SCHAR* nrgRef_e = nrgRef_m + MAX_FREQ_COEFFS;
+ fract* nrgEst_m = nrgRef_e + MAX_FREQ_COEFFS;
+ SCHAR* nrgEst_e = nrgEst_m + MAX_FREQ_COEFFS;
+ fract* noiseLevel_m = nrgEst_e + MAX_FREQ_COEFFS;
+ \endcode
+
+ <br>
+*/
+void calculateSbrEnvelope(
+ QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */
+ HANDLE_SBR_CALCULATE_ENVELOPE
+ h_sbr_cal_env, /*!< Handle to struct filled by the create-function */
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */
+ PVC_DYNAMIC_DATA *pPvcDynamicData,
+ FIXP_DBL *
+ *analysBufferReal, /*!< Real part of subband samples to be processed */
+ FIXP_DBL *
+ *analysBufferImag, /*!< Imag part of subband samples to be processed */
+ const int useLP,
+ FIXP_DBL *degreeAlias, /*!< Estimated aliasing for each QMF channel */
+ const UINT flags, const int frameErrorFlag) {
+ int c, i, i_stop, j, envNoise = 0;
+ UCHAR *borders = hFrameData->frameInfo.borders;
+ UCHAR *bordersPvc = hFrameData->frameInfo.pvcBorders;
+ int pvc_mode = pPvcDynamicData->pvc_mode;
+ int first_start =
+ ((pvc_mode > 0) ? bordersPvc[0] : borders[0]) * hHeaderData->timeStep;
+ FIXP_SGL *noiseLevels = hFrameData->sbrNoiseFloorLevel;
+ HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData;
+ UCHAR **pFreqBandTable = hFreq->freqBandTable;
+ UCHAR *pFreqBandTableNoise = hFreq->freqBandTableNoise;
+
+ int lowSubband = hFreq->lowSubband;
+ int highSubband = hFreq->highSubband;
+ int noSubbands = highSubband - lowSubband;
+
+ /* old high subband before headerchange
+ we asume no headerchange here */
+ int ov_highSubband = hFreq->highSubband;
+
+ int noNoiseBands = hFreq->nNfb;
+ UCHAR *noSubFrameBands = hFreq->nSfb;
+ int no_cols = hHeaderData->numberTimeSlots * hHeaderData->timeStep;
+
+ SCHAR sineMapped[MAX_FREQ_COEFFS];
+ SCHAR ov_adj_e = SCALE2EXP(sbrScaleFactor->ov_hb_scale);
+ SCHAR adj_e = 0;
+ SCHAR output_e;
+ SCHAR final_e = 0;
+ /* inter-TES is active in one or more envelopes of the current SBR frame */
+ const int iTES_enable = hFrameData->iTESactive;
+ const int iTES_scale_change = (iTES_enable) ? INTER_TES_SF_CHANGE : 0;
+ SCHAR maxGainLimit_e = (frameErrorFlag) ? MAX_GAIN_CONCEAL_EXP : MAX_GAIN_EXP;
+
+ UCHAR smooth_length = 0;
+
+ FIXP_SGL *pIenv = hFrameData->iEnvelope;
+
+ C_ALLOC_SCRATCH_START(useAliasReduction, UCHAR, 64)
+
+ /* if values differ we had a headerchange; if old highband is bigger then new
+ one we need to patch overlap-highband-scaling for this frame (see use of
+ ov_highSubband) as overlap contains higher frequency components which would
+ get lost */
+ if (hFreq->highSubband < hFreq->ov_highSubband) {
+ ov_highSubband = hFreq->ov_highSubband;
+ }
+
+ if (pvc_mode > 0) {
+ if (hFrameData->frameInfo.bordersNoise[0] > bordersPvc[0]) {
+ /* noise envelope of previous frame is trailing into current PVC frame */
+ envNoise = -1;
+ noiseLevels = h_sbr_cal_env->prevSbrNoiseFloorLevel;
+ noNoiseBands = h_sbr_cal_env->prevNNfb;
+ noSubFrameBands = h_sbr_cal_env->prevNSfb;
+ lowSubband = h_sbr_cal_env->prevLoSubband;
+ highSubband = h_sbr_cal_env->prevHiSubband;
+
+ noSubbands = highSubband - lowSubband;
+ ov_highSubband = highSubband;
+ if (highSubband < h_sbr_cal_env->prev_ov_highSubband) {
+ ov_highSubband = h_sbr_cal_env->prev_ov_highSubband;
+ }
+
+ pFreqBandTable[0] = h_sbr_cal_env->prevFreqBandTableLo;
+ pFreqBandTable[1] = h_sbr_cal_env->prevFreqBandTableHi;
+ pFreqBandTableNoise = h_sbr_cal_env->prevFreqBandTableNoise;
+ }
+
+ mapSineFlagsPvc(pFreqBandTable[1], noSubFrameBands[1],
+ h_sbr_cal_env->harmFlagsPrev,
+ h_sbr_cal_env->harmFlagsPrevActive, sineMapped,
+ hFrameData->sinusoidal_position,
+ &h_sbr_cal_env->sinusoidal_positionPrev,
+ (borders[0] > bordersPvc[0]) ? 1 : 0);
+ } else {
+ /*
+ Extract sine flags for all QMF bands
+ */
+ mapSineFlags(pFreqBandTable[1], noSubFrameBands[1],
+ hFrameData->addHarmonics, h_sbr_cal_env->harmFlagsPrev,
+ h_sbr_cal_env->harmFlagsPrevActive,
+ hFrameData->frameInfo.tranEnv, sineMapped);
+ }
+
+ /*
+ Scan for maximum in bufferd noise levels.
+ This is needed in case that we had strong noise in the previous frame
+ which is smoothed into the current frame.
+ The resulting exponent is used as start value for the maximum search
+ in reference energies
+ */
+ if (!useLP)
+ adj_e = h_sbr_cal_env->filtBufferNoise_e -
+ getScalefactor(h_sbr_cal_env->filtBufferNoise, noSubbands);
+
+ /*
+ Scan for maximum reference energy to be able
+ to select appropriate values for adj_e and final_e.
+ */
+ if (pvc_mode > 0) {
+ INT maxSfbNrg_e = pPvcDynamicData->predEsg_expMax;
+
+ /* Energy -> magnitude (sqrt halfens exponent) */
+ maxSfbNrg_e =
+ (maxSfbNrg_e + 1) >> 1; /* +1 to go safe (round to next higher int) */
+
+ /* Some safety margin is needed for 2 reasons:
+ - The signal energy is not equally spread over all subband samples in
+ a specific sfb of an envelope (Nrg could be too high by a factor of
+ envWidth * sfbWidth)
+ - Smoothing can smear high gains of the previous envelope into the
+ current
+ */
+ maxSfbNrg_e += 6;
+
+ adj_e = maxSfbNrg_e;
+ // final_e should not exist for PVC fixfix framing
+ } else {
+ for (i = 0; i < hFrameData->frameInfo.nEnvelopes; i++) {
+ INT maxSfbNrg_e =
+ -FRACT_BITS + NRG_EXP_OFFSET; /* start value for maximum search */
+
+ /* Fetch frequency resolution for current envelope: */
+ for (j = noSubFrameBands[hFrameData->frameInfo.freqRes[i]]; j != 0; j--) {
+ maxSfbNrg_e = fixMax(maxSfbNrg_e, (INT)((LONG)(*pIenv++) & MASK_E));
+ }
+ maxSfbNrg_e -= NRG_EXP_OFFSET;
+
+ /* Energy -> magnitude (sqrt halfens exponent) */
+ maxSfbNrg_e =
+ (maxSfbNrg_e + 1) >> 1; /* +1 to go safe (round to next higher int) */
+
+ /* Some safety margin is needed for 2 reasons:
+ - The signal energy is not equally spread over all subband samples in
+ a specific sfb of an envelope (Nrg could be too high by a factor of
+ envWidth * sfbWidth)
+ - Smoothing can smear high gains of the previous envelope into the
+ current
+ */
+ maxSfbNrg_e += 6;
+
+ if (borders[i] < hHeaderData->numberTimeSlots)
+ /* This envelope affects timeslots that belong to the output frame */
+ adj_e = fMax(maxSfbNrg_e, adj_e);
+
+ if (borders[i + 1] > hHeaderData->numberTimeSlots)
+ /* This envelope affects timeslots after the output frame */
+ final_e = fMax(maxSfbNrg_e, final_e);
+ }
+ }
+ /*
+ Calculate adjustment factors and apply them for every envelope.
+ */
+ pIenv = hFrameData->iEnvelope;
+
+ if (pvc_mode > 0) {
+ /* iterate over SBR time slots starting with bordersPvc[i] */
+ i = bordersPvc[0]; /* usually 0; can be >0 if switching from legacy SBR to
+ PVC */
+ i_stop = PVC_NTIMESLOT;
+ FDK_ASSERT(bordersPvc[hFrameData->frameInfo.nEnvelopes] == PVC_NTIMESLOT);
+ } else {
+ /* iterate over SBR envelopes starting with 0 */
+ i = 0;
+ i_stop = hFrameData->frameInfo.nEnvelopes;
+ }
+ for (; i < i_stop; i++) {
+ int k, noNoiseFlag;
+ SCHAR noise_e, input_e = SCALE2EXP(sbrScaleFactor->hb_scale);
+ C_ALLOC_SCRATCH_START(pNrgs, ENV_CALC_NRGS, 1);
+
+ /*
+ Helper variables.
+ */
+ int start_pos, stop_pos, freq_res;
+ if (pvc_mode > 0) {
+ start_pos =
+ hHeaderData->timeStep *
+ i; /* Start-position in time (subband sample) for current envelope. */
+ stop_pos = hHeaderData->timeStep * (i + 1); /* Stop-position in time
+ (subband sample) for
+ current envelope. */
+ freq_res =
+ hFrameData->frameInfo
+ .freqRes[0]; /* Frequency resolution for current envelope. */
+ FDK_ASSERT(
+ freq_res ==
+ hFrameData->frameInfo.freqRes[hFrameData->frameInfo.nEnvelopes - 1]);
+ } else {
+ start_pos = hHeaderData->timeStep *
+ borders[i]; /* Start-position in time (subband sample) for
+ current envelope. */
+ stop_pos = hHeaderData->timeStep *
+ borders[i + 1]; /* Stop-position in time (subband sample) for
+ current envelope. */
+ freq_res =
+ hFrameData->frameInfo
+ .freqRes[i]; /* Frequency resolution for current envelope. */
+ }
+
+ /* Always fully initialize the temporary energy table. This prevents
+ negative energies and extreme gain factors in cases where the number of
+ limiter bands exceeds the number of subbands. The latter can be caused by
+ undetected bit errors and is tested by some streams from the
+ certification set. */
+ FDKmemclear(pNrgs, sizeof(ENV_CALC_NRGS));
+
+ if (pvc_mode > 0) {
+ /* get predicted energy values from PVC module */
+ expandPredEsg(pPvcDynamicData, i, (int)MAX_FREQ_COEFFS, pNrgs->nrgRef,
+ pNrgs->nrgRef_e);
+
+ if (i == borders[0]) {
+ mapSineFlags(pFreqBandTable[1], noSubFrameBands[1],
+ hFrameData->addHarmonics, h_sbr_cal_env->harmFlagsPrev,
+ h_sbr_cal_env->harmFlagsPrevActive,
+ hFrameData->sinusoidal_position, sineMapped);
+ }
+
+ if (i >= hFrameData->frameInfo.bordersNoise[envNoise + 1]) {
+ if (envNoise >= 0) {
+ noiseLevels += noNoiseBands; /* The noise floor data is stored in a
+ row [noiseFloor1 noiseFloor2...].*/
+ } else {
+ /* leave trailing noise envelope of past frame */
+ noNoiseBands = hFreq->nNfb;
+ noSubFrameBands = hFreq->nSfb;
+ noiseLevels = hFrameData->sbrNoiseFloorLevel;
+
+ lowSubband = hFreq->lowSubband;
+ highSubband = hFreq->highSubband;
+
+ noSubbands = highSubband - lowSubband;
+ ov_highSubband = highSubband;
+ if (highSubband < hFreq->ov_highSubband) {
+ ov_highSubband = hFreq->ov_highSubband;
+ }
+
+ pFreqBandTable[0] = hFreq->freqBandTableLo;
+ pFreqBandTable[1] = hFreq->freqBandTableHi;
+ pFreqBandTableNoise = hFreq->freqBandTableNoise;
+ }
+ envNoise++;
+ }
+ } else {
+ /* If the start-pos of the current envelope equals the stop pos of the
+ current noise envelope, increase the pointer (i.e. choose the next
+ noise-floor).*/
+ if (borders[i] == hFrameData->frameInfo.bordersNoise[envNoise + 1]) {
+ noiseLevels += noNoiseBands; /* The noise floor data is stored in a row
+ [noiseFloor1 noiseFloor2...].*/
+ envNoise++;
+ }
+ }
+ if (i == hFrameData->frameInfo.tranEnv ||
+ i == h_sbr_cal_env->prevTranEnv) /* attack */
+ {
+ noNoiseFlag = 1;
+ if (!useLP) smooth_length = 0; /* No smoothing on attacks! */
+ } else {
+ noNoiseFlag = 0;
+ if (!useLP)
+ smooth_length = (1 - hHeaderData->bs_data.smoothingLength)
+ << 2; /* can become either 0 or 4 */
+ }
+
+ /*
+ Energy estimation in transposed highband.
+ */
+ if (hHeaderData->bs_data.interpolFreq)
+ calcNrgPerSubband(analysBufferReal, (useLP) ? NULL : analysBufferImag,
+ lowSubband, highSubband, start_pos, stop_pos, input_e,
+ pNrgs->nrgEst, pNrgs->nrgEst_e);
+ else
+ calcNrgPerSfb(analysBufferReal, (useLP) ? NULL : analysBufferImag,
+ noSubFrameBands[freq_res], pFreqBandTable[freq_res],
+ start_pos, stop_pos, input_e, pNrgs->nrgEst,
+ pNrgs->nrgEst_e);
+
+ /*
+ Calculate subband gains
+ */
+ {
+ UCHAR *table = pFreqBandTable[freq_res];
+ UCHAR *pUiNoise =
+ &pFreqBandTableNoise[1]; /*! Upper limit of the current noise floor
+ band. */
+
+ FIXP_SGL *pNoiseLevels = noiseLevels;
+
+ FIXP_DBL tmpNoise =
+ FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M));
+ SCHAR tmpNoise_e =
+ (UCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET;
+
+ int cc = 0;
+ c = 0;
+ if (pvc_mode > 0) {
+ for (j = 0; j < noSubFrameBands[freq_res]; j++) {
+ UCHAR sinePresentFlag = 0;
+ int li = table[j];
+ int ui = table[j + 1];
+
+ for (k = li; k < ui; k++) {
+ sinePresentFlag |= (i >= sineMapped[cc]);
+ cc++;
+ }
+
+ for (k = li; k < ui; k++) {
+ FIXP_DBL refNrg = pNrgs->nrgRef[k - lowSubband];
+ SCHAR refNrg_e = pNrgs->nrgRef_e[k - lowSubband];
+
+ if (k >= *pUiNoise) {
+ tmpNoise =
+ FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M));
+ tmpNoise_e =
+ (SCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET;
+
+ pUiNoise++;
+ }
+
+ FDK_ASSERT(k >= lowSubband);
+
+ if (useLP) useAliasReduction[k - lowSubband] = !sinePresentFlag;
+
+ pNrgs->nrgSine[c] = FL2FXCONST_DBL(0.0f);
+ pNrgs->nrgSine_e[c] = 0;
+
+ calcSubbandGain(refNrg, refNrg_e, pNrgs, c, tmpNoise, tmpNoise_e,
+ sinePresentFlag, i >= sineMapped[c], noNoiseFlag);
+
+ c++;
+ }
+ }
+ } else {
+ for (j = 0; j < noSubFrameBands[freq_res]; j++) {
+ FIXP_DBL refNrg = FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pIenv) & MASK_M));
+ SCHAR refNrg_e = (SCHAR)((LONG)(*pIenv) & MASK_E) - NRG_EXP_OFFSET;
+
+ UCHAR sinePresentFlag = 0;
+ int li = table[j];
+ int ui = table[j + 1];
+
+ for (k = li; k < ui; k++) {
+ sinePresentFlag |= (i >= sineMapped[cc]);
+ cc++;
+ }
+
+ for (k = li; k < ui; k++) {
+ if (k >= *pUiNoise) {
+ tmpNoise =
+ FX_SGL2FX_DBL((FIXP_SGL)((LONG)(*pNoiseLevels) & MASK_M));
+ tmpNoise_e =
+ (SCHAR)((LONG)(*pNoiseLevels++) & MASK_E) - NOISE_EXP_OFFSET;
+
+ pUiNoise++;
+ }
+
+ FDK_ASSERT(k >= lowSubband);
+
+ if (useLP) useAliasReduction[k - lowSubband] = !sinePresentFlag;
+
+ pNrgs->nrgSine[c] = FL2FXCONST_DBL(0.0f);
+ pNrgs->nrgSine_e[c] = 0;
+
+ calcSubbandGain(refNrg, refNrg_e, pNrgs, c, tmpNoise, tmpNoise_e,
+ sinePresentFlag, i >= sineMapped[c], noNoiseFlag);
+
+ pNrgs->nrgRef[c] = refNrg;
+ pNrgs->nrgRef_e[c] = refNrg_e;
+
+ c++;
+ }
+ pIenv++;
+ }
+ }
+ }
+
+ /*
+ Noise limiting
+ */
+
+ for (c = 0; c < hFreq->noLimiterBands; c++) {
+ FIXP_DBL sumRef, boostGain, maxGain;
+ FIXP_DBL accu = FL2FXCONST_DBL(0.0f);
+ SCHAR sumRef_e, boostGain_e, maxGain_e, accu_e = 0;
+ int maxGainLimGainSum_e = 0;
+
+ calcAvgGain(pNrgs, hFreq->limiterBandTable[c],
+ hFreq->limiterBandTable[c + 1], &sumRef, &sumRef_e, &maxGain,
+ &maxGain_e);
+
+ /* Multiply maxGain with limiterGain: */
+ maxGain = fMult(
+ maxGain,
+ FDK_sbrDecoder_sbr_limGains_m[hHeaderData->bs_data.limiterGains]);
+ /* maxGain_e +=
+ * FDK_sbrDecoder_sbr_limGains_e[hHeaderData->bs_data.limiterGains]; */
+ /* The addition of maxGain_e and FDK_sbrDecoder_sbr_limGains_e[3] might
+ yield values greater than 127 which doesn't fit into an SCHAR! In these
+ rare situations limit maxGain_e to 127.
+ */
+ maxGainLimGainSum_e =
+ maxGain_e +
+ FDK_sbrDecoder_sbr_limGains_e[hHeaderData->bs_data.limiterGains];
+ maxGain_e =
+ (maxGainLimGainSum_e > 127) ? (SCHAR)127 : (SCHAR)maxGainLimGainSum_e;
+
+ /* Scale mantissa of MaxGain into range between 0.5 and 1: */
+ if (maxGain == FL2FXCONST_DBL(0.0f))
+ maxGain_e = -FRACT_BITS;
+ else {
+ SCHAR charTemp = CountLeadingBits(maxGain);
+ maxGain_e -= charTemp;
+ maxGain <<= (int)charTemp;
+ }
+
+ if (maxGain_e >= maxGainLimit_e) { /* upper limit (e.g. 96 dB) */
+ maxGain = FL2FXCONST_DBL(0.5f);
+ maxGain_e = maxGainLimit_e;
+ }
+
+ /* Every subband gain is compared to the scaled "average gain"
+ and limited if necessary: */
+ for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1];
+ k++) {
+ if ((pNrgs->nrgGain_e[k] > maxGain_e) ||
+ (pNrgs->nrgGain_e[k] == maxGain_e && pNrgs->nrgGain[k] > maxGain)) {
+ FIXP_DBL noiseAmp;
+ SCHAR noiseAmp_e;
+
+ FDK_divide_MantExp(maxGain, maxGain_e, pNrgs->nrgGain[k],
+ pNrgs->nrgGain_e[k], &noiseAmp, &noiseAmp_e);
+ pNrgs->noiseLevel[k] = fMult(pNrgs->noiseLevel[k], noiseAmp);
+ pNrgs->noiseLevel_e[k] += noiseAmp_e;
+ pNrgs->nrgGain[k] = maxGain;
+ pNrgs->nrgGain_e[k] = maxGain_e;
+ }
+ }
+
+ /* -- Boost gain
+ Calculate and apply boost factor for each limiter band:
+ 1. Check how much energy would be present when using the limited gain
+ 2. Calculate boost factor by comparison with reference energy
+ 3. Apply boost factor to compensate for the energy loss due to limiting
+ */
+ for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1];
+ k++) {
+ /* 1.a Add energy of adjusted signal (using preliminary gain) */
+ FIXP_DBL tmp = fMult(pNrgs->nrgGain[k], pNrgs->nrgEst[k]);
+ SCHAR tmp_e = pNrgs->nrgGain_e[k] + pNrgs->nrgEst_e[k];
+ FDK_add_MantExp(tmp, tmp_e, accu, accu_e, &accu, &accu_e);
+
+ /* 1.b Add sine energy (if present) */
+ if (pNrgs->nrgSine[k] != FL2FXCONST_DBL(0.0f)) {
+ FDK_add_MantExp(pNrgs->nrgSine[k], pNrgs->nrgSine_e[k], accu, accu_e,
+ &accu, &accu_e);
+ } else {
+ /* 1.c Add noise energy (if present) */
+ if (noNoiseFlag == 0) {
+ FDK_add_MantExp(pNrgs->noiseLevel[k], pNrgs->noiseLevel_e[k], accu,
+ accu_e, &accu, &accu_e);
+ }
+ }
+ }
+
+ /* 2.a Calculate ratio of wanted energy and accumulated energy */
+ if (accu == (FIXP_DBL)0) { /* If divisor is 0, limit quotient to +4 dB */
+ boostGain = FL2FXCONST_DBL(0.6279716f);
+ boostGain_e = 2;
+ } else {
+ INT div_e;
+ boostGain = fDivNorm(sumRef, accu, &div_e);
+ boostGain_e = sumRef_e - accu_e + div_e;
+ }
+
+ /* 2.b Result too high? --> Limit the boost factor to +4 dB */
+ if ((boostGain_e > 3) ||
+ (boostGain_e == 2 && boostGain > FL2FXCONST_DBL(0.6279716f)) ||
+ (boostGain_e == 3 && boostGain > FL2FXCONST_DBL(0.3139858f))) {
+ boostGain = FL2FXCONST_DBL(0.6279716f);
+ boostGain_e = 2;
+ }
+ /* 3. Multiply all signal components with the boost factor */
+ for (k = hFreq->limiterBandTable[c]; k < hFreq->limiterBandTable[c + 1];
+ k++) {
+ pNrgs->nrgGain[k] = fMultDiv2(pNrgs->nrgGain[k], boostGain);
+ pNrgs->nrgGain_e[k] = pNrgs->nrgGain_e[k] + boostGain_e + 1;
+
+ pNrgs->nrgSine[k] = fMultDiv2(pNrgs->nrgSine[k], boostGain);
+ pNrgs->nrgSine_e[k] = pNrgs->nrgSine_e[k] + boostGain_e + 1;
+
+ pNrgs->noiseLevel[k] = fMultDiv2(pNrgs->noiseLevel[k], boostGain);
+ pNrgs->noiseLevel_e[k] = pNrgs->noiseLevel_e[k] + boostGain_e + 1;
+ }
+ }
+ /* End of noise limiting */
+
+ if (useLP)
+ aliasingReduction(degreeAlias + lowSubband, pNrgs, useAliasReduction,
+ noSubbands);
+
+ /* For the timeslots within the range for the output frame,
+ use the same scale for the noise levels.
+ Drawback: If the envelope exceeds the frame border, the noise levels
+ will have to be rescaled later to fit final_e of
+ the gain-values.
+ */
+ noise_e = (start_pos < no_cols) ? adj_e : final_e;
+
+ /*
+ Convert energies to amplitude levels
+ */
+ for (k = 0; k < noSubbands; k++) {
+ FDK_sqrt_MantExp(&pNrgs->nrgSine[k], &pNrgs->nrgSine_e[k], &noise_e);
+ FDK_sqrt_MantExp(&pNrgs->nrgGain[k], &pNrgs->nrgGain_e[k],
+ &pNrgs->nrgGain_e[k]);
+ FDK_sqrt_MantExp(&pNrgs->noiseLevel[k], &pNrgs->noiseLevel_e[k],
+ &noise_e);
+ }
+
+ /*
+ Apply calculated gains and adaptive noise
+ */
+
+ /* assembleHfSignals() */
+ {
+ int scale_change, sc_change;
+ FIXP_SGL smooth_ratio;
+ int filtBufferNoiseShift = 0;
+
+ /* Initialize smoothing buffers with the first valid values */
+ if (h_sbr_cal_env->startUp) {
+ if (!useLP) {
+ h_sbr_cal_env->filtBufferNoise_e = noise_e;
+
+ FDKmemcpy(h_sbr_cal_env->filtBuffer_e, pNrgs->nrgGain_e,
+ noSubbands * sizeof(SCHAR));
+ FDKmemcpy(h_sbr_cal_env->filtBufferNoise, pNrgs->noiseLevel,
+ noSubbands * sizeof(FIXP_DBL));
+ FDKmemcpy(h_sbr_cal_env->filtBuffer, pNrgs->nrgGain,
+ noSubbands * sizeof(FIXP_DBL));
+ }
+ h_sbr_cal_env->startUp = 0;
+ }
+
+ if (!useLP) {
+ equalizeFiltBufferExp(h_sbr_cal_env->filtBuffer, /* buffered */
+ h_sbr_cal_env->filtBuffer_e, /* buffered */
+ pNrgs->nrgGain, /* current */
+ pNrgs->nrgGain_e, /* current */
+ noSubbands);
+
+ /* Adapt exponent of buffered noise levels to the current exponent
+ so they can easily be smoothed */
+ if ((h_sbr_cal_env->filtBufferNoise_e - noise_e) >= 0) {
+ int shift = fixMin(DFRACT_BITS - 1,
+ (int)(h_sbr_cal_env->filtBufferNoise_e - noise_e));
+ for (k = 0; k < noSubbands; k++)
+ h_sbr_cal_env->filtBufferNoise[k] <<= shift;
+ } else {
+ int shift =
+ fixMin(DFRACT_BITS - 1,
+ -(int)(h_sbr_cal_env->filtBufferNoise_e - noise_e));
+ for (k = 0; k < noSubbands; k++)
+ h_sbr_cal_env->filtBufferNoise[k] >>= shift;
+ }
+
+ h_sbr_cal_env->filtBufferNoise_e = noise_e;
+ }
+
+ /* find best scaling! */
+ scale_change = -(DFRACT_BITS - 1);
+ for (k = 0; k < noSubbands; k++) {
+ scale_change = fixMax(scale_change, (int)pNrgs->nrgGain_e[k]);
+ }
+ sc_change = (start_pos < no_cols) ? adj_e - input_e : final_e - input_e;
+
+ if ((scale_change - sc_change + 1) < 0)
+ scale_change -= (scale_change - sc_change + 1);
+
+ scale_change = (scale_change - sc_change) + 1;
+
+ for (k = 0; k < noSubbands; k++) {
+ int sc = scale_change - pNrgs->nrgGain_e[k] + (sc_change - 1);
+ pNrgs->nrgGain[k] >>= sc;
+ pNrgs->nrgGain_e[k] += sc;
+ }
+
+ if (!useLP) {
+ for (k = 0; k < noSubbands; k++) {
+ int sc =
+ scale_change - h_sbr_cal_env->filtBuffer_e[k] + (sc_change - 1);
+ h_sbr_cal_env->filtBuffer[k] >>= sc;
+ }
+ }
+
+ for (j = start_pos; j < stop_pos; j++) {
+ /* This timeslot is located within the first part of the processing
+ buffer and will be fed into the QMF-synthesis for the current frame.
+ adj_e - input_e
+ This timeslot will not yet be fed into the QMF so we do not care
+ about the adj_e.
+ sc_change = final_e - input_e
+ */
+ if ((j == no_cols) && (start_pos < no_cols)) {
+ int shift = (int)(noise_e - final_e);
+ if (!useLP)
+ filtBufferNoiseShift = shift; /* shifting of
+ h_sbr_cal_env->filtBufferNoise[k]
+ will be applied in function
+ adjustTimeSlotHQ() */
+ if (shift >= 0) {
+ shift = fixMin(DFRACT_BITS - 1, shift);
+ for (k = 0; k < noSubbands; k++) {
+ pNrgs->nrgSine[k] <<= shift;
+ pNrgs->noiseLevel[k] <<= shift;
+ /*
+ if (!useLP)
+ h_sbr_cal_env->filtBufferNoise[k] <<= shift;
+ */
+ }
+ } else {
+ shift = fixMin(DFRACT_BITS - 1, -shift);
+ for (k = 0; k < noSubbands; k++) {
+ pNrgs->nrgSine[k] >>= shift;
+ pNrgs->noiseLevel[k] >>= shift;
+ /*
+ if (!useLP)
+ h_sbr_cal_env->filtBufferNoise[k] >>= shift;
+ */
+ }
+ }
+
+ /* update noise scaling */
+ noise_e = final_e;
+ if (!useLP)
+ h_sbr_cal_env->filtBufferNoise_e =
+ noise_e; /* scaling value unused! */
+
+ /* update gain buffer*/
+ sc_change -= (final_e - input_e);
+
+ if (sc_change < 0) {
+ for (k = 0; k < noSubbands; k++) {
+ pNrgs->nrgGain[k] >>= -sc_change;
+ pNrgs->nrgGain_e[k] += -sc_change;
+ }
+ if (!useLP) {
+ for (k = 0; k < noSubbands; k++) {
+ h_sbr_cal_env->filtBuffer[k] >>= -sc_change;
+ }
+ }
+ } else {
+ scale_change += sc_change;
+ }
+
+ } /* if */
+
+ if (!useLP) {
+ /* Prevent the smoothing filter from running on constant levels */
+ if (j - start_pos < smooth_length)
+ smooth_ratio = FDK_sbrDecoder_sbr_smoothFilter[j - start_pos];
+ else
+ smooth_ratio = FL2FXCONST_SGL(0.0f);
+
+ if (iTES_enable) {
+ /* adjustTimeSlotHQ() without adding of additional harmonics */
+ adjustTimeSlotHQ_GainAndNoise(
+ &analysBufferReal[j][lowSubband],
+ &analysBufferImag[j][lowSubband], h_sbr_cal_env, pNrgs,
+ lowSubband, noSubbands, fMin(scale_change, DFRACT_BITS - 1),
+ smooth_ratio, noNoiseFlag, filtBufferNoiseShift);
+ } else {
+ adjustTimeSlotHQ(&analysBufferReal[j][lowSubband],
+ &analysBufferImag[j][lowSubband], h_sbr_cal_env,
+ pNrgs, lowSubband, noSubbands,
+ fMin(scale_change, DFRACT_BITS - 1), smooth_ratio,
+ noNoiseFlag, filtBufferNoiseShift);
+ }
+ } else {
+ FDK_ASSERT(!iTES_enable); /* not supported */
+ if (flags & SBRDEC_ELD_GRID) {
+ /* FDKmemset(analysBufferReal[j], 0, 64 * sizeof(FIXP_DBL)); */
+ adjustTimeSlot_EldGrid(&analysBufferReal[j][lowSubband], pNrgs,
+ &h_sbr_cal_env->harmIndex, lowSubband,
+ noSubbands,
+ fMin(scale_change, DFRACT_BITS - 1),
+ noNoiseFlag, &h_sbr_cal_env->phaseIndex,
+ EXP2SCALE(adj_e) - sbrScaleFactor->lb_scale);
+ } else {
+ adjustTimeSlotLC(&analysBufferReal[j][lowSubband], pNrgs,
+ &h_sbr_cal_env->harmIndex, lowSubband, noSubbands,
+ fMin(scale_change, DFRACT_BITS - 1), noNoiseFlag,
+ &h_sbr_cal_env->phaseIndex);
+ }
+ }
+ /* In case the envelope spans accross the no_cols border both exponents
+ * are needed. */
+ /* nrgGain_e[0...(noSubbands-1)] are equalized by
+ * equalizeFiltBufferExp() */
+ pNrgs->exponent[(j < no_cols) ? 0 : 1] =
+ (SCHAR)((15 - sbrScaleFactor->hb_scale) + pNrgs->nrgGain_e[0] + 1 -
+ scale_change);
+ } /* for */
+
+ if (iTES_enable) {
+ apply_inter_tes(
+ analysBufferReal, /* pABufR, */
+ analysBufferImag, /* pABufI, */
+ sbrScaleFactor, pNrgs->exponent, hHeaderData->timeStep, start_pos,
+ stop_pos, lowSubband, noSubbands,
+ hFrameData
+ ->interTempShapeMode[i] /* frameData->interTempShapeMode[env] */
+ );
+
+ /* add additional harmonics */
+ for (j = start_pos; j < stop_pos; j++) {
+ /* match exponent of additional harmonics to scale change of QMF data
+ * caused by apply_inter_tes() */
+ scale_change = 0;
+
+ if ((start_pos <= no_cols) && (stop_pos > no_cols)) {
+ /* Scaling of analysBuffers was potentially changed within this
+ envelope. The pNrgs->nrgSine_e match the second part of the
+ envelope. For (j<=no_cols) the exponent of the sine energies has
+ to be adapted. */
+ scale_change = pNrgs->exponent[1] - pNrgs->exponent[0];
+ }
+
+ adjustTimeSlotHQ_AddHarmonics(
+ &analysBufferReal[j][lowSubband],
+ &analysBufferImag[j][lowSubband], h_sbr_cal_env, pNrgs,
+ lowSubband, noSubbands,
+ -iTES_scale_change + ((j < no_cols) ? scale_change : 0));
+ }
+ }
+
+ if (!useLP) {
+ /* Update time-smoothing-buffers for gains and noise levels
+ The gains and the noise values of the current envelope are copied
+ into the buffer. This has to be done at the end of each envelope as
+ the values are required for a smooth transition to the next envelope.
+ */
+ FDKmemcpy(h_sbr_cal_env->filtBuffer, pNrgs->nrgGain,
+ noSubbands * sizeof(FIXP_DBL));
+ FDKmemcpy(h_sbr_cal_env->filtBuffer_e, pNrgs->nrgGain_e,
+ noSubbands * sizeof(SCHAR));
+ FDKmemcpy(h_sbr_cal_env->filtBufferNoise, pNrgs->noiseLevel,
+ noSubbands * sizeof(FIXP_DBL));
+ }
+ }
+ C_ALLOC_SCRATCH_END(pNrgs, ENV_CALC_NRGS, 1);
+ }
+
+ /* adapt adj_e to the scale change caused by apply_inter_tes() */
+ adj_e += iTES_scale_change;
+
+ /* Rescale output samples */
+ {
+ FIXP_DBL maxVal;
+ int ov_reserve, reserve;
+
+ /* Determine headroom in old adjusted samples */
+ maxVal =
+ maxSubbandSample(analysBufferReal, (useLP) ? NULL : analysBufferImag,
+ lowSubband, ov_highSubband, 0, first_start);
+
+ ov_reserve = fNorm(maxVal);
+
+ /* Determine headroom in new adjusted samples */
+ maxVal =
+ maxSubbandSample(analysBufferReal, (useLP) ? NULL : analysBufferImag,
+ lowSubband, highSubband, first_start, no_cols);
+
+ reserve = fNorm(maxVal);
+
+ /* Determine common output exponent */
+ output_e = fMax(ov_adj_e - ov_reserve, adj_e - reserve);
+
+ /* Rescale old samples */
+ rescaleSubbandSamples(analysBufferReal, (useLP) ? NULL : analysBufferImag,
+ lowSubband, ov_highSubband, 0, first_start,
+ ov_adj_e - output_e);
+
+ /* Rescale new samples */
+ rescaleSubbandSamples(analysBufferReal, (useLP) ? NULL : analysBufferImag,
+ lowSubband, highSubband, first_start, no_cols,
+ adj_e - output_e);
+ }
+
+ /* Update hb_scale */
+ sbrScaleFactor->hb_scale = EXP2SCALE(output_e);
+
+ /* Save the current final exponent for the next frame: */
+ /* adapt final_e to the scale change caused by apply_inter_tes() */
+ sbrScaleFactor->ov_hb_scale = EXP2SCALE(final_e + iTES_scale_change);
+
+ /* We need to remember to the next frame that the transient
+ will occur in the first envelope (if tranEnv == nEnvelopes). */
+ if (hFrameData->frameInfo.tranEnv == hFrameData->frameInfo.nEnvelopes)
+ h_sbr_cal_env->prevTranEnv = 0;
+ else
+ h_sbr_cal_env->prevTranEnv = -1;
+
+ if (pvc_mode > 0) {
+ /* Not more than just the last noise envelope reaches into the next PVC
+ frame! This should be true because bs_noise_position is <= 15 */
+ FDK_ASSERT(hFrameData->frameInfo
+ .bordersNoise[hFrameData->frameInfo.nNoiseEnvelopes - 1] <
+ PVC_NTIMESLOT);
+ if (hFrameData->frameInfo
+ .bordersNoise[hFrameData->frameInfo.nNoiseEnvelopes] >
+ PVC_NTIMESLOT) {
+ FDK_ASSERT(noiseLevels ==
+ (hFrameData->sbrNoiseFloorLevel +
+ (hFrameData->frameInfo.nNoiseEnvelopes - 1) * noNoiseBands));
+ h_sbr_cal_env->prevNNfb = noNoiseBands;
+
+ h_sbr_cal_env->prevNSfb[0] = noSubFrameBands[0];
+ h_sbr_cal_env->prevNSfb[1] = noSubFrameBands[1];
+
+ h_sbr_cal_env->prevLoSubband = lowSubband;
+ h_sbr_cal_env->prevHiSubband = highSubband;
+ h_sbr_cal_env->prev_ov_highSubband = ov_highSubband;
+
+ FDKmemcpy(h_sbr_cal_env->prevFreqBandTableLo, pFreqBandTable[0],
+ noSubFrameBands[0] + 1);
+ FDKmemcpy(h_sbr_cal_env->prevFreqBandTableHi, pFreqBandTable[1],
+ noSubFrameBands[1] + 1);
+ FDKmemcpy(h_sbr_cal_env->prevFreqBandTableNoise,
+ hFreq->freqBandTableNoise, sizeof(hFreq->freqBandTableNoise));
+
+ FDKmemcpy(h_sbr_cal_env->prevSbrNoiseFloorLevel, noiseLevels,
+ MAX_NOISE_COEFFS * sizeof(FIXP_SGL));
+ }
+ }
+
+ C_ALLOC_SCRATCH_END(useAliasReduction, UCHAR, 64)
+}
+
+/*!
+ \brief Create envelope instance
+
+ Must be called once for each channel before calculateSbrEnvelope() can be
+ used.
+
+ \return errorCode, 0 if successful
+*/
+SBR_ERROR
+createSbrEnvelopeCalc(
+ HANDLE_SBR_CALCULATE_ENVELOPE hs, /*!< pointer to envelope instance */
+ HANDLE_SBR_HEADER_DATA
+ hHeaderData, /*!< static SBR control data, initialized with defaults */
+ const int chan, /*!< Channel for which to assign buffers */
+ const UINT flags) {
+ SBR_ERROR err = SBRDEC_OK;
+ int i;
+
+ /* Clear previous missing harmonics flags */
+ for (i = 0; i < ADD_HARMONICS_FLAGS_SIZE; i++) {
+ hs->harmFlagsPrev[i] = 0;
+ hs->harmFlagsPrevActive[i] = 0;
+ }
+ hs->harmIndex = 0;
+
+ FDKmemclear(hs->prevSbrNoiseFloorLevel, sizeof(hs->prevSbrNoiseFloorLevel));
+ hs->prevNNfb = 0;
+ FDKmemclear(hs->prevFreqBandTableNoise, sizeof(hs->prevFreqBandTableNoise));
+ hs->sinusoidal_positionPrev = 0;
+
+ /*
+ Setup pointers for time smoothing.
+ The buffer itself will be initialized later triggered by the startUp-flag.
+ */
+ hs->prevTranEnv = -1;
+
+ /* initialization */
+ resetSbrEnvelopeCalc(hs);
+
+ if (chan == 0) { /* do this only once */
+ err = resetFreqBandTables(hHeaderData, flags);
+ }
+
+ return err;
+}
+
+/*!
+ \brief Create envelope instance
+
+ Must be called once for each channel before calculateSbrEnvelope() can be
+ used.
+
+ \return errorCode, 0 if successful
+*/
+int deleteSbrEnvelopeCalc(HANDLE_SBR_CALCULATE_ENVELOPE hs) { return 0; }
+
+/*!
+ \brief Reset envelope instance
+
+ This function must be called for each channel on a change of configuration.
+ Note that resetFreqBandTables should also be called in this case.
+
+ \return errorCode, 0 if successful
+*/
+void resetSbrEnvelopeCalc(
+ HANDLE_SBR_CALCULATE_ENVELOPE hCalEnv) /*!< pointer to envelope instance */
+{
+ hCalEnv->phaseIndex = 0;
+
+ /* Noise exponent needs to be reset because the output exponent for the next
+ * frame depends on it */
+ hCalEnv->filtBufferNoise_e = 0;
+
+ hCalEnv->startUp = 1;
+}
+
+/*!
+ \brief Equalize exponents of the buffered gain values and the new ones
+
+ After equalization of exponents, the FIR-filter addition for smoothing
+ can be performed.
+ This function is called once for each envelope before adjusting.
+*/
+static void equalizeFiltBufferExp(
+ FIXP_DBL *filtBuffer, /*!< bufferd gains */
+ SCHAR *filtBuffer_e, /*!< exponents of bufferd gains */
+ FIXP_DBL *nrgGain, /*!< gains for current envelope */
+ SCHAR *nrgGain_e, /*!< exponents of gains for current envelope */
+ int subbands) /*!< Number of QMF subbands */
+{
+ int band;
+ int diff;
+
+ for (band = 0; band < subbands; band++) {
+ diff = (int)(nrgGain_e[band] - filtBuffer_e[band]);
+ if (diff > 0) {
+ filtBuffer[band] >>=
+ diff; /* Compensate for the scale change by shifting the mantissa. */
+ filtBuffer_e[band] += diff; /* New gain is bigger, use its exponent */
+ } else if (diff < 0) {
+ /* The buffered gains seem to be larger, but maybe there
+ are some unused bits left in the mantissa */
+
+ int reserve = CntLeadingZeros(fixp_abs(filtBuffer[band])) - 1;
+
+ if ((-diff) <= reserve) {
+ /* There is enough space in the buffered mantissa so
+ that we can take the new exponent as common.
+ */
+ filtBuffer[band] <<= (-diff);
+ filtBuffer_e[band] += diff; /* becomes equal to *ptrNewExp */
+ } else {
+ filtBuffer[band] <<=
+ reserve; /* Shift the mantissa as far as possible: */
+ filtBuffer_e[band] -= reserve; /* Compensate in the exponent: */
+
+ /* For the remaining difference, change the new gain value */
+ diff = fixMin(-(reserve + diff), DFRACT_BITS - 1);
+ nrgGain[band] >>= diff;
+ nrgGain_e[band] += diff;
+ }
+ }
+ }
+}
+
+/*!
+ \brief Shift left the mantissas of all subband samples
+ in the giventime and frequency range by the specified number of bits.
+
+ This function is used to rescale the audio data in the overlap buffer
+ which has already been envelope adjusted with the last frame.
+*/
+void rescaleSubbandSamples(
+ FIXP_DBL **re, /*!< Real part of input and output subband samples */
+ FIXP_DBL **im, /*!< Imaginary part of input and output subband samples */
+ int lowSubband, /*!< Begin of frequency range to process */
+ int highSubband, /*!< End of frequency range to process */
+ int start_pos, /*!< Begin of time rage (QMF-timeslot) */
+ int next_pos, /*!< End of time rage (QMF-timeslot) */
+ int shift) /*!< number of bits to shift */
+{
+ int width = highSubband - lowSubband;
+
+ if ((width > 0) && (shift != 0)) {
+ if (im != NULL) {
+ for (int l = start_pos; l < next_pos; l++) {
+ scaleValues(&re[l][lowSubband], width, shift);
+ scaleValues(&im[l][lowSubband], width, shift);
+ }
+ } else {
+ for (int l = start_pos; l < next_pos; l++) {
+ scaleValues(&re[l][lowSubband], width, shift);
+ }
+ }
+ }
+}
+
+static inline FIXP_DBL FDK_get_maxval_real(FIXP_DBL maxVal, FIXP_DBL *reTmp,
+ INT width) {
+ maxVal = (FIXP_DBL)0;
+ while (width-- != 0) {
+ FIXP_DBL tmp = *(reTmp++);
+ maxVal |= (FIXP_DBL)((LONG)(tmp) ^ ((LONG)tmp >> (DFRACT_BITS - 1)));
+ }
+
+ return maxVal;
+}
+
+/*!
+ \brief Determine headroom for shifting
+
+ Determine by how much the spectrum can be shifted left
+ for better accuracy in later processing.
+
+ \return Number of free bits in the biggest spectral value
+*/
+
+FIXP_DBL maxSubbandSample(
+ FIXP_DBL **re, /*!< Real part of input and output subband samples */
+ FIXP_DBL **im, /*!< Real part of input and output subband samples */
+ int lowSubband, /*!< Begin of frequency range to process */
+ int highSubband, /*!< Number of QMF bands to process */
+ int start_pos, /*!< Begin of time rage (QMF-timeslot) */
+ int next_pos /*!< End of time rage (QMF-timeslot) */
+) {
+ FIXP_DBL maxVal = FL2FX_DBL(0.0f);
+ unsigned int width = highSubband - lowSubband;
+
+ FDK_ASSERT(width <= (64));
+
+ if (width > 0) {
+ if (im != NULL) {
+ for (int l = start_pos; l < next_pos; l++) {
+ int k = width;
+ FIXP_DBL *reTmp = &re[l][lowSubband];
+ FIXP_DBL *imTmp = &im[l][lowSubband];
+ do {
+ FIXP_DBL tmp1 = *(reTmp++);
+ FIXP_DBL tmp2 = *(imTmp++);
+ maxVal |=
+ (FIXP_DBL)((LONG)(tmp1) ^ ((LONG)tmp1 >> (DFRACT_BITS - 1)));
+ maxVal |=
+ (FIXP_DBL)((LONG)(tmp2) ^ ((LONG)tmp2 >> (DFRACT_BITS - 1)));
+ } while (--k != 0);
+ }
+ } else {
+ for (int l = start_pos; l < next_pos; l++) {
+ maxVal |= FDK_get_maxval_real(maxVal, &re[l][lowSubband], width);
+ }
+ }
+ }
+
+ if (maxVal > (FIXP_DBL)0) {
+ /* For negative input values, maxVal is too small by 1. Add 1 only when
+ * necessary: if maxVal is a power of 2 */
+ FIXP_DBL lowerPow2 =
+ (FIXP_DBL)(1 << (DFRACT_BITS - 1 - CntLeadingZeros(maxVal)));
+ if (maxVal == lowerPow2) maxVal += (FIXP_DBL)1;
+ }
+
+ return (maxVal);
+}
+
+/* #define SHIFT_BEFORE_SQUARE (3) */ /* (7/2) */
+/* Avoid assertion failures triggerd by overflows which occured in robustness
+ tests. Setting the SHIFT_BEFORE_SQUARE to 4 has negligible effect on (USAC)
+ conformance results. */
+#define SHIFT_BEFORE_SQUARE (4) /* ((8 - 0) / 2) */
+
+/*!<
+ If the accumulator does not provide enough overflow bits or
+ does not provide a high dynamic range, the below energy calculation
+ requires an additional shift operation for each sample.
+ On the other hand, doing the shift allows using a single-precision
+ multiplication for the square (at least 16bit x 16bit).
+ For even values of OVRFLW_BITS (0, 2, 4, 6), saturated arithmetic
+ is required for the energy accumulation.
+ Theoretically, the sample-squares can sum up to a value of 76,
+ requiring 7 overflow bits. However since such situations are *very*
+ rare, accu can be limited to 64.
+ In case native saturated arithmetic is not available, overflows
+ can be prevented by replacing the above #define by
+ #define SHIFT_BEFORE_SQUARE ((8 - OVRFLW_BITS) / 2)
+ which will result in slightly reduced accuracy.
+*/
+
+/*!
+ \brief Estimates the mean energy of each filter-bank channel for the
+ duration of the current envelope
+
+ This function is used when interpolFreq is true.
+*/
+static void calcNrgPerSubband(
+ FIXP_DBL **analysBufferReal, /*!< Real part of subband samples */
+ FIXP_DBL **analysBufferImag, /*!< Imaginary part of subband samples */
+ int lowSubband, /*!< Begin of the SBR frequency range */
+ int highSubband, /*!< High end of the SBR frequency range */
+ int start_pos, /*!< First QMF-slot of current envelope */
+ int next_pos, /*!< Last QMF-slot of current envelope + 1 */
+ SCHAR frameExp, /*!< Common exponent for all input samples */
+ FIXP_DBL *nrgEst, /*!< resulting Energy (0..1) */
+ SCHAR *nrgEst_e) /*!< Exponent of resulting Energy */
+{
+ FIXP_SGL invWidth;
+ SCHAR preShift;
+ SCHAR shift;
+ FIXP_DBL sum;
+ int k;
+
+ /* Divide by width of envelope later: */
+ invWidth = FX_DBL2FX_SGL(GetInvInt(next_pos - start_pos));
+ /* The common exponent needs to be doubled because all mantissas are squared:
+ */
+ frameExp = frameExp << 1;
+
+ for (k = lowSubband; k < highSubband; k++) {
+ FIXP_DBL bufferReal[(((1024) / (32) * (4) / 2) + (3 * (4)))];
+ FIXP_DBL bufferImag[(((1024) / (32) * (4) / 2) + (3 * (4)))];
+ FIXP_DBL maxVal;
+
+ if (analysBufferImag != NULL) {
+ int l;
+ maxVal = FL2FX_DBL(0.0f);
+ for (l = start_pos; l < next_pos; l++) {
+ bufferImag[l] = analysBufferImag[l][k];
+ maxVal |= (FIXP_DBL)((LONG)(bufferImag[l]) ^
+ ((LONG)bufferImag[l] >> (DFRACT_BITS - 1)));
+ bufferReal[l] = analysBufferReal[l][k];
+ maxVal |= (FIXP_DBL)((LONG)(bufferReal[l]) ^
+ ((LONG)bufferReal[l] >> (DFRACT_BITS - 1)));
+ }
+ } else {
+ int l;
+ maxVal = FL2FX_DBL(0.0f);
+ for (l = start_pos; l < next_pos; l++) {
+ bufferReal[l] = analysBufferReal[l][k];
+ maxVal |= (FIXP_DBL)((LONG)(bufferReal[l]) ^
+ ((LONG)bufferReal[l] >> (DFRACT_BITS - 1)));
+ }
+ }
+
+ if (maxVal != FL2FXCONST_DBL(0.f)) {
+ /* If the accu does not provide enough overflow bits, we cannot
+ shift the samples up to the limit.
+ Instead, keep up to 3 free bits in each sample, i.e. up to
+ 6 bits after calculation of square.
+ Please note the comment on saturated arithmetic above!
+ */
+ FIXP_DBL accu;
+ preShift = CntLeadingZeros(maxVal) - 1;
+ preShift -= SHIFT_BEFORE_SQUARE;
+
+ /* Limit preShift to a maximum value to prevent accumulator overflow in
+ exceptional situations where the signal in the analysis-buffer is very
+ small (small maxVal).
+ */
+ preShift = fMin(preShift, (SCHAR)25);
+
+ accu = FL2FXCONST_DBL(0.0f);
+ if (preShift >= 0) {
+ int l;
+ if (analysBufferImag != NULL) {
+ for (l = start_pos; l < next_pos; l++) {
+ FIXP_DBL temp1 = bufferReal[l] << (int)preShift;
+ FIXP_DBL temp2 = bufferImag[l] << (int)preShift;
+ accu = fPow2AddDiv2(accu, temp1);
+ accu = fPow2AddDiv2(accu, temp2);
+ }
+ } else {
+ for (l = start_pos; l < next_pos; l++) {
+ FIXP_DBL temp = bufferReal[l] << (int)preShift;
+ accu = fPow2AddDiv2(accu, temp);
+ }
+ }
+ } else { /* if negative shift value */
+ int l;
+ int negpreShift = -preShift;
+ if (analysBufferImag != NULL) {
+ for (l = start_pos; l < next_pos; l++) {
+ FIXP_DBL temp1 = bufferReal[l] >> (int)negpreShift;
+ FIXP_DBL temp2 = bufferImag[l] >> (int)negpreShift;
+ accu = fPow2AddDiv2(accu, temp1);
+ accu = fPow2AddDiv2(accu, temp2);
+ }
+ } else {
+ for (l = start_pos; l < next_pos; l++) {
+ FIXP_DBL temp = bufferReal[l] >> (int)negpreShift;
+ accu = fPow2AddDiv2(accu, temp);
+ }
+ }
+ }
+ accu <<= 1;
+
+ /* Convert double precision to Mantissa/Exponent: */
+ shift = fNorm(accu);
+ sum = accu << (int)shift;
+
+ /* Divide by width of envelope and apply frame scale: */
+ *nrgEst++ = fMult(sum, invWidth);
+ shift += 2 * preShift;
+ if (analysBufferImag != NULL)
+ *nrgEst_e++ = frameExp - shift;
+ else
+ *nrgEst_e++ = frameExp - shift + 1; /* +1 due to missing imag. part */
+ } /* maxVal!=0 */
+ else {
+ /* Prevent a zero-mantissa-number from being misinterpreted
+ due to its exponent. */
+ *nrgEst++ = FL2FXCONST_DBL(0.0f);
+ *nrgEst_e++ = 0;
+ }
+ }
+}
+
+/*!
+ \brief Estimates the mean energy of each Scale factor band for the
+ duration of the current envelope.
+
+ This function is used when interpolFreq is false.
+*/
+static void calcNrgPerSfb(
+ FIXP_DBL **analysBufferReal, /*!< Real part of subband samples */
+ FIXP_DBL **analysBufferImag, /*!< Imaginary part of subband samples */
+ int nSfb, /*!< Number of scale factor bands */
+ UCHAR *freqBandTable, /*!< First Subband for each Sfb */
+ int start_pos, /*!< First QMF-slot of current envelope */
+ int next_pos, /*!< Last QMF-slot of current envelope + 1 */
+ SCHAR input_e, /*!< Common exponent for all input samples */
+ FIXP_DBL *nrgEst, /*!< resulting Energy (0..1) */
+ SCHAR *nrgEst_e) /*!< Exponent of resulting Energy */
+{
+ FIXP_SGL invWidth;
+ FIXP_DBL temp;
+ SCHAR preShift;
+ SCHAR shift, sum_e;
+ FIXP_DBL sum;
+
+ int j, k, l, li, ui;
+ FIXP_DBL sumAll, sumLine; /* Single precision would be sufficient,
+ but overflow bits are required for accumulation */
+
+ /* Divide by width of envelope later: */
+ invWidth = FX_DBL2FX_SGL(GetInvInt(next_pos - start_pos));
+ /* The common exponent needs to be doubled because all mantissas are squared:
+ */
+ input_e = input_e << 1;
+
+ for (j = 0; j < nSfb; j++) {
+ li = freqBandTable[j];
+ ui = freqBandTable[j + 1];
+
+ FIXP_DBL maxVal = maxSubbandSample(analysBufferReal, analysBufferImag, li,
+ ui, start_pos, next_pos);
+
+ if (maxVal != FL2FXCONST_DBL(0.f)) {
+ preShift = CntLeadingZeros(maxVal) - 1;
+
+ /* If the accu does not provide enough overflow bits, we cannot
+ shift the samples up to the limit.
+ Instead, keep up to 3 free bits in each sample, i.e. up to
+ 6 bits after calculation of square.
+ Please note the comment on saturated arithmetic above!
+ */
+ preShift -= SHIFT_BEFORE_SQUARE;
+
+ sumAll = FL2FXCONST_DBL(0.0f);
+
+ for (k = li; k < ui; k++) {
+ sumLine = FL2FXCONST_DBL(0.0f);
+
+ if (analysBufferImag != NULL) {
+ if (preShift >= 0) {
+ for (l = start_pos; l < next_pos; l++) {
+ temp = analysBufferReal[l][k] << (int)preShift;
+ sumLine += fPow2Div2(temp);
+ temp = analysBufferImag[l][k] << (int)preShift;
+ sumLine += fPow2Div2(temp);
+ }
+ } else {
+ for (l = start_pos; l < next_pos; l++) {
+ temp = analysBufferReal[l][k] >> -(int)preShift;
+ sumLine += fPow2Div2(temp);
+ temp = analysBufferImag[l][k] >> -(int)preShift;
+ sumLine += fPow2Div2(temp);
+ }
+ }
+ } else {
+ if (preShift >= 0) {
+ for (l = start_pos; l < next_pos; l++) {
+ temp = analysBufferReal[l][k] << (int)preShift;
+ sumLine += fPow2Div2(temp);
+ }
+ } else {
+ for (l = start_pos; l < next_pos; l++) {
+ temp = analysBufferReal[l][k] >> -(int)preShift;
+ sumLine += fPow2Div2(temp);
+ }
+ }
+ }
+
+ /* The number of QMF-channels per SBR bands may be up to 15.
+ Shift right to avoid overflows in sum over all channels. */
+ sumLine = sumLine >> (4 - 1);
+ sumAll += sumLine;
+ }
+
+ /* Convert double precision to Mantissa/Exponent: */
+ shift = fNorm(sumAll);
+ sum = sumAll << (int)shift;
+
+ /* Divide by width of envelope: */
+ sum = fMult(sum, invWidth);
+
+ /* Divide by width of Sfb: */
+ sum = fMult(sum, FX_DBL2FX_SGL(GetInvInt(ui - li)));
+
+ /* Set all Subband energies in the Sfb to the average energy: */
+ if (analysBufferImag != NULL)
+ sum_e = input_e + 4 - shift; /* -4 to compensate right-shift */
+ else
+ sum_e = input_e + 4 + 1 -
+ shift; /* -4 to compensate right-shift; +1 due to missing
+ imag. part */
+
+ sum_e -= 2 * preShift;
+ } /* maxVal!=0 */
+ else {
+ /* Prevent a zero-mantissa-number from being misinterpreted
+ due to its exponent. */
+ sum = FL2FXCONST_DBL(0.0f);
+ sum_e = 0;
+ }
+
+ for (k = li; k < ui; k++) {
+ *nrgEst++ = sum;
+ *nrgEst_e++ = sum_e;
+ }
+ }
+}
+
+/*!
+ \brief Calculate gain, noise, and additional sine level for one subband.
+
+ The resulting energy gain is given by mantissa and exponent.
+*/
+static void calcSubbandGain(
+ FIXP_DBL nrgRef, /*!< Reference Energy according to envelope data */
+ SCHAR
+ nrgRef_e, /*!< Reference Energy according to envelope data (exponent) */
+ ENV_CALC_NRGS *nrgs, int i, FIXP_DBL tmpNoise, /*!< Relative noise level */
+ SCHAR tmpNoise_e, /*!< Relative noise level (exponent) */
+ UCHAR sinePresentFlag, /*!< Indicates if sine is present on band */
+ UCHAR sineMapped, /*!< Indicates if sine must be added */
+ int noNoiseFlag) /*!< Flag to suppress noise addition */
+{
+ FIXP_DBL nrgEst = nrgs->nrgEst[i]; /*!< Energy in transposed signal */
+ SCHAR nrgEst_e =
+ nrgs->nrgEst_e[i]; /*!< Energy in transposed signal (exponent) */
+ FIXP_DBL *ptrNrgGain = &nrgs->nrgGain[i]; /*!< Resulting energy gain */
+ SCHAR *ptrNrgGain_e =
+ &nrgs->nrgGain_e[i]; /*!< Resulting energy gain (exponent) */
+ FIXP_DBL *ptrNoiseLevel =
+ &nrgs->noiseLevel[i]; /*!< Resulting absolute noise energy */
+ SCHAR *ptrNoiseLevel_e =
+ &nrgs->noiseLevel_e[i]; /*!< Resulting absolute noise energy (exponent) */
+ FIXP_DBL *ptrNrgSine = &nrgs->nrgSine[i]; /*!< Additional sine energy */
+ SCHAR *ptrNrgSine_e =
+ &nrgs->nrgSine_e[i]; /*!< Additional sine energy (exponent) */
+
+ FIXP_DBL a, b, c;
+ SCHAR a_e, b_e, c_e;
+
+ /*
+ This addition of 1 prevents divisions by zero in the reference code.
+ For very small energies in nrgEst, it prevents the gains from becoming
+ very high which could cause some trouble due to the smoothing.
+ */
+ b_e = (int)(nrgEst_e - 1);
+ if (b_e >= 0) {
+ nrgEst = (FL2FXCONST_DBL(0.5f) >> (INT)fixMin(b_e + 1, DFRACT_BITS - 1)) +
+ (nrgEst >> 1);
+ nrgEst_e += 1; /* shift by 1 bit to avoid overflow */
+
+ } else {
+ nrgEst = (nrgEst >> (INT)(fixMin(-b_e + 1, DFRACT_BITS - 1))) +
+ (FL2FXCONST_DBL(0.5f) >> 1);
+ nrgEst_e = 2; /* shift by 1 bit to avoid overflow */
+ }
+
+ /* A = NrgRef * TmpNoise */
+ a = fMult(nrgRef, tmpNoise);
+ a_e = nrgRef_e + tmpNoise_e;
+
+ /* B = 1 + TmpNoise */
+ b_e = (int)(tmpNoise_e - 1);
+ if (b_e >= 0) {
+ b = (FL2FXCONST_DBL(0.5f) >> (INT)fixMin(b_e + 1, DFRACT_BITS - 1)) +
+ (tmpNoise >> 1);
+ b_e = tmpNoise_e + 1; /* shift by 1 bit to avoid overflow */
+ } else {
+ b = (tmpNoise >> (INT)(fixMin(-b_e + 1, DFRACT_BITS - 1))) +
+ (FL2FXCONST_DBL(0.5f) >> 1);
+ b_e = 2; /* shift by 1 bit to avoid overflow */
+ }
+
+ /* noiseLevel = A / B = (NrgRef * TmpNoise) / (1 + TmpNoise) */
+ FDK_divide_MantExp(a, a_e, b, b_e, ptrNoiseLevel, ptrNoiseLevel_e);
+
+ if (sinePresentFlag) {
+ /* C = (1 + TmpNoise) * NrgEst */
+ c = fMult(b, nrgEst);
+ c_e = b_e + nrgEst_e;
+
+ /* gain = A / C = (NrgRef * TmpNoise) / (1 + TmpNoise) * NrgEst */
+ FDK_divide_MantExp(a, a_e, c, c_e, ptrNrgGain, ptrNrgGain_e);
+
+ if (sineMapped) {
+ /* sineLevel = nrgRef/ (1 + TmpNoise) */
+ FDK_divide_MantExp(nrgRef, nrgRef_e, b, b_e, ptrNrgSine, ptrNrgSine_e);
+ }
+ } else {
+ if (noNoiseFlag) {
+ /* B = NrgEst */
+ b = nrgEst;
+ b_e = nrgEst_e;
+ } else {
+ /* B = NrgEst * (1 + TmpNoise) */
+ b = fMult(b, nrgEst);
+ b_e = b_e + nrgEst_e;
+ }
+
+ /* gain = nrgRef / B */
+ FDK_divide_MantExp(nrgRef, nrgRef_e, b, b_e, ptrNrgGain, ptrNrgGain_e);
+ }
+}
+
+/*!
+ \brief Calculate "average gain" for the specified subband range.
+
+ This is rather a gain of the average magnitude than the average
+ of gains!
+ The result is used as a relative limit for all gains within the
+ current "limiter band" (a certain frequency range).
+*/
+static void calcAvgGain(
+ ENV_CALC_NRGS *nrgs, int lowSubband, /*!< Begin of the limiter band */
+ int highSubband, /*!< High end of the limiter band */
+ FIXP_DBL *ptrSumRef, SCHAR *ptrSumRef_e,
+ FIXP_DBL *ptrAvgGain, /*!< Resulting overall gain (mantissa) */
+ SCHAR *ptrAvgGain_e) /*!< Resulting overall gain (exponent) */
+{
+ FIXP_DBL *nrgRef =
+ nrgs->nrgRef; /*!< Reference Energy according to envelope data */
+ SCHAR *nrgRef_e =
+ nrgs->nrgRef_e; /*!< Reference Energy according to envelope data
+ (exponent) */
+ FIXP_DBL *nrgEst = nrgs->nrgEst; /*!< Energy in transposed signal */
+ SCHAR *nrgEst_e =
+ nrgs->nrgEst_e; /*!< Energy in transposed signal (exponent) */
+
+ FIXP_DBL sumRef = 1;
+ FIXP_DBL sumEst = 1;
+ SCHAR sumRef_e = -FRACT_BITS;
+ SCHAR sumEst_e = -FRACT_BITS;
+ int k;
+
+ for (k = lowSubband; k < highSubband; k++) {
+ /* Add nrgRef[k] to sumRef: */
+ FDK_add_MantExp(sumRef, sumRef_e, nrgRef[k], nrgRef_e[k], &sumRef,
+ &sumRef_e);
+
+ /* Add nrgEst[k] to sumEst: */
+ FDK_add_MantExp(sumEst, sumEst_e, nrgEst[k], nrgEst_e[k], &sumEst,
+ &sumEst_e);
+ }
+
+ FDK_divide_MantExp(sumRef, sumRef_e, sumEst, sumEst_e, ptrAvgGain,
+ ptrAvgGain_e);
+
+ *ptrSumRef = sumRef;
+ *ptrSumRef_e = sumRef_e;
+}
+
+static void adjustTimeSlot_EldGrid(
+ FIXP_DBL *RESTRICT
+ ptrReal, /*!< Subband samples to be adjusted, real part */
+ ENV_CALC_NRGS *nrgs, UCHAR *ptrHarmIndex, /*!< Harmonic index */
+ int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
+ int noSubbands, /*!< Number of QMF subbands */
+ int scale_change, /*!< Number of bits to shift adjusted samples */
+ int noNoiseFlag, /*!< Flag to suppress noise addition */
+ int *ptrPhaseIndex, /*!< Start index to random number array */
+ int scale_diff_low) /*!< */
+
+{
+ int k;
+ FIXP_DBL signalReal, sbNoise;
+ int tone_count = 0;
+
+ FIXP_DBL *pGain = nrgs->nrgGain; /*!< Gains of current envelope */
+ FIXP_DBL *RESTRICT pNoiseLevel =
+ nrgs->noiseLevel; /*!< Noise levels of current envelope */
+ FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
+
+ int phaseIndex = *ptrPhaseIndex;
+ UCHAR harmIndex = *ptrHarmIndex;
+
+ static const INT harmonicPhase[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
+
+ static const FIXP_DBL harmonicPhaseX[4][2] = {
+ {FL2FXCONST_DBL(2.0 * 1.245183154539139e-001),
+ FL2FXCONST_DBL(2.0 * 1.245183154539139e-001)},
+ {FL2FXCONST_DBL(2.0 * -1.123767859325028e-001),
+ FL2FXCONST_DBL(2.0 * 1.123767859325028e-001)},
+ {FL2FXCONST_DBL(2.0 * -1.245183154539139e-001),
+ FL2FXCONST_DBL(2.0 * -1.245183154539139e-001)},
+ {FL2FXCONST_DBL(2.0 * 1.123767859325028e-001),
+ FL2FXCONST_DBL(2.0 * -1.123767859325028e-001)}};
+
+ const FIXP_DBL *p_harmonicPhaseX = &harmonicPhaseX[harmIndex][0];
+ const INT *p_harmonicPhase = &harmonicPhase[harmIndex][0];
+
+ *(ptrReal - 1) = fAddSaturate(
+ *(ptrReal - 1),
+ SATURATE_SHIFT(fMultDiv2(p_harmonicPhaseX[lowSubband & 1], pSineLevel[0]),
+ scale_diff_low, DFRACT_BITS));
+ FIXP_DBL pSineLevel_prev = (FIXP_DBL)0;
+
+ int idx_k = lowSubband & 1;
+
+ for (k = 0; k < noSubbands; k++) {
+ FIXP_DBL sineLevel_curr = *pSineLevel++;
+ phaseIndex = (phaseIndex + 1) & (SBR_NF_NO_RANDOM_VAL - 1);
+
+ signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
+ sbNoise = *pNoiseLevel++;
+ if (((INT)sineLevel_curr | noNoiseFlag) == 0) {
+ signalReal +=
+ (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[phaseIndex][0], sbNoise)
+ << 4);
+ }
+ signalReal += sineLevel_curr * p_harmonicPhase[0];
+ signalReal =
+ fMultAddDiv2(signalReal, pSineLevel_prev, p_harmonicPhaseX[idx_k]);
+ pSineLevel_prev = sineLevel_curr;
+ idx_k = !idx_k;
+ if (k < noSubbands - 1) {
+ signalReal =
+ fMultAddDiv2(signalReal, pSineLevel[0], p_harmonicPhaseX[idx_k]);
+ } else /* (k == noSubbands - 1) */
+ {
+ if (k + lowSubband + 1 < 63) {
+ *(ptrReal + 1) += fMultDiv2(pSineLevel_prev, p_harmonicPhaseX[idx_k]);
+ }
+ }
+ *ptrReal++ = signalReal;
+
+ if (pSineLevel_prev != FL2FXCONST_DBL(0.0f)) {
+ if (++tone_count == 16) {
+ k++;
+ break;
+ }
+ }
+ }
+ /* Run again, if previous loop got breaked with tone_count = 16 */
+ for (; k < noSubbands; k++) {
+ FIXP_DBL sineLevel_curr = *pSineLevel++;
+ phaseIndex = (phaseIndex + 1) & (SBR_NF_NO_RANDOM_VAL - 1);
+
+ signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
+ sbNoise = *pNoiseLevel++;
+ if (((INT)sineLevel_curr | noNoiseFlag) == 0) {
+ signalReal +=
+ (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[phaseIndex][0], sbNoise)
+ << 4);
+ }
+ signalReal += sineLevel_curr * p_harmonicPhase[0];
+ *ptrReal++ = signalReal;
+ }
+
+ *ptrHarmIndex = (harmIndex + 1) & 3;
+ *ptrPhaseIndex = phaseIndex & (SBR_NF_NO_RANDOM_VAL - 1);
+}
+
+/*!
+ \brief Amplify one timeslot of the signal with the calculated gains
+ and add the noisefloor.
+*/
+
+static void adjustTimeSlotLC(
+ FIXP_DBL *ptrReal, /*!< Subband samples to be adjusted, real part */
+ ENV_CALC_NRGS *nrgs, UCHAR *ptrHarmIndex, /*!< Harmonic index */
+ int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
+ int noSubbands, /*!< Number of QMF subbands */
+ int scale_change, /*!< Number of bits to shift adjusted samples */
+ int noNoiseFlag, /*!< Flag to suppress noise addition */
+ int *ptrPhaseIndex) /*!< Start index to random number array */
+{
+ FIXP_DBL *pGain = nrgs->nrgGain; /*!< Gains of current envelope */
+ FIXP_DBL *pNoiseLevel =
+ nrgs->noiseLevel; /*!< Noise levels of current envelope */
+ FIXP_DBL *pSineLevel = nrgs->nrgSine; /*!< Sine levels */
+
+ int k;
+ int index = *ptrPhaseIndex;
+ UCHAR harmIndex = *ptrHarmIndex;
+ UCHAR freqInvFlag = (lowSubband & 1);
+ FIXP_DBL signalReal, sineLevel, sineLevelNext, sineLevelPrev;
+ int tone_count = 0;
+ int sineSign = 1;
+
+#define C1 ((FIXP_SGL)FL2FXCONST_SGL(2.f * 0.00815f))
+#define C1_CLDFB ((FIXP_SGL)FL2FXCONST_SGL(2.f * 0.16773f))
+
+ /*
+ First pass for k=0 pulled out of the loop:
+ */
+
+ index = (index + 1) & (SBR_NF_NO_RANDOM_VAL - 1);
+
+ /*
+ The next multiplication constitutes the actual envelope adjustment
+ of the signal and should be carried out with full accuracy
+ (supplying #FRACT_BITS valid bits).
+ */
+ signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
+ sineLevel = *pSineLevel++;
+ sineLevelNext = (noSubbands > 1) ? pSineLevel[0] : FL2FXCONST_DBL(0.0f);
+
+ if (sineLevel != FL2FXCONST_DBL(0.0f))
+ tone_count++;
+ else if (!noNoiseFlag)
+ /* Add noisefloor to the amplified signal */
+ signalReal +=
+ (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])
+ << 4);
+
+ {
+ if (!(harmIndex & 0x1)) {
+ /* harmIndex 0,2 */
+ signalReal += (harmIndex & 0x2) ? -sineLevel : sineLevel;
+ *ptrReal++ = signalReal;
+ } else {
+ /* harmIndex 1,3 in combination with freqInvFlag */
+ int shift = (int)(scale_change + 1);
+ shift = (shift >= 0) ? fixMin(DFRACT_BITS - 1, shift)
+ : fixMax(-(DFRACT_BITS - 1), shift);
+
+ FIXP_DBL tmp1 = (shift >= 0) ? (fMultDiv2(C1, sineLevel) >> shift)
+ : (fMultDiv2(C1, sineLevel) << (-shift));
+ FIXP_DBL tmp2 = fMultDiv2(C1, sineLevelNext);
+
+ /* save switch and compare operations and reduce to XOR statement */
+ if (((harmIndex >> 1) & 0x1) ^ freqInvFlag) {
+ *(ptrReal - 1) += tmp1;
+ signalReal -= tmp2;
+ } else {
+ *(ptrReal - 1) -= tmp1;
+ signalReal += tmp2;
+ }
+ *ptrReal++ = signalReal;
+ freqInvFlag = !freqInvFlag;
+ }
+ }
+
+ pNoiseLevel++;
+
+ if (noSubbands > 2) {
+ if (!(harmIndex & 0x1)) {
+ /* harmIndex 0,2 */
+ if (!harmIndex) {
+ sineSign = 0;
+ }
+
+ for (k = noSubbands - 2; k != 0; k--) {
+ FIXP_DBL sinelevel = *pSineLevel++;
+ index++;
+ if (((signalReal = (sineSign ? -sinelevel : sinelevel)) ==
+ FL2FXCONST_DBL(0.0f)) &&
+ !noNoiseFlag) {
+ /* Add noisefloor to the amplified signal */
+ index &= (SBR_NF_NO_RANDOM_VAL - 1);
+ signalReal += (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0],
+ pNoiseLevel[0])
+ << 4);
+ }
+
+ /* The next multiplication constitutes the actual envelope adjustment of
+ * the signal. */
+ signalReal += fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
+
+ pNoiseLevel++;
+ *ptrReal++ = signalReal;
+ } /* for ... */
+ } else {
+ /* harmIndex 1,3 in combination with freqInvFlag */
+ if (harmIndex == 1) freqInvFlag = !freqInvFlag;
+
+ for (k = noSubbands - 2; k != 0; k--) {
+ index++;
+ /* The next multiplication constitutes the actual envelope adjustment of
+ * the signal. */
+ signalReal = fMultDiv2(*ptrReal, *pGain++) << ((int)scale_change);
+
+ if (*pSineLevel++ != FL2FXCONST_DBL(0.0f))
+ tone_count++;
+ else if (!noNoiseFlag) {
+ /* Add noisefloor to the amplified signal */
+ index &= (SBR_NF_NO_RANDOM_VAL - 1);
+ signalReal += (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0],
+ pNoiseLevel[0])
+ << 4);
+ }
+
+ pNoiseLevel++;
+
+ if (tone_count <= 16) {
+ FIXP_DBL addSine = fMultDiv2((pSineLevel[-2] - pSineLevel[0]), C1);
+ signalReal += (freqInvFlag) ? (-addSine) : (addSine);
+ }
+
+ *ptrReal++ = signalReal;
+ freqInvFlag = !freqInvFlag;
+ } /* for ... */
+ }
+ }
+
+ if (noSubbands > -1) {
+ index++;
+ /* The next multiplication constitutes the actual envelope adjustment of the
+ * signal. */
+ signalReal = fMultDiv2(*ptrReal, *pGain) << ((int)scale_change);
+ sineLevelPrev = fMultDiv2(pSineLevel[-1], FL2FX_SGL(0.0163f));
+ sineLevel = pSineLevel[0];
+
+ if (pSineLevel[0] != FL2FXCONST_DBL(0.0f))
+ tone_count++;
+ else if (!noNoiseFlag) {
+ /* Add noisefloor to the amplified signal */
+ index &= (SBR_NF_NO_RANDOM_VAL - 1);
+ signalReal =
+ signalReal +
+ (fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], pNoiseLevel[0])
+ << 4);
+ }
+
+ if (!(harmIndex & 0x1)) {
+ /* harmIndex 0,2 */
+ *ptrReal = signalReal + ((sineSign) ? -sineLevel : sineLevel);
+ } else {
+ /* harmIndex 1,3 in combination with freqInvFlag */
+ if (tone_count <= 16) {
+ if (freqInvFlag) {
+ *ptrReal++ = signalReal - sineLevelPrev;
+ if (noSubbands + lowSubband < 63)
+ *ptrReal = *ptrReal + fMultDiv2(C1, sineLevel);
+ } else {
+ *ptrReal++ = signalReal + sineLevelPrev;
+ if (noSubbands + lowSubband < 63)
+ *ptrReal = *ptrReal - fMultDiv2(C1, sineLevel);
+ }
+ } else
+ *ptrReal = signalReal;
+ }
+ }
+ *ptrHarmIndex = (harmIndex + 1) & 3;
+ *ptrPhaseIndex = index & (SBR_NF_NO_RANDOM_VAL - 1);
+}
+
+static void adjustTimeSlotHQ_GainAndNoise(
+ FIXP_DBL *RESTRICT
+ ptrReal, /*!< Subband samples to be adjusted, real part */
+ FIXP_DBL *RESTRICT
+ ptrImag, /*!< Subband samples to be adjusted, imag part */
+ HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
+ int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
+ int noSubbands, /*!< Number of QMF subbands */
+ int scale_change, /*!< Number of bits to shift adjusted samples */
+ FIXP_SGL smooth_ratio, /*!< Impact of last envelope */
+ int noNoiseFlag, /*!< Start index to random number array */
+ int filtBufferNoiseShift) /*!< Shift factor of filtBufferNoise */
+{
+ FIXP_DBL *RESTRICT gain = nrgs->nrgGain; /*!< Gains of current envelope */
+ FIXP_DBL *RESTRICT noiseLevel =
+ nrgs->noiseLevel; /*!< Noise levels of current envelope */
+ FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
+
+ FIXP_DBL *RESTRICT filtBuffer =
+ h_sbr_cal_env->filtBuffer; /*!< Gains of last envelope */
+ FIXP_DBL *RESTRICT filtBufferNoise =
+ h_sbr_cal_env->filtBufferNoise; /*!< Noise levels of last envelope */
+ int *RESTRICT ptrPhaseIndex =
+ &h_sbr_cal_env->phaseIndex; /*!< Start index to random number array */
+
+ int k;
+ FIXP_DBL signalReal, signalImag;
+ FIXP_DBL noiseReal, noiseImag;
+ FIXP_DBL smoothedGain, smoothedNoise;
+ FIXP_SGL direct_ratio =
+ /*FL2FXCONST_SGL(1.0f) */ (FIXP_SGL)MAXVAL_SGL - smooth_ratio;
+ int index = *ptrPhaseIndex;
+ int shift;
+
+ *ptrPhaseIndex = (index + noSubbands) & (SBR_NF_NO_RANDOM_VAL - 1);
+
+ filtBufferNoiseShift +=
+ 1; /* due to later use of fMultDiv2 instead of fMult */
+ if (filtBufferNoiseShift < 0) {
+ shift = fixMin(DFRACT_BITS - 1, -filtBufferNoiseShift);
+ } else {
+ shift = fixMin(DFRACT_BITS - 1, filtBufferNoiseShift);
+ }
+
+ if (smooth_ratio > FL2FXCONST_SGL(0.0f)) {
+ for (k = 0; k < noSubbands; k++) {
+ /*
+ Smoothing: The old envelope has been bufferd and a certain ratio
+ of the old gains and noise levels is used.
+ */
+ smoothedGain =
+ fMult(smooth_ratio, filtBuffer[k]) + fMult(direct_ratio, gain[k]);
+
+ if (filtBufferNoiseShift < 0) {
+ smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) >> shift) +
+ fMult(direct_ratio, noiseLevel[k]);
+ } else {
+ smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) << shift) +
+ fMult(direct_ratio, noiseLevel[k]);
+ }
+
+ /*
+ The next 2 multiplications constitute the actual envelope adjustment
+ of the signal and should be carried out with full accuracy
+ (supplying #DFRACT_BITS valid bits).
+ */
+ signalReal = fMultDiv2(*ptrReal, smoothedGain) << ((int)scale_change);
+ signalImag = fMultDiv2(*ptrImag, smoothedGain) << ((int)scale_change);
+
+ index++;
+
+ if ((pSineLevel[k] != FL2FXCONST_DBL(0.0f)) || noNoiseFlag) {
+ /* Just the amplified signal is saved */
+ *ptrReal++ = signalReal;
+ *ptrImag++ = signalImag;
+ } else {
+ /* Add noisefloor to the amplified signal */
+ index &= (SBR_NF_NO_RANDOM_VAL - 1);
+ noiseReal =
+ fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise)
+ << 4;
+ noiseImag =
+ fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise)
+ << 4;
+ *ptrReal++ = (signalReal + noiseReal);
+ *ptrImag++ = (signalImag + noiseImag);
+ }
+ }
+ } else {
+ for (k = 0; k < noSubbands; k++) {
+ smoothedGain = gain[k];
+ signalReal = fMultDiv2(*ptrReal, smoothedGain) << scale_change;
+ signalImag = fMultDiv2(*ptrImag, smoothedGain) << scale_change;
+
+ index++;
+
+ if ((pSineLevel[k] == FL2FXCONST_DBL(0.0f)) && (noNoiseFlag == 0)) {
+ /* Add noisefloor to the amplified signal */
+ smoothedNoise = noiseLevel[k];
+ index &= (SBR_NF_NO_RANDOM_VAL - 1);
+ noiseReal =
+ fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise);
+ noiseImag =
+ fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise);
+
+ /* FDK_sbrDecoder_sbr_randomPhase is downscaled by 2^3 */
+ signalReal += noiseReal << 4;
+ signalImag += noiseImag << 4;
+ }
+ *ptrReal++ = signalReal;
+ *ptrImag++ = signalImag;
+ }
+ }
+}
+
+static void adjustTimeSlotHQ_AddHarmonics(
+ FIXP_DBL *RESTRICT
+ ptrReal, /*!< Subband samples to be adjusted, real part */
+ FIXP_DBL *RESTRICT
+ ptrImag, /*!< Subband samples to be adjusted, imag part */
+ HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
+ int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
+ int noSubbands, /*!< Number of QMF subbands */
+ int scale_change /*!< Scale mismatch between QMF input and sineLevel
+ exponent. */
+) {
+ FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
+ UCHAR *RESTRICT ptrHarmIndex =
+ &h_sbr_cal_env->harmIndex; /*!< Harmonic index */
+
+ int k;
+ FIXP_DBL signalReal, signalImag;
+ UCHAR harmIndex = *ptrHarmIndex;
+ int freqInvFlag = (lowSubband & 1);
+ FIXP_DBL sineLevel;
+
+ *ptrHarmIndex = (harmIndex + 1) & 3;
+
+ for (k = 0; k < noSubbands; k++) {
+ sineLevel = pSineLevel[k];
+ freqInvFlag ^= 1;
+ if (sineLevel != FL2FXCONST_DBL(0.f)) {
+ signalReal = ptrReal[k];
+ signalImag = ptrImag[k];
+ sineLevel = scaleValue(sineLevel, scale_change);
+ if (harmIndex & 2) {
+ /* case 2,3 */
+ sineLevel = -sineLevel;
+ }
+ if (!(harmIndex & 1)) {
+ /* case 0,2: */
+ ptrReal[k] = signalReal + sineLevel;
+ } else {
+ /* case 1,3 */
+ if (!freqInvFlag) sineLevel = -sineLevel;
+ ptrImag[k] = signalImag + sineLevel;
+ }
+ }
+ }
+}
+
+static void adjustTimeSlotHQ(
+ FIXP_DBL *RESTRICT
+ ptrReal, /*!< Subband samples to be adjusted, real part */
+ FIXP_DBL *RESTRICT
+ ptrImag, /*!< Subband samples to be adjusted, imag part */
+ HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env, ENV_CALC_NRGS *nrgs,
+ int lowSubband, /*!< Lowest QMF-channel in the currently used SBR range. */
+ int noSubbands, /*!< Number of QMF subbands */
+ int scale_change, /*!< Number of bits to shift adjusted samples */
+ FIXP_SGL smooth_ratio, /*!< Impact of last envelope */
+ int noNoiseFlag, /*!< Start index to random number array */
+ int filtBufferNoiseShift) /*!< Shift factor of filtBufferNoise */
+{
+ FIXP_DBL *RESTRICT gain = nrgs->nrgGain; /*!< Gains of current envelope */
+ FIXP_DBL *RESTRICT noiseLevel =
+ nrgs->noiseLevel; /*!< Noise levels of current envelope */
+ FIXP_DBL *RESTRICT pSineLevel = nrgs->nrgSine; /*!< Sine levels */
+
+ FIXP_DBL *RESTRICT filtBuffer =
+ h_sbr_cal_env->filtBuffer; /*!< Gains of last envelope */
+ FIXP_DBL *RESTRICT filtBufferNoise =
+ h_sbr_cal_env->filtBufferNoise; /*!< Noise levels of last envelope */
+ UCHAR *RESTRICT ptrHarmIndex =
+ &h_sbr_cal_env->harmIndex; /*!< Harmonic index */
+ int *RESTRICT ptrPhaseIndex =
+ &h_sbr_cal_env->phaseIndex; /*!< Start index to random number array */
+
+ int k;
+ FIXP_DBL signalReal, signalImag;
+ FIXP_DBL noiseReal, noiseImag;
+ FIXP_DBL smoothedGain, smoothedNoise;
+ FIXP_SGL direct_ratio =
+ /*FL2FXCONST_SGL(1.0f) */ (FIXP_SGL)MAXVAL_SGL - smooth_ratio;
+ int index = *ptrPhaseIndex;
+ UCHAR harmIndex = *ptrHarmIndex;
+ int freqInvFlag = (lowSubband & 1);
+ FIXP_DBL sineLevel;
+ int shift;
+
+ *ptrPhaseIndex = (index + noSubbands) & (SBR_NF_NO_RANDOM_VAL - 1);
+ *ptrHarmIndex = (harmIndex + 1) & 3;
+
+ /*
+ Possible optimization:
+ smooth_ratio and harmIndex stay constant during the loop.
+ It might be faster to include a separate loop in each path.
+
+ the check for smooth_ratio is now outside the loop and the workload
+ of the whole function decreased by about 20 %
+ */
+
+ filtBufferNoiseShift +=
+ 1; /* due to later use of fMultDiv2 instead of fMult */
+ if (filtBufferNoiseShift < 0)
+ shift = fixMin(DFRACT_BITS - 1, -filtBufferNoiseShift);
+ else
+ shift = fixMin(DFRACT_BITS - 1, filtBufferNoiseShift);
+
+ if (smooth_ratio > FL2FXCONST_SGL(0.0f)) {
+ for (k = 0; k < noSubbands; k++) {
+ /*
+ Smoothing: The old envelope has been bufferd and a certain ratio
+ of the old gains and noise levels is used.
+ */
+
+ smoothedGain =
+ fMult(smooth_ratio, filtBuffer[k]) + fMult(direct_ratio, gain[k]);
+
+ if (filtBufferNoiseShift < 0) {
+ smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) >> shift) +
+ fMult(direct_ratio, noiseLevel[k]);
+ } else {
+ smoothedNoise = (fMultDiv2(smooth_ratio, filtBufferNoise[k]) << shift) +
+ fMult(direct_ratio, noiseLevel[k]);
+ }
+
+ /*
+ The next 2 multiplications constitute the actual envelope adjustment
+ of the signal and should be carried out with full accuracy
+ (supplying #DFRACT_BITS valid bits).
+ */
+ signalReal = fMultDiv2(*ptrReal, smoothedGain) << ((int)scale_change);
+ signalImag = fMultDiv2(*ptrImag, smoothedGain) << ((int)scale_change);
+
+ index++;
+
+ if (pSineLevel[k] != FL2FXCONST_DBL(0.0f)) {
+ sineLevel = pSineLevel[k];
+
+ switch (harmIndex) {
+ case 0:
+ *ptrReal++ = (signalReal + sineLevel);
+ *ptrImag++ = (signalImag);
+ break;
+ case 2:
+ *ptrReal++ = (signalReal - sineLevel);
+ *ptrImag++ = (signalImag);
+ break;
+ case 1:
+ *ptrReal++ = (signalReal);
+ if (freqInvFlag)
+ *ptrImag++ = (signalImag - sineLevel);
+ else
+ *ptrImag++ = (signalImag + sineLevel);
+ break;
+ case 3:
+ *ptrReal++ = signalReal;
+ if (freqInvFlag)
+ *ptrImag++ = (signalImag + sineLevel);
+ else
+ *ptrImag++ = (signalImag - sineLevel);
+ break;
+ }
+ } else {
+ if (noNoiseFlag) {
+ /* Just the amplified signal is saved */
+ *ptrReal++ = (signalReal);
+ *ptrImag++ = (signalImag);
+ } else {
+ /* Add noisefloor to the amplified signal */
+ index &= (SBR_NF_NO_RANDOM_VAL - 1);
+ /* FDK_sbrDecoder_sbr_randomPhase is downscaled by 2^3 */
+ noiseReal =
+ fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0], smoothedNoise)
+ << 4;
+ noiseImag =
+ fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][1], smoothedNoise)
+ << 4;
+ *ptrReal++ = (signalReal + noiseReal);
+ *ptrImag++ = (signalImag + noiseImag);
+ }
+ }
+ freqInvFlag ^= 1;
+ }
+
+ } else {
+ for (k = 0; k < noSubbands; k++) {
+ smoothedGain = gain[k];
+ signalReal = fMultDiv2(*ptrReal, smoothedGain) << scale_change;
+ signalImag = fMultDiv2(*ptrImag, smoothedGain) << scale_change;
+
+ index++;
+
+ if ((sineLevel = pSineLevel[k]) != FL2FXCONST_DBL(0.0f)) {
+ switch (harmIndex) {
+ case 0:
+ signalReal += sineLevel;
+ break;
+ case 1:
+ if (freqInvFlag)
+ signalImag -= sineLevel;
+ else
+ signalImag += sineLevel;
+ break;
+ case 2:
+ signalReal -= sineLevel;
+ break;
+ case 3:
+ if (freqInvFlag)
+ signalImag += sineLevel;
+ else
+ signalImag -= sineLevel;
+ break;
+ }
+ } else {
+ if (noNoiseFlag == 0) {
+ /* Add noisefloor to the amplified signal */
+ smoothedNoise = noiseLevel[k];
+ index &= (SBR_NF_NO_RANDOM_VAL - 1);
+ noiseReal = fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][0],
+ smoothedNoise);
+ noiseImag = fMultDiv2(FDK_sbrDecoder_sbr_randomPhase[index][1],
+ smoothedNoise);
+
+ /* FDK_sbrDecoder_sbr_randomPhase is downscaled by 2^3 */
+ signalReal += noiseReal << 4;
+ signalImag += noiseImag << 4;
+ }
+ }
+ *ptrReal++ = signalReal;
+ *ptrImag++ = signalImag;
+
+ freqInvFlag ^= 1;
+ }
+ }
+}
+
+/*!
+ \brief Reset limiter bands.
+
+ Build frequency band table for the gain limiter dependent on
+ the previously generated transposer patch areas.
+
+ \return SBRDEC_OK if ok, SBRDEC_UNSUPPORTED_CONFIG on error
+*/
+SBR_ERROR
+ResetLimiterBands(
+ UCHAR *limiterBandTable, /*!< Resulting band borders in QMF channels */
+ UCHAR *noLimiterBands, /*!< Resulting number of limiter band */
+ UCHAR *freqBandTable, /*!< Table with possible band borders */
+ int noFreqBands, /*!< Number of bands in freqBandTable */
+ const PATCH_PARAM *patchParam, /*!< Transposer patch parameters */
+ int noPatches, /*!< Number of transposer patches */
+ int limiterBands, /*!< Selected 'band density' from bitstream */
+ UCHAR sbrPatchingMode, int xOverQmf[MAX_NUM_PATCHES], int b41Sbr) {
+ int i, k, isPatchBorder[2], loLimIndex, hiLimIndex, tempNoLim, nBands;
+ UCHAR workLimiterBandTable[MAX_FREQ_COEFFS / 2 + MAX_NUM_PATCHES + 1];
+ int patchBorders[MAX_NUM_PATCHES + 1];
+ int kx, k2;
+
+ int lowSubband = freqBandTable[0];
+ int highSubband = freqBandTable[noFreqBands];
+
+ /* 1 limiter band. */
+ if (limiterBands == 0) {
+ limiterBandTable[0] = 0;
+ limiterBandTable[1] = highSubband - lowSubband;
+ nBands = 1;
+ } else {
+ if (!sbrPatchingMode && xOverQmf != NULL) {
+ noPatches = 0;
+
+ if (b41Sbr == 1) {
+ for (i = 1; i < MAX_NUM_PATCHES_HBE; i++)
+ if (xOverQmf[i] != 0) noPatches++;
+ } else {
+ for (i = 1; i < MAX_STRETCH_HBE; i++)
+ if (xOverQmf[i] != 0) noPatches++;
+ }
+ for (i = 0; i < noPatches; i++) {
+ patchBorders[i] = xOverQmf[i] - lowSubband;
+ }
+ } else {
+ for (i = 0; i < noPatches; i++) {
+ patchBorders[i] = patchParam[i].guardStartBand - lowSubband;
+ }
+ }
+ patchBorders[i] = highSubband - lowSubband;
+
+ /* 1.2, 2, or 3 limiter bands/octave plus bandborders at patchborders. */
+ for (k = 0; k <= noFreqBands; k++) {
+ workLimiterBandTable[k] = freqBandTable[k] - lowSubband;
+ }
+ for (k = 1; k < noPatches; k++) {
+ workLimiterBandTable[noFreqBands + k] = patchBorders[k];
+ }
+
+ tempNoLim = nBands = noFreqBands + noPatches - 1;
+ shellsort(workLimiterBandTable, tempNoLim + 1);
+
+ loLimIndex = 0;
+ hiLimIndex = 1;
+
+ while (hiLimIndex <= tempNoLim) {
+ FIXP_DBL div_m, oct_m, temp;
+ INT div_e = 0, oct_e = 0, temp_e = 0;
+
+ k2 = workLimiterBandTable[hiLimIndex] + lowSubband;
+ kx = workLimiterBandTable[loLimIndex] + lowSubband;
+
+ div_m = fDivNorm(k2, kx, &div_e);
+
+ /* calculate number of octaves */
+ oct_m = fLog2(div_m, div_e, &oct_e);
+
+ /* multiply with limiterbands per octave */
+ /* values 1, 1.2, 2, 3 -> scale factor of 2 */
+ temp = fMultNorm(
+ oct_m, FDK_sbrDecoder_sbr_limiterBandsPerOctaveDiv4_DBL[limiterBands],
+ &temp_e);
+
+ /* overall scale factor of temp ist addition of scalefactors from log2
+ calculation, limiter bands scalefactor (2) and limiter bands
+ multiplication */
+ temp_e += oct_e + 2;
+
+ /* div can be a maximum of 64 (k2 = 64 and kx = 1)
+ -> oct can be a maximum of 6
+ -> temp can be a maximum of 18 (as limiterBandsPerOctoave is a maximum
+ factor of 3)
+ -> we need a scale factor of 5 for comparisson
+ */
+ if (temp >> (5 - temp_e) < FL2FXCONST_DBL(0.49f) >> 5) {
+ if (workLimiterBandTable[hiLimIndex] ==
+ workLimiterBandTable[loLimIndex]) {
+ workLimiterBandTable[hiLimIndex] = highSubband;
+ nBands--;
+ hiLimIndex++;
+ continue;
+ }
+ isPatchBorder[0] = isPatchBorder[1] = 0;
+ for (k = 0; k <= noPatches; k++) {
+ if (workLimiterBandTable[hiLimIndex] == patchBorders[k]) {
+ isPatchBorder[1] = 1;
+ break;
+ }
+ }
+ if (!isPatchBorder[1]) {
+ workLimiterBandTable[hiLimIndex] = highSubband;
+ nBands--;
+ hiLimIndex++;
+ continue;
+ }
+ for (k = 0; k <= noPatches; k++) {
+ if (workLimiterBandTable[loLimIndex] == patchBorders[k]) {
+ isPatchBorder[0] = 1;
+ break;
+ }
+ }
+ if (!isPatchBorder[0]) {
+ workLimiterBandTable[loLimIndex] = highSubband;
+ nBands--;
+ }
+ }
+ loLimIndex = hiLimIndex;
+ hiLimIndex++;
+ }
+ shellsort(workLimiterBandTable, tempNoLim + 1);
+
+ /* Test if algorithm exceeded maximum allowed limiterbands */
+ if (nBands > MAX_NUM_LIMITERS || nBands <= 0) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ /* Copy limiterbands from working buffer into final destination */
+ for (k = 0; k <= nBands; k++) {
+ limiterBandTable[k] = workLimiterBandTable[k];
+ }
+ }
+ *noLimiterBands = nBands;
+
+ return SBRDEC_OK;
+}
diff --git a/fdk-aac/libSBRdec/src/env_calc.h b/fdk-aac/libSBRdec/src/env_calc.h
new file mode 100644
index 0000000..cff365d
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/env_calc.h
@@ -0,0 +1,182 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Envelope calculation prototypes
+*/
+#ifndef ENV_CALC_H
+#define ENV_CALC_H
+
+#include "sbrdecoder.h"
+#include "env_extr.h" /* for HANDLE_SBR_HEADER_DATA */
+
+typedef struct {
+ FIXP_DBL filtBuffer[MAX_FREQ_COEFFS]; /*!< previous gains (required for
+ smoothing) */
+ FIXP_DBL filtBufferNoise[MAX_FREQ_COEFFS]; /*!< previous noise levels
+ (required for smoothing) */
+ SCHAR filtBuffer_e[MAX_FREQ_COEFFS]; /*!< Exponents of previous gains */
+ SCHAR filtBufferNoise_e; /*!< Common exponent of previous noise levels */
+
+ int startUp; /*!< flag to signal initial conditions in buffers */
+ int phaseIndex; /*!< Index for randomPase array */
+ int prevTranEnv; /*!< The transient envelope of the previous frame. */
+
+ ULONG harmFlagsPrev[ADD_HARMONICS_FLAGS_SIZE];
+ /*!< Words with 16 flags each indicating where a sine was added in the
+ * previous frame.*/
+ UCHAR harmIndex; /*!< Current phase of synthetic sine */
+ int sbrPatchingMode; /*!< Current patching mode */
+
+ FIXP_SGL prevSbrNoiseFloorLevel[MAX_NOISE_COEFFS];
+ UCHAR prevNNfb;
+ UCHAR prevNSfb[2];
+ UCHAR prevLoSubband;
+ UCHAR prevHiSubband;
+ UCHAR prev_ov_highSubband;
+ UCHAR *prevFreqBandTable[2];
+ UCHAR prevFreqBandTableLo[MAX_FREQ_COEFFS / 2 + 1];
+ UCHAR prevFreqBandTableHi[MAX_FREQ_COEFFS + 1];
+ UCHAR prevFreqBandTableNoise[MAX_NOISE_COEFFS + 1];
+ SCHAR sinusoidal_positionPrev;
+ ULONG harmFlagsPrevActive[ADD_HARMONICS_FLAGS_SIZE];
+} SBR_CALCULATE_ENVELOPE;
+
+typedef SBR_CALCULATE_ENVELOPE *HANDLE_SBR_CALCULATE_ENVELOPE;
+
+void calculateSbrEnvelope(
+ QMF_SCALE_FACTOR *sbrScaleFactor,
+ HANDLE_SBR_CALCULATE_ENVELOPE h_sbr_cal_env,
+ HANDLE_SBR_HEADER_DATA hHeaderData, HANDLE_SBR_FRAME_DATA hFrameData,
+ PVC_DYNAMIC_DATA *pPvcDynamicData, FIXP_DBL **analysBufferReal,
+ FIXP_DBL *
+ *analysBufferImag, /*!< Imag part of subband samples to be processed */
+ const int useLP,
+ FIXP_DBL *degreeAlias, /*!< Estimated aliasing for each QMF channel */
+ const UINT flags, const int frameErrorFlag);
+
+SBR_ERROR
+createSbrEnvelopeCalc(HANDLE_SBR_CALCULATE_ENVELOPE hSbrCalculateEnvelope,
+ HANDLE_SBR_HEADER_DATA hHeaderData, const int chan,
+ const UINT flags);
+
+int deleteSbrEnvelopeCalc(HANDLE_SBR_CALCULATE_ENVELOPE hSbrCalculateEnvelope);
+
+void resetSbrEnvelopeCalc(HANDLE_SBR_CALCULATE_ENVELOPE hCalEnv);
+
+SBR_ERROR
+ResetLimiterBands(UCHAR *limiterBandTable, UCHAR *noLimiterBands,
+ UCHAR *freqBandTable, int noFreqBands,
+ const PATCH_PARAM *patchParam, int noPatches,
+ int limiterBands, UCHAR sbrPatchingMode,
+ int xOverQmf[MAX_NUM_PATCHES], int sbrRatio);
+
+void rescaleSubbandSamples(FIXP_DBL **re, FIXP_DBL **im, int lowSubband,
+ int noSubbands, int start_pos, int next_pos,
+ int shift);
+
+FIXP_DBL maxSubbandSample(FIXP_DBL **analysBufferReal_m,
+ FIXP_DBL **analysBufferImag_m, int lowSubband,
+ int highSubband, int start_pos, int stop_pos);
+
+#endif // ENV_CALC_H
diff --git a/fdk-aac/libSBRdec/src/env_dec.cpp b/fdk-aac/libSBRdec/src/env_dec.cpp
new file mode 100644
index 0000000..95807c9
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/env_dec.cpp
@@ -0,0 +1,873 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief envelope decoding
+ This module provides envelope decoding and error concealment algorithms. The
+ main entry point is decodeSbrData().
+
+ \sa decodeSbrData(),\ref documentationOverview
+*/
+
+#include "env_dec.h"
+
+#include "env_extr.h"
+#include "transcendent.h"
+
+#include "genericStds.h"
+
+static void decodeEnvelope(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA h_sbr_data,
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data,
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data_otherChannel);
+static void sbr_envelope_unmapping(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA h_data_left,
+ HANDLE_SBR_FRAME_DATA h_data_right);
+static void requantizeEnvelopeData(HANDLE_SBR_FRAME_DATA h_sbr_data,
+ int ampResolution);
+static void deltaToLinearPcmEnvelopeDecoding(
+ HANDLE_SBR_HEADER_DATA hHeaderData, HANDLE_SBR_FRAME_DATA h_sbr_data,
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data);
+static void decodeNoiseFloorlevels(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA h_sbr_data,
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data);
+static void timeCompensateFirstEnvelope(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA h_sbr_data,
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data);
+static int checkEnvelopeData(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA h_sbr_data,
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data);
+
+#define SBR_ENERGY_PAN_OFFSET (12 << ENV_EXP_FRACT)
+#define SBR_MAX_ENERGY (35 << ENV_EXP_FRACT)
+
+#define DECAY (1 << ENV_EXP_FRACT)
+
+#if ENV_EXP_FRACT
+#define DECAY_COUPLING \
+ (1 << (ENV_EXP_FRACT - 1)) /*!< corresponds to a value of 0.5 */
+#else
+#define DECAY_COUPLING \
+ 1 /*!< If the energy data is not shifted, use 1 instead of 0.5 */
+#endif
+
+/*!
+ \brief Convert table index
+*/
+static int indexLow2High(int offset, /*!< mapping factor */
+ int index, /*!< index to scalefactor band */
+ int res) /*!< frequency resolution */
+{
+ if (res == 0) {
+ if (offset >= 0) {
+ if (index < offset)
+ return (index);
+ else
+ return (2 * index - offset);
+ } else {
+ offset = -offset;
+ if (index < offset)
+ return (2 * index + index);
+ else
+ return (2 * index + offset);
+ }
+ } else
+ return (index);
+}
+
+/*!
+ \brief Update previous envelope value for delta-coding
+
+ The current envelope values needs to be stored for delta-coding
+ in the next frame. The stored envelope is always represented with
+ the high frequency resolution. If the current envelope uses the
+ low frequency resolution, the energy value will be mapped to the
+ corresponding high-res bands.
+*/
+static void mapLowResEnergyVal(
+ FIXP_SGL currVal, /*!< current energy value */
+ FIXP_SGL *prevData, /*!< pointer to previous data vector */
+ int offset, /*!< mapping factor */
+ int index, /*!< index to scalefactor band */
+ int res) /*!< frequeny resolution */
+{
+ if (res == 0) {
+ if (offset >= 0) {
+ if (index < offset)
+ prevData[index] = currVal;
+ else {
+ prevData[2 * index - offset] = currVal;
+ prevData[2 * index + 1 - offset] = currVal;
+ }
+ } else {
+ offset = -offset;
+ if (index < offset) {
+ prevData[3 * index] = currVal;
+ prevData[3 * index + 1] = currVal;
+ prevData[3 * index + 2] = currVal;
+ } else {
+ prevData[2 * index + offset] = currVal;
+ prevData[2 * index + 1 + offset] = currVal;
+ }
+ }
+ } else
+ prevData[index] = currVal;
+}
+
+/*!
+ \brief Convert raw envelope and noisefloor data to energy levels
+
+ This function is being called by sbrDecoder_ParseElement() and provides two
+ important algorithms:
+
+ First the function decodes envelopes and noise floor levels as described in
+ requantizeEnvelopeData() and sbr_envelope_unmapping(). The function also
+ implements concealment algorithms in case there are errors within the sbr
+ data. For both operations fractional arithmetic is used. Therefore you might
+ encounter different output values on your target system compared to the
+ reference implementation.
+*/
+void decodeSbrData(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA
+ h_data_left, /*!< pointer to left channel frame data */
+ HANDLE_SBR_PREV_FRAME_DATA
+ h_prev_data_left, /*!< pointer to left channel previous frame data */
+ HANDLE_SBR_FRAME_DATA
+ h_data_right, /*!< pointer to right channel frame data */
+ HANDLE_SBR_PREV_FRAME_DATA
+ h_prev_data_right) /*!< pointer to right channel previous frame data */
+{
+ FIXP_SGL tempSfbNrgPrev[MAX_FREQ_COEFFS];
+ int errLeft;
+
+ /* Save previous energy values to be able to reuse them later for concealment.
+ */
+ FDKmemcpy(tempSfbNrgPrev, h_prev_data_left->sfb_nrg_prev,
+ MAX_FREQ_COEFFS * sizeof(FIXP_SGL));
+
+ if (hHeaderData->frameErrorFlag || hHeaderData->bs_info.pvc_mode == 0) {
+ decodeEnvelope(hHeaderData, h_data_left, h_prev_data_left,
+ h_prev_data_right);
+ } else {
+ FDK_ASSERT(h_data_right == NULL);
+ }
+ decodeNoiseFloorlevels(hHeaderData, h_data_left, h_prev_data_left);
+
+ if (h_data_right != NULL) {
+ errLeft = hHeaderData->frameErrorFlag;
+ decodeEnvelope(hHeaderData, h_data_right, h_prev_data_right,
+ h_prev_data_left);
+ decodeNoiseFloorlevels(hHeaderData, h_data_right, h_prev_data_right);
+
+ if (!errLeft && hHeaderData->frameErrorFlag) {
+ /* If an error occurs in the right channel where the left channel seemed
+ ok, we apply concealment also on the left channel. This ensures that
+ the coupling modes of both channels match and that we have the same
+ number of envelopes in coupling mode. However, as the left channel has
+ already been processed before, the resulting energy levels are not the
+ same as if the left channel had been concealed during the first call of
+ decodeEnvelope().
+ */
+ /* Restore previous energy values for concealment, because the values have
+ been overwritten by the first call of decodeEnvelope(). */
+ FDKmemcpy(h_prev_data_left->sfb_nrg_prev, tempSfbNrgPrev,
+ MAX_FREQ_COEFFS * sizeof(FIXP_SGL));
+ /* Do concealment */
+ decodeEnvelope(hHeaderData, h_data_left, h_prev_data_left,
+ h_prev_data_right);
+ }
+
+ if (h_data_left->coupling) {
+ sbr_envelope_unmapping(hHeaderData, h_data_left, h_data_right);
+ }
+ }
+
+ /* Display the data for debugging: */
+}
+
+/*!
+ \brief Convert from coupled channels to independent L/R data
+*/
+static void sbr_envelope_unmapping(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_data_left, /*!< pointer to left channel */
+ HANDLE_SBR_FRAME_DATA h_data_right) /*!< pointer to right channel */
+{
+ int i;
+ FIXP_SGL tempL_m, tempR_m, tempRplus1_m, newL_m, newR_m;
+ SCHAR tempL_e, tempR_e, tempRplus1_e, newL_e, newR_e;
+
+ /* 1. Unmap (already dequantized) coupled envelope energies */
+
+ for (i = 0; i < h_data_left->nScaleFactors; i++) {
+ tempR_m = (FIXP_SGL)((LONG)h_data_right->iEnvelope[i] & MASK_M);
+ tempR_e = (SCHAR)((LONG)h_data_right->iEnvelope[i] & MASK_E);
+
+ tempR_e -= (18 + NRG_EXP_OFFSET); /* -18 = ld(UNMAPPING_SCALE /
+ h_data_right->nChannels) */
+ tempL_m = (FIXP_SGL)((LONG)h_data_left->iEnvelope[i] & MASK_M);
+ tempL_e = (SCHAR)((LONG)h_data_left->iEnvelope[i] & MASK_E);
+
+ tempL_e -= NRG_EXP_OFFSET;
+
+ /* Calculate tempRight+1 */
+ FDK_add_MantExp(tempR_m, tempR_e, FL2FXCONST_SGL(0.5f), 1, /* 1.0 */
+ &tempRplus1_m, &tempRplus1_e);
+
+ FDK_divide_MantExp(tempL_m, tempL_e + 1, /* 2 * tempLeft */
+ tempRplus1_m, tempRplus1_e, &newR_m, &newR_e);
+
+ if (newR_m >= ((FIXP_SGL)MAXVAL_SGL - ROUNDING)) {
+ newR_m >>= 1;
+ newR_e += 1;
+ }
+
+ newL_m = FX_DBL2FX_SGL(fMult(tempR_m, newR_m));
+ newL_e = tempR_e + newR_e;
+
+ h_data_right->iEnvelope[i] =
+ ((FIXP_SGL)((SHORT)(FIXP_SGL)(newR_m + ROUNDING) & MASK_M)) +
+ (FIXP_SGL)((SHORT)(FIXP_SGL)(newR_e + NRG_EXP_OFFSET) & MASK_E);
+ h_data_left->iEnvelope[i] =
+ ((FIXP_SGL)((SHORT)(FIXP_SGL)(newL_m + ROUNDING) & MASK_M)) +
+ (FIXP_SGL)((SHORT)(FIXP_SGL)(newL_e + NRG_EXP_OFFSET) & MASK_E);
+ }
+
+ /* 2. Dequantize and unmap coupled noise floor levels */
+
+ for (i = 0; i < hHeaderData->freqBandData.nNfb *
+ h_data_left->frameInfo.nNoiseEnvelopes;
+ i++) {
+ tempL_e = (SCHAR)(6 - (LONG)h_data_left->sbrNoiseFloorLevel[i]);
+ tempR_e = (SCHAR)((LONG)h_data_right->sbrNoiseFloorLevel[i] -
+ 12) /*SBR_ENERGY_PAN_OFFSET*/;
+
+ /* Calculate tempR+1 */
+ FDK_add_MantExp(FL2FXCONST_SGL(0.5f), 1 + tempR_e, /* tempR */
+ FL2FXCONST_SGL(0.5f), 1, /* 1.0 */
+ &tempRplus1_m, &tempRplus1_e);
+
+ /* Calculate 2*tempLeft/(tempR+1) */
+ FDK_divide_MantExp(FL2FXCONST_SGL(0.5f), tempL_e + 2, /* 2 * tempLeft */
+ tempRplus1_m, tempRplus1_e, &newR_m, &newR_e);
+
+ /* if (newR_m >= ((FIXP_SGL)MAXVAL_SGL - ROUNDING)) {
+ newR_m >>= 1;
+ newR_e += 1;
+ } */
+
+ /* L = tempR * R */
+ newL_m = newR_m;
+ newL_e = newR_e + tempR_e;
+ h_data_right->sbrNoiseFloorLevel[i] =
+ ((FIXP_SGL)((SHORT)(FIXP_SGL)(newR_m + ROUNDING) & MASK_M)) +
+ (FIXP_SGL)((SHORT)(FIXP_SGL)(newR_e + NOISE_EXP_OFFSET) & MASK_E);
+ h_data_left->sbrNoiseFloorLevel[i] =
+ ((FIXP_SGL)((SHORT)(FIXP_SGL)(newL_m + ROUNDING) & MASK_M)) +
+ (FIXP_SGL)((SHORT)(FIXP_SGL)(newL_e + NOISE_EXP_OFFSET) & MASK_E);
+ }
+}
+
+/*!
+ \brief Simple alternative to the real SBR concealment
+
+ If the real frameInfo is not available due to a frame loss, a replacement will
+ be constructed with 1 envelope spanning the whole frame (FIX-FIX).
+ The delta-coded energies are set to negative values, resulting in a fade-down.
+ In case of coupling, the balance-channel will move towards the center.
+*/
+static void leanSbrConcealment(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data /*!< pointer to data of last frame */
+) {
+ FIXP_SGL target; /* targeted level for sfb_nrg_prev during fade-down */
+ FIXP_SGL step; /* speed of fade */
+ int i;
+
+ int currentStartPos =
+ fMax(0, h_prev_data->stopPos - hHeaderData->numberTimeSlots);
+ int currentStopPos = hHeaderData->numberTimeSlots;
+
+ /* Use some settings of the previous frame */
+ h_sbr_data->ampResolutionCurrentFrame = h_prev_data->ampRes;
+ h_sbr_data->coupling = h_prev_data->coupling;
+ for (i = 0; i < MAX_INVF_BANDS; i++)
+ h_sbr_data->sbr_invf_mode[i] = h_prev_data->sbr_invf_mode[i];
+
+ /* Generate concealing control data */
+
+ h_sbr_data->frameInfo.nEnvelopes = 1;
+ h_sbr_data->frameInfo.borders[0] = currentStartPos;
+ h_sbr_data->frameInfo.borders[1] = currentStopPos;
+ h_sbr_data->frameInfo.freqRes[0] = 1;
+ h_sbr_data->frameInfo.tranEnv = -1; /* no transient */
+ h_sbr_data->frameInfo.nNoiseEnvelopes = 1;
+ h_sbr_data->frameInfo.bordersNoise[0] = currentStartPos;
+ h_sbr_data->frameInfo.bordersNoise[1] = currentStopPos;
+
+ h_sbr_data->nScaleFactors = hHeaderData->freqBandData.nSfb[1];
+
+ /* Generate fake envelope data */
+
+ h_sbr_data->domain_vec[0] = 1;
+
+ if (h_sbr_data->coupling == COUPLING_BAL) {
+ target = (FIXP_SGL)SBR_ENERGY_PAN_OFFSET;
+ step = (FIXP_SGL)DECAY_COUPLING;
+ } else {
+ target = FL2FXCONST_SGL(0.0f);
+ step = (FIXP_SGL)DECAY;
+ }
+ if (hHeaderData->bs_info.ampResolution == 0) {
+ target <<= 1;
+ step <<= 1;
+ }
+
+ for (i = 0; i < h_sbr_data->nScaleFactors; i++) {
+ if (h_prev_data->sfb_nrg_prev[i] > target)
+ h_sbr_data->iEnvelope[i] = -step;
+ else
+ h_sbr_data->iEnvelope[i] = step;
+ }
+
+ /* Noisefloor levels are always cleared ... */
+
+ h_sbr_data->domain_vec_noise[0] = 1;
+ FDKmemclear(h_sbr_data->sbrNoiseFloorLevel,
+ sizeof(h_sbr_data->sbrNoiseFloorLevel));
+
+ /* ... and so are the sines */
+ FDKmemclear(h_sbr_data->addHarmonics,
+ sizeof(ULONG) * ADD_HARMONICS_FLAGS_SIZE);
+}
+
+/*!
+ \brief Build reference energies and noise levels from bitstream elements
+*/
+static void decodeEnvelope(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */
+ HANDLE_SBR_PREV_FRAME_DATA
+ h_prev_data, /*!< pointer to data of last frame */
+ HANDLE_SBR_PREV_FRAME_DATA
+ otherChannel /*!< other channel's last frame data */
+) {
+ int i;
+ int fFrameError = hHeaderData->frameErrorFlag;
+ FIXP_SGL tempSfbNrgPrev[MAX_FREQ_COEFFS];
+
+ if (!fFrameError) {
+ /*
+ To avoid distortions after bad frames, set the error flag if delta coding
+ in time occurs. However, SBR can take a little longer to come up again.
+ */
+ if (h_prev_data->frameErrorFlag) {
+ if (h_sbr_data->domain_vec[0] != 0) {
+ fFrameError = 1;
+ }
+ } else {
+ /* Check that the previous stop position and the current start position
+ match. (Could be done in checkFrameInfo(), but the previous frame data
+ is not available there) */
+ if (h_sbr_data->frameInfo.borders[0] !=
+ h_prev_data->stopPos - hHeaderData->numberTimeSlots) {
+ /* Both the previous as well as the current frame are flagged to be ok,
+ * but they do not match! */
+ if (h_sbr_data->domain_vec[0] == 1) {
+ /* Prefer concealment over delta-time coding between the mismatching
+ * frames */
+ fFrameError = 1;
+ } else {
+ /* Close the gap in time by triggering timeCompensateFirstEnvelope()
+ */
+ fFrameError = 1;
+ }
+ }
+ }
+ }
+
+ if (fFrameError) /* Error is detected */
+ {
+ leanSbrConcealment(hHeaderData, h_sbr_data, h_prev_data);
+
+ /* decode the envelope data to linear PCM */
+ deltaToLinearPcmEnvelopeDecoding(hHeaderData, h_sbr_data, h_prev_data);
+ } else /*Do a temporary dummy decoding and check that the envelope values are
+ within limits */
+ {
+ if (h_prev_data->frameErrorFlag) {
+ timeCompensateFirstEnvelope(hHeaderData, h_sbr_data, h_prev_data);
+ if (h_sbr_data->coupling != h_prev_data->coupling) {
+ /*
+ Coupling mode has changed during concealment.
+ The stored energy levels need to be converted.
+ */
+ for (i = 0; i < hHeaderData->freqBandData.nSfb[1]; i++) {
+ /* Former Level-Channel will be used for both channels */
+ if (h_prev_data->coupling == COUPLING_BAL) {
+ h_prev_data->sfb_nrg_prev[i] =
+ (otherChannel != NULL) ? otherChannel->sfb_nrg_prev[i]
+ : (FIXP_SGL)SBR_ENERGY_PAN_OFFSET;
+ }
+ /* Former L/R will be combined as the new Level-Channel */
+ else if (h_sbr_data->coupling == COUPLING_LEVEL &&
+ otherChannel != NULL) {
+ h_prev_data->sfb_nrg_prev[i] = (h_prev_data->sfb_nrg_prev[i] +
+ otherChannel->sfb_nrg_prev[i]) >>
+ 1;
+ } else if (h_sbr_data->coupling == COUPLING_BAL) {
+ h_prev_data->sfb_nrg_prev[i] = (FIXP_SGL)SBR_ENERGY_PAN_OFFSET;
+ }
+ }
+ }
+ }
+ FDKmemcpy(tempSfbNrgPrev, h_prev_data->sfb_nrg_prev,
+ MAX_FREQ_COEFFS * sizeof(FIXP_SGL));
+
+ deltaToLinearPcmEnvelopeDecoding(hHeaderData, h_sbr_data, h_prev_data);
+
+ fFrameError = checkEnvelopeData(hHeaderData, h_sbr_data, h_prev_data);
+
+ if (fFrameError) {
+ hHeaderData->frameErrorFlag = 1;
+ FDKmemcpy(h_prev_data->sfb_nrg_prev, tempSfbNrgPrev,
+ MAX_FREQ_COEFFS * sizeof(FIXP_SGL));
+ decodeEnvelope(hHeaderData, h_sbr_data, h_prev_data, otherChannel);
+ return;
+ }
+ }
+
+ requantizeEnvelopeData(h_sbr_data, h_sbr_data->ampResolutionCurrentFrame);
+
+ hHeaderData->frameErrorFlag = fFrameError;
+}
+
+/*!
+ \brief Verify that envelope energies are within the allowed range
+ \return 0 if all is fine, 1 if an envelope value was too high
+*/
+static int checkEnvelopeData(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data /*!< pointer to data of last frame */
+) {
+ FIXP_SGL *iEnvelope = h_sbr_data->iEnvelope;
+ FIXP_SGL *sfb_nrg_prev = h_prev_data->sfb_nrg_prev;
+ int i = 0, errorFlag = 0;
+ FIXP_SGL sbr_max_energy = (h_sbr_data->ampResolutionCurrentFrame == 1)
+ ? SBR_MAX_ENERGY
+ : (SBR_MAX_ENERGY << 1);
+
+ /*
+ Range check for current energies
+ */
+ for (i = 0; i < h_sbr_data->nScaleFactors; i++) {
+ if (iEnvelope[i] > sbr_max_energy) {
+ errorFlag = 1;
+ }
+ if (iEnvelope[i] < FL2FXCONST_SGL(0.0f)) {
+ errorFlag = 1;
+ /* iEnvelope[i] = FL2FXCONST_SGL(0.0f); */
+ }
+ }
+
+ /*
+ Range check for previous energies
+ */
+ for (i = 0; i < hHeaderData->freqBandData.nSfb[1]; i++) {
+ sfb_nrg_prev[i] = fixMax(sfb_nrg_prev[i], FL2FXCONST_SGL(0.0f));
+ sfb_nrg_prev[i] = fixMin(sfb_nrg_prev[i], sbr_max_energy);
+ }
+
+ return (errorFlag);
+}
+
+/*!
+ \brief Verify that the noise levels are within the allowed range
+
+ The function is equivalent to checkEnvelopeData().
+ When the noise-levels are being decoded, it is already too late for
+ concealment. Therefore the noise levels are simply limited here.
+*/
+static void limitNoiseLevels(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_sbr_data) /*!< pointer to current data */
+{
+ int i;
+ int nNfb = hHeaderData->freqBandData.nNfb;
+
+/*
+ Set range limits. The exact values depend on the coupling mode.
+ However this limitation is primarily intended to avoid unlimited
+ accumulation of the delta-coded noise levels.
+*/
+#define lowerLimit \
+ ((FIXP_SGL)0) /* lowerLimit actually refers to the _highest_ noise energy */
+#define upperLimit \
+ ((FIXP_SGL)35) /* upperLimit actually refers to the _lowest_ noise energy */
+
+ /*
+ Range check for current noise levels
+ */
+ for (i = 0; i < h_sbr_data->frameInfo.nNoiseEnvelopes * nNfb; i++) {
+ h_sbr_data->sbrNoiseFloorLevel[i] =
+ fixMin(h_sbr_data->sbrNoiseFloorLevel[i], upperLimit);
+ h_sbr_data->sbrNoiseFloorLevel[i] =
+ fixMax(h_sbr_data->sbrNoiseFloorLevel[i], lowerLimit);
+ }
+}
+
+/*!
+ \brief Compensate for the wrong timing that might occur after a frame error.
+*/
+static void timeCompensateFirstEnvelope(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to actual data */
+ HANDLE_SBR_PREV_FRAME_DATA
+ h_prev_data) /*!< pointer to data of last frame */
+{
+ int i, nScalefactors;
+ FRAME_INFO *pFrameInfo = &h_sbr_data->frameInfo;
+ UCHAR *nSfb = hHeaderData->freqBandData.nSfb;
+ int estimatedStartPos =
+ fMax(0, h_prev_data->stopPos - hHeaderData->numberTimeSlots);
+ int refLen, newLen, shift;
+ FIXP_SGL deltaExp;
+
+ /* Original length of first envelope according to bitstream */
+ refLen = pFrameInfo->borders[1] - pFrameInfo->borders[0];
+ /* Corrected length of first envelope (concealing can make the first envelope
+ * longer) */
+ newLen = pFrameInfo->borders[1] - estimatedStartPos;
+
+ if (newLen <= 0) {
+ /* An envelope length of <= 0 would not work, so we don't use it.
+ May occur if the previous frame was flagged bad due to a mismatch
+ of the old and new frame infos. */
+ newLen = refLen;
+ estimatedStartPos = pFrameInfo->borders[0];
+ }
+
+ deltaExp = FDK_getNumOctavesDiv8(newLen, refLen);
+
+ /* Shift by -3 to rescale ld-table, ampRes-1 to enable coarser steps */
+ shift = (FRACT_BITS - 1 - ENV_EXP_FRACT - 1 +
+ h_sbr_data->ampResolutionCurrentFrame - 3);
+ deltaExp = deltaExp >> shift;
+ pFrameInfo->borders[0] = estimatedStartPos;
+ pFrameInfo->bordersNoise[0] = estimatedStartPos;
+
+ if (h_sbr_data->coupling != COUPLING_BAL) {
+ nScalefactors = (pFrameInfo->freqRes[0]) ? nSfb[1] : nSfb[0];
+
+ for (i = 0; i < nScalefactors; i++)
+ h_sbr_data->iEnvelope[i] = h_sbr_data->iEnvelope[i] + deltaExp;
+ }
+}
+
+/*!
+ \brief Convert each envelope value from logarithmic to linear domain
+
+ Energy levels are transmitted in powers of 2, i.e. only the exponent
+ is extracted from the bitstream.
+ Therefore, normally only integer exponents can occur. However during
+ fading (in case of a corrupt bitstream), a fractional part can also
+ occur. The data in the array iEnvelope is shifted left by ENV_EXP_FRACT
+ compared to an integer representation so that numbers smaller than 1
+ can be represented.
+
+ This function calculates a mantissa corresponding to the fractional
+ part of the exponent for each reference energy. The array iEnvelope
+ is converted in place to save memory. Input and output data must
+ be interpreted differently, as shown in the below figure:
+
+ \image html EnvelopeData.png
+
+ The data is then used in calculateSbrEnvelope().
+*/
+static void requantizeEnvelopeData(HANDLE_SBR_FRAME_DATA h_sbr_data,
+ int ampResolution) {
+ int i;
+ FIXP_SGL mantissa;
+ int ampShift = 1 - ampResolution;
+ int exponent;
+
+ /* In case that ENV_EXP_FRACT is changed to something else but 0 or 8,
+ the initialization of this array has to be adapted!
+ */
+#if ENV_EXP_FRACT
+ static const FIXP_SGL pow2[ENV_EXP_FRACT] = {
+ FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 1))), /* 0.7071 */
+ FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 2))), /* 0.5946 */
+ FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 3))),
+ FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 4))),
+ FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 5))),
+ FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 6))),
+ FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 7))),
+ FL2FXCONST_SGL(0.5f * pow(2.0f, pow(0.5f, 8))) /* 0.5013 */
+ };
+
+ int bit, mask;
+#endif
+
+ for (i = 0; i < h_sbr_data->nScaleFactors; i++) {
+ exponent = (LONG)h_sbr_data->iEnvelope[i];
+
+#if ENV_EXP_FRACT
+
+ exponent = exponent >> ampShift;
+ mantissa = 0.5f;
+
+ /* Amplify mantissa according to the fractional part of the
+ exponent (result will be between 0.500000 and 0.999999)
+ */
+ mask = 1; /* begin with lowest bit of exponent */
+
+ for (bit = ENV_EXP_FRACT - 1; bit >= 0; bit--) {
+ if (exponent & mask) {
+ /* The current bit of the exponent is set,
+ multiply mantissa with the corresponding factor: */
+ mantissa = (FIXP_SGL)((mantissa * pow2[bit]) << 1);
+ }
+ /* Advance to next bit */
+ mask = mask << 1;
+ }
+
+ /* Make integer part of exponent right aligned */
+ exponent = exponent >> ENV_EXP_FRACT;
+
+#else
+ /* In case of the high amplitude resolution, 1 bit of the exponent gets lost
+ by the shift. This will be compensated by a mantissa of 0.5*sqrt(2)
+ instead of 0.5 if that bit is 1. */
+ mantissa = (exponent & ampShift) ? FL2FXCONST_SGL(0.707106781186548f)
+ : FL2FXCONST_SGL(0.5f);
+ exponent = exponent >> ampShift;
+#endif
+
+ /*
+ Mantissa was set to 0.5 (instead of 1.0, therefore increase exponent by
+ 1). Multiply by L=nChannels=64 by increasing exponent by another 6.
+ => Increase exponent by 7
+ */
+ exponent += 7 + NRG_EXP_OFFSET;
+
+ /* Combine mantissa and exponent and write back the result */
+ h_sbr_data->iEnvelope[i] =
+ ((FIXP_SGL)((SHORT)(FIXP_SGL)mantissa & MASK_M)) +
+ (FIXP_SGL)((SHORT)(FIXP_SGL)exponent & MASK_E);
+ }
+}
+
+/*!
+ \brief Build new reference energies from old ones and delta coded data
+*/
+static void deltaToLinearPcmEnvelopeDecoding(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data) /*!< pointer to previous data */
+{
+ int i, domain, no_of_bands, band, freqRes;
+
+ FIXP_SGL *sfb_nrg_prev = h_prev_data->sfb_nrg_prev;
+ FIXP_SGL *ptr_nrg = h_sbr_data->iEnvelope;
+
+ int offset =
+ 2 * hHeaderData->freqBandData.nSfb[0] - hHeaderData->freqBandData.nSfb[1];
+
+ for (i = 0; i < h_sbr_data->frameInfo.nEnvelopes; i++) {
+ domain = h_sbr_data->domain_vec[i];
+ freqRes = h_sbr_data->frameInfo.freqRes[i];
+
+ FDK_ASSERT(freqRes >= 0 && freqRes <= 1);
+
+ no_of_bands = hHeaderData->freqBandData.nSfb[freqRes];
+
+ FDK_ASSERT(no_of_bands < (64));
+
+ if (domain == 0) {
+ mapLowResEnergyVal(*ptr_nrg, sfb_nrg_prev, offset, 0, freqRes);
+ ptr_nrg++;
+ for (band = 1; band < no_of_bands; band++) {
+ *ptr_nrg = *ptr_nrg + *(ptr_nrg - 1);
+ mapLowResEnergyVal(*ptr_nrg, sfb_nrg_prev, offset, band, freqRes);
+ ptr_nrg++;
+ }
+ } else {
+ for (band = 0; band < no_of_bands; band++) {
+ *ptr_nrg =
+ *ptr_nrg + sfb_nrg_prev[indexLow2High(offset, band, freqRes)];
+ mapLowResEnergyVal(*ptr_nrg, sfb_nrg_prev, offset, band, freqRes);
+ ptr_nrg++;
+ }
+ }
+ }
+}
+
+/*!
+ \brief Build new noise levels from old ones and delta coded data
+*/
+static void decodeNoiseFloorlevels(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_sbr_data, /*!< pointer to current data */
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data) /*!< pointer to previous data */
+{
+ int i;
+ int nNfb = hHeaderData->freqBandData.nNfb;
+ int nNoiseFloorEnvelopes = h_sbr_data->frameInfo.nNoiseEnvelopes;
+
+ /* Decode first noise envelope */
+
+ if (h_sbr_data->domain_vec_noise[0] == 0) {
+ FIXP_SGL noiseLevel = h_sbr_data->sbrNoiseFloorLevel[0];
+ for (i = 1; i < nNfb; i++) {
+ noiseLevel += h_sbr_data->sbrNoiseFloorLevel[i];
+ h_sbr_data->sbrNoiseFloorLevel[i] = noiseLevel;
+ }
+ } else {
+ for (i = 0; i < nNfb; i++) {
+ h_sbr_data->sbrNoiseFloorLevel[i] += h_prev_data->prevNoiseLevel[i];
+ }
+ }
+
+ /* If present, decode the second noise envelope
+ Note: nNoiseFloorEnvelopes can only be 1 or 2 */
+
+ if (nNoiseFloorEnvelopes > 1) {
+ if (h_sbr_data->domain_vec_noise[1] == 0) {
+ FIXP_SGL noiseLevel = h_sbr_data->sbrNoiseFloorLevel[nNfb];
+ for (i = nNfb + 1; i < 2 * nNfb; i++) {
+ noiseLevel += h_sbr_data->sbrNoiseFloorLevel[i];
+ h_sbr_data->sbrNoiseFloorLevel[i] = noiseLevel;
+ }
+ } else {
+ for (i = 0; i < nNfb; i++) {
+ h_sbr_data->sbrNoiseFloorLevel[i + nNfb] +=
+ h_sbr_data->sbrNoiseFloorLevel[i];
+ }
+ }
+ }
+
+ limitNoiseLevels(hHeaderData, h_sbr_data);
+
+ /* Update prevNoiseLevel with the last noise envelope */
+ for (i = 0; i < nNfb; i++)
+ h_prev_data->prevNoiseLevel[i] =
+ h_sbr_data->sbrNoiseFloorLevel[i + nNfb * (nNoiseFloorEnvelopes - 1)];
+
+ /* Requantize the noise floor levels in COUPLING_OFF-mode */
+ if (!h_sbr_data->coupling) {
+ int nf_e;
+
+ for (i = 0; i < nNoiseFloorEnvelopes * nNfb; i++) {
+ nf_e = 6 - (LONG)h_sbr_data->sbrNoiseFloorLevel[i] + 1 + NOISE_EXP_OFFSET;
+ /* +1 to compensate for a mantissa of 0.5 instead of 1.0 */
+
+ h_sbr_data->sbrNoiseFloorLevel[i] =
+ (FIXP_SGL)(((LONG)FL2FXCONST_SGL(0.5f)) + /* mantissa */
+ (nf_e & MASK_E)); /* exponent */
+ }
+ }
+}
diff --git a/fdk-aac/libSBRdec/src/env_dec.h b/fdk-aac/libSBRdec/src/env_dec.h
new file mode 100644
index 0000000..0b11ce1
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/env_dec.h
@@ -0,0 +1,119 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Envelope decoding
+*/
+#ifndef ENV_DEC_H
+#define ENV_DEC_H
+
+#include "sbrdecoder.h"
+#include "env_extr.h"
+
+void decodeSbrData(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA h_data_left,
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data_left,
+ HANDLE_SBR_FRAME_DATA h_data_right,
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_data_right);
+
+#endif
diff --git a/fdk-aac/libSBRdec/src/env_extr.cpp b/fdk-aac/libSBRdec/src/env_extr.cpp
new file mode 100644
index 0000000..c72a7b6
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/env_extr.cpp
@@ -0,0 +1,1728 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Envelope extraction
+ The functions provided by this module are mostly called by applySBR(). After
+ it is determined that there is valid SBR data, sbrGetHeaderData() might be
+ called if the current SBR data contains an \ref SBR_HEADER_ELEMENT as opposed
+ to a \ref SBR_STANDARD_ELEMENT. This function may return various error codes
+ as defined in #SBR_HEADER_STATUS . Most importantly it returns HEADER_RESET
+ when decoder settings need to be recalculated according to the SBR
+ specifications. In that case applySBR() will initiatite the required
+ re-configuration.
+
+ The header data is stored in a #SBR_HEADER_DATA structure.
+
+ The actual SBR data for the current frame is decoded into SBR_FRAME_DATA
+ stuctures by sbrGetChannelPairElement() [for stereo streams] and
+ sbrGetSingleChannelElement() [for mono streams]. There is no fractional
+ arithmetic involved.
+
+ Once the information is extracted, the data needs to be further prepared
+ before the actual decoding process. This is done in decodeSbrData().
+
+ \sa Description of buffer management in applySBR(). \ref documentationOverview
+
+ <h1>About the SBR data format:</h1>
+
+ Each frame includes SBR data (side chain information), and can be either the
+ \ref SBR_HEADER_ELEMENT or the \ref SBR_STANDARD_ELEMENT. Parts of the data
+ can be protected by a CRC checksum.
+
+ \anchor SBR_HEADER_ELEMENT <h2>The SBR_HEADER_ELEMENT</h2>
+
+ The SBR_HEADER_ELEMENT can be transmitted with every frame, however, it
+ typically is send every second or so. It contains fundamental information such
+ as SBR sampling frequency and frequency range as well as control signals that
+ do not require frequent changes. It also includes the \ref
+ SBR_STANDARD_ELEMENT.
+
+ Depending on the changes between the information in a current
+ SBR_HEADER_ELEMENT and the previous SBR_HEADER_ELEMENT, the SBR decoder might
+ need to be reset and reconfigured (e.g. new tables need to be calculated).
+
+ \anchor SBR_STANDARD_ELEMENT <h2>The SBR_STANDARD_ELEMENT</h2>
+
+ This data can be subdivided into "side info" and "raw data", where side info
+ is defined as signals needed to decode the raw data and some decoder tuning
+ signals. Raw data is referred to as PCM and Huffman coded envelope and noise
+ floor estimates. The side info also includes information about the
+ time-frequency grid for the current frame.
+
+ \sa \ref documentationOverview
+*/
+
+#include "env_extr.h"
+
+#include "sbr_ram.h"
+#include "sbr_rom.h"
+#include "huff_dec.h"
+
+#include "psbitdec.h"
+
+#define DRM_PARAMETRIC_STEREO 0
+#define EXTENSION_ID_PS_CODING 2
+
+static int extractPvcFrameInfo(
+ HANDLE_FDK_BITSTREAM hBs, /*!< bitbuffer handle */
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_frame_data, /*!< pointer to memory where the
+ frame-info will be stored */
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_frame_data, /*!< pointer to memory where
+ the previous frame-info
+ will be stored */
+ UCHAR pvc_mode_last, /**< PVC mode of last frame */
+ const UINT flags);
+static int extractFrameInfo(HANDLE_FDK_BITSTREAM hBs,
+ HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA h_frame_data,
+ const UINT nrOfChannels, const UINT flags);
+
+static int sbrGetPvcEnvelope(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA h_frame_data,
+ HANDLE_FDK_BITSTREAM hBs, const UINT flags,
+ const UINT pvcMode);
+static int sbrGetEnvelope(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA h_frame_data,
+ HANDLE_FDK_BITSTREAM hBs, const UINT flags);
+
+static void sbrGetDirectionControlData(HANDLE_SBR_FRAME_DATA hFrameData,
+ HANDLE_FDK_BITSTREAM hBs,
+ const UINT flags, const int bs_pvc_mode);
+
+static void sbrGetNoiseFloorData(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA h_frame_data,
+ HANDLE_FDK_BITSTREAM hBs);
+
+static int checkFrameInfo(FRAME_INFO *pFrameInfo, int numberOfTimeSlots,
+ int overlap, int timeStep);
+
+/* Mapping to std samplerate table according to 14496-3 (4.6.18.2.6) */
+typedef struct SR_MAPPING {
+ UINT fsRangeLo; /* If fsRangeLo(n+1)>fs>=fsRangeLo(n), it will be mapped to...
+ */
+ UINT fsMapped; /* fsMapped. */
+} SR_MAPPING;
+
+static const SR_MAPPING stdSampleRatesMapping[] = {
+ {0, 8000}, {9391, 11025}, {11502, 12000}, {13856, 16000},
+ {18783, 22050}, {23004, 24000}, {27713, 32000}, {37566, 44100},
+ {46009, 48000}, {55426, 64000}, {75132, 88200}, {92017, 96000}};
+static const SR_MAPPING stdSampleRatesMappingUsac[] = {
+ {0, 16000}, {18783, 22050}, {23004, 24000}, {27713, 32000},
+ {35777, 40000}, {42000, 44100}, {46009, 48000}, {55426, 64000},
+ {75132, 88200}, {92017, 96000}};
+
+UINT sbrdec_mapToStdSampleRate(UINT fs,
+ UINT isUsac) /*!< Output sampling frequency */
+{
+ UINT fsMapped = fs, tableSize = 0;
+ const SR_MAPPING *mappingTable;
+ int i;
+
+ if (!isUsac) {
+ mappingTable = stdSampleRatesMapping;
+ tableSize = sizeof(stdSampleRatesMapping) / sizeof(SR_MAPPING);
+ } else {
+ mappingTable = stdSampleRatesMappingUsac;
+ tableSize = sizeof(stdSampleRatesMappingUsac) / sizeof(SR_MAPPING);
+ }
+
+ for (i = tableSize - 1; i >= 0; i--) {
+ if (fs >= mappingTable[i].fsRangeLo) {
+ fsMapped = mappingTable[i].fsMapped;
+ break;
+ }
+ }
+
+ return (fsMapped);
+}
+
+SBR_ERROR
+initHeaderData(HANDLE_SBR_HEADER_DATA hHeaderData, const int sampleRateIn,
+ const int sampleRateOut, const INT downscaleFactor,
+ const int samplesPerFrame, const UINT flags,
+ const int setDefaultHdr) {
+ HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData;
+ SBR_ERROR sbrError = SBRDEC_OK;
+ int numAnalysisBands;
+ int sampleRateProc;
+
+ if (!(flags & (SBRDEC_SYNTAX_USAC | SBRDEC_SYNTAX_RSVD50))) {
+ sampleRateProc =
+ sbrdec_mapToStdSampleRate(sampleRateOut * downscaleFactor, 0);
+ } else {
+ sampleRateProc = sampleRateOut * downscaleFactor;
+ }
+
+ if (sampleRateIn == sampleRateOut) {
+ hHeaderData->sbrProcSmplRate = sampleRateProc << 1;
+ numAnalysisBands = 32;
+ } else {
+ hHeaderData->sbrProcSmplRate = sampleRateProc;
+ if ((sampleRateOut >> 1) == sampleRateIn) {
+ /* 1:2 */
+ numAnalysisBands = 32;
+ } else if ((sampleRateOut >> 2) == sampleRateIn) {
+ /* 1:4 */
+ numAnalysisBands = 16;
+ } else if ((sampleRateOut * 3) >> 3 == (sampleRateIn * 8) >> 3) {
+ /* 3:8, 3/4 core frame length */
+ numAnalysisBands = 24;
+ } else {
+ sbrError = SBRDEC_UNSUPPORTED_CONFIG;
+ goto bail;
+ }
+ }
+ numAnalysisBands /= downscaleFactor;
+
+ if (setDefaultHdr) {
+ /* Fill in default values first */
+ hHeaderData->syncState = SBR_NOT_INITIALIZED;
+ hHeaderData->status = 0;
+ hHeaderData->frameErrorFlag = 0;
+
+ hHeaderData->bs_info.ampResolution = 1;
+ hHeaderData->bs_info.xover_band = 0;
+ hHeaderData->bs_info.sbr_preprocessing = 0;
+ hHeaderData->bs_info.pvc_mode = 0;
+
+ hHeaderData->bs_data.startFreq = 5;
+ hHeaderData->bs_data.stopFreq = 0;
+ hHeaderData->bs_data.freqScale =
+ 0; /* previously 2; for ELD reduced delay bitstreams
+ /samplerates initializing of the sbr decoder instance fails if
+ freqScale is set to 2 because no master table can be generated; in
+ ELD reduced delay bitstreams this value is always 0; gets overwritten
+ when header is read */
+ hHeaderData->bs_data.alterScale = 1;
+ hHeaderData->bs_data.noise_bands = 2;
+ hHeaderData->bs_data.limiterBands = 2;
+ hHeaderData->bs_data.limiterGains = 2;
+ hHeaderData->bs_data.interpolFreq = 1;
+ hHeaderData->bs_data.smoothingLength = 1;
+
+ /* Patch some entries */
+ if (sampleRateOut * downscaleFactor >= 96000) {
+ hHeaderData->bs_data.startFreq =
+ 4; /* having read these frequency values from bit stream before. */
+ hHeaderData->bs_data.stopFreq = 3;
+ } else if (sampleRateOut * downscaleFactor >
+ 24000) { /* Trigger an error if SBR is going to be processed
+ without */
+ hHeaderData->bs_data.startFreq =
+ 7; /* having read these frequency values from bit stream before. */
+ hHeaderData->bs_data.stopFreq = 3;
+ }
+ }
+
+ if ((sampleRateOut >> 2) == sampleRateIn) {
+ hHeaderData->timeStep = 4;
+ } else {
+ hHeaderData->timeStep = (flags & SBRDEC_ELD_GRID) ? 1 : 2;
+ }
+
+ /* Setup pointers to frequency band tables */
+ hFreq->freqBandTable[0] = hFreq->freqBandTableLo;
+ hFreq->freqBandTable[1] = hFreq->freqBandTableHi;
+
+ /* One SBR timeslot corresponds to the amount of samples equal to the amount
+ * of analysis bands, divided by the timestep. */
+ hHeaderData->numberTimeSlots =
+ (samplesPerFrame / numAnalysisBands) >> (hHeaderData->timeStep - 1);
+ if (hHeaderData->numberTimeSlots > (16)) {
+ sbrError = SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ hHeaderData->numberOfAnalysisBands = numAnalysisBands;
+ if ((sampleRateOut >> 2) == sampleRateIn) {
+ hHeaderData->numberTimeSlots <<= 1;
+ }
+
+bail:
+ return sbrError;
+}
+
+/*!
+ \brief Initialize the SBR_PREV_FRAME_DATA struct
+*/
+void initSbrPrevFrameData(
+ HANDLE_SBR_PREV_FRAME_DATA
+ h_prev_data, /*!< handle to struct SBR_PREV_FRAME_DATA */
+ int timeSlots) /*!< Framelength in SBR-timeslots */
+{
+ int i;
+
+ /* Set previous energy and noise levels to 0 for the case
+ that decoding starts in the middle of a bitstream */
+ for (i = 0; i < MAX_FREQ_COEFFS; i++)
+ h_prev_data->sfb_nrg_prev[i] = (FIXP_DBL)0;
+ for (i = 0; i < MAX_NOISE_COEFFS; i++)
+ h_prev_data->prevNoiseLevel[i] = (FIXP_DBL)0;
+ for (i = 0; i < MAX_INVF_BANDS; i++) h_prev_data->sbr_invf_mode[i] = INVF_OFF;
+
+ h_prev_data->stopPos = timeSlots;
+ h_prev_data->coupling = COUPLING_OFF;
+ h_prev_data->ampRes = 0;
+
+ FDKmemclear(&h_prev_data->prevFrameInfo, sizeof(h_prev_data->prevFrameInfo));
+}
+
+/*!
+ \brief Read header data from bitstream
+
+ \return error status - 0 if ok
+*/
+SBR_HEADER_STATUS
+sbrGetHeaderData(HANDLE_SBR_HEADER_DATA hHeaderData, HANDLE_FDK_BITSTREAM hBs,
+ const UINT flags, const int fIsSbrData,
+ const UCHAR configMode) {
+ SBR_HEADER_DATA_BS *pBsData;
+ SBR_HEADER_DATA_BS lastHeader;
+ SBR_HEADER_DATA_BS_INFO lastInfo;
+ int headerExtra1 = 0, headerExtra2 = 0;
+
+ /* Read and discard new header in config change detection mode */
+ if (configMode & AC_CM_DET_CFG_CHANGE) {
+ if (!(flags & (SBRDEC_SYNTAX_RSVD50 | SBRDEC_SYNTAX_USAC))) {
+ /* ampResolution */
+ FDKreadBits(hBs, 1);
+ }
+ /* startFreq, stopFreq */
+ FDKpushFor(hBs, 8);
+ if (!(flags & (SBRDEC_SYNTAX_RSVD50 | SBRDEC_SYNTAX_USAC))) {
+ /* xover_band */
+ FDKreadBits(hBs, 3);
+ /* reserved bits */
+ FDKreadBits(hBs, 2);
+ }
+ headerExtra1 = FDKreadBit(hBs);
+ headerExtra2 = FDKreadBit(hBs);
+ FDKpushFor(hBs, 5 * headerExtra1 + 6 * headerExtra2);
+
+ return HEADER_OK;
+ }
+
+ /* Copy SBR bit stream header to temporary header */
+ lastHeader = hHeaderData->bs_data;
+ lastInfo = hHeaderData->bs_info;
+
+ /* Read new header from bitstream */
+ if ((flags & (SBRDEC_SYNTAX_RSVD50 | SBRDEC_SYNTAX_USAC)) && !fIsSbrData) {
+ pBsData = &hHeaderData->bs_dflt;
+ } else {
+ pBsData = &hHeaderData->bs_data;
+ }
+
+ if (!(flags & (SBRDEC_SYNTAX_RSVD50 | SBRDEC_SYNTAX_USAC))) {
+ hHeaderData->bs_info.ampResolution = FDKreadBits(hBs, 1);
+ }
+
+ pBsData->startFreq = FDKreadBits(hBs, 4);
+ pBsData->stopFreq = FDKreadBits(hBs, 4);
+
+ if (!(flags & (SBRDEC_SYNTAX_RSVD50 | SBRDEC_SYNTAX_USAC))) {
+ hHeaderData->bs_info.xover_band = FDKreadBits(hBs, 3);
+ FDKreadBits(hBs, 2);
+ }
+
+ headerExtra1 = FDKreadBits(hBs, 1);
+ headerExtra2 = FDKreadBits(hBs, 1);
+
+ /* Handle extra header information */
+ if (headerExtra1) {
+ pBsData->freqScale = FDKreadBits(hBs, 2);
+ pBsData->alterScale = FDKreadBits(hBs, 1);
+ pBsData->noise_bands = FDKreadBits(hBs, 2);
+ } else {
+ pBsData->freqScale = 2;
+ pBsData->alterScale = 1;
+ pBsData->noise_bands = 2;
+ }
+
+ if (headerExtra2) {
+ pBsData->limiterBands = FDKreadBits(hBs, 2);
+ pBsData->limiterGains = FDKreadBits(hBs, 2);
+ pBsData->interpolFreq = FDKreadBits(hBs, 1);
+ pBsData->smoothingLength = FDKreadBits(hBs, 1);
+ } else {
+ pBsData->limiterBands = 2;
+ pBsData->limiterGains = 2;
+ pBsData->interpolFreq = 1;
+ pBsData->smoothingLength = 1;
+ }
+
+ /* Look for new settings. IEC 14496-3, 4.6.18.3.1 */
+ if (hHeaderData->syncState < SBR_HEADER ||
+ lastHeader.startFreq != pBsData->startFreq ||
+ lastHeader.stopFreq != pBsData->stopFreq ||
+ lastHeader.freqScale != pBsData->freqScale ||
+ lastHeader.alterScale != pBsData->alterScale ||
+ lastHeader.noise_bands != pBsData->noise_bands ||
+ lastInfo.xover_band != hHeaderData->bs_info.xover_band) {
+ return HEADER_RESET; /* New settings */
+ }
+
+ return HEADER_OK;
+}
+
+/*!
+ \brief Get missing harmonics parameters (only used for AAC+SBR)
+
+ \return error status - 0 if ok
+*/
+int sbrGetSyntheticCodedData(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA hFrameData,
+ HANDLE_FDK_BITSTREAM hBs, const UINT flags) {
+ int i, bitsRead = 0;
+
+ int add_harmonic_flag = FDKreadBits(hBs, 1);
+ bitsRead++;
+
+ if (add_harmonic_flag) {
+ int nSfb = hHeaderData->freqBandData.nSfb[1];
+ for (i = 0; i < ADD_HARMONICS_FLAGS_SIZE; i++) {
+ /* read maximum 32 bits and align them to the MSB */
+ int readBits = fMin(32, nSfb);
+ nSfb -= readBits;
+ if (readBits > 0) {
+ hFrameData->addHarmonics[i] = FDKreadBits(hBs, readBits)
+ << (32 - readBits);
+ } else {
+ hFrameData->addHarmonics[i] = 0;
+ }
+
+ bitsRead += readBits;
+ }
+ /* bs_pvc_mode = 0 for Rsvd50 */
+ if (flags & SBRDEC_SYNTAX_USAC) {
+ if (hHeaderData->bs_info.pvc_mode) {
+ int bs_sinusoidal_position = 31;
+ if (FDKreadBit(hBs) /* bs_sinusoidal_position_flag */) {
+ bs_sinusoidal_position = FDKreadBits(hBs, 5);
+ }
+ hFrameData->sinusoidal_position = bs_sinusoidal_position;
+ }
+ }
+ } else {
+ for (i = 0; i < ADD_HARMONICS_FLAGS_SIZE; i++)
+ hFrameData->addHarmonics[i] = 0;
+ }
+
+ return (bitsRead);
+}
+
+/*!
+ \brief Reads extension data from the bitstream
+
+ The bitstream format allows up to 4 kinds of extended data element.
+ Extended data may contain several elements, each identified by a 2-bit-ID.
+ So far, no extended data elements are defined hence the first 2 parameters
+ are unused. The data should be skipped in order to update the number
+ of read bits for the consistency check in applySBR().
+*/
+static int extractExtendedData(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< handle to SBR header */
+ HANDLE_FDK_BITSTREAM hBs /*!< Handle to the bit buffer */
+ ,
+ HANDLE_PS_DEC hParametricStereoDec /*!< Parametric Stereo Decoder */
+) {
+ INT nBitsLeft;
+ int extended_data;
+ int i, frameOk = 1;
+
+ extended_data = FDKreadBits(hBs, 1);
+
+ if (extended_data) {
+ int cnt;
+ int bPsRead = 0;
+
+ cnt = FDKreadBits(hBs, 4);
+ if (cnt == (1 << 4) - 1) cnt += FDKreadBits(hBs, 8);
+
+ nBitsLeft = 8 * cnt;
+
+ /* sanity check for cnt */
+ if (nBitsLeft > (INT)FDKgetValidBits(hBs)) {
+ /* limit nBitsLeft */
+ nBitsLeft = (INT)FDKgetValidBits(hBs);
+ /* set frame error */
+ frameOk = 0;
+ }
+
+ while (nBitsLeft > 7) {
+ int extension_id = FDKreadBits(hBs, 2);
+ nBitsLeft -= 2;
+
+ switch (extension_id) {
+ case EXTENSION_ID_PS_CODING:
+
+ /* Read PS data from bitstream */
+
+ if (hParametricStereoDec != NULL) {
+ if (bPsRead &&
+ !hParametricStereoDec->bsData[hParametricStereoDec->bsReadSlot]
+ .mpeg.bPsHeaderValid) {
+ cnt = nBitsLeft >> 3; /* number of remaining bytes */
+ for (i = 0; i < cnt; i++) FDKreadBits(hBs, 8);
+ nBitsLeft -= cnt * 8;
+ } else {
+ nBitsLeft -=
+ (INT)ReadPsData(hParametricStereoDec, hBs, nBitsLeft);
+ bPsRead = 1;
+ }
+ }
+
+ /* parametric stereo detected, could set channelMode accordingly here
+ */
+ /* */
+ /* "The usage of this parametric stereo extension to HE-AAC is */
+ /* signalled implicitly in the bitstream. Hence, if an sbr_extension()
+ */
+ /* with bs_extension_id==EXTENSION_ID_PS is found in the SBR part of
+ */
+ /* the bitstream, a decoder supporting the combination of SBR and PS
+ */
+ /* shall operate the PS tool to generate a stereo output signal." */
+ /* source: ISO/IEC 14496-3:2001/FDAM 2:2004(E) */
+
+ break;
+
+ default:
+ cnt = nBitsLeft >> 3; /* number of remaining bytes */
+ for (i = 0; i < cnt; i++) FDKreadBits(hBs, 8);
+ nBitsLeft -= cnt * 8;
+ break;
+ }
+ }
+
+ if (nBitsLeft < 0) {
+ frameOk = 0;
+ goto bail;
+ } else {
+ /* Read fill bits for byte alignment */
+ FDKreadBits(hBs, nBitsLeft);
+ }
+ }
+
+bail:
+ return (frameOk);
+}
+
+/*!
+ \brief Read bitstream elements of a SBR channel element
+ \return SbrFrameOK
+*/
+int sbrGetChannelElement(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA hFrameDataLeft,
+ HANDLE_SBR_FRAME_DATA hFrameDataRight,
+ HANDLE_SBR_PREV_FRAME_DATA hFrameDataLeftPrev,
+ UCHAR pvc_mode_last, HANDLE_FDK_BITSTREAM hBs,
+ HANDLE_PS_DEC hParametricStereoDec, const UINT flags,
+ const int overlap) {
+ int i, bs_coupling = COUPLING_OFF;
+ const int nCh = (hFrameDataRight == NULL) ? 1 : 2;
+
+ if (!(flags & (SBRDEC_SYNTAX_USAC | SBRDEC_SYNTAX_RSVD50))) {
+ /* Reserved bits */
+ if (FDKreadBits(hBs, 1)) { /* bs_data_extra */
+ FDKreadBits(hBs, 4);
+ if ((flags & SBRDEC_SYNTAX_SCAL) || (nCh == 2)) {
+ FDKreadBits(hBs, 4);
+ }
+ }
+ }
+
+ if (nCh == 2) {
+ /* Read coupling flag */
+ bs_coupling = FDKreadBits(hBs, 1);
+ if (bs_coupling) {
+ hFrameDataLeft->coupling = COUPLING_LEVEL;
+ hFrameDataRight->coupling = COUPLING_BAL;
+ } else {
+ hFrameDataLeft->coupling = COUPLING_OFF;
+ hFrameDataRight->coupling = COUPLING_OFF;
+ }
+ } else {
+ if (flags & SBRDEC_SYNTAX_SCAL) {
+ FDKreadBits(hBs, 1); /* bs_coupling */
+ }
+ hFrameDataLeft->coupling = COUPLING_OFF;
+ }
+
+ if (flags & (SBRDEC_SYNTAX_USAC | SBRDEC_SYNTAX_RSVD50)) {
+ if (flags & SBRDEC_USAC_HARMONICSBR) {
+ hFrameDataLeft->sbrPatchingMode = FDKreadBit(hBs);
+ if (hFrameDataLeft->sbrPatchingMode == 0) {
+ hFrameDataLeft->sbrOversamplingFlag = FDKreadBit(hBs);
+ if (FDKreadBit(hBs)) { /* sbrPitchInBinsFlag */
+ hFrameDataLeft->sbrPitchInBins = FDKreadBits(hBs, 7);
+ } else {
+ hFrameDataLeft->sbrPitchInBins = 0;
+ }
+ } else {
+ hFrameDataLeft->sbrOversamplingFlag = 0;
+ hFrameDataLeft->sbrPitchInBins = 0;
+ }
+
+ if (nCh == 2) {
+ if (bs_coupling) {
+ hFrameDataRight->sbrPatchingMode = hFrameDataLeft->sbrPatchingMode;
+ hFrameDataRight->sbrOversamplingFlag =
+ hFrameDataLeft->sbrOversamplingFlag;
+ hFrameDataRight->sbrPitchInBins = hFrameDataLeft->sbrPitchInBins;
+ } else {
+ hFrameDataRight->sbrPatchingMode = FDKreadBit(hBs);
+ if (hFrameDataRight->sbrPatchingMode == 0) {
+ hFrameDataRight->sbrOversamplingFlag = FDKreadBit(hBs);
+ if (FDKreadBit(hBs)) { /* sbrPitchInBinsFlag */
+ hFrameDataRight->sbrPitchInBins = FDKreadBits(hBs, 7);
+ } else {
+ hFrameDataRight->sbrPitchInBins = 0;
+ }
+ } else {
+ hFrameDataRight->sbrOversamplingFlag = 0;
+ hFrameDataRight->sbrPitchInBins = 0;
+ }
+ }
+ }
+ } else {
+ if (nCh == 2) {
+ hFrameDataRight->sbrPatchingMode = 1;
+ hFrameDataRight->sbrOversamplingFlag = 0;
+ hFrameDataRight->sbrPitchInBins = 0;
+ }
+
+ hFrameDataLeft->sbrPatchingMode = 1;
+ hFrameDataLeft->sbrOversamplingFlag = 0;
+ hFrameDataLeft->sbrPitchInBins = 0;
+ }
+ } else {
+ if (nCh == 2) {
+ hFrameDataRight->sbrPatchingMode = 1;
+ hFrameDataRight->sbrOversamplingFlag = 0;
+ hFrameDataRight->sbrPitchInBins = 0;
+ }
+
+ hFrameDataLeft->sbrPatchingMode = 1;
+ hFrameDataLeft->sbrOversamplingFlag = 0;
+ hFrameDataLeft->sbrPitchInBins = 0;
+ }
+
+ /*
+ sbr_grid(): Grid control
+ */
+ if (hHeaderData->bs_info.pvc_mode) {
+ FDK_ASSERT(nCh == 1); /* PVC not possible for CPE */
+ if (!extractPvcFrameInfo(hBs, hHeaderData, hFrameDataLeft,
+ hFrameDataLeftPrev, pvc_mode_last, flags))
+ return 0;
+
+ if (!checkFrameInfo(&hFrameDataLeft->frameInfo,
+ hHeaderData->numberTimeSlots, overlap,
+ hHeaderData->timeStep))
+ return 0;
+ } else {
+ if (!extractFrameInfo(hBs, hHeaderData, hFrameDataLeft, 1, flags)) return 0;
+
+ if (!checkFrameInfo(&hFrameDataLeft->frameInfo,
+ hHeaderData->numberTimeSlots, overlap,
+ hHeaderData->timeStep))
+ return 0;
+ }
+ if (nCh == 2) {
+ if (hFrameDataLeft->coupling) {
+ FDKmemcpy(&hFrameDataRight->frameInfo, &hFrameDataLeft->frameInfo,
+ sizeof(FRAME_INFO));
+ hFrameDataRight->ampResolutionCurrentFrame =
+ hFrameDataLeft->ampResolutionCurrentFrame;
+ } else {
+ if (!extractFrameInfo(hBs, hHeaderData, hFrameDataRight, 2, flags))
+ return 0;
+
+ if (!checkFrameInfo(&hFrameDataRight->frameInfo,
+ hHeaderData->numberTimeSlots, overlap,
+ hHeaderData->timeStep))
+ return 0;
+ }
+ }
+
+ /*
+ sbr_dtdf(): Fetch domain vectors (time or frequency direction for
+ delta-coding)
+ */
+ sbrGetDirectionControlData(hFrameDataLeft, hBs, flags,
+ hHeaderData->bs_info.pvc_mode);
+ if (nCh == 2) {
+ sbrGetDirectionControlData(hFrameDataRight, hBs, flags, 0);
+ }
+
+ /* sbr_invf() */
+ for (i = 0; i < hHeaderData->freqBandData.nInvfBands; i++) {
+ hFrameDataLeft->sbr_invf_mode[i] = (INVF_MODE)FDKreadBits(hBs, 2);
+ }
+ if (nCh == 2) {
+ if (hFrameDataLeft->coupling) {
+ for (i = 0; i < hHeaderData->freqBandData.nInvfBands; i++) {
+ hFrameDataRight->sbr_invf_mode[i] = hFrameDataLeft->sbr_invf_mode[i];
+ }
+ } else {
+ for (i = 0; i < hHeaderData->freqBandData.nInvfBands; i++) {
+ hFrameDataRight->sbr_invf_mode[i] = (INVF_MODE)FDKreadBits(hBs, 2);
+ }
+ }
+ }
+
+ if (nCh == 1) {
+ if (hHeaderData->bs_info.pvc_mode) {
+ if (!sbrGetPvcEnvelope(hHeaderData, hFrameDataLeft, hBs, flags,
+ hHeaderData->bs_info.pvc_mode))
+ return 0;
+ } else if (!sbrGetEnvelope(hHeaderData, hFrameDataLeft, hBs, flags))
+ return 0;
+
+ sbrGetNoiseFloorData(hHeaderData, hFrameDataLeft, hBs);
+ } else if (hFrameDataLeft->coupling) {
+ if (!sbrGetEnvelope(hHeaderData, hFrameDataLeft, hBs, flags)) {
+ return 0;
+ }
+
+ sbrGetNoiseFloorData(hHeaderData, hFrameDataLeft, hBs);
+
+ if (!sbrGetEnvelope(hHeaderData, hFrameDataRight, hBs, flags)) {
+ return 0;
+ }
+ sbrGetNoiseFloorData(hHeaderData, hFrameDataRight, hBs);
+ } else { /* nCh == 2 && no coupling */
+
+ if (!sbrGetEnvelope(hHeaderData, hFrameDataLeft, hBs, flags)) return 0;
+
+ if (!sbrGetEnvelope(hHeaderData, hFrameDataRight, hBs, flags)) return 0;
+
+ sbrGetNoiseFloorData(hHeaderData, hFrameDataLeft, hBs);
+
+ sbrGetNoiseFloorData(hHeaderData, hFrameDataRight, hBs);
+ }
+
+ sbrGetSyntheticCodedData(hHeaderData, hFrameDataLeft, hBs, flags);
+ if (nCh == 2) {
+ sbrGetSyntheticCodedData(hHeaderData, hFrameDataRight, hBs, flags);
+ }
+
+ if (!(flags & (SBRDEC_SYNTAX_USAC | SBRDEC_SYNTAX_RSVD50))) {
+ if (!extractExtendedData(hHeaderData, hBs, hParametricStereoDec)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*!
+ \brief Read direction control data from bitstream
+*/
+void sbrGetDirectionControlData(
+ HANDLE_SBR_FRAME_DATA h_frame_data, /*!< handle to struct SBR_FRAME_DATA */
+ HANDLE_FDK_BITSTREAM hBs, /*!< handle to struct BIT_BUF */
+ const UINT flags, const int bs_pvc_mode)
+
+{
+ int i;
+ int indepFlag = 0;
+
+ if (flags & (SBRDEC_SYNTAX_USAC | SBRDEC_SYNTAX_RSVD50)) {
+ indepFlag = flags & SBRDEC_USAC_INDEP;
+ }
+
+ if (bs_pvc_mode == 0) {
+ i = 0;
+ if (indepFlag) {
+ h_frame_data->domain_vec[i++] = 0;
+ }
+ for (; i < h_frame_data->frameInfo.nEnvelopes; i++) {
+ h_frame_data->domain_vec[i] = FDKreadBits(hBs, 1);
+ }
+ }
+
+ i = 0;
+ if (indepFlag) {
+ h_frame_data->domain_vec_noise[i++] = 0;
+ }
+ for (; i < h_frame_data->frameInfo.nNoiseEnvelopes; i++) {
+ h_frame_data->domain_vec_noise[i] = FDKreadBits(hBs, 1);
+ }
+}
+
+/*!
+ \brief Read noise-floor-level data from bitstream
+*/
+void sbrGetNoiseFloorData(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_frame_data, /*!< handle to struct SBR_FRAME_DATA */
+ HANDLE_FDK_BITSTREAM hBs) /*!< handle to struct BIT_BUF */
+{
+ int i, j;
+ int delta;
+ COUPLING_MODE coupling;
+ int noNoiseBands = hHeaderData->freqBandData.nNfb;
+
+ Huffman hcb_noiseF;
+ Huffman hcb_noise;
+ int envDataTableCompFactor;
+
+ coupling = h_frame_data->coupling;
+
+ /*
+ Select huffman codebook depending on coupling mode
+ */
+ if (coupling == COUPLING_BAL) {
+ hcb_noise = (Huffman)&FDK_sbrDecoder_sbr_huffBook_NoiseBalance11T;
+ hcb_noiseF =
+ (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance11F; /* "sbr_huffBook_NoiseBalance11F"
+ */
+ envDataTableCompFactor = 1;
+ } else {
+ hcb_noise = (Huffman)&FDK_sbrDecoder_sbr_huffBook_NoiseLevel11T;
+ hcb_noiseF =
+ (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel11F; /* "sbr_huffBook_NoiseLevel11F"
+ */
+ envDataTableCompFactor = 0;
+ }
+
+ /*
+ Read raw noise-envelope data
+ */
+ for (i = 0; i < h_frame_data->frameInfo.nNoiseEnvelopes; i++) {
+ if (h_frame_data->domain_vec_noise[i] == 0) {
+ if (coupling == COUPLING_BAL) {
+ h_frame_data->sbrNoiseFloorLevel[i * noNoiseBands] =
+ (FIXP_SGL)(((int)FDKreadBits(hBs, 5)) << envDataTableCompFactor);
+ } else {
+ h_frame_data->sbrNoiseFloorLevel[i * noNoiseBands] =
+ (FIXP_SGL)(int)FDKreadBits(hBs, 5);
+ }
+
+ for (j = 1; j < noNoiseBands; j++) {
+ delta = DecodeHuffmanCW(hcb_noiseF, hBs);
+ h_frame_data->sbrNoiseFloorLevel[i * noNoiseBands + j] =
+ (FIXP_SGL)(delta << envDataTableCompFactor);
+ }
+ } else {
+ for (j = 0; j < noNoiseBands; j++) {
+ delta = DecodeHuffmanCW(hcb_noise, hBs);
+ h_frame_data->sbrNoiseFloorLevel[i * noNoiseBands + j] =
+ (FIXP_SGL)(delta << envDataTableCompFactor);
+ }
+ }
+ }
+}
+
+/* ns = mapNsMode2ns[pvcMode-1][nsMode] */
+static const UCHAR mapNsMode2ns[2][2] = {
+ {16, 4}, /* pvcMode = 1 */
+ {12, 3} /* pvcMode = 2 */
+};
+
+static int sbrGetPvcEnvelope(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_frame_data, /*!< handle to struct SBR_FRAME_DATA */
+ HANDLE_FDK_BITSTREAM hBs, /*!< handle to struct BIT_BUF */
+ const UINT flags, const UINT pvcMode) {
+ int divMode, nsMode;
+ int indepFlag = flags & SBRDEC_USAC_INDEP;
+ UCHAR *pvcID = h_frame_data->pvcID;
+
+ divMode = FDKreadBits(hBs, PVC_DIVMODE_BITS);
+ nsMode = FDKreadBit(hBs);
+ FDK_ASSERT((pvcMode == 1) || (pvcMode == 2));
+ h_frame_data->ns = mapNsMode2ns[pvcMode - 1][nsMode];
+
+ if (divMode <= 3) {
+ int i, k = 1, sum_length = 0, reuse_pcvID;
+
+ /* special treatment for first time slot k=0 */
+ indepFlag ? (reuse_pcvID = 0) : (reuse_pcvID = FDKreadBit(hBs));
+ if (reuse_pcvID) {
+ pvcID[0] = hHeaderData->pvcIDprev;
+ } else {
+ pvcID[0] = FDKreadBits(hBs, PVC_PVCID_BITS);
+ }
+
+ /* other time slots k>0 */
+ for (i = 0; i < divMode; i++) {
+ int length, numBits = 4;
+
+ if (sum_length >= 13) {
+ numBits = 1;
+ } else if (sum_length >= 11) {
+ numBits = 2;
+ } else if (sum_length >= 7) {
+ numBits = 3;
+ }
+
+ length = FDKreadBits(hBs, numBits);
+ sum_length += length + 1;
+ if (sum_length >= PVC_NTIMESLOT) {
+ return 0; /* parse error */
+ }
+ for (; length--; k++) {
+ pvcID[k] = pvcID[k - 1];
+ }
+ pvcID[k++] = FDKreadBits(hBs, PVC_PVCID_BITS);
+ }
+ for (; k < 16; k++) {
+ pvcID[k] = pvcID[k - 1];
+ }
+ } else { /* divMode >= 4 */
+ int num_grid_info, fixed_length, grid_info, j, k = 0;
+
+ divMode -= 4;
+ num_grid_info = 2 << divMode;
+ fixed_length = 8 >> divMode;
+ FDK_ASSERT(num_grid_info * fixed_length == PVC_NTIMESLOT);
+
+ /* special treatment for first time slot k=0 */
+ indepFlag ? (grid_info = 1) : (grid_info = FDKreadBit(hBs));
+ if (grid_info) {
+ pvcID[k++] = FDKreadBits(hBs, PVC_PVCID_BITS);
+ } else {
+ pvcID[k++] = hHeaderData->pvcIDprev;
+ }
+ j = fixed_length - 1;
+ for (; j--; k++) {
+ pvcID[k] = pvcID[k - 1];
+ }
+ num_grid_info--;
+
+ /* other time slots k>0 */
+ for (; num_grid_info--;) {
+ j = fixed_length;
+ grid_info = FDKreadBit(hBs);
+ if (grid_info) {
+ pvcID[k++] = FDKreadBits(hBs, PVC_PVCID_BITS);
+ j--;
+ }
+ for (; j--; k++) {
+ pvcID[k] = pvcID[k - 1];
+ }
+ }
+ }
+
+ hHeaderData->pvcIDprev = pvcID[PVC_NTIMESLOT - 1];
+
+ /* usage of PVC excludes inter-TES tool */
+ h_frame_data->iTESactive = (UCHAR)0;
+
+ return 1;
+}
+/*!
+ \brief Read envelope data from bitstream
+*/
+static int sbrGetEnvelope(
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_frame_data, /*!< handle to struct SBR_FRAME_DATA */
+ HANDLE_FDK_BITSTREAM hBs, /*!< handle to struct BIT_BUF */
+ const UINT flags) {
+ int i, j;
+ UCHAR no_band[MAX_ENVELOPES];
+ int delta = 0;
+ int offset = 0;
+ COUPLING_MODE coupling = h_frame_data->coupling;
+ int ampRes = hHeaderData->bs_info.ampResolution;
+ int nEnvelopes = h_frame_data->frameInfo.nEnvelopes;
+ int envDataTableCompFactor;
+ int start_bits, start_bits_balance;
+ Huffman hcb_t, hcb_f;
+
+ h_frame_data->nScaleFactors = 0;
+
+ if ((h_frame_data->frameInfo.frameClass == 0) && (nEnvelopes == 1)) {
+ if (flags & SBRDEC_ELD_GRID)
+ ampRes = h_frame_data->ampResolutionCurrentFrame;
+ else
+ ampRes = 0;
+ }
+ h_frame_data->ampResolutionCurrentFrame = ampRes;
+
+ /*
+ Set number of bits for first value depending on amplitude resolution
+ */
+ if (ampRes == 1) {
+ start_bits = 6;
+ start_bits_balance = 5;
+ } else {
+ start_bits = 7;
+ start_bits_balance = 6;
+ }
+
+ /*
+ Calculate number of values for each envelope and alltogether
+ */
+ for (i = 0; i < nEnvelopes; i++) {
+ no_band[i] =
+ hHeaderData->freqBandData.nSfb[h_frame_data->frameInfo.freqRes[i]];
+ h_frame_data->nScaleFactors += no_band[i];
+ }
+ if (h_frame_data->nScaleFactors > MAX_NUM_ENVELOPE_VALUES) return 0;
+
+ /*
+ Select Huffman codebook depending on coupling mode and amplitude resolution
+ */
+ if (coupling == COUPLING_BAL) {
+ envDataTableCompFactor = 1;
+ if (ampRes == 0) {
+ hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance10T;
+ hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance10F;
+ } else {
+ hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance11T;
+ hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvBalance11F;
+ }
+ } else {
+ envDataTableCompFactor = 0;
+ if (ampRes == 0) {
+ hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel10T;
+ hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel10F;
+ } else {
+ hcb_t = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel11T;
+ hcb_f = (Huffman)&FDK_sbrDecoder_sbr_huffBook_EnvLevel11F;
+ }
+ }
+
+ h_frame_data->iTESactive = (UCHAR)0; /* disable inter-TES by default */
+ /*
+ Now read raw envelope data
+ */
+ for (j = 0, offset = 0; j < nEnvelopes; j++) {
+ if (h_frame_data->domain_vec[j] == 0) {
+ if (coupling == COUPLING_BAL) {
+ h_frame_data->iEnvelope[offset] =
+ (FIXP_SGL)(((int)FDKreadBits(hBs, start_bits_balance))
+ << envDataTableCompFactor);
+ } else {
+ h_frame_data->iEnvelope[offset] =
+ (FIXP_SGL)(int)FDKreadBits(hBs, start_bits);
+ }
+ }
+
+ for (i = (1 - h_frame_data->domain_vec[j]); i < no_band[j]; i++) {
+ if (h_frame_data->domain_vec[j] == 0) {
+ delta = DecodeHuffmanCW(hcb_f, hBs);
+ } else {
+ delta = DecodeHuffmanCW(hcb_t, hBs);
+ }
+
+ h_frame_data->iEnvelope[offset + i] =
+ (FIXP_SGL)(delta << envDataTableCompFactor);
+ }
+ if ((flags & SBRDEC_SYNTAX_USAC) && (flags & SBRDEC_USAC_ITES)) {
+ int bs_temp_shape = FDKreadBit(hBs);
+ FDK_ASSERT(j < 8);
+ h_frame_data->iTESactive |= (UCHAR)(bs_temp_shape << j);
+ if (bs_temp_shape) {
+ h_frame_data->interTempShapeMode[j] =
+ FDKread2Bits(hBs); /* bs_inter_temp_shape_mode */
+ } else {
+ h_frame_data->interTempShapeMode[j] = 0;
+ }
+ }
+ offset += no_band[j];
+ }
+
+#if ENV_EXP_FRACT
+ /* Convert from int to scaled fract (ENV_EXP_FRACT bits for the fractional
+ * part) */
+ for (i = 0; i < h_frame_data->nScaleFactors; i++) {
+ h_frame_data->iEnvelope[i] <<= ENV_EXP_FRACT;
+ }
+#endif
+
+ return 1;
+}
+
+/***************************************************************************/
+/*!
+ \brief Generates frame info for FIXFIXonly frame class used for low delay
+ version
+
+ \return zero for error, one for correct.
+ ****************************************************************************/
+static int generateFixFixOnly(FRAME_INFO *hSbrFrameInfo, int tranPosInternal,
+ int numberTimeSlots, const UINT flags) {
+ int nEnv, i, tranIdx;
+ const int *pTable;
+
+ switch (numberTimeSlots) {
+ case 8:
+ pTable = FDK_sbrDecoder_envelopeTable_8[tranPosInternal];
+ break;
+ case 15:
+ pTable = FDK_sbrDecoder_envelopeTable_15[tranPosInternal];
+ break;
+ case 16:
+ pTable = FDK_sbrDecoder_envelopeTable_16[tranPosInternal];
+ break;
+ default:
+ return 0;
+ }
+
+ /* look number of envelopes in table */
+ nEnv = pTable[0];
+ /* look up envelope distribution in table */
+ for (i = 1; i < nEnv; i++) hSbrFrameInfo->borders[i] = pTable[i + 2];
+ /* open and close frame border */
+ hSbrFrameInfo->borders[0] = 0;
+ hSbrFrameInfo->borders[nEnv] = numberTimeSlots;
+ hSbrFrameInfo->nEnvelopes = nEnv;
+
+ /* transient idx */
+ tranIdx = hSbrFrameInfo->tranEnv = pTable[1];
+
+ /* add noise floors */
+ hSbrFrameInfo->bordersNoise[0] = 0;
+ hSbrFrameInfo->bordersNoise[1] =
+ hSbrFrameInfo->borders[tranIdx ? tranIdx : 1];
+ hSbrFrameInfo->bordersNoise[2] = numberTimeSlots;
+ /* nEnv is always > 1, so nNoiseEnvelopes is always 2 (IEC 14496-3 4.6.19.3.2)
+ */
+ hSbrFrameInfo->nNoiseEnvelopes = 2;
+
+ return 1;
+}
+
+/*!
+ \brief Extracts LowDelaySBR control data from the bitstream.
+
+ \return zero for bitstream error, one for correct.
+*/
+static int extractLowDelayGrid(
+ HANDLE_FDK_BITSTREAM hBitBuf, /*!< bitbuffer handle */
+ HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA
+ h_frame_data, /*!< contains the FRAME_INFO struct to be filled */
+ int timeSlots, const UINT flags) {
+ FRAME_INFO *pFrameInfo = &h_frame_data->frameInfo;
+ INT numberTimeSlots = hHeaderData->numberTimeSlots;
+ INT temp = 0, k;
+
+ /* FIXFIXonly framing case */
+ h_frame_data->frameInfo.frameClass = 0;
+
+ /* get the transient position from the bitstream */
+ switch (timeSlots) {
+ case 8:
+ /* 3bit transient position (temp={0;..;7}) */
+ temp = FDKreadBits(hBitBuf, 3);
+ break;
+
+ case 16:
+ case 15:
+ /* 4bit transient position (temp={0;..;15}) */
+ temp = FDKreadBits(hBitBuf, 4);
+ break;
+
+ default:
+ return 0;
+ }
+
+ /* For "case 15" only*/
+ if (temp >= timeSlots) {
+ return 0;
+ }
+
+ /* calculate borders according to the transient position */
+ if (!generateFixFixOnly(pFrameInfo, temp, numberTimeSlots, flags)) {
+ return 0;
+ }
+
+ /* decode freq res: */
+ for (k = 0; k < pFrameInfo->nEnvelopes; k++) {
+ pFrameInfo->freqRes[k] =
+ (UCHAR)FDKreadBits(hBitBuf, 1); /* f = F [1 bits] */
+ }
+
+ return 1;
+}
+
+/*!
+ \brief Extract the PVC frame information (structure FRAME_INFO) from the
+ bitstream \return Zero for bitstream error, one for correct.
+*/
+int extractPvcFrameInfo(
+ HANDLE_FDK_BITSTREAM hBs, /*!< bitbuffer handle */
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_frame_data, /*!< pointer to memory where the
+ frame-info will be stored */
+ HANDLE_SBR_PREV_FRAME_DATA h_prev_frame_data, /*!< pointer to memory where
+ the previous frame-info
+ will be stored */
+ UCHAR pvc_mode_last, /**< PVC mode of last frame */
+ const UINT flags) {
+ FRAME_INFO *pFrameInfo = &h_frame_data->frameInfo;
+ FRAME_INFO *pPrevFrameInfo = &h_prev_frame_data->prevFrameInfo;
+ int bs_var_len_hf, bs_noise_position;
+ bs_noise_position = FDKreadBits(hBs, 4); /* SBR_PVC_NOISEPOSITION_BITS 4 */
+ bs_var_len_hf = FDKreadBit(hBs);
+ pFrameInfo->noisePosition = bs_noise_position;
+ pFrameInfo->tranEnv = -1;
+
+ /* Init for bs_noise_position == 0 in case a parse error is found below. */
+ pFrameInfo->nEnvelopes = 1;
+ pFrameInfo->nNoiseEnvelopes = 1;
+ pFrameInfo->freqRes[0] = 0;
+
+ if (bs_var_len_hf) { /* 1 or 3 Bits */
+ pFrameInfo->varLength = FDKreadBits(hBs, 2) + 1;
+ if (pFrameInfo->varLength > 3) {
+ pFrameInfo->varLength =
+ 0; /* assume bs_var_len_hf == 0 in case of error */
+ return 0; /* reserved value -> parse error */
+ }
+ } else {
+ pFrameInfo->varLength = 0;
+ }
+
+ if (bs_noise_position) {
+ pFrameInfo->nEnvelopes = 2;
+ pFrameInfo->nNoiseEnvelopes = 2;
+ FDKmemclear(pFrameInfo->freqRes, sizeof(pFrameInfo->freqRes));
+ }
+
+ /* frame border calculation */
+ if (hHeaderData->bs_info.pvc_mode > 0) {
+ /* See "7.5.1.4 HF adjustment of SBR envelope scalefactors" for reference.
+ */
+
+ FDK_ASSERT((pFrameInfo->nEnvelopes == 1) || (pFrameInfo->nEnvelopes == 2));
+
+ /* left timeborder-offset: use the timeborder of prev SBR frame */
+ if (pPrevFrameInfo->nEnvelopes > 0) {
+ pFrameInfo->borders[0] =
+ pPrevFrameInfo->borders[pPrevFrameInfo->nEnvelopes] - PVC_NTIMESLOT;
+ FDK_ASSERT(pFrameInfo->borders[0] <= 3);
+ } else {
+ pFrameInfo->borders[0] = 0;
+ }
+
+ /* right timeborder-offset: */
+ pFrameInfo->borders[pFrameInfo->nEnvelopes] = 16 + pFrameInfo->varLength;
+
+ if (pFrameInfo->nEnvelopes == 2) {
+ pFrameInfo->borders[1] = pFrameInfo->noisePosition;
+ }
+
+ /* Calculation of PVC time borders t_EPVC */
+ if (pvc_mode_last == 0) {
+ /* there was a legacy SBR frame before this frame => use bs_var_len' for
+ * first PVC timeslot */
+ pFrameInfo->pvcBorders[0] = pFrameInfo->borders[0];
+ } else {
+ pFrameInfo->pvcBorders[0] = 0;
+ }
+ if (pFrameInfo->nEnvelopes == 2) {
+ pFrameInfo->pvcBorders[1] = pFrameInfo->borders[1];
+ }
+ pFrameInfo->pvcBorders[pFrameInfo->nEnvelopes] = 16;
+
+ /* calculation of SBR noise-floor time-border vector: */
+ for (INT i = 0; i <= pFrameInfo->nNoiseEnvelopes; i++) {
+ pFrameInfo->bordersNoise[i] = pFrameInfo->borders[i];
+ }
+
+ pFrameInfo->tranEnv = -1; /* tranEnv not used */
+ }
+ return 1;
+}
+
+/*!
+ \brief Extract the frame information (structure FRAME_INFO) from the
+ bitstream \return Zero for bitstream error, one for correct.
+*/
+int extractFrameInfo(
+ HANDLE_FDK_BITSTREAM hBs, /*!< bitbuffer handle */
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA h_frame_data, /*!< pointer to memory where the
+ frame-info will be stored */
+ const UINT nrOfChannels, const UINT flags) {
+ FRAME_INFO *pFrameInfo = &h_frame_data->frameInfo;
+ int numberTimeSlots = hHeaderData->numberTimeSlots;
+ int pointer_bits = 0, nEnv = 0, b = 0, border, i, n = 0, k, p, aL, aR, nL, nR,
+ temp = 0, staticFreqRes;
+ UCHAR frameClass;
+
+ if (flags & SBRDEC_ELD_GRID) {
+ /* CODEC_AACLD (LD+SBR) only uses the normal 0 Grid for non-transient Frames
+ * and the LowDelayGrid for transient Frames */
+ frameClass = FDKreadBits(hBs, 1); /* frameClass = [1 bit] */
+ if (frameClass == 1) {
+ /* if frameClass == 1, extract LowDelaySbrGrid, otherwise extract normal
+ * SBR-Grid for FIXIFX */
+ /* extract the AACLD-Sbr-Grid */
+ pFrameInfo->frameClass = frameClass;
+ int err = 1;
+ err = extractLowDelayGrid(hBs, hHeaderData, h_frame_data, numberTimeSlots,
+ flags);
+ return err;
+ }
+ } else {
+ frameClass = FDKreadBits(hBs, 2); /* frameClass = C [2 bits] */
+ }
+
+ switch (frameClass) {
+ case 0:
+ temp = FDKreadBits(hBs, 2); /* E [2 bits ] */
+ nEnv = (int)(1 << temp); /* E -> e */
+
+ if ((flags & SBRDEC_ELD_GRID) && (nEnv == 1))
+ h_frame_data->ampResolutionCurrentFrame =
+ FDKreadBits(hBs, 1); /* new ELD Syntax 07-11-09 */
+
+ staticFreqRes = FDKreadBits(hBs, 1);
+
+ if (flags & (SBRDEC_SYNTAX_USAC | SBRDEC_SYNTAX_RSVD50)) {
+ if (nEnv > MAX_ENVELOPES_USAC) return 0;
+ } else
+
+ b = nEnv + 1;
+ switch (nEnv) {
+ case 1:
+ switch (numberTimeSlots) {
+ case 15:
+ FDKmemcpy(pFrameInfo, &FDK_sbrDecoder_sbr_frame_info1_15,
+ sizeof(FRAME_INFO));
+ break;
+ case 16:
+ FDKmemcpy(pFrameInfo, &FDK_sbrDecoder_sbr_frame_info1_16,
+ sizeof(FRAME_INFO));
+ break;
+ default:
+ FDK_ASSERT(0);
+ }
+ break;
+ case 2:
+ switch (numberTimeSlots) {
+ case 15:
+ FDKmemcpy(pFrameInfo, &FDK_sbrDecoder_sbr_frame_info2_15,
+ sizeof(FRAME_INFO));
+ break;
+ case 16:
+ FDKmemcpy(pFrameInfo, &FDK_sbrDecoder_sbr_frame_info2_16,
+ sizeof(FRAME_INFO));
+ break;
+ default:
+ FDK_ASSERT(0);
+ }
+ break;
+ case 4:
+ switch (numberTimeSlots) {
+ case 15:
+ FDKmemcpy(pFrameInfo, &FDK_sbrDecoder_sbr_frame_info4_15,
+ sizeof(FRAME_INFO));
+ break;
+ case 16:
+ FDKmemcpy(pFrameInfo, &FDK_sbrDecoder_sbr_frame_info4_16,
+ sizeof(FRAME_INFO));
+ break;
+ default:
+ FDK_ASSERT(0);
+ }
+ break;
+ case 8:
+#if (MAX_ENVELOPES >= 8)
+ switch (numberTimeSlots) {
+ case 15:
+ FDKmemcpy(pFrameInfo, &FDK_sbrDecoder_sbr_frame_info8_15,
+ sizeof(FRAME_INFO));
+ break;
+ case 16:
+ FDKmemcpy(pFrameInfo, &FDK_sbrDecoder_sbr_frame_info8_16,
+ sizeof(FRAME_INFO));
+ break;
+ default:
+ FDK_ASSERT(0);
+ }
+ break;
+#else
+ return 0;
+#endif
+ }
+ /* Apply correct freqRes (High is default) */
+ if (!staticFreqRes) {
+ for (i = 0; i < nEnv; i++) pFrameInfo->freqRes[i] = 0;
+ }
+
+ break;
+ case 1:
+ case 2:
+ temp = FDKreadBits(hBs, 2); /* A [2 bits] */
+
+ n = FDKreadBits(hBs, 2); /* n = N [2 bits] */
+
+ nEnv = n + 1; /* # envelopes */
+ b = nEnv + 1; /* # borders */
+
+ break;
+ }
+
+ switch (frameClass) {
+ case 1:
+ /* Decode borders: */
+ pFrameInfo->borders[0] = 0; /* first border */
+ border = temp + numberTimeSlots; /* A -> aR */
+ i = b - 1; /* frame info index for last border */
+ pFrameInfo->borders[i] = border; /* last border */
+
+ for (k = 0; k < n; k++) {
+ temp = FDKreadBits(hBs, 2); /* R [2 bits] */
+ border -= (2 * temp + 2); /* R -> r */
+ pFrameInfo->borders[--i] = border;
+ }
+
+ /* Decode pointer: */
+ pointer_bits = DFRACT_BITS - 1 - CountLeadingBits((FIXP_DBL)(n + 1));
+ p = FDKreadBits(hBs, pointer_bits); /* p = P [pointer_bits bits] */
+
+ if (p > n + 1) return 0;
+
+ pFrameInfo->tranEnv = p ? n + 2 - p : -1;
+
+ /* Decode freq res: */
+ for (k = n; k >= 0; k--) {
+ pFrameInfo->freqRes[k] = FDKreadBits(hBs, 1); /* f = F [1 bits] */
+ }
+
+ /* Calculate noise floor middle border: */
+ if (p == 0 || p == 1)
+ pFrameInfo->bordersNoise[1] = pFrameInfo->borders[n];
+ else
+ pFrameInfo->bordersNoise[1] = pFrameInfo->borders[pFrameInfo->tranEnv];
+
+ break;
+
+ case 2:
+ /* Decode borders: */
+ border = temp; /* A -> aL */
+ pFrameInfo->borders[0] = border; /* first border */
+
+ for (k = 1; k <= n; k++) {
+ temp = FDKreadBits(hBs, 2); /* R [2 bits] */
+ border += (2 * temp + 2); /* R -> r */
+ pFrameInfo->borders[k] = border;
+ }
+ pFrameInfo->borders[k] = numberTimeSlots; /* last border */
+
+ /* Decode pointer: */
+ pointer_bits = DFRACT_BITS - 1 - CountLeadingBits((FIXP_DBL)(n + 1));
+ p = FDKreadBits(hBs, pointer_bits); /* p = P [pointer_bits bits] */
+ if (p > n + 1) return 0;
+
+ if (p == 0 || p == 1)
+ pFrameInfo->tranEnv = -1;
+ else
+ pFrameInfo->tranEnv = p - 1;
+
+ /* Decode freq res: */
+ for (k = 0; k <= n; k++) {
+ pFrameInfo->freqRes[k] = FDKreadBits(hBs, 1); /* f = F [1 bits] */
+ }
+
+ /* Calculate noise floor middle border: */
+ switch (p) {
+ case 0:
+ pFrameInfo->bordersNoise[1] = pFrameInfo->borders[1];
+ break;
+ case 1:
+ pFrameInfo->bordersNoise[1] = pFrameInfo->borders[n];
+ break;
+ default:
+ pFrameInfo->bordersNoise[1] =
+ pFrameInfo->borders[pFrameInfo->tranEnv];
+ break;
+ }
+
+ break;
+
+ case 3:
+ /* v_ctrlSignal = [frameClass,aL,aR,nL,nR,v_rL,v_rR,p,v_fLR]; */
+
+ aL = FDKreadBits(hBs, 2); /* AL [2 bits], AL -> aL */
+
+ aR = FDKreadBits(hBs, 2) + numberTimeSlots; /* AR [2 bits], AR -> aR */
+
+ nL = FDKreadBits(hBs, 2); /* nL = NL [2 bits] */
+
+ nR = FDKreadBits(hBs, 2); /* nR = NR [2 bits] */
+
+ /*-------------------------------------------------------------------------
+ Calculate help variables
+ --------------------------------------------------------------------------*/
+
+ /* general: */
+ nEnv = nL + nR + 1; /* # envelopes */
+ if (nEnv > MAX_ENVELOPES) return 0;
+ b = nEnv + 1; /* # borders */
+
+ /*-------------------------------------------------------------------------
+ Decode envelopes
+ --------------------------------------------------------------------------*/
+
+ /* L-borders: */
+ border = aL; /* first border */
+ pFrameInfo->borders[0] = border;
+
+ for (k = 1; k <= nL; k++) {
+ temp = FDKreadBits(hBs, 2); /* R [2 bits] */
+ border += (2 * temp + 2); /* R -> r */
+ pFrameInfo->borders[k] = border;
+ }
+
+ /* R-borders: */
+ border = aR; /* last border */
+ i = nEnv;
+
+ pFrameInfo->borders[i] = border;
+
+ for (k = 0; k < nR; k++) {
+ temp = FDKreadBits(hBs, 2); /* R [2 bits] */
+ border -= (2 * temp + 2); /* R -> r */
+ pFrameInfo->borders[--i] = border;
+ }
+
+ /* decode pointer: */
+ pointer_bits =
+ DFRACT_BITS - 1 - CountLeadingBits((FIXP_DBL)(nL + nR + 1));
+ p = FDKreadBits(hBs, pointer_bits); /* p = P [pointer_bits bits] */
+
+ if (p > nL + nR + 1) return 0;
+
+ pFrameInfo->tranEnv = p ? b - p : -1;
+
+ /* decode freq res: */
+ for (k = 0; k < nEnv; k++) {
+ pFrameInfo->freqRes[k] = FDKreadBits(hBs, 1); /* f = F [1 bits] */
+ }
+
+ /*-------------------------------------------------------------------------
+ Decode noise floors
+ --------------------------------------------------------------------------*/
+ pFrameInfo->bordersNoise[0] = aL;
+
+ if (nEnv == 1) {
+ /* 1 noise floor envelope: */
+ pFrameInfo->bordersNoise[1] = aR;
+ } else {
+ /* 2 noise floor envelopes */
+ if (p == 0 || p == 1)
+ pFrameInfo->bordersNoise[1] = pFrameInfo->borders[nEnv - 1];
+ else
+ pFrameInfo->bordersNoise[1] =
+ pFrameInfo->borders[pFrameInfo->tranEnv];
+ pFrameInfo->bordersNoise[2] = aR;
+ }
+ break;
+ }
+
+ /*
+ Store number of envelopes, noise floor envelopes and frame class
+ */
+ pFrameInfo->nEnvelopes = nEnv;
+
+ if (nEnv == 1)
+ pFrameInfo->nNoiseEnvelopes = 1;
+ else
+ pFrameInfo->nNoiseEnvelopes = 2;
+
+ pFrameInfo->frameClass = frameClass;
+
+ if (pFrameInfo->frameClass == 2 || pFrameInfo->frameClass == 1) {
+ /* calculate noise floor first and last borders: */
+ pFrameInfo->bordersNoise[0] = pFrameInfo->borders[0];
+ pFrameInfo->bordersNoise[pFrameInfo->nNoiseEnvelopes] =
+ pFrameInfo->borders[nEnv];
+ }
+
+ return 1;
+}
+
+/*!
+ \brief Check if the frameInfo vector has reasonable values.
+ \return Zero for error, one for correct
+*/
+static int checkFrameInfo(
+ FRAME_INFO *pFrameInfo, /*!< pointer to frameInfo */
+ int numberOfTimeSlots, /*!< QMF time slots per frame */
+ int overlap, /*!< Amount of overlap QMF time slots */
+ int timeStep) /*!< QMF slots to SBR slots step factor */
+{
+ int maxPos, i, j;
+ int startPos;
+ int stopPos;
+ int tranEnv;
+ int startPosNoise;
+ int stopPosNoise;
+ int nEnvelopes = pFrameInfo->nEnvelopes;
+ int nNoiseEnvelopes = pFrameInfo->nNoiseEnvelopes;
+
+ if (nEnvelopes < 1 || nEnvelopes > MAX_ENVELOPES) return 0;
+
+ if (nNoiseEnvelopes > MAX_NOISE_ENVELOPES) return 0;
+
+ startPos = pFrameInfo->borders[0];
+ stopPos = pFrameInfo->borders[nEnvelopes];
+ tranEnv = pFrameInfo->tranEnv;
+ startPosNoise = pFrameInfo->bordersNoise[0];
+ stopPosNoise = pFrameInfo->bordersNoise[nNoiseEnvelopes];
+
+ if (overlap < 0 || overlap > (3 * (4))) {
+ return 0;
+ }
+ if (timeStep < 1 || timeStep > (4)) {
+ return 0;
+ }
+ maxPos = numberOfTimeSlots + (overlap / timeStep);
+
+ /* Check that the start and stop positions of the frame are reasonable values.
+ */
+ if ((startPos < 0) || (startPos >= stopPos)) return 0;
+ if (startPos > maxPos - numberOfTimeSlots) /* First env. must start in or
+ directly after the overlap
+ buffer */
+ return 0;
+ if (stopPos < numberOfTimeSlots) /* One complete frame must be ready for
+ output after processing */
+ return 0;
+ if (stopPos > maxPos) return 0;
+
+ /* Check that the start border for every envelope is strictly later in time
+ */
+ for (i = 0; i < nEnvelopes; i++) {
+ if (pFrameInfo->borders[i] >= pFrameInfo->borders[i + 1]) return 0;
+ }
+
+ /* Check that the envelope to be shortened is actually among the envelopes */
+ if (tranEnv > nEnvelopes) return 0;
+
+ /* Check the noise borders */
+ if (nEnvelopes == 1 && nNoiseEnvelopes > 1) return 0;
+
+ if (startPos != startPosNoise || stopPos != stopPosNoise) return 0;
+
+ /* Check that the start border for every noise-envelope is strictly later in
+ * time*/
+ for (i = 0; i < nNoiseEnvelopes; i++) {
+ if (pFrameInfo->bordersNoise[i] >= pFrameInfo->bordersNoise[i + 1])
+ return 0;
+ }
+
+ /* Check that every noise border is the same as an envelope border*/
+ for (i = 0; i < nNoiseEnvelopes; i++) {
+ startPosNoise = pFrameInfo->bordersNoise[i];
+
+ for (j = 0; j < nEnvelopes; j++) {
+ if (pFrameInfo->borders[j] == startPosNoise) break;
+ }
+ if (j == nEnvelopes) return 0;
+ }
+
+ return 1;
+}
diff --git a/fdk-aac/libSBRdec/src/env_extr.h b/fdk-aac/libSBRdec/src/env_extr.h
new file mode 100644
index 0000000..38c04a3
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/env_extr.h
@@ -0,0 +1,415 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Envelope extraction prototypes
+*/
+
+#ifndef ENV_EXTR_H
+#define ENV_EXTR_H
+
+#include "sbrdecoder.h"
+
+#include "FDK_bitstream.h"
+#include "lpp_tran.h"
+
+#include "psdec.h"
+#include "pvc_dec.h"
+
+#define ENV_EXP_FRACT 0
+/*!< Shift raw envelope data to support fractional numbers.
+ Can be set to 8 instead of 0 to enhance accuracy during concealment.
+ This is not required for conformance and #requantizeEnvelopeData() will
+ become more expensive.
+*/
+
+#define EXP_BITS 6
+/*!< Size of exponent-part of a pseudo float envelope value (should be at least
+ 6). The remaining bits in each word are used for the mantissa (should be at
+ least 10). This format is used in the arrays iEnvelope[] and
+ sbrNoiseFloorLevel[] in the FRAME_DATA struct which must fit in a certain part
+ of the output buffer (See buffer management in sbr_dec.cpp). Exponents and
+ mantissas could also be stored in separate arrays. Accessing the exponent or
+ the mantissa would be simplified and the masks #MASK_E resp. #MASK_M would
+ no longer be required.
+*/
+
+#define MASK_M \
+ (((1 << (FRACT_BITS - EXP_BITS)) - 1) \
+ << EXP_BITS) /*!< Mask for extracting the mantissa of a pseudo float \
+ envelope value */
+#define MASK_E \
+ ((1 << EXP_BITS) - 1) /*!< Mask for extracting the exponent of a pseudo \
+ float envelope value */
+
+#define SIGN_EXT \
+ (((SCHAR)-1) ^ \
+ MASK_E) /*!< a CHAR-constant with all bits above our sign-bit set */
+#define ROUNDING \
+ ((FIXP_SGL)( \
+ 1 << (EXP_BITS - 1))) /*!< 0.5-offset for rounding the mantissa of a \
+ pseudo-float envelope value */
+#define NRG_EXP_OFFSET \
+ 16 /*!< Will be added to the reference energy's exponent to prevent negative \
+ numbers */
+#define NOISE_EXP_OFFSET \
+ 38 /*!< Will be added to the noise level exponent to prevent negative \
+ numbers */
+
+#define ADD_HARMONICS_FLAGS_SIZE 2 /* ceil(MAX_FREQ_COEFFS/32) */
+
+typedef enum {
+ HEADER_NOT_PRESENT,
+ HEADER_ERROR,
+ HEADER_OK,
+ HEADER_RESET
+} SBR_HEADER_STATUS;
+
+typedef enum {
+ SBR_NOT_INITIALIZED = 0,
+ UPSAMPLING = 1,
+ SBR_HEADER = 2,
+ SBR_ACTIVE = 3
+} SBR_SYNC_STATE;
+
+typedef enum { COUPLING_OFF = 0, COUPLING_LEVEL, COUPLING_BAL } COUPLING_MODE;
+
+typedef struct {
+ UCHAR nSfb[2]; /*!< Number of SBR-bands for low and high freq-resolution */
+ UCHAR nNfb; /*!< Actual number of noise bands to read from the bitstream*/
+ UCHAR numMaster; /*!< Number of SBR-bands in v_k_master */
+ UCHAR lowSubband; /*!< QMF-band where SBR frequency range starts */
+ UCHAR highSubband; /*!< QMF-band where SBR frequency range ends */
+ UCHAR ov_highSubband; /*!< if headerchange applies this value holds the old
+ highband value -> highband value of overlap area;
+ required for overlap in usac when headerchange
+ occurs between XVAR and VARX frame */
+ UCHAR limiterBandTable[MAX_NUM_LIMITERS + 1]; /*!< Limiter band table. */
+ UCHAR noLimiterBands; /*!< Number of limiter bands. */
+ UCHAR nInvfBands; /*!< Number of bands for inverse filtering */
+ UCHAR
+ *freqBandTable[2]; /*!< Pointers to freqBandTableLo and freqBandTableHi */
+ UCHAR freqBandTableLo[MAX_FREQ_COEFFS / 2 + 1];
+ /*!< Mapping of SBR bands to QMF bands for low frequency resolution */
+ UCHAR freqBandTableHi[MAX_FREQ_COEFFS + 1];
+ /*!< Mapping of SBR bands to QMF bands for high frequency resolution */
+ UCHAR freqBandTableNoise[MAX_NOISE_COEFFS + 1];
+ /*!< Mapping of SBR noise bands to QMF bands */
+ UCHAR v_k_master[MAX_FREQ_COEFFS + 1];
+ /*!< Master BandTable which freqBandTable is derived from */
+} FREQ_BAND_DATA;
+
+typedef FREQ_BAND_DATA *HANDLE_FREQ_BAND_DATA;
+
+#define SBRDEC_ELD_GRID 1
+#define SBRDEC_SYNTAX_SCAL 2
+#define SBRDEC_SYNTAX_USAC 4
+#define SBRDEC_SYNTAX_RSVD50 8
+#define SBRDEC_USAC_INDEP \
+ 16 /* Flag indicating that USAC global independency flag is active. */
+#define SBRDEC_LOW_POWER \
+ 32 /* Flag indicating that Low Power QMF mode shall be used. */
+#define SBRDEC_PS_DECODED \
+ 64 /* Flag indicating that PS was decoded and rendered. */
+#define SBRDEC_QUAD_RATE \
+ 128 /* Flag indicating that USAC SBR 4:1 is active. \
+ */
+#define SBRDEC_USAC_HARMONICSBR \
+ 256 /* Flag indicating that USAC HBE tool is active. */
+#define SBRDEC_LD_MPS_QMF \
+ 512 /* Flag indicating that the LD-MPS QMF shall be used. */
+#define SBRDEC_USAC_ITES \
+ 1024 /* Flag indicating that USAC inter TES tool is active. */
+#define SBRDEC_SYNTAX_DRM \
+ 2048 /* Flag indicating that DRM30/DRM+ reverse syntax is being used. */
+#define SBRDEC_ELD_DOWNSCALE \
+ 4096 /* Flag indicating that ELD downscaled mode decoding is used */
+#define SBRDEC_DOWNSAMPLE \
+ 8192 /* Flag indicating that the downsampling mode is used. */
+#define SBRDEC_FLUSH 16384 /* Flag is used to flush all elements in use. */
+#define SBRDEC_FORCE_RESET \
+ 32768 /* Flag is used to force a reset of all elements in use. */
+#define SBRDEC_SKIP_QMF_ANA \
+ (1 << 21) /* Flag indicating that the input data is provided in the QMF \
+ domain. */
+#define SBRDEC_SKIP_QMF_SYN \
+ (1 << 22) /* Flag indicating that the output data is exported in the QMF \
+ domain. */
+
+#define SBRDEC_HDR_STAT_RESET 1
+#define SBRDEC_HDR_STAT_UPDATE 2
+
+typedef struct {
+ UCHAR ampResolution; /*!< Amplitude resolution of envelope values (0: 1.5dB,
+ 1: 3dB) */
+ UCHAR
+ xover_band; /*!< Start index in #v_k_master[] used for dynamic crossover
+ frequency */
+ UCHAR sbr_preprocessing; /*!< SBR prewhitening flag. */
+ UCHAR pvc_mode; /*!< Predictive vector coding mode */
+} SBR_HEADER_DATA_BS_INFO;
+
+typedef struct {
+ /* Changes in these variables causes a reset of the decoder */
+ UCHAR startFreq; /*!< Index for SBR start frequency */
+ UCHAR stopFreq; /*!< Index for SBR highest frequency */
+ UCHAR freqScale; /*!< 0: linear scale, 1-3 logarithmic scales */
+ UCHAR alterScale; /*!< Flag for coarser frequency resolution */
+ UCHAR noise_bands; /*!< Noise bands per octave, read from bitstream*/
+
+ /* don't require reset */
+ UCHAR limiterBands; /*!< Index for number of limiter bands per octave */
+ UCHAR limiterGains; /*!< Index to select gain limit */
+ UCHAR interpolFreq; /*!< Select gain calculation method (1: per QMF channel,
+ 0: per SBR band) */
+ UCHAR smoothingLength; /*!< Smoothing of gains over time (0: on 1: off) */
+
+} SBR_HEADER_DATA_BS;
+
+typedef struct {
+ SBR_SYNC_STATE
+ syncState; /*!< The current initialization status of the header */
+
+ UCHAR status; /*!< Flags field used for signaling a reset right before the
+ processing starts and an update from config (e.g. ASC). */
+ UCHAR
+ frameErrorFlag; /*!< Frame data valid flag. CAUTION: This variable will be
+ overwritten by the flag stored in the element
+ structure. This is necessary because of the frame
+ delay. There it might happen that different slots use
+ the same header. */
+ UCHAR numberTimeSlots; /*!< AAC: 16,15 */
+ UCHAR numberOfAnalysisBands; /*!< Number of QMF analysis bands */
+ UCHAR timeStep; /*!< Time resolution of SBR in QMF-slots */
+ UINT
+ sbrProcSmplRate; /*!< SBR processing sampling frequency (!=
+ OutputSamplingRate) (always: CoreSamplingRate *
+ UpSamplingFactor; even in single rate mode) */
+
+ SBR_HEADER_DATA_BS bs_data; /*!< current SBR header. */
+ SBR_HEADER_DATA_BS bs_dflt; /*!< Default sbr header. */
+ SBR_HEADER_DATA_BS_INFO bs_info; /*!< SBR info. */
+
+ FREQ_BAND_DATA freqBandData; /*!< Pointer to struct #FREQ_BAND_DATA */
+ UCHAR pvcIDprev;
+} SBR_HEADER_DATA;
+
+typedef SBR_HEADER_DATA *HANDLE_SBR_HEADER_DATA;
+
+typedef struct {
+ UCHAR frameClass; /*!< Select grid type */
+ UCHAR nEnvelopes; /*!< Number of envelopes */
+ UCHAR borders[MAX_ENVELOPES + 1]; /*!< Envelope borders (in SBR-timeslots,
+ e.g. mp3PRO: 0..11) */
+ UCHAR freqRes[MAX_ENVELOPES]; /*!< Frequency resolution for each envelope
+ (0=low, 1=high) */
+ SCHAR tranEnv; /*!< Transient envelope, -1 if none */
+ UCHAR nNoiseEnvelopes; /*!< Number of noise envelopes */
+ UCHAR
+ bordersNoise[MAX_NOISE_ENVELOPES + 1]; /*!< borders of noise envelopes */
+ UCHAR pvcBorders[MAX_PVC_ENVELOPES + 1];
+ UCHAR noisePosition;
+ UCHAR varLength;
+} FRAME_INFO;
+
+typedef struct {
+ FIXP_SGL sfb_nrg_prev[MAX_FREQ_COEFFS]; /*!< Previous envelope (required for
+ differential-coded values) */
+ FIXP_SGL
+ prevNoiseLevel[MAX_NOISE_COEFFS]; /*!< Previous noise envelope (required
+ for differential-coded values) */
+ COUPLING_MODE coupling; /*!< Stereo-mode of previous frame */
+ INVF_MODE sbr_invf_mode[MAX_INVF_BANDS]; /*!< Previous strength of filtering
+ in transposer */
+ UCHAR ampRes; /*!< Previous amplitude resolution (0: 1.5dB, 1: 3dB) */
+ UCHAR stopPos; /*!< Position in time where last envelope ended */
+ UCHAR frameErrorFlag; /*!< Previous frame status */
+ UCHAR prevSbrPitchInBins; /*!< Previous frame pitchInBins */
+ FRAME_INFO prevFrameInfo;
+} SBR_PREV_FRAME_DATA;
+
+typedef SBR_PREV_FRAME_DATA *HANDLE_SBR_PREV_FRAME_DATA;
+
+typedef struct {
+ int nScaleFactors; /*!< total number of scalefactors in frame */
+
+ FRAME_INFO frameInfo; /*!< time grid for current frame */
+ UCHAR domain_vec[MAX_ENVELOPES]; /*!< Bitfield containing direction of
+ delta-coding for each envelope
+ (0:frequency, 1:time) */
+ UCHAR domain_vec_noise
+ [MAX_NOISE_ENVELOPES]; /*!< Same as above, but for noise envelopes */
+
+ INVF_MODE
+ sbr_invf_mode[MAX_INVF_BANDS]; /*!< Strength of filtering in transposer */
+ COUPLING_MODE coupling; /*!< Stereo-mode */
+ int ampResolutionCurrentFrame; /*!< Amplitude resolution of envelope values
+ (0: 1.5dB, 1: 3dB) */
+
+ ULONG addHarmonics[ADD_HARMONICS_FLAGS_SIZE]; /*!< Flags for synthetic sine
+ addition (aligned to MSB) */
+
+ FIXP_SGL iEnvelope[MAX_NUM_ENVELOPE_VALUES]; /*!< Envelope data */
+ FIXP_SGL sbrNoiseFloorLevel[MAX_NUM_NOISE_VALUES]; /*!< Noise envelope data */
+ UCHAR iTESactive; /*!< One flag for each envelope to enable USAC inter-TES */
+ UCHAR
+ interTempShapeMode[MAX_ENVELOPES]; /*!< USAC inter-TES:
+ bs_inter_temp_shape_mode[ch][env]
+ value */
+ UCHAR pvcID[PVC_NTIMESLOT]; /*!< One PVC ID value for each time slot */
+ UCHAR ns;
+ UCHAR sinusoidal_position;
+
+ UCHAR sbrPatchingMode;
+ UCHAR sbrOversamplingFlag;
+ UCHAR sbrPitchInBins;
+} SBR_FRAME_DATA;
+
+typedef SBR_FRAME_DATA *HANDLE_SBR_FRAME_DATA;
+
+/*!
+\brief Maps sampling frequencies to frequencies for which setup tables are
+available
+
+Maps arbitary sampling frequency to nearest neighbors for which setup tables
+are available (e.g. 25600 -> 24000).
+Used for startFreq calculation.
+The mapping is defined in 14496-3 (4.6.18.2.6), fs(SBR), and table 4.82
+
+\return mapped sampling frequency
+*/
+UINT sbrdec_mapToStdSampleRate(UINT fs,
+ UINT isUsac); /*!< Output sampling frequency */
+
+void initSbrPrevFrameData(HANDLE_SBR_PREV_FRAME_DATA h_prev_data,
+ int timeSlots);
+
+int sbrGetChannelElement(HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_FRAME_DATA hFrameDataLeft,
+ HANDLE_SBR_FRAME_DATA hFrameDataRight,
+ HANDLE_SBR_PREV_FRAME_DATA hFrameDataLeftPrev,
+ UCHAR pvc_mode_last, HANDLE_FDK_BITSTREAM hBitBuf,
+ HANDLE_PS_DEC hParametricStereoDec, const UINT flags,
+ const int overlap);
+
+SBR_HEADER_STATUS
+sbrGetHeaderData(HANDLE_SBR_HEADER_DATA headerData,
+ HANDLE_FDK_BITSTREAM hBitBuf, const UINT flags,
+ const int fIsSbrData, const UCHAR configMode);
+
+/*!
+ \brief Initialize SBR header data
+
+ Copy default values to the header data struct and patch some entries
+ depending on the core codec.
+*/
+SBR_ERROR
+initHeaderData(HANDLE_SBR_HEADER_DATA hHeaderData, const int sampleRateIn,
+ const int sampleRateOut, const INT downscaleFactor,
+ const int samplesPerFrame, const UINT flags,
+ const int setDefaultHdr);
+#endif
+
+/* Convert headroom bits to exponent */
+#define SCALE2EXP(s) (15 - (s))
+#define EXP2SCALE(e) (15 - (e))
diff --git a/fdk-aac/libSBRdec/src/hbe.cpp b/fdk-aac/libSBRdec/src/hbe.cpp
new file mode 100644
index 0000000..3310dcd
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/hbe.cpp
@@ -0,0 +1,2202 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Fast FFT routines prototypes
+ \author Fabian Haussel
+*/
+
+#include "hbe.h"
+#include "qmf.h"
+#include "env_extr.h"
+
+#define HBE_MAX_QMF_BANDS (40)
+
+#define HBE_MAX_OUT_SLOTS (11)
+
+#define QMF_WIN_LEN \
+ (12 + 6 - 4 - 1) /* 6 subband slots extra delay to align with HQ - 4 slots \
+ to compensate for critical sampling delay - 1 slot to \
+ align critical sampling exactly (w additional time \
+ domain delay)*/
+
+#ifndef PI
+#define PI 3.14159265358979323846
+#endif
+
+static const int xProducts[MAX_STRETCH_HBE - 1] = {
+ 1, 1, 1}; /* Cross products on(1)/off(0) for T=2,3,4. */
+static const int startSubband2kL[33] = {
+ 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6,
+ 6, 8, 8, 8, 8, 8, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12};
+
+static const int pmin = 12;
+
+static const FIXP_DBL hintReal_F[4][3] = {
+ {FL2FXCONST_DBL(0.39840335f), FL2FXCONST_DBL(0.39840335f),
+ FL2FXCONST_DBL(-0.39840335f)},
+ {FL2FXCONST_DBL(0.39840335f), FL2FXCONST_DBL(-0.39840335f),
+ FL2FXCONST_DBL(-0.39840335f)},
+ {FL2FXCONST_DBL(-0.39840335f), FL2FXCONST_DBL(-0.39840335f),
+ FL2FXCONST_DBL(0.39840335f)},
+ {FL2FXCONST_DBL(-0.39840335f), FL2FXCONST_DBL(0.39840335f),
+ FL2FXCONST_DBL(0.39840335f)}};
+
+static const FIXP_DBL factors[4] = {
+ FL2FXCONST_DBL(0.39840335f), FL2FXCONST_DBL(-0.39840335f),
+ FL2FXCONST_DBL(-0.39840335f), FL2FXCONST_DBL(0.39840335f)};
+
+#define PSCALE 32
+
+static const FIXP_DBL p_F[128] = {FL2FXCONST_DBL(0.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(1.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(2.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(3.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(4.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(5.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(6.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(7.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(8.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(9.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(10.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(11.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(12.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(13.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(14.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(15.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(16.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(17.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(18.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(19.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(20.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(21.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(22.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(23.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(24.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(25.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(26.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(27.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(28.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(29.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(30.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(31.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(32.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(33.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(34.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(35.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(36.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(37.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(38.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(39.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(40.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(41.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(42.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(43.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(44.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(45.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(46.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(47.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(48.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(49.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(50.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(51.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(52.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(53.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(54.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(55.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(56.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(57.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(58.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(59.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(60.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(61.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(62.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(63.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(64.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(65.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(66.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(67.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(68.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(69.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(70.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(71.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(72.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(73.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(74.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(75.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(76.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(77.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(78.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(79.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(80.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(81.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(82.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(83.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(84.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(85.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(86.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(87.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(88.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(89.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(90.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(91.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(92.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(93.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(94.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(95.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(96.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(97.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(98.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(99.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(100.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(101.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(102.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(103.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(104.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(105.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(106.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(107.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(108.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(109.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(110.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(111.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(112.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(113.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(114.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(115.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(116.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(117.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(118.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(119.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(120.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(121.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(122.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(123.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(124.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(125.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(126.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(127.f / (PSCALE * 12.f))};
+
+static const FIXP_DBL band_F[64] = {
+ FL2FXCONST_DBL((0.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((1.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((2.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((3.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((4.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((5.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((6.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((7.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((8.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((9.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((10.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((11.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((12.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((13.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((14.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((15.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((16.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((17.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((18.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((19.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((20.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((21.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((22.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((23.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((24.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((25.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((26.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((27.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((28.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((29.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((30.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((31.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((32.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((33.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((34.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((35.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((36.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((37.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((38.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((39.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((40.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((41.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((42.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((43.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((44.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((45.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((46.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((47.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((48.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((49.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((50.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((51.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((52.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((53.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((54.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((55.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((56.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((57.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((58.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((59.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((60.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((61.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((62.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((63.f * 2.f + 1) / (PSCALE << 2))};
+
+static const FIXP_DBL tr_str[3] = {FL2FXCONST_DBL(1.f / 4.f),
+ FL2FXCONST_DBL(2.f / 4.f),
+ FL2FXCONST_DBL(3.f / 4.f)};
+
+static const FIXP_DBL stretchfac[3] = {FL2FXCONST_DBL(1.f / 2.f),
+ FL2FXCONST_DBL(1.f / 3.f),
+ FL2FXCONST_DBL(1.f / 4.f)};
+
+static const FIXP_DBL cos_F[64] = {
+ 26353028, -79043208, 131685776, -184244944, 236697216, -289006912,
+ 341142496, -393072608, 444773984, -496191392, 547325824, -598114752,
+ 648559104, -698597248, 748230016, -797411904, 846083200, -894275136,
+ 941928192, -989013760, 1035474624, -1081340672, 1126555136, -1171063296,
+ 1214893696, -1257992192, 1300332544, -1341889408, 1382612736, -1422503808,
+ 1461586944, -1499741440, 1537039104, -1573364864, 1608743808, -1643196672,
+ 1676617344, -1709028992, 1740450560, -1770784896, 1800089472, -1828273536,
+ 1855357440, -1881356288, 1906190080, -1929876608, 1952428928, -1973777664,
+ 1993962880, -2012922240, 2030670208, -2047216000, 2062508288, -2076559488,
+ 2089376128, -2100932224, 2111196800, -2120214784, 2127953792, -2134394368,
+ 2139565056, -2143444864, 2146026624, -2147321856};
+
+static const FIXP_DBL twiddle[121] = {1073741824,
+ 1071442860,
+ 1064555814,
+ 1053110176,
+ 1037154959,
+ 1016758484,
+ 992008094,
+ 963009773,
+ 929887697,
+ 892783698,
+ 851856663,
+ 807281846,
+ 759250125,
+ 707967178,
+ 653652607,
+ 596538995,
+ 536870912,
+ 474903865,
+ 410903207,
+ 345142998,
+ 277904834,
+ 209476638,
+ 140151432,
+ 70226075,
+ 0,
+ -70226075,
+ -140151432,
+ -209476638,
+ -277904834,
+ -345142998,
+ -410903207,
+ -474903865,
+ -536870912,
+ -596538995,
+ -653652607,
+ -707967178,
+ -759250125,
+ -807281846,
+ -851856663,
+ -892783698,
+ -929887697,
+ -963009773,
+ -992008094,
+ -1016758484,
+ -1037154959,
+ -1053110176,
+ -1064555814,
+ -1071442860,
+ -1073741824,
+ -1071442860,
+ -1064555814,
+ -1053110176,
+ -1037154959,
+ -1016758484,
+ -992008094,
+ -963009773,
+ -929887697,
+ -892783698,
+ -851856663,
+ -807281846,
+ -759250125,
+ -707967178,
+ -653652607,
+ -596538995,
+ -536870912,
+ -474903865,
+ -410903207,
+ -345142998,
+ -277904834,
+ -209476638,
+ -140151432,
+ -70226075,
+ 0,
+ 70226075,
+ 140151432,
+ 209476638,
+ 277904834,
+ 345142998,
+ 410903207,
+ 474903865,
+ 536870912,
+ 596538995,
+ 653652607,
+ 707967178,
+ 759250125,
+ 807281846,
+ 851856663,
+ 892783698,
+ 929887697,
+ 963009773,
+ 992008094,
+ 1016758484,
+ 1037154959,
+ 1053110176,
+ 1064555814,
+ 1071442860,
+ 1073741824,
+ 1071442860,
+ 1064555814,
+ 1053110176,
+ 1037154959,
+ 1016758484,
+ 992008094,
+ 963009773,
+ 929887697,
+ 892783698,
+ 851856663,
+ 807281846,
+ 759250125,
+ 707967178,
+ 653652607,
+ 596538995,
+ 536870912,
+ 474903865,
+ 410903207,
+ 345142998,
+ 277904834,
+ 209476638,
+ 140151432,
+ 70226075,
+ 0};
+
+#if FIXP_QTW == FIXP_SGL
+#define HTW(x) (x)
+#else
+#define HTW(x) FX_DBL2FX_QTW(FX_SGL2FX_DBL((const FIXP_SGL)x))
+#endif
+
+static const FIXP_QTW post_twiddle_cos_8[8] = {
+ HTW(-1606), HTW(4756), HTW(-7723), HTW(10394),
+ HTW(-12665), HTW(14449), HTW(-15679), HTW(16305)};
+
+static const FIXP_QTW post_twiddle_cos_16[16] = {
+ HTW(-804), HTW(2404), HTW(-3981), HTW(5520), HTW(-7005), HTW(8423),
+ HTW(-9760), HTW(11003), HTW(-12140), HTW(13160), HTW(-14053), HTW(14811),
+ HTW(-15426), HTW(15893), HTW(-16207), HTW(16364)};
+
+static const FIXP_QTW post_twiddle_cos_24[24] = {
+ HTW(-536), HTW(1606), HTW(-2669), HTW(3720), HTW(-4756), HTW(5771),
+ HTW(-6762), HTW(7723), HTW(-8652), HTW(9543), HTW(-10394), HTW(11200),
+ HTW(-11958), HTW(12665), HTW(-13318), HTW(13913), HTW(-14449), HTW(14924),
+ HTW(-15334), HTW(15679), HTW(-15956), HTW(16165), HTW(-16305), HTW(16375)};
+
+static const FIXP_QTW post_twiddle_cos_32[32] = {
+ HTW(-402), HTW(1205), HTW(-2006), HTW(2801), HTW(-3590), HTW(4370),
+ HTW(-5139), HTW(5897), HTW(-6639), HTW(7366), HTW(-8076), HTW(8765),
+ HTW(-9434), HTW(10080), HTW(-10702), HTW(11297), HTW(-11866), HTW(12406),
+ HTW(-12916), HTW(13395), HTW(-13842), HTW(14256), HTW(-14635), HTW(14978),
+ HTW(-15286), HTW(15557), HTW(-15791), HTW(15986), HTW(-16143), HTW(16261),
+ HTW(-16340), HTW(16379)};
+
+static const FIXP_QTW post_twiddle_cos_40[40] = {
+ HTW(-322), HTW(965), HTW(-1606), HTW(2245), HTW(-2880), HTW(3511),
+ HTW(-4137), HTW(4756), HTW(-5368), HTW(5971), HTW(-6566), HTW(7150),
+ HTW(-7723), HTW(8285), HTW(-8833), HTW(9368), HTW(-9889), HTW(10394),
+ HTW(-10883), HTW(11356), HTW(-11810), HTW(12247), HTW(-12665), HTW(13063),
+ HTW(-13441), HTW(13799), HTW(-14135), HTW(14449), HTW(-14741), HTW(15011),
+ HTW(-15257), HTW(15480), HTW(-15679), HTW(15853), HTW(-16003), HTW(16129),
+ HTW(-16229), HTW(16305), HTW(-16356), HTW(16381)};
+
+static const FIXP_QTW post_twiddle_sin_8[8] = {
+ HTW(16305), HTW(-15679), HTW(14449), HTW(-12665),
+ HTW(10394), HTW(-7723), HTW(4756), HTW(-1606)};
+
+static const FIXP_QTW post_twiddle_sin_16[16] = {
+ HTW(16364), HTW(-16207), HTW(15893), HTW(-15426), HTW(14811), HTW(-14053),
+ HTW(13160), HTW(-12140), HTW(11003), HTW(-9760), HTW(8423), HTW(-7005),
+ HTW(5520), HTW(-3981), HTW(2404), HTW(-804)};
+
+static const FIXP_QTW post_twiddle_sin_24[24] = {
+ HTW(16375), HTW(-16305), HTW(16165), HTW(-15956), HTW(15679), HTW(-15334),
+ HTW(14924), HTW(-14449), HTW(13913), HTW(-13318), HTW(12665), HTW(-11958),
+ HTW(11200), HTW(-10394), HTW(9543), HTW(-8652), HTW(7723), HTW(-6762),
+ HTW(5771), HTW(-4756), HTW(3720), HTW(-2669), HTW(1606), HTW(-536)};
+
+static const FIXP_QTW post_twiddle_sin_32[32] = {
+ HTW(16379), HTW(-16340), HTW(16261), HTW(-16143), HTW(15986), HTW(-15791),
+ HTW(15557), HTW(-15286), HTW(14978), HTW(-14635), HTW(14256), HTW(-13842),
+ HTW(13395), HTW(-12916), HTW(12406), HTW(-11866), HTW(11297), HTW(-10702),
+ HTW(10080), HTW(-9434), HTW(8765), HTW(-8076), HTW(7366), HTW(-6639),
+ HTW(5897), HTW(-5139), HTW(4370), HTW(-3590), HTW(2801), HTW(-2006),
+ HTW(1205), HTW(-402)};
+
+static const FIXP_QTW post_twiddle_sin_40[40] = {
+ HTW(16381), HTW(-16356), HTW(16305), HTW(-16229), HTW(16129), HTW(-16003),
+ HTW(15853), HTW(-15679), HTW(15480), HTW(-15257), HTW(15011), HTW(-14741),
+ HTW(14449), HTW(-14135), HTW(13799), HTW(-13441), HTW(13063), HTW(-12665),
+ HTW(12247), HTW(-11810), HTW(11356), HTW(-10883), HTW(10394), HTW(-9889),
+ HTW(9368), HTW(-8833), HTW(8285), HTW(-7723), HTW(7150), HTW(-6566),
+ HTW(5971), HTW(-5368), HTW(4756), HTW(-4137), HTW(3511), HTW(-2880),
+ HTW(2245), HTW(-1606), HTW(965), HTW(-322)};
+
+static const FIXP_DBL preModCos[32] = {
+ -749875776, 786681536, 711263552, -821592064, -670937792, 854523392,
+ 628995648, -885396032, -585538240, 914135680, 540670208, -940673088,
+ -494499680, 964944384, 447137824, -986891008, -398698816, 1006460096,
+ 349299264, -1023604544, -299058240, 1038283072, 248096752, -1050460288,
+ -196537584, 1060106816, 144504928, -1067199488, -92124160, 1071721152,
+ 39521456, -1073660992};
+
+static const FIXP_DBL preModSin[32] = {
+ 768510144, 730789760, -804379072, -691308864, 838310208, 650162560,
+ -870221760, -607449920, 900036928, 563273856, -927683776, -517740896,
+ 953095808, 470960608, -976211712, -423045728, 996975808, 374111712,
+ -1015338112, -324276416, 1031254400, 273659904, -1044686336, -222384144,
+ 1055601472, 170572640, -1063973632, -118350192, 1069782528, 65842640,
+ -1073014208, -13176464};
+
+/* The cube root function */
+/*****************************************************************************
+
+ functionname: invCubeRootNorm2
+ description: delivers 1/cuberoot(op) in Q1.31 format and modified exponent
+
+*****************************************************************************/
+#define CUBE_ROOT_BITS 7
+#define CUBE_ROOT_VALUES (128 + 2)
+#define CUBE_ROOT_BITS_MASK 0x7f
+#define CUBE_ROOT_FRACT_BITS_MASK 0x007FFFFF
+/* Inverse cube root table for operands running from 0.5 to 1.0 */
+/* (INT) (1.0/cuberoot((op))); */
+/* Implicit exponent is 1. */
+
+LNK_SECTION_CONSTDATA
+static const FIXP_DBL invCubeRootTab[CUBE_ROOT_VALUES] = {
+ (0x50a28be6), (0x506d1172), (0x503823c4), (0x5003c05a), (0x4fcfe4c0),
+ (0x4f9c8e92), (0x4f69bb7d), (0x4f37693b), (0x4f059594), (0x4ed43e5f),
+ (0x4ea36181), (0x4e72fcea), (0x4e430e98), (0x4e139495), (0x4de48cf5),
+ (0x4db5f5db), (0x4d87cd73), (0x4d5a11f2), (0x4d2cc19c), (0x4cffdabb),
+ (0x4cd35ba4), (0x4ca742b7), (0x4c7b8e5c), (0x4c503d05), (0x4c254d2a),
+ (0x4bfabd50), (0x4bd08c00), (0x4ba6b7cd), (0x4b7d3f53), (0x4b542134),
+ (0x4b2b5c18), (0x4b02eeb1), (0x4adad7b8), (0x4ab315ea), (0x4a8ba80d),
+ (0x4a648cec), (0x4a3dc35b), (0x4a174a30), (0x49f1204a), (0x49cb448d),
+ (0x49a5b5e2), (0x49807339), (0x495b7b86), (0x4936cdc2), (0x491268ec),
+ (0x48ee4c08), (0x48ca761f), (0x48a6e63e), (0x48839b76), (0x486094de),
+ (0x483dd190), (0x481b50ad), (0x47f91156), (0x47d712b3), (0x47b553f0),
+ (0x4793d43c), (0x477292c9), (0x47518ece), (0x4730c785), (0x47103c2d),
+ (0x46efec06), (0x46cfd655), (0x46affa61), (0x46905777), (0x4670ece4),
+ (0x4651b9f9), (0x4632be0b), (0x4613f871), (0x45f56885), (0x45d70da5),
+ (0x45b8e72f), (0x459af487), (0x457d3511), (0x455fa835), (0x45424d5d),
+ (0x452523f6), (0x45082b6e), (0x44eb6337), (0x44cecac5), (0x44b2618d),
+ (0x44962708), (0x447a1ab1), (0x445e3c02), (0x44428a7c), (0x4427059e),
+ (0x440bacec), (0x43f07fe9), (0x43d57e1c), (0x43baa70e), (0x439ffa48),
+ (0x43857757), (0x436b1dc8), (0x4350ed2b), (0x4336e511), (0x431d050c),
+ (0x43034cb2), (0x42e9bb98), (0x42d05156), (0x42b70d85), (0x429defc0),
+ (0x4284f7a2), (0x426c24cb), (0x425376d8), (0x423aed6a), (0x42228823),
+ (0x420a46a6), (0x41f22898), (0x41da2d9f), (0x41c25561), (0x41aa9f86),
+ (0x41930bba), (0x417b99a5), (0x416448f5), (0x414d1956), (0x41360a76),
+ (0x411f1c06), (0x41084db5), (0x40f19f35), (0x40db1039), (0x40c4a074),
+ (0x40ae4f9b), (0x40981d64), (0x40820985), (0x406c13b6), (0x40563bb1),
+ (0x4040812e), (0x402ae3e7), (0x40156399), (0x40000000), (0x3FEAB8D9)};
+/* n.a. */
+static const FIXP_DBL invCubeRootCorrection[3] = {0x40000000, 0x50A28BE6,
+ 0x6597FA95};
+
+/*****************************************************************************
+ * \brief calculate 1.0/cube_root(op), op contains mantissa and exponent
+ * \param op_m: (i) mantissa of operand, must not be zero (0x0000.0000) or
+ * negative
+ * \param op_e: (i) pointer to the exponent of the operand (must be initialized)
+ * and .. (o) pointer to the exponent of the result
+ * \return: (o) mantissa of the result
+ * \description:
+ * This routine calculates the cube root of the input operand, that is
+ * given with its mantissa in Q31 format (FIXP_DBL) and its exponent (INT).
+ * The resulting mantissa is returned in format Q31. The exponent (*op_e)
+ * is modified accordingly. It is not assured, that the result is fully
+ * left-aligned but assumed to have not more than 2 bits headroom. There is one
+ * macro to activate the use of this algorithm: FUNCTION_invCubeRootNorm2 By
+ * means of activating the macro INVCUBEROOTNORM2_LINEAR_INTERPOLATE_HQ, a
+ * slightly higher precision is reachable (by default, not active). For DEBUG
+ * purpose only: a FDK_ASSERT macro validates, if the input mantissa is greater
+ * zero.
+ *
+ */
+static
+#ifdef __arm__
+ FIXP_DBL FDK_FORCEINLINE
+ invCubeRootNorm2(FIXP_DBL op_m, INT* op_e)
+#else
+ FIXP_DBL
+ invCubeRootNorm2(FIXP_DBL op_m, INT* op_e)
+#endif
+{
+ FDK_ASSERT(op_m > FIXP_DBL(0));
+
+ /* normalize input, calculate shift value */
+ INT exponent = (INT)fNormz(op_m) - 1;
+ op_m <<= exponent;
+
+ INT index = (INT)(op_m >> (DFRACT_BITS - 1 - (CUBE_ROOT_BITS + 1))) &
+ CUBE_ROOT_BITS_MASK;
+ FIXP_DBL fract = (FIXP_DBL)(((INT)op_m & CUBE_ROOT_FRACT_BITS_MASK)
+ << (CUBE_ROOT_BITS + 1));
+ FIXP_DBL diff = invCubeRootTab[index + 1] - invCubeRootTab[index];
+ op_m = fMultAddDiv2(invCubeRootTab[index], diff << 1, fract);
+#if defined(INVCUBEROOTNORM2_LINEAR_INTERPOLATE_HQ)
+ /* reg1 = t[i] + (t[i+1]-t[i])*fract ... already computed ... +
+ * (1-fract)fract*(t[i+2]-t[i+1])/2 */
+ if (fract != (FIXP_DBL)0) {
+ /* fract = fract * (1 - fract) */
+ fract = fMultDiv2(fract, (FIXP_DBL)((LONG)0x80000000 - (LONG)fract)) << 1;
+ diff = diff - (invCubeRootTab[index + 2] - invCubeRootTab[index + 1]);
+ op_m = fMultAddDiv2(op_m, fract, diff);
+ }
+#endif /* INVCUBEROOTNORM2_LINEAR_INTERPOLATE_HQ */
+
+ /* calculate the output exponent = input * exp/3 = cubicroot(m)*2^(exp/3)
+ * where 2^(exp/3) = 2^k'*2 or 2^k'*2^(1/3) or 2^k'*2^(2/3) */
+ exponent = exponent - *op_e + 3;
+ INT shift_tmp =
+ ((INT)fMultDiv2((FIXP_SGL)fAbs(exponent), (FIXP_SGL)0x5556)) >> 16;
+ if (exponent < 0) {
+ shift_tmp = -shift_tmp;
+ }
+ INT rem = exponent - 3 * shift_tmp;
+ if (rem < 0) {
+ rem += 3;
+ shift_tmp--;
+ }
+
+ *op_e = shift_tmp;
+ op_m = fMultDiv2(op_m, invCubeRootCorrection[rem]) << 2;
+
+ return (op_m);
+}
+
+ /*****************************************************************************
+
+ functionname: invFourthRootNorm2
+ description: delivers 1/FourthRoot(op) in Q1.31 format and modified
+ exponent
+
+ *****************************************************************************/
+
+#define FOURTHROOT_BITS 7
+#define FOURTHROOT_VALUES (128 + 2)
+#define FOURTHROOT_BITS_MASK 0x7f
+#define FOURTHROOT_FRACT_BITS_MASK 0x007FFFFF
+
+LNK_SECTION_CONSTDATA
+static const FIXP_DBL invFourthRootTab[FOURTHROOT_VALUES] = {
+ (0x4c1bf829), (0x4bf61977), (0x4bd09843), (0x4bab72ef), (0x4b86a7eb),
+ (0x4b6235ac), (0x4b3e1ab6), (0x4b1a5592), (0x4af6e4d4), (0x4ad3c718),
+ (0x4ab0fb03), (0x4a8e7f42), (0x4a6c5288), (0x4a4a7393), (0x4a28e126),
+ (0x4a079a0c), (0x49e69d16), (0x49c5e91f), (0x49a57d04), (0x498557ac),
+ (0x49657802), (0x4945dcf9), (0x49268588), (0x490770ac), (0x48e89d6a),
+ (0x48ca0ac9), (0x48abb7d6), (0x488da3a6), (0x486fcd4f), (0x485233ed),
+ (0x4834d6a3), (0x4817b496), (0x47faccf0), (0x47de1ee0), (0x47c1a999),
+ (0x47a56c51), (0x47896643), (0x476d96af), (0x4751fcd6), (0x473697ff),
+ (0x471b6773), (0x47006a81), (0x46e5a079), (0x46cb08ae), (0x46b0a279),
+ (0x46966d34), (0x467c683d), (0x466292f4), (0x4648ecbc), (0x462f74fe),
+ (0x46162b20), (0x45fd0e91), (0x45e41ebe), (0x45cb5b19), (0x45b2c315),
+ (0x459a562a), (0x458213cf), (0x4569fb81), (0x45520cbc), (0x453a4701),
+ (0x4522a9d1), (0x450b34b0), (0x44f3e726), (0x44dcc0ba), (0x44c5c0f7),
+ (0x44aee768), (0x4498339e), (0x4481a527), (0x446b3b96), (0x4454f67e),
+ (0x443ed576), (0x4428d815), (0x4412fdf3), (0x43fd46ad), (0x43e7b1de),
+ (0x43d23f23), (0x43bcee1e), (0x43a7be6f), (0x4392afb8), (0x437dc19d),
+ (0x4368f3c5), (0x435445d6), (0x433fb779), (0x432b4856), (0x4316f81a),
+ (0x4302c66f), (0x42eeb305), (0x42dabd8a), (0x42c6e5ad), (0x42b32b21),
+ (0x429f8d96), (0x428c0cc2), (0x4278a859), (0x42656010), (0x4252339e),
+ (0x423f22bc), (0x422c2d23), (0x4219528b), (0x420692b2), (0x41f3ed51),
+ (0x41e16228), (0x41cef0f2), (0x41bc9971), (0x41aa5b62), (0x41983687),
+ (0x41862aa2), (0x41743775), (0x41625cc3), (0x41509a50), (0x413eefe2),
+ (0x412d5d3e), (0x411be22b), (0x410a7e70), (0x40f931d5), (0x40e7fc23),
+ (0x40d6dd24), (0x40c5d4a2), (0x40b4e268), (0x40a40642), (0x40933ffc),
+ (0x40828f64), (0x4071f447), (0x40616e73), (0x4050fdb9), (0x4040a1e6),
+ (0x40305acc), (0x4020283c), (0x40100a08), (0x40000000), (0x3ff009f9),
+};
+
+static const FIXP_DBL invFourthRootCorrection[4] = {0x40000000, 0x4C1BF829,
+ 0x5A82799A, 0x6BA27E65};
+
+/* The fourth root function */
+/*****************************************************************************
+ * \brief calculate 1.0/fourth_root(op), op contains mantissa and exponent
+ * \param op_m: (i) mantissa of operand, must not be zero (0x0000.0000) or
+ * negative
+ * \param op_e: (i) pointer to the exponent of the operand (must be initialized)
+ * and .. (o) pointer to the exponent of the result
+ * \return: (o) mantissa of the result
+ * \description:
+ * This routine calculates the cube root of the input operand, that is
+ * given with its mantissa in Q31 format (FIXP_DBL) and its exponent (INT).
+ * The resulting mantissa is returned in format Q31. The exponent (*op_e)
+ * is modified accordingly. It is not assured, that the result is fully
+ * left-aligned but assumed to have not more than 2 bits headroom. There is one
+ * macro to activate the use of this algorithm: FUNCTION_invFourthRootNorm2 By
+ * means of activating the macro INVFOURTHROOTNORM2_LINEAR_INTERPOLATE_HQ, a
+ * slightly higher precision is reachable (by default, not active). For DEBUG
+ * purpose only: a FDK_ASSERT macro validates, if the input mantissa is greater
+ * zero.
+ *
+ */
+
+/* #define INVFOURTHROOTNORM2_LINEAR_INTERPOLATE_HQ */
+
+static
+#ifdef __arm__
+ FIXP_DBL FDK_FORCEINLINE
+ invFourthRootNorm2(FIXP_DBL op_m, INT* op_e)
+#else
+ FIXP_DBL
+ invFourthRootNorm2(FIXP_DBL op_m, INT* op_e)
+#endif
+{
+ FDK_ASSERT(op_m > FL2FXCONST_DBL(0.0));
+
+ /* normalize input, calculate shift value */
+ INT exponent = (INT)fNormz(op_m) - 1;
+ op_m <<= exponent;
+
+ INT index = (INT)(op_m >> (DFRACT_BITS - 1 - (FOURTHROOT_BITS + 1))) &
+ FOURTHROOT_BITS_MASK;
+ FIXP_DBL fract = (FIXP_DBL)(((INT)op_m & FOURTHROOT_FRACT_BITS_MASK)
+ << (FOURTHROOT_BITS + 1));
+ FIXP_DBL diff = invFourthRootTab[index + 1] - invFourthRootTab[index];
+ op_m = invFourthRootTab[index] + (fMultDiv2(diff, fract) << 1);
+
+#if defined(INVFOURTHROOTNORM2_LINEAR_INTERPOLATE_HQ)
+ /* reg1 = t[i] + (t[i+1]-t[i])*fract ... already computed ... +
+ * (1-fract)fract*(t[i+2]-t[i+1])/2 */
+ if (fract != (FIXP_DBL)0) {
+ /* fract = fract * (1 - fract) */
+ fract = fMultDiv2(fract, (FIXP_DBL)((LONG)0x80000000 - (LONG)fract)) << 1;
+ diff = diff - (invFourthRootTab[index + 2] - invFourthRootTab[index + 1]);
+ op_m = fMultAddDiv2(op_m, fract, diff);
+ }
+#endif /* INVFOURTHROOTNORM2_LINEAR_INTERPOLATE_HQ */
+
+ exponent = exponent - *op_e + 4;
+ INT rem = exponent & 0x00000003;
+ INT shift_tmp = (exponent >> 2);
+
+ *op_e = shift_tmp;
+ op_m = fMultDiv2(op_m, invFourthRootCorrection[rem]) << 2;
+
+ return (op_m);
+}
+
+/*****************************************************************************
+
+ functionname: inv3EigthRootNorm2
+ description: delivers 1/cubert(op) normalized to .5...1 and the shift value
+of the OUTPUT
+
+*****************************************************************************/
+#define THREEIGTHROOT_BITS 7
+#define THREEIGTHROOT_VALUES (128 + 2)
+#define THREEIGTHROOT_BITS_MASK 0x7f
+#define THREEIGTHROOT_FRACT_BITS_MASK 0x007FFFFF
+
+LNK_SECTION_CONSTDATA
+static const FIXP_DBL inv3EigthRootTab[THREEIGTHROOT_VALUES] = {
+ (0x45cae0f2), (0x45b981bf), (0x45a8492a), (0x45973691), (0x45864959),
+ (0x457580e6), (0x4564dca4), (0x45545c00), (0x4543fe6b), (0x4533c35a),
+ (0x4523aa44), (0x4513b2a4), (0x4503dbf7), (0x44f425be), (0x44e48f7b),
+ (0x44d518b6), (0x44c5c0f7), (0x44b687c8), (0x44a76cb8), (0x44986f58),
+ (0x44898f38), (0x447acbef), (0x446c2514), (0x445d9a3f), (0x444f2b0d),
+ (0x4440d71a), (0x44329e07), (0x44247f73), (0x44167b04), (0x4408905e),
+ (0x43fabf28), (0x43ed070b), (0x43df67b0), (0x43d1e0c5), (0x43c471f7),
+ (0x43b71af6), (0x43a9db71), (0x439cb31c), (0x438fa1ab), (0x4382a6d2),
+ (0x4375c248), (0x4368f3c5), (0x435c3b03), (0x434f97bc), (0x434309ac),
+ (0x43369091), (0x432a2c28), (0x431ddc30), (0x4311a06c), (0x4305789c),
+ (0x42f96483), (0x42ed63e5), (0x42e17688), (0x42d59c30), (0x42c9d4a6),
+ (0x42be1fb1), (0x42b27d1a), (0x42a6ecac), (0x429b6e2f), (0x42900172),
+ (0x4284a63f), (0x42795c64), (0x426e23b0), (0x4262fbf2), (0x4257e4f9),
+ (0x424cde96), (0x4241e89a), (0x423702d8), (0x422c2d23), (0x4221674d),
+ (0x4216b12c), (0x420c0a94), (0x4201735b), (0x41f6eb57), (0x41ec725f),
+ (0x41e2084b), (0x41d7acf3), (0x41cd6030), (0x41c321db), (0x41b8f1ce),
+ (0x41aecfe5), (0x41a4bbf8), (0x419ab5e6), (0x4190bd89), (0x4186d2bf),
+ (0x417cf565), (0x41732558), (0x41696277), (0x415faca1), (0x415603b4),
+ (0x414c6792), (0x4142d818), (0x4139552a), (0x412fdea6), (0x41267470),
+ (0x411d1668), (0x4113c472), (0x410a7e70), (0x41014445), (0x40f815d4),
+ (0x40eef302), (0x40e5dbb4), (0x40dccfcd), (0x40d3cf33), (0x40cad9cb),
+ (0x40c1ef7b), (0x40b9102a), (0x40b03bbd), (0x40a7721c), (0x409eb32e),
+ (0x4095feda), (0x408d5508), (0x4084b5a0), (0x407c208b), (0x407395b2),
+ (0x406b14fd), (0x40629e56), (0x405a31a6), (0x4051ced8), (0x404975d5),
+ (0x40412689), (0x4038e0dd), (0x4030a4bd), (0x40287215), (0x402048cf),
+ (0x401828d7), (0x4010121a), (0x40080483), (0x40000000), (0x3ff8047d),
+};
+
+/* The last value is rounded in order to avoid any overflow due to the values
+ * range of the root table */
+static const FIXP_DBL inv3EigthRootCorrection[8] = {
+ 0x40000000, 0x45CAE0F2, 0x4C1BF829, 0x52FF6B55,
+ 0x5A82799A, 0x62B39509, 0x6BA27E65, 0x75606373};
+
+/* The 3/8 root function */
+/*****************************************************************************
+ * \brief calculate 1.0/3Eigth_root(op) = 1.0/(x)^(3/8), op contains mantissa
+ * and exponent
+ * \param op_m: (i) mantissa of operand, must not be zero (0x0000.0000) or
+ * negative
+ * \param op_e: (i) pointer to the exponent of the operand (must be initialized)
+ * and .. (o) pointer to the exponent of the result
+ * \return: (o) mantissa of the result
+ * \description:
+ * This routine calculates the cube root of the input operand, that is
+ * given with its mantissa in Q31 format (FIXP_DBL) and its exponent (INT).
+ * The resulting mantissa is returned in format Q31. The exponent (*op_e)
+ * is modified accordingly. It is not assured, that the result is fully
+ * left-aligned but assumed to have not more than 2 bits headroom. There is one
+ * macro to activate the use of this algorithm: FUNCTION_inv3EigthRootNorm2 By
+ * means of activating the macro INVTHREEIGTHROOTNORM2_LINEAR_INTERPOLATE_HQ, a
+ * slightly higher precision is reachable (by default, not active). For DEBUG
+ * purpose only: a FDK_ASSERT macro validates, if the input mantissa is greater
+ * zero.
+ *
+ */
+
+/* #define INVTHREEIGTHROOTNORM2_LINEAR_INTERPOLATE_HQ */
+
+static
+#ifdef __arm__
+ FIXP_DBL FDK_FORCEINLINE
+ inv3EigthRootNorm2(FIXP_DBL op_m, INT* op_e)
+#else
+ FIXP_DBL
+ inv3EigthRootNorm2(FIXP_DBL op_m, INT* op_e)
+#endif
+{
+ FDK_ASSERT(op_m > FL2FXCONST_DBL(0.0));
+
+ /* normalize input, calculate shift op_mue */
+ INT exponent = (INT)fNormz(op_m) - 1;
+ op_m <<= exponent;
+
+ INT index = (INT)(op_m >> (DFRACT_BITS - 1 - (THREEIGTHROOT_BITS + 1))) &
+ THREEIGTHROOT_BITS_MASK;
+ FIXP_DBL fract = (FIXP_DBL)(((INT)op_m & THREEIGTHROOT_FRACT_BITS_MASK)
+ << (THREEIGTHROOT_BITS + 1));
+ FIXP_DBL diff = inv3EigthRootTab[index + 1] - inv3EigthRootTab[index];
+ op_m = inv3EigthRootTab[index] + (fMultDiv2(diff, fract) << 1);
+
+#if defined(INVTHREEIGTHROOTNORM2_LINEAR_INTERPOLATE_HQ)
+ /* op_m = t[i] + (t[i+1]-t[i])*fract ... already computed ... +
+ * (1-fract)fract*(t[i+2]-t[i+1])/2 */
+ if (fract != (FIXP_DBL)0) {
+ /* fract = fract * (1 - fract) */
+ fract = fMultDiv2(fract, (FIXP_DBL)((LONG)0x80000000 - (LONG)fract)) << 1;
+ diff = diff - (inv3EigthRootTab[index + 2] - inv3EigthRootTab[index + 1]);
+ op_m = fMultAddDiv2(op_m, fract, diff);
+ }
+#endif /* INVTHREEIGTHROOTNORM2_LINEAR_INTERPOLATE_HQ */
+
+ exponent = exponent - *op_e + 8;
+ INT rem = exponent & 0x00000007;
+ INT shift_tmp = (exponent >> 3);
+
+ *op_e = shift_tmp * 3;
+ op_m = fMultDiv2(op_m, inv3EigthRootCorrection[rem]) << 2;
+
+ return (fMult(op_m, fMult(op_m, op_m)));
+}
+
+SBR_ERROR
+QmfTransposerCreate(HANDLE_HBE_TRANSPOSER* hQmfTransposer, const int frameSize,
+ int bDisableCrossProducts, int bSbr41) {
+ HANDLE_HBE_TRANSPOSER hQmfTran = NULL;
+
+ int i;
+
+ if (hQmfTransposer != NULL) {
+ /* Memory allocation */
+ /*--------------------------------------------------------------------------------------------*/
+ hQmfTran =
+ (HANDLE_HBE_TRANSPOSER)FDKcalloc(1, sizeof(struct hbeTransposer));
+ if (hQmfTran == NULL) {
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ for (i = 0; i < MAX_STRETCH_HBE - 1; i++) {
+ hQmfTran->bXProducts[i] = (bDisableCrossProducts ? 0 : xProducts[i]);
+ }
+
+ hQmfTran->timeDomainWinLen = frameSize;
+ if (frameSize == 768) {
+ hQmfTran->noCols =
+ (8 * frameSize / 3) / QMF_SYNTH_CHANNELS; /* 32 for 24:64 */
+ } else {
+ hQmfTran->noCols =
+ (bSbr41 + 1) * 2 * frameSize /
+ QMF_SYNTH_CHANNELS; /* 32 for 32:64 and 64 for 16:64 -> identical to
+ sbrdec->no_cols */
+ }
+
+ hQmfTran->noChannels = frameSize / hQmfTran->noCols;
+
+ hQmfTran->qmfInBufSize = QMF_WIN_LEN;
+ hQmfTran->qmfOutBufSize = 2 * (hQmfTran->noCols / 2 + QMF_WIN_LEN - 1);
+
+ hQmfTran->inBuf_F =
+ (INT_PCM*)FDKcalloc(QMF_SYNTH_CHANNELS + 20 + 1, sizeof(INT_PCM));
+ /* buffered time signal needs to be delayed by synthesis_size; max
+ * synthesis_size = 20; */
+ if (hQmfTran->inBuf_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ hQmfTran->qmfInBufReal_F =
+ (FIXP_DBL**)FDKcalloc(hQmfTran->qmfInBufSize, sizeof(FIXP_DBL*));
+ hQmfTran->qmfInBufImag_F =
+ (FIXP_DBL**)FDKcalloc(hQmfTran->qmfInBufSize, sizeof(FIXP_DBL*));
+
+ if (hQmfTran->qmfInBufReal_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ if (hQmfTran->qmfInBufImag_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ for (i = 0; i < hQmfTran->qmfInBufSize; i++) {
+ hQmfTran->qmfInBufReal_F[i] = (FIXP_DBL*)FDKaalloc(
+ QMF_SYNTH_CHANNELS * sizeof(FIXP_DBL), ALIGNMENT_DEFAULT);
+ hQmfTran->qmfInBufImag_F[i] = (FIXP_DBL*)FDKaalloc(
+ QMF_SYNTH_CHANNELS * sizeof(FIXP_DBL), ALIGNMENT_DEFAULT);
+ if (hQmfTran->qmfInBufReal_F[i] == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ if (hQmfTran->qmfInBufImag_F[i] == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ }
+
+ hQmfTran->qmfHBEBufReal_F =
+ (FIXP_DBL**)FDKcalloc(HBE_MAX_OUT_SLOTS, sizeof(FIXP_DBL*));
+ hQmfTran->qmfHBEBufImag_F =
+ (FIXP_DBL**)FDKcalloc(HBE_MAX_OUT_SLOTS, sizeof(FIXP_DBL*));
+
+ if (hQmfTran->qmfHBEBufReal_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ if (hQmfTran->qmfHBEBufImag_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ for (i = 0; i < HBE_MAX_OUT_SLOTS; i++) {
+ hQmfTran->qmfHBEBufReal_F[i] =
+ (FIXP_DBL*)FDKcalloc(QMF_SYNTH_CHANNELS, sizeof(FIXP_DBL));
+ hQmfTran->qmfHBEBufImag_F[i] =
+ (FIXP_DBL*)FDKcalloc(QMF_SYNTH_CHANNELS, sizeof(FIXP_DBL));
+ if (hQmfTran->qmfHBEBufReal_F[i] == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ if (hQmfTran->qmfHBEBufImag_F[i] == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ }
+
+ hQmfTran->qmfBufferCodecTempSlot_F =
+ (FIXP_DBL*)FDKcalloc(QMF_SYNTH_CHANNELS / 2, sizeof(FIXP_DBL));
+ if (hQmfTran->qmfBufferCodecTempSlot_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ hQmfTran->bSbr41 = bSbr41;
+
+ hQmfTran->highband_exp[0] = 0;
+ hQmfTran->highband_exp[1] = 0;
+ hQmfTran->target_exp[0] = 0;
+ hQmfTran->target_exp[1] = 0;
+
+ *hQmfTransposer = hQmfTran;
+ }
+
+ return SBRDEC_OK;
+}
+
+SBR_ERROR QmfTransposerReInit(HANDLE_HBE_TRANSPOSER hQmfTransposer,
+ UCHAR* FreqBandTable[2], UCHAR NSfb[2])
+/* removed bSbr41 from parameterlist:
+ don't know where to get this value from
+ at call-side */
+{
+ int L, sfb, patch, stopPatch, qmfErr;
+
+ if (hQmfTransposer != NULL) {
+ const FIXP_QTW* tmp_t_cos;
+ const FIXP_QTW* tmp_t_sin;
+
+ hQmfTransposer->startBand = FreqBandTable[0][0];
+ FDK_ASSERT((!hQmfTransposer->bSbr41 && hQmfTransposer->startBand <= 32) ||
+ (hQmfTransposer->bSbr41 &&
+ hQmfTransposer->startBand <=
+ 16)); /* is checked by resetFreqBandTables() */
+ hQmfTransposer->stopBand = FreqBandTable[0][NSfb[0]];
+
+ hQmfTransposer->synthSize =
+ 4 * ((hQmfTransposer->startBand + 4) / 8 + 1); /* 8, 12, 16, 20 */
+ hQmfTransposer->kstart = startSubband2kL[hQmfTransposer->startBand];
+
+ /* don't know where to take this information from */
+ /* hQmfTransposer->bSbr41 = bSbr41; */
+
+ if (hQmfTransposer->bSbr41) {
+ if (hQmfTransposer->kstart + hQmfTransposer->synthSize > 16)
+ hQmfTransposer->kstart = 16 - hQmfTransposer->synthSize;
+ } else if (hQmfTransposer->timeDomainWinLen == 768) {
+ if (hQmfTransposer->kstart + hQmfTransposer->synthSize > 24)
+ hQmfTransposer->kstart = 24 - hQmfTransposer->synthSize;
+ }
+
+ hQmfTransposer->synthesisQmfPreModCos_F =
+ &preModCos[hQmfTransposer->kstart];
+ hQmfTransposer->synthesisQmfPreModSin_F =
+ &preModSin[hQmfTransposer->kstart];
+
+ L = 2 * hQmfTransposer->synthSize; /* 8, 16, 24, 32, 40 */
+ /* Change analysis post twiddles */
+
+ switch (L) {
+ case 8:
+ tmp_t_cos = post_twiddle_cos_8;
+ tmp_t_sin = post_twiddle_sin_8;
+ break;
+ case 16:
+ tmp_t_cos = post_twiddle_cos_16;
+ tmp_t_sin = post_twiddle_sin_16;
+ break;
+ case 24:
+ tmp_t_cos = post_twiddle_cos_24;
+ tmp_t_sin = post_twiddle_sin_24;
+ break;
+ case 32:
+ tmp_t_cos = post_twiddle_cos_32;
+ tmp_t_sin = post_twiddle_sin_32;
+ break;
+ case 40:
+ tmp_t_cos = post_twiddle_cos_40;
+ tmp_t_sin = post_twiddle_sin_40;
+ break;
+ default:
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ qmfErr = qmfInitSynthesisFilterBank(
+ &hQmfTransposer->HBESynthesisQMF, hQmfTransposer->synQmfStates,
+ hQmfTransposer->noCols, 0, hQmfTransposer->synthSize,
+ hQmfTransposer->synthSize, 1);
+ if (qmfErr != 0) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ qmfErr = qmfInitAnalysisFilterBank(
+ &hQmfTransposer->HBEAnalysiscQMF, hQmfTransposer->anaQmfStates,
+ hQmfTransposer->noCols / 2, 0, 2 * hQmfTransposer->synthSize,
+ 2 * hQmfTransposer->synthSize, 0);
+
+ if (qmfErr != 0) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ hQmfTransposer->HBEAnalysiscQMF.t_cos = tmp_t_cos;
+ hQmfTransposer->HBEAnalysiscQMF.t_sin = tmp_t_sin;
+
+ FDKmemset(hQmfTransposer->xOverQmf, 0,
+ MAX_NUM_PATCHES * sizeof(int)); /* global */
+ sfb = 0;
+ if (hQmfTransposer->bSbr41) {
+ stopPatch = MAX_NUM_PATCHES;
+ hQmfTransposer->maxStretch = MAX_STRETCH_HBE;
+ } else {
+ stopPatch = MAX_STRETCH_HBE;
+ }
+
+ for (patch = 1; patch <= stopPatch; patch++) {
+ while (sfb <= NSfb[0] &&
+ FreqBandTable[0][sfb] <= patch * hQmfTransposer->startBand)
+ sfb++;
+ if (sfb <= NSfb[0]) {
+ /* If the distance is larger than three QMF bands - try aligning to high
+ * resolution frequency bands instead. */
+ if ((patch * hQmfTransposer->startBand - FreqBandTable[0][sfb - 1]) <=
+ 3) {
+ hQmfTransposer->xOverQmf[patch - 1] = FreqBandTable[0][sfb - 1];
+ } else {
+ int sfb_tmp = 0;
+ while (sfb_tmp <= NSfb[1] &&
+ FreqBandTable[1][sfb_tmp] <= patch * hQmfTransposer->startBand)
+ sfb_tmp++;
+ hQmfTransposer->xOverQmf[patch - 1] = FreqBandTable[1][sfb_tmp - 1];
+ }
+ } else {
+ hQmfTransposer->xOverQmf[patch - 1] = hQmfTransposer->stopBand;
+ hQmfTransposer->maxStretch = fMin(patch, MAX_STRETCH_HBE);
+ break;
+ }
+ }
+
+ hQmfTransposer->highband_exp[0] = 0;
+ hQmfTransposer->highband_exp[1] = 0;
+ hQmfTransposer->target_exp[0] = 0;
+ hQmfTransposer->target_exp[1] = 0;
+ }
+
+ return SBRDEC_OK;
+}
+
+void QmfTransposerClose(HANDLE_HBE_TRANSPOSER hQmfTransposer) {
+ int i;
+
+ if (hQmfTransposer != NULL) {
+ if (hQmfTransposer->inBuf_F) FDKfree(hQmfTransposer->inBuf_F);
+
+ if (hQmfTransposer->qmfInBufReal_F) {
+ for (i = 0; i < hQmfTransposer->qmfInBufSize; i++) {
+ FDKafree(hQmfTransposer->qmfInBufReal_F[i]);
+ }
+ FDKfree(hQmfTransposer->qmfInBufReal_F);
+ }
+
+ if (hQmfTransposer->qmfInBufImag_F) {
+ for (i = 0; i < hQmfTransposer->qmfInBufSize; i++) {
+ FDKafree(hQmfTransposer->qmfInBufImag_F[i]);
+ }
+ FDKfree(hQmfTransposer->qmfInBufImag_F);
+ }
+
+ if (hQmfTransposer->qmfHBEBufReal_F) {
+ for (i = 0; i < HBE_MAX_OUT_SLOTS; i++) {
+ FDKfree(hQmfTransposer->qmfHBEBufReal_F[i]);
+ }
+ FDKfree(hQmfTransposer->qmfHBEBufReal_F);
+ }
+
+ if (hQmfTransposer->qmfHBEBufImag_F) {
+ for (i = 0; i < HBE_MAX_OUT_SLOTS; i++) {
+ FDKfree(hQmfTransposer->qmfHBEBufImag_F[i]);
+ }
+ FDKfree(hQmfTransposer->qmfHBEBufImag_F);
+ }
+
+ FDKfree(hQmfTransposer->qmfBufferCodecTempSlot_F);
+
+ FDKfree(hQmfTransposer);
+ }
+}
+
+inline void scaleUp(FIXP_DBL* real_m, FIXP_DBL* imag_m, INT* _e) {
+ INT reserve;
+ /* shift gc_r and gc_i up if possible */
+ reserve = CntLeadingZeros((INT(*real_m) ^ INT((*real_m >> 31))) |
+ (INT(*imag_m) ^ INT((*imag_m >> 31)))) -
+ 1;
+ reserve = fMax(reserve - 1,
+ 0); /* Leave one bit headroom such that (real_m^2 + imag_m^2)
+ does not overflow later if both are 0x80000000. */
+ reserve = fMin(reserve, *_e);
+ FDK_ASSERT(reserve >= 0);
+ *real_m <<= reserve;
+ *imag_m <<= reserve;
+ *_e -= reserve;
+}
+
+static void calculateCenterFIXP(FIXP_DBL gammaVecReal, FIXP_DBL gammaVecImag,
+ FIXP_DBL* centerReal, FIXP_DBL* centerImag,
+ INT* exponent, int stretch, int mult) {
+ scaleUp(&gammaVecReal, &gammaVecImag, exponent);
+ FIXP_DBL energy = fPow2Div2(gammaVecReal) + fPow2Div2(gammaVecImag);
+
+ if (energy != FL2FXCONST_DBL(0.f)) {
+ FIXP_DBL gc_r_m, gc_i_m, factor_m = (FIXP_DBL)0;
+ INT factor_e, gc_e;
+ factor_e = 2 * (*exponent) + 1;
+
+ switch (stretch) {
+ case 2:
+ factor_m = invFourthRootNorm2(energy, &factor_e);
+ break;
+ case 3:
+ factor_m = invCubeRootNorm2(energy, &factor_e);
+ break;
+ case 4:
+ factor_m = inv3EigthRootNorm2(energy, &factor_e);
+ break;
+ }
+
+ gc_r_m = fMultDiv2(gammaVecReal,
+ factor_m); /* exponent = HBE_SCALE + factor_e + 1 */
+ gc_i_m = fMultDiv2(gammaVecImag,
+ factor_m); /* exponent = HBE_SCALE + factor_e + 1*/
+ gc_e = *exponent + factor_e + 1;
+
+ scaleUp(&gc_r_m, &gc_i_m, &gc_e);
+
+ switch (mult) {
+ case 0:
+ *centerReal = gc_r_m;
+ *centerImag = gc_i_m;
+ break;
+ case 1:
+ *centerReal = fPow2Div2(gc_r_m) - fPow2Div2(gc_i_m);
+ *centerImag = fMult(gc_r_m, gc_i_m);
+ gc_e = 2 * gc_e + 1;
+ break;
+ case 2:
+ FIXP_DBL tmp_r = gc_r_m;
+ FIXP_DBL tmp_i = gc_i_m;
+ gc_r_m = fPow2Div2(gc_r_m) - fPow2Div2(gc_i_m);
+ gc_i_m = fMult(tmp_r, gc_i_m);
+ gc_e = 3 * gc_e + 1 + 1;
+ cplxMultDiv2(&centerReal[0], &centerImag[0], gc_r_m, gc_i_m, tmp_r,
+ tmp_i);
+ break;
+ }
+
+ scaleUp(centerReal, centerImag, &gc_e);
+
+ FDK_ASSERT(gc_e >= 0);
+ *exponent = gc_e;
+ } else {
+ *centerReal = energy; /* energy = 0 */
+ *centerImag = energy; /* energy = 0 */
+ *exponent = (INT)energy;
+ }
+}
+
+static int getHBEScaleFactorFrame(const int bSbr41, const int maxStretch,
+ const int pitchInBins) {
+ if (pitchInBins >= pmin * (1 + bSbr41)) {
+ /* crossproducts enabled */
+ return 26;
+ } else {
+ return (maxStretch == 2) ? 24 : 25;
+ }
+}
+
+static void addHighBandPart(FIXP_DBL g_r_m, FIXP_DBL g_i_m, INT g_e,
+ FIXP_DBL mult, FIXP_DBL gammaCenterReal_m,
+ FIXP_DBL gammaCenterImag_m, INT gammaCenter_e,
+ INT stretch, INT scale_factor_hbe,
+ FIXP_DBL* qmfHBEBufReal_F,
+ FIXP_DBL* qmfHBEBufImag_F) {
+ if ((g_r_m | g_i_m) != FL2FXCONST_DBL(0.f)) {
+ FIXP_DBL factor_m = (FIXP_DBL)0;
+ INT factor_e;
+ INT add = (stretch == 4) ? 1 : 0;
+ INT shift = (stretch == 4) ? 1 : 2;
+
+ scaleUp(&g_r_m, &g_i_m, &g_e);
+ FIXP_DBL energy = fPow2AddDiv2(fPow2Div2(g_r_m), g_i_m);
+ factor_e = 2 * g_e + 1;
+
+ switch (stretch) {
+ case 2:
+ factor_m = invFourthRootNorm2(energy, &factor_e);
+ break;
+ case 3:
+ factor_m = invCubeRootNorm2(energy, &factor_e);
+ break;
+ case 4:
+ factor_m = inv3EigthRootNorm2(energy, &factor_e);
+ break;
+ }
+
+ factor_m = fMult(factor_m, mult);
+
+ FIXP_DBL tmp_r, tmp_i;
+ cplxMultDiv2(&tmp_r, &tmp_i, g_r_m, g_i_m, gammaCenterReal_m,
+ gammaCenterImag_m);
+
+ g_r_m = fMultDiv2(tmp_r, factor_m) << shift;
+ g_i_m = fMultDiv2(tmp_i, factor_m) << shift;
+ g_e = scale_factor_hbe - (g_e + factor_e + gammaCenter_e + add);
+ fMax((INT)0, g_e);
+ *qmfHBEBufReal_F += g_r_m >> g_e;
+ *qmfHBEBufImag_F += g_i_m >> g_e;
+ }
+}
+
+void QmfTransposerApply(HANDLE_HBE_TRANSPOSER hQmfTransposer,
+ FIXP_DBL** qmfBufferCodecReal,
+ FIXP_DBL** qmfBufferCodecImag, int nColsIn,
+ FIXP_DBL** ppQmfBufferOutReal_F,
+ FIXP_DBL** ppQmfBufferOutImag_F,
+ FIXP_DBL lpcFilterStatesReal[2 + (3 * (4))][(64)],
+ FIXP_DBL lpcFilterStatesImag[2 + (3 * (4))][(64)],
+ int pitchInBins, int scale_lb, int scale_hbe,
+ int* scale_hb, int timeStep, int firstSlotOffsset,
+ int ov_len,
+ KEEP_STATES_SYNCED_MODE keepStatesSyncedMode) {
+ int i, j, stretch, band, sourceband, r, s;
+ int qmfVocoderColsIn = hQmfTransposer->noCols / 2;
+ int bSbr41 = hQmfTransposer->bSbr41;
+
+ const int winLength[3] = {10, 8, 6};
+ const int slotOffset = 6; /* hQmfTransposer->winLen-6; */
+
+ int qmfOffset = 2 * hQmfTransposer->kstart;
+ int scale_border = (nColsIn == 64) ? 32 : nColsIn;
+
+ INT slot_stretch4[9] = {0, 0, 0, 0, 2, 4, 6, 8, 10};
+ INT slot_stretch2[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ INT slot_stretch3[10] = {0, 0, 0, 1, 3, 4, 6, 7, 9, 10};
+ INT filt_stretch3[10] = {0, 0, 0, 1, 0, 1, 0, 1, 0, 1};
+ INT filt_dummy[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ INT* pSlotStretch;
+ INT* pFilt;
+
+ int offset = 0; /* where to take QmfTransposer data */
+
+ int signPreMod =
+ (hQmfTransposer->synthesisQmfPreModCos_F[0] < FL2FXCONST_DBL(0.f)) ? 1
+ : -1;
+
+ int scale_factor_hbe =
+ getHBEScaleFactorFrame(bSbr41, hQmfTransposer->maxStretch, pitchInBins);
+
+ if (keepStatesSyncedMode != KEEP_STATES_SYNCED_OFF) {
+ offset = hQmfTransposer->noCols - ov_len - LPC_ORDER;
+ }
+
+ hQmfTransposer->highband_exp[0] = hQmfTransposer->highband_exp[1];
+ hQmfTransposer->target_exp[0] = hQmfTransposer->target_exp[1];
+
+ hQmfTransposer->highband_exp[1] = scale_factor_hbe;
+ hQmfTransposer->target_exp[1] =
+ fixMax(hQmfTransposer->highband_exp[1], hQmfTransposer->highband_exp[0]);
+
+ scale_factor_hbe = hQmfTransposer->target_exp[1];
+
+ int shift_ov = hQmfTransposer->target_exp[0] - hQmfTransposer->target_exp[1];
+
+ if (shift_ov != 0) {
+ for (i = 0; i < HBE_MAX_OUT_SLOTS; i++) {
+ for (band = 0; band < QMF_SYNTH_CHANNELS; band++) {
+ if (shift_ov >= 0) {
+ hQmfTransposer->qmfHBEBufReal_F[i][band] <<= shift_ov;
+ hQmfTransposer->qmfHBEBufImag_F[i][band] <<= shift_ov;
+ } else {
+ hQmfTransposer->qmfHBEBufReal_F[i][band] >>= (-shift_ov);
+ hQmfTransposer->qmfHBEBufImag_F[i][band] >>= (-shift_ov);
+ }
+ }
+ }
+ }
+
+ if ((keepStatesSyncedMode == KEEP_STATES_SYNCED_OFF) && shift_ov != 0) {
+ for (i = timeStep * firstSlotOffsset; i < ov_len; i++) {
+ for (band = hQmfTransposer->startBand; band < hQmfTransposer->stopBand;
+ band++) {
+ if (shift_ov >= 0) {
+ ppQmfBufferOutReal_F[i][band] <<= shift_ov;
+ ppQmfBufferOutImag_F[i][band] <<= shift_ov;
+ } else {
+ ppQmfBufferOutReal_F[i][band] >>= (-shift_ov);
+ ppQmfBufferOutImag_F[i][band] >>= (-shift_ov);
+ }
+ }
+ }
+
+ /* shift lpc filterstates */
+ for (i = 0; i < timeStep * firstSlotOffsset + LPC_ORDER; i++) {
+ for (band = 0; band < (64); band++) {
+ if (shift_ov >= 0) {
+ lpcFilterStatesReal[i][band] <<= shift_ov;
+ lpcFilterStatesImag[i][band] <<= shift_ov;
+ } else {
+ lpcFilterStatesReal[i][band] >>= (-shift_ov);
+ lpcFilterStatesImag[i][band] >>= (-shift_ov);
+ }
+ }
+ }
+ }
+
+ FIXP_DBL twid_m_new[3][2]; /* [stretch][cos/sin] */
+ INT stepsize = 1 + !bSbr41, sine_offset = 24, mod = 96;
+ INT mult[3] = {1, 2, 3};
+
+ for (s = 0; s <= MAX_STRETCH_HBE - 2; s++) {
+ twid_m_new[s][0] = twiddle[(mult[s] * (stepsize * pitchInBins)) % mod];
+ twid_m_new[s][1] =
+ twiddle[((mult[s] * (stepsize * pitchInBins)) + sine_offset) % mod];
+ }
+
+ /* Time-stretch */
+ for (j = 0; j < qmfVocoderColsIn; j++) {
+ int sign = -1, k, z, addrshift, codecTemp_e;
+ /* update inbuf */
+ for (i = 0; i < hQmfTransposer->synthSize; i++) {
+ hQmfTransposer->inBuf_F[i] =
+ hQmfTransposer->inBuf_F[i + 2 * hQmfTransposer->synthSize];
+ }
+
+ /* run synthesis for two sbr slots as transposer uses
+ half slots double bands representation */
+ for (z = 0; z < 2; z++) {
+ int scale_factor = ((nColsIn == 64) && ((2 * j + z) < scale_border))
+ ? scale_lb
+ : scale_hbe;
+ codecTemp_e = scale_factor - 1; /* -2 for Div2 and cos/sin scale of 1 */
+
+ for (k = 0; k < hQmfTransposer->synthSize; k++) {
+ int ki = hQmfTransposer->kstart + k;
+ hQmfTransposer->qmfBufferCodecTempSlot_F[k] =
+ fMultDiv2(signPreMod * hQmfTransposer->synthesisQmfPreModCos_F[k],
+ qmfBufferCodecReal[2 * j + z][ki]);
+ hQmfTransposer->qmfBufferCodecTempSlot_F[k] +=
+ fMultDiv2(signPreMod * hQmfTransposer->synthesisQmfPreModSin_F[k],
+ qmfBufferCodecImag[2 * j + z][ki]);
+ }
+
+ C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, (HBE_MAX_QMF_BANDS << 1));
+
+ qmfSynthesisFilteringSlot(
+ &hQmfTransposer->HBESynthesisQMF,
+ hQmfTransposer->qmfBufferCodecTempSlot_F, NULL, 0,
+ -7 - hQmfTransposer->HBESynthesisQMF.filterScale - codecTemp_e + 1,
+ hQmfTransposer->inBuf_F + hQmfTransposer->synthSize * (z + 1), 1,
+ pWorkBuffer);
+
+ C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, (HBE_MAX_QMF_BANDS << 1));
+ }
+
+ C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, (HBE_MAX_QMF_BANDS << 1));
+
+ qmfAnalysisFilteringSlot(&hQmfTransposer->HBEAnalysiscQMF,
+ hQmfTransposer->qmfInBufReal_F[QMF_WIN_LEN - 1],
+ hQmfTransposer->qmfInBufImag_F[QMF_WIN_LEN - 1],
+ hQmfTransposer->inBuf_F + 1, 1, pWorkBuffer);
+
+ C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, (HBE_MAX_QMF_BANDS << 1));
+
+ if ((keepStatesSyncedMode == KEEP_STATES_SYNCED_NORMAL) &&
+ j <= qmfVocoderColsIn - ((LPC_ORDER + ov_len + QMF_WIN_LEN - 1) >> 1)) {
+ /* update in buffer */
+ for (i = 0; i < QMF_WIN_LEN - 1; i++) {
+ FDKmemcpy(
+ hQmfTransposer->qmfInBufReal_F[i],
+ hQmfTransposer->qmfInBufReal_F[i + 1],
+ sizeof(FIXP_DBL) * hQmfTransposer->HBEAnalysiscQMF.no_channels);
+ FDKmemcpy(
+ hQmfTransposer->qmfInBufImag_F[i],
+ hQmfTransposer->qmfInBufImag_F[i + 1],
+ sizeof(FIXP_DBL) * hQmfTransposer->HBEAnalysiscQMF.no_channels);
+ }
+ continue;
+ }
+
+ for (stretch = 2; stretch <= hQmfTransposer->maxStretch; stretch++) {
+ int start = slotOffset - winLength[stretch - 2] / 2;
+ int stop = slotOffset + winLength[stretch - 2] / 2;
+
+ FIXP_DBL factor = FL2FXCONST_DBL(1.f / 3.f);
+
+ for (band = hQmfTransposer->xOverQmf[stretch - 2];
+ band < hQmfTransposer->xOverQmf[stretch - 1]; band++) {
+ FIXP_DBL gammaCenterReal_m[2] = {(FIXP_DBL)0, (FIXP_DBL)0},
+ gammaCenterImag_m[2] = {(FIXP_DBL)0, (FIXP_DBL)0};
+ INT gammaCenter_e[2] = {0, 0};
+
+ FIXP_DBL gammaVecReal_m[2] = {(FIXP_DBL)0, (FIXP_DBL)0},
+ gammaVecImag_m[2] = {(FIXP_DBL)0, (FIXP_DBL)0};
+ INT gammaVec_e[2] = {0, 0};
+
+ FIXP_DBL wingain = (FIXP_DBL)0;
+
+ gammaCenter_e[0] =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ gammaCenter_e[1] =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+
+ /* interpolation filters for 3rd order */
+ sourceband = 2 * band / stretch - qmfOffset;
+ FDK_ASSERT(sourceband >= 0);
+
+ /* maximum gammaCenter_e == 20 */
+ calculateCenterFIXP(
+ hQmfTransposer->qmfInBufReal_F[slotOffset][sourceband],
+ hQmfTransposer->qmfInBufImag_F[slotOffset][sourceband],
+ &gammaCenterReal_m[0], &gammaCenterImag_m[0], &gammaCenter_e[0],
+ stretch, stretch - 2);
+
+ if (stretch == 4) {
+ r = band - 2 * (band / 2);
+ sourceband += (r == 0) ? -1 : 1;
+ pSlotStretch = slot_stretch4;
+ factor = FL2FXCONST_DBL(2.f / 3.f);
+ pFilt = filt_dummy;
+ } else if (stretch == 2) {
+ r = 0;
+ sourceband = 2 * band / stretch - qmfOffset;
+ pSlotStretch = slot_stretch2;
+ factor = FL2FXCONST_DBL(1.f / 3.f);
+ pFilt = filt_dummy;
+ } else {
+ r = 2 * band - 3 * (2 * band / 3);
+ sourceband = 2 * band / stretch - qmfOffset;
+ pSlotStretch = slot_stretch3;
+ factor = FL2FXCONST_DBL(1.4142f / 3.0f);
+ pFilt = filt_stretch3;
+ }
+
+ if (r == 2) {
+ calculateCenterFIXP(
+ hQmfTransposer->qmfInBufReal_F[slotOffset][sourceband + 1],
+ hQmfTransposer->qmfInBufImag_F[slotOffset][sourceband + 1],
+ &gammaCenterReal_m[1], &gammaCenterImag_m[1], &gammaCenter_e[1],
+ stretch, stretch - 2);
+
+ factor = FL2FXCONST_DBL(1.4142f / 6.0f);
+ }
+
+ if (r == 2) {
+ for (k = start; k < stop; k++) {
+ gammaVecReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[pSlotStretch[k]][sourceband];
+ gammaVecReal_m[1] =
+ hQmfTransposer->qmfInBufReal_F[pSlotStretch[k]][sourceband + 1];
+ gammaVecImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[pSlotStretch[k]][sourceband];
+ gammaVecImag_m[1] =
+ hQmfTransposer->qmfInBufImag_F[pSlotStretch[k]][sourceband + 1];
+ gammaVec_e[0] = gammaVec_e[1] =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+
+ if (pFilt[k] == 1) {
+ FIXP_DBL tmpRealF = gammaVecReal_m[0], tmpImagF;
+ gammaVecReal_m[0] =
+ (fMult(gammaVecReal_m[0], hintReal_F[sourceband % 4][1]) -
+ fMult(gammaVecImag_m[0],
+ hintReal_F[(sourceband + 3) % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVecImag_m[0] =
+ (fMult(tmpRealF, hintReal_F[(sourceband + 3) % 4][1]) +
+ fMult(gammaVecImag_m[0], hintReal_F[sourceband % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+
+ tmpRealF = hQmfTransposer
+ ->qmfInBufReal_F[pSlotStretch[k] + 1][sourceband];
+ tmpImagF = hQmfTransposer
+ ->qmfInBufImag_F[pSlotStretch[k] + 1][sourceband];
+
+ gammaVecReal_m[0] +=
+ (fMult(tmpRealF, hintReal_F[sourceband % 4][1]) -
+ fMult(tmpImagF, hintReal_F[(sourceband + 1) % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVecImag_m[0] +=
+ (fMult(tmpRealF, hintReal_F[(sourceband + 1) % 4][1]) +
+ fMult(tmpImagF, hintReal_F[sourceband % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVec_e[0]++;
+
+ tmpRealF = gammaVecReal_m[1];
+
+ gammaVecReal_m[1] =
+ (fMult(gammaVecReal_m[1], hintReal_F[sourceband % 4][2]) -
+ fMult(gammaVecImag_m[1],
+ hintReal_F[(sourceband + 3) % 4][2])) >>
+ 1;
+ gammaVecImag_m[1] =
+ (fMult(tmpRealF, hintReal_F[(sourceband + 3) % 4][2]) +
+ fMult(gammaVecImag_m[1], hintReal_F[sourceband % 4][2])) >>
+ 1;
+
+ tmpRealF =
+ hQmfTransposer
+ ->qmfInBufReal_F[pSlotStretch[k] + 1][sourceband + 1];
+ tmpImagF =
+ hQmfTransposer
+ ->qmfInBufImag_F[pSlotStretch[k] + 1][sourceband + 1];
+
+ gammaVecReal_m[1] +=
+ (fMult(tmpRealF, hintReal_F[sourceband % 4][2]) -
+ fMult(tmpImagF, hintReal_F[(sourceband + 1) % 4][2])) >>
+ 1;
+ gammaVecImag_m[1] +=
+ (fMult(tmpRealF, hintReal_F[(sourceband + 1) % 4][2]) +
+ fMult(tmpImagF, hintReal_F[sourceband % 4][2])) >>
+ 1;
+ gammaVec_e[1]++;
+ }
+
+ addHighBandPart(gammaVecReal_m[1], gammaVecImag_m[1], gammaVec_e[1],
+ factor, gammaCenterReal_m[0], gammaCenterImag_m[0],
+ gammaCenter_e[0], stretch, scale_factor_hbe,
+ &hQmfTransposer->qmfHBEBufReal_F[k][band],
+ &hQmfTransposer->qmfHBEBufImag_F[k][band]);
+
+ addHighBandPart(gammaVecReal_m[0], gammaVecImag_m[0], gammaVec_e[0],
+ factor, gammaCenterReal_m[1], gammaCenterImag_m[1],
+ gammaCenter_e[1], stretch, scale_factor_hbe,
+ &hQmfTransposer->qmfHBEBufReal_F[k][band],
+ &hQmfTransposer->qmfHBEBufImag_F[k][band]);
+ }
+ } else {
+ for (k = start; k < stop; k++) {
+ gammaVecReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[pSlotStretch[k]][sourceband];
+ gammaVecImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[pSlotStretch[k]][sourceband];
+ gammaVec_e[0] =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+
+ if (pFilt[k] == 1) {
+ FIXP_DBL tmpRealF = gammaVecReal_m[0], tmpImagF;
+ gammaVecReal_m[0] =
+ (fMult(gammaVecReal_m[0], hintReal_F[sourceband % 4][1]) -
+ fMult(gammaVecImag_m[0],
+ hintReal_F[(sourceband + 3) % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVecImag_m[0] =
+ (fMult(tmpRealF, hintReal_F[(sourceband + 3) % 4][1]) +
+ fMult(gammaVecImag_m[0], hintReal_F[sourceband % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+
+ tmpRealF = hQmfTransposer
+ ->qmfInBufReal_F[pSlotStretch[k] + 1][sourceband];
+ tmpImagF = hQmfTransposer
+ ->qmfInBufImag_F[pSlotStretch[k] + 1][sourceband];
+
+ gammaVecReal_m[0] +=
+ (fMult(tmpRealF, hintReal_F[sourceband % 4][1]) -
+ fMult(tmpImagF, hintReal_F[(sourceband + 1) % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVecImag_m[0] +=
+ (fMult(tmpRealF, hintReal_F[(sourceband + 1) % 4][1]) +
+ fMult(tmpImagF, hintReal_F[sourceband % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVec_e[0]++;
+ }
+
+ addHighBandPart(gammaVecReal_m[0], gammaVecImag_m[0], gammaVec_e[0],
+ factor, gammaCenterReal_m[0], gammaCenterImag_m[0],
+ gammaCenter_e[0], stretch, scale_factor_hbe,
+ &hQmfTransposer->qmfHBEBufReal_F[k][band],
+ &hQmfTransposer->qmfHBEBufImag_F[k][band]);
+ }
+ }
+
+ /* pitchInBins is given with the resolution of a 768 bins FFT and we
+ * need 64 QMF units so factor 768/64 = 12 */
+ if (pitchInBins >= pmin * (1 + bSbr41)) {
+ int tr, ti1, ti2, mTr = 0, ts1 = 0, ts2 = 0, mVal_e = 0, temp_e = 0;
+ int sqmag0_e =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+
+ FIXP_DBL mVal_F = FL2FXCONST_DBL(0.f), sqmag0_F, sqmag1_F, sqmag2_F,
+ temp_F, f1_F; /* all equal exponent */
+ sign = -1;
+
+ sourceband = 2 * band / stretch - qmfOffset; /* consistent with the
+ already computed for
+ stretch = 3,4. */
+ FDK_ASSERT(sourceband >= 0);
+
+ FIXP_DBL sqmag0R_F =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][sourceband];
+ FIXP_DBL sqmag0I_F =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][sourceband];
+ scaleUp(&sqmag0R_F, &sqmag0I_F, &sqmag0_e);
+
+ sqmag0_F = fPow2Div2(sqmag0R_F);
+ sqmag0_F += fPow2Div2(sqmag0I_F);
+ sqmag0_e = 2 * sqmag0_e + 1;
+
+ for (tr = 1; tr < stretch; tr++) {
+ int sqmag1_e =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ int sqmag2_e =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+
+ FIXP_DBL tmp_band = band_F[band];
+ FIXP_DBL tr_p =
+ fMult(p_F[pitchInBins] >> bSbr41, tr_str[tr - 1]); /* scale 7 */
+ f1_F =
+ fMult(tmp_band - tr_p, stretchfac[stretch - 2]); /* scale 7 */
+ ti1 = (INT)(f1_F >> (DFRACT_BITS - 1 - 7)) - qmfOffset;
+ ti2 = (INT)(((f1_F) + ((p_F[pitchInBins] >> bSbr41) >> 2)) >>
+ (DFRACT_BITS - 1 - 7)) -
+ qmfOffset;
+
+ if (ti1 >= 0 && ti2 < 2 * hQmfTransposer->synthSize) {
+ FIXP_DBL sqmag1R_F =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ti1];
+ FIXP_DBL sqmag1I_F =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ti1];
+ scaleUp(&sqmag1R_F, &sqmag1I_F, &sqmag1_e);
+ sqmag1_F = fPow2Div2(sqmag1R_F);
+ sqmag1_F += fPow2Div2(sqmag1I_F);
+ sqmag1_e = 2 * sqmag1_e + 1;
+
+ FIXP_DBL sqmag2R_F =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ti2];
+ FIXP_DBL sqmag2I_F =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ti2];
+ scaleUp(&sqmag2R_F, &sqmag2I_F, &sqmag2_e);
+ sqmag2_F = fPow2Div2(sqmag2R_F);
+ sqmag2_F += fPow2Div2(sqmag2I_F);
+ sqmag2_e = 2 * sqmag2_e + 1;
+
+ int shift1 = fMin(fMax(sqmag1_e, sqmag2_e) - sqmag1_e, 31);
+ int shift2 = fMin(fMax(sqmag1_e, sqmag2_e) - sqmag2_e, 31);
+
+ temp_F = fMin((sqmag1_F >> shift1), (sqmag2_F >> shift2));
+ temp_e = fMax(sqmag1_e, sqmag2_e);
+
+ int shift3 = fMin(fMax(temp_e, mVal_e) - temp_e, 31);
+ int shift4 = fMin(fMax(temp_e, mVal_e) - mVal_e, 31);
+
+ if ((temp_F >> shift3) > (mVal_F >> shift4)) {
+ mVal_F = temp_F;
+ mVal_e = temp_e; /* equals sqmag2_e + shift2 */
+ mTr = tr;
+ ts1 = ti1;
+ ts2 = ti2;
+ }
+ }
+ }
+
+ int shift1 = fMin(fMax(sqmag0_e, mVal_e) - sqmag0_e, 31);
+ int shift2 = fMin(fMax(sqmag0_e, mVal_e) - mVal_e, 31);
+
+ if ((mVal_F >> shift2) > (sqmag0_F >> shift1) && ts1 >= 0 &&
+ ts2 < 2 * hQmfTransposer->synthSize) {
+ INT gammaOut_e[2];
+ FIXP_DBL gammaOutReal_m[2], gammaOutImag_m[2];
+ FIXP_DBL tmpReal_m = (FIXP_DBL)0, tmpImag_m = (FIXP_DBL)0;
+
+ int Tcenter, Tvec;
+
+ Tcenter = stretch - mTr; /* default phase power parameters */
+ Tvec = mTr;
+ switch (stretch) /* 2 tap block creation design depends on stretch
+ order */
+ {
+ case 2:
+ wingain =
+ FL2FXCONST_DBL(5.f / 12.f); /* sum of taps divided by two */
+
+ if (hQmfTransposer->bXProducts[0]) {
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts1];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts1];
+
+ for (k = 0; k < 2; k++) {
+ gammaVecReal_m[k] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset - 1 + k][ts2];
+ gammaVecImag_m[k] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset - 1 + k][ts2];
+ }
+
+ gammaCenter_e[0] = SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ gammaVec_e[0] = gammaVec_e[1] = SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ }
+ break;
+
+ case 4:
+ wingain =
+ FL2FXCONST_DBL(6.f / 12.f); /* sum of taps divided by two */
+ if (hQmfTransposer->bXProducts[2]) {
+ if (mTr == 1) {
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts1];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts1];
+
+ for (k = 0; k < 2; k++) {
+ gammaVecReal_m[k] =
+ hQmfTransposer
+ ->qmfInBufReal_F[slotOffset + 2 * (k - 1)][ts2];
+ gammaVecImag_m[k] =
+ hQmfTransposer
+ ->qmfInBufImag_F[slotOffset + 2 * (k - 1)][ts2];
+ }
+ } else if (mTr == 2) {
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts1];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts1];
+
+ for (k = 0; k < 2; k++) {
+ gammaVecReal_m[k] =
+ hQmfTransposer
+ ->qmfInBufReal_F[slotOffset + (k - 1)][ts2];
+ gammaVecImag_m[k] =
+ hQmfTransposer
+ ->qmfInBufImag_F[slotOffset + (k - 1)][ts2];
+ }
+ } else /* (mTr == 3) */
+ {
+ sign = 1;
+ Tcenter = mTr; /* opposite phase power parameters as ts2 is
+ center */
+ Tvec = stretch - mTr;
+
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts2];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts2];
+
+ for (k = 0; k < 2; k++) {
+ gammaVecReal_m[k] =
+ hQmfTransposer
+ ->qmfInBufReal_F[slotOffset + 2 * (k - 1)][ts1];
+ gammaVecImag_m[k] =
+ hQmfTransposer
+ ->qmfInBufImag_F[slotOffset + 2 * (k - 1)][ts1];
+ }
+ }
+
+ gammaCenter_e[0] = SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ gammaVec_e[0] = gammaVec_e[1] = SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ }
+ break;
+
+ case 3:
+ wingain = FL2FXCONST_DBL(5.6568f /
+ 12.f); /* sum of taps divided by two */
+
+ if (hQmfTransposer->bXProducts[1]) {
+ FIXP_DBL tmpReal_F, tmpImag_F;
+ if (mTr == 1) {
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts1];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts1];
+ gammaVecReal_m[1] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts2];
+ gammaVecImag_m[1] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts2];
+
+ addrshift = -2;
+ tmpReal_F =
+ hQmfTransposer
+ ->qmfInBufReal_F[addrshift + slotOffset][ts2];
+ tmpImag_F =
+ hQmfTransposer
+ ->qmfInBufImag_F[addrshift + slotOffset][ts2];
+
+ gammaVecReal_m[0] =
+ (fMult(factors[ts2 % 4], tmpReal_F) -
+ fMult(factors[(ts2 + 3) % 4], tmpImag_F)) >>
+ 1;
+ gammaVecImag_m[0] =
+ (fMult(factors[(ts2 + 3) % 4], tmpReal_F) +
+ fMult(factors[ts2 % 4], tmpImag_F)) >>
+ 1;
+
+ tmpReal_F =
+ hQmfTransposer
+ ->qmfInBufReal_F[addrshift + 1 + slotOffset][ts2];
+ tmpImag_F =
+ hQmfTransposer
+ ->qmfInBufImag_F[addrshift + 1 + slotOffset][ts2];
+
+ gammaVecReal_m[0] +=
+ (fMult(factors[ts2 % 4], tmpReal_F) -
+ fMult(factors[(ts2 + 1) % 4], tmpImag_F)) >>
+ 1;
+ gammaVecImag_m[0] +=
+ (fMult(factors[(ts2 + 1) % 4], tmpReal_F) +
+ fMult(factors[ts2 % 4], tmpImag_F)) >>
+ 1;
+
+ } else /* (mTr == 2) */
+ {
+ sign = 1;
+ Tcenter = mTr; /* opposite phase power parameters as ts2 is
+ center */
+ Tvec = stretch - mTr;
+
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts2];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts2];
+ gammaVecReal_m[1] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts1];
+ gammaVecImag_m[1] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts1];
+
+ addrshift = -2;
+ tmpReal_F =
+ hQmfTransposer
+ ->qmfInBufReal_F[addrshift + slotOffset][ts1];
+ tmpImag_F =
+ hQmfTransposer
+ ->qmfInBufImag_F[addrshift + slotOffset][ts1];
+
+ gammaVecReal_m[0] =
+ (fMult(factors[ts1 % 4], tmpReal_F) -
+ fMult(factors[(ts1 + 3) % 4], tmpImag_F)) >>
+ 1;
+ gammaVecImag_m[0] =
+ (fMult(factors[(ts1 + 3) % 4], tmpReal_F) +
+ fMult(factors[ts1 % 4], tmpImag_F)) >>
+ 1;
+
+ tmpReal_F =
+ hQmfTransposer
+ ->qmfInBufReal_F[addrshift + 1 + slotOffset][ts1];
+ tmpImag_F =
+ hQmfTransposer
+ ->qmfInBufImag_F[addrshift + 1 + slotOffset][ts1];
+
+ gammaVecReal_m[0] +=
+ (fMult(factors[ts1 % 4], tmpReal_F) -
+ fMult(factors[(ts1 + 1) % 4], tmpImag_F)) >>
+ 1;
+ gammaVecImag_m[0] +=
+ (fMult(factors[(ts1 + 1) % 4], tmpReal_F) +
+ fMult(factors[ts1 % 4], tmpImag_F)) >>
+ 1;
+ }
+
+ gammaCenter_e[0] = gammaVec_e[1] = SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ gammaVec_e[0] =
+ SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor) +
+ 1;
+ }
+ break;
+ default:
+ FDK_ASSERT(0);
+ break;
+ } /* stretch cases */
+
+ /* parameter controlled phase modification parts */
+ /* maximum *_e == 20 */
+ calculateCenterFIXP(gammaCenterReal_m[0], gammaCenterImag_m[0],
+ &gammaCenterReal_m[0], &gammaCenterImag_m[0],
+ &gammaCenter_e[0], stretch, Tcenter - 1);
+ calculateCenterFIXP(gammaVecReal_m[0], gammaVecImag_m[0],
+ &gammaVecReal_m[0], &gammaVecImag_m[0],
+ &gammaVec_e[0], stretch, Tvec - 1);
+ calculateCenterFIXP(gammaVecReal_m[1], gammaVecImag_m[1],
+ &gammaVecReal_m[1], &gammaVecImag_m[1],
+ &gammaVec_e[1], stretch, Tvec - 1);
+
+ /* Final multiplication of prepared parts */
+ for (k = 0; k < 2; k++) {
+ gammaOutReal_m[k] =
+ fMultDiv2(gammaVecReal_m[k], gammaCenterReal_m[0]) -
+ fMultDiv2(gammaVecImag_m[k], gammaCenterImag_m[0]);
+ gammaOutImag_m[k] =
+ fMultDiv2(gammaVecReal_m[k], gammaCenterImag_m[0]) +
+ fMultDiv2(gammaVecImag_m[k], gammaCenterReal_m[0]);
+ gammaOut_e[k] = gammaCenter_e[0] + gammaVec_e[k] + 1;
+ }
+
+ scaleUp(&gammaOutReal_m[0], &gammaOutImag_m[0], &gammaOut_e[0]);
+ scaleUp(&gammaOutReal_m[1], &gammaOutImag_m[1], &gammaOut_e[1]);
+ FDK_ASSERT(gammaOut_e[0] >= 0);
+ FDK_ASSERT(gammaOut_e[0] < 32);
+
+ tmpReal_m = gammaOutReal_m[0];
+ tmpImag_m = gammaOutImag_m[0];
+
+ INT modstretch4 = ((stretch == 4) && (mTr == 2));
+
+ FIXP_DBL cos_twid = twid_m_new[stretch - 2 - modstretch4][0];
+ FIXP_DBL sin_twid = sign * twid_m_new[stretch - 2 - modstretch4][1];
+
+ gammaOutReal_m[0] =
+ fMult(tmpReal_m, cos_twid) -
+ fMult(tmpImag_m, sin_twid); /* sum should be <= 1 because of
+ sin/cos multiplication */
+ gammaOutImag_m[0] =
+ fMult(tmpImag_m, cos_twid) +
+ fMult(tmpReal_m, sin_twid); /* sum should be <= 1 because of
+ sin/cos multiplication */
+
+ /* wingain */
+ for (k = 0; k < 2; k++) {
+ gammaOutReal_m[k] = (fMult(gammaOutReal_m[k], wingain) << 1);
+ gammaOutImag_m[k] = (fMult(gammaOutImag_m[k], wingain) << 1);
+ }
+
+ gammaOutReal_m[1] >>= 1;
+ gammaOutImag_m[1] >>= 1;
+ gammaOut_e[0] += 2;
+ gammaOut_e[1] += 2;
+
+ /* OLA including window scaling by wingain/3 */
+ for (k = 0; k < 2; k++) /* need k=1 to correspond to
+ grainModImag[slotOffset] -> out to
+ j*2+(slotOffset-offset) */
+ {
+ hQmfTransposer->qmfHBEBufReal_F[(k + slotOffset - 1)][band] +=
+ gammaOutReal_m[k] >> (scale_factor_hbe - gammaOut_e[k]);
+ hQmfTransposer->qmfHBEBufImag_F[(k + slotOffset - 1)][band] +=
+ gammaOutImag_m[k] >> (scale_factor_hbe - gammaOut_e[k]);
+ }
+ } /* mVal > qThrQMF * qThrQMF * sqmag0 && ts1 > 0 && ts2 < 64 */
+ } /* p >= pmin */
+ } /* for band */
+ } /* for stretch */
+
+ for (i = 0; i < QMF_WIN_LEN - 1; i++) {
+ FDKmemcpy(hQmfTransposer->qmfInBufReal_F[i],
+ hQmfTransposer->qmfInBufReal_F[i + 1],
+ sizeof(FIXP_DBL) * hQmfTransposer->HBEAnalysiscQMF.no_channels);
+ FDKmemcpy(hQmfTransposer->qmfInBufImag_F[i],
+ hQmfTransposer->qmfInBufImag_F[i + 1],
+ sizeof(FIXP_DBL) * hQmfTransposer->HBEAnalysiscQMF.no_channels);
+ }
+
+ if (keepStatesSyncedMode != KEEP_STATES_SYNCED_NOOUT) {
+ if (2 * j >= offset) {
+ /* copy first two slots of internal buffer to output */
+ if (keepStatesSyncedMode == KEEP_STATES_SYNCED_OUTDIFF) {
+ for (i = 0; i < 2; i++) {
+ FDKmemcpy(&ppQmfBufferOutReal_F[2 * j - offset + i]
+ [hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer
+ ->qmfHBEBufReal_F[i][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ FDKmemcpy(&ppQmfBufferOutImag_F[2 * j - offset + i]
+ [hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer
+ ->qmfHBEBufImag_F[i][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ }
+ } else {
+ for (i = 0; i < 2; i++) {
+ FDKmemcpy(&ppQmfBufferOutReal_F[2 * j + i + ov_len]
+ [hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer
+ ->qmfHBEBufReal_F[i][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ FDKmemcpy(&ppQmfBufferOutImag_F[2 * j + i + ov_len]
+ [hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer
+ ->qmfHBEBufImag_F[i][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ }
+ }
+ }
+ }
+
+ /* move slots up */
+ for (i = 0; i < HBE_MAX_OUT_SLOTS - 2; i++) {
+ FDKmemcpy(
+ &hQmfTransposer->qmfHBEBufReal_F[i][hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer->qmfHBEBufReal_F[i + 2][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ FDKmemcpy(
+ &hQmfTransposer->qmfHBEBufImag_F[i][hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer->qmfHBEBufImag_F[i + 2][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ }
+
+ /* finally set last two slot to zero */
+ for (i = 0; i < 2; i++) {
+ FDKmemset(&hQmfTransposer->qmfHBEBufReal_F[HBE_MAX_OUT_SLOTS - 1 - i]
+ [hQmfTransposer->xOverQmf[0]],
+ 0,
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ FDKmemset(&hQmfTransposer->qmfHBEBufImag_F[HBE_MAX_OUT_SLOTS - 1 - i]
+ [hQmfTransposer->xOverQmf[0]],
+ 0,
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ }
+ } /* qmfVocoderColsIn */
+
+ if (keepStatesSyncedMode != KEEP_STATES_SYNCED_NOOUT) {
+ if (keepStatesSyncedMode == KEEP_STATES_SYNCED_OUTDIFF) {
+ for (i = 0; i < ov_len + LPC_ORDER; i++) {
+ for (band = hQmfTransposer->startBand; band < hQmfTransposer->stopBand;
+ band++) {
+ FIXP_DBL tmpR = ppQmfBufferOutReal_F[i][band];
+ FIXP_DBL tmpI = ppQmfBufferOutImag_F[i][band];
+
+ ppQmfBufferOutReal_F[i][band] =
+ fMult(tmpR, cos_F[band]) -
+ fMult(tmpI, (-cos_F[64 - band - 1])); /* sum should be <= 1
+ because of sin/cos
+ multiplication */
+ ppQmfBufferOutImag_F[i][band] =
+ fMult(tmpR, (-cos_F[64 - band - 1])) +
+ fMult(tmpI, cos_F[band]); /* sum should by <= 1 because of sin/cos
+ multiplication */
+ }
+ }
+ } else {
+ for (i = offset; i < hQmfTransposer->noCols; i++) {
+ for (band = hQmfTransposer->startBand; band < hQmfTransposer->stopBand;
+ band++) {
+ FIXP_DBL tmpR = ppQmfBufferOutReal_F[i + ov_len][band];
+ FIXP_DBL tmpI = ppQmfBufferOutImag_F[i + ov_len][band];
+
+ ppQmfBufferOutReal_F[i + ov_len][band] =
+ fMult(tmpR, cos_F[band]) -
+ fMult(tmpI, (-cos_F[64 - band - 1])); /* sum should be <= 1
+ because of sin/cos
+ multiplication */
+ ppQmfBufferOutImag_F[i + ov_len][band] =
+ fMult(tmpR, (-cos_F[64 - band - 1])) +
+ fMult(tmpI, cos_F[band]); /* sum should by <= 1 because of sin/cos
+ multiplication */
+ }
+ }
+ }
+ }
+
+ *scale_hb = EXP2SCALE(scale_factor_hbe);
+}
+
+int* GetxOverBandQmfTransposer(HANDLE_HBE_TRANSPOSER hQmfTransposer) {
+ if (hQmfTransposer)
+ return hQmfTransposer->xOverQmf;
+ else
+ return NULL;
+}
+
+int Get41SbrQmfTransposer(HANDLE_HBE_TRANSPOSER hQmfTransposer) {
+ if (hQmfTransposer != NULL)
+ return hQmfTransposer->bSbr41;
+ else
+ return 0;
+}
diff --git a/fdk-aac/libSBRdec/src/hbe.h b/fdk-aac/libSBRdec/src/hbe.h
new file mode 100644
index 0000000..fdffe1e
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/hbe.h
@@ -0,0 +1,200 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+#ifndef HBE_H
+#define HBE_H
+
+#include "sbrdecoder.h"
+
+#ifndef QMF_SYNTH_CHANNELS
+#define QMF_SYNTH_CHANNELS (64)
+#endif
+
+#define HBE_QMF_FILTER_STATE_ANA_SIZE (400)
+#define HBE_QMF_FILTER_STATE_SYN_SIZE (200)
+
+#ifndef MAX_NUM_PATCHES_HBE
+#define MAX_NUM_PATCHES_HBE (6)
+#endif
+#define MAX_STRETCH_HBE (4)
+
+typedef enum {
+ KEEP_STATES_SYNCED_OFF = 0, /*!< normal QMF transposer behaviour */
+ KEEP_STATES_SYNCED_NORMAL = 1, /*!< QMF transposer called for syncing of
+ states the last 8/14 slots are calculated in
+ case next frame is HBE */
+ KEEP_STATES_SYNCED_OUTDIFF =
+ 2, /*!< QMF transposer behaviour as in normal case, but the calculated
+ slots are directly written to overlap area of buffer; only used in
+ resetSbrDec function */
+ KEEP_STATES_SYNCED_NOOUT =
+ 3 /*!< QMF transposer is called for syncing of states only, not output
+ is generated at all; only used in resetSbrDec function */
+} KEEP_STATES_SYNCED_MODE;
+
+struct hbeTransposer {
+ int xOverQmf[MAX_NUM_PATCHES_HBE];
+
+ int maxStretch;
+ int timeDomainWinLen;
+ int qmfInBufSize;
+ int qmfOutBufSize;
+ int noCols;
+ int noChannels;
+ int startBand;
+ int stopBand;
+ int bSbr41;
+
+ INT_PCM *inBuf_F;
+ FIXP_DBL **qmfInBufReal_F;
+ FIXP_DBL **qmfInBufImag_F;
+
+ FIXP_DBL *qmfBufferCodecTempSlot_F;
+
+ QMF_FILTER_BANK HBEAnalysiscQMF;
+ QMF_FILTER_BANK HBESynthesisQMF;
+
+ FIXP_DBL const *synthesisQmfPreModCos_F;
+ FIXP_DBL const *synthesisQmfPreModSin_F;
+
+ FIXP_QAS anaQmfStates[HBE_QMF_FILTER_STATE_ANA_SIZE];
+ FIXP_QSS synQmfStates[HBE_QMF_FILTER_STATE_SYN_SIZE];
+
+ FIXP_DBL **qmfHBEBufReal_F;
+ FIXP_DBL **qmfHBEBufImag_F;
+
+ int bXProducts[MAX_STRETCH_HBE];
+
+ int kstart;
+ int synthSize;
+
+ int highband_exp[2];
+ int target_exp[2];
+};
+
+typedef struct hbeTransposer *HANDLE_HBE_TRANSPOSER;
+
+SBR_ERROR QmfTransposerCreate(HANDLE_HBE_TRANSPOSER *hQmfTransposer,
+ const int frameSize, int bDisableCrossProducts,
+ int bSbr41);
+
+SBR_ERROR QmfTransposerReInit(HANDLE_HBE_TRANSPOSER hQmfTransposer,
+ UCHAR *FreqBandTable[2], UCHAR NSfb[2]);
+
+void QmfTransposerClose(HANDLE_HBE_TRANSPOSER hQmfTransposer);
+
+void QmfTransposerApply(HANDLE_HBE_TRANSPOSER hQmfTransposer,
+ FIXP_DBL **qmfBufferCodecReal,
+ FIXP_DBL **qmfBufferCodecImag, int nColsIn,
+ FIXP_DBL **ppQmfBufferOutReal_F,
+ FIXP_DBL **ppQmfBufferOutImag_F,
+ FIXP_DBL lpcFilterStatesReal[2 + (3 * (4))][(64)],
+ FIXP_DBL lpcFilterStatesImag[2 + (3 * (4))][(64)],
+ int pitchInBins, int scale_lb, int scale_hbe,
+ int *scale_hb, int timeStep, int firstSlotOffsset,
+ int ov_len,
+ KEEP_STATES_SYNCED_MODE keepStatesSyncedMode);
+
+int *GetxOverBandQmfTransposer(HANDLE_HBE_TRANSPOSER hQmfTransposer);
+
+int Get41SbrQmfTransposer(HANDLE_HBE_TRANSPOSER hQmfTransposer);
+#endif /* HBE_H */
diff --git a/fdk-aac/libSBRdec/src/huff_dec.cpp b/fdk-aac/libSBRdec/src/huff_dec.cpp
new file mode 100644
index 0000000..90c9541
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/huff_dec.cpp
@@ -0,0 +1,137 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Huffman Decoder
+*/
+
+#include "huff_dec.h"
+
+/***************************************************************************/
+/*!
+ \brief Decodes one huffman code word
+
+ Reads bits from the bitstream until a valid codeword is found.
+ The table entries are interpreted either as index to the next entry
+ or - if negative - as the codeword.
+
+ \return decoded value
+
+ \author
+
+****************************************************************************/
+int DecodeHuffmanCW(Huffman h, /*!< pointer to huffman codebook table */
+ HANDLE_FDK_BITSTREAM hBs) /*!< Handle to Bitbuffer */
+{
+ SCHAR index = 0;
+ int value, bit;
+
+ while (index >= 0) {
+ bit = FDKreadBits(hBs, 1);
+ index = h[index][bit];
+ }
+
+ value = index + 64; /* Add offset */
+
+ return value;
+}
diff --git a/fdk-aac/libSBRdec/src/huff_dec.h b/fdk-aac/libSBRdec/src/huff_dec.h
new file mode 100644
index 0000000..9aa62b4
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/huff_dec.h
@@ -0,0 +1,117 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Huffman Decoder
+*/
+#ifndef HUFF_DEC_H
+#define HUFF_DEC_H
+
+#include "sbrdecoder.h"
+#include "FDK_bitstream.h"
+
+typedef const SCHAR (*Huffman)[2];
+
+int DecodeHuffmanCW(Huffman h, HANDLE_FDK_BITSTREAM hBitBuf);
+
+#endif
diff --git a/fdk-aac/libSBRdec/src/lpp_tran.cpp b/fdk-aac/libSBRdec/src/lpp_tran.cpp
new file mode 100644
index 0000000..2ef07eb
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/lpp_tran.cpp
@@ -0,0 +1,1471 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Low Power Profile Transposer
+ This module provides the transposer. The main entry point is lppTransposer().
+ The function generates high frequency content by copying data from the low
+ band (provided by core codec) into the high band. This process is also
+ referred to as "patching". The function also implements spectral whitening by
+ means of inverse filtering based on LPC coefficients.
+
+ Together with the QMF filterbank the transposer can be tested using a supplied
+ test program. See main_audio.cpp for details. This module does use fractional
+ arithmetic and the accuracy of the computations has an impact on the overall
+ sound quality. The module also needs to take into account the different
+ scaling of spectral data.
+
+ \sa lppTransposer(), main_audio.cpp, sbr_scale.h, \ref documentationOverview
+*/
+
+#ifdef __ANDROID__
+#include "log/log.h"
+#endif
+
+#include "lpp_tran.h"
+
+#include "sbr_ram.h"
+#include "sbr_rom.h"
+
+#include "genericStds.h"
+#include "autocorr2nd.h"
+
+#include "HFgen_preFlat.h"
+
+#if defined(__arm__)
+#include "arm/lpp_tran_arm.cpp"
+#endif
+
+#define LPC_SCALE_FACTOR 2
+
+/*!
+ *
+ * \brief Get bandwidth expansion factor from filtering level
+ *
+ * Returns a filter parameter (bandwidth expansion factor) depending on
+ * the desired filtering level signalled in the bitstream.
+ * When switching the filtering level from LOW to OFF, an additional
+ * level is being inserted to achieve a smooth transition.
+ */
+
+static FIXP_DBL mapInvfMode(INVF_MODE mode, INVF_MODE prevMode,
+ WHITENING_FACTORS whFactors) {
+ switch (mode) {
+ case INVF_LOW_LEVEL:
+ if (prevMode == INVF_OFF)
+ return whFactors.transitionLevel;
+ else
+ return whFactors.lowLevel;
+
+ case INVF_MID_LEVEL:
+ return whFactors.midLevel;
+
+ case INVF_HIGH_LEVEL:
+ return whFactors.highLevel;
+
+ default:
+ if (prevMode == INVF_LOW_LEVEL)
+ return whFactors.transitionLevel;
+ else
+ return whFactors.off;
+ }
+}
+
+/*!
+ *
+ * \brief Perform inverse filtering level emphasis
+ *
+ * Retrieve bandwidth expansion factor and apply smoothing for each filter band
+ *
+ */
+
+static void inverseFilteringLevelEmphasis(
+ HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */
+ UCHAR nInvfBands, /*!< Number of bands for inverse filtering */
+ INVF_MODE *sbr_invf_mode, /*!< Current inverse filtering modes */
+ INVF_MODE *sbr_invf_mode_prev, /*!< Previous inverse filtering modes */
+ FIXP_DBL *bwVector /*!< Resulting filtering levels */
+) {
+ for (int i = 0; i < nInvfBands; i++) {
+ FIXP_DBL accu;
+ FIXP_DBL bwTmp = mapInvfMode(sbr_invf_mode[i], sbr_invf_mode_prev[i],
+ hLppTrans->pSettings->whFactors);
+
+ if (bwTmp < hLppTrans->bwVectorOld[i]) {
+ accu = fMultDiv2(FL2FXCONST_DBL(0.75f), bwTmp) +
+ fMultDiv2(FL2FXCONST_DBL(0.25f), hLppTrans->bwVectorOld[i]);
+ } else {
+ accu = fMultDiv2(FL2FXCONST_DBL(0.90625f), bwTmp) +
+ fMultDiv2(FL2FXCONST_DBL(0.09375f), hLppTrans->bwVectorOld[i]);
+ }
+
+ if (accu<FL2FXCONST_DBL(0.015625f)>> 1) {
+ bwVector[i] = FL2FXCONST_DBL(0.0f);
+ } else {
+ bwVector[i] = fixMin(accu << 1, FL2FXCONST_DBL(0.99609375f));
+ }
+ }
+}
+
+/* Resulting autocorrelation determinant exponent */
+#define ACDET_EXP \
+ (2 * (DFRACT_BITS + sbrScaleFactor->lb_scale + 10 - ac.det_scale))
+#define AC_EXP (-sbrScaleFactor->lb_scale + LPC_SCALE_FACTOR)
+#define ALPHA_EXP (-sbrScaleFactor->lb_scale + LPC_SCALE_FACTOR + 1)
+/* Resulting transposed QMF values exponent 16 bit normalized samplebits
+ * assumed. */
+#define QMFOUT_EXP ((SAMPLE_BITS - 15) - sbrScaleFactor->lb_scale)
+
+static inline void calc_qmfBufferReal(FIXP_DBL **qmfBufferReal,
+ const FIXP_DBL *const lowBandReal,
+ const int startSample,
+ const int stopSample, const UCHAR hiBand,
+ const int dynamicScale, const int descale,
+ const FIXP_SGL a0r, const FIXP_SGL a1r) {
+ FIXP_DBL accu1, accu2;
+ int i;
+
+ for (i = 0; i < stopSample - startSample; i++) {
+ accu1 = fMultDiv2(a1r, lowBandReal[i]);
+ accu1 = (fMultDiv2(a0r, lowBandReal[i + 1]) + accu1);
+ accu1 = accu1 >> dynamicScale;
+
+ accu1 <<= 1;
+ accu2 = (lowBandReal[i + 2] >> descale);
+ qmfBufferReal[i + startSample][hiBand] = accu1 + accu2;
+ }
+}
+
+/*!
+ *
+ * \brief Perform transposition by patching of subband samples.
+ * This function serves as the main entry point into the module. The function
+ * determines the areas for the patching process (these are the source range as
+ * well as the target range) and implements spectral whitening by means of
+ * inverse filtering. The function autoCorrelation2nd() is an auxiliary function
+ * for calculating the LPC coefficients for the filtering. The actual
+ * calculation of the LPC coefficients and the implementation of the filtering
+ * are done as part of lppTransposer().
+ *
+ * Note that the filtering is done on all available QMF subsamples, whereas the
+ * patching is only done on those QMF subsamples that will be used in the next
+ * QMF synthesis. The filtering is also implemented before the patching includes
+ * further dependencies on parameters from the SBR data.
+ *
+ */
+
+void lppTransposer(
+ HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */
+ QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */
+ FIXP_DBL **qmfBufferReal, /*!< Pointer to pointer to real part of subband
+ samples (source) */
+
+ FIXP_DBL *degreeAlias, /*!< Vector for results of aliasing estimation */
+ FIXP_DBL **qmfBufferImag, /*!< Pointer to pointer to imaginary part of
+ subband samples (source) */
+ const int useLP, const int fPreWhitening, const int v_k_master0,
+ const int timeStep, /*!< Time step of envelope */
+ const int firstSlotOffs, /*!< Start position in time */
+ const int lastSlotOffs, /*!< Number of overlap-slots into next frame */
+ const int nInvfBands, /*!< Number of bands for inverse filtering */
+ INVF_MODE *sbr_invf_mode, /*!< Current inverse filtering modes */
+ INVF_MODE *sbr_invf_mode_prev /*!< Previous inverse filtering modes */
+) {
+ INT bwIndex[MAX_NUM_PATCHES];
+ FIXP_DBL bwVector[MAX_NUM_PATCHES]; /*!< pole moving factors */
+ FIXP_DBL preWhiteningGains[(64) / 2];
+ int preWhiteningGains_exp[(64) / 2];
+
+ int i;
+ int loBand, start, stop;
+ TRANSPOSER_SETTINGS *pSettings = hLppTrans->pSettings;
+ PATCH_PARAM *patchParam = pSettings->patchParam;
+ int patch;
+
+ FIXP_SGL alphar[LPC_ORDER], a0r, a1r;
+ FIXP_SGL alphai[LPC_ORDER], a0i = 0, a1i = 0;
+ FIXP_SGL bw = FL2FXCONST_SGL(0.0f);
+
+ int autoCorrLength;
+
+ FIXP_DBL k1, k1_below = 0, k1_below2 = 0;
+
+ ACORR_COEFS ac;
+ int startSample;
+ int stopSample;
+ int stopSampleClear;
+
+ int comLowBandScale;
+ int ovLowBandShift;
+ int lowBandShift;
+ /* int ovHighBandShift;*/
+
+ alphai[0] = FL2FXCONST_SGL(0.0f);
+ alphai[1] = FL2FXCONST_SGL(0.0f);
+
+ startSample = firstSlotOffs * timeStep;
+ stopSample = pSettings->nCols + lastSlotOffs * timeStep;
+ FDK_ASSERT((lastSlotOffs * timeStep) <= pSettings->overlap);
+
+ inverseFilteringLevelEmphasis(hLppTrans, nInvfBands, sbr_invf_mode,
+ sbr_invf_mode_prev, bwVector);
+
+ stopSampleClear = stopSample;
+
+ autoCorrLength = pSettings->nCols + pSettings->overlap;
+
+ if (pSettings->noOfPatches > 0) {
+ /* Set upper subbands to zero:
+ This is required in case that the patches do not cover the complete
+ highband (because the last patch would be too short). Possible
+ optimization: Clearing bands up to usb would be sufficient here. */
+ int targetStopBand =
+ patchParam[pSettings->noOfPatches - 1].targetStartBand +
+ patchParam[pSettings->noOfPatches - 1].numBandsInPatch;
+
+ int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL);
+
+ if (!useLP) {
+ for (i = startSample; i < stopSampleClear; i++) {
+ FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
+ FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize);
+ }
+ } else {
+ for (i = startSample; i < stopSampleClear; i++) {
+ FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
+ }
+ }
+ }
+#ifdef __ANDROID__
+ else {
+ // Safetynet logging
+ android_errorWriteLog(0x534e4554, "112160868");
+ }
+#endif
+
+ /* init bwIndex for each patch */
+ FDKmemclear(bwIndex, sizeof(bwIndex));
+
+ /*
+ Calc common low band scale factor
+ */
+ comLowBandScale =
+ fixMin(sbrScaleFactor->ov_lb_scale, sbrScaleFactor->lb_scale);
+
+ ovLowBandShift = sbrScaleFactor->ov_lb_scale - comLowBandScale;
+ lowBandShift = sbrScaleFactor->lb_scale - comLowBandScale;
+ /* ovHighBandShift = firstSlotOffs == 0 ? ovLowBandShift:0;*/
+
+ if (fPreWhitening) {
+ sbrDecoder_calculateGainVec(
+ qmfBufferReal, qmfBufferImag,
+ DFRACT_BITS - 1 - 16 -
+ sbrScaleFactor->ov_lb_scale, /* convert scale to exponent */
+ DFRACT_BITS - 1 - 16 -
+ sbrScaleFactor->lb_scale, /* convert scale to exponent */
+ pSettings->overlap, preWhiteningGains, preWhiteningGains_exp,
+ v_k_master0, startSample, stopSample);
+ }
+
+ /* outer loop over bands to do analysis only once for each band */
+
+ if (!useLP) {
+ start = pSettings->lbStartPatching;
+ stop = pSettings->lbStopPatching;
+ } else {
+ start = fixMax(1, pSettings->lbStartPatching - 2);
+ stop = patchParam[0].targetStartBand;
+ }
+
+ for (loBand = start; loBand < stop; loBand++) {
+ FIXP_DBL lowBandReal[(((1024) / (32) * (4) / 2) + (3 * (4))) + LPC_ORDER];
+ FIXP_DBL *plowBandReal = lowBandReal;
+ FIXP_DBL **pqmfBufferReal =
+ qmfBufferReal + firstSlotOffs * timeStep /* + pSettings->overlap */;
+ FIXP_DBL lowBandImag[(((1024) / (32) * (4) / 2) + (3 * (4))) + LPC_ORDER];
+ FIXP_DBL *plowBandImag = lowBandImag;
+ FIXP_DBL **pqmfBufferImag =
+ qmfBufferImag + firstSlotOffs * timeStep /* + pSettings->overlap */;
+ int resetLPCCoeffs = 0;
+ int dynamicScale = DFRACT_BITS - 1 - LPC_SCALE_FACTOR;
+ int acDetScale = 0; /* scaling of autocorrelation determinant */
+
+ for (i = 0;
+ i < LPC_ORDER + firstSlotOffs * timeStep /*+pSettings->overlap*/;
+ i++) {
+ *plowBandReal++ = hLppTrans->lpcFilterStatesRealLegSBR[i][loBand];
+ if (!useLP)
+ *plowBandImag++ = hLppTrans->lpcFilterStatesImagLegSBR[i][loBand];
+ }
+
+ /*
+ Take old slope length qmf slot source values out of (overlap)qmf buffer
+ */
+ if (!useLP) {
+ for (i = 0;
+ i < pSettings->nCols + pSettings->overlap - firstSlotOffs * timeStep;
+ i++) {
+ *plowBandReal++ = (*pqmfBufferReal++)[loBand];
+ *plowBandImag++ = (*pqmfBufferImag++)[loBand];
+ }
+ } else {
+ /* pSettings->overlap is always even */
+ FDK_ASSERT((pSettings->overlap & 1) == 0);
+ for (i = 0; i < ((pSettings->nCols + pSettings->overlap -
+ firstSlotOffs * timeStep) >>
+ 1);
+ i++) {
+ *plowBandReal++ = (*pqmfBufferReal++)[loBand];
+ *plowBandReal++ = (*pqmfBufferReal++)[loBand];
+ }
+ if (pSettings->nCols & 1) {
+ *plowBandReal++ = (*pqmfBufferReal++)[loBand];
+ }
+ }
+
+ /*
+ Determine dynamic scaling value.
+ */
+ dynamicScale =
+ fixMin(dynamicScale,
+ getScalefactor(lowBandReal, LPC_ORDER + pSettings->overlap) +
+ ovLowBandShift);
+ dynamicScale =
+ fixMin(dynamicScale,
+ getScalefactor(&lowBandReal[LPC_ORDER + pSettings->overlap],
+ pSettings->nCols) +
+ lowBandShift);
+ if (!useLP) {
+ dynamicScale =
+ fixMin(dynamicScale,
+ getScalefactor(lowBandImag, LPC_ORDER + pSettings->overlap) +
+ ovLowBandShift);
+ dynamicScale =
+ fixMin(dynamicScale,
+ getScalefactor(&lowBandImag[LPC_ORDER + pSettings->overlap],
+ pSettings->nCols) +
+ lowBandShift);
+ }
+ dynamicScale = fixMax(
+ 0, dynamicScale - 1); /* one additional bit headroom to prevent -1.0 */
+
+ /*
+ Scale temporal QMF buffer.
+ */
+ scaleValues(&lowBandReal[0], LPC_ORDER + pSettings->overlap,
+ dynamicScale - ovLowBandShift);
+ scaleValues(&lowBandReal[LPC_ORDER + pSettings->overlap], pSettings->nCols,
+ dynamicScale - lowBandShift);
+
+ if (!useLP) {
+ scaleValues(&lowBandImag[0], LPC_ORDER + pSettings->overlap,
+ dynamicScale - ovLowBandShift);
+ scaleValues(&lowBandImag[LPC_ORDER + pSettings->overlap],
+ pSettings->nCols, dynamicScale - lowBandShift);
+ }
+
+ if (!useLP) {
+ acDetScale += autoCorr2nd_cplx(&ac, lowBandReal + LPC_ORDER,
+ lowBandImag + LPC_ORDER, autoCorrLength);
+ } else {
+ acDetScale +=
+ autoCorr2nd_real(&ac, lowBandReal + LPC_ORDER, autoCorrLength);
+ }
+
+ /* Examine dynamic of determinant in autocorrelation. */
+ acDetScale += 2 * (comLowBandScale + dynamicScale);
+ acDetScale *= 2; /* two times reflection coefficent scaling */
+ acDetScale += ac.det_scale; /* ac scaling of determinant */
+
+ /* In case of determinant < 10^-38, resetLPCCoeffs=1 has to be enforced. */
+ if (acDetScale > 126) {
+ resetLPCCoeffs = 1;
+ }
+
+ alphar[1] = FL2FXCONST_SGL(0.0f);
+ if (!useLP) alphai[1] = FL2FXCONST_SGL(0.0f);
+
+ if (ac.det != FL2FXCONST_DBL(0.0f)) {
+ FIXP_DBL tmp, absTmp, absDet;
+
+ absDet = fixp_abs(ac.det);
+
+ if (!useLP) {
+ tmp = (fMultDiv2(ac.r01r, ac.r12r) >> (LPC_SCALE_FACTOR - 1)) -
+ ((fMultDiv2(ac.r01i, ac.r12i) + fMultDiv2(ac.r02r, ac.r11r)) >>
+ (LPC_SCALE_FACTOR - 1));
+ } else {
+ tmp = (fMultDiv2(ac.r01r, ac.r12r) >> (LPC_SCALE_FACTOR - 1)) -
+ (fMultDiv2(ac.r02r, ac.r11r) >> (LPC_SCALE_FACTOR - 1));
+ }
+ absTmp = fixp_abs(tmp);
+
+ /*
+ Quick check: is first filter coeff >= 1(4)
+ */
+ {
+ INT scale;
+ FIXP_DBL result = fDivNorm(absTmp, absDet, &scale);
+ scale = scale + ac.det_scale;
+
+ if ((scale > 0) && (result >= (FIXP_DBL)MAXVAL_DBL >> scale)) {
+ resetLPCCoeffs = 1;
+ } else {
+ alphar[1] = FX_DBL2FX_SGL(scaleValue(result, scale));
+ if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) {
+ alphar[1] = -alphar[1];
+ }
+ }
+ }
+
+ if (!useLP) {
+ tmp = (fMultDiv2(ac.r01i, ac.r12r) >> (LPC_SCALE_FACTOR - 1)) +
+ ((fMultDiv2(ac.r01r, ac.r12i) -
+ (FIXP_DBL)fMultDiv2(ac.r02i, ac.r11r)) >>
+ (LPC_SCALE_FACTOR - 1));
+
+ absTmp = fixp_abs(tmp);
+
+ /*
+ Quick check: is second filter coeff >= 1(4)
+ */
+ {
+ INT scale;
+ FIXP_DBL result = fDivNorm(absTmp, absDet, &scale);
+ scale = scale + ac.det_scale;
+
+ if ((scale > 0) &&
+ (result >= /*FL2FXCONST_DBL(1.f)*/ (FIXP_DBL)MAXVAL_DBL >>
+ scale)) {
+ resetLPCCoeffs = 1;
+ } else {
+ alphai[1] = FX_DBL2FX_SGL(scaleValue(result, scale));
+ if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) {
+ alphai[1] = -alphai[1];
+ }
+ }
+ }
+ }
+ }
+
+ alphar[0] = FL2FXCONST_SGL(0.0f);
+ if (!useLP) alphai[0] = FL2FXCONST_SGL(0.0f);
+
+ if (ac.r11r != FL2FXCONST_DBL(0.0f)) {
+ /* ac.r11r is always >=0 */
+ FIXP_DBL tmp, absTmp;
+
+ if (!useLP) {
+ tmp = (ac.r01r >> (LPC_SCALE_FACTOR + 1)) +
+ (fMultDiv2(alphar[1], ac.r12r) + fMultDiv2(alphai[1], ac.r12i));
+ } else {
+ if (ac.r01r >= FL2FXCONST_DBL(0.0f))
+ tmp = (ac.r01r >> (LPC_SCALE_FACTOR + 1)) +
+ fMultDiv2(alphar[1], ac.r12r);
+ else
+ tmp = -((-ac.r01r) >> (LPC_SCALE_FACTOR + 1)) +
+ fMultDiv2(alphar[1], ac.r12r);
+ }
+
+ absTmp = fixp_abs(tmp);
+
+ /*
+ Quick check: is first filter coeff >= 1(4)
+ */
+
+ if (absTmp >= (ac.r11r >> 1)) {
+ resetLPCCoeffs = 1;
+ } else {
+ INT scale;
+ FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale);
+ alphar[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1));
+
+ if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f)))
+ alphar[0] = -alphar[0];
+ }
+
+ if (!useLP) {
+ tmp = (ac.r01i >> (LPC_SCALE_FACTOR + 1)) +
+ (fMultDiv2(alphai[1], ac.r12r) - fMultDiv2(alphar[1], ac.r12i));
+
+ absTmp = fixp_abs(tmp);
+
+ /*
+ Quick check: is second filter coeff >= 1(4)
+ */
+ if (absTmp >= (ac.r11r >> 1)) {
+ resetLPCCoeffs = 1;
+ } else {
+ INT scale;
+ FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale);
+ alphai[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1));
+ if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f)))
+ alphai[0] = -alphai[0];
+ }
+ }
+ }
+
+ if (!useLP) {
+ /* Now check the quadratic criteria */
+ if ((fMultDiv2(alphar[0], alphar[0]) + fMultDiv2(alphai[0], alphai[0])) >=
+ FL2FXCONST_DBL(0.5f))
+ resetLPCCoeffs = 1;
+ if ((fMultDiv2(alphar[1], alphar[1]) + fMultDiv2(alphai[1], alphai[1])) >=
+ FL2FXCONST_DBL(0.5f))
+ resetLPCCoeffs = 1;
+ }
+
+ if (resetLPCCoeffs) {
+ alphar[0] = FL2FXCONST_SGL(0.0f);
+ alphar[1] = FL2FXCONST_SGL(0.0f);
+ if (!useLP) {
+ alphai[0] = FL2FXCONST_SGL(0.0f);
+ alphai[1] = FL2FXCONST_SGL(0.0f);
+ }
+ }
+
+ if (useLP) {
+ /* Aliasing detection */
+ if (ac.r11r == FL2FXCONST_DBL(0.0f)) {
+ k1 = FL2FXCONST_DBL(0.0f);
+ } else {
+ if (fixp_abs(ac.r01r) >= fixp_abs(ac.r11r)) {
+ if (fMultDiv2(ac.r01r, ac.r11r) < FL2FX_DBL(0.0f)) {
+ k1 = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_SGL(1.0f)*/;
+ } else {
+ /* Since this value is squared later, it must not ever become -1.0f.
+ */
+ k1 = (FIXP_DBL)(MINVAL_DBL + 1) /*FL2FXCONST_SGL(-1.0f)*/;
+ }
+ } else {
+ INT scale;
+ FIXP_DBL result =
+ fDivNorm(fixp_abs(ac.r01r), fixp_abs(ac.r11r), &scale);
+ k1 = scaleValue(result, scale);
+
+ if (!((ac.r01r < FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f)))) {
+ k1 = -k1;
+ }
+ }
+ }
+ if ((loBand > 1) && (loBand < v_k_master0)) {
+ /* Check if the gain should be locked */
+ FIXP_DBL deg =
+ /*FL2FXCONST_DBL(1.0f)*/ (FIXP_DBL)MAXVAL_DBL - fPow2(k1_below);
+ degreeAlias[loBand] = FL2FXCONST_DBL(0.0f);
+ if (((loBand & 1) == 0) && (k1 < FL2FXCONST_DBL(0.0f))) {
+ if (k1_below < FL2FXCONST_DBL(0.0f)) { /* 2-Ch Aliasing Detection */
+ degreeAlias[loBand] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/;
+ if (k1_below2 >
+ FL2FXCONST_DBL(0.0f)) { /* 3-Ch Aliasing Detection */
+ degreeAlias[loBand - 1] = deg;
+ }
+ } else if (k1_below2 >
+ FL2FXCONST_DBL(0.0f)) { /* 3-Ch Aliasing Detection */
+ degreeAlias[loBand] = deg;
+ }
+ }
+ if (((loBand & 1) == 1) && (k1 > FL2FXCONST_DBL(0.0f))) {
+ if (k1_below > FL2FXCONST_DBL(0.0f)) { /* 2-CH Aliasing Detection */
+ degreeAlias[loBand] = (FIXP_DBL)MAXVAL_DBL /*FL2FXCONST_DBL(1.0f)*/;
+ if (k1_below2 <
+ FL2FXCONST_DBL(0.0f)) { /* 3-CH Aliasing Detection */
+ degreeAlias[loBand - 1] = deg;
+ }
+ } else if (k1_below2 <
+ FL2FXCONST_DBL(0.0f)) { /* 3-CH Aliasing Detection */
+ degreeAlias[loBand] = deg;
+ }
+ }
+ }
+ /* remember k1 values of the 2 QMF channels below the current channel */
+ k1_below2 = k1_below;
+ k1_below = k1;
+ }
+
+ patch = 0;
+
+ while (patch < pSettings->noOfPatches) { /* inner loop over every patch */
+
+ int hiBand = loBand + patchParam[patch].targetBandOffs;
+
+ if (loBand < patchParam[patch].sourceStartBand ||
+ loBand >= patchParam[patch].sourceStopBand
+ //|| hiBand >= hLppTrans->pSettings->noChannels
+ ) {
+ /* Lowband not in current patch - proceed */
+ patch++;
+ continue;
+ }
+
+ FDK_ASSERT(hiBand < (64));
+
+ /* bwIndex[patch] is already initialized with value from previous band
+ * inside this patch */
+ while (hiBand >= pSettings->bwBorders[bwIndex[patch]] &&
+ bwIndex[patch] < MAX_NUM_PATCHES - 1) {
+ bwIndex[patch]++;
+ }
+
+ /*
+ Filter Step 2: add the left slope with the current filter to the buffer
+ pure source values are already in there
+ */
+ bw = FX_DBL2FX_SGL(bwVector[bwIndex[patch]]);
+
+ a0r = FX_DBL2FX_SGL(
+ fMult(bw, alphar[0])); /* Apply current bandwidth expansion factor */
+
+ if (!useLP) a0i = FX_DBL2FX_SGL(fMult(bw, alphai[0]));
+ bw = FX_DBL2FX_SGL(fPow2(bw));
+ a1r = FX_DBL2FX_SGL(fMult(bw, alphar[1]));
+ if (!useLP) a1i = FX_DBL2FX_SGL(fMult(bw, alphai[1]));
+
+ /*
+ Filter Step 3: insert the middle part which won't be windowed
+ */
+ if (bw <= FL2FXCONST_SGL(0.0f)) {
+ if (!useLP) {
+ int descale =
+ fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale));
+ for (i = startSample; i < stopSample; i++) {
+ FIXP_DBL accu1, accu2;
+ accu1 = lowBandReal[LPC_ORDER + i] >> descale;
+ accu2 = lowBandImag[LPC_ORDER + i] >> descale;
+ if (fPreWhitening) {
+ accu1 = scaleValueSaturate(
+ fMultDiv2(accu1, preWhiteningGains[loBand]),
+ preWhiteningGains_exp[loBand] + 1);
+ accu2 = scaleValueSaturate(
+ fMultDiv2(accu2, preWhiteningGains[loBand]),
+ preWhiteningGains_exp[loBand] + 1);
+ }
+ qmfBufferReal[i][hiBand] = accu1;
+ qmfBufferImag[i][hiBand] = accu2;
+ }
+ } else {
+ int descale =
+ fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale));
+ for (i = startSample; i < stopSample; i++) {
+ qmfBufferReal[i][hiBand] = lowBandReal[LPC_ORDER + i] >> descale;
+ }
+ }
+ } else { /* bw <= 0 */
+
+ if (!useLP) {
+ int descale =
+ fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale));
+#ifdef FUNCTION_LPPTRANSPOSER_func1
+ lppTransposer_func1(
+ lowBandReal + LPC_ORDER + startSample,
+ lowBandImag + LPC_ORDER + startSample,
+ qmfBufferReal + startSample, qmfBufferImag + startSample,
+ stopSample - startSample, (int)hiBand, dynamicScale, descale, a0r,
+ a0i, a1r, a1i, fPreWhitening, preWhiteningGains[loBand],
+ preWhiteningGains_exp[loBand] + 1);
+#else
+ for (i = startSample; i < stopSample; i++) {
+ FIXP_DBL accu1, accu2;
+
+ accu1 = (fMultDiv2(a0r, lowBandReal[LPC_ORDER + i - 1]) -
+ fMultDiv2(a0i, lowBandImag[LPC_ORDER + i - 1]) +
+ fMultDiv2(a1r, lowBandReal[LPC_ORDER + i - 2]) -
+ fMultDiv2(a1i, lowBandImag[LPC_ORDER + i - 2])) >>
+ dynamicScale;
+ accu2 = (fMultDiv2(a0i, lowBandReal[LPC_ORDER + i - 1]) +
+ fMultDiv2(a0r, lowBandImag[LPC_ORDER + i - 1]) +
+ fMultDiv2(a1i, lowBandReal[LPC_ORDER + i - 2]) +
+ fMultDiv2(a1r, lowBandImag[LPC_ORDER + i - 2])) >>
+ dynamicScale;
+
+ accu1 = (lowBandReal[LPC_ORDER + i] >> descale) + (accu1 << 1);
+ accu2 = (lowBandImag[LPC_ORDER + i] >> descale) + (accu2 << 1);
+ if (fPreWhitening) {
+ accu1 = scaleValueSaturate(
+ fMultDiv2(accu1, preWhiteningGains[loBand]),
+ preWhiteningGains_exp[loBand] + 1);
+ accu2 = scaleValueSaturate(
+ fMultDiv2(accu2, preWhiteningGains[loBand]),
+ preWhiteningGains_exp[loBand] + 1);
+ }
+ qmfBufferReal[i][hiBand] = accu1;
+ qmfBufferImag[i][hiBand] = accu2;
+ }
+#endif
+ } else {
+ FDK_ASSERT(dynamicScale >= 0);
+ calc_qmfBufferReal(
+ qmfBufferReal, &(lowBandReal[LPC_ORDER + startSample - 2]),
+ startSample, stopSample, hiBand, dynamicScale,
+ fMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale)), a0r,
+ a1r);
+ }
+ } /* bw <= 0 */
+
+ patch++;
+
+ } /* inner loop over patches */
+
+ /*
+ * store the unmodified filter coefficients if there is
+ * an overlapping envelope
+ *****************************************************************/
+
+ } /* outer loop over bands (loBand) */
+
+ if (useLP) {
+ for (loBand = pSettings->lbStartPatching;
+ loBand < pSettings->lbStopPatching; loBand++) {
+ patch = 0;
+ while (patch < pSettings->noOfPatches) {
+ UCHAR hiBand = loBand + patchParam[patch].targetBandOffs;
+
+ if (loBand < patchParam[patch].sourceStartBand ||
+ loBand >= patchParam[patch].sourceStopBand ||
+ hiBand >= (64) /* Highband out of range (biterror) */
+ ) {
+ /* Lowband not in current patch or highband out of range (might be
+ * caused by biterrors)- proceed */
+ patch++;
+ continue;
+ }
+
+ if (hiBand != patchParam[patch].targetStartBand)
+ degreeAlias[hiBand] = degreeAlias[loBand];
+
+ patch++;
+ }
+ } /* end for loop */
+ }
+
+ for (i = 0; i < nInvfBands; i++) {
+ hLppTrans->bwVectorOld[i] = bwVector[i];
+ }
+
+ /*
+ set high band scale factor
+ */
+ sbrScaleFactor->hb_scale = comLowBandScale - (LPC_SCALE_FACTOR);
+}
+
+void lppTransposerHBE(
+ HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */
+ HANDLE_HBE_TRANSPOSER hQmfTransposer,
+ QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */
+ FIXP_DBL **qmfBufferReal, /*!< Pointer to pointer to real part of subband
+ samples (source) */
+ FIXP_DBL **qmfBufferImag, /*!< Pointer to pointer to imaginary part of
+ subband samples (source) */
+ const int timeStep, /*!< Time step of envelope */
+ const int firstSlotOffs, /*!< Start position in time */
+ const int lastSlotOffs, /*!< Number of overlap-slots into next frame */
+ const int nInvfBands, /*!< Number of bands for inverse filtering */
+ INVF_MODE *sbr_invf_mode, /*!< Current inverse filtering modes */
+ INVF_MODE *sbr_invf_mode_prev /*!< Previous inverse filtering modes */
+) {
+ INT bwIndex;
+ FIXP_DBL bwVector[MAX_NUM_PATCHES_HBE]; /*!< pole moving factors */
+
+ int i;
+ int loBand, start, stop;
+ TRANSPOSER_SETTINGS *pSettings = hLppTrans->pSettings;
+ PATCH_PARAM *patchParam = pSettings->patchParam;
+
+ FIXP_SGL alphar[LPC_ORDER], a0r, a1r;
+ FIXP_SGL alphai[LPC_ORDER], a0i = 0, a1i = 0;
+ FIXP_SGL bw = FL2FXCONST_SGL(0.0f);
+
+ int autoCorrLength;
+
+ ACORR_COEFS ac;
+ int startSample;
+ int stopSample;
+ int stopSampleClear;
+
+ int comBandScale;
+ int ovLowBandShift;
+ int lowBandShift;
+ /* int ovHighBandShift;*/
+
+ alphai[0] = FL2FXCONST_SGL(0.0f);
+ alphai[1] = FL2FXCONST_SGL(0.0f);
+
+ startSample = firstSlotOffs * timeStep;
+ stopSample = pSettings->nCols + lastSlotOffs * timeStep;
+
+ inverseFilteringLevelEmphasis(hLppTrans, nInvfBands, sbr_invf_mode,
+ sbr_invf_mode_prev, bwVector);
+
+ stopSampleClear = stopSample;
+
+ autoCorrLength = pSettings->nCols + pSettings->overlap;
+
+ if (pSettings->noOfPatches > 0) {
+ /* Set upper subbands to zero:
+ This is required in case that the patches do not cover the complete
+ highband (because the last patch would be too short). Possible
+ optimization: Clearing bands up to usb would be sufficient here. */
+ int targetStopBand =
+ patchParam[pSettings->noOfPatches - 1].targetStartBand +
+ patchParam[pSettings->noOfPatches - 1].numBandsInPatch;
+
+ int memSize = ((64) - targetStopBand) * sizeof(FIXP_DBL);
+
+ for (i = startSample; i < stopSampleClear; i++) {
+ FDKmemclear(&qmfBufferReal[i][targetStopBand], memSize);
+ FDKmemclear(&qmfBufferImag[i][targetStopBand], memSize);
+ }
+ }
+#ifdef __ANDROID__
+ else {
+ // Safetynet logging
+ android_errorWriteLog(0x534e4554, "112160868");
+ }
+#endif
+
+ /*
+ Calc common low band scale factor
+ */
+ comBandScale = sbrScaleFactor->hb_scale;
+
+ ovLowBandShift = sbrScaleFactor->hb_scale - comBandScale;
+ lowBandShift = sbrScaleFactor->hb_scale - comBandScale;
+ /* ovHighBandShift = firstSlotOffs == 0 ? ovLowBandShift:0;*/
+
+ /* outer loop over bands to do analysis only once for each band */
+
+ start = hQmfTransposer->startBand;
+ stop = hQmfTransposer->stopBand;
+
+ for (loBand = start; loBand < stop; loBand++) {
+ bwIndex = 0;
+
+ FIXP_DBL lowBandReal[(((1024) / (32) * (4) / 2) + (3 * (4))) + LPC_ORDER];
+ FIXP_DBL lowBandImag[(((1024) / (32) * (4) / 2) + (3 * (4))) + LPC_ORDER];
+
+ int resetLPCCoeffs = 0;
+ int dynamicScale = DFRACT_BITS - 1 - LPC_SCALE_FACTOR;
+ int acDetScale = 0; /* scaling of autocorrelation determinant */
+
+ for (i = 0; i < LPC_ORDER; i++) {
+ lowBandReal[i] = hLppTrans->lpcFilterStatesRealHBE[i][loBand];
+ lowBandImag[i] = hLppTrans->lpcFilterStatesImagHBE[i][loBand];
+ }
+
+ for (; i < LPC_ORDER + firstSlotOffs * timeStep; i++) {
+ lowBandReal[i] = hLppTrans->lpcFilterStatesRealHBE[i][loBand];
+ lowBandImag[i] = hLppTrans->lpcFilterStatesImagHBE[i][loBand];
+ }
+
+ /*
+ Take old slope length qmf slot source values out of (overlap)qmf buffer
+ */
+ for (i = firstSlotOffs * timeStep;
+ i < pSettings->nCols + pSettings->overlap; i++) {
+ lowBandReal[i + LPC_ORDER] = qmfBufferReal[i][loBand];
+ lowBandImag[i + LPC_ORDER] = qmfBufferImag[i][loBand];
+ }
+
+ /* store unmodified values to buffer */
+ for (i = 0; i < LPC_ORDER + pSettings->overlap; i++) {
+ hLppTrans->lpcFilterStatesRealHBE[i][loBand] =
+ qmfBufferReal[pSettings->nCols - LPC_ORDER + i][loBand];
+ hLppTrans->lpcFilterStatesImagHBE[i][loBand] =
+ qmfBufferImag[pSettings->nCols - LPC_ORDER + i][loBand];
+ }
+
+ /*
+ Determine dynamic scaling value.
+ */
+ dynamicScale =
+ fixMin(dynamicScale,
+ getScalefactor(lowBandReal, LPC_ORDER + pSettings->overlap) +
+ ovLowBandShift);
+ dynamicScale =
+ fixMin(dynamicScale,
+ getScalefactor(&lowBandReal[LPC_ORDER + pSettings->overlap],
+ pSettings->nCols) +
+ lowBandShift);
+ dynamicScale =
+ fixMin(dynamicScale,
+ getScalefactor(lowBandImag, LPC_ORDER + pSettings->overlap) +
+ ovLowBandShift);
+ dynamicScale =
+ fixMin(dynamicScale,
+ getScalefactor(&lowBandImag[LPC_ORDER + pSettings->overlap],
+ pSettings->nCols) +
+ lowBandShift);
+
+ dynamicScale = fixMax(
+ 0, dynamicScale - 1); /* one additional bit headroom to prevent -1.0 */
+
+ /*
+ Scale temporal QMF buffer.
+ */
+ scaleValues(&lowBandReal[0], LPC_ORDER + pSettings->overlap,
+ dynamicScale - ovLowBandShift);
+ scaleValues(&lowBandReal[LPC_ORDER + pSettings->overlap], pSettings->nCols,
+ dynamicScale - lowBandShift);
+ scaleValues(&lowBandImag[0], LPC_ORDER + pSettings->overlap,
+ dynamicScale - ovLowBandShift);
+ scaleValues(&lowBandImag[LPC_ORDER + pSettings->overlap], pSettings->nCols,
+ dynamicScale - lowBandShift);
+
+ acDetScale += autoCorr2nd_cplx(&ac, lowBandReal + LPC_ORDER,
+ lowBandImag + LPC_ORDER, autoCorrLength);
+
+ /* Examine dynamic of determinant in autocorrelation. */
+ acDetScale += 2 * (comBandScale + dynamicScale);
+ acDetScale *= 2; /* two times reflection coefficent scaling */
+ acDetScale += ac.det_scale; /* ac scaling of determinant */
+
+ /* In case of determinant < 10^-38, resetLPCCoeffs=1 has to be enforced. */
+ if (acDetScale > 126) {
+ resetLPCCoeffs = 1;
+ }
+
+ alphar[1] = FL2FXCONST_SGL(0.0f);
+ alphai[1] = FL2FXCONST_SGL(0.0f);
+
+ if (ac.det != FL2FXCONST_DBL(0.0f)) {
+ FIXP_DBL tmp, absTmp, absDet;
+
+ absDet = fixp_abs(ac.det);
+
+ tmp = (fMultDiv2(ac.r01r, ac.r12r) >> (LPC_SCALE_FACTOR - 1)) -
+ ((fMultDiv2(ac.r01i, ac.r12i) + fMultDiv2(ac.r02r, ac.r11r)) >>
+ (LPC_SCALE_FACTOR - 1));
+ absTmp = fixp_abs(tmp);
+
+ /*
+ Quick check: is first filter coeff >= 1(4)
+ */
+ {
+ INT scale;
+ FIXP_DBL result = fDivNorm(absTmp, absDet, &scale);
+ scale = scale + ac.det_scale;
+
+ if ((scale > 0) && (result >= (FIXP_DBL)MAXVAL_DBL >> scale)) {
+ resetLPCCoeffs = 1;
+ } else {
+ alphar[1] = FX_DBL2FX_SGL(scaleValue(result, scale));
+ if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) {
+ alphar[1] = -alphar[1];
+ }
+ }
+ }
+
+ tmp = (fMultDiv2(ac.r01i, ac.r12r) >> (LPC_SCALE_FACTOR - 1)) +
+ ((fMultDiv2(ac.r01r, ac.r12i) -
+ (FIXP_DBL)fMultDiv2(ac.r02i, ac.r11r)) >>
+ (LPC_SCALE_FACTOR - 1));
+
+ absTmp = fixp_abs(tmp);
+
+ /*
+ Quick check: is second filter coeff >= 1(4)
+ */
+ {
+ INT scale;
+ FIXP_DBL result = fDivNorm(absTmp, absDet, &scale);
+ scale = scale + ac.det_scale;
+
+ if ((scale > 0) &&
+ (result >= /*FL2FXCONST_DBL(1.f)*/ (FIXP_DBL)MAXVAL_DBL >> scale)) {
+ resetLPCCoeffs = 1;
+ } else {
+ alphai[1] = FX_DBL2FX_SGL(scaleValue(result, scale));
+ if ((tmp < FL2FX_DBL(0.0f)) ^ (ac.det < FL2FX_DBL(0.0f))) {
+ alphai[1] = -alphai[1];
+ }
+ }
+ }
+ }
+
+ alphar[0] = FL2FXCONST_SGL(0.0f);
+ alphai[0] = FL2FXCONST_SGL(0.0f);
+
+ if (ac.r11r != FL2FXCONST_DBL(0.0f)) {
+ /* ac.r11r is always >=0 */
+ FIXP_DBL tmp, absTmp;
+
+ tmp = (ac.r01r >> (LPC_SCALE_FACTOR + 1)) +
+ (fMultDiv2(alphar[1], ac.r12r) + fMultDiv2(alphai[1], ac.r12i));
+
+ absTmp = fixp_abs(tmp);
+
+ /*
+ Quick check: is first filter coeff >= 1(4)
+ */
+
+ if (absTmp >= (ac.r11r >> 1)) {
+ resetLPCCoeffs = 1;
+ } else {
+ INT scale;
+ FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale);
+ alphar[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1));
+
+ if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f)))
+ alphar[0] = -alphar[0];
+ }
+
+ tmp = (ac.r01i >> (LPC_SCALE_FACTOR + 1)) +
+ (fMultDiv2(alphai[1], ac.r12r) - fMultDiv2(alphar[1], ac.r12i));
+
+ absTmp = fixp_abs(tmp);
+
+ /*
+ Quick check: is second filter coeff >= 1(4)
+ */
+ if (absTmp >= (ac.r11r >> 1)) {
+ resetLPCCoeffs = 1;
+ } else {
+ INT scale;
+ FIXP_DBL result = fDivNorm(absTmp, fixp_abs(ac.r11r), &scale);
+ alphai[0] = FX_DBL2FX_SGL(scaleValue(result, scale + 1));
+ if ((tmp > FL2FX_DBL(0.0f)) ^ (ac.r11r < FL2FX_DBL(0.0f))) {
+ alphai[0] = -alphai[0];
+ }
+ }
+ }
+
+ /* Now check the quadratic criteria */
+ if ((fMultDiv2(alphar[0], alphar[0]) + fMultDiv2(alphai[0], alphai[0])) >=
+ FL2FXCONST_DBL(0.5f)) {
+ resetLPCCoeffs = 1;
+ }
+ if ((fMultDiv2(alphar[1], alphar[1]) + fMultDiv2(alphai[1], alphai[1])) >=
+ FL2FXCONST_DBL(0.5f)) {
+ resetLPCCoeffs = 1;
+ }
+
+ if (resetLPCCoeffs) {
+ alphar[0] = FL2FXCONST_SGL(0.0f);
+ alphar[1] = FL2FXCONST_SGL(0.0f);
+ alphai[0] = FL2FXCONST_SGL(0.0f);
+ alphai[1] = FL2FXCONST_SGL(0.0f);
+ }
+
+ while (bwIndex < MAX_NUM_PATCHES - 1 &&
+ loBand >= pSettings->bwBorders[bwIndex]) {
+ bwIndex++;
+ }
+
+ /*
+ Filter Step 2: add the left slope with the current filter to the buffer
+ pure source values are already in there
+ */
+ bw = FX_DBL2FX_SGL(bwVector[bwIndex]);
+
+ a0r = FX_DBL2FX_SGL(
+ fMult(bw, alphar[0])); /* Apply current bandwidth expansion factor */
+ a0i = FX_DBL2FX_SGL(fMult(bw, alphai[0]));
+ bw = FX_DBL2FX_SGL(fPow2(bw));
+ a1r = FX_DBL2FX_SGL(fMult(bw, alphar[1]));
+ a1i = FX_DBL2FX_SGL(fMult(bw, alphai[1]));
+
+ /*
+ Filter Step 3: insert the middle part which won't be windowed
+ */
+ if (bw <= FL2FXCONST_SGL(0.0f)) {
+ int descale = fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale));
+ for (i = startSample; i < stopSample; i++) {
+ qmfBufferReal[i][loBand] = lowBandReal[LPC_ORDER + i] >> descale;
+ qmfBufferImag[i][loBand] = lowBandImag[LPC_ORDER + i] >> descale;
+ }
+ } else { /* bw <= 0 */
+
+ int descale = fixMin(DFRACT_BITS - 1, (LPC_SCALE_FACTOR + dynamicScale));
+
+ for (i = startSample; i < stopSample; i++) {
+ FIXP_DBL accu1, accu2;
+
+ accu1 = (fMultDiv2(a0r, lowBandReal[LPC_ORDER + i - 1]) -
+ fMultDiv2(a0i, lowBandImag[LPC_ORDER + i - 1]) +
+ fMultDiv2(a1r, lowBandReal[LPC_ORDER + i - 2]) -
+ fMultDiv2(a1i, lowBandImag[LPC_ORDER + i - 2])) >>
+ dynamicScale;
+ accu2 = (fMultDiv2(a0i, lowBandReal[LPC_ORDER + i - 1]) +
+ fMultDiv2(a0r, lowBandImag[LPC_ORDER + i - 1]) +
+ fMultDiv2(a1i, lowBandReal[LPC_ORDER + i - 2]) +
+ fMultDiv2(a1r, lowBandImag[LPC_ORDER + i - 2])) >>
+ dynamicScale;
+
+ qmfBufferReal[i][loBand] =
+ (lowBandReal[LPC_ORDER + i] >> descale) + (accu1 << 1);
+ qmfBufferImag[i][loBand] =
+ (lowBandImag[LPC_ORDER + i] >> descale) + (accu2 << 1);
+ }
+ } /* bw <= 0 */
+
+ /*
+ * store the unmodified filter coefficients if there is
+ * an overlapping envelope
+ *****************************************************************/
+
+ } /* outer loop over bands (loBand) */
+
+ for (i = 0; i < nInvfBands; i++) {
+ hLppTrans->bwVectorOld[i] = bwVector[i];
+ }
+
+ /*
+ set high band scale factor
+ */
+ sbrScaleFactor->hb_scale = comBandScale - (LPC_SCALE_FACTOR);
+}
+
+/*!
+ *
+ * \brief Initialize one low power transposer instance
+ *
+ *
+ */
+SBR_ERROR
+createLppTransposer(
+ HANDLE_SBR_LPP_TRANS hs, /*!< Handle of low power transposer */
+ TRANSPOSER_SETTINGS *pSettings, /*!< Pointer to settings */
+ const int highBandStartSb, /*!< ? */
+ UCHAR *v_k_master, /*!< Master table */
+ const int numMaster, /*!< Valid entries in master table */
+ const int usb, /*!< Highband area stop subband */
+ const int timeSlots, /*!< Number of time slots */
+ const int nCols, /*!< Number of colums (codec qmf bank) */
+ UCHAR *noiseBandTable, /*!< Mapping of SBR noise bands to QMF bands */
+ const int noNoiseBands, /*!< Number of noise bands */
+ UINT fs, /*!< Sample Frequency */
+ const int chan, /*!< Channel number */
+ const int overlap) {
+ /* FB inverse filtering settings */
+ hs->pSettings = pSettings;
+
+ pSettings->nCols = nCols;
+ pSettings->overlap = overlap;
+
+ switch (timeSlots) {
+ case 15:
+ case 16:
+ break;
+
+ default:
+ return SBRDEC_UNSUPPORTED_CONFIG; /* Unimplemented */
+ }
+
+ if (chan == 0) {
+ /* Init common data only once */
+ hs->pSettings->nCols = nCols;
+
+ return resetLppTransposer(hs, highBandStartSb, v_k_master, numMaster,
+ noiseBandTable, noNoiseBands, usb, fs);
+ }
+ return SBRDEC_OK;
+}
+
+static int findClosestEntry(UCHAR goalSb, UCHAR *v_k_master, UCHAR numMaster,
+ UCHAR direction) {
+ int index;
+
+ if (goalSb <= v_k_master[0]) return v_k_master[0];
+
+ if (goalSb >= v_k_master[numMaster]) return v_k_master[numMaster];
+
+ if (direction) {
+ index = 0;
+ while (v_k_master[index] < goalSb) {
+ index++;
+ }
+ } else {
+ index = numMaster;
+ while (v_k_master[index] > goalSb) {
+ index--;
+ }
+ }
+
+ return v_k_master[index];
+}
+
+/*!
+ *
+ * \brief Reset memory for one lpp transposer instance
+ *
+ * \return SBRDEC_OK on success, SBRDEC_UNSUPPORTED_CONFIG on error
+ */
+SBR_ERROR
+resetLppTransposer(
+ HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */
+ UCHAR highBandStartSb, /*!< High band area: start subband */
+ UCHAR *v_k_master, /*!< Master table */
+ UCHAR numMaster, /*!< Valid entries in master table */
+ UCHAR *noiseBandTable, /*!< Mapping of SBR noise bands to QMF bands */
+ UCHAR noNoiseBands, /*!< Number of noise bands */
+ UCHAR usb, /*!< High band area: stop subband */
+ UINT fs /*!< SBR output sampling frequency */
+) {
+ TRANSPOSER_SETTINGS *pSettings = hLppTrans->pSettings;
+ PATCH_PARAM *patchParam = pSettings->patchParam;
+
+ int i, patch;
+ int targetStopBand;
+ int sourceStartBand;
+ int patchDistance;
+ int numBandsInPatch;
+
+ int lsb = v_k_master[0]; /* Start subband expressed in "non-critical" sampling
+ terms*/
+ int xoverOffset = highBandStartSb -
+ lsb; /* Calculate distance in QMF bands between k0 and kx */
+ int startFreqHz;
+
+ int desiredBorder;
+
+ usb = fixMin(usb, v_k_master[numMaster]); /* Avoid endless loops (compare with
+ float code). */
+
+ /*
+ * Plausibility check
+ */
+
+ if (pSettings->nCols == 64) {
+ if (lsb < 4) {
+ /* 4:1 SBR Requirement k0 >= 4 missed! */
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+ } else if (lsb - SHIFT_START_SB < 4) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ /*
+ * Initialize the patching parameter
+ */
+ /* ISO/IEC 14496-3 (Figure 4.48): goalSb = round( 2.048e6 / fs ) */
+ desiredBorder = (((2048000 * 2) / fs) + 1) >> 1;
+
+ desiredBorder = findClosestEntry(desiredBorder, v_k_master, numMaster,
+ 1); /* Adapt region to master-table */
+
+ /* First patch */
+ sourceStartBand = SHIFT_START_SB + xoverOffset;
+ targetStopBand = lsb + xoverOffset; /* upperBand */
+
+ /* Even (odd) numbered channel must be patched to even (odd) numbered channel
+ */
+ patch = 0;
+ while (targetStopBand < usb) {
+ /* Too many patches?
+ Allow MAX_NUM_PATCHES+1 patches here.
+ we need to check later again, since patch might be the highest patch
+ AND contain less than 3 bands => actual number of patches will be reduced
+ by 1.
+ */
+ if (patch > MAX_NUM_PATCHES) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ patchParam[patch].guardStartBand = targetStopBand;
+ patchParam[patch].targetStartBand = targetStopBand;
+
+ numBandsInPatch =
+ desiredBorder - targetStopBand; /* Get the desired range of the patch */
+
+ if (numBandsInPatch >= lsb - sourceStartBand) {
+ /* Desired number bands are not available -> patch whole source range */
+ patchDistance =
+ targetStopBand - sourceStartBand; /* Get the targetOffset */
+ patchDistance =
+ patchDistance & ~1; /* Rounding off odd numbers and make all even */
+ numBandsInPatch =
+ lsb - (targetStopBand -
+ patchDistance); /* Update number of bands to be patched */
+ numBandsInPatch = findClosestEntry(targetStopBand + numBandsInPatch,
+ v_k_master, numMaster, 0) -
+ targetStopBand; /* Adapt region to master-table */
+ }
+
+ if (pSettings->nCols == 64) {
+ if (numBandsInPatch == 0 && sourceStartBand == SHIFT_START_SB) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+ }
+
+ /* Desired number bands are available -> get the minimal even patching
+ * distance */
+ patchDistance =
+ numBandsInPatch + targetStopBand - lsb; /* Get minimal distance */
+ patchDistance = (patchDistance + 1) &
+ ~1; /* Rounding up odd numbers and make all even */
+
+ if (numBandsInPatch > 0) {
+ patchParam[patch].sourceStartBand = targetStopBand - patchDistance;
+ patchParam[patch].targetBandOffs = patchDistance;
+ patchParam[patch].numBandsInPatch = numBandsInPatch;
+ patchParam[patch].sourceStopBand =
+ patchParam[patch].sourceStartBand + numBandsInPatch;
+
+ targetStopBand += patchParam[patch].numBandsInPatch;
+ patch++;
+ }
+
+ /* All patches but first */
+ sourceStartBand = SHIFT_START_SB;
+
+ /* Check if we are close to desiredBorder */
+ if (desiredBorder - targetStopBand < 3) /* MPEG doc */
+ {
+ desiredBorder = usb;
+ }
+ }
+
+ patch--;
+
+ /* If highest patch contains less than three subband: skip it */
+ if ((patch > 0) && (patchParam[patch].numBandsInPatch < 3)) {
+ patch--;
+ targetStopBand =
+ patchParam[patch].targetStartBand + patchParam[patch].numBandsInPatch;
+ }
+
+ /* now check if we don't have one too many */
+ if (patch >= MAX_NUM_PATCHES) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ pSettings->noOfPatches = patch + 1;
+
+ /* Check lowest and highest source subband */
+ pSettings->lbStartPatching = targetStopBand;
+ pSettings->lbStopPatching = 0;
+ for (patch = 0; patch < pSettings->noOfPatches; patch++) {
+ pSettings->lbStartPatching =
+ fixMin(pSettings->lbStartPatching, patchParam[patch].sourceStartBand);
+ pSettings->lbStopPatching =
+ fixMax(pSettings->lbStopPatching, patchParam[patch].sourceStopBand);
+ }
+
+ for (i = 0; i < noNoiseBands; i++) {
+ pSettings->bwBorders[i] = noiseBandTable[i + 1];
+ }
+ for (; i < MAX_NUM_NOISE_VALUES; i++) {
+ pSettings->bwBorders[i] = 255;
+ }
+
+ /*
+ * Choose whitening factors
+ */
+
+ startFreqHz =
+ ((lsb + xoverOffset) * fs) >> 7; /* Shift does a division by 2*(64) */
+
+ for (i = 1; i < NUM_WHFACTOR_TABLE_ENTRIES; i++) {
+ if (startFreqHz < FDK_sbrDecoder_sbr_whFactorsIndex[i]) break;
+ }
+ i--;
+
+ pSettings->whFactors.off = FDK_sbrDecoder_sbr_whFactorsTable[i][0];
+ pSettings->whFactors.transitionLevel =
+ FDK_sbrDecoder_sbr_whFactorsTable[i][1];
+ pSettings->whFactors.lowLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][2];
+ pSettings->whFactors.midLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][3];
+ pSettings->whFactors.highLevel = FDK_sbrDecoder_sbr_whFactorsTable[i][4];
+
+ return SBRDEC_OK;
+}
diff --git a/fdk-aac/libSBRdec/src/lpp_tran.h b/fdk-aac/libSBRdec/src/lpp_tran.h
new file mode 100644
index 0000000..51b4395
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/lpp_tran.h
@@ -0,0 +1,275 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Low Power Profile Transposer
+*/
+
+#ifndef LPP_TRAN_H
+#define LPP_TRAN_H
+
+#include "sbrdecoder.h"
+#include "hbe.h"
+#include "qmf.h"
+
+/*
+ Common
+*/
+#define QMF_OUT_SCALE 8
+
+/*
+ Frequency scales
+*/
+
+/*
+ Env-Adjust
+*/
+#define MAX_NOISE_ENVELOPES 2
+#define MAX_NOISE_COEFFS 5
+#define MAX_NUM_NOISE_VALUES (MAX_NOISE_ENVELOPES * MAX_NOISE_COEFFS)
+#define MAX_NUM_LIMITERS 12
+
+/* Set MAX_ENVELOPES to the largest value of all supported BSFORMATs
+ by overriding MAX_ENVELOPES in the correct order: */
+#define MAX_ENVELOPES_LEGACY 5
+#define MAX_ENVELOPES_USAC 8
+#define MAX_ENVELOPES MAX_ENVELOPES_USAC
+
+#define MAX_FREQ_COEFFS_DUAL_RATE 48
+#define MAX_FREQ_COEFFS_QUAD_RATE 56
+#define MAX_FREQ_COEFFS MAX_FREQ_COEFFS_QUAD_RATE
+
+#define MAX_FREQ_COEFFS_FS44100 35
+#define MAX_FREQ_COEFFS_FS48000 32
+
+#define MAX_NUM_ENVELOPE_VALUES (MAX_ENVELOPES * MAX_FREQ_COEFFS)
+
+#define MAX_GAIN_EXP 34
+/* Maximum gain will be sqrt(0.5 * 2^MAX_GAIN_EXP)
+ example: 34=99dB */
+#define MAX_GAIN_CONCEAL_EXP 1
+/* Maximum gain will be sqrt(0.5 * 2^MAX_GAIN_CONCEAL_EXP) in concealment case
+ * (0dB) */
+
+/*
+ LPP Transposer
+*/
+#define LPC_ORDER 2
+
+#define MAX_INVF_BANDS MAX_NOISE_COEFFS
+
+#define MAX_NUM_PATCHES 6
+#define SHIFT_START_SB 1 /*!< lowest subband of source range */
+
+typedef enum {
+ INVF_OFF = 0,
+ INVF_LOW_LEVEL,
+ INVF_MID_LEVEL,
+ INVF_HIGH_LEVEL,
+ INVF_SWITCHED /* not a real choice but used here to control behaviour */
+} INVF_MODE;
+
+/** parameter set for one single patch */
+typedef struct {
+ UCHAR sourceStartBand; /*!< first band in lowbands where to take the samples
+ from */
+ UCHAR
+ sourceStopBand; /*!< first band in lowbands which is not included in the
+ patch anymore */
+ UCHAR guardStartBand; /*!< first band in highbands to be filled with zeros in
+ order to reduce interferences between patches */
+ UCHAR
+ targetStartBand; /*!< first band in highbands to be filled with whitened
+ lowband signal */
+ UCHAR targetBandOffs; /*!< difference between 'startTargetBand' and
+ 'startSourceBand' */
+ UCHAR numBandsInPatch; /*!< number of consecutive bands in this one patch */
+} PATCH_PARAM;
+
+/** whitening factors for different levels of whitening
+ need to be initialized corresponding to crossover frequency */
+typedef struct {
+ FIXP_DBL off; /*!< bw factor for signal OFF */
+ FIXP_DBL transitionLevel;
+ FIXP_DBL lowLevel; /*!< bw factor for signal LOW_LEVEL */
+ FIXP_DBL midLevel; /*!< bw factor for signal MID_LEVEL */
+ FIXP_DBL highLevel; /*!< bw factor for signal HIGH_LEVEL */
+} WHITENING_FACTORS;
+
+/*! The transposer settings are calculated on a header reset and are shared by
+ * both channels. */
+typedef struct {
+ UCHAR nCols; /*!< number subsamples of a codec frame */
+ UCHAR noOfPatches; /*!< number of patches */
+ UCHAR lbStartPatching; /*!< first band of lowbands that will be patched */
+ UCHAR lbStopPatching; /*!< first band that won't be patched anymore*/
+ UCHAR bwBorders[MAX_NUM_NOISE_VALUES]; /*!< spectral bands with different
+ inverse filtering levels */
+
+ PATCH_PARAM
+ patchParam[MAX_NUM_PATCHES]; /*!< new parameter set for patching */
+ WHITENING_FACTORS
+ whFactors; /*!< the pole moving factors for certain
+ whitening levels as indicated in the bitstream
+ depending on the crossover frequency */
+ UCHAR overlap; /*!< Overlap size */
+} TRANSPOSER_SETTINGS;
+
+typedef struct {
+ TRANSPOSER_SETTINGS *pSettings; /*!< Common settings for both channels */
+ FIXP_DBL
+ bwVectorOld[MAX_NUM_PATCHES]; /*!< pole moving factors of past frame */
+ FIXP_DBL lpcFilterStatesRealLegSBR[LPC_ORDER + (3 * (4))][(
+ 32)]; /*!< pointer array to save filter states */
+
+ FIXP_DBL lpcFilterStatesImagLegSBR[LPC_ORDER + (3 * (4))][(
+ 32)]; /*!< pointer array to save filter states */
+
+ FIXP_DBL lpcFilterStatesRealHBE[LPC_ORDER + (3 * (4))][(
+ 64)]; /*!< pointer array to save filter states */
+ FIXP_DBL lpcFilterStatesImagHBE[LPC_ORDER + (3 * (4))][(
+ 64)]; /*!< pointer array to save filter states */
+} SBR_LPP_TRANS;
+
+typedef SBR_LPP_TRANS *HANDLE_SBR_LPP_TRANS;
+
+void lppTransposer(HANDLE_SBR_LPP_TRANS hLppTrans,
+ QMF_SCALE_FACTOR *sbrScaleFactor, FIXP_DBL **qmfBufferReal,
+
+ FIXP_DBL *degreeAlias, FIXP_DBL **qmfBufferImag,
+ const int useLP, const int fPreWhitening,
+ const int v_k_master0, const int timeStep,
+ const int firstSlotOffset, const int lastSlotOffset,
+ const int nInvfBands, INVF_MODE *sbr_invf_mode,
+ INVF_MODE *sbr_invf_mode_prev);
+
+void lppTransposerHBE(
+ HANDLE_SBR_LPP_TRANS hLppTrans, /*!< Handle of lpp transposer */
+ HANDLE_HBE_TRANSPOSER hQmfTransposer,
+ QMF_SCALE_FACTOR *sbrScaleFactor, /*!< Scaling factors */
+ FIXP_DBL **qmfBufferReal, /*!< Pointer to pointer to real part of subband
+ samples (source) */
+ FIXP_DBL **qmfBufferImag, /*!< Pointer to pointer to imaginary part of
+ subband samples (source) */
+ const int timeStep, /*!< Time step of envelope */
+ const int firstSlotOffs, /*!< Start position in time */
+ const int lastSlotOffs, /*!< Number of overlap-slots into next frame */
+ const int nInvfBands, /*!< Number of bands for inverse filtering */
+ INVF_MODE *sbr_invf_mode, /*!< Current inverse filtering modes */
+ INVF_MODE *sbr_invf_mode_prev /*!< Previous inverse filtering modes */
+);
+
+SBR_ERROR
+createLppTransposer(HANDLE_SBR_LPP_TRANS hLppTrans,
+ TRANSPOSER_SETTINGS *pSettings, const int highBandStartSb,
+ UCHAR *v_k_master, const int numMaster, const int usb,
+ const int timeSlots, const int nCols, UCHAR *noiseBandTable,
+ const int noNoiseBands, UINT fs, const int chan,
+ const int overlap);
+
+SBR_ERROR
+resetLppTransposer(HANDLE_SBR_LPP_TRANS hLppTrans, UCHAR highBandStartSb,
+ UCHAR *v_k_master, UCHAR numMaster, UCHAR *noiseBandTable,
+ UCHAR noNoiseBands, UCHAR usb, UINT fs);
+
+#endif /* LPP_TRAN_H */
diff --git a/fdk-aac/libSBRdec/src/psbitdec.cpp b/fdk-aac/libSBRdec/src/psbitdec.cpp
new file mode 100644
index 0000000..82bb65b
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/psbitdec.cpp
@@ -0,0 +1,594 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+#include "psbitdec.h"
+
+#include "sbr_rom.h"
+#include "huff_dec.h"
+
+/* PS dec privat functions */
+SBR_ERROR ResetPsDec(HANDLE_PS_DEC h_ps_d);
+
+/***************************************************************************/
+/*!
+ \brief huffman decoding by codebook table
+
+ \return index of huffman codebook table
+
+****************************************************************************/
+static SCHAR decode_huff_cw(
+ Huffman h, /*!< pointer to huffman codebook table */
+ HANDLE_FDK_BITSTREAM hBitBuf, /*!< Handle to Bitbuffer */
+ int *length) /*!< length of huffman codeword (or NULL) */
+{
+ UCHAR bit = 0;
+ SCHAR index = 0;
+ UCHAR bitCount = 0;
+
+ while (index >= 0) {
+ bit = FDKreadBits(hBitBuf, 1);
+ bitCount++;
+ index = h[index][bit];
+ }
+ if (length) {
+ *length = bitCount;
+ }
+ return (index + 64); /* Add offset */
+}
+
+/***************************************************************************/
+/*!
+ \brief helper function - limiting of value to min/max values
+
+ \return limited value
+
+****************************************************************************/
+
+static SCHAR limitMinMax(SCHAR i, SCHAR min, SCHAR max) {
+ if (i < min)
+ return min;
+ else if (i > max)
+ return max;
+ else
+ return i;
+}
+
+/***************************************************************************/
+/*!
+ \brief Decodes delta values in-place and updates
+ data buffers according to quantization classes.
+
+ When delta coded in frequency the first element is deltacode from zero.
+ aIndex buffer is decoded from delta values to actual values.
+
+ \return none
+
+****************************************************************************/
+static void deltaDecodeArray(
+ SCHAR enable, SCHAR *aIndex, /*!< ICC/IID parameters */
+ SCHAR *aPrevFrameIndex, /*!< ICC/IID parameters of previous frame */
+ SCHAR DtDf, UCHAR nrElements, /*!< as conveyed in bitstream */
+ /*!< output array size: nrElements*stride */
+ UCHAR stride, /*!< 1=dflt, 2=half freq. resolution */
+ SCHAR minIdx, SCHAR maxIdx) {
+ int i;
+
+ /* Delta decode */
+ if (enable == 1) {
+ if (DtDf == 0) { /* Delta coded in freq */
+ aIndex[0] = 0 + aIndex[0];
+ aIndex[0] = limitMinMax(aIndex[0], minIdx, maxIdx);
+ for (i = 1; i < nrElements; i++) {
+ aIndex[i] = aIndex[i - 1] + aIndex[i];
+ aIndex[i] = limitMinMax(aIndex[i], minIdx, maxIdx);
+ }
+ } else { /* Delta time */
+ for (i = 0; i < nrElements; i++) {
+ aIndex[i] = aPrevFrameIndex[i * stride] + aIndex[i];
+ aIndex[i] = limitMinMax(aIndex[i], minIdx, maxIdx);
+ }
+ }
+ } else { /* No data is sent, set index to zero */
+ for (i = 0; i < nrElements; i++) {
+ aIndex[i] = 0;
+ }
+ }
+ if (stride == 2) {
+ for (i = nrElements * stride - 1; i > 0; i--) {
+ aIndex[i] = aIndex[i >> 1];
+ }
+ }
+}
+
+/***************************************************************************/
+/*!
+ \brief Mapping of ICC/IID parameters to 20 stereo bands
+
+ \return none
+
+****************************************************************************/
+static void map34IndexTo20(SCHAR *aIndex, /*!< decoded ICC/IID parameters */
+ UCHAR noBins) /*!< number of stereo bands */
+{
+ aIndex[0] = (2 * aIndex[0] + aIndex[1]) / 3;
+ aIndex[1] = (aIndex[1] + 2 * aIndex[2]) / 3;
+ aIndex[2] = (2 * aIndex[3] + aIndex[4]) / 3;
+ aIndex[3] = (aIndex[4] + 2 * aIndex[5]) / 3;
+ aIndex[4] = (aIndex[6] + aIndex[7]) / 2;
+ aIndex[5] = (aIndex[8] + aIndex[9]) / 2;
+ aIndex[6] = aIndex[10];
+ aIndex[7] = aIndex[11];
+ aIndex[8] = (aIndex[12] + aIndex[13]) / 2;
+ aIndex[9] = (aIndex[14] + aIndex[15]) / 2;
+ aIndex[10] = aIndex[16];
+ /* For IPD/OPD it stops here */
+
+ if (noBins == NO_HI_RES_BINS) {
+ aIndex[11] = aIndex[17];
+ aIndex[12] = aIndex[18];
+ aIndex[13] = aIndex[19];
+ aIndex[14] = (aIndex[20] + aIndex[21]) / 2;
+ aIndex[15] = (aIndex[22] + aIndex[23]) / 2;
+ aIndex[16] = (aIndex[24] + aIndex[25]) / 2;
+ aIndex[17] = (aIndex[26] + aIndex[27]) / 2;
+ aIndex[18] = (aIndex[28] + aIndex[29] + aIndex[30] + aIndex[31]) / 4;
+ aIndex[19] = (aIndex[32] + aIndex[33]) / 2;
+ }
+}
+
+/***************************************************************************/
+/*!
+ \brief Decodes delta coded IID, ICC, IPD and OPD indices
+
+ \return PS processing flag. If set to 1
+
+****************************************************************************/
+int DecodePs(struct PS_DEC *h_ps_d, /*!< PS handle */
+ const UCHAR frameError, /*!< Flag telling that frame had errors */
+ PS_DEC_COEFFICIENTS *pScratch) {
+ MPEG_PS_BS_DATA *pBsData;
+ UCHAR gr, env;
+ int bPsHeaderValid, bPsDataAvail;
+
+ /* Assign Scratch */
+ h_ps_d->specificTo.mpeg.pCoef = pScratch;
+
+ /* Shortcuts to avoid deferencing and keep the code readable */
+ pBsData = &h_ps_d->bsData[h_ps_d->processSlot].mpeg;
+ bPsHeaderValid = pBsData->bPsHeaderValid;
+ bPsDataAvail =
+ (h_ps_d->bPsDataAvail[h_ps_d->processSlot] == ppt_mpeg) ? 1 : 0;
+
+ /***************************************************************************************
+ * Decide whether to process or to conceal PS data or not. */
+
+ if ((h_ps_d->psDecodedPrv && !frameError && !bPsDataAvail) ||
+ (!h_ps_d->psDecodedPrv &&
+ (frameError || !bPsDataAvail || !bPsHeaderValid))) {
+ /* Don't apply PS processing.
+ * Declare current PS header and bitstream data invalid. */
+ pBsData->bPsHeaderValid = 0;
+ h_ps_d->bPsDataAvail[h_ps_d->processSlot] = ppt_none;
+ return (0);
+ }
+
+ if (frameError ||
+ !bPsHeaderValid) { /* no new PS data available (e.g. frame loss) */
+ /* => keep latest data constant (i.e. FIX with noEnv=0) */
+ pBsData->noEnv = 0;
+ }
+
+ /***************************************************************************************
+ * Decode bitstream payload or prepare parameter for concealment:
+ */
+ for (env = 0; env < pBsData->noEnv; env++) {
+ SCHAR *aPrevIidIndex;
+ SCHAR *aPrevIccIndex;
+
+ UCHAR noIidSteps = pBsData->bFineIidQ ? NO_IID_STEPS_FINE : NO_IID_STEPS;
+
+ if (env == 0) {
+ aPrevIidIndex = h_ps_d->specificTo.mpeg.aIidPrevFrameIndex;
+ aPrevIccIndex = h_ps_d->specificTo.mpeg.aIccPrevFrameIndex;
+ } else {
+ aPrevIidIndex = pBsData->aaIidIndex[env - 1];
+ aPrevIccIndex = pBsData->aaIccIndex[env - 1];
+ }
+
+ deltaDecodeArray(pBsData->bEnableIid, pBsData->aaIidIndex[env],
+ aPrevIidIndex, pBsData->abIidDtFlag[env],
+ FDK_sbrDecoder_aNoIidBins[pBsData->freqResIid],
+ (pBsData->freqResIid) ? 1 : 2, -noIidSteps, noIidSteps);
+
+ deltaDecodeArray(pBsData->bEnableIcc, pBsData->aaIccIndex[env],
+ aPrevIccIndex, pBsData->abIccDtFlag[env],
+ FDK_sbrDecoder_aNoIccBins[pBsData->freqResIcc],
+ (pBsData->freqResIcc) ? 1 : 2, 0, NO_ICC_STEPS - 1);
+ } /* for (env=0; env<pBsData->noEnv; env++) */
+
+ /* handling of FIX noEnv=0 */
+ if (pBsData->noEnv == 0) {
+ /* set noEnv=1, keep last parameters or force 0 if not enabled */
+ pBsData->noEnv = 1;
+
+ if (pBsData->bEnableIid) {
+ pBsData->bFineIidQ = h_ps_d->specificTo.mpeg.bPrevFrameFineIidQ;
+ pBsData->freqResIid = h_ps_d->specificTo.mpeg.prevFreqResIid;
+ for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) {
+ pBsData->aaIidIndex[pBsData->noEnv - 1][gr] =
+ h_ps_d->specificTo.mpeg.aIidPrevFrameIndex[gr];
+ }
+ } else {
+ for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) {
+ pBsData->aaIidIndex[pBsData->noEnv - 1][gr] = 0;
+ }
+ }
+
+ if (pBsData->bEnableIcc) {
+ pBsData->freqResIcc = h_ps_d->specificTo.mpeg.prevFreqResIcc;
+ for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) {
+ pBsData->aaIccIndex[pBsData->noEnv - 1][gr] =
+ h_ps_d->specificTo.mpeg.aIccPrevFrameIndex[gr];
+ }
+ } else {
+ for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) {
+ pBsData->aaIccIndex[pBsData->noEnv - 1][gr] = 0;
+ }
+ }
+ }
+
+ /* Update previous frame Iid quantization */
+ h_ps_d->specificTo.mpeg.bPrevFrameFineIidQ = pBsData->bFineIidQ;
+
+ /* Update previous frequency resolution for IID */
+ h_ps_d->specificTo.mpeg.prevFreqResIid = pBsData->freqResIid;
+
+ /* Update previous frequency resolution for ICC */
+ h_ps_d->specificTo.mpeg.prevFreqResIcc = pBsData->freqResIcc;
+
+ /* Update previous frame index buffers */
+ for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) {
+ h_ps_d->specificTo.mpeg.aIidPrevFrameIndex[gr] =
+ pBsData->aaIidIndex[pBsData->noEnv - 1][gr];
+ }
+ for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) {
+ h_ps_d->specificTo.mpeg.aIccPrevFrameIndex[gr] =
+ pBsData->aaIccIndex[pBsData->noEnv - 1][gr];
+ }
+
+ /* PS data from bitstream (if avail) was decoded now */
+ h_ps_d->bPsDataAvail[h_ps_d->processSlot] = ppt_none;
+
+ /* handling of env borders for FIX & VAR */
+ if (pBsData->bFrameClass == 0) {
+ /* FIX_BORDERS NoEnv=0,1,2,4 */
+ pBsData->aEnvStartStop[0] = 0;
+ for (env = 1; env < pBsData->noEnv; env++) {
+ pBsData->aEnvStartStop[env] =
+ (env * h_ps_d->noSubSamples) / pBsData->noEnv;
+ }
+ pBsData->aEnvStartStop[pBsData->noEnv] = h_ps_d->noSubSamples;
+ /* 1024 (32 slots) env borders: 0, 8, 16, 24, 32 */
+ /* 960 (30 slots) env borders: 0, 7, 15, 22, 30 */
+ } else { /* if (h_ps_d->bFrameClass == 0) */
+ /* VAR_BORDERS NoEnv=1,2,3,4 */
+ pBsData->aEnvStartStop[0] = 0;
+
+ /* handle case aEnvStartStop[noEnv]<noSubSample for VAR_BORDERS by
+ duplicating last PS parameters and incrementing noEnv */
+ if (pBsData->aEnvStartStop[pBsData->noEnv] < h_ps_d->noSubSamples) {
+ for (gr = 0; gr < NO_HI_RES_IID_BINS; gr++) {
+ pBsData->aaIidIndex[pBsData->noEnv][gr] =
+ pBsData->aaIidIndex[pBsData->noEnv - 1][gr];
+ }
+ for (gr = 0; gr < NO_HI_RES_ICC_BINS; gr++) {
+ pBsData->aaIccIndex[pBsData->noEnv][gr] =
+ pBsData->aaIccIndex[pBsData->noEnv - 1][gr];
+ }
+ pBsData->noEnv++;
+ pBsData->aEnvStartStop[pBsData->noEnv] = h_ps_d->noSubSamples;
+ }
+
+ /* enforce strictly monotonic increasing borders */
+ for (env = 1; env < pBsData->noEnv; env++) {
+ UCHAR thr;
+ thr = (UCHAR)h_ps_d->noSubSamples - (pBsData->noEnv - env);
+ if (pBsData->aEnvStartStop[env] > thr) {
+ pBsData->aEnvStartStop[env] = thr;
+ } else {
+ thr = pBsData->aEnvStartStop[env - 1] + 1;
+ if (pBsData->aEnvStartStop[env] < thr) {
+ pBsData->aEnvStartStop[env] = thr;
+ }
+ }
+ }
+ } /* if (h_ps_d->bFrameClass == 0) ... else */
+
+ /* copy data prior to possible 20<->34 in-place mapping */
+ for (env = 0; env < pBsData->noEnv; env++) {
+ UCHAR i;
+ for (i = 0; i < NO_HI_RES_IID_BINS; i++) {
+ h_ps_d->specificTo.mpeg.pCoef->aaIidIndexMapped[env][i] =
+ pBsData->aaIidIndex[env][i];
+ }
+ for (i = 0; i < NO_HI_RES_ICC_BINS; i++) {
+ h_ps_d->specificTo.mpeg.pCoef->aaIccIndexMapped[env][i] =
+ pBsData->aaIccIndex[env][i];
+ }
+ }
+
+ /* MPEG baseline PS */
+ /* Baseline version of PS always uses the hybrid filter structure with 20
+ * stereo bands. */
+ /* If ICC/IID parameters for 34 stereo bands are decoded they have to be
+ * mapped to 20 */
+ /* stereo bands. */
+ /* Additionaly the IPD/OPD parameters won't be used. */
+
+ for (env = 0; env < pBsData->noEnv; env++) {
+ if (pBsData->freqResIid == 2)
+ map34IndexTo20(h_ps_d->specificTo.mpeg.pCoef->aaIidIndexMapped[env],
+ NO_HI_RES_IID_BINS);
+ if (pBsData->freqResIcc == 2)
+ map34IndexTo20(h_ps_d->specificTo.mpeg.pCoef->aaIccIndexMapped[env],
+ NO_HI_RES_ICC_BINS);
+
+ /* IPD/OPD is disabled in baseline version and thus was removed here */
+ }
+
+ return (1);
+}
+
+/***************************************************************************/
+/*!
+
+ \brief Reads parametric stereo data from bitstream
+
+ \return
+
+****************************************************************************/
+unsigned int ReadPsData(
+ HANDLE_PS_DEC h_ps_d, /*!< handle to struct PS_DEC */
+ HANDLE_FDK_BITSTREAM hBitBuf, /*!< handle to struct BIT_BUF */
+ int nBitsLeft /*!< max number of bits available */
+) {
+ MPEG_PS_BS_DATA *pBsData;
+
+ UCHAR gr, env;
+ SCHAR dtFlag;
+ INT startbits;
+ Huffman CurrentTable;
+ SCHAR bEnableHeader;
+
+ if (!h_ps_d) return 0;
+
+ pBsData = &h_ps_d->bsData[h_ps_d->bsReadSlot].mpeg;
+
+ if (h_ps_d->bsReadSlot != h_ps_d->bsLastSlot) {
+ /* Copy last header data */
+ FDKmemcpy(pBsData, &h_ps_d->bsData[h_ps_d->bsLastSlot].mpeg,
+ sizeof(MPEG_PS_BS_DATA));
+ }
+
+ startbits = (INT)FDKgetValidBits(hBitBuf);
+
+ bEnableHeader = (SCHAR)FDKreadBits(hBitBuf, 1);
+
+ /* Read header */
+ if (bEnableHeader) {
+ pBsData->bPsHeaderValid = 1;
+ pBsData->bEnableIid = (UCHAR)FDKreadBits(hBitBuf, 1);
+ if (pBsData->bEnableIid) {
+ pBsData->modeIid = (UCHAR)FDKreadBits(hBitBuf, 3);
+ }
+
+ pBsData->bEnableIcc = (UCHAR)FDKreadBits(hBitBuf, 1);
+ if (pBsData->bEnableIcc) {
+ pBsData->modeIcc = (UCHAR)FDKreadBits(hBitBuf, 3);
+ }
+
+ pBsData->bEnableExt = (UCHAR)FDKreadBits(hBitBuf, 1);
+ }
+
+ pBsData->bFrameClass = (UCHAR)FDKreadBits(hBitBuf, 1);
+ if (pBsData->bFrameClass == 0) {
+ /* FIX_BORDERS NoEnv=0,1,2,4 */
+ pBsData->noEnv =
+ FDK_sbrDecoder_aFixNoEnvDecode[(UCHAR)FDKreadBits(hBitBuf, 2)];
+ /* all additional handling of env borders is now in DecodePs() */
+ } else {
+ /* VAR_BORDERS NoEnv=1,2,3,4 */
+ pBsData->noEnv = 1 + (UCHAR)FDKreadBits(hBitBuf, 2);
+ for (env = 1; env < pBsData->noEnv + 1; env++)
+ pBsData->aEnvStartStop[env] = ((UCHAR)FDKreadBits(hBitBuf, 5)) + 1;
+ /* all additional handling of env borders is now in DecodePs() */
+ }
+
+ /* verify that IID & ICC modes (quant grid, freq res) are supported */
+ if ((pBsData->modeIid > 5) || (pBsData->modeIcc > 5)) {
+ /* no useful PS data could be read from bitstream */
+ h_ps_d->bPsDataAvail[h_ps_d->bsReadSlot] = ppt_none;
+ /* discard all remaining bits */
+ nBitsLeft -= startbits - (INT)FDKgetValidBits(hBitBuf);
+ while (nBitsLeft > 0) {
+ int i = nBitsLeft;
+ if (i > 8) {
+ i = 8;
+ }
+ FDKreadBits(hBitBuf, i);
+ nBitsLeft -= i;
+ }
+ return (UINT)(startbits - (INT)FDKgetValidBits(hBitBuf));
+ }
+
+ if (pBsData->modeIid > 2) {
+ pBsData->freqResIid = pBsData->modeIid - 3;
+ pBsData->bFineIidQ = 1;
+ } else {
+ pBsData->freqResIid = pBsData->modeIid;
+ pBsData->bFineIidQ = 0;
+ }
+
+ if (pBsData->modeIcc > 2) {
+ pBsData->freqResIcc = pBsData->modeIcc - 3;
+ } else {
+ pBsData->freqResIcc = pBsData->modeIcc;
+ }
+
+ /* Extract IID data */
+ if (pBsData->bEnableIid) {
+ for (env = 0; env < pBsData->noEnv; env++) {
+ dtFlag = (SCHAR)FDKreadBits(hBitBuf, 1);
+ if (!dtFlag) {
+ if (pBsData->bFineIidQ)
+ CurrentTable = (Huffman)&aBookPsIidFineFreqDecode;
+ else
+ CurrentTable = (Huffman)&aBookPsIidFreqDecode;
+ } else {
+ if (pBsData->bFineIidQ)
+ CurrentTable = (Huffman)&aBookPsIidFineTimeDecode;
+ else
+ CurrentTable = (Huffman)&aBookPsIidTimeDecode;
+ }
+
+ for (gr = 0; gr < FDK_sbrDecoder_aNoIidBins[pBsData->freqResIid]; gr++)
+ pBsData->aaIidIndex[env][gr] =
+ decode_huff_cw(CurrentTable, hBitBuf, NULL);
+ pBsData->abIidDtFlag[env] = dtFlag;
+ }
+ }
+
+ /* Extract ICC data */
+ if (pBsData->bEnableIcc) {
+ for (env = 0; env < pBsData->noEnv; env++) {
+ dtFlag = (SCHAR)FDKreadBits(hBitBuf, 1);
+ if (!dtFlag)
+ CurrentTable = (Huffman)&aBookPsIccFreqDecode;
+ else
+ CurrentTable = (Huffman)&aBookPsIccTimeDecode;
+
+ for (gr = 0; gr < FDK_sbrDecoder_aNoIccBins[pBsData->freqResIcc]; gr++)
+ pBsData->aaIccIndex[env][gr] =
+ decode_huff_cw(CurrentTable, hBitBuf, NULL);
+ pBsData->abIccDtFlag[env] = dtFlag;
+ }
+ }
+
+ if (pBsData->bEnableExt) {
+ /*!
+ Decoders that support only the baseline version of the PS tool are allowed
+ to ignore the IPD/OPD data, but according header data has to be parsed.
+ ISO/IEC 14496-3 Subpart 8 Annex 4
+ */
+
+ int cnt = FDKreadBits(hBitBuf, PS_EXTENSION_SIZE_BITS);
+ if (cnt == (1 << PS_EXTENSION_SIZE_BITS) - 1) {
+ cnt += FDKreadBits(hBitBuf, PS_EXTENSION_ESC_COUNT_BITS);
+ }
+ while (cnt--) FDKreadBits(hBitBuf, 8);
+ }
+
+ /* new PS data was read from bitstream */
+ h_ps_d->bPsDataAvail[h_ps_d->bsReadSlot] = ppt_mpeg;
+
+ return (startbits - (INT)FDKgetValidBits(hBitBuf));
+}
diff --git a/fdk-aac/libSBRdec/src/psbitdec.h b/fdk-aac/libSBRdec/src/psbitdec.h
new file mode 100644
index 0000000..f0fc43a
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/psbitdec.h
@@ -0,0 +1,116 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+#ifndef PSBITDEC_H
+#define PSBITDEC_H
+
+#include "sbrdecoder.h"
+
+#include "psdec.h"
+
+unsigned int ReadPsData(struct PS_DEC *h_ps_d, HANDLE_FDK_BITSTREAM hBs,
+ int nBitsLeft);
+
+int DecodePs(struct PS_DEC *h_ps_d, const UCHAR frameError,
+ PS_DEC_COEFFICIENTS *pCoef);
+
+#endif /* PSBITDEC_H */
diff --git a/fdk-aac/libSBRdec/src/psdec.cpp b/fdk-aac/libSBRdec/src/psdec.cpp
new file mode 100644
index 0000000..b31b310
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/psdec.cpp
@@ -0,0 +1,722 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief parametric stereo decoder
+*/
+
+#include "psdec.h"
+
+#include "FDK_bitbuffer.h"
+
+#include "sbr_rom.h"
+#include "sbr_ram.h"
+
+#include "FDK_tools_rom.h"
+
+#include "genericStds.h"
+
+#include "FDK_trigFcts.h"
+
+/********************************************************************/
+/* MLQUAL DEFINES */
+/********************************************************************/
+
+#define FRACT_ZERO FRACT_BITS - 1
+/********************************************************************/
+
+SBR_ERROR ResetPsDec(HANDLE_PS_DEC h_ps_d);
+
+/***** HELPERS *****/
+
+/***************************************************************************/
+/*!
+ \brief Creates one instance of the PS_DEC struct
+
+ \return Error info
+
+****************************************************************************/
+int CreatePsDec(HANDLE_PS_DEC *h_PS_DEC, /*!< pointer to the module state */
+ int aacSamplesPerFrame) {
+ SBR_ERROR errorInfo = SBRDEC_OK;
+ HANDLE_PS_DEC h_ps_d;
+ int i;
+
+ if (*h_PS_DEC == NULL) {
+ /* Get ps dec ram */
+ h_ps_d = GetRam_ps_dec();
+ if (h_ps_d == NULL) {
+ goto bail;
+ }
+ } else {
+ /* Reset an open instance */
+ h_ps_d = *h_PS_DEC;
+ }
+
+ /*
+ * Create Analysis Hybrid filterbank.
+ */
+ FDKhybridAnalysisOpen(&h_ps_d->specificTo.mpeg.hybridAnalysis,
+ h_ps_d->specificTo.mpeg.pHybridAnaStatesLFdmx,
+ sizeof(h_ps_d->specificTo.mpeg.pHybridAnaStatesLFdmx),
+ NULL, 0);
+
+ /* initialisation */
+ switch (aacSamplesPerFrame) {
+ case 960:
+ h_ps_d->noSubSamples = 30; /* col */
+ break;
+ case 1024:
+ h_ps_d->noSubSamples = 32; /* col */
+ break;
+ default:
+ h_ps_d->noSubSamples = -1;
+ break;
+ }
+
+ if (h_ps_d->noSubSamples > MAX_NUM_COL || h_ps_d->noSubSamples <= 0) {
+ goto bail;
+ }
+ h_ps_d->noChannels = NO_QMF_CHANNELS; /* row */
+
+ h_ps_d->psDecodedPrv = 0;
+ h_ps_d->procFrameBased = -1;
+ for (i = 0; i < (1) + 1; i++) {
+ h_ps_d->bPsDataAvail[i] = ppt_none;
+ }
+ {
+ int error;
+ error = FDKdecorrelateOpen(&(h_ps_d->specificTo.mpeg.apDecor),
+ h_ps_d->specificTo.mpeg.decorrBufferCplx,
+ (2 * ((825) + (373))));
+ if (error) goto bail;
+ }
+
+ for (i = 0; i < (1) + 1; i++) {
+ FDKmemclear(&h_ps_d->bsData[i].mpeg, sizeof(MPEG_PS_BS_DATA));
+ }
+
+ errorInfo = ResetPsDec(h_ps_d);
+
+ if (errorInfo != SBRDEC_OK) goto bail;
+
+ *h_PS_DEC = h_ps_d;
+
+ return 0;
+
+bail:
+ if (h_ps_d != NULL) {
+ DeletePsDec(&h_ps_d);
+ }
+
+ return -1;
+} /*END CreatePsDec */
+
+/***************************************************************************/
+/*!
+ \brief Delete one instance of the PS_DEC struct
+
+ \return Error info
+
+****************************************************************************/
+int DeletePsDec(HANDLE_PS_DEC *h_PS_DEC) /*!< pointer to the module state */
+{
+ if (*h_PS_DEC == NULL) {
+ return -1;
+ }
+
+ {
+ HANDLE_PS_DEC h_ps_d = *h_PS_DEC;
+ FDKdecorrelateClose(&(h_ps_d->specificTo.mpeg.apDecor));
+ }
+
+ FreeRam_ps_dec(h_PS_DEC);
+
+ return 0;
+} /*END DeletePsDec */
+
+/***************************************************************************/
+/*!
+ \brief resets some values of the PS handle to default states
+
+ \return
+
+****************************************************************************/
+SBR_ERROR ResetPsDec(HANDLE_PS_DEC h_ps_d) /*!< pointer to the module state */
+{
+ SBR_ERROR errorInfo = SBRDEC_OK;
+ INT i;
+
+ /* explicitly init state variables to safe values (until first ps header
+ * arrives) */
+
+ h_ps_d->specificTo.mpeg.lastUsb = 0;
+
+ /*
+ * Initialize Analysis Hybrid filterbank.
+ */
+ FDKhybridAnalysisInit(&h_ps_d->specificTo.mpeg.hybridAnalysis, THREE_TO_TEN,
+ NO_QMF_BANDS_HYBRID20, NO_QMF_BANDS_HYBRID20, 1);
+
+ /*
+ * Initialize Synthesis Hybrid filterbank.
+ */
+ for (i = 0; i < 2; i++) {
+ FDKhybridSynthesisInit(&h_ps_d->specificTo.mpeg.hybridSynthesis[i],
+ THREE_TO_TEN, NO_QMF_CHANNELS, NO_QMF_CHANNELS);
+ }
+ {
+ INT error;
+ error = FDKdecorrelateInit(&h_ps_d->specificTo.mpeg.apDecor, 71, DECORR_PS,
+ DUCKER_AUTOMATIC, 0, 0, 0, 0, 1, /* isLegacyPS */
+ 1);
+ if (error) return SBRDEC_NOT_INITIALIZED;
+ }
+
+ for (i = 0; i < NO_IID_GROUPS; i++) {
+ h_ps_d->specificTo.mpeg.h11rPrev[i] = FL2FXCONST_DBL(0.5f);
+ h_ps_d->specificTo.mpeg.h12rPrev[i] = FL2FXCONST_DBL(0.5f);
+ }
+
+ FDKmemclear(h_ps_d->specificTo.mpeg.h21rPrev,
+ sizeof(h_ps_d->specificTo.mpeg.h21rPrev));
+ FDKmemclear(h_ps_d->specificTo.mpeg.h22rPrev,
+ sizeof(h_ps_d->specificTo.mpeg.h22rPrev));
+
+ return errorInfo;
+}
+
+/***************************************************************************/
+/*!
+ \brief Feed delaylines when parametric stereo is switched on.
+ \return
+****************************************************************************/
+void PreparePsProcessing(HANDLE_PS_DEC h_ps_d,
+ const FIXP_DBL *const *const rIntBufferLeft,
+ const FIXP_DBL *const *const iIntBufferLeft,
+ const int scaleFactorLowBand) {
+ if (h_ps_d->procFrameBased ==
+ 1) /* If we have switched from frame to slot based processing */
+ { /* fill hybrid delay buffer. */
+ int i, j;
+
+ for (i = 0; i < HYBRID_FILTER_DELAY; i++) {
+ FIXP_DBL qmfInputData[2][NO_QMF_BANDS_HYBRID20];
+ FIXP_DBL hybridOutputData[2][NO_SUB_QMF_CHANNELS];
+
+ for (j = 0; j < NO_QMF_BANDS_HYBRID20; j++) {
+ qmfInputData[0][j] =
+ scaleValue(rIntBufferLeft[i][j], scaleFactorLowBand);
+ qmfInputData[1][j] =
+ scaleValue(iIntBufferLeft[i][j], scaleFactorLowBand);
+ }
+
+ FDKhybridAnalysisApply(&h_ps_d->specificTo.mpeg.hybridAnalysis,
+ qmfInputData[0], qmfInputData[1],
+ hybridOutputData[0], hybridOutputData[1]);
+ }
+ h_ps_d->procFrameBased = 0; /* switch to slot based processing. */
+
+ } /* procFrameBased==1 */
+}
+
+void initSlotBasedRotation(
+ HANDLE_PS_DEC h_ps_d, /*!< pointer to the module state */
+ int env, int usb) {
+ INT group = 0;
+ INT bin = 0;
+ INT noIidSteps, noFactors;
+
+ FIXP_SGL invL;
+ FIXP_DBL ScaleL, ScaleR;
+ FIXP_DBL Alpha, Beta, AlphasValue;
+ FIXP_DBL h11r, h12r, h21r, h22r;
+
+ const FIXP_DBL *PScaleFactors;
+
+ if (h_ps_d->bsData[h_ps_d->processSlot].mpeg.bFineIidQ) {
+ PScaleFactors = ScaleFactorsFine; /* values are shiftet right by one */
+ noIidSteps = NO_IID_STEPS_FINE;
+ noFactors = NO_IID_LEVELS_FINE;
+ } else {
+ PScaleFactors = ScaleFactors; /* values are shiftet right by one */
+ noIidSteps = NO_IID_STEPS;
+ noFactors = NO_IID_LEVELS;
+ }
+
+ /* dequantize and decode */
+ for (group = 0; group < NO_IID_GROUPS; group++) {
+ bin = bins2groupMap20[group];
+
+ /*!
+ <h3> type 'A' rotation </h3>
+ mixing procedure R_a, used in baseline version<br>
+
+ Scale-factor vectors c1 and c2 are precalculated in initPsTables () and
+ stored in scaleFactors[] and scaleFactorsFine[] = pScaleFactors []. From the
+ linearized IID parameters (intensity differences), two scale factors are
+ calculated. They are used to obtain the coefficients h11... h22.
+ */
+
+ /* ScaleR and ScaleL are scaled by 1 shift right */
+
+ ScaleL = ScaleR = 0;
+ if (noIidSteps + h_ps_d->specificTo.mpeg.pCoef->aaIidIndexMapped[env][bin] >= 0 && noIidSteps + h_ps_d->specificTo.mpeg.pCoef->aaIidIndexMapped[env][bin] < noFactors)
+ ScaleR = PScaleFactors[noIidSteps + h_ps_d->specificTo.mpeg.pCoef
+ ->aaIidIndexMapped[env][bin]];
+ if (noIidSteps - h_ps_d->specificTo.mpeg.pCoef->aaIidIndexMapped[env][bin] >= 0 && noIidSteps - h_ps_d->specificTo.mpeg.pCoef->aaIidIndexMapped[env][bin] < noFactors)
+ ScaleL = PScaleFactors[noIidSteps - h_ps_d->specificTo.mpeg.pCoef
+ ->aaIidIndexMapped[env][bin]];
+
+ AlphasValue = 0;
+ if (h_ps_d->specificTo.mpeg.pCoef->aaIccIndexMapped[env][bin] >= 0)
+ AlphasValue = Alphas[h_ps_d->specificTo.mpeg.pCoef->aaIccIndexMapped[env][bin]];
+ Beta = fMult(
+ fMult(AlphasValue,
+ (ScaleR - ScaleL)),
+ FIXP_SQRT05);
+ Alpha =
+ AlphasValue >> 1;
+
+ /* Alpha and Beta are now both scaled by 2 shifts right */
+
+ /* calculate the coefficients h11... h22 from scale-factors and ICC
+ * parameters */
+
+ /* h values are scaled by 1 shift right */
+ {
+ FIXP_DBL trigData[4];
+
+ inline_fixp_cos_sin(Beta + Alpha, Beta - Alpha, 2, trigData);
+ h11r = fMult(ScaleL, trigData[0]);
+ h12r = fMult(ScaleR, trigData[2]);
+ h21r = fMult(ScaleL, trigData[1]);
+ h22r = fMult(ScaleR, trigData[3]);
+ }
+ /*****************************************************************************************/
+ /* Interpolation of the matrices H11... H22: */
+ /* */
+ /* H11(k,n) = H11(k,n[e]) + (n-n[e]) * (H11(k,n[e+1] - H11(k,n[e])) /
+ * (n[e+1] - n[e]) */
+ /* ... */
+ /*****************************************************************************************/
+
+ /* invL = 1/(length of envelope) */
+ invL = FX_DBL2FX_SGL(GetInvInt(
+ h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env + 1] -
+ h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env]));
+
+ h_ps_d->specificTo.mpeg.pCoef->H11r[group] =
+ h_ps_d->specificTo.mpeg.h11rPrev[group];
+ h_ps_d->specificTo.mpeg.pCoef->H12r[group] =
+ h_ps_d->specificTo.mpeg.h12rPrev[group];
+ h_ps_d->specificTo.mpeg.pCoef->H21r[group] =
+ h_ps_d->specificTo.mpeg.h21rPrev[group];
+ h_ps_d->specificTo.mpeg.pCoef->H22r[group] =
+ h_ps_d->specificTo.mpeg.h22rPrev[group];
+
+ h_ps_d->specificTo.mpeg.pCoef->DeltaH11r[group] =
+ fMult(h11r - h_ps_d->specificTo.mpeg.pCoef->H11r[group], invL);
+ h_ps_d->specificTo.mpeg.pCoef->DeltaH12r[group] =
+ fMult(h12r - h_ps_d->specificTo.mpeg.pCoef->H12r[group], invL);
+ h_ps_d->specificTo.mpeg.pCoef->DeltaH21r[group] =
+ fMult(h21r - h_ps_d->specificTo.mpeg.pCoef->H21r[group], invL);
+ h_ps_d->specificTo.mpeg.pCoef->DeltaH22r[group] =
+ fMult(h22r - h_ps_d->specificTo.mpeg.pCoef->H22r[group], invL);
+
+ /* update prev coefficients for interpolation in next envelope */
+
+ h_ps_d->specificTo.mpeg.h11rPrev[group] = h11r;
+ h_ps_d->specificTo.mpeg.h12rPrev[group] = h12r;
+ h_ps_d->specificTo.mpeg.h21rPrev[group] = h21r;
+ h_ps_d->specificTo.mpeg.h22rPrev[group] = h22r;
+
+ } /* group loop */
+}
+
+static const UCHAR groupTable[NO_IID_GROUPS + 1] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 18, 21, 25, 30, 42, 71};
+
+static void applySlotBasedRotation(
+ HANDLE_PS_DEC h_ps_d, /*!< pointer to the module state */
+
+ FIXP_DBL *mHybridRealLeft, /*!< hybrid values real left */
+ FIXP_DBL *mHybridImagLeft, /*!< hybrid values imag left */
+
+ FIXP_DBL *mHybridRealRight, /*!< hybrid values real right */
+ FIXP_DBL *mHybridImagRight /*!< hybrid values imag right */
+) {
+ INT group;
+ INT subband;
+
+ /**********************************************************************************************/
+ /*!
+ <h2> Mapping </h2>
+
+ The number of stereo bands that is actually used depends on the number of
+ availble parameters for IID and ICC: <pre> nr. of IID para.| nr. of ICC para.
+ | nr. of Stereo bands
+ ----------------|------------------|-------------------
+ 10,20 | 10,20 | 20
+ 10,20 | 34 | 34
+ 34 | 10,20 | 34
+ 34 | 34 | 34
+ </pre>
+ In the case the number of parameters for IIS and ICC differs from the number
+ of stereo bands, a mapping from the lower number to the higher number of
+ parameters is applied. Index mapping of IID and ICC parameters is already done
+ in psbitdec.cpp. Further mapping is not needed here in baseline version.
+ **********************************************************************************************/
+
+ /************************************************************************************************/
+ /*!
+ <h2> Mixing </h2>
+
+ To generate the QMF subband signals for the subband samples n = n[e]+1 ,,,
+ n_[e+1] the parameters at position n[e] and n[e+1] are required as well as the
+ subband domain signals s_k(n) and d_k(n) for n = n[e]+1... n_[e+1]. n[e]
+ represents the start position for envelope e. The border positions n[e] are
+ handled in DecodePS().
+
+ The stereo sub subband signals are constructed as:
+ <pre>
+ l_k(n) = H11(k,n) s_k(n) + H21(k,n) d_k(n)
+ r_k(n) = H21(k,n) s_k(n) + H22(k,n) d_k(n)
+ </pre>
+ In order to obtain the matrices H11(k,n)... H22 (k,n), the vectors h11(b)...
+ h22(b) need to be calculated first (b: parameter index). Depending on ICC mode
+ either mixing procedure R_a or R_b is used for that. For both procedures, the
+ parameters for parameter position n[e+1] is used.
+ ************************************************************************************************/
+
+ /************************************************************************************************/
+ /*!
+ <h2>Phase parameters </h2>
+ With disabled phase parameters (which is the case in baseline version), the
+ H-matrices are just calculated by:
+
+ <pre>
+ H11(k,n[e+1] = h11(b(k))
+ (...)
+ b(k): parameter index according to mapping table
+ </pre>
+
+ <h2>Processing of the samples in the sub subbands </h2>
+ this loop includes the interpolation of the coefficients Hxx
+ ************************************************************************************************/
+
+ /******************************************************/
+ /* construct stereo sub subband signals according to: */
+ /* */
+ /* l_k(n) = H11(k,n) s_k(n) + H21(k,n) d_k(n) */
+ /* r_k(n) = H12(k,n) s_k(n) + H22(k,n) d_k(n) */
+ /******************************************************/
+ PS_DEC_COEFFICIENTS *pCoef = h_ps_d->specificTo.mpeg.pCoef;
+
+ for (group = 0; group < NO_IID_GROUPS; group++) {
+ pCoef->H11r[group] += pCoef->DeltaH11r[group];
+ pCoef->H12r[group] += pCoef->DeltaH12r[group];
+ pCoef->H21r[group] += pCoef->DeltaH21r[group];
+ pCoef->H22r[group] += pCoef->DeltaH22r[group];
+
+ const int start = groupTable[group];
+ const int stop = groupTable[group + 1];
+ for (subband = start; subband < stop; subband++) {
+ FIXP_DBL tmpLeft =
+ fMultAdd(fMultDiv2(pCoef->H11r[group], mHybridRealLeft[subband]),
+ pCoef->H21r[group], mHybridRealRight[subband]);
+ FIXP_DBL tmpRight =
+ fMultAdd(fMultDiv2(pCoef->H12r[group], mHybridRealLeft[subband]),
+ pCoef->H22r[group], mHybridRealRight[subband]);
+ mHybridRealLeft[subband] = tmpLeft;
+ mHybridRealRight[subband] = tmpRight;
+
+ tmpLeft =
+ fMultAdd(fMultDiv2(pCoef->H11r[group], mHybridImagLeft[subband]),
+ pCoef->H21r[group], mHybridImagRight[subband]);
+ tmpRight =
+ fMultAdd(fMultDiv2(pCoef->H12r[group], mHybridImagLeft[subband]),
+ pCoef->H22r[group], mHybridImagRight[subband]);
+ mHybridImagLeft[subband] = tmpLeft;
+ mHybridImagRight[subband] = tmpRight;
+ } /* subband */
+ }
+}
+
+/***************************************************************************/
+/*!
+ \brief Applies IID, ICC, IPD and OPD parameters to the current frame.
+
+ \return none
+
+****************************************************************************/
+void ApplyPsSlot(
+ HANDLE_PS_DEC h_ps_d, /*!< handle PS_DEC*/
+ FIXP_DBL **rIntBufferLeft, /*!< real bands left qmf channel (38x64) */
+ FIXP_DBL **iIntBufferLeft, /*!< imag bands left qmf channel (38x64) */
+ FIXP_DBL *rIntBufferRight, /*!< real bands right qmf channel (38x64) */
+ FIXP_DBL *iIntBufferRight, /*!< imag bands right qmf channel (38x64) */
+ const int scaleFactorLowBand_no_ov, const int scaleFactorLowBand,
+ const int scaleFactorHighBand, const int lsb, const int usb) {
+/*!
+The 64-band QMF representation of the monaural signal generated by the SBR tool
+is used as input of the PS tool. After the PS processing, the outputs of the
+left and right hybrid synthesis filterbanks are used to generate the stereo
+output signal.
+
+<pre>
+
+ ------------- ---------- -------------
+ | Hybrid | M_n[k,m] | | L_n[k,m] | Hybrid | l[n]
+ m[n] --->| analysis |--------->| |--------->| synthesis |----->
+ ------------- | Stereo | -------------
+ | | recon- |
+ | | stuction |
+ \|/ | |
+ ------------- | |
+ | De- | D_n[k,m] | |
+ | correlation |--------->| |
+ ------------- | | -------------
+ | | R_n[k,m] | Hybrid | r[n]
+ | |--------->| synthesis |----->
+ IID, ICC ------------------------>| | | filter bank |
+(IPD, OPD) ---------- -------------
+
+m[n]: QMF represantation of the mono input
+M_n[k,m]: (sub-)sub-band domain signals of the mono input
+D_n[k,m]: decorrelated (sub-)sub-band domain signals
+L_n[k,m]: (sub-)sub-band domain signals of the left output
+R_n[k,m]: (sub-)sub-band domain signals of the right output
+l[n],r[n]: left/right output signals
+
+</pre>
+*/
+#define NO_HYBRID_DATA_BANDS (71)
+
+ int i;
+ FIXP_DBL qmfInputData[2][NO_QMF_BANDS_HYBRID20];
+ FIXP_DBL *hybridData[2][2];
+ C_ALLOC_SCRATCH_START(pHybridData, FIXP_DBL, 4 * NO_HYBRID_DATA_BANDS);
+
+ hybridData[0][0] =
+ pHybridData + 0 * NO_HYBRID_DATA_BANDS; /* left real hybrid data */
+ hybridData[0][1] =
+ pHybridData + 1 * NO_HYBRID_DATA_BANDS; /* left imag hybrid data */
+ hybridData[1][0] =
+ pHybridData + 2 * NO_HYBRID_DATA_BANDS; /* right real hybrid data */
+ hybridData[1][1] =
+ pHybridData + 3 * NO_HYBRID_DATA_BANDS; /* right imag hybrid data */
+
+ /*!
+ Hybrid analysis filterbank:
+ The lower 3 (5) of the 64 QMF subbands are further split to provide better
+ frequency resolution. for PS processing. For the 10 and 20 stereo bands
+ configuration, the QMF band H_0(w) is split up into 8 (sub-) sub-bands and the
+ QMF bands H_1(w) and H_2(w) are spit into 2 (sub-) 4th. (See figures 8.20
+ and 8.22 of ISO/IEC 14496-3:2001/FDAM 2:2004(E) )
+ */
+
+ /*
+ * Hybrid analysis.
+ */
+
+ /* Get qmf input data and apply descaling */
+ for (i = 0; i < NO_QMF_BANDS_HYBRID20; i++) {
+ qmfInputData[0][i] = scaleValue(rIntBufferLeft[HYBRID_FILTER_DELAY][i],
+ scaleFactorLowBand_no_ov);
+ qmfInputData[1][i] = scaleValue(iIntBufferLeft[HYBRID_FILTER_DELAY][i],
+ scaleFactorLowBand_no_ov);
+ }
+
+ /* LF - part */
+ FDKhybridAnalysisApply(&h_ps_d->specificTo.mpeg.hybridAnalysis,
+ qmfInputData[0], qmfInputData[1], hybridData[0][0],
+ hybridData[0][1]);
+
+ /* HF - part */
+ /* bands up to lsb */
+ scaleValues(&hybridData[0][0][NO_SUB_QMF_CHANNELS - 2],
+ &rIntBufferLeft[0][NO_QMF_BANDS_HYBRID20],
+ lsb - NO_QMF_BANDS_HYBRID20, scaleFactorLowBand);
+ scaleValues(&hybridData[0][1][NO_SUB_QMF_CHANNELS - 2],
+ &iIntBufferLeft[0][NO_QMF_BANDS_HYBRID20],
+ lsb - NO_QMF_BANDS_HYBRID20, scaleFactorLowBand);
+
+ /* bands from lsb to usb */
+ scaleValues(&hybridData[0][0][lsb + (NO_SUB_QMF_CHANNELS - 2 -
+ NO_QMF_BANDS_HYBRID20)],
+ &rIntBufferLeft[0][lsb], usb - lsb, scaleFactorHighBand);
+ scaleValues(&hybridData[0][1][lsb + (NO_SUB_QMF_CHANNELS - 2 -
+ NO_QMF_BANDS_HYBRID20)],
+ &iIntBufferLeft[0][lsb], usb - lsb, scaleFactorHighBand);
+
+ /* bands from usb to NO_SUB_QMF_CHANNELS which should be zero for non-overlap
+ slots but can be non-zero for overlap slots */
+ FDKmemcpy(
+ &hybridData[0][0]
+ [usb + (NO_SUB_QMF_CHANNELS - 2 - NO_QMF_BANDS_HYBRID20)],
+ &rIntBufferLeft[0][usb], sizeof(FIXP_DBL) * (NO_QMF_CHANNELS - usb));
+ FDKmemcpy(
+ &hybridData[0][1]
+ [usb + (NO_SUB_QMF_CHANNELS - 2 - NO_QMF_BANDS_HYBRID20)],
+ &iIntBufferLeft[0][usb], sizeof(FIXP_DBL) * (NO_QMF_CHANNELS - usb));
+
+ /*!
+ Decorrelation:
+ By means of all-pass filtering and delaying, the (sub-)sub-band samples s_k(n)
+ are converted into de-correlated (sub-)sub-band samples d_k(n).
+ - k: frequency in hybrid spectrum
+ - n: time index
+ */
+
+ FDKdecorrelateApply(&h_ps_d->specificTo.mpeg.apDecor,
+ &hybridData[0][0][0], /* left real hybrid data */
+ &hybridData[0][1][0], /* left imag hybrid data */
+ &hybridData[1][0][0], /* right real hybrid data */
+ &hybridData[1][1][0], /* right imag hybrid data */
+ 0 /* startHybBand */
+ );
+
+ /*!
+ Stereo Processing:
+ The sets of (sub-)sub-band samples s_k(n) and d_k(n) are processed according
+ to the stereo cues which are defined per stereo band.
+ */
+
+ applySlotBasedRotation(h_ps_d,
+ &hybridData[0][0][0], /* left real hybrid data */
+ &hybridData[0][1][0], /* left imag hybrid data */
+ &hybridData[1][0][0], /* right real hybrid data */
+ &hybridData[1][1][0] /* right imag hybrid data */
+ );
+
+ /*!
+ Hybrid synthesis filterbank:
+ The stereo processed hybrid subband signals l_k(n) and r_k(n) are fed into the
+ hybrid synthesis filterbanks which are identical to the 64 complex synthesis
+ filterbank of the SBR tool. The input to the filterbank are slots of 64 QMF
+ samples. For each slot the filterbank outputs one block of 64 samples of one
+ reconstructed stereo channel. The hybrid synthesis filterbank is computed
+ seperatly for the left and right channel.
+ */
+
+ /*
+ * Hybrid synthesis.
+ */
+ for (i = 0; i < 2; i++) {
+ FDKhybridSynthesisApply(
+ &h_ps_d->specificTo.mpeg.hybridSynthesis[i],
+ hybridData[i][0], /* real hybrid data */
+ hybridData[i][1], /* imag hybrid data */
+ (i == 0) ? rIntBufferLeft[0]
+ : rIntBufferRight, /* output real qmf buffer */
+ (i == 0) ? iIntBufferLeft[0]
+ : iIntBufferRight /* output imag qmf buffer */
+ );
+ }
+
+ /* free temporary hybrid qmf values of one timeslot */
+ C_ALLOC_SCRATCH_END(pHybridData, FIXP_DBL, 4 * NO_HYBRID_DATA_BANDS);
+
+} /* END ApplyPsSlot */
diff --git a/fdk-aac/libSBRdec/src/psdec.h b/fdk-aac/libSBRdec/src/psdec.h
new file mode 100644
index 0000000..029eac4
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/psdec.h
@@ -0,0 +1,333 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Sbr decoder
+*/
+#ifndef PSDEC_H
+#define PSDEC_H
+
+#include "sbrdecoder.h"
+#include "FDK_hybrid.h"
+
+#include "FDK_decorrelate.h"
+
+/* This PS decoder implements the baseline version. So it always uses the */
+/* hybrid filter structure for 20 stereo bands and does not implemet IPD/OPD */
+/* synthesis. The baseline version has to support the complete PS bitstream */
+/* syntax. But IPD/OPD data is ignored and set to 0. If 34 stereo band config */
+/* is used in the bitstream for IIS/ICC the decoded parameters are mapped to */
+/* 20 stereo bands. */
+
+#include "FDK_bitstream.h"
+
+#define SCAL_HEADROOM (2)
+
+#define PS_EXTENSION_SIZE_BITS (4)
+#define PS_EXTENSION_ESC_COUNT_BITS (8)
+
+#define NO_QMF_CHANNELS (64)
+#define MAX_NUM_COL (32)
+
+#define NO_QMF_BANDS_HYBRID20 (3)
+#define NO_SUB_QMF_CHANNELS (12)
+#define HYBRID_FILTER_DELAY (6)
+
+#define MAX_NO_PS_ENV (4 + 1) /* +1 needed for VAR_BORDER */
+
+#define NO_HI_RES_BINS (34)
+#define NO_MID_RES_BINS (20)
+#define NO_LOW_RES_BINS (10)
+
+#define NO_HI_RES_IID_BINS (NO_HI_RES_BINS)
+#define NO_HI_RES_ICC_BINS (NO_HI_RES_BINS)
+
+#define NO_MID_RES_IID_BINS (NO_MID_RES_BINS)
+#define NO_MID_RES_ICC_BINS (NO_MID_RES_BINS)
+
+#define NO_LOW_RES_IID_BINS (NO_LOW_RES_BINS)
+#define NO_LOW_RES_ICC_BINS (NO_LOW_RES_BINS)
+
+#define SUBQMF_GROUPS (10)
+#define QMF_GROUPS (12)
+
+//#define SUBQMF_GROUPS_HI_RES ( 32 )
+//#define QMF_GROUPS_HI_RES ( 18 )
+
+#define NO_IID_GROUPS (SUBQMF_GROUPS + QMF_GROUPS)
+//#define NO_IID_GROUPS_HI_RES ( SUBQMF_GROUPS_HI_RES +
+// QMF_GROUPS_HI_RES )
+
+#define NO_IID_STEPS (7) /* 1 .. + 7 */
+#define NO_IID_STEPS_FINE (15) /* 1 .. +15 */
+#define NO_ICC_STEPS (8) /* 0 .. + 7 */
+
+#define NO_IID_LEVELS (2 * NO_IID_STEPS + 1) /* - 7 .. + 7 */
+#define NO_IID_LEVELS_FINE (2 * NO_IID_STEPS_FINE + 1) /* -15 .. +15 */
+#define NO_ICC_LEVELS (NO_ICC_STEPS) /* 0 .. + 7 */
+
+#define FIXP_SQRT05 ((FIXP_DBL)0x5a827980) /* 1/SQRT2 */
+
+struct PS_DEC_COEFFICIENTS {
+ FIXP_DBL H11r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */
+ FIXP_DBL H12r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */
+ FIXP_DBL H21r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */
+ FIXP_DBL H22r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */
+
+ FIXP_DBL
+ DeltaH11r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */
+ FIXP_DBL
+ DeltaH12r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */
+ FIXP_DBL
+ DeltaH21r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */
+ FIXP_DBL
+ DeltaH22r[NO_IID_GROUPS]; /*!< coefficients of the sub-subband groups */
+
+ SCHAR
+ aaIidIndexMapped[MAX_NO_PS_ENV]
+ [NO_HI_RES_IID_BINS]; /*!< The mapped IID index for all
+ envelopes and all IID bins */
+ SCHAR
+ aaIccIndexMapped[MAX_NO_PS_ENV]
+ [NO_HI_RES_ICC_BINS]; /*!< The mapped ICC index for all
+ envelopes and all ICC bins */
+};
+
+typedef enum { ppt_none = 0, ppt_mpeg = 1, ppt_drm = 2 } PS_PAYLOAD_TYPE;
+
+typedef struct {
+ UCHAR bPsHeaderValid; /*!< set if new header is available from bitstream */
+
+ UCHAR bEnableIid; /*!< One bit denoting the presence of IID parameters */
+ UCHAR bEnableIcc; /*!< One bit denoting the presence of ICC parameters */
+ UCHAR bEnableExt; /*!< The PS extension layer is enabled using the enable_ext
+ bit. If it is set to %1 the IPD and OPD parameters are
+ sent. If it is disabled, i.e. %0, the extension layer is
+ skipped. */
+
+ UCHAR
+ modeIid; /*!< The configuration of IID parameters (number of bands and
+ quantisation grid, iid_quant) is determined by iid_mode. */
+ UCHAR modeIcc; /*!< The configuration of Inter-channel Coherence parameters
+ (number of bands and quantisation grid) is determined by
+ icc_mode. */
+
+ UCHAR freqResIid; /*!< 0=low, 1=mid or 2=high frequency resolution for iid */
+ UCHAR freqResIcc; /*!< 0=low, 1=mid or 2=high frequency resolution for icc */
+
+ UCHAR bFineIidQ; /*!< Use fine Iid quantisation. */
+
+ UCHAR bFrameClass; /*!< The frame_class bit determines whether the parameter
+ positions of the current frame are uniformly spaced
+ accross the frame or they are defined using the
+ positions described by border_position.
+ */
+
+ UCHAR noEnv; /*!< The number of envelopes per frame */
+ UCHAR aEnvStartStop[MAX_NO_PS_ENV + 1]; /*!< In case of variable parameter
+ spacing the parameter positions are
+ determined by border_position */
+
+ SCHAR abIidDtFlag[MAX_NO_PS_ENV]; /*!< Deltacoding time/freq flag for IID, 0
+ => freq */
+ SCHAR abIccDtFlag[MAX_NO_PS_ENV]; /*!< Deltacoding time/freq flag for ICC, 0
+ => freq */
+
+ SCHAR
+ aaIidIndex[MAX_NO_PS_ENV]
+ [NO_HI_RES_IID_BINS]; /*!< The IID index for all envelopes and
+ all IID bins */
+ SCHAR
+ aaIccIndex[MAX_NO_PS_ENV]
+ [NO_HI_RES_ICC_BINS]; /*!< The ICC index for all envelopes and
+ all ICC bins */
+
+} MPEG_PS_BS_DATA;
+
+struct PS_DEC {
+ SCHAR noSubSamples;
+ SCHAR noChannels;
+
+ SCHAR procFrameBased; /*!< Helper to detected switching from frame based to
+ slot based processing
+ */
+
+ PS_PAYLOAD_TYPE
+ bPsDataAvail[(1) + 1]; /*!< set if new data available from bitstream */
+ UCHAR psDecodedPrv; /*!< set if PS has been processed in the last frame */
+
+ /* helpers for frame delay line */
+ UCHAR bsLastSlot; /*!< Index of last read slot. */
+ UCHAR bsReadSlot; /*!< Index of current read slot for additional delay. */
+ UCHAR processSlot; /*!< Index of current slot for processing (need for add.
+ delay). */
+
+ union { /* Bitstream data */
+ MPEG_PS_BS_DATA
+ mpeg; /*!< Struct containing all MPEG specific PS data from bitstream.
+ */
+ } bsData[(1) + 1];
+
+ shouldBeUnion { /* Static data */
+ struct {
+ SCHAR aIidPrevFrameIndex[NO_HI_RES_IID_BINS]; /*!< The IID index for
+ previous frame */
+ SCHAR aIccPrevFrameIndex[NO_HI_RES_ICC_BINS]; /*!< The ICC index for
+ previous frame */
+ UCHAR
+ bPrevFrameFineIidQ; /*!< The IID quantization of the previous frame */
+ UCHAR prevFreqResIid; /*!< Frequency resolution for IID of the previous
+ frame */
+ UCHAR prevFreqResIcc; /*!< Frequency resolution for ICC of the previous
+ frame */
+ UCHAR lastUsb; /*!< uppermost WMF delay band of last frame */
+
+ FIXP_DBL pHybridAnaStatesLFdmx
+ [2 * 13 * NO_QMF_BANDS_HYBRID20]; /*!< Memory used in hybrid analysis
+ for filter states. */
+ FDK_ANA_HYB_FILTER hybridAnalysis;
+ FDK_SYN_HYB_FILTER hybridSynthesis[2];
+
+ DECORR_DEC apDecor; /*!< Decorrelator instance. */
+ FIXP_DBL decorrBufferCplx[(2 * ((825) + (373)))];
+
+ FIXP_DBL h11rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy)
+ coefficients */
+ FIXP_DBL h12rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy)
+ coefficients */
+ FIXP_DBL h21rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy)
+ coefficients */
+ FIXP_DBL h22rPrev[NO_IID_GROUPS]; /*!< previous calculated h(xy)
+ coefficients */
+
+ PS_DEC_COEFFICIENTS
+ *pCoef; /*!< temporal coefficients are on reusable scratch memory */
+
+ } mpeg;
+ }
+ specificTo;
+};
+
+typedef struct PS_DEC *HANDLE_PS_DEC;
+
+int CreatePsDec(HANDLE_PS_DEC *h_PS_DEC, int aacSamplesPerFrame);
+
+int DeletePsDec(HANDLE_PS_DEC *h_PS_DEC);
+
+void PreparePsProcessing(HANDLE_PS_DEC h_ps_d,
+ const FIXP_DBL *const *const rIntBufferLeft,
+ const FIXP_DBL *const *const iIntBufferLeft,
+ const int scaleFactorLowBand);
+
+void initSlotBasedRotation(HANDLE_PS_DEC h_ps_d, int env, int usb);
+
+void ApplyPsSlot(
+ HANDLE_PS_DEC h_ps_d, /* parametric stereo decoder handle */
+ FIXP_DBL **rIntBufferLeft, /* real values of left qmf timeslot */
+ FIXP_DBL **iIntBufferLeft, /* imag values of left qmf timeslot */
+ FIXP_DBL *rIntBufferRight, /* real values of right qmf timeslot */
+ FIXP_DBL *iIntBufferRight, /* imag values of right qmf timeslot */
+ const int scaleFactorLowBand_no_ov, const int scaleFactorLowBand,
+ const int scaleFactorHighBand, const int lsb, const int usb);
+
+#endif /* PSDEC_H */
diff --git a/fdk-aac/libSBRdec/src/psdec_drm.cpp b/fdk-aac/libSBRdec/src/psdec_drm.cpp
new file mode 100644
index 0000000..6971f53
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/psdec_drm.cpp
@@ -0,0 +1,108 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief parametric stereo decoder for Digital radio mondial
+*/
+
+#include "psdec_drm.h"
diff --git a/fdk-aac/libSBRdec/src/psdec_drm.h b/fdk-aac/libSBRdec/src/psdec_drm.h
new file mode 100644
index 0000000..5e2575d
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/psdec_drm.h
@@ -0,0 +1,113 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief parametric stereo decoder for digital radio mondial
+*/
+
+#ifndef PSDEC_DRM_H
+#define PSDEC_DRM_H
+
+#include "sbrdecoder.h"
+
+#endif /* PSDEC_DRM_H */
diff --git a/fdk-aac/libSBRdec/src/psdecrom_drm.cpp b/fdk-aac/libSBRdec/src/psdecrom_drm.cpp
new file mode 100644
index 0000000..2033a83
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/psdecrom_drm.cpp
@@ -0,0 +1,108 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief rom tables for Drm parametric stereo decoder
+*/
+
+#include "psdec_drm.h"
diff --git a/fdk-aac/libSBRdec/src/pvc_dec.cpp b/fdk-aac/libSBRdec/src/pvc_dec.cpp
new file mode 100644
index 0000000..b477122
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/pvc_dec.cpp
@@ -0,0 +1,683 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s): Matthias Hildenbrand
+
+ Description: Decode Predictive Vector Coding Data
+
+*******************************************************************************/
+
+#include "pvc_dec.h"
+
+/* PVC interal definitions */
+#define PVC_DIVMODE_BITS 3
+#define PVC_NSMODE_BITS 1
+#define PVC_REUSEPVCID_BITS 1
+#define PVC_PVCID_BITS 7
+#define PVC_GRIDINFO_BITS 1
+#define PVC_NQMFBAND 64
+#define PVC_NBLOW 3 /* max. number of grouped QMF subbands below SBR range */
+
+#define PVC_NTAB1 3
+#define PVC_NTAB2 128
+#define PVC_ID_NBIT 7
+
+/* Exponent of pPvcStaticData->Esg and predictedEsg in dB domain.
+ max(Esg) = 10*log10(2^15*2^15) = 90.30;
+ min(Esg) = 10*log10(0.1) = -10
+ max of predicted Esg seems to be higher than 90dB but 7 Bit should be enough.
+*/
+#define PVC_ESG_EXP 7
+
+#define LOG10FAC 0.752574989159953f /* == 10/log2(10) * 2^-2 */
+#define LOG10FAC_INV 0.664385618977472f /* == log2(10)/10 * 2^1 */
+
+RAM_ALIGN
+LNK_SECTION_CONSTDATA
+static const FIXP_SGL pvc_SC_16[] = {
+ FX_DBL2FXCONST_SGL(0x14413695), FX_DBL2FXCONST_SGL(0x1434b6cb),
+ FX_DBL2FXCONST_SGL(0x140f27c7), FX_DBL2FXCONST_SGL(0x13d0591d),
+ FX_DBL2FXCONST_SGL(0x1377f502), FX_DBL2FXCONST_SGL(0x130577d6),
+ FX_DBL2FXCONST_SGL(0x12782266), FX_DBL2FXCONST_SGL(0x11cee459),
+ FX_DBL2FXCONST_SGL(0x11083a2a), FX_DBL2FXCONST_SGL(0x1021f5e9),
+ FX_DBL2FXCONST_SGL(0x0f18e17c), FX_DBL2FXCONST_SGL(0x0de814ca),
+ FX_DBL2FXCONST_SGL(0x0c87a568), FX_DBL2FXCONST_SGL(0x0ae9b167),
+ FX_DBL2FXCONST_SGL(0x08f24226), FX_DBL2FXCONST_SGL(0x06575ed5),
+};
+
+RAM_ALIGN
+LNK_SECTION_CONSTDATA
+static const FIXP_SGL pvc_SC_12[] = {
+ FX_DBL2FXCONST_SGL(0x1aba6b3e), FX_DBL2FXCONST_SGL(0x1a9d164e),
+ FX_DBL2FXCONST_SGL(0x1a44d56d), FX_DBL2FXCONST_SGL(0x19b0d742),
+ FX_DBL2FXCONST_SGL(0x18df969a), FX_DBL2FXCONST_SGL(0x17ce91a0),
+ FX_DBL2FXCONST_SGL(0x1679c3fa), FX_DBL2FXCONST_SGL(0x14daabfc),
+ FX_DBL2FXCONST_SGL(0x12e65221), FX_DBL2FXCONST_SGL(0x1088d125),
+ FX_DBL2FXCONST_SGL(0x0d9907b3), FX_DBL2FXCONST_SGL(0x09a80e9d),
+};
+
+RAM_ALIGN
+LNK_SECTION_CONSTDATA
+static const FIXP_SGL pvc_SC_4[] = {
+ FX_DBL2FXCONST_SGL(0x4ad6ab0f),
+ FX_DBL2FXCONST_SGL(0x47ef0dbe),
+ FX_DBL2FXCONST_SGL(0x3eee7496),
+ FX_DBL2FXCONST_SGL(0x2e4bd29d),
+};
+
+RAM_ALIGN
+LNK_SECTION_CONSTDATA
+static const FIXP_SGL pvc_SC_3[] = {
+ FX_DBL2FXCONST_SGL(0x610dc761),
+ FX_DBL2FXCONST_SGL(0x5a519a3d),
+ FX_DBL2FXCONST_SGL(0x44a09e62),
+};
+
+static const UCHAR g_3a_pvcTab1_mode1[PVC_NTAB1][PVC_NBLOW][PVC_NBHIGH_MODE1] =
+ {{{0x4F, 0x5B, 0x57, 0x52, 0x4D, 0x65, 0x45, 0x57},
+ {0xF3, 0x0F, 0x18, 0x20, 0x19, 0x4F, 0x3D, 0x23},
+ {0x78, 0x57, 0x55, 0x50, 0x50, 0x20, 0x36, 0x37}},
+ {{0x4C, 0x5F, 0x53, 0x37, 0x1E, 0xFD, 0x15, 0x0A},
+ {0x05, 0x0E, 0x28, 0x41, 0x48, 0x6E, 0x54, 0x5B},
+ {0x59, 0x47, 0x40, 0x40, 0x3D, 0x33, 0x3F, 0x39}},
+ {{0x47, 0x5F, 0x57, 0x34, 0x3C, 0x2E, 0x2E, 0x31},
+ {0xFA, 0x13, 0x23, 0x4E, 0x44, 0x7C, 0x34, 0x38},
+ {0x63, 0x43, 0x41, 0x3D, 0x35, 0x19, 0x3D, 0x33}}};
+
+static const UCHAR g_2a_pvcTab2_mode1[PVC_NTAB2][PVC_NBHIGH_MODE1] = {
+ {0xCB, 0xD1, 0xCC, 0xD2, 0xE2, 0xEB, 0xE7, 0xE8},
+ {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80},
+ {0x84, 0x8C, 0x88, 0x83, 0x90, 0x93, 0x86, 0x80},
+ {0xD7, 0xD8, 0xC0, 0xC7, 0xCF, 0xE5, 0xF1, 0xF6},
+ {0xA5, 0xA6, 0xAA, 0xA8, 0xB0, 0xB1, 0xB8, 0xB8},
+ {0xD7, 0xCB, 0xC1, 0xC3, 0xC5, 0xC9, 0xC9, 0xCE},
+ {0xCA, 0xB5, 0xB8, 0xB3, 0xAC, 0xB6, 0xBB, 0xB8},
+ {0xC1, 0xC4, 0xC3, 0xC5, 0xC6, 0xCA, 0xCA, 0xCB},
+ {0xE0, 0xE1, 0xD8, 0xCD, 0xCB, 0xCB, 0xCE, 0xCC},
+ {0xDB, 0xE1, 0xDF, 0xDB, 0xDC, 0xD9, 0xD9, 0xD6},
+ {0xE0, 0xDE, 0xDD, 0xDD, 0xE0, 0xE3, 0xE5, 0xE6},
+ {0xCA, 0xD2, 0xCD, 0xCE, 0xD5, 0xDB, 0xD9, 0xDB},
+ {0xD2, 0xE0, 0xDB, 0xD5, 0xDB, 0xDE, 0xE3, 0xE1},
+ {0xE5, 0xDB, 0xD0, 0xD2, 0xD8, 0xDD, 0xDB, 0xDD},
+ {0xC0, 0xB5, 0xBF, 0xDD, 0xE3, 0xDC, 0xDC, 0xE4},
+ {0xDB, 0xCE, 0xC6, 0xCF, 0xCF, 0xD1, 0xD3, 0xD4},
+ {0xC9, 0xD7, 0xDA, 0xE2, 0xE9, 0xE7, 0xDF, 0xDC},
+ {0x0A, 0x07, 0x0A, 0x08, 0x19, 0x24, 0x1F, 0x22},
+ {0x1E, 0x1F, 0x11, 0x0E, 0x22, 0x2D, 0x33, 0x32},
+ {0xF0, 0xDA, 0xDC, 0x18, 0x1F, 0x19, 0x0A, 0x1E},
+ {0x09, 0xF8, 0xE6, 0x05, 0x19, 0x11, 0x0E, 0x0B},
+ {0x09, 0x10, 0x0E, 0xE6, 0xF4, 0x20, 0x22, 0xFA},
+ {0xF2, 0xE5, 0xF8, 0x0E, 0x18, 0x15, 0x0D, 0x10},
+ {0x15, 0x13, 0x16, 0x0A, 0x0D, 0x1F, 0x1D, 0x1B},
+ {0xFA, 0xFF, 0xFE, 0xFF, 0x09, 0x11, 0x03, 0x0B},
+ {0xFE, 0xFA, 0xF2, 0xF8, 0x0C, 0x1E, 0x11, 0x12},
+ {0xFA, 0xF8, 0x0B, 0x17, 0x1D, 0x17, 0x0E, 0x16},
+ {0x00, 0xF3, 0xFD, 0x0A, 0x1C, 0x17, 0xFD, 0x08},
+ {0xEA, 0xEA, 0x03, 0x12, 0x1E, 0x14, 0x09, 0x04},
+ {0x02, 0xFE, 0x04, 0xFB, 0x0C, 0x0E, 0x07, 0x02},
+ {0xF6, 0x02, 0x07, 0x0B, 0x17, 0x17, 0x01, 0xFF},
+ {0xF5, 0xFB, 0xFE, 0x04, 0x12, 0x14, 0x0C, 0x0D},
+ {0x10, 0x10, 0x0E, 0x04, 0x07, 0x11, 0x0F, 0x13},
+ {0x0C, 0x0F, 0xFB, 0xF2, 0x0A, 0x12, 0x09, 0x0D},
+ {0x0D, 0x1D, 0xF1, 0xF4, 0x2A, 0x06, 0x3B, 0x32},
+ {0xFC, 0x08, 0x06, 0x02, 0x0E, 0x17, 0x08, 0x0E},
+ {0x07, 0x02, 0xEE, 0xEE, 0x2B, 0xF6, 0x23, 0x13},
+ {0x04, 0x02, 0x05, 0x08, 0x0B, 0x0E, 0xFB, 0xFB},
+ {0x00, 0x04, 0x10, 0x18, 0x22, 0x25, 0x1D, 0x1F},
+ {0xFB, 0x0D, 0x07, 0x00, 0x0C, 0x0F, 0xFC, 0x02},
+ {0x00, 0x00, 0x00, 0x01, 0x05, 0x07, 0x03, 0x05},
+ {0x04, 0x05, 0x08, 0x13, 0xFF, 0xEB, 0x0C, 0x06},
+ {0x05, 0x13, 0x0E, 0x0B, 0x12, 0x15, 0x09, 0x0A},
+ {0x09, 0x03, 0x09, 0x05, 0x12, 0x16, 0x11, 0x12},
+ {0x14, 0x1A, 0x06, 0x01, 0x10, 0x11, 0xFE, 0x02},
+ {0x01, 0x0B, 0x0B, 0x0C, 0x18, 0x21, 0x10, 0x13},
+ {0x12, 0x0D, 0x0A, 0x10, 0x1C, 0x1D, 0x0D, 0x10},
+ {0x03, 0x09, 0x14, 0x15, 0x1B, 0x1A, 0x01, 0xFF},
+ {0x08, 0x12, 0x13, 0x0E, 0x16, 0x1D, 0x14, 0x1B},
+ {0x07, 0x15, 0x1C, 0x1B, 0x20, 0x21, 0x11, 0x0E},
+ {0x12, 0x18, 0x19, 0x17, 0x20, 0x25, 0x1A, 0x1E},
+ {0x0C, 0x1A, 0x1D, 0x22, 0x2F, 0x33, 0x27, 0x28},
+ {0x0E, 0x1A, 0x17, 0x10, 0x0A, 0x0E, 0xFF, 0x06},
+ {0x1A, 0x1C, 0x18, 0x14, 0x1A, 0x16, 0x0A, 0x0E},
+ {0x1E, 0x27, 0x25, 0x26, 0x27, 0x2A, 0x21, 0x21},
+ {0xF1, 0x0A, 0x16, 0x1C, 0x28, 0x25, 0x15, 0x19},
+ {0x08, 0x12, 0x09, 0x08, 0x16, 0x17, 0xEF, 0xF6},
+ {0x0C, 0x0B, 0x00, 0xFC, 0x04, 0x09, 0xFC, 0x03},
+ {0xFB, 0xF1, 0xF8, 0x26, 0x24, 0x18, 0x1D, 0x20},
+ {0xF9, 0x01, 0x0C, 0x0F, 0x07, 0x08, 0x06, 0x07},
+ {0x07, 0x06, 0x08, 0x04, 0x07, 0x0D, 0x07, 0x09},
+ {0xFE, 0x01, 0x06, 0x05, 0x13, 0x1B, 0x14, 0x19},
+ {0x09, 0x0C, 0x0E, 0x01, 0x08, 0x05, 0xFB, 0xFD},
+ {0x07, 0x06, 0x03, 0x0A, 0x16, 0x12, 0x04, 0x07},
+ {0x04, 0x01, 0x00, 0x04, 0x1F, 0x20, 0x0E, 0x0A},
+ {0x03, 0xFF, 0xF6, 0xFB, 0x15, 0x1A, 0x00, 0x03},
+ {0xFC, 0x18, 0x0B, 0x2D, 0x35, 0x23, 0x12, 0x09},
+ {0x02, 0xFE, 0x01, 0xFF, 0x0C, 0x11, 0x0D, 0x0F},
+ {0xFA, 0xE9, 0xD9, 0xFF, 0x0D, 0x05, 0x0D, 0x10},
+ {0xF1, 0xE0, 0xF0, 0x01, 0x06, 0x06, 0x06, 0x10},
+ {0xE9, 0xD4, 0xD7, 0x0F, 0x14, 0x0B, 0x0D, 0x16},
+ {0x00, 0xFF, 0xEE, 0xE5, 0xFF, 0x08, 0x02, 0xF9},
+ {0xE0, 0xDA, 0xE5, 0xFE, 0x09, 0x02, 0xF9, 0x04},
+ {0xE0, 0xE2, 0xF4, 0x09, 0x13, 0x0C, 0x0D, 0x09},
+ {0xFC, 0x02, 0x04, 0xFF, 0x00, 0xFF, 0xF8, 0xF7},
+ {0xFE, 0xFB, 0xED, 0xF2, 0xFE, 0xFE, 0x08, 0x0C},
+ {0xF3, 0xEF, 0xD0, 0xE3, 0x05, 0x11, 0xFD, 0xFF},
+ {0xFA, 0xEF, 0xEA, 0xFE, 0x0D, 0x0E, 0xFE, 0x02},
+ {0xF7, 0xFB, 0xDB, 0xDF, 0x14, 0xDD, 0x07, 0xFE},
+ {0xFE, 0x08, 0x00, 0xDB, 0xE5, 0x1A, 0x13, 0xED},
+ {0xF9, 0xFE, 0xFF, 0xF4, 0xF3, 0x00, 0x05, 0x02},
+ {0xEF, 0xDE, 0xD8, 0xEB, 0xEA, 0xF5, 0x0E, 0x19},
+ {0xFB, 0xFC, 0xFA, 0xEC, 0xEB, 0xED, 0xEE, 0xE8},
+ {0xEE, 0xFC, 0xFD, 0x00, 0x04, 0xFC, 0xF0, 0xF5},
+ {0x00, 0xFA, 0xF4, 0xF1, 0xF5, 0xFA, 0xFB, 0xF9},
+ {0xEB, 0xF0, 0xDF, 0xE3, 0xEF, 0x07, 0x02, 0x05},
+ {0xF7, 0xF0, 0xE6, 0xE7, 0x06, 0x15, 0x06, 0x0C},
+ {0xF1, 0xE4, 0xD8, 0xEA, 0x06, 0xF2, 0x07, 0x09},
+ {0xFF, 0xFE, 0xFE, 0xF9, 0xFF, 0xFF, 0x02, 0xF9},
+ {0xDD, 0xF4, 0xF0, 0xF1, 0xFF, 0xFF, 0xEA, 0xF1},
+ {0xF0, 0xF1, 0xFD, 0x03, 0x03, 0xFE, 0x00, 0x05},
+ {0xF1, 0xF6, 0xE0, 0xDF, 0xF5, 0x01, 0xF4, 0xF8},
+ {0x02, 0x03, 0xE5, 0xDC, 0xE7, 0xFD, 0x02, 0x08},
+ {0xEC, 0xF1, 0xF5, 0xEC, 0xF2, 0xF8, 0xF6, 0xEE},
+ {0xF3, 0xF4, 0xF6, 0xF4, 0xF5, 0xF1, 0xE7, 0xEA},
+ {0xF7, 0xF3, 0xEC, 0xEA, 0xEF, 0xF0, 0xEE, 0xF1},
+ {0xEB, 0xF6, 0xFB, 0xFA, 0xEF, 0xF3, 0xF3, 0xF7},
+ {0x01, 0x03, 0xF1, 0xF6, 0x05, 0xF8, 0xE1, 0xEB},
+ {0xF5, 0xF6, 0xF6, 0xF4, 0xFB, 0xFB, 0xFF, 0x00},
+ {0xF8, 0x01, 0xFB, 0xFA, 0xFF, 0x03, 0xFE, 0x04},
+ {0x04, 0xFB, 0x03, 0xFD, 0xF5, 0xF7, 0xF6, 0xFB},
+ {0x06, 0x09, 0xFB, 0xF4, 0xF9, 0xFA, 0xFC, 0xFF},
+ {0xF5, 0xF6, 0xF1, 0xEE, 0xF5, 0xF8, 0xF5, 0xF9},
+ {0xF5, 0xF9, 0xFA, 0xFC, 0x07, 0x09, 0x01, 0xFB},
+ {0xD7, 0xE9, 0xE8, 0xEC, 0x00, 0x0C, 0xFE, 0xF1},
+ {0xEC, 0x04, 0xE9, 0xDF, 0x03, 0xE8, 0x00, 0xFA},
+ {0xE6, 0xE2, 0xFF, 0x0A, 0x13, 0x01, 0x00, 0xF7},
+ {0xF1, 0xFA, 0xF7, 0xF5, 0x01, 0x06, 0x05, 0x0A},
+ {0xF6, 0xF6, 0xFC, 0xF6, 0xE8, 0x11, 0xF2, 0xFE},
+ {0xFE, 0x08, 0x05, 0x12, 0xFD, 0xD0, 0x0E, 0x07},
+ {0xF1, 0xFE, 0xF7, 0xF2, 0xFB, 0x02, 0xFA, 0xF8},
+ {0xF4, 0xEA, 0xEC, 0xF3, 0xFE, 0x01, 0xF7, 0xF6},
+ {0xFF, 0xFA, 0xFB, 0xF9, 0xFF, 0x01, 0x04, 0x03},
+ {0x00, 0xF9, 0xF4, 0xFC, 0x05, 0xFC, 0xF7, 0xFB},
+ {0xF8, 0xFF, 0xEF, 0xEC, 0xFB, 0x04, 0xF8, 0x03},
+ {0xEB, 0xF1, 0xED, 0xF4, 0x02, 0x0E, 0x0B, 0x04},
+ {0xF7, 0x01, 0xF8, 0xF4, 0xF8, 0xEF, 0xF8, 0x04},
+ {0xEB, 0xF0, 0xF7, 0xFC, 0x10, 0x0D, 0xF8, 0xF8},
+ {0xE8, 0xFE, 0xEE, 0xE8, 0xED, 0xF7, 0xF5, 0xF8},
+ {0xED, 0xEB, 0xE9, 0xEA, 0xF2, 0xF5, 0xF4, 0xF9},
+ {0xEA, 0xF2, 0xEF, 0xEE, 0xF9, 0xFE, 0xFD, 0x02},
+ {0xFA, 0xFD, 0x02, 0x0D, 0xFA, 0xE4, 0x0F, 0x01},
+ {0xFF, 0x08, 0x05, 0xF6, 0xF7, 0xFB, 0xF1, 0xF1},
+ {0xF4, 0xEC, 0xEE, 0xF6, 0xEE, 0xEE, 0xF8, 0x06},
+ {0xE8, 0xFA, 0xF8, 0xE8, 0xF8, 0xE9, 0xEE, 0xF9},
+ {0xE5, 0xE9, 0xF0, 0x00, 0x00, 0xEF, 0xF3, 0xF8},
+ {0xF7, 0xFB, 0xFB, 0xF7, 0xF9, 0xF9, 0xF5, 0xF0},
+ {0xFD, 0xFF, 0xF2, 0xEE, 0xF2, 0xF5, 0xF1, 0xF3}};
+
+static const UCHAR g_3a_pvcTab1_mode2[PVC_NTAB1][PVC_NBLOW][PVC_NBHIGH_MODE2] =
+ {{{0x11, 0x27, 0x0F, 0xFD, 0x04, 0xFC},
+ {0x00, 0xBE, 0xE3, 0xF4, 0xDB, 0xF0},
+ {0x09, 0x1E, 0x18, 0x1A, 0x21, 0x1B}},
+ {{0x16, 0x28, 0x2B, 0x29, 0x25, 0x32},
+ {0xF2, 0xE9, 0xE4, 0xE5, 0xE2, 0xD4},
+ {0x0E, 0x0B, 0x0C, 0x0D, 0x0D, 0x0E}},
+ {{0x2E, 0x3C, 0x20, 0x16, 0x1B, 0x1A},
+ {0xE4, 0xC6, 0xE5, 0xF4, 0xDC, 0xDC},
+ {0x0F, 0x1B, 0x18, 0x14, 0x1E, 0x1A}}};
+
+static const UCHAR g_2a_pvcTab2_mode2[PVC_NTAB2][PVC_NBHIGH_MODE2] = {
+ {0x26, 0x25, 0x11, 0x0C, 0xFA, 0x15}, {0x1B, 0x18, 0x11, 0x0E, 0x0E, 0x0E},
+ {0x12, 0x10, 0x10, 0x10, 0x11, 0x10}, {0x1E, 0x24, 0x19, 0x15, 0x14, 0x12},
+ {0x24, 0x16, 0x12, 0x13, 0x15, 0x1C}, {0xEA, 0xED, 0xEB, 0xEA, 0xEC, 0xEB},
+ {0xFC, 0xFD, 0xFD, 0xFC, 0xFE, 0xFE}, {0x0F, 0x0C, 0x0B, 0x0A, 0x0B, 0x0B},
+ {0x22, 0x0B, 0x16, 0x18, 0x13, 0x19}, {0x1C, 0x14, 0x1D, 0x20, 0x19, 0x1A},
+ {0x10, 0x08, 0x00, 0xFF, 0x02, 0x05}, {0x06, 0x07, 0x05, 0x03, 0x05, 0x04},
+ {0x2A, 0x1F, 0x12, 0x12, 0x11, 0x18}, {0x19, 0x19, 0x02, 0x04, 0x00, 0x04},
+ {0x18, 0x17, 0x17, 0x15, 0x16, 0x15}, {0x21, 0x1E, 0x1B, 0x19, 0x1C, 0x1B},
+ {0x3C, 0x35, 0x20, 0x1D, 0x30, 0x34}, {0x3A, 0x1F, 0x37, 0x38, 0x33, 0x31},
+ {0x37, 0x34, 0x25, 0x27, 0x35, 0x34}, {0x34, 0x2E, 0x32, 0x31, 0x34, 0x31},
+ {0x36, 0x33, 0x2F, 0x2F, 0x32, 0x2F}, {0x35, 0x20, 0x2F, 0x32, 0x2F, 0x2C},
+ {0x2E, 0x2B, 0x2F, 0x34, 0x36, 0x30}, {0x3F, 0x39, 0x30, 0x28, 0x29, 0x29},
+ {0x3C, 0x30, 0x32, 0x37, 0x39, 0x36}, {0x37, 0x36, 0x30, 0x2B, 0x26, 0x24},
+ {0x44, 0x38, 0x2F, 0x2D, 0x2D, 0x2D}, {0x38, 0x2B, 0x2C, 0x2C, 0x30, 0x2D},
+ {0x37, 0x36, 0x2F, 0x23, 0x2D, 0x32}, {0x3C, 0x39, 0x29, 0x2E, 0x38, 0x37},
+ {0x3B, 0x3A, 0x35, 0x32, 0x31, 0x2D}, {0x32, 0x31, 0x2F, 0x2C, 0x2D, 0x28},
+ {0x2C, 0x31, 0x32, 0x30, 0x32, 0x2D}, {0x35, 0x34, 0x34, 0x34, 0x35, 0x33},
+ {0x34, 0x38, 0x3B, 0x3C, 0x3E, 0x3A}, {0x3E, 0x3C, 0x3B, 0x3A, 0x3C, 0x39},
+ {0x3D, 0x41, 0x46, 0x41, 0x3D, 0x38}, {0x44, 0x41, 0x40, 0x3E, 0x3F, 0x3A},
+ {0x47, 0x47, 0x47, 0x42, 0x44, 0x40}, {0x4C, 0x4A, 0x4A, 0x46, 0x49, 0x45},
+ {0x53, 0x52, 0x52, 0x4C, 0x4E, 0x49}, {0x41, 0x3D, 0x39, 0x2C, 0x2E, 0x2E},
+ {0x2D, 0x37, 0x36, 0x30, 0x28, 0x36}, {0x3B, 0x32, 0x2E, 0x2D, 0x2D, 0x29},
+ {0x40, 0x39, 0x36, 0x35, 0x36, 0x32}, {0x30, 0x2D, 0x2D, 0x2E, 0x31, 0x30},
+ {0x38, 0x3D, 0x3B, 0x37, 0x35, 0x34}, {0x44, 0x3D, 0x3C, 0x38, 0x37, 0x33},
+ {0x3A, 0x36, 0x37, 0x37, 0x39, 0x36}, {0x32, 0x36, 0x37, 0x30, 0x2E, 0x2A},
+ {0x3C, 0x33, 0x33, 0x31, 0x33, 0x30}, {0x30, 0x31, 0x36, 0x37, 0x38, 0x34},
+ {0x26, 0x27, 0x2E, 0x29, 0x1C, 0x16}, {0x14, 0x15, 0x1F, 0x17, 0x15, 0x1C},
+ {0x38, 0x2D, 0x18, 0x13, 0x1E, 0x2B}, {0x30, 0x22, 0x17, 0x1A, 0x26, 0x2B},
+ {0x24, 0x20, 0x1F, 0x10, 0x0C, 0x11}, {0x27, 0x1F, 0x13, 0x17, 0x24, 0x2A},
+ {0x2F, 0x13, 0x18, 0x13, 0x2A, 0x32}, {0x31, 0x1E, 0x1E, 0x1E, 0x21, 0x28},
+ {0x2A, 0x12, 0x19, 0x17, 0x16, 0x24}, {0x27, 0x0F, 0x16, 0x1D, 0x17, 0x1C},
+ {0x2F, 0x26, 0x25, 0x22, 0x20, 0x22}, {0x1E, 0x1B, 0x1E, 0x18, 0x1E, 0x24},
+ {0x31, 0x26, 0x0E, 0x15, 0x15, 0x25}, {0x2D, 0x22, 0x1E, 0x14, 0x10, 0x22},
+ {0x25, 0x1B, 0x18, 0x11, 0x13, 0x1F}, {0x2F, 0x1B, 0x13, 0x1B, 0x18, 0x22},
+ {0x21, 0x24, 0x1D, 0x1C, 0x1D, 0x1B}, {0x23, 0x1E, 0x28, 0x29, 0x27, 0x25},
+ {0x2E, 0x2A, 0x1D, 0x17, 0x26, 0x2D}, {0x31, 0x2C, 0x1A, 0x0E, 0x1A, 0x24},
+ {0x26, 0x16, 0x20, 0x1D, 0x14, 0x1E}, {0x29, 0x20, 0x1B, 0x1B, 0x17, 0x17},
+ {0x1D, 0x06, 0x1A, 0x1E, 0x1B, 0x1D}, {0x2B, 0x23, 0x1F, 0x1F, 0x1D, 0x1C},
+ {0x27, 0x1A, 0x0C, 0x0E, 0x0F, 0x1A}, {0x29, 0x1D, 0x1E, 0x22, 0x22, 0x24},
+ {0x20, 0x21, 0x1B, 0x18, 0x13, 0x21}, {0x27, 0x0E, 0x10, 0x14, 0x10, 0x1A},
+ {0x26, 0x24, 0x25, 0x25, 0x26, 0x28}, {0x1A, 0x24, 0x25, 0x29, 0x26, 0x24},
+ {0x1D, 0x1D, 0x15, 0x12, 0x0F, 0x18}, {0x1E, 0x14, 0x13, 0x12, 0x14, 0x18},
+ {0x16, 0x13, 0x13, 0x1A, 0x1B, 0x1D}, {0x20, 0x27, 0x22, 0x24, 0x1A, 0x19},
+ {0x1F, 0x17, 0x19, 0x18, 0x17, 0x18}, {0x20, 0x1B, 0x1C, 0x1C, 0x1B, 0x1A},
+ {0x23, 0x19, 0x1D, 0x1F, 0x1E, 0x21}, {0x26, 0x1F, 0x1D, 0x1B, 0x19, 0x1A},
+ {0x23, 0x1E, 0x1F, 0x20, 0x1F, 0x1E}, {0x29, 0x20, 0x22, 0x20, 0x20, 0x1F},
+ {0x26, 0x23, 0x21, 0x22, 0x23, 0x23}, {0x29, 0x1F, 0x24, 0x25, 0x26, 0x29},
+ {0x2B, 0x22, 0x25, 0x27, 0x23, 0x21}, {0x29, 0x21, 0x19, 0x0E, 0x22, 0x2D},
+ {0x32, 0x29, 0x1F, 0x1C, 0x1B, 0x21}, {0x1E, 0x1A, 0x1E, 0x24, 0x25, 0x25},
+ {0x24, 0x1D, 0x21, 0x22, 0x22, 0x25}, {0x2C, 0x25, 0x21, 0x22, 0x23, 0x25},
+ {0x24, 0x1E, 0x21, 0x26, 0x2B, 0x2C}, {0x28, 0x24, 0x1B, 0x1F, 0x28, 0x2D},
+ {0x23, 0x13, 0x16, 0x22, 0x22, 0x29}, {0x1B, 0x23, 0x1C, 0x20, 0x14, 0x0D},
+ {0x1E, 0x16, 0x1A, 0x1E, 0x1C, 0x1D}, {0x2B, 0x1C, 0x1D, 0x20, 0x1B, 0x1C},
+ {0x1C, 0x1B, 0x23, 0x1F, 0x19, 0x1E}, {0x21, 0x23, 0x26, 0x20, 0x20, 0x22},
+ {0x1D, 0x0B, 0x19, 0x1E, 0x11, 0x19}, {0x18, 0x17, 0x16, 0x17, 0x14, 0x16},
+ {0x16, 0x19, 0x1C, 0x20, 0x21, 0x22}, {0x30, 0x1E, 0x22, 0x24, 0x25, 0x26},
+ {0x1B, 0x1F, 0x17, 0x1D, 0x1E, 0x21}, {0x32, 0x2B, 0x27, 0x1F, 0x1B, 0x1A},
+ {0x28, 0x20, 0x1A, 0x1B, 0x1F, 0x23}, {0x32, 0x21, 0x20, 0x21, 0x1D, 0x1F},
+ {0x22, 0x18, 0x12, 0x15, 0x1B, 0x20}, {0x27, 0x27, 0x2A, 0x24, 0x21, 0x21},
+ {0x1E, 0x0F, 0x0D, 0x1A, 0x1D, 0x23}, {0x28, 0x25, 0x27, 0x21, 0x17, 0x25},
+ {0x2B, 0x27, 0x23, 0x19, 0x13, 0x14}, {0x25, 0x2B, 0x22, 0x22, 0x20, 0x21},
+ {0x27, 0x1B, 0x16, 0x17, 0x0F, 0x15}, {0x29, 0x26, 0x23, 0x15, 0x1E, 0x28},
+ {0x24, 0x1C, 0x19, 0x1A, 0x18, 0x19}, {0x2D, 0x15, 0x27, 0x2B, 0x24, 0x23},
+ {0x2C, 0x12, 0x1F, 0x23, 0x1F, 0x20}, {0x25, 0x0F, 0x22, 0x27, 0x1F, 0x21}};
+
+static const UCHAR g_a_pvcTab1_dp_mode1[PVC_NTAB1 - 1] = {17, 68};
+static const UCHAR g_a_pvcTab1_dp_mode2[PVC_NTAB1 - 1] = {16, 52};
+/* fractional exponent which corresponds to Q representation value */
+static const SCHAR g_a_scalingCoef_mode1[PVC_NBLOW + 1] = {
+ -1, -1, 0, 6}; /* { 8, 8, 7, 1 }; Q scaling */
+static const SCHAR g_a_scalingCoef_mode2[PVC_NBLOW + 1] = {
+ 0, 0, 1, 7}; /* { 7, 7, 6, 0 }; Q scaling */
+
+int pvcInitFrame(PVC_STATIC_DATA *pPvcStaticData,
+ PVC_DYNAMIC_DATA *pPvcDynamicData, const UCHAR pvcMode,
+ const UCHAR ns, const int RATE, const int kx,
+ const int pvcBorder0, const UCHAR *pPvcID) {
+ int lbw, hbw, i, temp;
+ pPvcDynamicData->pvc_mode = pvcMode;
+ pPvcDynamicData->kx = kx;
+ pPvcDynamicData->RATE = RATE;
+
+ switch (pvcMode) {
+ case 0:
+ /* legacy SBR, nothing to do */
+ return 0;
+ case 1:
+ pPvcDynamicData->nbHigh = 8;
+ pPvcDynamicData->pPVCTab1 = (const UCHAR *)g_3a_pvcTab1_mode1;
+ pPvcDynamicData->pPVCTab2 = (const UCHAR *)g_2a_pvcTab2_mode1;
+ pPvcDynamicData->pPVCTab1_dp = g_a_pvcTab1_dp_mode1;
+ pPvcDynamicData->pScalingCoef = g_a_scalingCoef_mode1;
+ hbw = 8 / RATE;
+ break;
+ case 2:
+ pPvcDynamicData->nbHigh = 6;
+ pPvcDynamicData->pPVCTab1 = (const UCHAR *)g_3a_pvcTab1_mode2;
+ pPvcDynamicData->pPVCTab2 = (const UCHAR *)g_2a_pvcTab2_mode2;
+ pPvcDynamicData->pPVCTab1_dp = g_a_pvcTab1_dp_mode2;
+ pPvcDynamicData->pScalingCoef = g_a_scalingCoef_mode2;
+ hbw = 12 / RATE;
+ break;
+ default:
+ /* invalid pvcMode */
+ return 1;
+ }
+
+ pPvcDynamicData->pvcBorder0 = pvcBorder0;
+ UCHAR pvcBorder0_last = pPvcStaticData->pvcBorder0;
+ pPvcStaticData->pvcBorder0 = pvcBorder0;
+ pPvcDynamicData->pPvcID = pPvcID;
+
+ pPvcDynamicData->ns = ns;
+ switch (ns) {
+ case 16:
+ pPvcDynamicData->pSCcoeffs = pvc_SC_16;
+ break;
+ case 12:
+ pPvcDynamicData->pSCcoeffs = pvc_SC_12;
+ break;
+ case 4:
+ pPvcDynamicData->pSCcoeffs = pvc_SC_4;
+ break;
+ case 3:
+ pPvcDynamicData->pSCcoeffs = pvc_SC_3;
+ break;
+ default:
+ return 1;
+ }
+
+ /* in the lower part of Esg-array there are previous values of Esg (from last
+ call to this function In case of an previous legay-SBR frame, or if there
+ was a change in cross-over FQ the value of first PVC SBR timeslot is
+ propagated to prev-values in order to have reasonable values for
+ smooth-filtering
+ */
+ if ((pPvcStaticData->pvc_mode_last == 0) || (pPvcStaticData->kx_last != kx)) {
+ pPvcDynamicData->pastEsgSlotsAvail = 0;
+ } else {
+ pPvcDynamicData->pastEsgSlotsAvail = PVC_NS_MAX - pvcBorder0_last;
+ }
+
+ lbw = 8 / RATE;
+
+ temp = kx;
+ for (i = PVC_NBLOW; i >= 0; i--) {
+ pPvcDynamicData->sg_offset_low[i] = temp;
+ temp -= lbw;
+ }
+
+ temp = 0;
+ for (i = 0; i <= pPvcDynamicData->nbHigh; i++) {
+ pPvcDynamicData->sg_offset_high_kx[i] = temp;
+ temp += hbw;
+ }
+
+ return 0;
+}
+
+/* call if pvcMode = 1,2 */
+void pvcDecodeFrame(PVC_STATIC_DATA *pPvcStaticData,
+ PVC_DYNAMIC_DATA *pPvcDynamicData, FIXP_DBL **qmfBufferReal,
+ FIXP_DBL **qmfBufferImag, const int overlap,
+ const int qmfExponentOverlap,
+ const int qmfExponentCurrent) {
+ int t;
+ FIXP_DBL *predictedEsgSlot;
+ int RATE = pPvcDynamicData->RATE;
+ int pvcBorder0 = pPvcDynamicData->pvcBorder0;
+
+ for (t = pvcBorder0; t < PVC_NTIMESLOT; t++) {
+ int *pPredEsg_exp = &pPvcDynamicData->predEsg_exp[t];
+ predictedEsgSlot = pPvcDynamicData->predEsg[t];
+
+ pvcDecodeTimeSlot(
+ pPvcStaticData, pPvcDynamicData, &qmfBufferReal[t * RATE],
+ &qmfBufferImag[t * RATE],
+ (t * RATE < overlap) ? qmfExponentOverlap : qmfExponentCurrent,
+ pvcBorder0, t, predictedEsgSlot, pPredEsg_exp);
+ }
+
+ return;
+}
+
+void pvcDecodeTimeSlot(PVC_STATIC_DATA *pPvcStaticData,
+ PVC_DYNAMIC_DATA *pPvcDynamicData,
+ FIXP_DBL **qmfSlotReal, FIXP_DBL **qmfSlotImag,
+ const int qmfExponent, const int pvcBorder0,
+ const int timeSlotNumber, FIXP_DBL predictedEsgSlot[],
+ int *predictedEsg_exp) {
+ int i, band, ksg, ksg_start = 0;
+ int RATE = pPvcDynamicData->RATE;
+ int Esg_index = pPvcStaticData->Esg_slot_index;
+ const SCHAR *sg_borders = pPvcDynamicData->sg_offset_low;
+ FIXP_DBL *pEsg = pPvcStaticData->Esg[Esg_index];
+ FIXP_DBL E[PVC_NBLOW] = {0};
+
+ /* Subband grouping in QMF subbands below SBR range */
+ /* Within one timeslot ( i = [0...(RATE-1)] QMF subsamples) calculate energy
+ E(ib,t) and group them to Esg(ksg,t). Then transfer values to logarithmical
+ domain and store them for time domain smoothing. (7.5.6.3 Subband grouping
+ in QMF subbands below SBR range)
+ */
+ for (ksg = 0; sg_borders[ksg] < 0; ksg++) {
+ pEsg[ksg] = FL2FXCONST_DBL(-10.0 / (1 << PVC_ESG_EXP)); /* 10*log10(0.1) */
+ ksg_start++;
+ }
+
+ for (i = 0; i < RATE; i++) {
+ FIXP_DBL *qmfR, *qmfI;
+ qmfR = qmfSlotReal[i];
+ qmfI = qmfSlotImag[i];
+ for (ksg = ksg_start; ksg < PVC_NBLOW; ksg++) {
+ for (band = sg_borders[ksg]; band < sg_borders[ksg + 1]; band++) {
+ /* The division by 8 == (RATE*lbw) is required algorithmically */
+ E[ksg] += (fPow2Div2(qmfR[band]) + fPow2Div2(qmfI[band])) >> 2;
+ }
+ }
+ }
+ for (ksg = ksg_start; ksg < PVC_NBLOW; ksg++) {
+ if (E[ksg] > (FIXP_DBL)0) {
+ /* 10/log2(10) = 0.752574989159953 * 2^2 */
+ int exp_log;
+ FIXP_DBL nrg = CalcLog2(E[ksg], 2 * qmfExponent, &exp_log);
+ nrg = fMult(nrg, FL2FXCONST_SGL(LOG10FAC));
+ nrg = scaleValue(nrg, exp_log - PVC_ESG_EXP + 2);
+ pEsg[ksg] = fMax(nrg, FL2FXCONST_DBL(-10.0 / (1 << PVC_ESG_EXP)));
+ } else {
+ pEsg[ksg] =
+ FL2FXCONST_DBL(-10.0 / (1 << PVC_ESG_EXP)); /* 10*log10(0.1) */
+ }
+ }
+
+ /* Time domain smoothing of subband-grouped energy */
+ {
+ int idx = pPvcStaticData->Esg_slot_index;
+ FIXP_DBL *pEsg_filt;
+ FIXP_SGL SCcoeff;
+
+ E[0] = E[1] = E[2] = (FIXP_DBL)0;
+ for (i = 0; i < pPvcDynamicData->ns; i++) {
+ SCcoeff = pPvcDynamicData->pSCcoeffs[i];
+ pEsg_filt = pPvcStaticData->Esg[idx];
+ /* Div2 is compensated by scaling of coeff table */
+ E[0] = fMultAddDiv2(E[0], pEsg_filt[0], SCcoeff);
+ E[1] = fMultAddDiv2(E[1], pEsg_filt[1], SCcoeff);
+ E[2] = fMultAddDiv2(E[2], pEsg_filt[2], SCcoeff);
+ if (i >= pPvcDynamicData->pastEsgSlotsAvail) {
+ /* if past Esg values are not available use the ones from the last valid
+ * slot */
+ continue;
+ }
+ if (idx > 0) {
+ idx--;
+ } else {
+ idx += PVC_NS_MAX - 1;
+ }
+ }
+ }
+
+ /* SBR envelope scalefactor prediction */
+ {
+ int E_high_exp[PVC_NBHIGH_MAX];
+ int E_high_exp_max = 0;
+ int pvcTab1ID;
+ int pvcTab2ID = (int)pPvcDynamicData->pPvcID[timeSlotNumber];
+ const UCHAR *pTab1, *pTab2;
+ if (pvcTab2ID < pPvcDynamicData->pPVCTab1_dp[0]) {
+ pvcTab1ID = 0;
+ } else if (pvcTab2ID < pPvcDynamicData->pPVCTab1_dp[1]) {
+ pvcTab1ID = 1;
+ } else {
+ pvcTab1ID = 2;
+ }
+ pTab1 = &(pPvcDynamicData
+ ->pPVCTab1[pvcTab1ID * PVC_NBLOW * pPvcDynamicData->nbHigh]);
+ pTab2 = &(pPvcDynamicData->pPVCTab2[pvcTab2ID * pPvcDynamicData->nbHigh]);
+ for (ksg = 0; ksg < pPvcDynamicData->nbHigh; ksg++) {
+ FIXP_SGL predCoeff;
+ FIXP_DBL accu;
+ int predCoeff_exp, kb;
+ E_high_exp[ksg] = 0;
+
+ /* residual part */
+ accu = ((LONG)(SCHAR)*pTab2++) << (DFRACT_BITS - 8 - PVC_ESG_EXP +
+ pPvcDynamicData->pScalingCoef[3]);
+
+ /* linear combination of lower grouped energies part */
+ for (kb = 0; kb < PVC_NBLOW; kb++) {
+ predCoeff = (FIXP_SGL)(
+ (SHORT)(SCHAR)pTab1[kb * pPvcDynamicData->nbHigh + ksg] << 8);
+ predCoeff_exp = pPvcDynamicData->pScalingCoef[kb] +
+ 1; /* +1 to compensate for Div2 */
+ accu += fMultDiv2(E[kb], predCoeff) << predCoeff_exp;
+ }
+ /* convert back to linear domain */
+ accu = fMult(accu, FL2FXCONST_SGL(LOG10FAC_INV));
+ accu = f2Pow(
+ accu, PVC_ESG_EXP - 1,
+ &predCoeff_exp); /* -1 compensates for exponent of LOG10FAC_INV */
+ predictedEsgSlot[ksg] = accu;
+ E_high_exp[ksg] = predCoeff_exp;
+ if (predCoeff_exp > E_high_exp_max) {
+ E_high_exp_max = predCoeff_exp;
+ }
+ }
+
+ /* rescale output vector according to largest exponent */
+ for (ksg = 0; ksg < pPvcDynamicData->nbHigh; ksg++) {
+ int scale = E_high_exp[ksg] - E_high_exp_max;
+ predictedEsgSlot[ksg] = scaleValue(predictedEsgSlot[ksg], scale);
+ }
+ *predictedEsg_exp = E_high_exp_max;
+ }
+
+ pPvcStaticData->Esg_slot_index =
+ (pPvcStaticData->Esg_slot_index + 1) & (PVC_NS_MAX - 1);
+ pPvcDynamicData->pastEsgSlotsAvail =
+ fMin(pPvcDynamicData->pastEsgSlotsAvail + 1, PVC_NS_MAX - 1);
+ return;
+}
+
+/* call if pvcMode = 0,1,2 */
+void pvcEndFrame(PVC_STATIC_DATA *pPvcStaticData,
+ PVC_DYNAMIC_DATA *pPvcDynamicData) {
+ pPvcStaticData->pvc_mode_last = pPvcDynamicData->pvc_mode;
+ pPvcStaticData->kx_last = pPvcDynamicData->kx;
+
+ if (pPvcDynamicData->pvc_mode == 0) return;
+
+ {
+ int t, max = -100;
+ for (t = pPvcDynamicData->pvcBorder0; t < PVC_NTIMESLOT; t++) {
+ if (pPvcDynamicData->predEsg_exp[t] > max) {
+ max = pPvcDynamicData->predEsg_exp[t];
+ }
+ }
+ pPvcDynamicData->predEsg_expMax = max;
+ }
+ return;
+}
+
+void expandPredEsg(const PVC_DYNAMIC_DATA *pPvcDynamicData, const int timeSlot,
+ const int lengthOutputVector, FIXP_DBL *pOutput,
+ SCHAR *pOutput_exp) {
+ int k = 0, ksg;
+ const FIXP_DBL *predEsg = pPvcDynamicData->predEsg[timeSlot];
+
+ for (ksg = 0; ksg < pPvcDynamicData->nbHigh; ksg++) {
+ for (; k < pPvcDynamicData->sg_offset_high_kx[ksg + 1]; k++) {
+ pOutput[k] = predEsg[ksg];
+ pOutput_exp[k] = (SCHAR)pPvcDynamicData->predEsg_exp[timeSlot];
+ }
+ }
+ ksg--;
+ for (; k < lengthOutputVector; k++) {
+ pOutput[k] = predEsg[ksg];
+ pOutput_exp[k] = (SCHAR)pPvcDynamicData->predEsg_exp[timeSlot];
+ }
+
+ return;
+}
diff --git a/fdk-aac/libSBRdec/src/pvc_dec.h b/fdk-aac/libSBRdec/src/pvc_dec.h
new file mode 100644
index 0000000..f5a467f
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/pvc_dec.h
@@ -0,0 +1,238 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s): Matthias Hildenbrand
+
+ Description: Decode Predictive Vector Coding Data
+
+*******************************************************************************/
+
+#ifndef PVC_DEC_H
+#define PVC_DEC_H
+
+#include "common_fix.h"
+
+#define PVC_DIVMODE_BITS 3
+#define PVC_REUSEPVCID_BITS 1
+#define PVC_PVCID_BITS 7
+#define PVC_GRIDINFO_BITS 1
+
+#define MAX_PVC_ENVELOPES 2
+#define PVC_NTIMESLOT 16
+#define PVC_NBLOW 3 /* max. number of grouped QMF subbands below SBR range */
+
+#define PVC_NBHIGH_MODE1 8
+#define PVC_NBHIGH_MODE2 6
+#define PVC_NBHIGH_MAX (PVC_NBHIGH_MODE1)
+#define PVC_NS_MAX 16
+
+/** Data for each PVC instance which needs to be persistent accross SBR frames
+ */
+typedef struct {
+ UCHAR kx_last; /**< Xover frequency of last frame */
+ UCHAR pvc_mode_last; /**< PVC mode of last frame */
+ UCHAR Esg_slot_index; /**< Ring buffer index to current Esg time slot */
+ UCHAR pvcBorder0; /**< Start SBR time slot of PVC frame */
+ FIXP_DBL Esg[PVC_NS_MAX][PVC_NBLOW]; /**< Esg(ksg,t) of current and 15
+ previous time slots (ring buffer) in
+ logarithmical domain */
+} PVC_STATIC_DATA;
+
+/** Data for each PVC instance which is valid during one SBR frame */
+typedef struct {
+ UCHAR pvc_mode; /**< PVC mode 1 or 2, 0 means legacy SBR */
+ UCHAR pvcBorder0; /**< Start SBR time slot of PVC frame */
+ UCHAR kx; /**< Index of the first QMF subband in the SBR range */
+ UCHAR RATE; /**< Number of QMF subband samples per time slot (2 or 4) */
+ UCHAR ns; /**< Number of time slots for time-domain smoothing of Esg(ksg,t) */
+ const UCHAR
+ *pPvcID; /**< Pointer to prediction coefficient matrix index table */
+ UCHAR pastEsgSlotsAvail; /**< Number of past Esg(ksg,t) which are available
+ for smoothing filter */
+ const FIXP_SGL *pSCcoeffs; /**< Pointer to smoothing window table */
+ SCHAR
+ sg_offset_low[PVC_NBLOW + 1]; /**< Offset table for PVC grouping of SBR
+ subbands below SBR range */
+ SCHAR sg_offset_high_kx[PVC_NBHIGH_MAX + 1]; /**< Offset table for PVC
+ grouping of SBR subbands in
+ SBR range (relativ to kx) */
+ UCHAR nbHigh; /**< Number of grouped QMF subbands in the SBR range */
+ const SCHAR *pScalingCoef; /**< Pointer to scaling coeff table */
+ const UCHAR *pPVCTab1; /**< PVC mode 1 table */
+ const UCHAR *pPVCTab2; /**< PVC mode 2 table */
+ const UCHAR *pPVCTab1_dp; /**< Mapping of pvcID to PVC mode 1 table */
+ FIXP_DBL predEsg[PVC_NTIMESLOT]
+ [PVC_NBHIGH_MAX]; /**< Predicted Energy in linear domain */
+ int predEsg_exp[PVC_NTIMESLOT]; /**< Exponent of predicted Energy in linear
+ domain */
+ int predEsg_expMax; /**< Maximum of predEsg_exp[] */
+} PVC_DYNAMIC_DATA;
+
+/**
+ * \brief Initialize PVC data structures for current frame (call if pvcMode =
+ * 0,1,2)
+ * \param[in] pPvcStaticData Pointer to PVC persistent data
+ * \param[out] pPvcDynamicData Pointer to PVC dynamic data
+ * \param[in] pvcMode PVC mode 1 or 2, 0 means legacy SBR
+ * \param[in] ns Number of time slots for time-domain smoothing of Esg(ksg,t)
+ * \param[in] RATE Number of QMF subband samples per time slot (2 or 4)
+ * \param[in] kx Index of the first QMF subband in the SBR range
+ * \param[in] pvcBorder0 Start SBR time slot of PVC frame
+ * \param[in] pPvcID Pointer to array of PvcIDs read from bitstream
+ */
+int pvcInitFrame(PVC_STATIC_DATA *pPvcStaticData,
+ PVC_DYNAMIC_DATA *pPvcDynamicData, const UCHAR pvcMode,
+ const UCHAR ns, const int RATE, const int kx,
+ const int pvcBorder0, const UCHAR *pPvcID);
+
+/**
+ * \brief Wrapper function for pvcDecodeTimeSlot() to decode PVC data of one
+ * frame (call if pvcMode = 1,2)
+ * \param[in,out] pPvcStaticData Pointer to PVC persistent data
+ * \param[in,out] pPvcDynamicData Pointer to PVC dynamic data
+ * \param[in] qmfBufferReal Pointer to array with real QMF subbands
+ * \param[in] qmfBufferImag Pointer to array with imag QMF subbands
+ * \param[in] overlap Number of QMF overlap slots
+ * \param[in] qmfExponentOverlap Exponent of qmfBuffer (low part) of overlap
+ * slots
+ * \param[in] qmfExponentCurrent Exponent of qmfBuffer (low part)
+ */
+void pvcDecodeFrame(PVC_STATIC_DATA *pPvcStaticData,
+ PVC_DYNAMIC_DATA *pPvcDynamicData, FIXP_DBL **qmfBufferReal,
+ FIXP_DBL **qmfBufferImag, const int overlap,
+ const int qmfExponentOverlap, const int qmfExponentCurrent);
+
+/**
+ * \brief Decode PVC data for one SBR time slot (call if pvcMode = 1,2)
+ * \param[in,out] pPvcStaticData Pointer to PVC persistent data
+ * \param[in,out] pPvcDynamicData Pointer to PVC dynamic data
+ * \param[in] qmfBufferReal Pointer to array with real QMF subbands
+ * \param[in] qmfBufferImag Pointer to array with imag QMF subbands
+ * \param[in] qmfExponent Exponent of qmfBuffer of current time slot
+ * \param[in] pvcBorder0 Start SBR time slot of PVC frame
+ * \param[in] timeSlotNumber Number of current SBR time slot (0..15)
+ * \param[out] predictedEsgSlot Predicted Energy of current time slot
+ * \param[out] predictedEsg_exp Exponent of predicted Energy of current time
+ * slot
+ */
+void pvcDecodeTimeSlot(PVC_STATIC_DATA *pPvcStaticData,
+ PVC_DYNAMIC_DATA *pPvcDynamicData,
+ FIXP_DBL **qmfSlotReal, FIXP_DBL **qmfSlotImag,
+ const int qmfExponent, const int pvcBorder0,
+ const int timeSlotNumber, FIXP_DBL predictedEsgSlot[],
+ int *predictedEsg_exp);
+
+/**
+ * \brief Finish the current PVC frame (call if pvcMode = 0,1,2)
+ * \param[in,out] pPvcStaticData Pointer to PVC persistent data
+ * \param[in,out] pPvcDynamicData Pointer to PVC dynamic data
+ */
+void pvcEndFrame(PVC_STATIC_DATA *pPvcStaticData,
+ PVC_DYNAMIC_DATA *pPvcDynamicData);
+
+/**
+ * \brief Expand predicted PVC grouped energies to full QMF subband resolution
+ * \param[in] pPvcDynamicData Pointer to PVC dynamic data
+ * \param[in] timeSlot Number of current SBR time slot (0..15)
+ * \param[in] lengthOutputVector Lenght of output vector
+ * \param[out] pOutput Output array for predicted energies
+ * \param[out] pOutput_exp Exponent of predicted energies
+ */
+void expandPredEsg(const PVC_DYNAMIC_DATA *pPvcDynamicData, const int timeSlot,
+ const int lengthOutputVector, FIXP_DBL *pOutput,
+ SCHAR *pOutput_exp);
+
+#endif /* PVC_DEC_H*/
diff --git a/fdk-aac/libSBRdec/src/sbr_crc.cpp b/fdk-aac/libSBRdec/src/sbr_crc.cpp
new file mode 100644
index 0000000..ba0fd05
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbr_crc.cpp
@@ -0,0 +1,192 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief CRC check coutines
+*/
+
+#include "sbr_crc.h"
+
+#include "FDK_bitstream.h"
+#include "transcendent.h"
+
+#define MAXCRCSTEP 16
+#define MAXCRCSTEP_LD 4
+
+/*!
+ \brief crc calculation
+*/
+static ULONG calcCRC(HANDLE_CRC hCrcBuf, ULONG bValue, int nBits) {
+ int i;
+ ULONG bMask = (1UL << (nBits - 1));
+
+ for (i = 0; i < nBits; i++, bMask >>= 1) {
+ USHORT flag = (hCrcBuf->crcState & hCrcBuf->crcMask) ? 1 : 0;
+ USHORT flag1 = (bMask & bValue) ? 1 : 0;
+
+ flag ^= flag1;
+ hCrcBuf->crcState <<= 1;
+ if (flag) hCrcBuf->crcState ^= hCrcBuf->crcPoly;
+ }
+
+ return (hCrcBuf->crcState);
+}
+
+/*!
+ \brief crc
+*/
+static int getCrc(HANDLE_FDK_BITSTREAM hBs, ULONG NrBits) {
+ int i;
+ CRC_BUFFER CrcBuf;
+
+ CrcBuf.crcState = SBR_CRC_START;
+ CrcBuf.crcPoly = SBR_CRC_POLY;
+ CrcBuf.crcMask = SBR_CRC_MASK;
+
+ int CrcStep = NrBits >> MAXCRCSTEP_LD;
+
+ int CrcNrBitsRest = (NrBits - CrcStep * MAXCRCSTEP);
+ ULONG bValue;
+
+ for (i = 0; i < CrcStep; i++) {
+ bValue = FDKreadBits(hBs, MAXCRCSTEP);
+ calcCRC(&CrcBuf, bValue, MAXCRCSTEP);
+ }
+
+ bValue = FDKreadBits(hBs, CrcNrBitsRest);
+ calcCRC(&CrcBuf, bValue, CrcNrBitsRest);
+
+ return (CrcBuf.crcState & SBR_CRC_RANGE);
+}
+
+/*!
+ \brief crc interface
+ \return 1: CRC OK, 0: CRC check failure
+*/
+int SbrCrcCheck(HANDLE_FDK_BITSTREAM hBs, /*!< handle to bit-buffer */
+ LONG NrBits) /*!< max. CRC length */
+{
+ int crcResult = 1;
+ ULONG NrCrcBits;
+ ULONG crcCheckResult;
+ LONG NrBitsAvailable;
+ ULONG crcCheckSum;
+
+ crcCheckSum = FDKreadBits(hBs, 10);
+
+ NrBitsAvailable = FDKgetValidBits(hBs);
+ if (NrBitsAvailable <= 0) {
+ return 0;
+ }
+
+ NrCrcBits = fixMin((INT)NrBits, (INT)NrBitsAvailable);
+
+ crcCheckResult = getCrc(hBs, NrCrcBits);
+ FDKpushBack(hBs, (NrBitsAvailable - FDKgetValidBits(hBs)));
+
+ if (crcCheckResult != crcCheckSum) {
+ crcResult = 0;
+ }
+
+ return (crcResult);
+}
diff --git a/fdk-aac/libSBRdec/src/sbr_crc.h b/fdk-aac/libSBRdec/src/sbr_crc.h
new file mode 100644
index 0000000..9633717
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbr_crc.h
@@ -0,0 +1,138 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief CRC checking routines
+*/
+#ifndef SBR_CRC_H
+#define SBR_CRC_H
+
+#include "sbrdecoder.h"
+
+#include "FDK_bitstream.h"
+
+/* some useful crc polynoms:
+
+crc5: x^5+x^4+x^2+x^1+1
+crc6: x^6+x^5+x^3+x^2+x+1
+crc7: x^7+x^6+x^2+1
+crc8: x^8+x^2+x+x+1
+*/
+
+/* default SBR CRC */ /* G(x) = x^10 + x^9 + x^5 + x^4 + x + 1 */
+#define SBR_CRC_POLY 0x0233
+#define SBR_CRC_MASK 0x0200
+#define SBR_CRC_START 0x0000
+#define SBR_CRC_RANGE 0x03FF
+
+typedef struct {
+ USHORT crcState;
+ USHORT crcMask;
+ USHORT crcPoly;
+} CRC_BUFFER;
+
+typedef CRC_BUFFER *HANDLE_CRC;
+
+int SbrCrcCheck(HANDLE_FDK_BITSTREAM hBitBuf, LONG NrCrcBits);
+
+#endif
diff --git a/fdk-aac/libSBRdec/src/sbr_deb.cpp b/fdk-aac/libSBRdec/src/sbr_deb.cpp
new file mode 100644
index 0000000..13cd211
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbr_deb.cpp
@@ -0,0 +1,108 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Print selected debug messages
+*/
+
+#include "sbr_deb.h"
diff --git a/fdk-aac/libSBRdec/src/sbr_deb.h b/fdk-aac/libSBRdec/src/sbr_deb.h
new file mode 100644
index 0000000..97d572a
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbr_deb.h
@@ -0,0 +1,113 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Debugging aids
+*/
+
+#ifndef SBR_DEB_H
+#define SBR_DEB_H
+
+#include "sbrdecoder.h"
+
+#endif
diff --git a/fdk-aac/libSBRdec/src/sbr_dec.cpp b/fdk-aac/libSBRdec/src/sbr_dec.cpp
new file mode 100644
index 0000000..30611e7
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbr_dec.cpp
@@ -0,0 +1,1480 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Sbr decoder
+ This module provides the actual decoder implementation. The SBR data (side
+ information) is already decoded. Only three functions are provided:
+
+ \li 1.) createSbrDec(): One time initialization
+ \li 2.) resetSbrDec(): Called by sbr_Apply() when the information contained in
+ an SBR_HEADER_ELEMENT requires a reset and recalculation of important SBR
+ structures. \li 3.) sbr_dec(): The actual decoder. Calls the different tools
+ such as filterbanks, lppTransposer(), and calculateSbrEnvelope() [the envelope
+ adjuster].
+
+ \sa sbr_dec(), \ref documentationOverview
+*/
+
+#include "sbr_dec.h"
+
+#include "sbr_ram.h"
+#include "env_extr.h"
+#include "env_calc.h"
+#include "scale.h"
+#include "FDK_matrixCalloc.h"
+#include "hbe.h"
+
+#include "genericStds.h"
+
+#include "sbrdec_drc.h"
+
+static void copyHarmonicSpectrum(int *xOverQmf, FIXP_DBL **qmfReal,
+ FIXP_DBL **qmfImag, int noCols, int overlap,
+ KEEP_STATES_SYNCED_MODE keepStatesSynced) {
+ int patchBands;
+ int patch, band, col, target, sourceBands, i;
+ int numPatches = 0;
+ int slotOffset = 0;
+
+ FIXP_DBL **ppqmfReal = qmfReal + overlap;
+ FIXP_DBL **ppqmfImag = qmfImag + overlap;
+
+ if (keepStatesSynced == KEEP_STATES_SYNCED_NORMAL) {
+ slotOffset = noCols - overlap - LPC_ORDER;
+ }
+
+ if (keepStatesSynced == KEEP_STATES_SYNCED_OUTDIFF) {
+ ppqmfReal = qmfReal;
+ ppqmfImag = qmfImag;
+ }
+
+ for (i = 1; i < MAX_NUM_PATCHES; i++) {
+ if (xOverQmf[i] != 0) {
+ numPatches++;
+ }
+ }
+
+ for (patch = (MAX_STRETCH_HBE - 1); patch < numPatches; patch++) {
+ patchBands = xOverQmf[patch + 1] - xOverQmf[patch];
+ target = xOverQmf[patch];
+ sourceBands = xOverQmf[MAX_STRETCH_HBE - 1] - xOverQmf[MAX_STRETCH_HBE - 2];
+
+ while (patchBands > 0) {
+ int numBands = sourceBands;
+ int startBand = xOverQmf[MAX_STRETCH_HBE - 1] - 1;
+ if (target + numBands >= xOverQmf[patch + 1]) {
+ numBands = xOverQmf[patch + 1] - target;
+ }
+ if ((((target + numBands - 1) % 2) +
+ ((xOverQmf[MAX_STRETCH_HBE - 1] - 1) % 2)) %
+ 2) {
+ if (numBands == sourceBands) {
+ numBands--;
+ } else {
+ startBand--;
+ }
+ }
+ if (keepStatesSynced == KEEP_STATES_SYNCED_OUTDIFF) {
+ for (col = slotOffset; col < overlap + LPC_ORDER; col++) {
+ i = 0;
+ for (band = numBands; band > 0; band--) {
+ if ((target + band - 1 < 64) &&
+ (target + band - 1 < xOverQmf[patch + 1])) {
+ ppqmfReal[col][target + band - 1] = ppqmfReal[col][startBand - i];
+ ppqmfImag[col][target + band - 1] = ppqmfImag[col][startBand - i];
+ i++;
+ }
+ }
+ }
+ } else {
+ for (col = slotOffset; col < noCols; col++) {
+ i = 0;
+ for (band = numBands; band > 0; band--) {
+ if ((target + band - 1 < 64) &&
+ (target + band - 1 < xOverQmf[patch + 1])) {
+ ppqmfReal[col][target + band - 1] = ppqmfReal[col][startBand - i];
+ ppqmfImag[col][target + band - 1] = ppqmfImag[col][startBand - i];
+ i++;
+ }
+ }
+ }
+ }
+ target += numBands;
+ patchBands -= numBands;
+ }
+ }
+}
+
+/*!
+ \brief SBR decoder core function for one channel
+
+ \image html BufferMgmtDetailed-1632.png
+
+ Besides the filter states of the QMF filter bank and the LPC-states of
+ the LPP-Transposer, processing is mainly based on four buffers:
+ #timeIn, #timeOut, #WorkBuffer2 and #OverlapBuffer. The #WorkBuffer2
+ is reused for all channels and might be used by the core decoder, a
+ static overlap buffer is required for each channel. Due to in-place
+ processing, #timeIn and #timeOut point to identical locations.
+
+ The spectral data is organized in so-called slots. Each slot
+ contains 64 bands of complex data. The number of slots per frame
+ depends on the frame size. For mp3PRO, there are 18 slots per frame
+ and 6 slots per #OverlapBuffer. It is not necessary to have the slots
+ in located consecutive address ranges.
+
+ To optimize memory usage and to minimize the number of memory
+ accesses, the memory management is organized as follows (slot numbers
+ based on mp3PRO):
+
+ 1.) Input time domain signal is located in #timeIn. The last slots
+ (0..5) of the spectral data of the previous frame are located in the
+ #OverlapBuffer. In addition, #frameData of the current frame resides
+ in the upper part of #timeIn.
+
+ 2.) During the cplxAnalysisQmfFiltering(), 32 samples from #timeIn are
+ transformed into a slot of up to 32 complex spectral low band values at a
+ time. The first spectral slot -- nr. 6 -- is written at slot number
+ zero of #WorkBuffer2. #WorkBuffer2 will be completely filled with
+ spectral data.
+
+ 3.) LPP-Transposition in lppTransposer() is processed on 24 slots. During the
+ transposition, the high band part of the spectral data is replicated
+ based on the low band data.
+
+ Envelope Adjustment is processed on the high band part of the spectral
+ data only by calculateSbrEnvelope().
+
+ 4.) The cplxSynthesisQmfFiltering() creates 64 time domain samples out
+ of a slot of 64 complex spectral values at a time. The first 6 slots
+ in #timeOut are filled from the results of spectral slots 0..5 in the
+ #OverlapBuffer. The consecutive slots in timeOut are now filled with
+ the results of spectral slots 6..17.
+
+ 5.) The preprocessed slots 18..23 have to be stored in the
+ #OverlapBuffer.
+
+*/
+
+void sbr_dec(
+ HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */
+ INT_PCM *timeIn, /*!< pointer to input time signal */
+ INT_PCM *timeOut, /*!< pointer to output time signal */
+ HANDLE_SBR_DEC hSbrDecRight, /*!< handle to Decoder channel right */
+ INT_PCM *timeOutRight, /*!< pointer to output time signal */
+ const int strideOut, /*!< Time data traversal strideOut */
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */
+ HANDLE_SBR_PREV_FRAME_DATA
+ hPrevFrameData, /*!< Some control data of last frame */
+ const int applyProcessing, /*!< Flag for SBR operation */
+ HANDLE_PS_DEC h_ps_d, const UINT flags, const int codecFrameSize) {
+ int i, slot, reserve;
+ int saveLbScale;
+ int lastSlotOffs;
+ FIXP_DBL maxVal;
+
+ /* temporary pointer / variable for QMF;
+ required as we want to use temporary buffer
+ creating one frame delay for HBE in LP mode */
+ INT_PCM *pTimeInQmf = timeIn;
+
+ /* Number of QMF timeslots in the overlap buffer: */
+ int ov_len = hSbrDec->LppTrans.pSettings->overlap;
+
+ /* Number of QMF slots per frame */
+ int noCols = hHeaderData->numberTimeSlots * hHeaderData->timeStep;
+
+ /* create pointer array for data to use for HBE and legacy sbr */
+ FIXP_DBL *pLowBandReal[(3 * 4) + 2 * ((1024) / (32) * (4) / 2)];
+ FIXP_DBL *pLowBandImag[(3 * 4) + 2 * ((1024) / (32) * (4) / 2)];
+
+ /* set pReal to where QMF analysis writes in case of legacy SBR */
+ FIXP_DBL **pReal = pLowBandReal + ov_len;
+ FIXP_DBL **pImag = pLowBandImag + ov_len;
+
+ /* map QMF buffer to pointer array (Overlap + Frame)*/
+ for (i = 0; i < noCols + ov_len; i++) {
+ pLowBandReal[i] = hSbrDec->qmfDomainInCh->hQmfSlotsReal[i];
+ pLowBandImag[i] = hSbrDec->qmfDomainInCh->hQmfSlotsImag[i];
+ }
+
+ if ((flags & SBRDEC_USAC_HARMONICSBR)) {
+ /* in case of harmonic SBR and no HBE_LP map additional buffer for
+ one more frame to pointer arry */
+ for (i = 0; i < noCols; i++) {
+ pLowBandReal[i + noCols + ov_len] = hSbrDec->hQmfHBESlotsReal[i];
+ pLowBandImag[i + noCols + ov_len] = hSbrDec->hQmfHBESlotsImag[i];
+ }
+
+ /* shift scale values according to buffer */
+ hSbrDec->scale_ov = hSbrDec->scale_lb;
+ hSbrDec->scale_lb = hSbrDec->scale_hbe;
+
+ /* set pReal to where QMF analysis writes in case of HBE */
+ pReal += noCols;
+ pImag += noCols;
+ if (flags & SBRDEC_SKIP_QMF_ANA) {
+ /* stereoCfgIndex3 with HBE */
+ FDK_QmfDomain_QmfData2HBE(hSbrDec->qmfDomainInCh,
+ hSbrDec->hQmfHBESlotsReal,
+ hSbrDec->hQmfHBESlotsImag);
+ } else {
+ /* We have to move old hbe frame data to lb area of buffer */
+ for (i = 0; i < noCols; i++) {
+ FDKmemcpy(pLowBandReal[ov_len + i], hSbrDec->hQmfHBESlotsReal[i],
+ hHeaderData->numberOfAnalysisBands * sizeof(FIXP_DBL));
+ FDKmemcpy(pLowBandImag[ov_len + i], hSbrDec->hQmfHBESlotsImag[i],
+ hHeaderData->numberOfAnalysisBands * sizeof(FIXP_DBL));
+ }
+ }
+ }
+
+ /*
+ low band codec signal subband filtering
+ */
+
+ if (flags & SBRDEC_SKIP_QMF_ANA) {
+ if (!(flags & SBRDEC_USAC_HARMONICSBR)) /* stereoCfgIndex3 w/o HBE */
+ FDK_QmfDomain_WorkBuffer2ProcChannel(hSbrDec->qmfDomainInCh);
+ } else {
+ C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2 * (64));
+ qmfAnalysisFiltering(&hSbrDec->qmfDomainInCh->fb, pReal, pImag,
+ &hSbrDec->qmfDomainInCh->scaling, pTimeInQmf, 0, 1,
+ qmfTemp);
+
+ C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2 * (64));
+ }
+
+ /*
+ Clear upper half of spectrum
+ */
+ if (!((flags & SBRDEC_USAC_HARMONICSBR) &&
+ (hFrameData->sbrPatchingMode == 0))) {
+ int nAnalysisBands = hHeaderData->numberOfAnalysisBands;
+
+ if (!(flags & SBRDEC_LOW_POWER)) {
+ for (slot = ov_len; slot < noCols + ov_len; slot++) {
+ FDKmemclear(&pLowBandReal[slot][nAnalysisBands],
+ ((64) - nAnalysisBands) * sizeof(FIXP_DBL));
+ FDKmemclear(&pLowBandImag[slot][nAnalysisBands],
+ ((64) - nAnalysisBands) * sizeof(FIXP_DBL));
+ }
+ } else {
+ for (slot = ov_len; slot < noCols + ov_len; slot++) {
+ FDKmemclear(&pLowBandReal[slot][nAnalysisBands],
+ ((64) - nAnalysisBands) * sizeof(FIXP_DBL));
+ }
+ }
+ }
+
+ /*
+ Shift spectral data left to gain accuracy in transposer and adjustor
+ */
+ /* Range was increased from lsb to no_channels because in some cases (e.g.
+ USAC conf eSbr_4_Pvc.mp4 and some HBE cases) it could be observed that the
+ signal between lsb and no_channels is used for the patching process.
+ */
+ maxVal = maxSubbandSample(pReal, (flags & SBRDEC_LOW_POWER) ? NULL : pImag, 0,
+ hSbrDec->qmfDomainInCh->fb.no_channels, 0, noCols);
+
+ reserve = fixMax(0, CntLeadingZeros(maxVal) - 1);
+ reserve = fixMin(reserve,
+ DFRACT_BITS - 1 - hSbrDec->qmfDomainInCh->scaling.lb_scale);
+
+ /* If all data is zero, lb_scale could become too large */
+ rescaleSubbandSamples(pReal, (flags & SBRDEC_LOW_POWER) ? NULL : pImag, 0,
+ hSbrDec->qmfDomainInCh->fb.no_channels, 0, noCols,
+ reserve);
+
+ hSbrDec->qmfDomainInCh->scaling.lb_scale += reserve;
+
+ if ((flags & SBRDEC_USAC_HARMONICSBR)) {
+ /* actually this is our hbe_scale */
+ hSbrDec->scale_hbe = hSbrDec->qmfDomainInCh->scaling.lb_scale;
+ /* the real lb_scale is stored in scale_lb from sbr */
+ hSbrDec->qmfDomainInCh->scaling.lb_scale = hSbrDec->scale_lb;
+ }
+ /*
+ save low band scale, wavecoding or parametric stereo may modify it
+ */
+ saveLbScale = hSbrDec->qmfDomainInCh->scaling.lb_scale;
+
+ if (applyProcessing) {
+ UCHAR *borders = hFrameData->frameInfo.borders;
+ lastSlotOffs = borders[hFrameData->frameInfo.nEnvelopes] -
+ hHeaderData->numberTimeSlots;
+
+ FIXP_DBL degreeAlias[(64)];
+ PVC_DYNAMIC_DATA pvcDynamicData;
+ pvcInitFrame(
+ &hSbrDec->PvcStaticData, &pvcDynamicData,
+ (hHeaderData->frameErrorFlag ? 0 : hHeaderData->bs_info.pvc_mode),
+ hFrameData->ns, hHeaderData->timeStep,
+ hHeaderData->freqBandData.lowSubband,
+ hFrameData->frameInfo.pvcBorders[0], hFrameData->pvcID);
+
+ if (!hHeaderData->frameErrorFlag && (hHeaderData->bs_info.pvc_mode > 0)) {
+ pvcDecodeFrame(&hSbrDec->PvcStaticData, &pvcDynamicData, pLowBandReal,
+ pLowBandImag, ov_len,
+ SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale),
+ SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.lb_scale));
+ }
+ pvcEndFrame(&hSbrDec->PvcStaticData, &pvcDynamicData);
+
+ /* The transposer will override most values in degreeAlias[].
+ The array needs to be cleared at least from lowSubband to highSubband
+ before. */
+ if (flags & SBRDEC_LOW_POWER)
+ FDKmemclear(&degreeAlias[hHeaderData->freqBandData.lowSubband],
+ (hHeaderData->freqBandData.highSubband -
+ hHeaderData->freqBandData.lowSubband) *
+ sizeof(FIXP_DBL));
+
+ /*
+ Inverse filtering of lowband and transposition into the SBR-frequency
+ range
+ */
+
+ {
+ KEEP_STATES_SYNCED_MODE keepStatesSyncedMode =
+ ((flags & SBRDEC_USAC_HARMONICSBR) &&
+ (hFrameData->sbrPatchingMode != 0))
+ ? KEEP_STATES_SYNCED_NORMAL
+ : KEEP_STATES_SYNCED_OFF;
+
+ if (flags & SBRDEC_USAC_HARMONICSBR) {
+ if (flags & SBRDEC_QUAD_RATE) {
+ pReal -= 32;
+ pImag -= 32;
+ }
+
+ if ((hSbrDec->savedStates == 0) && (hFrameData->sbrPatchingMode == 1)) {
+ /* copy saved states from previous frame to legacy SBR lpc filterstate
+ * buffer */
+ for (i = 0; i < LPC_ORDER + ov_len; i++) {
+ FDKmemcpy(
+ hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
+ hSbrDec->codecQMFBufferReal[noCols - LPC_ORDER - ov_len + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ FDKmemcpy(
+ hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i],
+ hSbrDec->codecQMFBufferImag[noCols - LPC_ORDER - ov_len + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ }
+ }
+
+ /* saving unmodified QMF states in case we are switching from legacy SBR
+ * to HBE */
+ for (i = 0; i < hSbrDec->hHBE->noCols; i++) {
+ FDKmemcpy(hSbrDec->codecQMFBufferReal[i], pLowBandReal[ov_len + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ FDKmemcpy(hSbrDec->codecQMFBufferImag[i], pLowBandImag[ov_len + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ }
+
+ QmfTransposerApply(
+ hSbrDec->hHBE, pReal, pImag, noCols, pLowBandReal, pLowBandImag,
+ hSbrDec->LppTrans.lpcFilterStatesRealHBE,
+ hSbrDec->LppTrans.lpcFilterStatesImagHBE,
+ hFrameData->sbrPitchInBins, hSbrDec->scale_lb, hSbrDec->scale_hbe,
+ &hSbrDec->qmfDomainInCh->scaling.hb_scale, hHeaderData->timeStep,
+ borders[0], ov_len, keepStatesSyncedMode);
+
+ if (flags & SBRDEC_QUAD_RATE) {
+ int *xOverQmf = GetxOverBandQmfTransposer(hSbrDec->hHBE);
+
+ copyHarmonicSpectrum(xOverQmf, pLowBandReal, pLowBandImag, noCols,
+ ov_len, keepStatesSyncedMode);
+ }
+ }
+ }
+
+ if ((flags & SBRDEC_USAC_HARMONICSBR) &&
+ (hFrameData->sbrPatchingMode == 0)) {
+ hSbrDec->prev_frame_lSbr = 0;
+ hSbrDec->prev_frame_hbeSbr = 1;
+
+ lppTransposerHBE(
+ &hSbrDec->LppTrans, hSbrDec->hHBE, &hSbrDec->qmfDomainInCh->scaling,
+ pLowBandReal, pLowBandImag, hHeaderData->timeStep, borders[0],
+ lastSlotOffs, hHeaderData->freqBandData.nInvfBands,
+ hFrameData->sbr_invf_mode, hPrevFrameData->sbr_invf_mode);
+
+ } else {
+ if (flags & SBRDEC_USAC_HARMONICSBR) {
+ for (i = 0; i < LPC_ORDER + hSbrDec->LppTrans.pSettings->overlap; i++) {
+ /*
+ Store the unmodified qmf Slots values for upper part of spectrum
+ (required for LPC filtering) required if next frame is a HBE frame
+ */
+ FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesRealHBE[i],
+ hSbrDec->qmfDomainInCh
+ ->hQmfSlotsReal[hSbrDec->hHBE->noCols - LPC_ORDER + i],
+ (64) * sizeof(FIXP_DBL));
+ FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesImagHBE[i],
+ hSbrDec->qmfDomainInCh
+ ->hQmfSlotsImag[hSbrDec->hHBE->noCols - LPC_ORDER + i],
+ (64) * sizeof(FIXP_DBL));
+ }
+ }
+ {
+ hSbrDec->prev_frame_lSbr = 1;
+ hSbrDec->prev_frame_hbeSbr = 0;
+ }
+
+ lppTransposer(
+ &hSbrDec->LppTrans, &hSbrDec->qmfDomainInCh->scaling, pLowBandReal,
+ degreeAlias, // only used if useLP = 1
+ pLowBandImag, flags & SBRDEC_LOW_POWER,
+ hHeaderData->bs_info.sbr_preprocessing,
+ hHeaderData->freqBandData.v_k_master[0], hHeaderData->timeStep,
+ borders[0], lastSlotOffs, hHeaderData->freqBandData.nInvfBands,
+ hFrameData->sbr_invf_mode, hPrevFrameData->sbr_invf_mode);
+ }
+
+ /*
+ Adjust envelope of current frame.
+ */
+
+ if ((hFrameData->sbrPatchingMode !=
+ hSbrDec->SbrCalculateEnvelope.sbrPatchingMode)) {
+ ResetLimiterBands(hHeaderData->freqBandData.limiterBandTable,
+ &hHeaderData->freqBandData.noLimiterBands,
+ hHeaderData->freqBandData.freqBandTable[0],
+ hHeaderData->freqBandData.nSfb[0],
+ hSbrDec->LppTrans.pSettings->patchParam,
+ hSbrDec->LppTrans.pSettings->noOfPatches,
+ hHeaderData->bs_data.limiterBands,
+ hFrameData->sbrPatchingMode,
+ (flags & SBRDEC_USAC_HARMONICSBR) &&
+ (hFrameData->sbrPatchingMode == 0)
+ ? GetxOverBandQmfTransposer(hSbrDec->hHBE)
+ : NULL,
+ Get41SbrQmfTransposer(hSbrDec->hHBE));
+
+ hSbrDec->SbrCalculateEnvelope.sbrPatchingMode =
+ hFrameData->sbrPatchingMode;
+ }
+
+ calculateSbrEnvelope(
+ &hSbrDec->qmfDomainInCh->scaling, &hSbrDec->SbrCalculateEnvelope,
+ hHeaderData, hFrameData, &pvcDynamicData, pLowBandReal, pLowBandImag,
+ flags & SBRDEC_LOW_POWER,
+
+ degreeAlias, flags,
+ (hHeaderData->frameErrorFlag || hPrevFrameData->frameErrorFlag));
+
+#if (SBRDEC_MAX_HB_FADE_FRAMES > 0)
+ /* Avoid hard onsets of high band */
+ if (hHeaderData->frameErrorFlag) {
+ if (hSbrDec->highBandFadeCnt < SBRDEC_MAX_HB_FADE_FRAMES) {
+ hSbrDec->highBandFadeCnt += 1;
+ }
+ } else {
+ if (hSbrDec->highBandFadeCnt >
+ 0) { /* Manipulate high band scale factor to get a smooth fade-in */
+ hSbrDec->qmfDomainInCh->scaling.hb_scale += hSbrDec->highBandFadeCnt;
+ hSbrDec->qmfDomainInCh->scaling.hb_scale =
+ fMin(hSbrDec->qmfDomainInCh->scaling.hb_scale, DFRACT_BITS - 1);
+ hSbrDec->highBandFadeCnt -= 1;
+ }
+ }
+
+#endif
+ /*
+ Update hPrevFrameData (to be used in the next frame)
+ */
+ for (i = 0; i < hHeaderData->freqBandData.nInvfBands; i++) {
+ hPrevFrameData->sbr_invf_mode[i] = hFrameData->sbr_invf_mode[i];
+ }
+ hPrevFrameData->coupling = hFrameData->coupling;
+ hPrevFrameData->stopPos = borders[hFrameData->frameInfo.nEnvelopes];
+ hPrevFrameData->ampRes = hFrameData->ampResolutionCurrentFrame;
+ hPrevFrameData->prevSbrPitchInBins = hFrameData->sbrPitchInBins;
+ /* could be done in extractFrameInfo_pvc() but hPrevFrameData is not
+ * available there */
+ FDKmemcpy(&hPrevFrameData->prevFrameInfo, &hFrameData->frameInfo,
+ sizeof(FRAME_INFO));
+ } else {
+ /* rescale from lsb to nAnalysisBands in order to compensate scaling with
+ * hb_scale in this area, done by synthesisFiltering*/
+ int rescale;
+ int lsb;
+ int length;
+
+ /* Reset hb_scale if no highband is present, because hb_scale is considered
+ * in the QMF-synthesis */
+ hSbrDec->qmfDomainInCh->scaling.hb_scale = saveLbScale;
+
+ rescale = hSbrDec->qmfDomainInCh->scaling.hb_scale -
+ hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
+ lsb = hSbrDec->qmfDomainOutCh->fb.lsb;
+ length = (hSbrDec->qmfDomainInCh->fb.no_channels - lsb);
+
+ if ((rescale < 0) && (length > 0)) {
+ if (!(flags & SBRDEC_LOW_POWER)) {
+ for (i = 0; i < ov_len; i++) {
+ scaleValues(&pLowBandReal[i][lsb], length, rescale);
+ scaleValues(&pLowBandImag[i][lsb], length, rescale);
+ }
+ } else {
+ for (i = 0; i < ov_len; i++) {
+ scaleValues(&pLowBandReal[i][lsb], length, rescale);
+ }
+ }
+ }
+ }
+
+ if (!(flags & SBRDEC_USAC_HARMONICSBR)) {
+ int length = hSbrDec->qmfDomainInCh->fb.lsb;
+ if (flags & SBRDEC_SYNTAX_USAC) {
+ length = hSbrDec->qmfDomainInCh->fb.no_channels;
+ }
+
+ /* in case of legacy sbr saving of filter states here */
+ for (i = 0; i < LPC_ORDER + ov_len; i++) {
+ /*
+ Store the unmodified qmf Slots values (required for LPC filtering)
+ */
+ if (!(flags & SBRDEC_LOW_POWER)) {
+ FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
+ pLowBandReal[noCols - LPC_ORDER + i],
+ length * sizeof(FIXP_DBL));
+ FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i],
+ pLowBandImag[noCols - LPC_ORDER + i],
+ length * sizeof(FIXP_DBL));
+ } else
+ FDKmemcpy(hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
+ pLowBandReal[noCols - LPC_ORDER + i],
+ length * sizeof(FIXP_DBL));
+ }
+ }
+
+ /*
+ Synthesis subband filtering.
+ */
+
+ if (!(flags & SBRDEC_PS_DECODED)) {
+ if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
+ int outScalefactor = 0;
+
+ if (h_ps_d != NULL) {
+ h_ps_d->procFrameBased = 1; /* we here do frame based processing */
+ }
+
+ sbrDecoder_drcApply(&hSbrDec->sbrDrcChannel, pLowBandReal,
+ (flags & SBRDEC_LOW_POWER) ? NULL : pLowBandImag,
+ hSbrDec->qmfDomainOutCh->fb.no_col, &outScalefactor);
+
+ qmfChangeOutScalefactor(&hSbrDec->qmfDomainOutCh->fb, outScalefactor);
+
+ {
+ HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData;
+ int save_usb = hSbrDec->qmfDomainOutCh->fb.usb;
+
+#if (QMF_MAX_SYNTHESIS_BANDS <= 64)
+ C_AALLOC_SCRATCH_START(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#else
+ C_AALLOC_STACK_START(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#endif
+ if (hSbrDec->qmfDomainOutCh->fb.usb < hFreq->ov_highSubband) {
+ /* we need to patch usb for this frame as overlap may contain higher
+ frequency range if headerchange occured; fb. usb is always limited
+ to maximum fb.no_channels; In case of wrongly decoded headers it
+ might be that ov_highSubband is higher than the number of synthesis
+ channels (fb.no_channels), which is forbidden, therefore we need to
+ limit ov_highSubband with fMin function to avoid not allowed usb in
+ synthesis filterbank. */
+ hSbrDec->qmfDomainOutCh->fb.usb =
+ fMin((UINT)hFreq->ov_highSubband,
+ (UINT)hSbrDec->qmfDomainOutCh->fb.no_channels);
+ }
+ {
+ qmfSynthesisFiltering(
+ &hSbrDec->qmfDomainOutCh->fb, pLowBandReal,
+ (flags & SBRDEC_LOW_POWER) ? NULL : pLowBandImag,
+ &hSbrDec->qmfDomainInCh->scaling,
+ hSbrDec->LppTrans.pSettings->overlap, timeOut, strideOut,
+ qmfTemp);
+ }
+ /* restore saved value */
+ hSbrDec->qmfDomainOutCh->fb.usb = save_usb;
+ hFreq->ov_highSubband = save_usb;
+#if (QMF_MAX_SYNTHESIS_BANDS <= 64)
+ C_AALLOC_SCRATCH_END(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#else
+ C_AALLOC_STACK_END(qmfTemp, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#endif
+ }
+ }
+
+ } else { /* (flags & SBRDEC_PS_DECODED) */
+ INT sdiff;
+ INT scaleFactorHighBand, scaleFactorLowBand_ov, scaleFactorLowBand_no_ov;
+
+ HANDLE_QMF_FILTER_BANK synQmf = &hSbrDec->qmfDomainOutCh->fb;
+ HANDLE_QMF_FILTER_BANK synQmfRight = &hSbrDecRight->qmfDomainOutCh->fb;
+
+ /* adapt scaling */
+ sdiff = hSbrDec->qmfDomainInCh->scaling.lb_scale -
+ reserve; /* Scaling difference */
+ scaleFactorHighBand = sdiff - hSbrDec->qmfDomainInCh->scaling.hb_scale;
+ scaleFactorLowBand_ov = sdiff - hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
+ scaleFactorLowBand_no_ov = sdiff - hSbrDec->qmfDomainInCh->scaling.lb_scale;
+
+ /* Scale of low band overlapping QMF data */
+ scaleFactorLowBand_ov =
+ fMin(DFRACT_BITS - 1, fMax(-(DFRACT_BITS - 1), scaleFactorLowBand_ov));
+ /* Scale of low band current QMF data */
+ scaleFactorLowBand_no_ov = fMin(
+ DFRACT_BITS - 1, fMax(-(DFRACT_BITS - 1), scaleFactorLowBand_no_ov));
+ /* Scale of current high band */
+ scaleFactorHighBand =
+ fMin(DFRACT_BITS - 1, fMax(-(DFRACT_BITS - 1), scaleFactorHighBand));
+
+ if (h_ps_d->procFrameBased == 1) /* If we have switched from frame to slot
+ based processing copy filter states */
+ { /* procFrameBased will be unset later */
+ /* copy filter states from left to right */
+ /* was ((640)-(64))*sizeof(FIXP_QSS)
+ flexible amount of synthesis bands needed for QMF based resampling
+ */
+ FDK_ASSERT(hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis <=
+ QMF_MAX_SYNTHESIS_BANDS);
+ FDKmemcpy(synQmfRight->FilterStates, synQmf->FilterStates,
+ 9 * hSbrDec->qmfDomainInCh->pGlobalConf->nBandsSynthesis *
+ sizeof(FIXP_QSS));
+ }
+
+ /* Feed delaylines when parametric stereo is switched on. */
+ PreparePsProcessing(h_ps_d, pLowBandReal, pLowBandImag,
+ scaleFactorLowBand_ov);
+
+ /* use the same synthese qmf values for left and right channel */
+ synQmfRight->no_col = synQmf->no_col;
+ synQmfRight->lsb = synQmf->lsb;
+ synQmfRight->usb = synQmf->usb;
+
+ int env = 0;
+
+ {
+#if (QMF_MAX_SYNTHESIS_BANDS <= 64)
+ C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL,
+ 2 * QMF_MAX_SYNTHESIS_BANDS);
+#else
+ C_AALLOC_STACK_START(pWorkBuffer, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#endif
+
+ int maxShift = 0;
+
+ if (hSbrDec->sbrDrcChannel.enable != 0) {
+ if (hSbrDec->sbrDrcChannel.prevFact_exp > maxShift) {
+ maxShift = hSbrDec->sbrDrcChannel.prevFact_exp;
+ }
+ if (hSbrDec->sbrDrcChannel.currFact_exp > maxShift) {
+ maxShift = hSbrDec->sbrDrcChannel.currFact_exp;
+ }
+ if (hSbrDec->sbrDrcChannel.nextFact_exp > maxShift) {
+ maxShift = hSbrDec->sbrDrcChannel.nextFact_exp;
+ }
+ }
+
+ /* copy DRC data to right channel (with PS both channels use the same DRC
+ * gains) */
+ FDKmemcpy(&hSbrDecRight->sbrDrcChannel, &hSbrDec->sbrDrcChannel,
+ sizeof(SBRDEC_DRC_CHANNEL));
+
+ for (i = 0; i < synQmf->no_col; i++) { /* ----- no_col loop ----- */
+
+ INT outScalefactorR, outScalefactorL;
+
+ /* qmf timeslot of right channel */
+ FIXP_DBL *rQmfReal = pWorkBuffer;
+ FIXP_DBL *rQmfImag = pWorkBuffer + synQmf->no_channels;
+
+ {
+ if (i ==
+ h_ps_d->bsData[h_ps_d->processSlot].mpeg.aEnvStartStop[env]) {
+ initSlotBasedRotation(h_ps_d, env,
+ hHeaderData->freqBandData.highSubband);
+ env++;
+ }
+
+ ApplyPsSlot(
+ h_ps_d, /* parametric stereo decoder handle */
+ (pLowBandReal + i), /* one timeslot of left/mono channel */
+ (pLowBandImag + i), /* one timeslot of left/mono channel */
+ rQmfReal, /* one timeslot or right channel */
+ rQmfImag, /* one timeslot or right channel */
+ scaleFactorLowBand_no_ov,
+ (i < hSbrDec->LppTrans.pSettings->overlap)
+ ? scaleFactorLowBand_ov
+ : scaleFactorLowBand_no_ov,
+ scaleFactorHighBand, synQmf->lsb, synQmf->usb);
+
+ outScalefactorL = outScalefactorR = 1; /* psDiffScale! (MPEG-PS) */
+ }
+
+ sbrDecoder_drcApplySlot(/* right channel */
+ &hSbrDecRight->sbrDrcChannel, rQmfReal,
+ rQmfImag, i, synQmfRight->no_col, maxShift);
+
+ outScalefactorR += maxShift;
+
+ sbrDecoder_drcApplySlot(/* left channel */
+ &hSbrDec->sbrDrcChannel, *(pLowBandReal + i),
+ *(pLowBandImag + i), i, synQmf->no_col,
+ maxShift);
+
+ outScalefactorL += maxShift;
+
+ if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
+ qmfSynthesisFilteringSlot(
+ synQmfRight, rQmfReal, /* QMF real buffer */
+ rQmfImag, /* QMF imag buffer */
+ outScalefactorL, outScalefactorL,
+ timeOutRight + (i * synQmf->no_channels * strideOut), strideOut,
+ pWorkBuffer);
+
+ qmfSynthesisFilteringSlot(
+ synQmf, *(pLowBandReal + i), /* QMF real buffer */
+ *(pLowBandImag + i), /* QMF imag buffer */
+ outScalefactorR, outScalefactorR,
+ timeOut + (i * synQmf->no_channels * strideOut), strideOut,
+ pWorkBuffer);
+ }
+ } /* no_col loop i */
+#if (QMF_MAX_SYNTHESIS_BANDS <= 64)
+ C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#else
+ C_AALLOC_STACK_END(pWorkBuffer, FIXP_DBL, 2 * QMF_MAX_SYNTHESIS_BANDS);
+#endif
+ }
+ }
+
+ sbrDecoder_drcUpdateChannel(&hSbrDec->sbrDrcChannel);
+
+ /*
+ Update overlap buffer
+ Even bands above usb are copied to avoid outdated spectral data in case
+ the stop frequency raises.
+ */
+
+ if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
+ {
+ FDK_QmfDomain_SaveOverlap(hSbrDec->qmfDomainInCh, 0);
+ FDK_ASSERT(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale == saveLbScale);
+ }
+ }
+
+ hSbrDec->savedStates = 0;
+
+ /* Save current frame status */
+ hPrevFrameData->frameErrorFlag = hHeaderData->frameErrorFlag;
+ hSbrDec->applySbrProc_old = applyProcessing;
+
+} /* sbr_dec() */
+
+/*!
+ \brief Creates sbr decoder structure
+ \return errorCode, 0 if successful
+*/
+SBR_ERROR
+createSbrDec(SBR_CHANNEL *hSbrChannel,
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ TRANSPOSER_SETTINGS *pSettings,
+ const int downsampleFac, /*!< Downsampling factor */
+ const UINT qmfFlags, /*!< flags -> 1: HQ/LP selector, 2: CLDFB */
+ const UINT flags, const int overlap,
+ int chan, /*!< Channel for which to assign buffers etc. */
+ int codecFrameSize)
+
+{
+ SBR_ERROR err = SBRDEC_OK;
+ int timeSlots =
+ hHeaderData->numberTimeSlots; /* Number of SBR slots per frame */
+ int noCols =
+ timeSlots * hHeaderData->timeStep; /* Number of QMF slots per frame */
+ HANDLE_SBR_DEC hs = &(hSbrChannel->SbrDec);
+
+#if (SBRDEC_MAX_HB_FADE_FRAMES > 0)
+ hs->highBandFadeCnt = SBRDEC_MAX_HB_FADE_FRAMES;
+
+#endif
+ hs->scale_hbe = 15;
+ hs->scale_lb = 15;
+ hs->scale_ov = 15;
+
+ hs->prev_frame_lSbr = 0;
+ hs->prev_frame_hbeSbr = 0;
+
+ hs->codecFrameSize = codecFrameSize;
+
+ /*
+ create envelope calculator
+ */
+ err = createSbrEnvelopeCalc(&hs->SbrCalculateEnvelope, hHeaderData, chan,
+ flags);
+ if (err != SBRDEC_OK) {
+ return err;
+ }
+
+ initSbrPrevFrameData(&hSbrChannel->prevFrameData, timeSlots);
+
+ /*
+ create transposer
+ */
+ err = createLppTransposer(
+ &hs->LppTrans, pSettings, hHeaderData->freqBandData.lowSubband,
+ hHeaderData->freqBandData.v_k_master, hHeaderData->freqBandData.numMaster,
+ hHeaderData->freqBandData.highSubband, timeSlots, noCols,
+ hHeaderData->freqBandData.freqBandTableNoise,
+ hHeaderData->freqBandData.nNfb, hHeaderData->sbrProcSmplRate, chan,
+ overlap);
+ if (err != SBRDEC_OK) {
+ return err;
+ }
+
+ if (flags & SBRDEC_USAC_HARMONICSBR) {
+ int noChannels, bSbr41 = flags & SBRDEC_QUAD_RATE ? 1 : 0;
+
+ noChannels =
+ QMF_SYNTH_CHANNELS /
+ ((bSbr41 + 1) * 2); /* 32 for (32:64 and 24:64) and 16 for 16:64 */
+
+ /* shared memory between hbeLightTimeDelayBuffer and hQmfHBESlotsReal if
+ * SBRDEC_HBE_ENABLE */
+ hSbrChannel->SbrDec.tmp_memory = (FIXP_DBL **)fdkCallocMatrix2D_aligned(
+ noCols, noChannels, sizeof(FIXP_DBL));
+ if (hSbrChannel->SbrDec.tmp_memory == NULL) {
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ hSbrChannel->SbrDec.hQmfHBESlotsReal = hSbrChannel->SbrDec.tmp_memory;
+ hSbrChannel->SbrDec.hQmfHBESlotsImag =
+ (FIXP_DBL **)fdkCallocMatrix2D_aligned(noCols, noChannels,
+ sizeof(FIXP_DBL));
+ if (hSbrChannel->SbrDec.hQmfHBESlotsImag == NULL) {
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ /* buffers containing unmodified qmf data; required when switching from
+ * legacy SBR to HBE */
+ /* buffer can be used as LPCFilterstates buffer because legacy SBR needs
+ * exactly these values for LPC filtering */
+ hSbrChannel->SbrDec.codecQMFBufferReal =
+ (FIXP_DBL **)fdkCallocMatrix2D_aligned(noCols, noChannels,
+ sizeof(FIXP_DBL));
+ if (hSbrChannel->SbrDec.codecQMFBufferReal == NULL) {
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ hSbrChannel->SbrDec.codecQMFBufferImag =
+ (FIXP_DBL **)fdkCallocMatrix2D_aligned(noCols, noChannels,
+ sizeof(FIXP_DBL));
+ if (hSbrChannel->SbrDec.codecQMFBufferImag == NULL) {
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ err = QmfTransposerCreate(&hs->hHBE, codecFrameSize, 0, bSbr41);
+ if (err != SBRDEC_OK) {
+ return err;
+ }
+ }
+
+ return err;
+}
+
+/*!
+ \brief Delete sbr decoder structure
+ \return errorCode, 0 if successful
+*/
+int deleteSbrDec(SBR_CHANNEL *hSbrChannel) {
+ HANDLE_SBR_DEC hs = &hSbrChannel->SbrDec;
+
+ deleteSbrEnvelopeCalc(&hs->SbrCalculateEnvelope);
+
+ if (hs->tmp_memory != NULL) {
+ FDK_FREE_MEMORY_2D_ALIGNED(hs->tmp_memory);
+ }
+
+ /* modify here */
+ FDK_FREE_MEMORY_2D_ALIGNED(hs->hQmfHBESlotsImag);
+
+ if (hs->hHBE != NULL) QmfTransposerClose(hs->hHBE);
+
+ if (hs->codecQMFBufferReal != NULL) {
+ FDK_FREE_MEMORY_2D_ALIGNED(hs->codecQMFBufferReal);
+ }
+
+ if (hs->codecQMFBufferImag != NULL) {
+ FDK_FREE_MEMORY_2D_ALIGNED(hs->codecQMFBufferImag);
+ }
+
+ return 0;
+}
+
+/*!
+ \brief resets sbr decoder structure
+ \return errorCode, 0 if successful
+*/
+SBR_ERROR
+resetSbrDec(HANDLE_SBR_DEC hSbrDec, HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, const int downsampleFac,
+ const UINT flags, HANDLE_SBR_FRAME_DATA hFrameData) {
+ SBR_ERROR sbrError = SBRDEC_OK;
+ int i;
+ FIXP_DBL *pLowBandReal[128];
+ FIXP_DBL *pLowBandImag[128];
+ int useLP = flags & SBRDEC_LOW_POWER;
+
+ int old_lsb = hSbrDec->qmfDomainInCh->fb.lsb;
+ int old_usb = hSbrDec->qmfDomainInCh->fb.usb;
+ int new_lsb = hHeaderData->freqBandData.lowSubband;
+ /* int new_usb = hHeaderData->freqBandData.highSubband; */
+ int l, startBand, stopBand, startSlot, size;
+
+ FIXP_DBL **OverlapBufferReal = hSbrDec->qmfDomainInCh->hQmfSlotsReal;
+ FIXP_DBL **OverlapBufferImag = hSbrDec->qmfDomainInCh->hQmfSlotsImag;
+
+ /* in case the previous frame was not active in terms of SBR processing, the
+ full band from 0 to no_channels was rescaled and not overwritten. Thats why
+ the scaling factor lb_scale can be seen as assigned to all bands from 0 to
+ no_channels in the previous frame. The same states for the current frame if
+ the current frame is not active in terms of SBR processing
+ */
+ int applySbrProc = (hHeaderData->syncState == SBR_ACTIVE ||
+ (hHeaderData->frameErrorFlag == 0 &&
+ hHeaderData->syncState == SBR_HEADER));
+ int applySbrProc_old = hSbrDec->applySbrProc_old;
+
+ if (!applySbrProc) {
+ new_lsb = (hSbrDec->qmfDomainInCh->fb).no_channels;
+ }
+ if (!applySbrProc_old) {
+ old_lsb = (hSbrDec->qmfDomainInCh->fb).no_channels;
+ old_usb = old_lsb;
+ }
+
+ resetSbrEnvelopeCalc(&hSbrDec->SbrCalculateEnvelope);
+
+ /* Change lsb and usb */
+ /* Synthesis */
+ FDK_ASSERT(hSbrDec->qmfDomainOutCh != NULL);
+ hSbrDec->qmfDomainOutCh->fb.lsb =
+ fixMin((INT)hSbrDec->qmfDomainOutCh->fb.no_channels,
+ (INT)hHeaderData->freqBandData.lowSubband);
+ hSbrDec->qmfDomainOutCh->fb.usb =
+ fixMin((INT)hSbrDec->qmfDomainOutCh->fb.no_channels,
+ (INT)hHeaderData->freqBandData.highSubband);
+ /* Analysis */
+ FDK_ASSERT(hSbrDec->qmfDomainInCh != NULL);
+ hSbrDec->qmfDomainInCh->fb.lsb = hSbrDec->qmfDomainOutCh->fb.lsb;
+ hSbrDec->qmfDomainInCh->fb.usb = hSbrDec->qmfDomainOutCh->fb.usb;
+
+ /*
+ The following initialization of spectral data in the overlap buffer
+ is required for dynamic x-over or a change of the start-freq for 2 reasons:
+
+ 1. If the lowband gets _wider_, unadjusted data would remain
+
+ 2. If the lowband becomes _smaller_, the highest bands of the old lowband
+ must be cleared because the whitening would be affected
+ */
+ startBand = old_lsb;
+ stopBand = new_lsb;
+ startSlot = fMax(0, hHeaderData->timeStep * (hPrevFrameData->stopPos -
+ hHeaderData->numberTimeSlots));
+ size = fMax(0, stopBand - startBand);
+
+ /* in case of USAC we don't want to zero out the memory, as this can lead to
+ holes in the spectrum; fix shall only be applied for USAC not for MPEG-4
+ SBR, in this case setting zero remains */
+ if (!(flags & SBRDEC_SYNTAX_USAC)) {
+ /* keep already adjusted data in the x-over-area */
+ if (!useLP) {
+ for (l = startSlot; l < hSbrDec->LppTrans.pSettings->overlap; l++) {
+ FDKmemclear(&OverlapBufferReal[l][startBand], size * sizeof(FIXP_DBL));
+ FDKmemclear(&OverlapBufferImag[l][startBand], size * sizeof(FIXP_DBL));
+ }
+ } else {
+ for (l = startSlot; l < hSbrDec->LppTrans.pSettings->overlap; l++) {
+ FDKmemclear(&OverlapBufferReal[l][startBand], size * sizeof(FIXP_DBL));
+ }
+ }
+
+ /*
+ reset LPC filter states
+ */
+ startBand = fixMin(old_lsb, new_lsb);
+ stopBand = fixMax(old_lsb, new_lsb);
+ size = fixMax(0, stopBand - startBand);
+
+ FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[0][startBand],
+ size * sizeof(FIXP_DBL));
+ FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[1][startBand],
+ size * sizeof(FIXP_DBL));
+ if (!useLP) {
+ FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[0][startBand],
+ size * sizeof(FIXP_DBL));
+ FDKmemclear(&hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[1][startBand],
+ size * sizeof(FIXP_DBL));
+ }
+ }
+
+ if (startSlot != 0) {
+ int source_exp, target_exp, delta_exp, target_lsb, target_usb, reserve;
+ FIXP_DBL maxVal;
+
+ /*
+ Rescale already processed spectral data between old and new x-over
+ frequency. This must be done because of the separate scalefactors for
+ lowband and highband.
+ */
+
+ /* We have four relevant transitions to cover:
+ 1. old_usb is lower than new_lsb; old SBR area is completely below new SBR
+ area.
+ -> entire old area was highband and belongs to lowband now
+ and has to be rescaled.
+ 2. old_lsb is higher than new_usb; new SBR area is completely below old SBR
+ area.
+ -> old area between new_lsb and old_lsb was lowband and belongs to
+ highband now and has to be rescaled to match new highband scale.
+ 3. old_lsb is lower and old_usb is higher than new_lsb; old and new SBR
+ areas overlap.
+ -> old area between old_lsb and new_lsb was highband and belongs to
+ lowband now and has to be rescaled to match new lowband scale.
+ 4. new_lsb is lower and new_usb_is higher than old_lsb; old and new SBR
+ areas overlap.
+ -> old area between new_lsb and old_usb was lowband and belongs to
+ highband now and has to be rescaled to match new highband scale.
+ */
+
+ if (new_lsb > old_lsb) {
+ /* case 1 and 3 */
+ source_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_hb_scale);
+ target_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale);
+
+ startBand = old_lsb;
+
+ if (new_lsb >= old_usb) {
+ /* case 1 */
+ stopBand = old_usb;
+ } else {
+ /* case 3 */
+ stopBand = new_lsb;
+ }
+
+ target_lsb = 0;
+ target_usb = old_lsb;
+ } else {
+ /* case 2 and 4 */
+ source_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale);
+ target_exp = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_hb_scale);
+
+ startBand = new_lsb;
+ stopBand = old_lsb;
+
+ target_lsb = old_lsb;
+ target_usb = old_usb;
+ }
+
+ maxVal =
+ maxSubbandSample(OverlapBufferReal, (useLP) ? NULL : OverlapBufferImag,
+ startBand, stopBand, 0, startSlot);
+
+ reserve = ((LONG)maxVal != 0 ? CntLeadingZeros(maxVal) - 1 : 0);
+ reserve = fixMin(
+ reserve,
+ DFRACT_BITS - 1 -
+ EXP2SCALE(
+ source_exp)); /* what is this line for, why do we need it? */
+
+ /* process only if x-over-area is not dominant after rescale;
+ otherwise I'm not sure if all buffers are scaled correctly;
+ */
+ if (target_exp - (source_exp - reserve) >= 0) {
+ rescaleSubbandSamples(OverlapBufferReal,
+ (useLP) ? NULL : OverlapBufferImag, startBand,
+ stopBand, 0, startSlot, reserve);
+ source_exp -= reserve;
+ }
+
+ delta_exp = target_exp - source_exp;
+
+ if (delta_exp < 0) { /* x-over-area is dominant */
+ startBand = target_lsb;
+ stopBand = target_usb;
+ delta_exp = -delta_exp;
+
+ if (new_lsb > old_lsb) {
+ /* The lowband has to be rescaled */
+ hSbrDec->qmfDomainInCh->scaling.ov_lb_scale = EXP2SCALE(source_exp);
+ } else {
+ /* The highband has to be rescaled */
+ hSbrDec->qmfDomainInCh->scaling.ov_hb_scale = EXP2SCALE(source_exp);
+ }
+ }
+
+ FDK_ASSERT(startBand <= stopBand);
+
+ if (!useLP) {
+ for (l = 0; l < startSlot; l++) {
+ scaleValues(OverlapBufferReal[l] + startBand, stopBand - startBand,
+ -delta_exp);
+ scaleValues(OverlapBufferImag[l] + startBand, stopBand - startBand,
+ -delta_exp);
+ }
+ } else
+ for (l = 0; l < startSlot; l++) {
+ scaleValues(OverlapBufferReal[l] + startBand, stopBand - startBand,
+ -delta_exp);
+ }
+ } /* startSlot != 0 */
+
+ /*
+ Initialize transposer and limiter
+ */
+ sbrError = resetLppTransposer(
+ &hSbrDec->LppTrans, hHeaderData->freqBandData.lowSubband,
+ hHeaderData->freqBandData.v_k_master, hHeaderData->freqBandData.numMaster,
+ hHeaderData->freqBandData.freqBandTableNoise,
+ hHeaderData->freqBandData.nNfb, hHeaderData->freqBandData.highSubband,
+ hHeaderData->sbrProcSmplRate);
+ if (sbrError != SBRDEC_OK) return sbrError;
+
+ hSbrDec->savedStates = 0;
+
+ if ((flags & SBRDEC_USAC_HARMONICSBR) && applySbrProc) {
+ sbrError = QmfTransposerReInit(hSbrDec->hHBE,
+ hHeaderData->freqBandData.freqBandTable,
+ hHeaderData->freqBandData.nSfb);
+ if (sbrError != SBRDEC_OK) return sbrError;
+
+ /* copy saved states from previous frame to legacy SBR lpc filterstate
+ * buffer */
+ for (i = 0; i < LPC_ORDER + hSbrDec->LppTrans.pSettings->overlap; i++) {
+ FDKmemcpy(
+ hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i],
+ hSbrDec->codecQMFBufferReal[hSbrDec->hHBE->noCols - LPC_ORDER -
+ hSbrDec->LppTrans.pSettings->overlap + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ FDKmemcpy(
+ hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i],
+ hSbrDec->codecQMFBufferImag[hSbrDec->hHBE->noCols - LPC_ORDER -
+ hSbrDec->LppTrans.pSettings->overlap + i],
+ hSbrDec->hHBE->noChannels * sizeof(FIXP_DBL));
+ }
+ hSbrDec->savedStates = 1;
+
+ {
+ /* map QMF buffer to pointer array (Overlap + Frame)*/
+ for (i = 0; i < hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER; i++) {
+ pLowBandReal[i] = hSbrDec->LppTrans.lpcFilterStatesRealHBE[i];
+ pLowBandImag[i] = hSbrDec->LppTrans.lpcFilterStatesImagHBE[i];
+ }
+
+ /* map QMF buffer to pointer array (Overlap + Frame)*/
+ for (i = 0; i < hSbrDec->hHBE->noCols; i++) {
+ pLowBandReal[i + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->codecQMFBufferReal[i];
+ pLowBandImag[i + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->codecQMFBufferImag[i];
+ }
+
+ if (flags & SBRDEC_QUAD_RATE) {
+ if (hFrameData->sbrPatchingMode == 0) {
+ int *xOverQmf = GetxOverBandQmfTransposer(hSbrDec->hHBE);
+
+ /* in case of harmonic SBR and no HBE_LP map additional buffer for
+ one more frame to pointer arry */
+ for (i = 0; i < hSbrDec->hHBE->noCols / 2; i++) {
+ pLowBandReal[i + hSbrDec->hHBE->noCols +
+ hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->hQmfHBESlotsReal[i];
+ pLowBandImag[i + hSbrDec->hHBE->noCols +
+ hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->hQmfHBESlotsImag[i];
+ }
+
+ QmfTransposerApply(
+ hSbrDec->hHBE,
+ pLowBandReal + hSbrDec->LppTrans.pSettings->overlap +
+ hSbrDec->hHBE->noCols / 2 + LPC_ORDER,
+ pLowBandImag + hSbrDec->LppTrans.pSettings->overlap +
+ hSbrDec->hHBE->noCols / 2 + LPC_ORDER,
+ hSbrDec->hHBE->noCols, pLowBandReal, pLowBandImag,
+ hSbrDec->LppTrans.lpcFilterStatesRealHBE,
+ hSbrDec->LppTrans.lpcFilterStatesImagHBE,
+ hPrevFrameData->prevSbrPitchInBins, hSbrDec->scale_lb,
+ hSbrDec->scale_hbe, &hSbrDec->qmfDomainInCh->scaling.hb_scale,
+ hHeaderData->timeStep, hFrameData->frameInfo.borders[0],
+ hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_OUTDIFF);
+
+ copyHarmonicSpectrum(
+ xOverQmf, pLowBandReal, pLowBandImag, hSbrDec->hHBE->noCols,
+ hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_OUTDIFF);
+ }
+ } else {
+ /* in case of harmonic SBR and no HBE_LP map additional buffer for
+ one more frame to pointer arry */
+ for (i = 0; i < hSbrDec->hHBE->noCols; i++) {
+ pLowBandReal[i + hSbrDec->hHBE->noCols +
+ hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->hQmfHBESlotsReal[i];
+ pLowBandImag[i + hSbrDec->hHBE->noCols +
+ hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER] =
+ hSbrDec->hQmfHBESlotsImag[i];
+ }
+
+ if (hFrameData->sbrPatchingMode == 0) {
+ QmfTransposerApply(
+ hSbrDec->hHBE,
+ pLowBandReal + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER,
+ pLowBandImag + hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER,
+ hSbrDec->hHBE->noCols, pLowBandReal, pLowBandImag,
+ hSbrDec->LppTrans.lpcFilterStatesRealHBE,
+ hSbrDec->LppTrans.lpcFilterStatesImagHBE,
+ 0 /* not required for keeping states updated in this frame*/,
+ hSbrDec->scale_lb, hSbrDec->scale_lb,
+ &hSbrDec->qmfDomainInCh->scaling.hb_scale, hHeaderData->timeStep,
+ hFrameData->frameInfo.borders[0],
+ hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_NOOUT);
+ }
+
+ QmfTransposerApply(
+ hSbrDec->hHBE,
+ pLowBandReal + hSbrDec->LppTrans.pSettings->overlap +
+ hSbrDec->hHBE->noCols + LPC_ORDER,
+ pLowBandImag + hSbrDec->LppTrans.pSettings->overlap +
+ hSbrDec->hHBE->noCols + LPC_ORDER,
+ hSbrDec->hHBE->noCols, pLowBandReal, pLowBandImag,
+ hSbrDec->LppTrans.lpcFilterStatesRealHBE,
+ hSbrDec->LppTrans.lpcFilterStatesImagHBE,
+ hPrevFrameData->prevSbrPitchInBins, hSbrDec->scale_lb,
+ hSbrDec->scale_hbe, &hSbrDec->qmfDomainInCh->scaling.hb_scale,
+ hHeaderData->timeStep, hFrameData->frameInfo.borders[0],
+ hSbrDec->LppTrans.pSettings->overlap, KEEP_STATES_SYNCED_OUTDIFF);
+ }
+
+ if (hFrameData->sbrPatchingMode == 0) {
+ for (i = startSlot; i < hSbrDec->LppTrans.pSettings->overlap; i++) {
+ /*
+ Store the unmodified qmf Slots values for upper part of spectrum
+ (required for LPC filtering) required if next frame is a HBE frame
+ */
+ FDKmemcpy(hSbrDec->qmfDomainInCh->hQmfSlotsReal[i],
+ hSbrDec->LppTrans.lpcFilterStatesRealHBE[i + LPC_ORDER],
+ (64) * sizeof(FIXP_DBL));
+ FDKmemcpy(hSbrDec->qmfDomainInCh->hQmfSlotsImag[i],
+ hSbrDec->LppTrans.lpcFilterStatesImagHBE[i + LPC_ORDER],
+ (64) * sizeof(FIXP_DBL));
+ }
+
+ for (i = startSlot; i < hSbrDec->LppTrans.pSettings->overlap; i++) {
+ /*
+ Store the unmodified qmf Slots values for upper part of spectrum
+ (required for LPC filtering) required if next frame is a HBE frame
+ */
+ FDKmemcpy(
+ hSbrDec->qmfDomainInCh->hQmfSlotsReal[i],
+ hSbrDec->codecQMFBufferReal[hSbrDec->hHBE->noCols -
+ hSbrDec->LppTrans.pSettings->overlap +
+ i],
+ new_lsb * sizeof(FIXP_DBL));
+ FDKmemcpy(
+ hSbrDec->qmfDomainInCh->hQmfSlotsImag[i],
+ hSbrDec->codecQMFBufferImag[hSbrDec->hHBE->noCols -
+ hSbrDec->LppTrans.pSettings->overlap +
+ i],
+ new_lsb * sizeof(FIXP_DBL));
+ }
+ }
+ }
+ }
+
+ {
+ int adapt_lb = 0, diff = 0,
+ new_scale = hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
+
+ if ((hSbrDec->qmfDomainInCh->scaling.ov_lb_scale !=
+ hSbrDec->qmfDomainInCh->scaling.lb_scale) &&
+ startSlot != 0) {
+ /* we need to adapt spectrum to have equal scale factor, always larger
+ * than zero */
+ diff = SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.ov_lb_scale) -
+ SCALE2EXP(hSbrDec->qmfDomainInCh->scaling.lb_scale);
+
+ if (diff > 0) {
+ adapt_lb = 1;
+ diff = -diff;
+ new_scale = hSbrDec->qmfDomainInCh->scaling.ov_lb_scale;
+ }
+
+ stopBand = new_lsb;
+ }
+
+ if (hFrameData->sbrPatchingMode == 1) {
+ /* scale states from LegSBR filterstates buffer */
+ for (i = 0; i < hSbrDec->LppTrans.pSettings->overlap + LPC_ORDER; i++) {
+ scaleValues(hSbrDec->LppTrans.lpcFilterStatesRealLegSBR[i], new_lsb,
+ diff);
+ if (!useLP) {
+ scaleValues(hSbrDec->LppTrans.lpcFilterStatesImagLegSBR[i], new_lsb,
+ diff);
+ }
+ }
+
+ if (flags & SBRDEC_SYNTAX_USAC) {
+ /* get missing states between old and new x_over from LegSBR
+ * filterstates buffer */
+ /* in case of legacy SBR we leave these values zeroed out */
+ for (i = startSlot; i < hSbrDec->LppTrans.pSettings->overlap; i++) {
+ FDKmemcpy(&OverlapBufferReal[i][old_lsb],
+ &hSbrDec->LppTrans
+ .lpcFilterStatesRealLegSBR[LPC_ORDER + i][old_lsb],
+ fMax(new_lsb - old_lsb, 0) * sizeof(FIXP_DBL));
+ if (!useLP) {
+ FDKmemcpy(&OverlapBufferImag[i][old_lsb],
+ &hSbrDec->LppTrans
+ .lpcFilterStatesImagLegSBR[LPC_ORDER + i][old_lsb],
+ fMax(new_lsb - old_lsb, 0) * sizeof(FIXP_DBL));
+ }
+ }
+ }
+
+ if (new_lsb > old_lsb) {
+ stopBand = old_lsb;
+ }
+ }
+ if ((adapt_lb == 1) && (stopBand > startBand)) {
+ for (l = startSlot; l < hSbrDec->LppTrans.pSettings->overlap; l++) {
+ scaleValues(OverlapBufferReal[l] + startBand, stopBand - startBand,
+ diff);
+ if (!useLP) {
+ scaleValues(OverlapBufferImag[l] + startBand, stopBand - startBand,
+ diff);
+ }
+ }
+ }
+ hSbrDec->qmfDomainInCh->scaling.ov_lb_scale = new_scale;
+ }
+
+ sbrError = ResetLimiterBands(hHeaderData->freqBandData.limiterBandTable,
+ &hHeaderData->freqBandData.noLimiterBands,
+ hHeaderData->freqBandData.freqBandTable[0],
+ hHeaderData->freqBandData.nSfb[0],
+ hSbrDec->LppTrans.pSettings->patchParam,
+ hSbrDec->LppTrans.pSettings->noOfPatches,
+ hHeaderData->bs_data.limiterBands,
+ hFrameData->sbrPatchingMode,
+ GetxOverBandQmfTransposer(hSbrDec->hHBE),
+ Get41SbrQmfTransposer(hSbrDec->hHBE));
+
+ hSbrDec->SbrCalculateEnvelope.sbrPatchingMode = hFrameData->sbrPatchingMode;
+
+ return sbrError;
+}
diff --git a/fdk-aac/libSBRdec/src/sbr_dec.h b/fdk-aac/libSBRdec/src/sbr_dec.h
new file mode 100644
index 0000000..156da03
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbr_dec.h
@@ -0,0 +1,204 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Sbr decoder
+*/
+#ifndef SBR_DEC_H
+#define SBR_DEC_H
+
+#include "sbrdecoder.h"
+
+#include "lpp_tran.h"
+#include "qmf.h"
+#include "env_calc.h"
+#include "FDK_audio.h"
+
+#include "sbrdec_drc.h"
+
+#include "pvc_dec.h"
+
+#include "hbe.h"
+
+enum SBRDEC_QMF_SKIP {
+ qmfSkipNothing = 0,
+ qmfSkipAnalysis = 1 << 0,
+ qmfSkipSynthesis = 1 << 1
+};
+
+typedef struct {
+ SBR_CALCULATE_ENVELOPE SbrCalculateEnvelope;
+ SBR_LPP_TRANS LppTrans;
+ PVC_STATIC_DATA PvcStaticData;
+
+ /* do scale handling in sbr an not in qmf */
+ SHORT scale_ov;
+ SHORT scale_lb;
+ SHORT scale_hbe;
+
+ SHORT prev_frame_lSbr;
+ SHORT prev_frame_hbeSbr;
+
+ int codecFrameSize;
+
+ HANDLE_HBE_TRANSPOSER hHBE;
+
+ HANDLE_FDK_QMF_DOMAIN_IN qmfDomainInCh;
+ HANDLE_FDK_QMF_DOMAIN_OUT qmfDomainOutCh;
+
+ SBRDEC_DRC_CHANNEL sbrDrcChannel;
+
+#if (SBRDEC_MAX_HB_FADE_FRAMES > 0)
+ INT highBandFadeCnt; /* counter for fading in high-band signal smoothly */
+
+#endif
+ FIXP_DBL **tmp_memory; /* shared memory between hbeLightTimeDelayBuffer and
+ hQmfHBESlotsReal */
+
+ FIXP_DBL **hQmfHBESlotsReal;
+ FIXP_DBL **hQmfHBESlotsImag;
+
+ FIXP_DBL **codecQMFBufferReal;
+ FIXP_DBL **codecQMFBufferImag;
+ UCHAR savedStates;
+ int applySbrProc_old;
+} SBR_DEC;
+
+typedef SBR_DEC *HANDLE_SBR_DEC;
+
+typedef struct {
+ SBR_FRAME_DATA frameData[(1) + 1];
+ SBR_PREV_FRAME_DATA prevFrameData;
+ SBR_DEC SbrDec;
+} SBR_CHANNEL;
+
+typedef SBR_CHANNEL *HANDLE_SBR_CHANNEL;
+
+void sbr_dec(
+ HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */
+ INT_PCM *timeIn, /*!< pointer to input time signal */
+ INT_PCM *timeOut, /*!< pointer to output time signal */
+ HANDLE_SBR_DEC hSbrDecRight, /*!< handle to Decoder channel right */
+ INT_PCM *timeOutRight, /*!< pointer to output time signal */
+ INT strideOut, /*!< Time data traversal strideOut */
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Static control data */
+ HANDLE_SBR_FRAME_DATA hFrameData, /*!< Control data of current frame */
+ HANDLE_SBR_PREV_FRAME_DATA
+ hPrevFrameData, /*!< Some control data of last frame */
+ const int applyProcessing, /*!< Flag for SBR operation */
+ HANDLE_PS_DEC h_ps_d, const UINT flags, const int codecFrameSize);
+
+SBR_ERROR
+createSbrDec(SBR_CHANNEL *hSbrChannel, HANDLE_SBR_HEADER_DATA hHeaderData,
+ TRANSPOSER_SETTINGS *pSettings, const int downsampleFac,
+ const UINT qmfFlags, const UINT flags, const int overlap, int chan,
+ int codecFrameSize);
+
+int deleteSbrDec(SBR_CHANNEL *hSbrChannel);
+
+SBR_ERROR
+resetSbrDec(HANDLE_SBR_DEC hSbrDec, HANDLE_SBR_HEADER_DATA hHeaderData,
+ HANDLE_SBR_PREV_FRAME_DATA hPrevFrameData, const int downsampleFac,
+ const UINT flags, HANDLE_SBR_FRAME_DATA hFrameData);
+
+#endif
diff --git a/fdk-aac/libSBRdec/src/sbr_ram.cpp b/fdk-aac/libSBRdec/src/sbr_ram.cpp
new file mode 100644
index 0000000..8b35fd2
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbr_ram.cpp
@@ -0,0 +1,191 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Memory layout
+
+ This module declares all static and dynamic memory spaces
+*/
+
+#include "sbr_ram.h"
+
+#define WORKBUFFER1_TAG 2
+#define WORKBUFFER2_TAG 3
+
+/*!
+ \name StaticSbrData
+
+ Static memory areas, must not be overwritten in other sections of the decoder
+*/
+/* @{ */
+
+/*! SBR Decoder main structure */
+C_ALLOC_MEM(Ram_SbrDecoder, struct SBR_DECODER_INSTANCE, 1)
+/*! SBR Decoder element data <br>
+ Dimension: (8) */
+C_ALLOC_MEM2(Ram_SbrDecElement, SBR_DECODER_ELEMENT, 1, (8))
+/*! SBR Decoder individual channel data <br>
+ Dimension: (8) */
+C_ALLOC_MEM2(Ram_SbrDecChannel, SBR_CHANNEL, 1, (8) + 1)
+
+/*! Static Data of PS */
+
+C_ALLOC_MEM(Ram_ps_dec, struct PS_DEC, 1)
+
+/* @} */
+
+/*!
+ \name DynamicSbrData
+
+ Dynamic memory areas, might be reused in other algorithm sections,
+ e.g. the core decoder
+ <br>
+ Depending on the mode set by DONT_USE_CORE_WORKBUFFER, workbuffers are
+ defined additionally to the CoreWorkbuffer.
+ <br>
+ The size of WorkBuffers is ((1024) / (32) * (4) / 2)*(64) = 2048.
+ <br>
+ WorkBuffer2 is a pointer to the CoreWorkBuffer wich is reused here in the SBR
+ part. In case of DONT_USE_CORE_WORKBUFFER, the CoreWorkbuffer is not used and
+ the according Workbuffer2 is defined locally in this file. <br> WorkBuffer1 is
+ reused in the AAC core (-> aacdecoder.cpp, aac_ram.cpp) <br>
+
+ Use of WorkBuffers:
+ <pre>
+
+ -------------------------------------------------------------
+ AAC core:
+
+ CoreWorkbuffer: spectral coefficients
+ WorkBuffer1: CAacDecoderChannelInfo, CAacDecoderDynamicData
+
+ -------------------------------------------------------------
+ SBR part:
+ ----------------------------------------------
+ Low Power Mode (useLP=1 or LOW_POWER_SBR_ONLY), see assignLcTimeSlots()
+
+ SLOT_BASED_PROTOTYPE_SYN_FILTER
+
+ WorkBuffer1 WorkBuffer2(=CoreWorkbuffer)
+ ________________ ________________
+ | RealLeft | | RealRight |
+ |________________| |________________|
+
+ ----------------------------------------------
+ High Quality Mode (!LOW_POWER_SBR_ONLY and useLP=0), see
+ assignHqTimeSlots()
+
+ SLOTBASED_PS
+
+ WorkBuffer1 WorkBuffer2(=CoreWorkbuffer)
+ ________________ ________________
+ | Real/Imag | interleaved | Real/Imag |
+ interleaved
+ |________________| first half actual ch |________________| second
+ half actual ch
+
+ -------------------------------------------------------------
+
+ </pre>
+
+*/
diff --git a/fdk-aac/libSBRdec/src/sbr_ram.h b/fdk-aac/libSBRdec/src/sbr_ram.h
new file mode 100644
index 0000000..e00f8b5
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbr_ram.h
@@ -0,0 +1,186 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+\file
+\brief Memory layout
+*/
+#ifndef SBR_RAM_H
+#define SBR_RAM_H
+
+#include "sbrdecoder.h"
+
+#include "env_extr.h"
+#include "sbr_dec.h"
+
+#define SBRDEC_MAX_CH_PER_ELEMENT (2)
+
+#define FRAME_OK (0)
+#define FRAME_ERROR (1)
+#define FRAME_ERROR_ALLSLOTS (2)
+
+typedef struct {
+ SBR_CHANNEL *pSbrChannel[SBRDEC_MAX_CH_PER_ELEMENT];
+ TRANSPOSER_SETTINGS
+ transposerSettings; /* Common transport settings for each individual
+ channel of an element */
+ HANDLE_FDK_BITSTREAM hBs;
+
+ MP4_ELEMENT_ID
+ elementID; /* Element ID set during initialization. Can be used for
+ concealment */
+ int nChannels; /* Number of elements output channels (=2 in case of PS) */
+
+ UCHAR frameErrorFlag[(1) + 1]; /* Frame error status (for every slot in the
+ delay line). Will be copied into header at
+ the very beginning of decodeElement()
+ routine. */
+
+ UCHAR useFrameSlot; /* Index which defines which slot will be decoded/filled
+ next (used with additional delay) */
+ UCHAR useHeaderSlot[(1) + 1]; /* Index array that provides the link between
+ header and frame data (important when
+ processing with additional delay). */
+} SBR_DECODER_ELEMENT;
+
+struct SBR_DECODER_INSTANCE {
+ SBR_DECODER_ELEMENT *pSbrElement[(8)];
+ SBR_HEADER_DATA sbrHeader[(
+ 8)][(1) + 1]; /* Sbr header for each individual channel of an element */
+
+ HANDLE_FDK_QMF_DOMAIN pQmfDomain;
+
+ HANDLE_PS_DEC hParametricStereoDec;
+
+ /* Global parameters */
+ AUDIO_OBJECT_TYPE coreCodec; /* AOT of core codec */
+ int numSbrElements;
+ int numSbrChannels;
+ INT sampleRateIn; /* SBR decoder input sampling rate; might be different than
+ the transposer input sampling rate. */
+ INT sampleRateOut; /* Sampling rate of the SBR decoder output audio samples.
+ */
+ USHORT codecFrameSize;
+ UCHAR synDownsampleFac;
+ INT downscaleFactor;
+ UCHAR numDelayFrames; /* The current number of additional delay frames used
+ for processing. */
+ UCHAR harmonicSBR;
+ UCHAR
+ numFlushedFrames; /* The variable counts the number of frames which are
+ flushed consecutively. */
+
+ UINT flags;
+};
+
+H_ALLOC_MEM(Ram_SbrDecElement, SBR_DECODER_ELEMENT)
+H_ALLOC_MEM(Ram_SbrDecChannel, SBR_CHANNEL)
+H_ALLOC_MEM(Ram_SbrDecoder, struct SBR_DECODER_INSTANCE)
+
+H_ALLOC_MEM(Ram_sbr_QmfStatesSynthesis, FIXP_QSS)
+H_ALLOC_MEM(Ram_sbr_OverlapBuffer, FIXP_DBL)
+
+H_ALLOC_MEM(Ram_sbr_HBEOverlapBuffer, FIXP_DBL)
+
+H_ALLOC_MEM(Ram_ps_dec, PS_DEC)
+
+#endif /* SBR_RAM_H */
diff --git a/fdk-aac/libSBRdec/src/sbr_rom.cpp b/fdk-aac/libSBRdec/src/sbr_rom.cpp
new file mode 100644
index 0000000..8a6688a
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbr_rom.cpp
@@ -0,0 +1,1705 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Definition of constant tables
+
+ This module contains most of the constant data that can be stored in ROM.
+*/
+
+#include "sbr_rom.h"
+
+/*!
+ \name StartStopBands
+ \brief Start and stop subbands of the highband.
+
+ k_o = startMin + offset[bs_start_freq];
+ startMin = {3000,4000,5000} * (128/FS_sbr) / FS_sbr < 32Khz, 32Khz <= FS_sbr <
+ 64KHz, 64KHz <= FS_sbr The stop subband can also be calculated to save memory
+ by defining #CALC_STOP_BAND.
+*/
+//@{
+/* tables were created with ../addon/octave/sbr_start_freq_table.m */
+const UCHAR FDK_sbrDecoder_sbr_start_freq_16[][16] = {
+ {16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
+ {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}};
+const UCHAR FDK_sbrDecoder_sbr_start_freq_22[][16] = {
+ {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30},
+ {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22}};
+const UCHAR FDK_sbrDecoder_sbr_start_freq_24[][16] = {
+ {11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32},
+ {3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 19, 21, 24}};
+const UCHAR FDK_sbrDecoder_sbr_start_freq_32[][16] = {
+ {10, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32},
+ {2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 19, 21, 24}};
+const UCHAR FDK_sbrDecoder_sbr_start_freq_40[][16] = {
+ {12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 26, 28, 30, 32},
+ {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 19, 21, 23, 25}};
+const UCHAR FDK_sbrDecoder_sbr_start_freq_44[][16] = {
+ {8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 23, 25, 28, 32},
+ {2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 17, 19, 22, 26}};
+const UCHAR FDK_sbrDecoder_sbr_start_freq_48[][16] = {
+ {7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 27, 31},
+ {1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 21, 25}};
+const UCHAR FDK_sbrDecoder_sbr_start_freq_64[][16] = {
+ {6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 21, 23, 26, 30},
+ {1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 21, 25}};
+const UCHAR FDK_sbrDecoder_sbr_start_freq_88[][16] = {
+ {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 23, 27, 31},
+ {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 24, 28}};
+const UCHAR FDK_sbrDecoder_sbr_start_freq_192[16] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 19, 23, 27};
+const UCHAR FDK_sbrDecoder_sbr_start_freq_176[16] = {
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20, 24, 28};
+const UCHAR FDK_sbrDecoder_sbr_start_freq_128[16] = {
+ 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 21, 25};
+
+//@}
+
+/*!
+ \name Whitening
+ \brief Coefficients for spectral whitening in the transposer
+*/
+//@{
+/*! Assignment of whitening tuning depending on the crossover frequency */
+const USHORT FDK_sbrDecoder_sbr_whFactorsIndex[NUM_WHFACTOR_TABLE_ENTRIES] = {
+ 0, 5000, 6000, 6500, 7000, 7500, 8000, 9000, 10000};
+
+/*!
+ \brief Whithening levels tuning table
+
+ With the current tuning, there are some redundant entries:
+
+ \li NUM_WHFACTOR_TABLE_ENTRIES can be reduced by 3,
+ \li the first coloumn can be eliminated.
+
+*/
+const FIXP_DBL
+ FDK_sbrDecoder_sbr_whFactorsTable[NUM_WHFACTOR_TABLE_ENTRIES][6] = {
+ /* OFF_LEVEL, TRANSITION_LEVEL, LOW_LEVEL, MID_LEVEL, HIGH_LEVEL */
+ {FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f),
+ FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* < 5000 */
+ {FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f),
+ FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 5000 < 6000 */
+ {FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f),
+ FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 6000 < 6500 */
+ {FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f),
+ FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 6500 < 7000 */
+ {FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f),
+ FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 7000 < 7500 */
+ {FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f),
+ FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 7500 < 8000 */
+ {FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f),
+ FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 8000 < 9000 */
+ {FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f),
+ FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* 9000 < 10000 */
+ {FL2FXCONST_DBL(0.00f), FL2FXCONST_DBL(0.6f), FL2FXCONST_DBL(0.75f),
+ FL2FXCONST_DBL(0.90f), FL2FXCONST_DBL(0.98f)}, /* > 10000 */
+};
+
+//@}
+
+/*!
+ \name EnvAdj
+ \brief Constants and tables used for envelope adjustment
+*/
+//@{
+
+/*! Mantissas of gain limits */
+const FIXP_SGL FDK_sbrDecoder_sbr_limGains_m[4] = {
+ FL2FXCONST_SGL(0.5011932025f), /*!< -3 dB. Gain limit when limiterGains in
+ frameData is 0 */
+ FL2FXCONST_SGL(
+ 0.5f), /*!< 0 dB. Gain limit when limiterGains in frameData is 1 */
+ FL2FXCONST_SGL(0.9976346258f), /*!< +3 dB. Gain limit when limiterGains in
+ frameData is 2 */
+ FL2FXCONST_SGL(0.6776263578f) /*!< Inf. Gain limit when limiterGains in
+ frameData is 3 */
+};
+
+/*! Exponents of gain limits */
+const UCHAR FDK_sbrDecoder_sbr_limGains_e[4] = {0, 1, 1, 67};
+
+/*! Constants for calculating the number of limiter bands */
+const FIXP_SGL FDK_sbrDecoder_sbr_limiterBandsPerOctaveDiv4[4] = {
+ FL2FXCONST_SGL(1.0f / 4.0f), FL2FXCONST_SGL(1.2f / 4.0f),
+ FL2FXCONST_SGL(2.0f / 4.0f), FL2FXCONST_SGL(3.0f / 4.0f)};
+
+/*! Constants for calculating the number of limiter bands */
+const FIXP_DBL FDK_sbrDecoder_sbr_limiterBandsPerOctaveDiv4_DBL[4] = {
+ FL2FXCONST_DBL(1.0f / 4.0f), FL2FXCONST_DBL(1.2f / 4.0f),
+ FL2FXCONST_DBL(2.0f / 4.0f), FL2FXCONST_DBL(3.0f / 4.0f)};
+
+/*! Ratio of old gains and noise levels for the first 4 timeslots of an envelope
+ */
+const FIXP_SGL FDK_sbrDecoder_sbr_smoothFilter[4] = {
+ FL2FXCONST_SGL(0.66666666666666f), FL2FXCONST_SGL(0.36516383427084f),
+ FL2FXCONST_SGL(0.14699433520835f), FL2FXCONST_SGL(0.03183050093751f)};
+
+/*! Real and imaginary part of random noise which will be modulated
+ to the desired level. An accuracy of 13 bits is sufficient for these
+ random numbers.
+*/
+const FIXP_SGL FDK_sbrDecoder_sbr_randomPhase[SBR_NF_NO_RANDOM_VAL][2] = {
+ {FL2FXCONST_SGL(-0.99948153278296f / 8.0),
+ FL2FXCONST_SGL(-0.59483417516607f / 8.0)},
+ {FL2FXCONST_SGL(0.97113454393991f / 8.0),
+ FL2FXCONST_SGL(-0.67528515225647f / 8.0)},
+ {FL2FXCONST_SGL(0.14130051758487f / 8.0),
+ FL2FXCONST_SGL(-0.95090983575689f / 8.0)},
+ {FL2FXCONST_SGL(-0.47005496701697f / 8.0),
+ FL2FXCONST_SGL(-0.37340549728647f / 8.0)},
+ {FL2FXCONST_SGL(0.80705063769351f / 8.0),
+ FL2FXCONST_SGL(0.29653668284408f / 8.0)},
+ {FL2FXCONST_SGL(-0.38981478896926f / 8.0),
+ FL2FXCONST_SGL(0.89572605717087f / 8.0)},
+ {FL2FXCONST_SGL(-0.01053049862020f / 8.0),
+ FL2FXCONST_SGL(-0.66959058036166f / 8.0)},
+ {FL2FXCONST_SGL(-0.91266367957293f / 8.0),
+ FL2FXCONST_SGL(-0.11522938140034f / 8.0)},
+ {FL2FXCONST_SGL(0.54840422910309f / 8.0),
+ FL2FXCONST_SGL(0.75221367176302f / 8.0)},
+ {FL2FXCONST_SGL(0.40009252867955f / 8.0),
+ FL2FXCONST_SGL(-0.98929400334421f / 8.0)},
+ {FL2FXCONST_SGL(-0.99867974711855f / 8.0),
+ FL2FXCONST_SGL(-0.88147068645358f / 8.0)},
+ {FL2FXCONST_SGL(-0.95531076805040f / 8.0),
+ FL2FXCONST_SGL(0.90908757154593f / 8.0)},
+ {FL2FXCONST_SGL(-0.45725933317144f / 8.0),
+ FL2FXCONST_SGL(-0.56716323646760f / 8.0)},
+ {FL2FXCONST_SGL(-0.72929675029275f / 8.0),
+ FL2FXCONST_SGL(-0.98008272727324f / 8.0)},
+ {FL2FXCONST_SGL(0.75622801399036f / 8.0),
+ FL2FXCONST_SGL(0.20950329995549f / 8.0)},
+ {FL2FXCONST_SGL(0.07069442601050f / 8.0),
+ FL2FXCONST_SGL(-0.78247898470706f / 8.0)},
+ {FL2FXCONST_SGL(0.74496252926055f / 8.0),
+ FL2FXCONST_SGL(-0.91169004445807f / 8.0)},
+ {FL2FXCONST_SGL(-0.96440182703856f / 8.0),
+ FL2FXCONST_SGL(-0.94739918296622f / 8.0)},
+ {FL2FXCONST_SGL(0.30424629369539f / 8.0),
+ FL2FXCONST_SGL(-0.49438267012479f / 8.0)},
+ {FL2FXCONST_SGL(0.66565033746925f / 8.0),
+ FL2FXCONST_SGL(0.64652935542491f / 8.0)},
+ {FL2FXCONST_SGL(0.91697008020594f / 8.0),
+ FL2FXCONST_SGL(0.17514097332009f / 8.0)},
+ {FL2FXCONST_SGL(-0.70774918760427f / 8.0),
+ FL2FXCONST_SGL(0.52548653416543f / 8.0)},
+ {FL2FXCONST_SGL(-0.70051415345560f / 8.0),
+ FL2FXCONST_SGL(-0.45340028808763f / 8.0)},
+ {FL2FXCONST_SGL(-0.99496513054797f / 8.0),
+ FL2FXCONST_SGL(-0.90071908066973f / 8.0)},
+ {FL2FXCONST_SGL(0.98164490790123f / 8.0),
+ FL2FXCONST_SGL(-0.77463155528697f / 8.0)},
+ {FL2FXCONST_SGL(-0.54671580548181f / 8.0),
+ FL2FXCONST_SGL(-0.02570928536004f / 8.0)},
+ {FL2FXCONST_SGL(-0.01689629065389f / 8.0),
+ FL2FXCONST_SGL(0.00287506445732f / 8.0)},
+ {FL2FXCONST_SGL(-0.86110349531986f / 8.0),
+ FL2FXCONST_SGL(0.42548583726477f / 8.0)},
+ {FL2FXCONST_SGL(-0.98892980586032f / 8.0),
+ FL2FXCONST_SGL(-0.87881132267556f / 8.0)},
+ {FL2FXCONST_SGL(0.51756627678691f / 8.0),
+ FL2FXCONST_SGL(0.66926784710139f / 8.0)},
+ {FL2FXCONST_SGL(-0.99635026409640f / 8.0),
+ FL2FXCONST_SGL(-0.58107730574765f / 8.0)},
+ {FL2FXCONST_SGL(-0.99969370862163f / 8.0),
+ FL2FXCONST_SGL(0.98369989360250f / 8.0)},
+ {FL2FXCONST_SGL(0.55266258627194f / 8.0),
+ FL2FXCONST_SGL(0.59449057465591f / 8.0)},
+ {FL2FXCONST_SGL(0.34581177741673f / 8.0),
+ FL2FXCONST_SGL(0.94879421061866f / 8.0)},
+ {FL2FXCONST_SGL(0.62664209577999f / 8.0),
+ FL2FXCONST_SGL(-0.74402970906471f / 8.0)},
+ {FL2FXCONST_SGL(-0.77149701404973f / 8.0),
+ FL2FXCONST_SGL(-0.33883658042801f / 8.0)},
+ {FL2FXCONST_SGL(-0.91592244254432f / 8.0),
+ FL2FXCONST_SGL(0.03687901376713f / 8.0)},
+ {FL2FXCONST_SGL(-0.76285492357887f / 8.0),
+ FL2FXCONST_SGL(-0.91371867919124f / 8.0)},
+ {FL2FXCONST_SGL(0.79788337195331f / 8.0),
+ FL2FXCONST_SGL(-0.93180971199849f / 8.0)},
+ {FL2FXCONST_SGL(0.54473080610200f / 8.0),
+ FL2FXCONST_SGL(-0.11919206037186f / 8.0)},
+ {FL2FXCONST_SGL(-0.85639281671058f / 8.0),
+ FL2FXCONST_SGL(0.42429854760451f / 8.0)},
+ {FL2FXCONST_SGL(-0.92882402971423f / 8.0),
+ FL2FXCONST_SGL(0.27871809078609f / 8.0)},
+ {FL2FXCONST_SGL(-0.11708371046774f / 8.0),
+ FL2FXCONST_SGL(-0.99800843444966f / 8.0)},
+ {FL2FXCONST_SGL(0.21356749817493f / 8.0),
+ FL2FXCONST_SGL(-0.90716295627033f / 8.0)},
+ {FL2FXCONST_SGL(-0.76191692573909f / 8.0),
+ FL2FXCONST_SGL(0.99768118356265f / 8.0)},
+ {FL2FXCONST_SGL(0.98111043100884f / 8.0),
+ FL2FXCONST_SGL(-0.95854459734407f / 8.0)},
+ {FL2FXCONST_SGL(-0.85913269895572f / 8.0),
+ FL2FXCONST_SGL(0.95766566168880f / 8.0)},
+ {FL2FXCONST_SGL(-0.93307242253692f / 8.0),
+ FL2FXCONST_SGL(0.49431757696466f / 8.0)},
+ {FL2FXCONST_SGL(0.30485754879632f / 8.0),
+ FL2FXCONST_SGL(-0.70540034357529f / 8.0)},
+ {FL2FXCONST_SGL(0.85289650925190f / 8.0),
+ FL2FXCONST_SGL(0.46766131791044f / 8.0)},
+ {FL2FXCONST_SGL(0.91328082618125f / 8.0),
+ FL2FXCONST_SGL(-0.99839597361769f / 8.0)},
+ {FL2FXCONST_SGL(-0.05890199924154f / 8.0),
+ FL2FXCONST_SGL(0.70741827819497f / 8.0)},
+ {FL2FXCONST_SGL(0.28398686150148f / 8.0),
+ FL2FXCONST_SGL(0.34633555702188f / 8.0)},
+ {FL2FXCONST_SGL(0.95258164539612f / 8.0),
+ FL2FXCONST_SGL(-0.54893416026939f / 8.0)},
+ {FL2FXCONST_SGL(-0.78566324168507f / 8.0),
+ FL2FXCONST_SGL(-0.75568541079691f / 8.0)},
+ {FL2FXCONST_SGL(-0.95789495447877f / 8.0),
+ FL2FXCONST_SGL(-0.20423194696966f / 8.0)},
+ {FL2FXCONST_SGL(0.82411158711197f / 8.0),
+ FL2FXCONST_SGL(0.96654618432562f / 8.0)},
+ {FL2FXCONST_SGL(-0.65185446735885f / 8.0),
+ FL2FXCONST_SGL(-0.88734990773289f / 8.0)},
+ {FL2FXCONST_SGL(-0.93643603134666f / 8.0),
+ FL2FXCONST_SGL(0.99870790442385f / 8.0)},
+ {FL2FXCONST_SGL(0.91427159529618f / 8.0),
+ FL2FXCONST_SGL(-0.98290505544444f / 8.0)},
+ {FL2FXCONST_SGL(-0.70395684036886f / 8.0),
+ FL2FXCONST_SGL(0.58796798221039f / 8.0)},
+ {FL2FXCONST_SGL(0.00563771969365f / 8.0),
+ FL2FXCONST_SGL(0.61768196727244f / 8.0)},
+ {FL2FXCONST_SGL(0.89065051931895f / 8.0),
+ FL2FXCONST_SGL(0.52783352697585f / 8.0)},
+ {FL2FXCONST_SGL(-0.68683707712762f / 8.0),
+ FL2FXCONST_SGL(0.80806944710339f / 8.0)},
+ {FL2FXCONST_SGL(0.72165342518718f / 8.0),
+ FL2FXCONST_SGL(-0.69259857349564f / 8.0)},
+ {FL2FXCONST_SGL(-0.62928247730667f / 8.0),
+ FL2FXCONST_SGL(0.13627037407335f / 8.0)},
+ {FL2FXCONST_SGL(0.29938434065514f / 8.0),
+ FL2FXCONST_SGL(-0.46051329682246f / 8.0)},
+ {FL2FXCONST_SGL(-0.91781958879280f / 8.0),
+ FL2FXCONST_SGL(-0.74012716684186f / 8.0)},
+ {FL2FXCONST_SGL(0.99298717043688f / 8.0),
+ FL2FXCONST_SGL(0.40816610075661f / 8.0)},
+ {FL2FXCONST_SGL(0.82368298622748f / 8.0),
+ FL2FXCONST_SGL(-0.74036047190173f / 8.0)},
+ {FL2FXCONST_SGL(-0.98512833386833f / 8.0),
+ FL2FXCONST_SGL(-0.99972330709594f / 8.0)},
+ {FL2FXCONST_SGL(-0.95915368242257f / 8.0),
+ FL2FXCONST_SGL(-0.99237800466040f / 8.0)},
+ {FL2FXCONST_SGL(-0.21411126572790f / 8.0),
+ FL2FXCONST_SGL(-0.93424819052545f / 8.0)},
+ {FL2FXCONST_SGL(-0.68821476106884f / 8.0),
+ FL2FXCONST_SGL(-0.26892306315457f / 8.0)},
+ {FL2FXCONST_SGL(0.91851997982317f / 8.0),
+ FL2FXCONST_SGL(0.09358228901785f / 8.0)},
+ {FL2FXCONST_SGL(-0.96062769559127f / 8.0),
+ FL2FXCONST_SGL(0.36099095133739f / 8.0)},
+ {FL2FXCONST_SGL(0.51646184922287f / 8.0),
+ FL2FXCONST_SGL(-0.71373332873917f / 8.0)},
+ {FL2FXCONST_SGL(0.61130721139669f / 8.0),
+ FL2FXCONST_SGL(0.46950141175917f / 8.0)},
+ {FL2FXCONST_SGL(0.47336129371299f / 8.0),
+ FL2FXCONST_SGL(-0.27333178296162f / 8.0)},
+ {FL2FXCONST_SGL(0.90998308703519f / 8.0),
+ FL2FXCONST_SGL(0.96715662938132f / 8.0)},
+ {FL2FXCONST_SGL(0.44844799194357f / 8.0),
+ FL2FXCONST_SGL(0.99211574628306f / 8.0)},
+ {FL2FXCONST_SGL(0.66614891079092f / 8.0),
+ FL2FXCONST_SGL(0.96590176169121f / 8.0)},
+ {FL2FXCONST_SGL(0.74922239129237f / 8.0),
+ FL2FXCONST_SGL(-0.89879858826087f / 8.0)},
+ {FL2FXCONST_SGL(-0.99571588506485f / 8.0),
+ FL2FXCONST_SGL(0.52785521494349f / 8.0)},
+ {FL2FXCONST_SGL(0.97401082477563f / 8.0),
+ FL2FXCONST_SGL(-0.16855870075190f / 8.0)},
+ {FL2FXCONST_SGL(0.72683747733879f / 8.0),
+ FL2FXCONST_SGL(-0.48060774432251f / 8.0)},
+ {FL2FXCONST_SGL(0.95432193457128f / 8.0),
+ FL2FXCONST_SGL(0.68849603408441f / 8.0)},
+ {FL2FXCONST_SGL(-0.72962208425191f / 8.0),
+ FL2FXCONST_SGL(-0.76608443420917f / 8.0)},
+ {FL2FXCONST_SGL(-0.85359479233537f / 8.0),
+ FL2FXCONST_SGL(0.88738125901579f / 8.0)},
+ {FL2FXCONST_SGL(-0.81412430338535f / 8.0),
+ FL2FXCONST_SGL(-0.97480768049637f / 8.0)},
+ {FL2FXCONST_SGL(-0.87930772356786f / 8.0),
+ FL2FXCONST_SGL(0.74748307690436f / 8.0)},
+ {FL2FXCONST_SGL(-0.71573331064977f / 8.0),
+ FL2FXCONST_SGL(-0.98570608178923f / 8.0)},
+ {FL2FXCONST_SGL(0.83524300028228f / 8.0),
+ FL2FXCONST_SGL(0.83702537075163f / 8.0)},
+ {FL2FXCONST_SGL(-0.48086065601423f / 8.0),
+ FL2FXCONST_SGL(-0.98848504923531f / 8.0)},
+ {FL2FXCONST_SGL(0.97139128574778f / 8.0),
+ FL2FXCONST_SGL(0.80093621198236f / 8.0)},
+ {FL2FXCONST_SGL(0.51992825347895f / 8.0),
+ FL2FXCONST_SGL(0.80247631400510f / 8.0)},
+ {FL2FXCONST_SGL(-0.00848591195325f / 8.0),
+ FL2FXCONST_SGL(-0.76670128000486f / 8.0)},
+ {FL2FXCONST_SGL(-0.70294374303036f / 8.0),
+ FL2FXCONST_SGL(0.55359910445577f / 8.0)},
+ {FL2FXCONST_SGL(-0.95894428168140f / 8.0),
+ FL2FXCONST_SGL(-0.43265504344783f / 8.0)},
+ {FL2FXCONST_SGL(0.97079252950321f / 8.0),
+ FL2FXCONST_SGL(0.09325857238682f / 8.0)},
+ {FL2FXCONST_SGL(-0.92404293670797f / 8.0),
+ FL2FXCONST_SGL(0.85507704027855f / 8.0)},
+ {FL2FXCONST_SGL(-0.69506469500450f / 8.0),
+ FL2FXCONST_SGL(0.98633412625459f / 8.0)},
+ {FL2FXCONST_SGL(0.26559203620024f / 8.0),
+ FL2FXCONST_SGL(0.73314307966524f / 8.0)},
+ {FL2FXCONST_SGL(0.28038443336943f / 8.0),
+ FL2FXCONST_SGL(0.14537913654427f / 8.0)},
+ {FL2FXCONST_SGL(-0.74138124825523f / 8.0),
+ FL2FXCONST_SGL(0.99310339807762f / 8.0)},
+ {FL2FXCONST_SGL(-0.01752795995444f / 8.0),
+ FL2FXCONST_SGL(-0.82616635284178f / 8.0)},
+ {FL2FXCONST_SGL(-0.55126773094930f / 8.0),
+ FL2FXCONST_SGL(-0.98898543862153f / 8.0)},
+ {FL2FXCONST_SGL(0.97960898850996f / 8.0),
+ FL2FXCONST_SGL(-0.94021446752851f / 8.0)},
+ {FL2FXCONST_SGL(-0.99196309146936f / 8.0),
+ FL2FXCONST_SGL(0.67019017358456f / 8.0)},
+ {FL2FXCONST_SGL(-0.67684928085260f / 8.0),
+ FL2FXCONST_SGL(0.12631491649378f / 8.0)},
+ {FL2FXCONST_SGL(0.09140039465500f / 8.0),
+ FL2FXCONST_SGL(-0.20537731453108f / 8.0)},
+ {FL2FXCONST_SGL(-0.71658965751996f / 8.0),
+ FL2FXCONST_SGL(-0.97788200391224f / 8.0)},
+ {FL2FXCONST_SGL(0.81014640078925f / 8.0),
+ FL2FXCONST_SGL(0.53722648362443f / 8.0)},
+ {FL2FXCONST_SGL(0.40616991671205f / 8.0),
+ FL2FXCONST_SGL(-0.26469008598449f / 8.0)},
+ {FL2FXCONST_SGL(-0.67680188682972f / 8.0),
+ FL2FXCONST_SGL(0.94502052337695f / 8.0)},
+ {FL2FXCONST_SGL(0.86849774348749f / 8.0),
+ FL2FXCONST_SGL(-0.18333598647899f / 8.0)},
+ {FL2FXCONST_SGL(-0.99500381284851f / 8.0),
+ FL2FXCONST_SGL(-0.02634122068550f / 8.0)},
+ {FL2FXCONST_SGL(0.84329189340667f / 8.0),
+ FL2FXCONST_SGL(0.10406957462213f / 8.0)},
+ {FL2FXCONST_SGL(-0.09215968531446f / 8.0),
+ FL2FXCONST_SGL(0.69540012101253f / 8.0)},
+ {FL2FXCONST_SGL(0.99956173327206f / 8.0),
+ FL2FXCONST_SGL(-0.12358542001404f / 8.0)},
+ {FL2FXCONST_SGL(-0.79732779473535f / 8.0),
+ FL2FXCONST_SGL(-0.91582524736159f / 8.0)},
+ {FL2FXCONST_SGL(0.96349973642406f / 8.0),
+ FL2FXCONST_SGL(0.96640458041000f / 8.0)},
+ {FL2FXCONST_SGL(-0.79942778496547f / 8.0),
+ FL2FXCONST_SGL(0.64323902822857f / 8.0)},
+ {FL2FXCONST_SGL(-0.11566039853896f / 8.0),
+ FL2FXCONST_SGL(0.28587846253726f / 8.0)},
+ {FL2FXCONST_SGL(-0.39922954514662f / 8.0),
+ FL2FXCONST_SGL(0.94129601616966f / 8.0)},
+ {FL2FXCONST_SGL(0.99089197565987f / 8.0),
+ FL2FXCONST_SGL(-0.92062625581587f / 8.0)},
+ {FL2FXCONST_SGL(0.28631285179909f / 8.0),
+ FL2FXCONST_SGL(-0.91035047143603f / 8.0)},
+ {FL2FXCONST_SGL(-0.83302725605608f / 8.0),
+ FL2FXCONST_SGL(-0.67330410892084f / 8.0)},
+ {FL2FXCONST_SGL(0.95404443402072f / 8.0),
+ FL2FXCONST_SGL(0.49162765398743f / 8.0)},
+ {FL2FXCONST_SGL(-0.06449863579434f / 8.0),
+ FL2FXCONST_SGL(0.03250560813135f / 8.0)},
+ {FL2FXCONST_SGL(-0.99575054486311f / 8.0),
+ FL2FXCONST_SGL(0.42389784469507f / 8.0)},
+ {FL2FXCONST_SGL(-0.65501142790847f / 8.0),
+ FL2FXCONST_SGL(0.82546114655624f / 8.0)},
+ {FL2FXCONST_SGL(-0.81254441908887f / 8.0),
+ FL2FXCONST_SGL(-0.51627234660629f / 8.0)},
+ {FL2FXCONST_SGL(-0.99646369485481f / 8.0),
+ FL2FXCONST_SGL(0.84490533520752f / 8.0)},
+ {FL2FXCONST_SGL(0.00287840603348f / 8.0),
+ FL2FXCONST_SGL(0.64768261158166f / 8.0)},
+ {FL2FXCONST_SGL(0.70176989408455f / 8.0),
+ FL2FXCONST_SGL(-0.20453028573322f / 8.0)},
+ {FL2FXCONST_SGL(0.96361882270190f / 8.0),
+ FL2FXCONST_SGL(0.40706967140989f / 8.0)},
+ {FL2FXCONST_SGL(-0.68883758192426f / 8.0),
+ FL2FXCONST_SGL(0.91338958840772f / 8.0)},
+ {FL2FXCONST_SGL(-0.34875585502238f / 8.0),
+ FL2FXCONST_SGL(0.71472290693300f / 8.0)},
+ {FL2FXCONST_SGL(0.91980081243087f / 8.0),
+ FL2FXCONST_SGL(0.66507455644919f / 8.0)},
+ {FL2FXCONST_SGL(-0.99009048343881f / 8.0),
+ FL2FXCONST_SGL(0.85868021604848f / 8.0)},
+ {FL2FXCONST_SGL(0.68865791458395f / 8.0),
+ FL2FXCONST_SGL(0.55660316809678f / 8.0)},
+ {FL2FXCONST_SGL(-0.99484402129368f / 8.0),
+ FL2FXCONST_SGL(-0.20052559254934f / 8.0)},
+ {FL2FXCONST_SGL(0.94214511408023f / 8.0),
+ FL2FXCONST_SGL(-0.99696425367461f / 8.0)},
+ {FL2FXCONST_SGL(-0.67414626793544f / 8.0),
+ FL2FXCONST_SGL(0.49548221180078f / 8.0)},
+ {FL2FXCONST_SGL(-0.47339353684664f / 8.0),
+ FL2FXCONST_SGL(-0.85904328834047f / 8.0)},
+ {FL2FXCONST_SGL(0.14323651387360f / 8.0),
+ FL2FXCONST_SGL(-0.94145598222488f / 8.0)},
+ {FL2FXCONST_SGL(-0.29268293575672f / 8.0),
+ FL2FXCONST_SGL(0.05759224927952f / 8.0)},
+ {FL2FXCONST_SGL(0.43793861458754f / 8.0),
+ FL2FXCONST_SGL(-0.78904969892724f / 8.0)},
+ {FL2FXCONST_SGL(-0.36345126374441f / 8.0),
+ FL2FXCONST_SGL(0.64874435357162f / 8.0)},
+ {FL2FXCONST_SGL(-0.08750604656825f / 8.0),
+ FL2FXCONST_SGL(0.97686944362527f / 8.0)},
+ {FL2FXCONST_SGL(-0.96495267812511f / 8.0),
+ FL2FXCONST_SGL(-0.53960305946511f / 8.0)},
+ {FL2FXCONST_SGL(0.55526940659947f / 8.0),
+ FL2FXCONST_SGL(0.78891523734774f / 8.0)},
+ {FL2FXCONST_SGL(0.73538215752630f / 8.0),
+ FL2FXCONST_SGL(0.96452072373404f / 8.0)},
+ {FL2FXCONST_SGL(-0.30889773919437f / 8.0),
+ FL2FXCONST_SGL(-0.80664389776860f / 8.0)},
+ {FL2FXCONST_SGL(0.03574995626194f / 8.0),
+ FL2FXCONST_SGL(-0.97325616900959f / 8.0)},
+ {FL2FXCONST_SGL(0.98720684660488f / 8.0),
+ FL2FXCONST_SGL(0.48409133691962f / 8.0)},
+ {FL2FXCONST_SGL(-0.81689296271203f / 8.0),
+ FL2FXCONST_SGL(-0.90827703628298f / 8.0)},
+ {FL2FXCONST_SGL(0.67866860118215f / 8.0),
+ FL2FXCONST_SGL(0.81284503870856f / 8.0)},
+ {FL2FXCONST_SGL(-0.15808569732583f / 8.0),
+ FL2FXCONST_SGL(0.85279555024382f / 8.0)},
+ {FL2FXCONST_SGL(0.80723395114371f / 8.0),
+ FL2FXCONST_SGL(-0.24717418514605f / 8.0)},
+ {FL2FXCONST_SGL(0.47788757329038f / 8.0),
+ FL2FXCONST_SGL(-0.46333147839295f / 8.0)},
+ {FL2FXCONST_SGL(0.96367554763201f / 8.0),
+ FL2FXCONST_SGL(0.38486749303242f / 8.0)},
+ {FL2FXCONST_SGL(-0.99143875716818f / 8.0),
+ FL2FXCONST_SGL(-0.24945277239809f / 8.0)},
+ {FL2FXCONST_SGL(0.83081876925833f / 8.0),
+ FL2FXCONST_SGL(-0.94780851414763f / 8.0)},
+ {FL2FXCONST_SGL(-0.58753191905341f / 8.0),
+ FL2FXCONST_SGL(0.01290772389163f / 8.0)},
+ {FL2FXCONST_SGL(0.95538108220960f / 8.0),
+ FL2FXCONST_SGL(-0.85557052096538f / 8.0)},
+ {FL2FXCONST_SGL(-0.96490920476211f / 8.0),
+ FL2FXCONST_SGL(-0.64020970923102f / 8.0)},
+ {FL2FXCONST_SGL(-0.97327101028521f / 8.0),
+ FL2FXCONST_SGL(0.12378128133110f / 8.0)},
+ {FL2FXCONST_SGL(0.91400366022124f / 8.0),
+ FL2FXCONST_SGL(0.57972471346930f / 8.0)},
+ {FL2FXCONST_SGL(-0.99925837363824f / 8.0),
+ FL2FXCONST_SGL(0.71084847864067f / 8.0)},
+ {FL2FXCONST_SGL(-0.86875903507313f / 8.0),
+ FL2FXCONST_SGL(-0.20291699203564f / 8.0)},
+ {FL2FXCONST_SGL(-0.26240034795124f / 8.0),
+ FL2FXCONST_SGL(-0.68264554369108f / 8.0)},
+ {FL2FXCONST_SGL(-0.24664412953388f / 8.0),
+ FL2FXCONST_SGL(-0.87642273115183f / 8.0)},
+ {FL2FXCONST_SGL(0.02416275806869f / 8.0),
+ FL2FXCONST_SGL(0.27192914288905f / 8.0)},
+ {FL2FXCONST_SGL(0.82068619590515f / 8.0),
+ FL2FXCONST_SGL(-0.85087787994476f / 8.0)},
+ {FL2FXCONST_SGL(0.88547373760759f / 8.0),
+ FL2FXCONST_SGL(-0.89636802901469f / 8.0)},
+ {FL2FXCONST_SGL(-0.18173078152226f / 8.0),
+ FL2FXCONST_SGL(-0.26152145156800f / 8.0)},
+ {FL2FXCONST_SGL(0.09355476558534f / 8.0),
+ FL2FXCONST_SGL(0.54845123045604f / 8.0)},
+ {FL2FXCONST_SGL(-0.54668414224090f / 8.0),
+ FL2FXCONST_SGL(0.95980774020221f / 8.0)},
+ {FL2FXCONST_SGL(0.37050990604091f / 8.0),
+ FL2FXCONST_SGL(-0.59910140383171f / 8.0)},
+ {FL2FXCONST_SGL(-0.70373594262891f / 8.0),
+ FL2FXCONST_SGL(0.91227665827081f / 8.0)},
+ {FL2FXCONST_SGL(-0.34600785879594f / 8.0),
+ FL2FXCONST_SGL(-0.99441426144200f / 8.0)},
+ {FL2FXCONST_SGL(-0.68774481731008f / 8.0),
+ FL2FXCONST_SGL(-0.30238837956299f / 8.0)},
+ {FL2FXCONST_SGL(-0.26843291251234f / 8.0),
+ FL2FXCONST_SGL(0.83115668004362f / 8.0)},
+ {FL2FXCONST_SGL(0.49072334613242f / 8.0),
+ FL2FXCONST_SGL(-0.45359708737775f / 8.0)},
+ {FL2FXCONST_SGL(0.38975993093975f / 8.0),
+ FL2FXCONST_SGL(0.95515358099121f / 8.0)},
+ {FL2FXCONST_SGL(-0.97757125224150f / 8.0),
+ FL2FXCONST_SGL(0.05305894580606f / 8.0)},
+ {FL2FXCONST_SGL(-0.17325552859616f / 8.0),
+ FL2FXCONST_SGL(-0.92770672250494f / 8.0)},
+ {FL2FXCONST_SGL(0.99948035025744f / 8.0),
+ FL2FXCONST_SGL(0.58285545563426f / 8.0)},
+ {FL2FXCONST_SGL(-0.64946246527458f / 8.0),
+ FL2FXCONST_SGL(0.68645507104960f / 8.0)},
+ {FL2FXCONST_SGL(-0.12016920576437f / 8.0),
+ FL2FXCONST_SGL(-0.57147322153312f / 8.0)},
+ {FL2FXCONST_SGL(-0.58947456517751f / 8.0),
+ FL2FXCONST_SGL(-0.34847132454388f / 8.0)},
+ {FL2FXCONST_SGL(-0.41815140454465f / 8.0),
+ FL2FXCONST_SGL(0.16276422358861f / 8.0)},
+ {FL2FXCONST_SGL(0.99885650204884f / 8.0),
+ FL2FXCONST_SGL(0.11136095490444f / 8.0)},
+ {FL2FXCONST_SGL(-0.56649614128386f / 8.0),
+ FL2FXCONST_SGL(-0.90494866361587f / 8.0)},
+ {FL2FXCONST_SGL(0.94138021032330f / 8.0),
+ FL2FXCONST_SGL(0.35281916733018f / 8.0)},
+ {FL2FXCONST_SGL(-0.75725076534641f / 8.0),
+ FL2FXCONST_SGL(0.53650549640587f / 8.0)},
+ {FL2FXCONST_SGL(0.20541973692630f / 8.0),
+ FL2FXCONST_SGL(-0.94435144369918f / 8.0)},
+ {FL2FXCONST_SGL(0.99980371023351f / 8.0),
+ FL2FXCONST_SGL(0.79835913565599f / 8.0)},
+ {FL2FXCONST_SGL(0.29078277605775f / 8.0),
+ FL2FXCONST_SGL(0.35393777921520f / 8.0)},
+ {FL2FXCONST_SGL(-0.62858772103030f / 8.0),
+ FL2FXCONST_SGL(0.38765693387102f / 8.0)},
+ {FL2FXCONST_SGL(0.43440904467688f / 8.0),
+ FL2FXCONST_SGL(-0.98546330463232f / 8.0)},
+ {FL2FXCONST_SGL(-0.98298583762390f / 8.0),
+ FL2FXCONST_SGL(0.21021524625209f / 8.0)},
+ {FL2FXCONST_SGL(0.19513029146934f / 8.0),
+ FL2FXCONST_SGL(-0.94239832251867f / 8.0)},
+ {FL2FXCONST_SGL(-0.95476662400101f / 8.0),
+ FL2FXCONST_SGL(0.98364554179143f / 8.0)},
+ {FL2FXCONST_SGL(0.93379635304810f / 8.0),
+ FL2FXCONST_SGL(-0.70881994583682f / 8.0)},
+ {FL2FXCONST_SGL(-0.85235410573336f / 8.0),
+ FL2FXCONST_SGL(-0.08342347966410f / 8.0)},
+ {FL2FXCONST_SGL(-0.86425093011245f / 8.0),
+ FL2FXCONST_SGL(-0.45795025029466f / 8.0)},
+ {FL2FXCONST_SGL(0.38879779059045f / 8.0),
+ FL2FXCONST_SGL(0.97274429344593f / 8.0)},
+ {FL2FXCONST_SGL(0.92045124735495f / 8.0),
+ FL2FXCONST_SGL(-0.62433652524220f / 8.0)},
+ {FL2FXCONST_SGL(0.89162532251878f / 8.0),
+ FL2FXCONST_SGL(0.54950955570563f / 8.0)},
+ {FL2FXCONST_SGL(-0.36834336949252f / 8.0),
+ FL2FXCONST_SGL(0.96458298020975f / 8.0)},
+ {FL2FXCONST_SGL(0.93891760988045f / 8.0),
+ FL2FXCONST_SGL(-0.89968353740388f / 8.0)},
+ {FL2FXCONST_SGL(0.99267657565094f / 8.0),
+ FL2FXCONST_SGL(-0.03757034316958f / 8.0)},
+ {FL2FXCONST_SGL(-0.94063471614176f / 8.0),
+ FL2FXCONST_SGL(0.41332338538963f / 8.0)},
+ {FL2FXCONST_SGL(0.99740224117019f / 8.0),
+ FL2FXCONST_SGL(-0.16830494996370f / 8.0)},
+ {FL2FXCONST_SGL(-0.35899413170555f / 8.0),
+ FL2FXCONST_SGL(-0.46633226649613f / 8.0)},
+ {FL2FXCONST_SGL(0.05237237274947f / 8.0),
+ FL2FXCONST_SGL(-0.25640361602661f / 8.0)},
+ {FL2FXCONST_SGL(0.36703583957424f / 8.0),
+ FL2FXCONST_SGL(-0.38653265641875f / 8.0)},
+ {FL2FXCONST_SGL(0.91653180367913f / 8.0),
+ FL2FXCONST_SGL(-0.30587628726597f / 8.0)},
+ {FL2FXCONST_SGL(0.69000803499316f / 8.0),
+ FL2FXCONST_SGL(0.90952171386132f / 8.0)},
+ {FL2FXCONST_SGL(-0.38658751133527f / 8.0),
+ FL2FXCONST_SGL(0.99501571208985f / 8.0)},
+ {FL2FXCONST_SGL(-0.29250814029851f / 8.0),
+ FL2FXCONST_SGL(0.37444994344615f / 8.0)},
+ {FL2FXCONST_SGL(-0.60182204677608f / 8.0),
+ FL2FXCONST_SGL(0.86779651036123f / 8.0)},
+ {FL2FXCONST_SGL(-0.97418588163217f / 8.0),
+ FL2FXCONST_SGL(0.96468523666475f / 8.0)},
+ {FL2FXCONST_SGL(0.88461574003963f / 8.0),
+ FL2FXCONST_SGL(0.57508405276414f / 8.0)},
+ {FL2FXCONST_SGL(0.05198933055162f / 8.0),
+ FL2FXCONST_SGL(0.21269661669964f / 8.0)},
+ {FL2FXCONST_SGL(-0.53499621979720f / 8.0),
+ FL2FXCONST_SGL(0.97241553731237f / 8.0)},
+ {FL2FXCONST_SGL(-0.49429560226497f / 8.0),
+ FL2FXCONST_SGL(0.98183865291903f / 8.0)},
+ {FL2FXCONST_SGL(-0.98935142339139f / 8.0),
+ FL2FXCONST_SGL(-0.40249159006933f / 8.0)},
+ {FL2FXCONST_SGL(-0.98081380091130f / 8.0),
+ FL2FXCONST_SGL(-0.72856895534041f / 8.0)},
+ {FL2FXCONST_SGL(-0.27338148835532f / 8.0),
+ FL2FXCONST_SGL(0.99950922447209f / 8.0)},
+ {FL2FXCONST_SGL(0.06310802338302f / 8.0),
+ FL2FXCONST_SGL(-0.54539587529618f / 8.0)},
+ {FL2FXCONST_SGL(-0.20461677199539f / 8.0),
+ FL2FXCONST_SGL(-0.14209977628489f / 8.0)},
+ {FL2FXCONST_SGL(0.66223843141647f / 8.0),
+ FL2FXCONST_SGL(0.72528579940326f / 8.0)},
+ {FL2FXCONST_SGL(-0.84764345483665f / 8.0),
+ FL2FXCONST_SGL(0.02372316801261f / 8.0)},
+ {FL2FXCONST_SGL(-0.89039863483811f / 8.0),
+ FL2FXCONST_SGL(0.88866581484602f / 8.0)},
+ {FL2FXCONST_SGL(0.95903308477986f / 8.0),
+ FL2FXCONST_SGL(0.76744927173873f / 8.0)},
+ {FL2FXCONST_SGL(0.73504123909879f / 8.0),
+ FL2FXCONST_SGL(-0.03747203173192f / 8.0)},
+ {FL2FXCONST_SGL(-0.31744434966056f / 8.0),
+ FL2FXCONST_SGL(-0.36834111883652f / 8.0)},
+ {FL2FXCONST_SGL(-0.34110827591623f / 8.0),
+ FL2FXCONST_SGL(0.40211222807691f / 8.0)},
+ {FL2FXCONST_SGL(0.47803883714199f / 8.0),
+ FL2FXCONST_SGL(-0.39423219786288f / 8.0)},
+ {FL2FXCONST_SGL(0.98299195879514f / 8.0),
+ FL2FXCONST_SGL(0.01989791390047f / 8.0)},
+ {FL2FXCONST_SGL(-0.30963073129751f / 8.0),
+ FL2FXCONST_SGL(-0.18076720599336f / 8.0)},
+ {FL2FXCONST_SGL(0.99992588229018f / 8.0),
+ FL2FXCONST_SGL(-0.26281872094289f / 8.0)},
+ {FL2FXCONST_SGL(-0.93149731080767f / 8.0),
+ FL2FXCONST_SGL(-0.98313162570490f / 8.0)},
+ {FL2FXCONST_SGL(0.99923472302773f / 8.0),
+ FL2FXCONST_SGL(-0.80142993767554f / 8.0)},
+ {FL2FXCONST_SGL(-0.26024169633417f / 8.0),
+ FL2FXCONST_SGL(-0.75999759855752f / 8.0)},
+ {FL2FXCONST_SGL(-0.35712514743563f / 8.0),
+ FL2FXCONST_SGL(0.19298963768574f / 8.0)},
+ {FL2FXCONST_SGL(-0.99899084509530f / 8.0),
+ FL2FXCONST_SGL(0.74645156992493f / 8.0)},
+ {FL2FXCONST_SGL(0.86557171579452f / 8.0),
+ FL2FXCONST_SGL(0.55593866696299f / 8.0)},
+ {FL2FXCONST_SGL(0.33408042438752f / 8.0),
+ FL2FXCONST_SGL(0.86185953874709f / 8.0)},
+ {FL2FXCONST_SGL(0.99010736374716f / 8.0),
+ FL2FXCONST_SGL(0.04602397576623f / 8.0)},
+ {FL2FXCONST_SGL(-0.66694269691195f / 8.0),
+ FL2FXCONST_SGL(-0.91643611810148f / 8.0)},
+ {FL2FXCONST_SGL(0.64016792079480f / 8.0),
+ FL2FXCONST_SGL(0.15649530836856f / 8.0)},
+ {FL2FXCONST_SGL(0.99570534804836f / 8.0),
+ FL2FXCONST_SGL(0.45844586038111f / 8.0)},
+ {FL2FXCONST_SGL(-0.63431466947340f / 8.0),
+ FL2FXCONST_SGL(0.21079116459234f / 8.0)},
+ {FL2FXCONST_SGL(-0.07706847005931f / 8.0),
+ FL2FXCONST_SGL(-0.89581437101329f / 8.0)},
+ {FL2FXCONST_SGL(0.98590090577724f / 8.0),
+ FL2FXCONST_SGL(0.88241721133981f / 8.0)},
+ {FL2FXCONST_SGL(0.80099335254678f / 8.0),
+ FL2FXCONST_SGL(-0.36851896710853f / 8.0)},
+ {FL2FXCONST_SGL(0.78368131392666f / 8.0),
+ FL2FXCONST_SGL(0.45506999802597f / 8.0)},
+ {FL2FXCONST_SGL(0.08707806671691f / 8.0),
+ FL2FXCONST_SGL(0.80938994918745f / 8.0)},
+ {FL2FXCONST_SGL(-0.86811883080712f / 8.0),
+ FL2FXCONST_SGL(0.39347308654705f / 8.0)},
+ {FL2FXCONST_SGL(-0.39466529740375f / 8.0),
+ FL2FXCONST_SGL(-0.66809432114456f / 8.0)},
+ {FL2FXCONST_SGL(0.97875325649683f / 8.0),
+ FL2FXCONST_SGL(-0.72467840967746f / 8.0)},
+ {FL2FXCONST_SGL(-0.95038560288864f / 8.0),
+ FL2FXCONST_SGL(0.89563219587625f / 8.0)},
+ {FL2FXCONST_SGL(0.17005239424212f / 8.0),
+ FL2FXCONST_SGL(0.54683053962658f / 8.0)},
+ {FL2FXCONST_SGL(-0.76910792026848f / 8.0),
+ FL2FXCONST_SGL(-0.96226617549298f / 8.0)},
+ {FL2FXCONST_SGL(0.99743281016846f / 8.0),
+ FL2FXCONST_SGL(0.42697157037567f / 8.0)},
+ {FL2FXCONST_SGL(0.95437383549973f / 8.0),
+ FL2FXCONST_SGL(0.97002324109952f / 8.0)},
+ {FL2FXCONST_SGL(0.99578905365569f / 8.0),
+ FL2FXCONST_SGL(-0.54106826257356f / 8.0)},
+ {FL2FXCONST_SGL(0.28058259829990f / 8.0),
+ FL2FXCONST_SGL(-0.85361420634036f / 8.0)},
+ {FL2FXCONST_SGL(0.85256524470573f / 8.0),
+ FL2FXCONST_SGL(-0.64567607735589f / 8.0)},
+ {FL2FXCONST_SGL(-0.50608540105128f / 8.0),
+ FL2FXCONST_SGL(-0.65846015480300f / 8.0)},
+ {FL2FXCONST_SGL(-0.97210735183243f / 8.0),
+ FL2FXCONST_SGL(-0.23095213067791f / 8.0)},
+ {FL2FXCONST_SGL(0.95424048234441f / 8.0),
+ FL2FXCONST_SGL(-0.99240147091219f / 8.0)},
+ {FL2FXCONST_SGL(-0.96926570524023f / 8.0),
+ FL2FXCONST_SGL(0.73775654896574f / 8.0)},
+ {FL2FXCONST_SGL(0.30872163214726f / 8.0),
+ FL2FXCONST_SGL(0.41514960556126f / 8.0)},
+ {FL2FXCONST_SGL(-0.24523839572639f / 8.0),
+ FL2FXCONST_SGL(0.63206633394807f / 8.0)},
+ {FL2FXCONST_SGL(-0.33813265086024f / 8.0),
+ FL2FXCONST_SGL(-0.38661779441897f / 8.0)},
+ {FL2FXCONST_SGL(-0.05826828420146f / 8.0),
+ FL2FXCONST_SGL(-0.06940774188029f / 8.0)},
+ {FL2FXCONST_SGL(-0.22898461455054f / 8.0),
+ FL2FXCONST_SGL(0.97054853316316f / 8.0)},
+ {FL2FXCONST_SGL(-0.18509915019881f / 8.0),
+ FL2FXCONST_SGL(0.47565762892084f / 8.0)},
+ {FL2FXCONST_SGL(-0.10488238045009f / 8.0),
+ FL2FXCONST_SGL(-0.87769947402394f / 8.0)},
+ {FL2FXCONST_SGL(-0.71886586182037f / 8.0),
+ FL2FXCONST_SGL(0.78030982480538f / 8.0)},
+ {FL2FXCONST_SGL(0.99793873738654f / 8.0),
+ FL2FXCONST_SGL(0.90041310491497f / 8.0)},
+ {FL2FXCONST_SGL(0.57563307626120f / 8.0),
+ FL2FXCONST_SGL(-0.91034337352097f / 8.0)},
+ {FL2FXCONST_SGL(0.28909646383717f / 8.0),
+ FL2FXCONST_SGL(0.96307783970534f / 8.0)},
+ {FL2FXCONST_SGL(0.42188998312520f / 8.0),
+ FL2FXCONST_SGL(0.48148651230437f / 8.0)},
+ {FL2FXCONST_SGL(0.93335049681047f / 8.0),
+ FL2FXCONST_SGL(-0.43537023883588f / 8.0)},
+ {FL2FXCONST_SGL(-0.97087374418267f / 8.0),
+ FL2FXCONST_SGL(0.86636445711364f / 8.0)},
+ {FL2FXCONST_SGL(0.36722871286923f / 8.0),
+ FL2FXCONST_SGL(0.65291654172961f / 8.0)},
+ {FL2FXCONST_SGL(-0.81093025665696f / 8.0),
+ FL2FXCONST_SGL(0.08778370229363f / 8.0)},
+ {FL2FXCONST_SGL(-0.26240603062237f / 8.0),
+ FL2FXCONST_SGL(-0.92774095379098f / 8.0)},
+ {FL2FXCONST_SGL(0.83996497984604f / 8.0),
+ FL2FXCONST_SGL(0.55839849139647f / 8.0)},
+ {FL2FXCONST_SGL(-0.99909615720225f / 8.0),
+ FL2FXCONST_SGL(-0.96024605713970f / 8.0)},
+ {FL2FXCONST_SGL(0.74649464155061f / 8.0),
+ FL2FXCONST_SGL(0.12144893606462f / 8.0)},
+ {FL2FXCONST_SGL(-0.74774595569805f / 8.0),
+ FL2FXCONST_SGL(-0.26898062008959f / 8.0)},
+ {FL2FXCONST_SGL(0.95781667469567f / 8.0),
+ FL2FXCONST_SGL(-0.79047927052628f / 8.0)},
+ {FL2FXCONST_SGL(0.95472308713099f / 8.0),
+ FL2FXCONST_SGL(-0.08588776019550f / 8.0)},
+ {FL2FXCONST_SGL(0.48708332746299f / 8.0),
+ FL2FXCONST_SGL(0.99999041579432f / 8.0)},
+ {FL2FXCONST_SGL(0.46332038247497f / 8.0),
+ FL2FXCONST_SGL(0.10964126185063f / 8.0)},
+ {FL2FXCONST_SGL(-0.76497004940162f / 8.0),
+ FL2FXCONST_SGL(0.89210929242238f / 8.0)},
+ {FL2FXCONST_SGL(0.57397389364339f / 8.0),
+ FL2FXCONST_SGL(0.35289703373760f / 8.0)},
+ {FL2FXCONST_SGL(0.75374316974495f / 8.0),
+ FL2FXCONST_SGL(0.96705214651335f / 8.0)},
+ {FL2FXCONST_SGL(-0.59174397685714f / 8.0),
+ FL2FXCONST_SGL(-0.89405370422752f / 8.0)},
+ {FL2FXCONST_SGL(0.75087906691890f / 8.0),
+ FL2FXCONST_SGL(-0.29612672982396f / 8.0)},
+ {FL2FXCONST_SGL(-0.98607857336230f / 8.0),
+ FL2FXCONST_SGL(0.25034911730023f / 8.0)},
+ {FL2FXCONST_SGL(-0.40761056640505f / 8.0),
+ FL2FXCONST_SGL(-0.90045573444695f / 8.0)},
+ {FL2FXCONST_SGL(0.66929266740477f / 8.0),
+ FL2FXCONST_SGL(0.98629493401748f / 8.0)},
+ {FL2FXCONST_SGL(-0.97463695257310f / 8.0),
+ FL2FXCONST_SGL(-0.00190223301301f / 8.0)},
+ {FL2FXCONST_SGL(0.90145509409859f / 8.0),
+ FL2FXCONST_SGL(0.99781390365446f / 8.0)},
+ {FL2FXCONST_SGL(-0.87259289048043f / 8.0),
+ FL2FXCONST_SGL(0.99233587353666f / 8.0)},
+ {FL2FXCONST_SGL(-0.91529461447692f / 8.0),
+ FL2FXCONST_SGL(-0.15698707534206f / 8.0)},
+ {FL2FXCONST_SGL(-0.03305738840705f / 8.0),
+ FL2FXCONST_SGL(-0.37205262859764f / 8.0)},
+ {FL2FXCONST_SGL(0.07223051368337f / 8.0),
+ FL2FXCONST_SGL(-0.88805001733626f / 8.0)},
+ {FL2FXCONST_SGL(0.99498012188353f / 8.0),
+ FL2FXCONST_SGL(0.97094358113387f / 8.0)},
+ {FL2FXCONST_SGL(-0.74904939500519f / 8.0),
+ FL2FXCONST_SGL(0.99985483641521f / 8.0)},
+ {FL2FXCONST_SGL(0.04585228574211f / 8.0),
+ FL2FXCONST_SGL(0.99812337444082f / 8.0)},
+ {FL2FXCONST_SGL(-0.89054954257993f / 8.0),
+ FL2FXCONST_SGL(-0.31791913188064f / 8.0)},
+ {FL2FXCONST_SGL(-0.83782144651251f / 8.0),
+ FL2FXCONST_SGL(0.97637632547466f / 8.0)},
+ {FL2FXCONST_SGL(0.33454804933804f / 8.0),
+ FL2FXCONST_SGL(-0.86231516800408f / 8.0)},
+ {FL2FXCONST_SGL(-0.99707579362824f / 8.0),
+ FL2FXCONST_SGL(0.93237990079441f / 8.0)},
+ {FL2FXCONST_SGL(-0.22827527843994f / 8.0),
+ FL2FXCONST_SGL(0.18874759397997f / 8.0)},
+ {FL2FXCONST_SGL(0.67248046289143f / 8.0),
+ FL2FXCONST_SGL(-0.03646211390569f / 8.0)},
+ {FL2FXCONST_SGL(-0.05146538187944f / 8.0),
+ FL2FXCONST_SGL(-0.92599700120679f / 8.0)},
+ {FL2FXCONST_SGL(0.99947295749905f / 8.0),
+ FL2FXCONST_SGL(0.93625229707912f / 8.0)},
+ {FL2FXCONST_SGL(0.66951124390363f / 8.0),
+ FL2FXCONST_SGL(0.98905825623893f / 8.0)},
+ {FL2FXCONST_SGL(-0.99602956559179f / 8.0),
+ FL2FXCONST_SGL(-0.44654715757688f / 8.0)},
+ {FL2FXCONST_SGL(0.82104905483590f / 8.0),
+ FL2FXCONST_SGL(0.99540741724928f / 8.0)},
+ {FL2FXCONST_SGL(0.99186510988782f / 8.0),
+ FL2FXCONST_SGL(0.72023001312947f / 8.0)},
+ {FL2FXCONST_SGL(-0.65284592392918f / 8.0),
+ FL2FXCONST_SGL(0.52186723253637f / 8.0)},
+ {FL2FXCONST_SGL(0.93885443798188f / 8.0),
+ FL2FXCONST_SGL(-0.74895312615259f / 8.0)},
+ {FL2FXCONST_SGL(0.96735248738388f / 8.0),
+ FL2FXCONST_SGL(0.90891816978629f / 8.0)},
+ {FL2FXCONST_SGL(-0.22225968841114f / 8.0),
+ FL2FXCONST_SGL(0.57124029781228f / 8.0)},
+ {FL2FXCONST_SGL(-0.44132783753414f / 8.0),
+ FL2FXCONST_SGL(-0.92688840659280f / 8.0)},
+ {FL2FXCONST_SGL(-0.85694974219574f / 8.0),
+ FL2FXCONST_SGL(0.88844532719844f / 8.0)},
+ {FL2FXCONST_SGL(0.91783042091762f / 8.0),
+ FL2FXCONST_SGL(-0.46356892383970f / 8.0)},
+ {FL2FXCONST_SGL(0.72556974415690f / 8.0),
+ FL2FXCONST_SGL(-0.99899555770747f / 8.0)},
+ {FL2FXCONST_SGL(-0.99711581834508f / 8.0),
+ FL2FXCONST_SGL(0.58211560180426f / 8.0)},
+ {FL2FXCONST_SGL(0.77638976371966f / 8.0),
+ FL2FXCONST_SGL(0.94321834873819f / 8.0)},
+ {FL2FXCONST_SGL(0.07717324253925f / 8.0),
+ FL2FXCONST_SGL(0.58638399856595f / 8.0)},
+ {FL2FXCONST_SGL(-0.56049829194163f / 8.0),
+ FL2FXCONST_SGL(0.82522301569036f / 8.0)},
+ {FL2FXCONST_SGL(0.98398893639988f / 8.0),
+ FL2FXCONST_SGL(0.39467440420569f / 8.0)},
+ {FL2FXCONST_SGL(0.47546946844938f / 8.0),
+ FL2FXCONST_SGL(0.68613044836811f / 8.0)},
+ {FL2FXCONST_SGL(0.65675089314631f / 8.0),
+ FL2FXCONST_SGL(0.18331637134880f / 8.0)},
+ {FL2FXCONST_SGL(0.03273375457980f / 8.0),
+ FL2FXCONST_SGL(-0.74933109564108f / 8.0)},
+ {FL2FXCONST_SGL(-0.38684144784738f / 8.0),
+ FL2FXCONST_SGL(0.51337349030406f / 8.0)},
+ {FL2FXCONST_SGL(-0.97346267944545f / 8.0),
+ FL2FXCONST_SGL(-0.96549364384098f / 8.0)},
+ {FL2FXCONST_SGL(-0.53282156061942f / 8.0),
+ FL2FXCONST_SGL(-0.91423265091354f / 8.0)},
+ {FL2FXCONST_SGL(0.99817310731176f / 8.0),
+ FL2FXCONST_SGL(0.61133572482148f / 8.0)},
+ {FL2FXCONST_SGL(-0.50254500772635f / 8.0),
+ FL2FXCONST_SGL(-0.88829338134294f / 8.0)},
+ {FL2FXCONST_SGL(0.01995873238855f / 8.0),
+ FL2FXCONST_SGL(0.85223515096765f / 8.0)},
+ {FL2FXCONST_SGL(0.99930381973804f / 8.0),
+ FL2FXCONST_SGL(0.94578896296649f / 8.0)},
+ {FL2FXCONST_SGL(0.82907767600783f / 8.0),
+ FL2FXCONST_SGL(-0.06323442598128f / 8.0)},
+ {FL2FXCONST_SGL(-0.58660709669728f / 8.0),
+ FL2FXCONST_SGL(0.96840773806582f / 8.0)},
+ {FL2FXCONST_SGL(-0.17573736667267f / 8.0),
+ FL2FXCONST_SGL(-0.48166920859485f / 8.0)},
+ {FL2FXCONST_SGL(0.83434292401346f / 8.0),
+ FL2FXCONST_SGL(-0.13023450646997f / 8.0)},
+ {FL2FXCONST_SGL(0.05946491307025f / 8.0),
+ FL2FXCONST_SGL(0.20511047074866f / 8.0)},
+ {FL2FXCONST_SGL(0.81505484574602f / 8.0),
+ FL2FXCONST_SGL(-0.94685947861369f / 8.0)},
+ {FL2FXCONST_SGL(-0.44976380954860f / 8.0),
+ FL2FXCONST_SGL(0.40894572671545f / 8.0)},
+ {FL2FXCONST_SGL(-0.89746474625671f / 8.0),
+ FL2FXCONST_SGL(0.99846578838537f / 8.0)},
+ {FL2FXCONST_SGL(0.39677256130792f / 8.0),
+ FL2FXCONST_SGL(-0.74854668609359f / 8.0)},
+ {FL2FXCONST_SGL(-0.07588948563079f / 8.0),
+ FL2FXCONST_SGL(0.74096214084170f / 8.0)},
+ {FL2FXCONST_SGL(0.76343198951445f / 8.0),
+ FL2FXCONST_SGL(0.41746629422634f / 8.0)},
+ {FL2FXCONST_SGL(-0.74490104699626f / 8.0),
+ FL2FXCONST_SGL(0.94725911744610f / 8.0)},
+ {FL2FXCONST_SGL(0.64880119792759f / 8.0),
+ FL2FXCONST_SGL(0.41336660830571f / 8.0)},
+ {FL2FXCONST_SGL(0.62319537462542f / 8.0),
+ FL2FXCONST_SGL(-0.93098313552599f / 8.0)},
+ {FL2FXCONST_SGL(0.42215817594807f / 8.0),
+ FL2FXCONST_SGL(-0.07712787385208f / 8.0)},
+ {FL2FXCONST_SGL(0.02704554141885f / 8.0),
+ FL2FXCONST_SGL(-0.05417518053666f / 8.0)},
+ {FL2FXCONST_SGL(0.80001773566818f / 8.0),
+ FL2FXCONST_SGL(0.91542195141039f / 8.0)},
+ {FL2FXCONST_SGL(-0.79351832348816f / 8.0),
+ FL2FXCONST_SGL(-0.36208897989136f / 8.0)},
+ {FL2FXCONST_SGL(0.63872359151636f / 8.0),
+ FL2FXCONST_SGL(0.08128252493444f / 8.0)},
+ {FL2FXCONST_SGL(0.52890520960295f / 8.0),
+ FL2FXCONST_SGL(0.60048872455592f / 8.0)},
+ {FL2FXCONST_SGL(0.74238552914587f / 8.0),
+ FL2FXCONST_SGL(0.04491915291044f / 8.0)},
+ {FL2FXCONST_SGL(0.99096131449250f / 8.0),
+ FL2FXCONST_SGL(-0.19451182854402f / 8.0)},
+ {FL2FXCONST_SGL(-0.80412329643109f / 8.0),
+ FL2FXCONST_SGL(-0.88513818199457f / 8.0)},
+ {FL2FXCONST_SGL(-0.64612616129736f / 8.0),
+ FL2FXCONST_SGL(0.72198674804544f / 8.0)},
+ {FL2FXCONST_SGL(0.11657770663191f / 8.0),
+ FL2FXCONST_SGL(-0.83662833815041f / 8.0)},
+ {FL2FXCONST_SGL(-0.95053182488101f / 8.0),
+ FL2FXCONST_SGL(-0.96939905138082f / 8.0)},
+ {FL2FXCONST_SGL(-0.62228872928622f / 8.0),
+ FL2FXCONST_SGL(0.82767262846661f / 8.0)},
+ {FL2FXCONST_SGL(0.03004475787316f / 8.0),
+ FL2FXCONST_SGL(-0.99738896333384f / 8.0)},
+ {FL2FXCONST_SGL(-0.97987214341034f / 8.0),
+ FL2FXCONST_SGL(0.36526129686425f / 8.0)},
+ {FL2FXCONST_SGL(-0.99986980746200f / 8.0),
+ FL2FXCONST_SGL(-0.36021610299715f / 8.0)},
+ {FL2FXCONST_SGL(0.89110648599879f / 8.0),
+ FL2FXCONST_SGL(-0.97894250343044f / 8.0)},
+ {FL2FXCONST_SGL(0.10407960510582f / 8.0),
+ FL2FXCONST_SGL(0.77357793811619f / 8.0)},
+ {FL2FXCONST_SGL(0.95964737821728f / 8.0),
+ FL2FXCONST_SGL(-0.35435818285502f / 8.0)},
+ {FL2FXCONST_SGL(0.50843233159162f / 8.0),
+ FL2FXCONST_SGL(0.96107691266205f / 8.0)},
+ {FL2FXCONST_SGL(0.17006334670615f / 8.0),
+ FL2FXCONST_SGL(-0.76854025314829f / 8.0)},
+ {FL2FXCONST_SGL(0.25872675063360f / 8.0),
+ FL2FXCONST_SGL(0.99893303933816f / 8.0)},
+ {FL2FXCONST_SGL(-0.01115998681937f / 8.0),
+ FL2FXCONST_SGL(0.98496019742444f / 8.0)},
+ {FL2FXCONST_SGL(-0.79598702973261f / 8.0),
+ FL2FXCONST_SGL(0.97138411318894f / 8.0)},
+ {FL2FXCONST_SGL(-0.99264708948101f / 8.0),
+ FL2FXCONST_SGL(-0.99542822402536f / 8.0)},
+ {FL2FXCONST_SGL(-0.99829663752818f / 8.0),
+ FL2FXCONST_SGL(0.01877138824311f / 8.0)},
+ {FL2FXCONST_SGL(-0.70801016548184f / 8.0),
+ FL2FXCONST_SGL(0.33680685948117f / 8.0)},
+ {FL2FXCONST_SGL(-0.70467057786826f / 8.0),
+ FL2FXCONST_SGL(0.93272777501857f / 8.0)},
+ {FL2FXCONST_SGL(0.99846021905254f / 8.0),
+ FL2FXCONST_SGL(-0.98725746254433f / 8.0)},
+ {FL2FXCONST_SGL(-0.63364968534650f / 8.0),
+ FL2FXCONST_SGL(-0.16473594423746f / 8.0)},
+ {FL2FXCONST_SGL(-0.16258217500792f / 8.0),
+ FL2FXCONST_SGL(-0.95939125400802f / 8.0)},
+ {FL2FXCONST_SGL(-0.43645594360633f / 8.0),
+ FL2FXCONST_SGL(-0.94805030113284f / 8.0)},
+ {FL2FXCONST_SGL(-0.99848471702976f / 8.0),
+ FL2FXCONST_SGL(0.96245166923809f / 8.0)},
+ {FL2FXCONST_SGL(-0.16796458968998f / 8.0),
+ FL2FXCONST_SGL(-0.98987511890470f / 8.0)},
+ {FL2FXCONST_SGL(-0.87979225745213f / 8.0),
+ FL2FXCONST_SGL(-0.71725725041680f / 8.0)},
+ {FL2FXCONST_SGL(0.44183099021786f / 8.0),
+ FL2FXCONST_SGL(-0.93568974498761f / 8.0)},
+ {FL2FXCONST_SGL(0.93310180125532f / 8.0),
+ FL2FXCONST_SGL(-0.99913308068246f / 8.0)},
+ {FL2FXCONST_SGL(-0.93941931782002f / 8.0),
+ FL2FXCONST_SGL(-0.56409379640356f / 8.0)},
+ {FL2FXCONST_SGL(-0.88590003188677f / 8.0),
+ FL2FXCONST_SGL(0.47624600491382f / 8.0)},
+ {FL2FXCONST_SGL(0.99971463703691f / 8.0),
+ FL2FXCONST_SGL(-0.83889954253462f / 8.0)},
+ {FL2FXCONST_SGL(-0.75376385639978f / 8.0),
+ FL2FXCONST_SGL(0.00814643438625f / 8.0)},
+ {FL2FXCONST_SGL(0.93887685615875f / 8.0),
+ FL2FXCONST_SGL(-0.11284528204636f / 8.0)},
+ {FL2FXCONST_SGL(0.85126435782309f / 8.0),
+ FL2FXCONST_SGL(0.52349251543547f / 8.0)},
+ {FL2FXCONST_SGL(0.39701421446381f / 8.0),
+ FL2FXCONST_SGL(0.81779634174316f / 8.0)},
+ {FL2FXCONST_SGL(-0.37024464187437f / 8.0),
+ FL2FXCONST_SGL(-0.87071656222959f / 8.0)},
+ {FL2FXCONST_SGL(-0.36024828242896f / 8.0),
+ FL2FXCONST_SGL(0.34655735648287f / 8.0)},
+ {FL2FXCONST_SGL(-0.93388812549209f / 8.0),
+ FL2FXCONST_SGL(-0.84476541096429f / 8.0)},
+ {FL2FXCONST_SGL(-0.65298804552119f / 8.0),
+ FL2FXCONST_SGL(-0.18439575450921f / 8.0)},
+ {FL2FXCONST_SGL(0.11960319006843f / 8.0),
+ FL2FXCONST_SGL(0.99899346780168f / 8.0)},
+ {FL2FXCONST_SGL(0.94292565553160f / 8.0),
+ FL2FXCONST_SGL(0.83163906518293f / 8.0)},
+ {FL2FXCONST_SGL(0.75081145286948f / 8.0),
+ FL2FXCONST_SGL(-0.35533223142265f / 8.0)},
+ {FL2FXCONST_SGL(0.56721979748394f / 8.0),
+ FL2FXCONST_SGL(-0.24076836414499f / 8.0)},
+ {FL2FXCONST_SGL(0.46857766746029f / 8.0),
+ FL2FXCONST_SGL(-0.30140233457198f / 8.0)},
+ {FL2FXCONST_SGL(0.97312313923635f / 8.0),
+ FL2FXCONST_SGL(-0.99548191630031f / 8.0)},
+ {FL2FXCONST_SGL(-0.38299976567017f / 8.0),
+ FL2FXCONST_SGL(0.98516909715427f / 8.0)},
+ {FL2FXCONST_SGL(0.41025800019463f / 8.0),
+ FL2FXCONST_SGL(0.02116736935734f / 8.0)},
+ {FL2FXCONST_SGL(0.09638062008048f / 8.0),
+ FL2FXCONST_SGL(0.04411984381457f / 8.0)},
+ {FL2FXCONST_SGL(-0.85283249275397f / 8.0),
+ FL2FXCONST_SGL(0.91475563922421f / 8.0)},
+ {FL2FXCONST_SGL(0.88866808958124f / 8.0),
+ FL2FXCONST_SGL(-0.99735267083226f / 8.0)},
+ {FL2FXCONST_SGL(-0.48202429536989f / 8.0),
+ FL2FXCONST_SGL(-0.96805608884164f / 8.0)},
+ {FL2FXCONST_SGL(0.27572582416567f / 8.0),
+ FL2FXCONST_SGL(0.58634753335832f / 8.0)},
+ {FL2FXCONST_SGL(-0.65889129659168f / 8.0),
+ FL2FXCONST_SGL(0.58835634138583f / 8.0)},
+ {FL2FXCONST_SGL(0.98838086953732f / 8.0),
+ FL2FXCONST_SGL(0.99994349600236f / 8.0)},
+ {FL2FXCONST_SGL(-0.20651349620689f / 8.0),
+ FL2FXCONST_SGL(0.54593044066355f / 8.0)},
+ {FL2FXCONST_SGL(-0.62126416356920f / 8.0),
+ FL2FXCONST_SGL(-0.59893681700392f / 8.0)},
+ {FL2FXCONST_SGL(0.20320105410437f / 8.0),
+ FL2FXCONST_SGL(-0.86879180355289f / 8.0)},
+ {FL2FXCONST_SGL(-0.97790548600584f / 8.0),
+ FL2FXCONST_SGL(0.96290806999242f / 8.0)},
+ {FL2FXCONST_SGL(0.11112534735126f / 8.0),
+ FL2FXCONST_SGL(0.21484763313301f / 8.0)},
+ {FL2FXCONST_SGL(-0.41368337314182f / 8.0),
+ FL2FXCONST_SGL(0.28216837680365f / 8.0)},
+ {FL2FXCONST_SGL(0.24133038992960f / 8.0),
+ FL2FXCONST_SGL(0.51294362630238f / 8.0)},
+ {FL2FXCONST_SGL(-0.66393410674885f / 8.0),
+ FL2FXCONST_SGL(-0.08249679629081f / 8.0)},
+ {FL2FXCONST_SGL(-0.53697829178752f / 8.0),
+ FL2FXCONST_SGL(-0.97649903936228f / 8.0)},
+ {FL2FXCONST_SGL(-0.97224737889348f / 8.0),
+ FL2FXCONST_SGL(0.22081333579837f / 8.0)},
+ {FL2FXCONST_SGL(0.87392477144549f / 8.0),
+ FL2FXCONST_SGL(-0.12796173740361f / 8.0)},
+ {FL2FXCONST_SGL(0.19050361015753f / 8.0),
+ FL2FXCONST_SGL(0.01602615387195f / 8.0)},
+ {FL2FXCONST_SGL(-0.46353441212724f / 8.0),
+ FL2FXCONST_SGL(-0.95249041539006f / 8.0)},
+ {FL2FXCONST_SGL(-0.07064096339021f / 8.0),
+ FL2FXCONST_SGL(-0.94479803205886f / 8.0)},
+ {FL2FXCONST_SGL(-0.92444085484466f / 8.0),
+ FL2FXCONST_SGL(-0.10457590187436f / 8.0)},
+ {FL2FXCONST_SGL(-0.83822593578728f / 8.0),
+ FL2FXCONST_SGL(-0.01695043208885f / 8.0)},
+ {FL2FXCONST_SGL(0.75214681811150f / 8.0),
+ FL2FXCONST_SGL(-0.99955681042665f / 8.0)},
+ {FL2FXCONST_SGL(-0.42102998829339f / 8.0),
+ FL2FXCONST_SGL(0.99720941999394f / 8.0)},
+ {FL2FXCONST_SGL(-0.72094786237696f / 8.0),
+ FL2FXCONST_SGL(-0.35008961934255f / 8.0)},
+ {FL2FXCONST_SGL(0.78843311019251f / 8.0),
+ FL2FXCONST_SGL(0.52851398958271f / 8.0)},
+ {FL2FXCONST_SGL(0.97394027897442f / 8.0),
+ FL2FXCONST_SGL(-0.26695944086561f / 8.0)},
+ {FL2FXCONST_SGL(0.99206463477946f / 8.0),
+ FL2FXCONST_SGL(-0.57010120849429f / 8.0)},
+ {FL2FXCONST_SGL(0.76789609461795f / 8.0),
+ FL2FXCONST_SGL(-0.76519356730966f / 8.0)},
+ {FL2FXCONST_SGL(-0.82002421836409f / 8.0),
+ FL2FXCONST_SGL(-0.73530179553767f / 8.0)},
+ {FL2FXCONST_SGL(0.81924990025724f / 8.0),
+ FL2FXCONST_SGL(0.99698425250579f / 8.0)},
+ {FL2FXCONST_SGL(-0.26719850873357f / 8.0),
+ FL2FXCONST_SGL(0.68903369776193f / 8.0)},
+ {FL2FXCONST_SGL(-0.43311260380975f / 8.0),
+ FL2FXCONST_SGL(0.85321815947490f / 8.0)},
+ {FL2FXCONST_SGL(0.99194979673836f / 8.0),
+ FL2FXCONST_SGL(0.91876249766422f / 8.0)},
+ {FL2FXCONST_SGL(-0.80692001248487f / 8.0),
+ FL2FXCONST_SGL(-0.32627540663214f / 8.0)},
+ {FL2FXCONST_SGL(0.43080003649976f / 8.0),
+ FL2FXCONST_SGL(-0.21919095636638f / 8.0)},
+ {FL2FXCONST_SGL(0.67709491937357f / 8.0),
+ FL2FXCONST_SGL(-0.95478075822906f / 8.0)},
+ {FL2FXCONST_SGL(0.56151770568316f / 8.0),
+ FL2FXCONST_SGL(-0.70693811747778f / 8.0)},
+ {FL2FXCONST_SGL(0.10831862810749f / 8.0),
+ FL2FXCONST_SGL(-0.08628837174592f / 8.0)},
+ {FL2FXCONST_SGL(0.91229417540436f / 8.0),
+ FL2FXCONST_SGL(-0.65987351408410f / 8.0)},
+ {FL2FXCONST_SGL(-0.48972893932274f / 8.0),
+ FL2FXCONST_SGL(0.56289246362686f / 8.0)},
+ {FL2FXCONST_SGL(-0.89033658689697f / 8.0),
+ FL2FXCONST_SGL(-0.71656563987082f / 8.0)},
+ {FL2FXCONST_SGL(0.65269447475094f / 8.0),
+ FL2FXCONST_SGL(0.65916004833932f / 8.0)},
+ {FL2FXCONST_SGL(0.67439478141121f / 8.0),
+ FL2FXCONST_SGL(-0.81684380846796f / 8.0)},
+ {FL2FXCONST_SGL(-0.47770832416973f / 8.0),
+ FL2FXCONST_SGL(-0.16789556203025f / 8.0)},
+ {FL2FXCONST_SGL(-0.99715979260878f / 8.0),
+ FL2FXCONST_SGL(-0.93565784007648f / 8.0)},
+ {FL2FXCONST_SGL(-0.90889593602546f / 8.0),
+ FL2FXCONST_SGL(0.62034397054380f / 8.0)},
+ {FL2FXCONST_SGL(-0.06618622548177f / 8.0),
+ FL2FXCONST_SGL(-0.23812217221359f / 8.0)},
+ {FL2FXCONST_SGL(0.99430266919728f / 8.0),
+ FL2FXCONST_SGL(0.18812555317553f / 8.0)},
+ {FL2FXCONST_SGL(0.97686402381843f / 8.0),
+ FL2FXCONST_SGL(-0.28664534366620f / 8.0)},
+ {FL2FXCONST_SGL(0.94813650221268f / 8.0),
+ FL2FXCONST_SGL(-0.97506640027128f / 8.0)},
+ {FL2FXCONST_SGL(-0.95434497492853f / 8.0),
+ FL2FXCONST_SGL(-0.79607978501983f / 8.0)},
+ {FL2FXCONST_SGL(-0.49104783137150f / 8.0),
+ FL2FXCONST_SGL(0.32895214359663f / 8.0)},
+ {FL2FXCONST_SGL(0.99881175120751f / 8.0),
+ FL2FXCONST_SGL(0.88993983831354f / 8.0)},
+ {FL2FXCONST_SGL(0.50449166760303f / 8.0),
+ FL2FXCONST_SGL(-0.85995072408434f / 8.0)},
+ {FL2FXCONST_SGL(0.47162891065108f / 8.0),
+ FL2FXCONST_SGL(-0.18680204049569f / 8.0)},
+ {FL2FXCONST_SGL(-0.62081581361840f / 8.0),
+ FL2FXCONST_SGL(0.75000676218956f / 8.0)},
+ {FL2FXCONST_SGL(-0.43867015250812f / 8.0),
+ FL2FXCONST_SGL(0.99998069244322f / 8.0)},
+ {FL2FXCONST_SGL(0.98630563232075f / 8.0),
+ FL2FXCONST_SGL(-0.53578899600662f / 8.0)},
+ {FL2FXCONST_SGL(-0.61510362277374f / 8.0),
+ FL2FXCONST_SGL(-0.89515019899997f / 8.0)},
+ {FL2FXCONST_SGL(-0.03841517601843f / 8.0),
+ FL2FXCONST_SGL(-0.69888815681179f / 8.0)},
+ {FL2FXCONST_SGL(-0.30102157304644f / 8.0),
+ FL2FXCONST_SGL(-0.07667808922205f / 8.0)},
+ {FL2FXCONST_SGL(0.41881284182683f / 8.0),
+ FL2FXCONST_SGL(0.02188098922282f / 8.0)},
+ {FL2FXCONST_SGL(-0.86135454941237f / 8.0),
+ FL2FXCONST_SGL(0.98947480909359f / 8.0)},
+ {FL2FXCONST_SGL(0.67226861393788f / 8.0),
+ FL2FXCONST_SGL(-0.13494389011014f / 8.0)},
+ {FL2FXCONST_SGL(-0.70737398842068f / 8.0),
+ FL2FXCONST_SGL(-0.76547349325992f / 8.0)},
+ {FL2FXCONST_SGL(0.94044946687963f / 8.0),
+ FL2FXCONST_SGL(0.09026201157416f / 8.0)},
+ {FL2FXCONST_SGL(-0.82386352534327f / 8.0),
+ FL2FXCONST_SGL(0.08924768823676f / 8.0)},
+ {FL2FXCONST_SGL(-0.32070666698656f / 8.0),
+ FL2FXCONST_SGL(0.50143421908753f / 8.0)},
+ {FL2FXCONST_SGL(0.57593163224487f / 8.0),
+ FL2FXCONST_SGL(-0.98966422921509f / 8.0)},
+ {FL2FXCONST_SGL(-0.36326018419965f / 8.0),
+ FL2FXCONST_SGL(0.07440243123228f / 8.0)},
+ {FL2FXCONST_SGL(0.99979044674350f / 8.0),
+ FL2FXCONST_SGL(-0.14130287347405f / 8.0)},
+ {FL2FXCONST_SGL(-0.92366023326932f / 8.0),
+ FL2FXCONST_SGL(-0.97979298068180f / 8.0)},
+ {FL2FXCONST_SGL(-0.44607178518598f / 8.0),
+ FL2FXCONST_SGL(-0.54233252016394f / 8.0)},
+ {FL2FXCONST_SGL(0.44226800932956f / 8.0),
+ FL2FXCONST_SGL(0.71326756742752f / 8.0)},
+ {FL2FXCONST_SGL(0.03671907158312f / 8.0),
+ FL2FXCONST_SGL(0.63606389366675f / 8.0)},
+ {FL2FXCONST_SGL(0.52175424682195f / 8.0),
+ FL2FXCONST_SGL(-0.85396826735705f / 8.0)},
+ {FL2FXCONST_SGL(-0.94701139690956f / 8.0),
+ FL2FXCONST_SGL(-0.01826348194255f / 8.0)},
+ {FL2FXCONST_SGL(-0.98759606946049f / 8.0),
+ FL2FXCONST_SGL(0.82288714303073f / 8.0)},
+ {FL2FXCONST_SGL(0.87434794743625f / 8.0),
+ FL2FXCONST_SGL(0.89399495655433f / 8.0)},
+ {FL2FXCONST_SGL(-0.93412041758744f / 8.0),
+ FL2FXCONST_SGL(0.41374052024363f / 8.0)},
+ {FL2FXCONST_SGL(0.96063943315511f / 8.0),
+ FL2FXCONST_SGL(0.93116709541280f / 8.0)},
+ {FL2FXCONST_SGL(0.97534253457837f / 8.0),
+ FL2FXCONST_SGL(0.86150930812689f / 8.0)},
+ {FL2FXCONST_SGL(0.99642466504163f / 8.0),
+ FL2FXCONST_SGL(0.70190043427512f / 8.0)},
+ {FL2FXCONST_SGL(-0.94705089665984f / 8.0),
+ FL2FXCONST_SGL(-0.29580042814306f / 8.0)},
+ {FL2FXCONST_SGL(0.91599807087376f / 8.0),
+ FL2FXCONST_SGL(-0.98147830385781f / 8.0)}};
+//@}
+
+/*
+static const FIXP_SGL harmonicPhase [2][4] = {
+ { 1.0, 0.0, -1.0, 0.0},
+ { 0.0, 1.0, 0.0, -1.0}
+};
+*/
+
+/* tables for SBR and AAC LD */
+/* table for 8 time slot index */
+const int FDK_sbrDecoder_envelopeTable_8[8][5] = {
+ /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */
+ /* borders from left to right side; -1 = not in use */
+ /*[|T-|------]*/ {2, 0, 0, 1, -1},
+ /*[|-T-|-----]*/ {2, 0, 0, 2, -1},
+ /*[--|T-|----]*/ {3, 1, 1, 2, 4},
+ /*[---|T-|---]*/ {3, 1, 1, 3, 5},
+ /*[----|T-|--]*/ {3, 1, 1, 4, 6},
+ /*[-----|T--|]*/ {2, 1, 1, 5, -1},
+ /*[------|T-|]*/ {2, 1, 1, 6, -1},
+ /*[-------|T|]*/ {2, 1, 1, 7, -1},
+};
+
+/* table for 15 time slot index */
+const int FDK_sbrDecoder_envelopeTable_15[15][6] = {
+ /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */
+ /* length from left to right side; -1 = not in use */
+ /*[|T---|------------]*/ {2, 0, 0, 4, -1, -1},
+ /*[|-T---|-----------]*/ {2, 0, 0, 5, -1, -1},
+ /*[|--|T---|---------]*/ {3, 1, 1, 2, 6, -1},
+ /*[|---|T---|--------]*/ {3, 1, 1, 3, 7, -1},
+ /*[|----|T---|-------]*/ {3, 1, 1, 4, 8, -1},
+ /*[|-----|T---|------]*/ {3, 1, 1, 5, 9, -1},
+ /*[|------|T---|-----]*/ {3, 1, 1, 6, 10, -1},
+ /*[|-------|T---|----]*/ {3, 1, 1, 7, 11, -1},
+ /*[|--------|T---|---]*/ {3, 1, 1, 8, 12, -1},
+ /*[|---------|T---|--]*/ {3, 1, 1, 9, 13, -1},
+ /*[|----------|T----|]*/ {2, 1, 1, 10, -1, -1},
+ /*[|-----------|T---|]*/ {2, 1, 1, 11, -1, -1},
+ /*[|------------|T--|]*/ {2, 1, 1, 12, -1, -1},
+ /*[|-------------|T-|]*/ {2, 1, 1, 13, -1, -1},
+ /*[|--------------|T|]*/ {2, 1, 1, 14, -1, -1},
+};
+
+/* table for 16 time slot index */
+const int FDK_sbrDecoder_envelopeTable_16[16][6] = {
+ /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */
+ /* length from left to right side; -1 = not in use */
+ /*[|T---|------------|]*/ {2, 0, 0, 4, -1, -1},
+ /*[|-T---|-----------|]*/ {2, 0, 0, 5, -1, -1},
+ /*[|--|T---|----------]*/ {3, 1, 1, 2, 6, -1},
+ /*[|---|T---|---------]*/ {3, 1, 1, 3, 7, -1},
+ /*[|----|T---|--------]*/ {3, 1, 1, 4, 8, -1},
+ /*[|-----|T---|-------]*/ {3, 1, 1, 5, 9, -1},
+ /*[|------|T---|------]*/ {3, 1, 1, 6, 10, -1},
+ /*[|-------|T---|-----]*/ {3, 1, 1, 7, 11, -1},
+ /*[|--------|T---|----]*/ {3, 1, 1, 8, 12, -1},
+ /*[|---------|T---|---]*/ {3, 1, 1, 9, 13, -1},
+ /*[|----------|T---|--]*/ {3, 1, 1, 10, 14, -1},
+ /*[|-----------|T----|]*/ {2, 1, 1, 11, -1, -1},
+ /*[|------------|T---|]*/ {2, 1, 1, 12, -1, -1},
+ /*[|-------------|T--|]*/ {2, 1, 1, 13, -1, -1},
+ /*[|--------------|T-|]*/ {2, 1, 1, 14, -1, -1},
+ /*[|---------------|T|]*/ {2, 1, 1, 15, -1, -1},
+};
+
+/*!
+ \name FrameInfoDefaults
+
+ Predefined envelope positions for the FIX-FIX case (static framing)
+*/
+//@{
+const FRAME_INFO FDK_sbrDecoder_sbr_frame_info1_15 = {
+ 0, 1, {0, 15, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, -1, 1, {0, 15, 0}, {0, 0, 0},
+ 0, 0};
+const FRAME_INFO FDK_sbrDecoder_sbr_frame_info2_15 = {
+ 0, 2, {0, 8, 15, 0, 0, 0}, {1, 1, 0, 0, 0}, -1, 2, {0, 8, 15}, {0, 0, 0},
+ 0, 0};
+const FRAME_INFO FDK_sbrDecoder_sbr_frame_info4_15 = {
+ 0, 4, {0, 4, 8, 12, 15, 0}, {1, 1, 1, 1, 0}, -1, 2, {0, 8, 15}, {0, 0, 0},
+ 0, 0};
+#if (MAX_ENVELOPES >= 8)
+const FRAME_INFO FDK_sbrDecoder_sbr_frame_info8_15 = {
+ 0,
+ 8,
+ {0, 2, 4, 6, 8, 10, 12, 14, 15},
+ {1, 1, 1, 1, 1, 1, 1, 1},
+ -1,
+ 2,
+ {0, 8, 15},
+ {0, 0, 0},
+ 0,
+ 0};
+#endif
+
+const FRAME_INFO FDK_sbrDecoder_sbr_frame_info1_16 = {
+ 0, 1, {0, 16, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, -1, 1, {0, 16, 0}, {0, 0, 0},
+ 0, 0};
+const FRAME_INFO FDK_sbrDecoder_sbr_frame_info2_16 = {
+ 0, 2, {0, 8, 16, 0, 0, 0}, {1, 1, 0, 0, 0}, -1, 2, {0, 8, 16}, {0, 0, 0},
+ 0, 0};
+const FRAME_INFO FDK_sbrDecoder_sbr_frame_info4_16 = {
+ 0, 4, {0, 4, 8, 12, 16, 0}, {1, 1, 1, 1, 0}, -1, 2, {0, 8, 16}, {0, 0, 0},
+ 0, 0};
+
+#if (MAX_ENVELOPES >= 8)
+const FRAME_INFO FDK_sbrDecoder_sbr_frame_info8_16 = {
+ 0,
+ 8,
+ {0, 2, 4, 6, 8, 10, 12, 14, 16},
+ {1, 1, 1, 1, 1, 1, 1, 1},
+ -1,
+ 2,
+ {0, 8, 16},
+ {0, 0, 0},
+ 0,
+ 0};
+#endif
+
+//@}
+
+/*!
+ \name SBR_HuffmanTables
+
+ SBR Huffman Table Overview: \n
+ \n
+ o envelope level, 1.5 dB: \n
+ 1) sbr_huffBook_EnvLevel10T[120][2] \n
+ 2) sbr_huffBook_EnvLevel10F[120][2] \n
+ \n
+ o envelope balance, 1.5 dB: \n
+ 3) sbr_huffBook_EnvBalance10T[48][2] \n
+ 4) sbr_huffBook_EnvBalance10F[48][2] \n
+ \n
+ o envelope level, 3.0 dB: \n
+ 5) sbr_huffBook_EnvLevel11T[62][2] \n
+ 6) sbr_huffBook_EnvLevel11F[62][2] \n
+ \n
+ o envelope balance, 3.0 dB: \n
+ 7) sbr_huffBook_EnvBalance11T[24][2] \n
+ 8) sbr_huffBook_EnvBalance11F[24][2] \n
+ \n
+ o noise level, 3.0 dB: \n
+ 9) sbr_huffBook_NoiseLevel11T[62][2] \n
+ -) (sbr_huffBook_EnvLevel11F[62][2] is used for freq dir)\n
+ \n
+ o noise balance, 3.0 dB: \n
+ 10) sbr_huffBook_NoiseBalance11T[24][2]\n
+ -) (sbr_huffBook_EnvBalance11F[24][2] is used for freq dir)\n
+ \n
+ (1.5 dB is never used for noise)
+
+*/
+//@{
+const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel10T[120][2] = {
+ {1, 2}, {-64, -65}, {3, 4}, {-63, -66}, {5, 6},
+ {-62, -67}, {7, 8}, {-61, -68}, {9, 10}, {-60, -69},
+ {11, 12}, {-59, -70}, {13, 14}, {-58, -71}, {15, 16},
+ {-57, -72}, {17, 18}, {-73, -56}, {19, 21}, {-74, 20},
+ {-55, -75}, {22, 26}, {23, 24}, {-54, -76}, {-77, 25},
+ {-53, -78}, {27, 34}, {28, 29}, {-52, -79}, {30, 31},
+ {-80, -51}, {32, 33}, {-83, -82}, {-81, -50}, {35, 57},
+ {36, 40}, {37, 38}, {-88, -84}, {-48, 39}, {-90, -85},
+ {41, 46}, {42, 43}, {-49, -87}, {44, 45}, {-89, -86},
+ {-124, -123}, {47, 50}, {48, 49}, {-122, -121}, {-120, -119},
+ {51, 54}, {52, 53}, {-118, -117}, {-116, -115}, {55, 56},
+ {-114, -113}, {-112, -111}, {58, 89}, {59, 74}, {60, 67},
+ {61, 64}, {62, 63}, {-110, -109}, {-108, -107}, {65, 66},
+ {-106, -105}, {-104, -103}, {68, 71}, {69, 70}, {-102, -101},
+ {-100, -99}, {72, 73}, {-98, -97}, {-96, -95}, {75, 82},
+ {76, 79}, {77, 78}, {-94, -93}, {-92, -91}, {80, 81},
+ {-47, -46}, {-45, -44}, {83, 86}, {84, 85}, {-43, -42},
+ {-41, -40}, {87, 88}, {-39, -38}, {-37, -36}, {90, 105},
+ {91, 98}, {92, 95}, {93, 94}, {-35, -34}, {-33, -32},
+ {96, 97}, {-31, -30}, {-29, -28}, {99, 102}, {100, 101},
+ {-27, -26}, {-25, -24}, {103, 104}, {-23, -22}, {-21, -20},
+ {106, 113}, {107, 110}, {108, 109}, {-19, -18}, {-17, -16},
+ {111, 112}, {-15, -14}, {-13, -12}, {114, 117}, {115, 116},
+ {-11, -10}, {-9, -8}, {118, 119}, {-7, -6}, {-5, -4}};
+
+const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel10F[120][2] = {
+ {1, 2}, {-64, -65}, {3, 4}, {-63, -66}, {5, 6},
+ {-67, -62}, {7, 8}, {-68, -61}, {9, 10}, {-69, -60},
+ {11, 13}, {-70, 12}, {-59, -71}, {14, 16}, {-58, 15},
+ {-72, -57}, {17, 19}, {-73, 18}, {-56, -74}, {20, 23},
+ {21, 22}, {-55, -75}, {-54, -53}, {24, 27}, {25, 26},
+ {-76, -52}, {-77, -51}, {28, 31}, {29, 30}, {-50, -78},
+ {-79, -49}, {32, 36}, {33, 34}, {-48, -47}, {-80, 35},
+ {-81, -82}, {37, 47}, {38, 41}, {39, 40}, {-83, -46},
+ {-45, -84}, {42, 44}, {-85, 43}, {-44, -43}, {45, 46},
+ {-88, -87}, {-86, -90}, {48, 66}, {49, 56}, {50, 53},
+ {51, 52}, {-92, -42}, {-41, -39}, {54, 55}, {-105, -89},
+ {-38, -37}, {57, 60}, {58, 59}, {-94, -91}, {-40, -36},
+ {61, 63}, {-20, 62}, {-115, -110}, {64, 65}, {-108, -107},
+ {-101, -97}, {67, 89}, {68, 75}, {69, 72}, {70, 71},
+ {-95, -93}, {-34, -27}, {73, 74}, {-22, -17}, {-16, -124},
+ {76, 82}, {77, 79}, {-123, 78}, {-122, -121}, {80, 81},
+ {-120, -119}, {-118, -117}, {83, 86}, {84, 85}, {-116, -114},
+ {-113, -112}, {87, 88}, {-111, -109}, {-106, -104}, {90, 105},
+ {91, 98}, {92, 95}, {93, 94}, {-103, -102}, {-100, -99},
+ {96, 97}, {-98, -96}, {-35, -33}, {99, 102}, {100, 101},
+ {-32, -31}, {-30, -29}, {103, 104}, {-28, -26}, {-25, -24},
+ {106, 113}, {107, 110}, {108, 109}, {-23, -21}, {-19, -18},
+ {111, 112}, {-15, -14}, {-13, -12}, {114, 117}, {115, 116},
+ {-11, -10}, {-9, -8}, {118, 119}, {-7, -6}, {-5, -4}};
+
+const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance10T[48][2] = {
+ {-64, 1}, {-63, 2}, {-65, 3}, {-62, 4}, {-66, 5}, {-61, 6},
+ {-67, 7}, {-60, 8}, {-68, 9}, {10, 11}, {-69, -59}, {12, 13},
+ {-70, -58}, {14, 28}, {15, 21}, {16, 18}, {-57, 17}, {-71, -56},
+ {19, 20}, {-88, -87}, {-86, -85}, {22, 25}, {23, 24}, {-84, -83},
+ {-82, -81}, {26, 27}, {-80, -79}, {-78, -77}, {29, 36}, {30, 33},
+ {31, 32}, {-76, -75}, {-74, -73}, {34, 35}, {-72, -55}, {-54, -53},
+ {37, 41}, {38, 39}, {-52, -51}, {-50, 40}, {-49, -48}, {42, 45},
+ {43, 44}, {-47, -46}, {-45, -44}, {46, 47}, {-43, -42}, {-41, -40}};
+
+const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance10F[48][2] = {
+ {-64, 1}, {-65, 2}, {-63, 3}, {-66, 4}, {-62, 5}, {-61, 6},
+ {-67, 7}, {-68, 8}, {-60, 9}, {10, 11}, {-69, -59}, {-70, 12},
+ {-58, 13}, {14, 17}, {-71, 15}, {-57, 16}, {-56, -73}, {18, 32},
+ {19, 25}, {20, 22}, {-72, 21}, {-88, -87}, {23, 24}, {-86, -85},
+ {-84, -83}, {26, 29}, {27, 28}, {-82, -81}, {-80, -79}, {30, 31},
+ {-78, -77}, {-76, -75}, {33, 40}, {34, 37}, {35, 36}, {-74, -55},
+ {-54, -53}, {38, 39}, {-52, -51}, {-50, -49}, {41, 44}, {42, 43},
+ {-48, -47}, {-46, -45}, {45, 46}, {-44, -43}, {-42, 47}, {-41, -40}};
+
+const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel11T[62][2] = {
+ {-64, 1}, {-65, 2}, {-63, 3}, {-66, 4}, {-62, 5}, {-67, 6},
+ {-61, 7}, {-68, 8}, {-60, 9}, {10, 11}, {-69, -59}, {12, 14},
+ {-70, 13}, {-71, -58}, {15, 18}, {16, 17}, {-72, -57}, {-73, -74},
+ {19, 22}, {-56, 20}, {-55, 21}, {-54, -77}, {23, 31}, {24, 25},
+ {-75, -76}, {26, 27}, {-78, -53}, {28, 29}, {-52, -95}, {-94, 30},
+ {-93, -92}, {32, 47}, {33, 40}, {34, 37}, {35, 36}, {-91, -90},
+ {-89, -88}, {38, 39}, {-87, -86}, {-85, -84}, {41, 44}, {42, 43},
+ {-83, -82}, {-81, -80}, {45, 46}, {-79, -51}, {-50, -49}, {48, 55},
+ {49, 52}, {50, 51}, {-48, -47}, {-46, -45}, {53, 54}, {-44, -43},
+ {-42, -41}, {56, 59}, {57, 58}, {-40, -39}, {-38, -37}, {60, 61},
+ {-36, -35}, {-34, -33}};
+
+const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel11F[62][2] = {
+ {-64, 1}, {-65, 2}, {-63, 3}, {-66, 4}, {-62, 5}, {-67, 6},
+ {7, 8}, {-61, -68}, {9, 10}, {-60, -69}, {11, 12}, {-59, -70},
+ {13, 14}, {-58, -71}, {15, 16}, {-57, -72}, {17, 19}, {-56, 18},
+ {-55, -73}, {20, 24}, {21, 22}, {-74, -54}, {-53, 23}, {-75, -76},
+ {25, 30}, {26, 27}, {-52, -51}, {28, 29}, {-77, -79}, {-50, -49},
+ {31, 39}, {32, 35}, {33, 34}, {-78, -46}, {-82, -88}, {36, 37},
+ {-83, -48}, {-47, 38}, {-86, -85}, {40, 47}, {41, 44}, {42, 43},
+ {-80, -44}, {-43, -42}, {45, 46}, {-39, -87}, {-84, -40}, {48, 55},
+ {49, 52}, {50, 51}, {-95, -94}, {-93, -92}, {53, 54}, {-91, -90},
+ {-89, -81}, {56, 59}, {57, 58}, {-45, -41}, {-38, -37}, {60, 61},
+ {-36, -35}, {-34, -33}};
+
+const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance11T[24][2] = {
+ {-64, 1}, {-63, 2}, {-65, 3}, {-66, 4}, {-62, 5}, {-61, 6},
+ {-67, 7}, {-68, 8}, {-60, 9}, {10, 16}, {11, 13}, {-69, 12},
+ {-76, -75}, {14, 15}, {-74, -73}, {-72, -71}, {17, 20}, {18, 19},
+ {-70, -59}, {-58, -57}, {21, 22}, {-56, -55}, {-54, 23}, {-53, -52}};
+
+const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance11F[24][2] = {
+ {-64, 1}, {-65, 2}, {-63, 3}, {-66, 4}, {-62, 5}, {-61, 6},
+ {-67, 7}, {-68, 8}, {-60, 9}, {10, 13}, {-69, 11}, {-59, 12},
+ {-58, -76}, {14, 17}, {15, 16}, {-75, -74}, {-73, -72}, {18, 21},
+ {19, 20}, {-71, -70}, {-57, -56}, {22, 23}, {-55, -54}, {-53, -52}};
+
+const SCHAR FDK_sbrDecoder_sbr_huffBook_NoiseLevel11T[62][2] = {
+ {-64, 1}, {-63, 2}, {-65, 3}, {-66, 4}, {-62, 5}, {-67, 6},
+ {7, 8}, {-61, -68}, {9, 30}, {10, 15}, {-60, 11}, {-69, 12},
+ {13, 14}, {-59, -53}, {-95, -94}, {16, 23}, {17, 20}, {18, 19},
+ {-93, -92}, {-91, -90}, {21, 22}, {-89, -88}, {-87, -86}, {24, 27},
+ {25, 26}, {-85, -84}, {-83, -82}, {28, 29}, {-81, -80}, {-79, -78},
+ {31, 46}, {32, 39}, {33, 36}, {34, 35}, {-77, -76}, {-75, -74},
+ {37, 38}, {-73, -72}, {-71, -70}, {40, 43}, {41, 42}, {-58, -57},
+ {-56, -55}, {44, 45}, {-54, -52}, {-51, -50}, {47, 54}, {48, 51},
+ {49, 50}, {-49, -48}, {-47, -46}, {52, 53}, {-45, -44}, {-43, -42},
+ {55, 58}, {56, 57}, {-41, -40}, {-39, -38}, {59, 60}, {-37, -36},
+ {-35, 61}, {-34, -33}};
+
+const SCHAR FDK_sbrDecoder_sbr_huffBook_NoiseBalance11T[24][2] = {
+ {-64, 1}, {-65, 2}, {-63, 3}, {4, 9}, {-66, 5}, {-62, 6},
+ {7, 8}, {-76, -75}, {-74, -73}, {10, 17}, {11, 14}, {12, 13},
+ {-72, -71}, {-70, -69}, {15, 16}, {-68, -67}, {-61, -60}, {18, 21},
+ {19, 20}, {-59, -58}, {-57, -56}, {22, 23}, {-55, -54}, {-53, -52}};
+//@}
+
+/*!
+ \name parametric stereo
+ \brief constants used by the parametric stereo part of the decoder
+
+*/
+
+/* constants used in psbitdec.cpp */
+
+/* FIX_BORDER can have 0, 1, 2, 4 envelopes */
+const UCHAR FDK_sbrDecoder_aFixNoEnvDecode[4] = {0, 1, 2, 4};
+
+/* IID & ICC Huffman codebooks */
+const SCHAR aBookPsIidTimeDecode[28][2] = {
+ {-64, 1}, {-65, 2}, {-63, 3}, {-66, 4}, {-62, 5}, {-67, 6},
+ {-61, 7}, {-68, 8}, {-60, 9}, {-69, 10}, {-59, 11}, {-70, 12},
+ {-58, 13}, {-57, 14}, {-71, 15}, {16, 17}, {-56, -72}, {18, 21},
+ {19, 20}, {-55, -78}, {-77, -76}, {22, 25}, {23, 24}, {-75, -74},
+ {-73, -54}, {26, 27}, {-53, -52}, {-51, -50}};
+
+const SCHAR aBookPsIidFreqDecode[28][2] = {
+ {-64, 1}, {2, 3}, {-63, -65}, {4, 5}, {-62, -66}, {6, 7},
+ {-61, -67}, {8, 9}, {-68, -60}, {-59, 10}, {-69, 11}, {-58, 12},
+ {-70, 13}, {-71, 14}, {-57, 15}, {16, 17}, {-56, -72}, {18, 19},
+ {-55, -54}, {20, 21}, {-73, -53}, {22, 24}, {-74, 23}, {-75, -78},
+ {25, 26}, {-77, -76}, {-52, 27}, {-51, -50}};
+
+const SCHAR aBookPsIccTimeDecode[14][2] = {
+ {-64, 1}, {-63, 2}, {-65, 3}, {-62, 4}, {-66, 5}, {-61, 6}, {-67, 7},
+ {-60, 8}, {-68, 9}, {-59, 10}, {-69, 11}, {-58, 12}, {-70, 13}, {-71, -57}};
+
+const SCHAR aBookPsIccFreqDecode[14][2] = {
+ {-64, 1}, {-63, 2}, {-65, 3}, {-62, 4}, {-66, 5}, {-61, 6}, {-67, 7},
+ {-60, 8}, {-59, 9}, {-68, 10}, {-58, 11}, {-69, 12}, {-57, 13}, {-70, -71}};
+
+/* IID-fine Huffman codebooks */
+
+const SCHAR aBookPsIidFineTimeDecode[60][2] = {
+ {1, -64}, {-63, 2}, {3, -65}, {4, 59}, {5, 7}, {6, -67},
+ {-68, -60}, {-61, 8}, {9, 11}, {-59, 10}, {-70, -58}, {12, 41},
+ {13, 20}, {14, -71}, {-55, 15}, {-53, 16}, {17, -77}, {18, 19},
+ {-85, -84}, {-46, -45}, {-57, 21}, {22, 40}, {23, 29}, {-51, 24},
+ {25, 26}, {-83, -82}, {27, 28}, {-90, -38}, {-92, -91}, {30, 37},
+ {31, 34}, {32, 33}, {-35, -34}, {-37, -36}, {35, 36}, {-94, -93},
+ {-89, -39}, {38, -79}, {39, -81}, {-88, -40}, {-74, -54}, {42, -69},
+ {43, 44}, {-72, -56}, {45, 52}, {46, 50}, {47, -76}, {-49, 48},
+ {-47, 49}, {-87, -41}, {-52, 51}, {-78, -50}, {53, -73}, {54, -75},
+ {55, 57}, {56, -80}, {-86, -42}, {-48, 58}, {-44, -43}, {-66, -62}};
+
+const SCHAR aBookPsIidFineFreqDecode[60][2] = {
+ {1, -64}, {2, 4}, {3, -65}, {-66, -62}, {-63, 5}, {6, 7},
+ {-67, -61}, {8, 9}, {-68, -60}, {10, 11}, {-69, -59}, {12, 13},
+ {-70, -58}, {14, 18}, {-57, 15}, {16, -72}, {-54, 17}, {-75, -53},
+ {19, 37}, {-56, 20}, {21, -73}, {22, 29}, {23, -76}, {24, -78},
+ {25, 28}, {26, 27}, {-85, -43}, {-83, -45}, {-81, -47}, {-52, 30},
+ {-50, 31}, {32, -79}, {33, 34}, {-82, -46}, {35, 36}, {-90, -89},
+ {-92, -91}, {38, -71}, {-55, 39}, {40, -74}, {41, 50}, {42, -77},
+ {-49, 43}, {44, 47}, {45, 46}, {-86, -42}, {-88, -87}, {48, 49},
+ {-39, -38}, {-41, -40}, {-51, 51}, {52, 59}, {53, 56}, {54, 55},
+ {-35, -34}, {-37, -36}, {57, 58}, {-94, -93}, {-84, -44}, {-80, -48}};
+
+/* constants used in psdec.cpp */
+
+/* the values of the following 3 tables are shiftet right by 1 ! */
+const FIXP_DBL ScaleFactors[NO_IID_LEVELS] = {
+
+ 0x5a5ded00, 0x59cd0400, 0x58c29680, 0x564c2e80, 0x52a3d480,
+ 0x4c8be080, 0x46df3080, 0x40000000, 0x384ba5c0, 0x304c2980,
+ 0x24e9f640, 0x1b4a2940, 0x11b5c0a0, 0x0b4e2540, 0x0514ea90};
+
+const FIXP_DBL ScaleFactorsFine[NO_IID_LEVELS_FINE] = {
+
+ 0x5a825c00, 0x5a821c00, 0x5a815100, 0x5a7ed000, 0x5a76e600, 0x5a5ded00,
+ 0x5a39b880, 0x59f1fd00, 0x5964d680, 0x5852ca00, 0x564c2e80, 0x54174480,
+ 0x50ea7500, 0x4c8be080, 0x46df3080, 0x40000000, 0x384ba5c0, 0x304c2980,
+ 0x288dd240, 0x217a2900, 0x1b4a2940, 0x13c5ece0, 0x0e2b0090, 0x0a178ef0,
+ 0x072ab798, 0x0514ea90, 0x02dc5944, 0x019bf87c, 0x00e7b173, 0x00824b8b,
+ 0x00494568};
+const FIXP_DBL Alphas[NO_ICC_LEVELS] = {
+
+ 0x00000000, 0x0b6b5be0, 0x12485f80, 0x1da2fa40,
+ 0x2637ebc0, 0x3243f6c0, 0x466b7480, 0x6487ed80};
+
+const UCHAR bins2groupMap20[NO_IID_GROUPS] = {
+ 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
+
+const UCHAR FDK_sbrDecoder_aNoIidBins[3] = {
+ NO_LOW_RES_IID_BINS, NO_MID_RES_IID_BINS, NO_HI_RES_IID_BINS};
+
+const UCHAR FDK_sbrDecoder_aNoIccBins[3] = {
+ NO_LOW_RES_ICC_BINS, NO_MID_RES_ICC_BINS, NO_HI_RES_ICC_BINS};
+
+/************************************************************************/
+/*!
+ \brief Create lookup tables for some arithmetic functions
+
+ The tables would normally be defined as const arrays,
+ but initialization at run time allows to specify their accuracy.
+*/
+/************************************************************************/
+
+/* 1/x-table: (example for INV_TABLE_BITS 8)
+
+ The table covers an input range from 0.5 to 1.0 with a step size of 1/512,
+ starting at 0.5 + 1/512.
+ Each table entry corresponds to an input interval starting 1/1024 below the
+ exact value and ending 1/1024 above it.
+
+ The table is actually a 0.5/x-table, so that the output range is again
+ 0.5...1.0 and the exponent of the result must be increased by 1.
+
+ Input range Index in table result
+ -------------------------------------------------------------------
+ 0.500000...0.500976 - 0.5 / 0.500000 = 1.000000
+ 0.500976...0.502930 0 0.5 / 0.501953 = 0.996109
+ 0.502930...0.500488 1 0.5 / 0.503906 = 0.992248
+ ...
+ 0.999023...1.000000 255 0.5 / 1.000000 = 0.500000
+
+ for (i=0; i<INV_TABLE_SIZE; i++) {
+ d = 0.5f / ( 0.5f+(double)(i+1)/(INV_TABLE_SIZE*2) ) ;
+ invTable[i] = FL2FX_SGL(d);
+ }
+*/
+const FIXP_SGL FDK_sbrDecoder_invTable[INV_TABLE_SIZE] = {
+ 0x7f80, 0x7f01, 0x7e83, 0x7e07, 0x7d8b, 0x7d11, 0x7c97, 0x7c1e, 0x7ba6,
+ 0x7b2f, 0x7ab9, 0x7a44, 0x79cf, 0x795c, 0x78e9, 0x7878, 0x7807, 0x7796,
+ 0x7727, 0x76b9, 0x764b, 0x75de, 0x7572, 0x7506, 0x749c, 0x7432, 0x73c9,
+ 0x7360, 0x72f9, 0x7292, 0x722c, 0x71c6, 0x7161, 0x70fd, 0x709a, 0x7037,
+ 0x6fd5, 0x6f74, 0x6f13, 0x6eb3, 0x6e54, 0x6df5, 0x6d97, 0x6d39, 0x6cdc,
+ 0x6c80, 0x6c24, 0x6bc9, 0x6b6f, 0x6b15, 0x6abc, 0x6a63, 0x6a0b, 0x69b3,
+ 0x695c, 0x6906, 0x68b0, 0x685a, 0x6806, 0x67b1, 0x675e, 0x670a, 0x66b8,
+ 0x6666, 0x6614, 0x65c3, 0x6572, 0x6522, 0x64d2, 0x6483, 0x6434, 0x63e6,
+ 0x6399, 0x634b, 0x62fe, 0x62b2, 0x6266, 0x621b, 0x61d0, 0x6185, 0x613b,
+ 0x60f2, 0x60a8, 0x6060, 0x6017, 0x5fcf, 0x5f88, 0x5f41, 0x5efa, 0x5eb4,
+ 0x5e6e, 0x5e28, 0x5de3, 0x5d9f, 0x5d5a, 0x5d17, 0x5cd3, 0x5c90, 0x5c4d,
+ 0x5c0b, 0x5bc9, 0x5b87, 0x5b46, 0x5b05, 0x5ac4, 0x5a84, 0x5a44, 0x5a05,
+ 0x59c6, 0x5987, 0x5949, 0x590a, 0x58cd, 0x588f, 0x5852, 0x5815, 0x57d9,
+ 0x579d, 0x5761, 0x5725, 0x56ea, 0x56af, 0x5675, 0x563b, 0x5601, 0x55c7,
+ 0x558e, 0x5555, 0x551c, 0x54e3, 0x54ab, 0x5473, 0x543c, 0x5405, 0x53ce,
+ 0x5397, 0x5360, 0x532a, 0x52f4, 0x52bf, 0x5289, 0x5254, 0x521f, 0x51eb,
+ 0x51b7, 0x5183, 0x514f, 0x511b, 0x50e8, 0x50b5, 0x5082, 0x5050, 0x501d,
+ 0x4feb, 0x4fba, 0x4f88, 0x4f57, 0x4f26, 0x4ef5, 0x4ec4, 0x4e94, 0x4e64,
+ 0x4e34, 0x4e04, 0x4dd5, 0x4da6, 0x4d77, 0x4d48, 0x4d19, 0x4ceb, 0x4cbd,
+ 0x4c8f, 0x4c61, 0x4c34, 0x4c07, 0x4bd9, 0x4bad, 0x4b80, 0x4b54, 0x4b27,
+ 0x4afb, 0x4acf, 0x4aa4, 0x4a78, 0x4a4d, 0x4a22, 0x49f7, 0x49cd, 0x49a2,
+ 0x4978, 0x494e, 0x4924, 0x48fa, 0x48d1, 0x48a7, 0x487e, 0x4855, 0x482d,
+ 0x4804, 0x47dc, 0x47b3, 0x478b, 0x4763, 0x473c, 0x4714, 0x46ed, 0x46c5,
+ 0x469e, 0x4677, 0x4651, 0x462a, 0x4604, 0x45de, 0x45b8, 0x4592, 0x456c,
+ 0x4546, 0x4521, 0x44fc, 0x44d7, 0x44b2, 0x448d, 0x4468, 0x4444, 0x441f,
+ 0x43fb, 0x43d7, 0x43b3, 0x4390, 0x436c, 0x4349, 0x4325, 0x4302, 0x42df,
+ 0x42bc, 0x4299, 0x4277, 0x4254, 0x4232, 0x4210, 0x41ee, 0x41cc, 0x41aa,
+ 0x4189, 0x4167, 0x4146, 0x4125, 0x4104, 0x40e3, 0x40c2, 0x40a1, 0x4081,
+ 0x4060, 0x4040, 0x4020, 0x4000};
diff --git a/fdk-aac/libSBRdec/src/sbr_rom.h b/fdk-aac/libSBRdec/src/sbr_rom.h
new file mode 100644
index 0000000..039743c
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbr_rom.h
@@ -0,0 +1,216 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+\file
+\brief Declaration of constant tables
+*/
+#ifndef SBR_ROM_H
+#define SBR_ROM_H
+
+#include "sbrdecoder.h"
+#include "env_extr.h"
+#include "qmf.h"
+
+#define INV_INT_TABLE_SIZE 49
+#define SBR_NF_NO_RANDOM_VAL \
+ 512 /*!< Size of random number array for noise floor */
+
+/*
+ Frequency scales
+*/
+
+/* if defined(SBRDEC_RATIO_16_64_ENABLE) ((4) = 4) else ((4) = 2) */
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_16[(4) / 2][16];
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_22[(4) / 2][16];
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_24[(4) / 2][16];
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_32[(4) / 2][16];
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_40[(4) / 2][16];
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_44[(4) / 2][16];
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_48[(4) / 2][16];
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_64[(4) / 2][16];
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_88[(4) / 2][16];
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_192[16];
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_176[16];
+extern const UCHAR FDK_sbrDecoder_sbr_start_freq_128[16];
+
+/*
+ Low-Power-Profile Transposer
+*/
+#define NUM_WHFACTOR_TABLE_ENTRIES 9
+extern const USHORT
+ FDK_sbrDecoder_sbr_whFactorsIndex[NUM_WHFACTOR_TABLE_ENTRIES];
+extern const FIXP_DBL
+ FDK_sbrDecoder_sbr_whFactorsTable[NUM_WHFACTOR_TABLE_ENTRIES][6];
+
+/*
+ Envelope Adjustor
+*/
+extern const FIXP_SGL FDK_sbrDecoder_sbr_limGains_m[4];
+extern const UCHAR FDK_sbrDecoder_sbr_limGains_e[4];
+extern const FIXP_SGL FDK_sbrDecoder_sbr_limGainsPvc_m[4];
+extern const UCHAR FDK_sbrDecoder_sbr_limGainsPvc_e[4];
+extern const FIXP_SGL FDK_sbrDecoder_sbr_limiterBandsPerOctaveDiv4[4];
+extern const FIXP_DBL FDK_sbrDecoder_sbr_limiterBandsPerOctaveDiv4_DBL[4];
+extern const FIXP_SGL FDK_sbrDecoder_sbr_smoothFilter[4];
+extern const FIXP_SGL FDK_sbrDecoder_sbr_randomPhase[SBR_NF_NO_RANDOM_VAL][2];
+
+/*
+ Envelope Extractor
+*/
+extern const int FDK_sbrDecoder_envelopeTable_8[8][5];
+extern const int FDK_sbrDecoder_envelopeTable_15[15][6];
+extern const int FDK_sbrDecoder_envelopeTable_16[16][6];
+extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info1_15;
+extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info2_15;
+extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info4_15;
+extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info8_15;
+extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info1_16;
+extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info2_16;
+extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info4_16;
+extern const FRAME_INFO FDK_sbrDecoder_sbr_frame_info8_16;
+
+extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel10T[120][2];
+extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel10F[120][2];
+extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance10T[48][2];
+extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance10F[48][2];
+extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel11T[62][2];
+extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvLevel11F[62][2];
+extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance11T[24][2];
+extern const SCHAR FDK_sbrDecoder_sbr_huffBook_EnvBalance11F[24][2];
+extern const SCHAR FDK_sbrDecoder_sbr_huffBook_NoiseLevel11T[62][2];
+extern const SCHAR FDK_sbrDecoder_sbr_huffBook_NoiseBalance11T[24][2];
+
+/*
+ Parametric stereo
+*/
+
+/* FIX_BORDER can have 0, 1, 2, 4 envelops */
+extern const UCHAR FDK_sbrDecoder_aFixNoEnvDecode[4];
+
+/* IID & ICC Huffman codebooks */
+extern const SCHAR aBookPsIidTimeDecode[28][2];
+extern const SCHAR aBookPsIidFreqDecode[28][2];
+extern const SCHAR aBookPsIccTimeDecode[14][2];
+extern const SCHAR aBookPsIccFreqDecode[14][2];
+
+/* IID-fine Huffman codebooks */
+
+extern const SCHAR aBookPsIidFineTimeDecode[60][2];
+extern const SCHAR aBookPsIidFineFreqDecode[60][2];
+
+/* the values of the following 3 tables are shiftet right by 1 ! */
+extern const FIXP_DBL ScaleFactors[NO_IID_LEVELS];
+extern const FIXP_DBL ScaleFactorsFine[NO_IID_LEVELS_FINE];
+extern const FIXP_DBL Alphas[NO_ICC_LEVELS];
+
+extern const UCHAR bins2groupMap20[NO_IID_GROUPS];
+extern const UCHAR FDK_sbrDecoder_aNoIidBins[3];
+extern const UCHAR FDK_sbrDecoder_aNoIccBins[3];
+
+/* Lookup tables for some arithmetic functions */
+
+#define INV_TABLE_BITS 8
+#define INV_TABLE_SIZE (1 << INV_TABLE_BITS)
+extern const FIXP_SGL FDK_sbrDecoder_invTable[INV_TABLE_SIZE];
+
+#endif // SBR_ROM_H
diff --git a/fdk-aac/libSBRdec/src/sbrdec_drc.cpp b/fdk-aac/libSBRdec/src/sbrdec_drc.cpp
new file mode 100644
index 0000000..2d73f32
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbrdec_drc.cpp
@@ -0,0 +1,528 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s): Christian Griebel
+
+ Description: Dynamic range control (DRC) decoder tool for SBR
+
+*******************************************************************************/
+
+#include "sbrdec_drc.h"
+
+/* DRC - Offset table for QMF interpolation. Shifted by one index position.
+ The table defines the (short) window borders rounded to the nearest QMF
+ timeslot. It has the size 16 because it is accessed with the
+ drcInterpolationScheme that is read from the bitstream with 4 bit. */
+static const UCHAR winBorderToColMappingTab[2][16] = {
+ /*-1, 0, 1, 2, 3, 4, 5, 6, 7, 8 */
+ {0, 0, 4, 8, 12, 16, 20, 24, 28, 32, 32, 32, 32, 32, 32,
+ 32}, /* 1024 framing */
+ {0, 0, 4, 8, 11, 15, 19, 23, 26, 30, 30, 30, 30, 30, 30,
+ 30} /* 960 framing */
+};
+
+/*!
+ \brief Initialize DRC QMF factors
+
+ \hDrcData Handle to DRC channel data.
+
+ \return none
+*/
+void sbrDecoder_drcInitChannel(HANDLE_SBR_DRC_CHANNEL hDrcData) {
+ int band;
+
+ if (hDrcData == NULL) {
+ return;
+ }
+
+ for (band = 0; band < (64); band++) {
+ hDrcData->prevFact_mag[band] = FL2FXCONST_DBL(0.5f);
+ }
+
+ for (band = 0; band < SBRDEC_MAX_DRC_BANDS; band++) {
+ hDrcData->currFact_mag[band] = FL2FXCONST_DBL(0.5f);
+ hDrcData->nextFact_mag[band] = FL2FXCONST_DBL(0.5f);
+ }
+
+ hDrcData->prevFact_exp = 1;
+ hDrcData->currFact_exp = 1;
+ hDrcData->nextFact_exp = 1;
+
+ hDrcData->numBandsCurr = 1;
+ hDrcData->numBandsNext = 1;
+
+ hDrcData->winSequenceCurr = 0;
+ hDrcData->winSequenceNext = 0;
+
+ hDrcData->drcInterpolationSchemeCurr = 0;
+ hDrcData->drcInterpolationSchemeNext = 0;
+
+ hDrcData->enable = 0;
+}
+
+/*!
+ \brief Swap DRC QMF scaling factors after they have been applied.
+
+ \hDrcData Handle to DRC channel data.
+
+ \return none
+*/
+void sbrDecoder_drcUpdateChannel(HANDLE_SBR_DRC_CHANNEL hDrcData) {
+ if (hDrcData == NULL) {
+ return;
+ }
+ if (hDrcData->enable != 1) {
+ return;
+ }
+
+ /* swap previous data */
+ FDKmemcpy(hDrcData->currFact_mag, hDrcData->nextFact_mag,
+ SBRDEC_MAX_DRC_BANDS * sizeof(FIXP_DBL));
+
+ hDrcData->currFact_exp = hDrcData->nextFact_exp;
+
+ hDrcData->numBandsCurr = hDrcData->numBandsNext;
+
+ FDKmemcpy(hDrcData->bandTopCurr, hDrcData->bandTopNext,
+ SBRDEC_MAX_DRC_BANDS * sizeof(USHORT));
+
+ hDrcData->drcInterpolationSchemeCurr = hDrcData->drcInterpolationSchemeNext;
+
+ hDrcData->winSequenceCurr = hDrcData->winSequenceNext;
+}
+
+/*!
+ \brief Apply DRC factors slot based.
+
+ \hDrcData Handle to DRC channel data.
+ \qmfRealSlot Pointer to real valued QMF data of one time slot.
+ \qmfImagSlot Pointer to the imaginary QMF data of one time slot.
+ \col Number of the time slot.
+ \numQmfSubSamples Total number of time slots for one frame.
+ \scaleFactor Pointer to the out scale factor of the time slot.
+
+ \return None.
+*/
+void sbrDecoder_drcApplySlot(HANDLE_SBR_DRC_CHANNEL hDrcData,
+ FIXP_DBL *qmfRealSlot, FIXP_DBL *qmfImagSlot,
+ int col, int numQmfSubSamples, int maxShift) {
+ const UCHAR *winBorderToColMap;
+
+ int band, bottomMdct, topMdct, bin, useLP;
+ int indx = numQmfSubSamples - (numQmfSubSamples >> 1) - 10; /* l_border */
+ int frameLenFlag = (numQmfSubSamples == 30) ? 1 : 0;
+ int frameSize = (frameLenFlag == 1) ? 960 : 1024;
+
+ const FIXP_DBL *fact_mag = NULL;
+ INT fact_exp = 0;
+ UINT numBands = 0;
+ USHORT *bandTop = NULL;
+ int shortDrc = 0;
+
+ FIXP_DBL alphaValue = FL2FXCONST_DBL(0.0f);
+
+ if (hDrcData == NULL) {
+ return;
+ }
+ if (hDrcData->enable != 1) {
+ return;
+ }
+
+ winBorderToColMap = winBorderToColMappingTab[frameLenFlag];
+
+ useLP = (qmfImagSlot == NULL) ? 1 : 0;
+
+ col += indx;
+ bottomMdct = 0;
+
+ /* get respective data and calc interpolation factor */
+ if (col < (numQmfSubSamples >> 1)) { /* first half of current frame */
+ if (hDrcData->winSequenceCurr != 2) { /* long window */
+ int j = col + (numQmfSubSamples >> 1);
+
+ if (hDrcData->drcInterpolationSchemeCurr == 0) {
+ INT k = (frameLenFlag) ? 0x4444445 : 0x4000000;
+
+ alphaValue = (FIXP_DBL)(j * k);
+ } else {
+ if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeCurr]) {
+ alphaValue = (FIXP_DBL)MAXVAL_DBL;
+ }
+ }
+ } else { /* short windows */
+ shortDrc = 1;
+ }
+
+ fact_mag = hDrcData->currFact_mag;
+ fact_exp = hDrcData->currFact_exp;
+ numBands = hDrcData->numBandsCurr;
+ bandTop = hDrcData->bandTopCurr;
+ } else if (col < numQmfSubSamples) { /* second half of current frame */
+ if (hDrcData->winSequenceNext != 2) { /* next: long window */
+ int j = col - (numQmfSubSamples >> 1);
+
+ if (hDrcData->drcInterpolationSchemeNext == 0) {
+ INT k = (frameLenFlag) ? 0x4444445 : 0x4000000;
+
+ alphaValue = (FIXP_DBL)(j * k);
+ } else {
+ if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) {
+ alphaValue = (FIXP_DBL)MAXVAL_DBL;
+ }
+ }
+
+ fact_mag = hDrcData->nextFact_mag;
+ fact_exp = hDrcData->nextFact_exp;
+ numBands = hDrcData->numBandsNext;
+ bandTop = hDrcData->bandTopNext;
+ } else { /* next: short windows */
+ if (hDrcData->winSequenceCurr != 2) { /* current: long window */
+ alphaValue = (FIXP_DBL)0;
+
+ fact_mag = hDrcData->nextFact_mag;
+ fact_exp = hDrcData->nextFact_exp;
+ numBands = hDrcData->numBandsNext;
+ bandTop = hDrcData->bandTopNext;
+ } else { /* current: short windows */
+ shortDrc = 1;
+
+ fact_mag = hDrcData->currFact_mag;
+ fact_exp = hDrcData->currFact_exp;
+ numBands = hDrcData->numBandsCurr;
+ bandTop = hDrcData->bandTopCurr;
+ }
+ }
+ } else { /* first half of next frame */
+ if (hDrcData->winSequenceNext != 2) { /* long window */
+ int j = col - (numQmfSubSamples >> 1);
+
+ if (hDrcData->drcInterpolationSchemeNext == 0) {
+ INT k = (frameLenFlag) ? 0x4444445 : 0x4000000;
+
+ alphaValue = (FIXP_DBL)(j * k);
+ } else {
+ if (j >= (int)winBorderToColMap[hDrcData->drcInterpolationSchemeNext]) {
+ alphaValue = (FIXP_DBL)MAXVAL_DBL;
+ }
+ }
+ } else { /* short windows */
+ shortDrc = 1;
+ }
+
+ fact_mag = hDrcData->nextFact_mag;
+ fact_exp = hDrcData->nextFact_exp;
+ numBands = hDrcData->numBandsNext;
+ bandTop = hDrcData->bandTopNext;
+
+ col -= numQmfSubSamples;
+ }
+
+ /* process bands */
+ for (band = 0; band < (int)numBands; band++) {
+ int bottomQmf, topQmf;
+
+ FIXP_DBL drcFact_mag = (FIXP_DBL)MAXVAL_DBL;
+
+ topMdct = (bandTop[band] + 1) << 2;
+
+ if (!shortDrc) { /* long window */
+ if (frameLenFlag) {
+ /* 960 framing */
+ bottomQmf = fMultIfloor((FIXP_DBL)0x4444445, bottomMdct);
+ topQmf = fMultIfloor((FIXP_DBL)0x4444445, topMdct);
+
+ topMdct = 30 * topQmf;
+ } else {
+ /* 1024 framing */
+ topMdct &= ~0x1f;
+
+ bottomQmf = bottomMdct >> 5;
+ topQmf = topMdct >> 5;
+ }
+
+ if (band == ((int)numBands - 1)) {
+ topQmf = (64);
+ }
+
+ for (bin = bottomQmf; bin < topQmf; bin++) {
+ FIXP_DBL drcFact1_mag = hDrcData->prevFact_mag[bin];
+ FIXP_DBL drcFact2_mag = fact_mag[band];
+
+ /* normalize scale factors */
+ if (hDrcData->prevFact_exp < maxShift) {
+ drcFact1_mag >>= maxShift - hDrcData->prevFact_exp;
+ }
+ if (fact_exp < maxShift) {
+ drcFact2_mag >>= maxShift - fact_exp;
+ }
+
+ /* interpolate */
+ if (alphaValue == (FIXP_DBL)0) {
+ drcFact_mag = drcFact1_mag;
+ } else if (alphaValue == (FIXP_DBL)MAXVAL_DBL) {
+ drcFact_mag = drcFact2_mag;
+ } else {
+ drcFact_mag =
+ fMult(alphaValue, drcFact2_mag) +
+ fMult(((FIXP_DBL)MAXVAL_DBL - alphaValue), drcFact1_mag);
+ }
+
+ /* apply scaling */
+ qmfRealSlot[bin] = fMult(qmfRealSlot[bin], drcFact_mag);
+ if (!useLP) {
+ qmfImagSlot[bin] = fMult(qmfImagSlot[bin], drcFact_mag);
+ }
+
+ /* save previous factors */
+ if (col == (numQmfSubSamples >> 1) - 1) {
+ hDrcData->prevFact_mag[bin] = fact_mag[band];
+ }
+ }
+ } else { /* short windows */
+ unsigned startWinIdx, stopWinIdx;
+ int startCol, stopCol;
+ FIXP_DBL invFrameSizeDiv8 =
+ (frameLenFlag) ? (FIXP_DBL)0x1111112 : (FIXP_DBL)0x1000000;
+
+ /* limit top at the frame borders */
+ if (topMdct < 0) {
+ topMdct = 0;
+ }
+ if (topMdct >= frameSize) {
+ topMdct = frameSize - 1;
+ }
+
+ if (frameLenFlag) {
+ /* 960 framing */
+ topMdct = fMultIfloor((FIXP_DBL)0x78000000,
+ fMultIfloor((FIXP_DBL)0x22222223, topMdct) << 2);
+
+ startWinIdx = fMultIfloor(invFrameSizeDiv8, bottomMdct) +
+ 1; /* winBorderToColMap table has offset of 1 */
+ stopWinIdx = fMultIceil(invFrameSizeDiv8 - (FIXP_DBL)1, topMdct) + 1;
+ } else {
+ /* 1024 framing */
+ topMdct &= ~0x03;
+
+ startWinIdx = fMultIfloor(invFrameSizeDiv8, bottomMdct) + 1;
+ stopWinIdx = fMultIceil(invFrameSizeDiv8, topMdct) + 1;
+ }
+
+ /* startCol is truncated to the nearest corresponding start subsample in
+ the QMF of the short window bottom is present in:*/
+ startCol = (int)winBorderToColMap[startWinIdx];
+
+ /* stopCol is rounded upwards to the nearest corresponding stop subsample
+ in the QMF of the short window top is present in. */
+ stopCol = (int)winBorderToColMap[stopWinIdx];
+
+ bottomQmf = fMultIfloor(invFrameSizeDiv8,
+ ((bottomMdct % (numQmfSubSamples << 2)) << 5));
+ topQmf = fMultIfloor(invFrameSizeDiv8,
+ ((topMdct % (numQmfSubSamples << 2)) << 5));
+
+ /* extend last band */
+ if (band == ((int)numBands - 1)) {
+ topQmf = (64);
+ stopCol = numQmfSubSamples;
+ stopWinIdx = 10;
+ }
+
+ if (topQmf == 0) {
+ if (frameLenFlag) {
+ FIXP_DBL rem = fMult(invFrameSizeDiv8,
+ (FIXP_DBL)(topMdct << (DFRACT_BITS - 12)));
+ if ((LONG)rem & (LONG)0x1F) {
+ stopWinIdx -= 1;
+ stopCol = (int)winBorderToColMap[stopWinIdx];
+ }
+ }
+ topQmf = (64);
+ }
+
+ /* save previous factors */
+ if (stopCol == numQmfSubSamples) {
+ int tmpBottom = bottomQmf;
+
+ if ((int)winBorderToColMap[8] > startCol) {
+ tmpBottom = 0; /* band starts in previous short window */
+ }
+
+ for (bin = tmpBottom; bin < topQmf; bin++) {
+ hDrcData->prevFact_mag[bin] = fact_mag[band];
+ }
+ }
+
+ /* apply */
+ if ((col >= startCol) && (col < stopCol)) {
+ if (col >= (int)winBorderToColMap[startWinIdx + 1]) {
+ bottomQmf = 0; /* band starts in previous short window */
+ }
+ if (col < (int)winBorderToColMap[stopWinIdx - 1]) {
+ topQmf = (64); /* band ends in next short window */
+ }
+
+ drcFact_mag = fact_mag[band];
+
+ /* normalize scale factor */
+ if (fact_exp < maxShift) {
+ drcFact_mag >>= maxShift - fact_exp;
+ }
+
+ /* apply scaling */
+ for (bin = bottomQmf; bin < topQmf; bin++) {
+ qmfRealSlot[bin] = fMult(qmfRealSlot[bin], drcFact_mag);
+ if (!useLP) {
+ qmfImagSlot[bin] = fMult(qmfImagSlot[bin], drcFact_mag);
+ }
+ }
+ }
+ }
+
+ bottomMdct = topMdct;
+ } /* end of bands loop */
+
+ if (col == (numQmfSubSamples >> 1) - 1) {
+ hDrcData->prevFact_exp = fact_exp;
+ }
+}
+
+/*!
+ \brief Apply DRC factors frame based.
+
+ \hDrcData Handle to DRC channel data.
+ \qmfRealSlot Pointer to real valued QMF data of the whole frame.
+ \qmfImagSlot Pointer to the imaginary QMF data of the whole frame.
+ \numQmfSubSamples Total number of time slots for one frame.
+ \scaleFactor Pointer to the out scale factor of the frame.
+
+ \return None.
+*/
+void sbrDecoder_drcApply(HANDLE_SBR_DRC_CHANNEL hDrcData,
+ FIXP_DBL **QmfBufferReal, FIXP_DBL **QmfBufferImag,
+ int numQmfSubSamples, int *scaleFactor) {
+ int col;
+ int maxShift = 0;
+
+ if (hDrcData == NULL) {
+ return;
+ }
+ if (hDrcData->enable == 0) {
+ return; /* Avoid changing the scaleFactor even though the processing is
+ disabled. */
+ }
+
+ /* get max scale factor */
+ if (hDrcData->prevFact_exp > maxShift) {
+ maxShift = hDrcData->prevFact_exp;
+ }
+ if (hDrcData->currFact_exp > maxShift) {
+ maxShift = hDrcData->currFact_exp;
+ }
+ if (hDrcData->nextFact_exp > maxShift) {
+ maxShift = hDrcData->nextFact_exp;
+ }
+
+ for (col = 0; col < numQmfSubSamples; col++) {
+ FIXP_DBL *qmfSlotReal = QmfBufferReal[col];
+ FIXP_DBL *qmfSlotImag = (QmfBufferImag == NULL) ? NULL : QmfBufferImag[col];
+
+ sbrDecoder_drcApplySlot(hDrcData, qmfSlotReal, qmfSlotImag, col,
+ numQmfSubSamples, maxShift);
+ }
+
+ *scaleFactor += maxShift;
+}
diff --git a/fdk-aac/libSBRdec/src/sbrdec_drc.h b/fdk-aac/libSBRdec/src/sbrdec_drc.h
new file mode 100644
index 0000000..2eb0e20
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbrdec_drc.h
@@ -0,0 +1,149 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s): Christian Griebel
+
+ Description: Dynamic range control (DRC) decoder tool for SBR
+
+*******************************************************************************/
+
+#ifndef SBRDEC_DRC_H
+#define SBRDEC_DRC_H
+
+#include "sbrdecoder.h"
+
+#define SBRDEC_MAX_DRC_CHANNELS (8)
+#define SBRDEC_MAX_DRC_BANDS (16)
+
+typedef struct {
+ FIXP_DBL prevFact_mag[(64)];
+ INT prevFact_exp;
+
+ FIXP_DBL currFact_mag[SBRDEC_MAX_DRC_BANDS];
+ FIXP_DBL nextFact_mag[SBRDEC_MAX_DRC_BANDS];
+ INT currFact_exp;
+ INT nextFact_exp;
+
+ UINT numBandsCurr;
+ UINT numBandsNext;
+ USHORT bandTopCurr[SBRDEC_MAX_DRC_BANDS];
+ USHORT bandTopNext[SBRDEC_MAX_DRC_BANDS];
+
+ SHORT drcInterpolationSchemeCurr;
+ SHORT drcInterpolationSchemeNext;
+
+ SHORT enable;
+
+ UCHAR winSequenceCurr;
+ UCHAR winSequenceNext;
+
+} SBRDEC_DRC_CHANNEL;
+
+typedef SBRDEC_DRC_CHANNEL *HANDLE_SBR_DRC_CHANNEL;
+
+void sbrDecoder_drcInitChannel(HANDLE_SBR_DRC_CHANNEL hDrcData);
+
+void sbrDecoder_drcUpdateChannel(HANDLE_SBR_DRC_CHANNEL hDrcData);
+
+void sbrDecoder_drcApplySlot(HANDLE_SBR_DRC_CHANNEL hDrcData,
+ FIXP_DBL *qmfRealSlot, FIXP_DBL *qmfImagSlot,
+ int col, int numQmfSubSamples, int maxShift);
+
+void sbrDecoder_drcApply(HANDLE_SBR_DRC_CHANNEL hDrcData,
+ FIXP_DBL **QmfBufferReal, FIXP_DBL **QmfBufferImag,
+ int numQmfSubSamples, int *scaleFactor);
+
+#endif /* SBRDEC_DRC_H */
diff --git a/fdk-aac/libSBRdec/src/sbrdec_freq_sca.cpp b/fdk-aac/libSBRdec/src/sbrdec_freq_sca.cpp
new file mode 100644
index 0000000..165f94b
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbrdec_freq_sca.cpp
@@ -0,0 +1,835 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Frequency scale calculation
+*/
+
+#include "sbrdec_freq_sca.h"
+
+#include "transcendent.h"
+#include "sbr_rom.h"
+#include "env_extr.h"
+
+#include "genericStds.h" /* need log() for debug-code only */
+
+#define MAX_OCTAVE 29
+#define MAX_SECOND_REGION 50
+
+static int numberOfBands(FIXP_SGL bpo_div16, int start, int stop, int warpFlag);
+static void CalcBands(UCHAR *diff, UCHAR start, UCHAR stop, UCHAR num_bands);
+static SBR_ERROR modifyBands(UCHAR max_band, UCHAR *diff, UCHAR length);
+static void cumSum(UCHAR start_value, UCHAR *diff, UCHAR length,
+ UCHAR *start_adress);
+
+/*!
+ \brief Retrieve QMF-band where the SBR range starts
+
+ Convert startFreq which was read from the bitstream into a
+ QMF-channel number.
+
+ \return Number of start band
+*/
+static UCHAR getStartBand(
+ UINT fs, /*!< Output sampling frequency */
+ UCHAR startFreq, /*!< Index to table of possible start bands */
+ UINT headerDataFlags) /*!< Info to SBR mode */
+{
+ INT band;
+ UINT fsMapped = fs;
+ SBR_RATE rate = DUAL;
+
+ if (headerDataFlags & (SBRDEC_SYNTAX_USAC | SBRDEC_SYNTAX_RSVD50)) {
+ if (headerDataFlags & SBRDEC_QUAD_RATE) {
+ rate = QUAD;
+ }
+ fsMapped = sbrdec_mapToStdSampleRate(fs, 1);
+ }
+
+ FDK_ASSERT(2 * (rate + 1) <= (4));
+
+ switch (fsMapped) {
+ case 192000:
+ band = FDK_sbrDecoder_sbr_start_freq_192[startFreq];
+ break;
+ case 176400:
+ band = FDK_sbrDecoder_sbr_start_freq_176[startFreq];
+ break;
+ case 128000:
+ band = FDK_sbrDecoder_sbr_start_freq_128[startFreq];
+ break;
+ case 96000:
+ case 88200:
+ band = FDK_sbrDecoder_sbr_start_freq_88[rate][startFreq];
+ break;
+ case 64000:
+ band = FDK_sbrDecoder_sbr_start_freq_64[rate][startFreq];
+ break;
+ case 48000:
+ band = FDK_sbrDecoder_sbr_start_freq_48[rate][startFreq];
+ break;
+ case 44100:
+ band = FDK_sbrDecoder_sbr_start_freq_44[rate][startFreq];
+ break;
+ case 40000:
+ band = FDK_sbrDecoder_sbr_start_freq_40[rate][startFreq];
+ break;
+ case 32000:
+ band = FDK_sbrDecoder_sbr_start_freq_32[rate][startFreq];
+ break;
+ case 24000:
+ band = FDK_sbrDecoder_sbr_start_freq_24[rate][startFreq];
+ break;
+ case 22050:
+ band = FDK_sbrDecoder_sbr_start_freq_22[rate][startFreq];
+ break;
+ case 16000:
+ band = FDK_sbrDecoder_sbr_start_freq_16[rate][startFreq];
+ break;
+ default:
+ band = 255;
+ }
+
+ return band;
+}
+
+/*!
+ \brief Retrieve QMF-band where the SBR range starts
+
+ Convert startFreq which was read from the bitstream into a
+ QMF-channel number.
+
+ \return Number of start band
+*/
+static UCHAR getStopBand(
+ UINT fs, /*!< Output sampling frequency */
+ UCHAR stopFreq, /*!< Index to table of possible start bands */
+ UINT headerDataFlags, /*!< Info to SBR mode */
+ UCHAR k0) /*!< Start freq index */
+{
+ UCHAR k2;
+
+ if (stopFreq < 14) {
+ INT stopMin;
+ INT num = 2 * (64);
+ UCHAR diff_tot[MAX_OCTAVE + MAX_SECOND_REGION];
+ UCHAR *diff0 = diff_tot;
+ UCHAR *diff1 = diff_tot + MAX_OCTAVE;
+
+ if (headerDataFlags & SBRDEC_QUAD_RATE) {
+ num >>= 1;
+ }
+
+ if (fs < 32000) {
+ stopMin = (((2 * 6000 * num) / fs) + 1) >> 1;
+ } else {
+ if (fs < 64000) {
+ stopMin = (((2 * 8000 * num) / fs) + 1) >> 1;
+ } else {
+ stopMin = (((2 * 10000 * num) / fs) + 1) >> 1;
+ }
+ }
+
+ /*
+ Choose a stop band between k1 and 64 depending on stopFreq (0..13),
+ based on a logarithmic scale.
+ The vectors diff0 and diff1 are used temporarily here.
+ */
+ CalcBands(diff0, stopMin, 64, 13);
+ shellsort(diff0, 13);
+ cumSum(stopMin, diff0, 13, diff1);
+ k2 = diff1[stopFreq];
+ } else if (stopFreq == 14)
+ k2 = 2 * k0;
+ else
+ k2 = 3 * k0;
+
+ /* Limit to Nyquist */
+ if (k2 > (64)) k2 = (64);
+
+ /* Range checks */
+ /* 1 <= difference <= 48; 1 <= fs <= 96000 */
+ {
+ UCHAR max_freq_coeffs = (headerDataFlags & SBRDEC_QUAD_RATE)
+ ? MAX_FREQ_COEFFS_QUAD_RATE
+ : MAX_FREQ_COEFFS;
+ if (((k2 - k0) > max_freq_coeffs) || (k2 <= k0)) {
+ return 255;
+ }
+ }
+
+ if (headerDataFlags & SBRDEC_QUAD_RATE) {
+ return k2; /* skip other checks: (k2 - k0) must be <=
+ MAX_FREQ_COEFFS_QUAD_RATE for all fs */
+ }
+ if (headerDataFlags & (SBRDEC_SYNTAX_USAC | SBRDEC_SYNTAX_RSVD50)) {
+ /* 1 <= difference <= 35; 42000 <= fs <= 96000 */
+ if ((fs >= 42000) && ((k2 - k0) > MAX_FREQ_COEFFS_FS44100)) {
+ return 255;
+ }
+ /* 1 <= difference <= 32; 46009 <= fs <= 96000 */
+ if ((fs >= 46009) && ((k2 - k0) > MAX_FREQ_COEFFS_FS48000)) {
+ return 255;
+ }
+ } else {
+ /* 1 <= difference <= 35; fs == 44100 */
+ if ((fs == 44100) && ((k2 - k0) > MAX_FREQ_COEFFS_FS44100)) {
+ return 255;
+ }
+ /* 1 <= difference <= 32; 48000 <= fs <= 96000 */
+ if ((fs >= 48000) && ((k2 - k0) > MAX_FREQ_COEFFS_FS48000)) {
+ return 255;
+ }
+ }
+
+ return k2;
+}
+
+/*!
+ \brief Generates master frequency tables
+
+ Frequency tables are calculated according to the selected domain
+ (linear/logarithmic) and granularity.
+ IEC 14496-3 4.6.18.3.2.1
+
+ \return errorCode, 0 if successful
+*/
+SBR_ERROR
+sbrdecUpdateFreqScale(
+ UCHAR *v_k_master, /*!< Master table to be created */
+ UCHAR *numMaster, /*!< Number of entries in master table */
+ UINT fs, /*!< SBR working sampling rate */
+ HANDLE_SBR_HEADER_DATA hHeaderData, /*!< Control data from bitstream */
+ UINT flags) {
+ FIXP_SGL bpo_div16; /* bands_per_octave divided by 16 */
+ INT dk = 0;
+
+ /* Internal variables */
+ UCHAR k0, k2, i;
+ UCHAR num_bands0 = 0;
+ UCHAR num_bands1 = 0;
+ UCHAR diff_tot[MAX_OCTAVE + MAX_SECOND_REGION];
+ UCHAR *diff0 = diff_tot;
+ UCHAR *diff1 = diff_tot + MAX_OCTAVE;
+ INT k2_achived;
+ INT k2_diff;
+ INT incr = 0;
+
+ /*
+ Determine start band
+ */
+ if (flags & SBRDEC_QUAD_RATE) {
+ fs >>= 1;
+ }
+
+ k0 = getStartBand(fs, hHeaderData->bs_data.startFreq, flags);
+ if (k0 == 255) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ /*
+ Determine stop band
+ */
+ k2 = getStopBand(fs, hHeaderData->bs_data.stopFreq, flags, k0);
+ if (k2 == 255) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ if (hHeaderData->bs_data.freqScale > 0) { /* Bark */
+ INT k1;
+
+ if (hHeaderData->bs_data.freqScale == 1) {
+ bpo_div16 = FL2FXCONST_SGL(12.0f / 16.0f);
+ } else if (hHeaderData->bs_data.freqScale == 2) {
+ bpo_div16 = FL2FXCONST_SGL(10.0f / 16.0f);
+ } else {
+ bpo_div16 = FL2FXCONST_SGL(8.0f / 16.0f);
+ }
+
+ /* Ref: ISO/IEC 23003-3, Figure 12 - Flowchart calculation of fMaster for
+ * 4:1 system when bs_freq_scale > 0 */
+ if (flags & SBRDEC_QUAD_RATE) {
+ if ((SHORT)k0 < (SHORT)(bpo_div16 >> ((FRACT_BITS - 1) - 4))) {
+ bpo_div16 = (FIXP_SGL)(k0 & (UCHAR)0xfe)
+ << ((FRACT_BITS - 1) - 4); /* bpo_div16 = floor(k0/2)*2 */
+ }
+ }
+
+ if (1000 * k2 > 2245 * k0) { /* Two or more regions */
+ k1 = 2 * k0;
+
+ num_bands0 = numberOfBands(bpo_div16, k0, k1, 0);
+ num_bands1 =
+ numberOfBands(bpo_div16, k1, k2, hHeaderData->bs_data.alterScale);
+ if (num_bands0 < 1) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+ if (num_bands1 < 1) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ CalcBands(diff0, k0, k1, num_bands0);
+ shellsort(diff0, num_bands0);
+ if (diff0[0] == 0) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ cumSum(k0, diff0, num_bands0, v_k_master);
+
+ CalcBands(diff1, k1, k2, num_bands1);
+ shellsort(diff1, num_bands1);
+ if (diff0[num_bands0 - 1] > diff1[0]) {
+ SBR_ERROR err;
+
+ err = modifyBands(diff0[num_bands0 - 1], diff1, num_bands1);
+ if (err) return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ /* Add 2nd region */
+ cumSum(k1, diff1, num_bands1, &v_k_master[num_bands0]);
+ *numMaster = num_bands0 + num_bands1; /* Output nr of bands */
+
+ } else { /* Only one region */
+ k1 = k2;
+
+ num_bands0 = numberOfBands(bpo_div16, k0, k1, 0);
+ if (num_bands0 < 1) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+ CalcBands(diff0, k0, k1, num_bands0);
+ shellsort(diff0, num_bands0);
+ if (diff0[0] == 0) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ cumSum(k0, diff0, num_bands0, v_k_master);
+ *numMaster = num_bands0; /* Output nr of bands */
+ }
+ } else { /* Linear mode */
+ if (hHeaderData->bs_data.alterScale == 0) {
+ dk = 1;
+ /* FLOOR to get to few number of bands (next lower even number) */
+ num_bands0 = (k2 - k0) & 254;
+ } else {
+ dk = 2;
+ num_bands0 = (((k2 - k0) >> 1) + 1) & 254; /* ROUND to the closest fit */
+ }
+
+ if (num_bands0 < 1) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ /* We must return already here because 'i' can become negative below. */
+ }
+
+ k2_achived = k0 + num_bands0 * dk;
+ k2_diff = k2 - k2_achived;
+
+ for (i = 0; i < num_bands0; i++) diff_tot[i] = dk;
+
+ /* If linear scale wasn't achieved */
+ /* and we got too wide SBR area */
+ if (k2_diff < 0) {
+ incr = 1;
+ i = 0;
+ }
+
+ /* If linear scale wasn't achieved */
+ /* and we got too small SBR area */
+ if (k2_diff > 0) {
+ incr = -1;
+ i = num_bands0 - 1;
+ }
+
+ /* Adjust diff vector to get sepc. SBR range */
+ while (k2_diff != 0) {
+ diff_tot[i] = diff_tot[i] - incr;
+ i = i + incr;
+ k2_diff = k2_diff + incr;
+ }
+
+ cumSum(k0, diff_tot, num_bands0, v_k_master); /* cumsum */
+ *numMaster = num_bands0; /* Output nr of bands */
+ }
+
+ if (*numMaster < 1) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ /* Ref: ISO/IEC 23003-3 Cor.3, "In 7.5.5.2, add to the requirements:"*/
+ if (flags & SBRDEC_QUAD_RATE) {
+ int k;
+ for (k = 1; k < *numMaster; k++) {
+ if (!(v_k_master[k] - v_k_master[k - 1] <= k0 - 2)) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+ }
+ }
+
+ /*
+ Print out the calculated table
+ */
+
+ return SBRDEC_OK;
+}
+
+/*!
+ \brief Calculate frequency ratio of one SBR band
+
+ All SBR bands should span a constant frequency range in the logarithmic
+ domain. This function calculates the ratio of any SBR band's upper and lower
+ frequency.
+
+ \return num_band-th root of k_start/k_stop
+*/
+static FIXP_SGL calcFactorPerBand(int k_start, int k_stop, int num_bands) {
+ /* Scaled bandfactor and step 1 bit right to avoid overflow
+ * use double data type */
+ FIXP_DBL bandfactor = FL2FXCONST_DBL(0.25f); /* Start value */
+ FIXP_DBL step = FL2FXCONST_DBL(0.125f); /* Initial increment for factor */
+
+ int direction = 1;
+
+ /* Because saturation can't be done in INT IIS,
+ * changed start and stop data type from FIXP_SGL to FIXP_DBL */
+ FIXP_DBL start = k_start << (DFRACT_BITS - 8);
+ FIXP_DBL stop = k_stop << (DFRACT_BITS - 8);
+
+ FIXP_DBL temp;
+
+ int j, i = 0;
+
+ while (step > FL2FXCONST_DBL(0.0f)) {
+ i++;
+ temp = stop;
+
+ /* Calculate temp^num_bands: */
+ for (j = 0; j < num_bands; j++)
+ // temp = fMult(temp,bandfactor);
+ temp = fMultDiv2(temp, bandfactor) << 2;
+
+ if (temp < start) { /* Factor too strong, make it weaker */
+ if (direction == 0)
+ /* Halfen step. Right shift is not done as fract because otherwise the
+ lowest bit cannot be cleared due to rounding */
+ step = (FIXP_DBL)((LONG)step >> 1);
+ direction = 1;
+ bandfactor = bandfactor + step;
+ } else { /* Factor is too weak: make it stronger */
+ if (direction == 1) step = (FIXP_DBL)((LONG)step >> 1);
+ direction = 0;
+ bandfactor = bandfactor - step;
+ }
+
+ if (i > 100) {
+ step = FL2FXCONST_DBL(0.0f);
+ }
+ }
+ return FX_DBL2FX_SGL(bandfactor << 1);
+}
+
+/*!
+ \brief Calculate number of SBR bands between start and stop band
+
+ Given the number of bands per octave, this function calculates how many
+ bands fit in the given frequency range.
+ When the warpFlag is set, the 'band density' is decreased by a factor
+ of 1/1.3
+
+ \return number of bands
+*/
+static int numberOfBands(
+ FIXP_SGL bpo_div16, /*!< Input: number of bands per octave divided by 16 */
+ int start, /*!< First QMF band of SBR frequency range */
+ int stop, /*!< Last QMF band of SBR frequency range + 1 */
+ int warpFlag) /*!< Stretching flag */
+{
+ FIXP_SGL num_bands_div128;
+ int num_bands;
+
+ num_bands_div128 =
+ FX_DBL2FX_SGL(fMult(FDK_getNumOctavesDiv8(start, stop), bpo_div16));
+
+ if (warpFlag) {
+ /* Apply the warp factor of 1.3 to get wider bands. We use a value
+ of 32768/25200 instead of the exact value to avoid critical cases
+ of rounding.
+ */
+ num_bands_div128 = FX_DBL2FX_SGL(
+ fMult(num_bands_div128, FL2FXCONST_SGL(25200.0 / 32768.0)));
+ }
+
+ /* add scaled 1 for rounding to even numbers: */
+ num_bands_div128 = num_bands_div128 + FL2FXCONST_SGL(1.0f / 128.0f);
+ /* scale back to right aligned integer and double the value: */
+ num_bands = 2 * ((LONG)num_bands_div128 >> (FRACT_BITS - 7));
+
+ return (num_bands);
+}
+
+/*!
+ \brief Calculate width of SBR bands
+
+ Given the desired number of bands within the SBR frequency range,
+ this function calculates the width of each SBR band in QMF channels.
+ The bands get wider from start to stop (bark scale).
+*/
+static void CalcBands(UCHAR *diff, /*!< Vector of widths to be calculated */
+ UCHAR start, /*!< Lower end of subband range */
+ UCHAR stop, /*!< Upper end of subband range */
+ UCHAR num_bands) /*!< Desired number of bands */
+{
+ int i;
+ int previous;
+ int current;
+ FIXP_SGL exact, temp;
+ FIXP_SGL bandfactor = calcFactorPerBand(start, stop, num_bands);
+
+ previous = stop; /* Start with highest QMF channel */
+ exact = (FIXP_SGL)(
+ stop << (FRACT_BITS - 8)); /* Shift left to gain some accuracy */
+
+ for (i = num_bands - 1; i >= 0; i--) {
+ /* Calculate border of next lower sbr band */
+ exact = FX_DBL2FX_SGL(fMult(exact, bandfactor));
+
+ /* Add scaled 0.5 for rounding:
+ We use a value 128/256 instead of 0.5 to avoid some critical cases of
+ rounding. */
+ temp = exact + FL2FXCONST_SGL(128.0 / 32768.0);
+
+ /* scale back to right alinged integer: */
+ current = (LONG)temp >> (FRACT_BITS - 8);
+
+ /* Save width of band i */
+ diff[i] = previous - current;
+ previous = current;
+ }
+}
+
+/*!
+ \brief Calculate cumulated sum vector from delta vector
+*/
+static void cumSum(UCHAR start_value, UCHAR *diff, UCHAR length,
+ UCHAR *start_adress) {
+ int i;
+ start_adress[0] = start_value;
+ for (i = 1; i <= length; i++)
+ start_adress[i] = start_adress[i - 1] + diff[i - 1];
+}
+
+/*!
+ \brief Adapt width of frequency bands in the second region
+
+ If SBR spans more than 2 octaves, the upper part of a bark-frequency-scale
+ is calculated separately. This function tries to avoid that the second region
+ starts with a band smaller than the highest band of the first region.
+*/
+static SBR_ERROR modifyBands(UCHAR max_band_previous, UCHAR *diff,
+ UCHAR length) {
+ int change = max_band_previous - diff[0];
+
+ /* Limit the change so that the last band cannot get narrower than the first
+ * one */
+ if (change > (diff[length - 1] - diff[0]) >> 1)
+ change = (diff[length - 1] - diff[0]) >> 1;
+
+ diff[0] += change;
+ diff[length - 1] -= change;
+ shellsort(diff, length);
+
+ return SBRDEC_OK;
+}
+
+/*!
+ \brief Update high resolution frequency band table
+*/
+static void sbrdecUpdateHiRes(UCHAR *h_hires, UCHAR *num_hires,
+ UCHAR *v_k_master, UCHAR num_bands,
+ UCHAR xover_band) {
+ UCHAR i;
+
+ *num_hires = num_bands - xover_band;
+
+ for (i = xover_band; i <= num_bands; i++) {
+ h_hires[i - xover_band] = v_k_master[i];
+ }
+}
+
+/*!
+ \brief Build low resolution table out of high resolution table
+*/
+static void sbrdecUpdateLoRes(UCHAR *h_lores, UCHAR *num_lores, UCHAR *h_hires,
+ UCHAR num_hires) {
+ UCHAR i;
+
+ if ((num_hires & 1) == 0) {
+ /* If even number of hires bands */
+ *num_lores = num_hires >> 1;
+ /* Use every second lores=hires[0,2,4...] */
+ for (i = 0; i <= *num_lores; i++) h_lores[i] = h_hires[i * 2];
+ } else {
+ /* Odd number of hires, which means xover is odd */
+ *num_lores = (num_hires + 1) >> 1;
+ /* Use lores=hires[0,1,3,5 ...] */
+ h_lores[0] = h_hires[0];
+ for (i = 1; i <= *num_lores; i++) {
+ h_lores[i] = h_hires[i * 2 - 1];
+ }
+ }
+}
+
+/*!
+ \brief Derive a low-resolution frequency-table from the master frequency
+ table
+*/
+void sbrdecDownSampleLoRes(UCHAR *v_result, UCHAR num_result,
+ UCHAR *freqBandTableRef, UCHAR num_Ref) {
+ int step;
+ int i, j;
+ int org_length, result_length;
+ int v_index[MAX_FREQ_COEFFS >> 1];
+
+ /* init */
+ org_length = num_Ref;
+ result_length = num_result;
+
+ v_index[0] = 0; /* Always use left border */
+ i = 0;
+ while (org_length > 0) {
+ /* Create downsample vector */
+ i++;
+ step = org_length / result_length;
+ org_length = org_length - step;
+ result_length--;
+ v_index[i] = v_index[i - 1] + step;
+ }
+
+ for (j = 0; j <= i; j++) {
+ /* Use downsample vector to index LoResolution vector */
+ v_result[j] = freqBandTableRef[v_index[j]];
+ }
+}
+
+/*!
+ \brief Sorting routine
+*/
+void shellsort(UCHAR *in, UCHAR n) {
+ int i, j, v, w;
+ int inc = 1;
+
+ do
+ inc = 3 * inc + 1;
+ while (inc <= n);
+
+ do {
+ inc = inc / 3;
+ for (i = inc; i < n; i++) {
+ v = in[i];
+ j = i;
+ while ((w = in[j - inc]) > v) {
+ in[j] = w;
+ j -= inc;
+ if (j < inc) break;
+ }
+ in[j] = v;
+ }
+ } while (inc > 1);
+}
+
+/*!
+ \brief Reset frequency band tables
+ \return errorCode, 0 if successful
+*/
+SBR_ERROR
+resetFreqBandTables(HANDLE_SBR_HEADER_DATA hHeaderData, const UINT flags) {
+ SBR_ERROR err = SBRDEC_OK;
+ int k2, kx, lsb, usb;
+ int intTemp;
+ UCHAR nBandsLo, nBandsHi;
+ HANDLE_FREQ_BAND_DATA hFreq = &hHeaderData->freqBandData;
+
+ /* Calculate master frequency function */
+ err = sbrdecUpdateFreqScale(hFreq->v_k_master, &hFreq->numMaster,
+ hHeaderData->sbrProcSmplRate, hHeaderData, flags);
+
+ if (err || (hHeaderData->bs_info.xover_band > hFreq->numMaster)) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ /* Derive Hiresolution from master frequency function */
+ sbrdecUpdateHiRes(hFreq->freqBandTable[1], &nBandsHi, hFreq->v_k_master,
+ hFreq->numMaster, hHeaderData->bs_info.xover_band);
+ /* Derive Loresolution from Hiresolution */
+ sbrdecUpdateLoRes(hFreq->freqBandTable[0], &nBandsLo, hFreq->freqBandTable[1],
+ nBandsHi);
+
+ hFreq->nSfb[0] = nBandsLo;
+ hFreq->nSfb[1] = nBandsHi;
+
+ /* Check index to freqBandTable[0] */
+ if (!(nBandsLo > 0) ||
+ (nBandsLo > (((hHeaderData->numberOfAnalysisBands == 16)
+ ? MAX_FREQ_COEFFS_QUAD_RATE
+ : MAX_FREQ_COEFFS_DUAL_RATE) >>
+ 1))) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ lsb = hFreq->freqBandTable[0][0];
+ usb = hFreq->freqBandTable[0][nBandsLo];
+
+ /* Check for start frequency border k_x:
+ - ISO/IEC 14496-3 4.6.18.3.6 Requirements
+ - ISO/IEC 23003-3 7.5.5.2 Modifications and additions to the MPEG-4 SBR
+ tool
+ */
+ /* Note that lsb > as hHeaderData->numberOfAnalysisBands is a valid SBR config
+ * for 24 band QMF analysis. */
+ if ((lsb > ((flags & SBRDEC_QUAD_RATE) ? 16 : (32))) || (lsb >= usb)) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ /* Calculate number of noise bands */
+
+ k2 = hFreq->freqBandTable[1][nBandsHi];
+ kx = hFreq->freqBandTable[1][0];
+
+ if (hHeaderData->bs_data.noise_bands == 0) {
+ hFreq->nNfb = 1;
+ } else /* Calculate no of noise bands 1,2 or 3 bands/octave */
+ {
+ /* Fetch number of octaves divided by 32 */
+ intTemp = (LONG)FDK_getNumOctavesDiv8(kx, k2) >> 2;
+
+ /* Integer-Multiplication with number of bands: */
+ intTemp = intTemp * hHeaderData->bs_data.noise_bands;
+
+ /* Add scaled 0.5 for rounding: */
+ intTemp = intTemp + (LONG)FL2FXCONST_SGL(0.5f / 32.0f);
+
+ /* Convert to right-aligned integer: */
+ intTemp = intTemp >> (FRACT_BITS - 1 /*sign*/ - 5 /* rescale */);
+
+ if (intTemp == 0) intTemp = 1;
+
+ hFreq->nNfb = intTemp;
+ }
+
+ hFreq->nInvfBands = hFreq->nNfb;
+
+ if (hFreq->nNfb > MAX_NOISE_COEFFS) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ /* Get noise bands */
+ sbrdecDownSampleLoRes(hFreq->freqBandTableNoise, hFreq->nNfb,
+ hFreq->freqBandTable[0], nBandsLo);
+
+ /* save old highband; required for overlap in usac
+ when headerchange occurs at XVAR and VARX frame; */
+ hFreq->ov_highSubband = hFreq->highSubband;
+
+ hFreq->lowSubband = lsb;
+ hFreq->highSubband = usb;
+
+ return SBRDEC_OK;
+}
diff --git a/fdk-aac/libSBRdec/src/sbrdec_freq_sca.h b/fdk-aac/libSBRdec/src/sbrdec_freq_sca.h
new file mode 100644
index 0000000..7e6b8e8
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbrdec_freq_sca.h
@@ -0,0 +1,127 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Frequency scale prototypes
+*/
+#ifndef SBRDEC_FREQ_SCA_H
+#define SBRDEC_FREQ_SCA_H
+
+#include "sbrdecoder.h"
+#include "env_extr.h"
+
+typedef enum { DUAL, QUAD } SBR_RATE;
+
+SBR_ERROR
+sbrdecUpdateFreqScale(UCHAR *v_k_master, UCHAR *numMaster, UINT fs,
+ HANDLE_SBR_HEADER_DATA headerData, UINT flags);
+
+void sbrdecDownSampleLoRes(UCHAR *v_result, UCHAR num_result,
+ UCHAR *freqBandTableRef, UCHAR num_Ref);
+
+void shellsort(UCHAR *in, UCHAR n);
+
+SBR_ERROR
+resetFreqBandTables(HANDLE_SBR_HEADER_DATA hHeaderData, const UINT flags);
+
+#endif
diff --git a/fdk-aac/libSBRdec/src/sbrdecoder.cpp b/fdk-aac/libSBRdec/src/sbrdecoder.cpp
new file mode 100644
index 0000000..4bc6f69
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/sbrdecoder.cpp
@@ -0,0 +1,2023 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief SBR decoder frontend
+ This module provides a frontend to the SBR decoder. The function openSBR() is
+ called for initialization. The function sbrDecoder_Apply() is called for each
+ frame. sbr_Apply() will call the required functions to decode the raw SBR data
+ (provided by env_extr.cpp), to decode the envelope data and noise floor levels
+ [decodeSbrData()], and to finally apply SBR to the current frame [sbr_dec()].
+
+ \sa sbrDecoder_Apply(), \ref documentationOverview
+*/
+
+/*!
+ \page documentationOverview Overview of important information resources and
+ source code documentation
+
+ As part of this documentation you can find more extensive descriptions about
+ key concepts and algorithms at the following locations:
+
+ <h2>Programming</h2>
+
+ \li Buffer management: sbrDecoder_Apply() and sbr_dec()
+ \li Internal scale factors to maximize SNR on fixed point processors:
+ #QMF_SCALE_FACTOR \li Special mantissa-exponent format: Created in
+ requantizeEnvelopeData() and used in calculateSbrEnvelope()
+
+ <h2>Algorithmic details</h2>
+ \li About the SBR data format: \ref SBR_HEADER_ELEMENT and \ref
+ SBR_STANDARD_ELEMENT \li Details about the bitstream decoder: env_extr.cpp \li
+ Details about the QMF filterbank and the provided polyphase implementation:
+ qmf_dec.cpp \li Details about the transposer: lpp_tran.cpp \li Details about
+ the envelope adjuster: env_calc.cpp
+
+*/
+
+#include "sbrdecoder.h"
+
+#include "FDK_bitstream.h"
+
+#include "sbrdec_freq_sca.h"
+#include "env_extr.h"
+#include "sbr_dec.h"
+#include "env_dec.h"
+#include "sbr_crc.h"
+#include "sbr_ram.h"
+#include "sbr_rom.h"
+#include "lpp_tran.h"
+#include "transcendent.h"
+
+#include "FDK_crc.h"
+
+#include "sbrdec_drc.h"
+
+#include "psbitdec.h"
+
+/* Decoder library info */
+#define SBRDECODER_LIB_VL0 3
+#define SBRDECODER_LIB_VL1 0
+#define SBRDECODER_LIB_VL2 0
+#define SBRDECODER_LIB_TITLE "SBR Decoder"
+#ifdef __ANDROID__
+#define SBRDECODER_LIB_BUILD_DATE ""
+#define SBRDECODER_LIB_BUILD_TIME ""
+#else
+#define SBRDECODER_LIB_BUILD_DATE __DATE__
+#define SBRDECODER_LIB_BUILD_TIME __TIME__
+#endif
+
+static void setFrameErrorFlag(SBR_DECODER_ELEMENT *pSbrElement, UCHAR value) {
+ if (pSbrElement != NULL) {
+ switch (value) {
+ case FRAME_ERROR_ALLSLOTS:
+ FDKmemset(pSbrElement->frameErrorFlag, FRAME_ERROR,
+ sizeof(pSbrElement->frameErrorFlag));
+ break;
+ default:
+ pSbrElement->frameErrorFlag[pSbrElement->useFrameSlot] = value;
+ }
+ }
+}
+
+static UCHAR getHeaderSlot(UCHAR currentSlot, UCHAR hdrSlotUsage[(1) + 1]) {
+ UINT occupied = 0;
+ int s;
+ UCHAR slot = hdrSlotUsage[currentSlot];
+
+ FDK_ASSERT((1) + 1 < 32);
+
+ for (s = 0; s < (1) + 1; s++) {
+ if ((hdrSlotUsage[s] == slot) && (s != slot)) {
+ occupied = 1;
+ break;
+ }
+ }
+
+ if (occupied) {
+ occupied = 0;
+
+ for (s = 0; s < (1) + 1; s++) {
+ occupied |= 1 << hdrSlotUsage[s];
+ }
+ for (s = 0; s < (1) + 1; s++) {
+ if (!(occupied & 0x1)) {
+ slot = s;
+ break;
+ }
+ occupied >>= 1;
+ }
+ }
+
+ return slot;
+}
+
+static void copySbrHeader(HANDLE_SBR_HEADER_DATA hDst,
+ const HANDLE_SBR_HEADER_DATA hSrc) {
+ /* copy the whole header memory (including pointers) */
+ FDKmemcpy(hDst, hSrc, sizeof(SBR_HEADER_DATA));
+
+ /* update pointers */
+ hDst->freqBandData.freqBandTable[0] = hDst->freqBandData.freqBandTableLo;
+ hDst->freqBandData.freqBandTable[1] = hDst->freqBandData.freqBandTableHi;
+}
+
+static int compareSbrHeader(const HANDLE_SBR_HEADER_DATA hHdr1,
+ const HANDLE_SBR_HEADER_DATA hHdr2) {
+ int result = 0;
+
+ /* compare basic data */
+ result |= (hHdr1->syncState != hHdr2->syncState) ? 1 : 0;
+ result |= (hHdr1->status != hHdr2->status) ? 1 : 0;
+ result |= (hHdr1->frameErrorFlag != hHdr2->frameErrorFlag) ? 1 : 0;
+ result |= (hHdr1->numberTimeSlots != hHdr2->numberTimeSlots) ? 1 : 0;
+ result |=
+ (hHdr1->numberOfAnalysisBands != hHdr2->numberOfAnalysisBands) ? 1 : 0;
+ result |= (hHdr1->timeStep != hHdr2->timeStep) ? 1 : 0;
+ result |= (hHdr1->sbrProcSmplRate != hHdr2->sbrProcSmplRate) ? 1 : 0;
+
+ /* compare bitstream data */
+ result |=
+ FDKmemcmp(&hHdr1->bs_data, &hHdr2->bs_data, sizeof(SBR_HEADER_DATA_BS));
+ result |=
+ FDKmemcmp(&hHdr1->bs_dflt, &hHdr2->bs_dflt, sizeof(SBR_HEADER_DATA_BS));
+ result |= FDKmemcmp(&hHdr1->bs_info, &hHdr2->bs_info,
+ sizeof(SBR_HEADER_DATA_BS_INFO));
+
+ /* compare frequency band data */
+ result |= FDKmemcmp(&hHdr1->freqBandData, &hHdr2->freqBandData,
+ (8 + MAX_NUM_LIMITERS + 1) * sizeof(UCHAR));
+ result |= FDKmemcmp(hHdr1->freqBandData.freqBandTableLo,
+ hHdr2->freqBandData.freqBandTableLo,
+ (MAX_FREQ_COEFFS / 2 + 1) * sizeof(UCHAR));
+ result |= FDKmemcmp(hHdr1->freqBandData.freqBandTableHi,
+ hHdr2->freqBandData.freqBandTableHi,
+ (MAX_FREQ_COEFFS + 1) * sizeof(UCHAR));
+ result |= FDKmemcmp(hHdr1->freqBandData.freqBandTableNoise,
+ hHdr2->freqBandData.freqBandTableNoise,
+ (MAX_NOISE_COEFFS + 1) * sizeof(UCHAR));
+ result |=
+ FDKmemcmp(hHdr1->freqBandData.v_k_master, hHdr2->freqBandData.v_k_master,
+ (MAX_FREQ_COEFFS + 1) * sizeof(UCHAR));
+
+ return result;
+}
+
+/*!
+ \brief Reset SBR decoder.
+
+ Reset should only be called if SBR has been sucessfully detected by
+ an appropriate checkForPayload() function.
+
+ \return Error code.
+*/
+static SBR_ERROR sbrDecoder_ResetElement(HANDLE_SBRDECODER self,
+ int sampleRateIn, int sampleRateOut,
+ int samplesPerFrame,
+ const MP4_ELEMENT_ID elementID,
+ const int elementIndex,
+ const int overlap) {
+ SBR_ERROR sbrError = SBRDEC_OK;
+ HANDLE_SBR_HEADER_DATA hSbrHeader;
+ UINT qmfFlags = 0;
+
+ int i, synDownsampleFac;
+
+ /* USAC: assuming theoretical case 8 kHz output sample rate with 4:1 SBR */
+ const int sbr_min_sample_rate_in = IS_USAC(self->coreCodec) ? 2000 : 6400;
+
+ /* Check in/out samplerates */
+ if (sampleRateIn < sbr_min_sample_rate_in || sampleRateIn > (96000)) {
+ sbrError = SBRDEC_UNSUPPORTED_CONFIG;
+ goto bail;
+ }
+
+ if (sampleRateOut > (96000)) {
+ sbrError = SBRDEC_UNSUPPORTED_CONFIG;
+ goto bail;
+ }
+
+ /* Set QMF mode flags */
+ if (self->flags & SBRDEC_LOW_POWER) qmfFlags |= QMF_FLAG_LP;
+
+ if (self->coreCodec == AOT_ER_AAC_ELD) {
+ if (self->flags & SBRDEC_LD_MPS_QMF) {
+ qmfFlags |= QMF_FLAG_MPSLDFB;
+ } else {
+ qmfFlags |= QMF_FLAG_CLDFB;
+ }
+ }
+
+ /* Set downsampling factor for synthesis filter bank */
+ if (sampleRateOut == 0) {
+ /* no single rate mode */
+ sampleRateOut =
+ sampleRateIn
+ << 1; /* In case of implicit signalling, assume dual rate SBR */
+ }
+
+ if (sampleRateIn == sampleRateOut) {
+ synDownsampleFac = 2;
+ self->flags |= SBRDEC_DOWNSAMPLE;
+ } else {
+ synDownsampleFac = 1;
+ self->flags &= ~SBRDEC_DOWNSAMPLE;
+ }
+
+ self->synDownsampleFac = synDownsampleFac;
+ self->sampleRateOut = sampleRateOut;
+
+ {
+ for (i = 0; i < (1) + 1; i++) {
+ int setDflt;
+ hSbrHeader = &(self->sbrHeader[elementIndex][i]);
+ setDflt = ((hSbrHeader->syncState == SBR_NOT_INITIALIZED) ||
+ (self->flags & SBRDEC_FORCE_RESET))
+ ? 1
+ : 0;
+
+ /* init a default header such that we can at least do upsampling later */
+ sbrError = initHeaderData(hSbrHeader, sampleRateIn, sampleRateOut,
+ self->downscaleFactor, samplesPerFrame,
+ self->flags, setDflt);
+
+ /* Set synchState to UPSAMPLING in case it already is initialized */
+ hSbrHeader->syncState = hSbrHeader->syncState > UPSAMPLING
+ ? UPSAMPLING
+ : hSbrHeader->syncState;
+ }
+ }
+
+ if (sbrError != SBRDEC_OK) {
+ goto bail;
+ }
+
+ if (!self->pQmfDomain->globalConf.qmfDomainExplicitConfig) {
+ self->pQmfDomain->globalConf.flags_requested |= qmfFlags;
+ self->pQmfDomain->globalConf.nBandsAnalysis_requested =
+ self->sbrHeader[elementIndex][0].numberOfAnalysisBands;
+ self->pQmfDomain->globalConf.nBandsSynthesis_requested =
+ (synDownsampleFac == 1) ? 64 : 32; /* may be overwritten by MPS */
+ self->pQmfDomain->globalConf.nBandsSynthesis_requested /=
+ self->downscaleFactor;
+ self->pQmfDomain->globalConf.nQmfTimeSlots_requested =
+ self->sbrHeader[elementIndex][0].numberTimeSlots *
+ self->sbrHeader[elementIndex][0].timeStep;
+ self->pQmfDomain->globalConf.nQmfOvTimeSlots_requested = overlap;
+ self->pQmfDomain->globalConf.nQmfProcBands_requested = 64; /* always 64 */
+ self->pQmfDomain->globalConf.nQmfProcChannels_requested =
+ 1; /* may be overwritten by MPS */
+ }
+
+ /* Init SBR channels going to be assigned to a SBR element */
+ {
+ int ch;
+ for (ch = 0; ch < self->pSbrElement[elementIndex]->nChannels; ch++) {
+ int headerIndex =
+ getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot,
+ self->pSbrElement[elementIndex]->useHeaderSlot);
+
+ /* and create sbrDec */
+ sbrError =
+ createSbrDec(self->pSbrElement[elementIndex]->pSbrChannel[ch],
+ &self->sbrHeader[elementIndex][headerIndex],
+ &self->pSbrElement[elementIndex]->transposerSettings,
+ synDownsampleFac, qmfFlags, self->flags, overlap, ch,
+ self->codecFrameSize);
+
+ if (sbrError != SBRDEC_OK) {
+ goto bail;
+ }
+ }
+ }
+
+ // FDKmemclear(sbr_OverlapBuffer, sizeof(sbr_OverlapBuffer));
+
+ if (self->numSbrElements == 1) {
+ switch (self->coreCodec) {
+ case AOT_AAC_LC:
+ case AOT_SBR:
+ case AOT_PS:
+ case AOT_ER_AAC_SCAL:
+ case AOT_DRM_AAC:
+ case AOT_DRM_SURROUND:
+ if (CreatePsDec(&self->hParametricStereoDec, samplesPerFrame)) {
+ sbrError = SBRDEC_CREATE_ERROR;
+ goto bail;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Init frame delay slot handling */
+ self->pSbrElement[elementIndex]->useFrameSlot = 0;
+ for (i = 0; i < ((1) + 1); i++) {
+ self->pSbrElement[elementIndex]->useHeaderSlot[i] = i;
+ }
+
+bail:
+
+ return sbrError;
+}
+
+/*!
+ \brief Assign QMF domain provided QMF channels to SBR channels.
+
+ \return void
+*/
+static void sbrDecoder_AssignQmfChannels2SbrChannels(HANDLE_SBRDECODER self) {
+ int ch, el, absCh_offset = 0;
+ for (el = 0; el < self->numSbrElements; el++) {
+ if (self->pSbrElement[el] != NULL) {
+ for (ch = 0; ch < self->pSbrElement[el]->nChannels; ch++) {
+ FDK_ASSERT(((absCh_offset + ch) < ((8) + (1))) &&
+ ((absCh_offset + ch) < ((8) + (1))));
+ self->pSbrElement[el]->pSbrChannel[ch]->SbrDec.qmfDomainInCh =
+ &self->pQmfDomain->QmfDomainIn[absCh_offset + ch];
+ self->pSbrElement[el]->pSbrChannel[ch]->SbrDec.qmfDomainOutCh =
+ &self->pQmfDomain->QmfDomainOut[absCh_offset + ch];
+ }
+ absCh_offset += self->pSbrElement[el]->nChannels;
+ }
+ }
+}
+
+SBR_ERROR sbrDecoder_Open(HANDLE_SBRDECODER *pSelf,
+ HANDLE_FDK_QMF_DOMAIN pQmfDomain) {
+ HANDLE_SBRDECODER self = NULL;
+ SBR_ERROR sbrError = SBRDEC_OK;
+ int elIdx;
+
+ if ((pSelf == NULL) || (pQmfDomain == NULL)) {
+ return SBRDEC_INVALID_ARGUMENT;
+ }
+
+ /* Get memory for this instance */
+ self = GetRam_SbrDecoder();
+ if (self == NULL) {
+ sbrError = SBRDEC_MEM_ALLOC_FAILED;
+ goto bail;
+ }
+
+ self->pQmfDomain = pQmfDomain;
+
+ /*
+ Already zero because of calloc
+ self->numSbrElements = 0;
+ self->numSbrChannels = 0;
+ self->codecFrameSize = 0;
+ */
+
+ self->numDelayFrames = (1); /* set to the max value by default */
+
+ /* Initialize header sync state */
+ for (elIdx = 0; elIdx < (8); elIdx += 1) {
+ int i;
+ for (i = 0; i < (1) + 1; i += 1) {
+ self->sbrHeader[elIdx][i].syncState = SBR_NOT_INITIALIZED;
+ }
+ }
+
+ *pSelf = self;
+
+bail:
+ return sbrError;
+}
+
+/**
+ * \brief determine if the given core codec AOT can be processed or not.
+ * \param coreCodec core codec audio object type.
+ * \return 1 if SBR can be processed, 0 if SBR cannot be processed/applied.
+ */
+static int sbrDecoder_isCoreCodecValid(AUDIO_OBJECT_TYPE coreCodec) {
+ switch (coreCodec) {
+ case AOT_AAC_LC:
+ case AOT_SBR:
+ case AOT_PS:
+ case AOT_ER_AAC_SCAL:
+ case AOT_ER_AAC_ELD:
+ case AOT_DRM_AAC:
+ case AOT_DRM_SURROUND:
+ case AOT_USAC:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void sbrDecoder_DestroyElement(HANDLE_SBRDECODER self,
+ const int elementIndex) {
+ if (self->pSbrElement[elementIndex] != NULL) {
+ int ch;
+
+ for (ch = 0; ch < SBRDEC_MAX_CH_PER_ELEMENT; ch++) {
+ if (self->pSbrElement[elementIndex]->pSbrChannel[ch] != NULL) {
+ deleteSbrDec(self->pSbrElement[elementIndex]->pSbrChannel[ch]);
+ FreeRam_SbrDecChannel(
+ &self->pSbrElement[elementIndex]->pSbrChannel[ch]);
+ self->numSbrChannels -= 1;
+ }
+ }
+ FreeRam_SbrDecElement(&self->pSbrElement[elementIndex]);
+ self->numSbrElements -= 1;
+ }
+}
+
+SBR_ERROR sbrDecoder_InitElement(
+ HANDLE_SBRDECODER self, const int sampleRateIn, const int sampleRateOut,
+ const int samplesPerFrame, const AUDIO_OBJECT_TYPE coreCodec,
+ const MP4_ELEMENT_ID elementID, const int elementIndex,
+ const UCHAR harmonicSBR, const UCHAR stereoConfigIndex,
+ const UCHAR configMode, UCHAR *configChanged, const INT downscaleFactor) {
+ SBR_ERROR sbrError = SBRDEC_OK;
+ int chCnt = 0;
+ int nSbrElementsStart;
+ int nSbrChannelsStart;
+ if (self == NULL) {
+ return SBRDEC_INVALID_ARGUMENT;
+ }
+
+ nSbrElementsStart = self->numSbrElements;
+ nSbrChannelsStart = self->numSbrChannels;
+
+ /* Check core codec AOT */
+ if (!sbrDecoder_isCoreCodecValid(coreCodec) || elementIndex >= (8)) {
+ sbrError = SBRDEC_UNSUPPORTED_CONFIG;
+ goto bail;
+ }
+
+ if (elementID != ID_SCE && elementID != ID_CPE && elementID != ID_LFE) {
+ sbrError = SBRDEC_UNSUPPORTED_CONFIG;
+ goto bail;
+ }
+
+ if (self->sampleRateIn == sampleRateIn &&
+ self->codecFrameSize == samplesPerFrame && self->coreCodec == coreCodec &&
+ self->pSbrElement[elementIndex] != NULL &&
+ self->pSbrElement[elementIndex]->elementID == elementID &&
+ !(self->flags & SBRDEC_FORCE_RESET) &&
+ ((sampleRateOut == 0) ? 1 : (self->sampleRateOut == sampleRateOut)) &&
+ ((harmonicSBR == 2) ? 1
+ : (self->harmonicSBR ==
+ harmonicSBR)) /* The value 2 signalizes that
+ harmonicSBR shall be ignored in
+ the config change detection */
+ ) {
+ /* Nothing to do */
+ return SBRDEC_OK;
+ } else {
+ if (configMode & AC_CM_DET_CFG_CHANGE) {
+ *configChanged = 1;
+ }
+ }
+
+ /* reaching this point the SBR-decoder gets (re-)configured */
+
+ /* The flags field is used for all elements! */
+ self->flags &=
+ (SBRDEC_FORCE_RESET | SBRDEC_FLUSH); /* Keep the global flags. They will
+ be reset after decoding. */
+ self->flags |= (downscaleFactor > 1) ? SBRDEC_ELD_DOWNSCALE : 0;
+ self->flags |= (coreCodec == AOT_ER_AAC_ELD) ? SBRDEC_ELD_GRID : 0;
+ self->flags |= (coreCodec == AOT_ER_AAC_SCAL) ? SBRDEC_SYNTAX_SCAL : 0;
+ self->flags |=
+ (coreCodec == AOT_DRM_AAC) ? SBRDEC_SYNTAX_SCAL | SBRDEC_SYNTAX_DRM : 0;
+ self->flags |= (coreCodec == AOT_DRM_SURROUND)
+ ? SBRDEC_SYNTAX_SCAL | SBRDEC_SYNTAX_DRM
+ : 0;
+ self->flags |= (coreCodec == AOT_USAC) ? SBRDEC_SYNTAX_USAC : 0;
+ /* Robustness: Take integer division rounding into consideration. E.g. 22050
+ * Hz with 4:1 SBR => 5512 Hz core sampling rate. */
+ self->flags |= (sampleRateIn == sampleRateOut / 4) ? SBRDEC_QUAD_RATE : 0;
+ self->flags |= (harmonicSBR == 1) ? SBRDEC_USAC_HARMONICSBR : 0;
+
+ if (configMode & AC_CM_DET_CFG_CHANGE) {
+ return SBRDEC_OK;
+ }
+
+ self->sampleRateIn = sampleRateIn;
+ self->codecFrameSize = samplesPerFrame;
+ self->coreCodec = coreCodec;
+ self->harmonicSBR = harmonicSBR;
+ self->downscaleFactor = downscaleFactor;
+
+ /* Init SBR elements */
+ {
+ int elChannels, ch;
+
+ if (self->pSbrElement[elementIndex] == NULL) {
+ self->pSbrElement[elementIndex] = GetRam_SbrDecElement(elementIndex);
+ if (self->pSbrElement[elementIndex] == NULL) {
+ sbrError = SBRDEC_MEM_ALLOC_FAILED;
+ goto bail;
+ }
+ self->numSbrElements++;
+ } else {
+ self->numSbrChannels -= self->pSbrElement[elementIndex]->nChannels;
+ }
+
+ /* Save element ID for sanity checks and to have a fallback for concealment.
+ */
+ self->pSbrElement[elementIndex]->elementID = elementID;
+
+ /* Determine amount of channels for this element */
+ switch (elementID) {
+ case ID_NONE:
+ case ID_CPE:
+ elChannels = 2;
+ break;
+ case ID_LFE:
+ case ID_SCE:
+ elChannels = 1;
+ break;
+ default:
+ elChannels = 0;
+ break;
+ }
+
+ /* Handle case of Parametric Stereo */
+ if (elementIndex == 0 && elementID == ID_SCE) {
+ switch (coreCodec) {
+ case AOT_AAC_LC:
+ case AOT_SBR:
+ case AOT_PS:
+ case AOT_ER_AAC_SCAL:
+ case AOT_DRM_AAC:
+ case AOT_DRM_SURROUND:
+ elChannels = 2;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Sanity check to avoid memory leaks */
+ if (elChannels < self->pSbrElement[elementIndex]->nChannels) {
+ self->numSbrChannels += self->pSbrElement[elementIndex]->nChannels;
+ sbrError = SBRDEC_PARSE_ERROR;
+ goto bail;
+ }
+
+ self->pSbrElement[elementIndex]->nChannels = elChannels;
+
+ for (ch = 0; ch < elChannels; ch++) {
+ if (self->pSbrElement[elementIndex]->pSbrChannel[ch] == NULL) {
+ self->pSbrElement[elementIndex]->pSbrChannel[ch] =
+ GetRam_SbrDecChannel(chCnt);
+ if (self->pSbrElement[elementIndex]->pSbrChannel[ch] == NULL) {
+ sbrError = SBRDEC_MEM_ALLOC_FAILED;
+ goto bail;
+ }
+ }
+ self->numSbrChannels++;
+
+ sbrDecoder_drcInitChannel(&self->pSbrElement[elementIndex]
+ ->pSbrChannel[ch]
+ ->SbrDec.sbrDrcChannel);
+
+ chCnt++;
+ }
+ }
+
+ if (!self->pQmfDomain->globalConf.qmfDomainExplicitConfig) {
+ self->pQmfDomain->globalConf.nInputChannels_requested =
+ self->numSbrChannels;
+ self->pQmfDomain->globalConf.nOutputChannels_requested =
+ fMax((INT)self->numSbrChannels,
+ (INT)self->pQmfDomain->globalConf.nOutputChannels_requested);
+ }
+
+ /* Make sure each SBR channel has one QMF channel assigned even if
+ * numSbrChannels or element set-up has changed. */
+ sbrDecoder_AssignQmfChannels2SbrChannels(self);
+
+ /* clear error flags for all delay slots */
+ FDKmemclear(self->pSbrElement[elementIndex]->frameErrorFlag,
+ ((1) + 1) * sizeof(UCHAR));
+
+ {
+ int overlap;
+
+ if (coreCodec == AOT_ER_AAC_ELD) {
+ overlap = 0;
+ } else if (self->flags & SBRDEC_QUAD_RATE) {
+ overlap = (3 * 4);
+ } else {
+ overlap = (3 * 2);
+ }
+ /* Initialize this instance */
+ sbrError = sbrDecoder_ResetElement(self, sampleRateIn, sampleRateOut,
+ samplesPerFrame, elementID, elementIndex,
+ overlap);
+ }
+
+bail:
+ if (sbrError != SBRDEC_OK) {
+ if ((nSbrElementsStart < self->numSbrElements) ||
+ (nSbrChannelsStart < self->numSbrChannels)) {
+ /* Free the memory allocated for this element */
+ sbrDecoder_DestroyElement(self, elementIndex);
+ } else if ((elementIndex < (8)) &&
+ (self->pSbrElement[elementIndex] !=
+ NULL)) { /* Set error flag to trigger concealment */
+ setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_ERROR);
+ }
+ }
+
+ return sbrError;
+}
+
+/**
+ * \brief Free config dependent SBR memory.
+ * \param self SBR decoder instance handle
+ */
+SBR_ERROR sbrDecoder_FreeMem(HANDLE_SBRDECODER *self) {
+ int i;
+ int elIdx;
+
+ if (self != NULL && *self != NULL) {
+ for (i = 0; i < (8); i++) {
+ sbrDecoder_DestroyElement(*self, i);
+ }
+
+ for (elIdx = 0; elIdx < (8); elIdx += 1) {
+ for (i = 0; i < (1) + 1; i += 1) {
+ (*self)->sbrHeader[elIdx][i].syncState = SBR_NOT_INITIALIZED;
+ }
+ }
+ }
+
+ return SBRDEC_OK;
+}
+
+/**
+ * \brief Apply decoded SBR header for one element.
+ * \param self SBR decoder instance handle
+ * \param hSbrHeader SBR header handle to be processed.
+ * \param hSbrChannel pointer array to the SBR element channels corresponding to
+ * the SBR header.
+ * \param headerStatus header status value returned from SBR header parser.
+ * \param numElementChannels amount of channels for the SBR element whos header
+ * is to be processed.
+ */
+static SBR_ERROR sbrDecoder_HeaderUpdate(HANDLE_SBRDECODER self,
+ HANDLE_SBR_HEADER_DATA hSbrHeader,
+ SBR_HEADER_STATUS headerStatus,
+ HANDLE_SBR_CHANNEL hSbrChannel[],
+ const int numElementChannels) {
+ SBR_ERROR errorStatus = SBRDEC_OK;
+
+ /*
+ change of control data, reset decoder
+ */
+ errorStatus = resetFreqBandTables(hSbrHeader, self->flags);
+
+ if (errorStatus == SBRDEC_OK) {
+ if (hSbrHeader->syncState == UPSAMPLING && headerStatus != HEADER_RESET) {
+#if (SBRDEC_MAX_HB_FADE_FRAMES > 0)
+ int ch;
+ for (ch = 0; ch < numElementChannels; ch += 1) {
+ hSbrChannel[ch]->SbrDec.highBandFadeCnt = SBRDEC_MAX_HB_FADE_FRAMES;
+ }
+
+#endif
+ /* As the default header would limit the frequency range,
+ lowSubband and highSubband must be patched. */
+ hSbrHeader->freqBandData.lowSubband = hSbrHeader->numberOfAnalysisBands;
+ hSbrHeader->freqBandData.highSubband = hSbrHeader->numberOfAnalysisBands;
+ }
+
+ /* Trigger a reset before processing this slot */
+ hSbrHeader->status |= SBRDEC_HDR_STAT_RESET;
+ }
+
+ return errorStatus;
+}
+
+INT sbrDecoder_Header(HANDLE_SBRDECODER self, HANDLE_FDK_BITSTREAM hBs,
+ const INT sampleRateIn, const INT sampleRateOut,
+ const INT samplesPerFrame,
+ const AUDIO_OBJECT_TYPE coreCodec,
+ const MP4_ELEMENT_ID elementID, const INT elementIndex,
+ const UCHAR harmonicSBR, const UCHAR stereoConfigIndex,
+ const UCHAR configMode, UCHAR *configChanged,
+ const INT downscaleFactor) {
+ SBR_HEADER_STATUS headerStatus;
+ HANDLE_SBR_HEADER_DATA hSbrHeader;
+ SBR_ERROR sbrError = SBRDEC_OK;
+ int headerIndex;
+ UINT flagsSaved =
+ 0; /* flags should not be changed in AC_CM_DET_CFG_CHANGE - mode after
+ parsing */
+
+ if (self == NULL || elementIndex >= (8)) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ if (!sbrDecoder_isCoreCodecValid(coreCodec)) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ if (configMode & AC_CM_DET_CFG_CHANGE) {
+ flagsSaved = self->flags; /* store */
+ }
+
+ sbrError = sbrDecoder_InitElement(
+ self, sampleRateIn, sampleRateOut, samplesPerFrame, coreCodec, elementID,
+ elementIndex, harmonicSBR, stereoConfigIndex, configMode, configChanged,
+ downscaleFactor);
+
+ if ((sbrError != SBRDEC_OK) || (elementID == ID_LFE)) {
+ goto bail;
+ }
+
+ if (configMode & AC_CM_DET_CFG_CHANGE) {
+ hSbrHeader = NULL;
+ } else {
+ headerIndex = getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot,
+ self->pSbrElement[elementIndex]->useHeaderSlot);
+
+ hSbrHeader = &(self->sbrHeader[elementIndex][headerIndex]);
+ }
+
+ headerStatus = sbrGetHeaderData(hSbrHeader, hBs, self->flags, 0, configMode);
+
+ if (coreCodec == AOT_USAC) {
+ if (configMode & AC_CM_DET_CFG_CHANGE) {
+ self->flags = flagsSaved; /* restore */
+ }
+ return sbrError;
+ }
+
+ if (configMode & AC_CM_ALLOC_MEM) {
+ SBR_DECODER_ELEMENT *pSbrElement;
+
+ pSbrElement = self->pSbrElement[elementIndex];
+
+ /* Sanity check */
+ if (pSbrElement != NULL) {
+ if ((elementID == ID_CPE && pSbrElement->nChannels != 2) ||
+ (elementID != ID_CPE && pSbrElement->nChannels != 1)) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+ if (headerStatus == HEADER_RESET) {
+ sbrError = sbrDecoder_HeaderUpdate(self, hSbrHeader, headerStatus,
+ pSbrElement->pSbrChannel,
+ pSbrElement->nChannels);
+
+ if (sbrError == SBRDEC_OK) {
+ hSbrHeader->syncState = SBR_HEADER;
+ hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE;
+ }
+ /* else {
+ Since we already have overwritten the old SBR header the only way out
+ is UPSAMPLING! This will be prepared in the next step.
+ } */
+ }
+ }
+ }
+bail:
+ if (configMode & AC_CM_DET_CFG_CHANGE) {
+ self->flags = flagsSaved; /* restore */
+ }
+ return sbrError;
+}
+
+SBR_ERROR sbrDecoder_SetParam(HANDLE_SBRDECODER self, const SBRDEC_PARAM param,
+ const INT value) {
+ SBR_ERROR errorStatus = SBRDEC_OK;
+
+ /* configure the subsystems */
+ switch (param) {
+ case SBR_SYSTEM_BITSTREAM_DELAY:
+ if (value < 0 || value > (1)) {
+ errorStatus = SBRDEC_SET_PARAM_FAIL;
+ break;
+ }
+ if (self == NULL) {
+ errorStatus = SBRDEC_NOT_INITIALIZED;
+ } else {
+ self->numDelayFrames = (UCHAR)value;
+ }
+ break;
+ case SBR_QMF_MODE:
+ if (self == NULL) {
+ errorStatus = SBRDEC_NOT_INITIALIZED;
+ } else {
+ if (value == 1) {
+ self->flags |= SBRDEC_LOW_POWER;
+ } else {
+ self->flags &= ~SBRDEC_LOW_POWER;
+ }
+ }
+ break;
+ case SBR_LD_QMF_TIME_ALIGN:
+ if (self == NULL) {
+ errorStatus = SBRDEC_NOT_INITIALIZED;
+ } else {
+ if (value == 1) {
+ self->flags |= SBRDEC_LD_MPS_QMF;
+ } else {
+ self->flags &= ~SBRDEC_LD_MPS_QMF;
+ }
+ }
+ break;
+ case SBR_FLUSH_DATA:
+ if (value != 0) {
+ if (self == NULL) {
+ errorStatus = SBRDEC_NOT_INITIALIZED;
+ } else {
+ self->flags |= SBRDEC_FLUSH;
+ }
+ }
+ break;
+ case SBR_CLEAR_HISTORY:
+ if (value != 0) {
+ if (self == NULL) {
+ errorStatus = SBRDEC_NOT_INITIALIZED;
+ } else {
+ self->flags |= SBRDEC_FORCE_RESET;
+ }
+ }
+ break;
+ case SBR_BS_INTERRUPTION: {
+ int elementIndex;
+
+ if (self == NULL) {
+ errorStatus = SBRDEC_NOT_INITIALIZED;
+ break;
+ }
+
+ /* Loop over SBR elements */
+ for (elementIndex = 0; elementIndex < self->numSbrElements;
+ elementIndex++) {
+ if (self->pSbrElement[elementIndex] != NULL) {
+ HANDLE_SBR_HEADER_DATA hSbrHeader;
+ int headerIndex =
+ getHeaderSlot(self->pSbrElement[elementIndex]->useFrameSlot,
+ self->pSbrElement[elementIndex]->useHeaderSlot);
+
+ hSbrHeader = &(self->sbrHeader[elementIndex][headerIndex]);
+
+ /* Set sync state UPSAMPLING for the corresponding slot.
+ This switches off bitstream parsing until a new header arrives. */
+ hSbrHeader->syncState = UPSAMPLING;
+ hSbrHeader->status |= SBRDEC_HDR_STAT_UPDATE;
+ }
+ }
+ } break;
+
+ case SBR_SKIP_QMF:
+ if (self == NULL) {
+ errorStatus = SBRDEC_NOT_INITIALIZED;
+ } else {
+ if (value == 1) {
+ self->flags |= SBRDEC_SKIP_QMF_ANA;
+ } else {
+ self->flags &= ~SBRDEC_SKIP_QMF_ANA;
+ }
+ if (value == 2) {
+ self->flags |= SBRDEC_SKIP_QMF_SYN;
+ } else {
+ self->flags &= ~SBRDEC_SKIP_QMF_SYN;
+ }
+ }
+ break;
+ default:
+ errorStatus = SBRDEC_SET_PARAM_FAIL;
+ break;
+ } /* switch(param) */
+
+ return (errorStatus);
+}
+
+static SBRDEC_DRC_CHANNEL *sbrDecoder_drcGetChannel(
+ const HANDLE_SBRDECODER self, const INT channel) {
+ SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL;
+ int elementIndex, elChanIdx = 0, numCh = 0;
+
+ for (elementIndex = 0; (elementIndex < (8)) && (numCh <= channel);
+ elementIndex++) {
+ SBR_DECODER_ELEMENT *pSbrElement = self->pSbrElement[elementIndex];
+ int c, elChannels;
+
+ elChanIdx = 0;
+ if (pSbrElement == NULL) break;
+
+ /* Determine amount of channels for this element */
+ switch (pSbrElement->elementID) {
+ case ID_CPE:
+ elChannels = 2;
+ break;
+ case ID_LFE:
+ case ID_SCE:
+ elChannels = 1;
+ break;
+ case ID_NONE:
+ default:
+ elChannels = 0;
+ break;
+ }
+
+ /* Limit with actual allocated element channels */
+ elChannels = fMin(elChannels, pSbrElement->nChannels);
+
+ for (c = 0; (c < elChannels) && (numCh <= channel); c++) {
+ if (pSbrElement->pSbrChannel[elChanIdx] != NULL) {
+ numCh++;
+ elChanIdx++;
+ }
+ }
+ }
+ elementIndex -= 1;
+ elChanIdx -= 1;
+
+ if (elChanIdx < 0 || elementIndex < 0) {
+ return NULL;
+ }
+
+ if (self->pSbrElement[elementIndex] != NULL) {
+ if (self->pSbrElement[elementIndex]->pSbrChannel[elChanIdx] != NULL) {
+ pSbrDrcChannelData = &self->pSbrElement[elementIndex]
+ ->pSbrChannel[elChanIdx]
+ ->SbrDec.sbrDrcChannel;
+ }
+ }
+
+ return (pSbrDrcChannelData);
+}
+
+SBR_ERROR sbrDecoder_drcFeedChannel(HANDLE_SBRDECODER self, INT ch,
+ UINT numBands, FIXP_DBL *pNextFact_mag,
+ INT nextFact_exp,
+ SHORT drcInterpolationScheme,
+ UCHAR winSequence, USHORT *pBandTop) {
+ SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL;
+ int band, isValidData = 0;
+
+ if (self == NULL) {
+ return SBRDEC_NOT_INITIALIZED;
+ }
+ if (ch > (8) || pNextFact_mag == NULL) {
+ return SBRDEC_SET_PARAM_FAIL;
+ }
+
+ /* Search for gain values different to 1.0f */
+ for (band = 0; band < (int)numBands; band += 1) {
+ if (!((pNextFact_mag[band] == FL2FXCONST_DBL(0.5)) &&
+ (nextFact_exp == 1)) &&
+ !((pNextFact_mag[band] == (FIXP_DBL)MAXVAL_DBL) &&
+ (nextFact_exp == 0))) {
+ isValidData = 1;
+ break;
+ }
+ }
+
+ /* Find the right SBR channel */
+ pSbrDrcChannelData = sbrDecoder_drcGetChannel(self, ch);
+
+ if (pSbrDrcChannelData != NULL) {
+ if (pSbrDrcChannelData->enable ||
+ isValidData) { /* Activate processing only with real and valid data */
+ int i;
+
+ pSbrDrcChannelData->enable = 1;
+ pSbrDrcChannelData->numBandsNext = numBands;
+
+ pSbrDrcChannelData->winSequenceNext = winSequence;
+ pSbrDrcChannelData->drcInterpolationSchemeNext = drcInterpolationScheme;
+ pSbrDrcChannelData->nextFact_exp = nextFact_exp;
+
+ for (i = 0; i < (int)numBands; i++) {
+ pSbrDrcChannelData->bandTopNext[i] = pBandTop[i];
+ pSbrDrcChannelData->nextFact_mag[i] = pNextFact_mag[i];
+ }
+ }
+ }
+
+ return SBRDEC_OK;
+}
+
+void sbrDecoder_drcDisable(HANDLE_SBRDECODER self, INT ch) {
+ SBRDEC_DRC_CHANNEL *pSbrDrcChannelData = NULL;
+
+ if ((self == NULL) || (ch > (8)) || (self->numSbrElements == 0) ||
+ (self->numSbrChannels == 0)) {
+ return;
+ }
+
+ /* Find the right SBR channel */
+ pSbrDrcChannelData = sbrDecoder_drcGetChannel(self, ch);
+
+ if (pSbrDrcChannelData != NULL) {
+ sbrDecoder_drcInitChannel(pSbrDrcChannelData);
+ }
+}
+
+SBR_ERROR sbrDecoder_Parse(HANDLE_SBRDECODER self, HANDLE_FDK_BITSTREAM hBs,
+ UCHAR *pDrmBsBuffer, USHORT drmBsBufferSize,
+ int *count, int bsPayLen, int crcFlag,
+ MP4_ELEMENT_ID prevElement, int elementIndex,
+ UINT acFlags, UINT acElFlags[]) {
+ SBR_DECODER_ELEMENT *hSbrElement = NULL;
+ HANDLE_SBR_HEADER_DATA hSbrHeader = NULL;
+ HANDLE_SBR_CHANNEL *pSbrChannel;
+
+ SBR_FRAME_DATA *hFrameDataLeft = NULL;
+ SBR_FRAME_DATA *hFrameDataRight = NULL;
+ SBR_FRAME_DATA frameDataLeftCopy;
+ SBR_FRAME_DATA frameDataRightCopy;
+
+ SBR_ERROR errorStatus = SBRDEC_OK;
+ SBR_HEADER_STATUS headerStatus = HEADER_NOT_PRESENT;
+
+ INT startPos = FDKgetValidBits(hBs);
+ INT CRCLen = 0;
+ HANDLE_FDK_BITSTREAM hBsOriginal = hBs;
+ FDK_BITSTREAM bsBwd;
+
+ FDK_CRCINFO crcInfo;
+ INT crcReg = 0;
+ USHORT drmSbrCrc = 0;
+ const int fGlobalIndependencyFlag = acFlags & AC_INDEP;
+ const int bs_pvc = acElFlags[elementIndex] & AC_EL_USAC_PVC;
+ const int bs_interTes = acElFlags[elementIndex] & AC_EL_USAC_ITES;
+ int stereo;
+ int fDoDecodeSbrData = 1;
+
+ int lastSlot, lastHdrSlot = 0, thisHdrSlot = 0;
+
+ if (*count <= 0) {
+ setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_ERROR);
+ return SBRDEC_OK;
+ }
+
+ /* SBR sanity checks */
+ if (self == NULL) {
+ errorStatus = SBRDEC_NOT_INITIALIZED;
+ goto bail;
+ }
+
+ /* Reverse bits of DRM SBR payload */
+ if ((self->flags & SBRDEC_SYNTAX_DRM) && *count > 0) {
+ int dataBytes, dataBits;
+
+ FDK_ASSERT(drmBsBufferSize >= (512));
+ dataBits = *count;
+
+ if (dataBits > ((512) * 8)) {
+ /* do not flip more data than needed */
+ dataBits = (512) * 8;
+ }
+
+ dataBytes = (dataBits + 7) >> 3;
+
+ int j;
+
+ if ((j = (int)FDKgetValidBits(hBs)) != 8) {
+ FDKpushBiDirectional(hBs, (j - 8));
+ }
+
+ j = 0;
+ for (; dataBytes > 0; dataBytes--) {
+ int i;
+ UCHAR tmpByte;
+ UCHAR buffer = 0x00;
+
+ tmpByte = (UCHAR)FDKreadBits(hBs, 8);
+ for (i = 0; i < 4; i++) {
+ int shift = 2 * i + 1;
+ buffer |= (tmpByte & (0x08 >> i)) << shift;
+ buffer |= (tmpByte & (0x10 << i)) >> shift;
+ }
+ pDrmBsBuffer[j++] = buffer;
+ FDKpushBack(hBs, 16);
+ }
+
+ FDKinitBitStream(&bsBwd, pDrmBsBuffer, (512), dataBits, BS_READER);
+
+ /* Use reversed data */
+ hBs = &bsBwd;
+ bsPayLen = *count;
+ }
+
+ /* Remember start position of SBR element */
+ startPos = FDKgetValidBits(hBs);
+
+ /* SBR sanity checks */
+ if (self->pSbrElement[elementIndex] == NULL) {
+ errorStatus = SBRDEC_NOT_INITIALIZED;
+ goto bail;
+ }
+ hSbrElement = self->pSbrElement[elementIndex];
+
+ lastSlot = (hSbrElement->useFrameSlot > 0) ? hSbrElement->useFrameSlot - 1
+ : self->numDelayFrames;
+ lastHdrSlot = hSbrElement->useHeaderSlot[lastSlot];
+ thisHdrSlot = getHeaderSlot(
+ hSbrElement->useFrameSlot,
+ hSbrElement->useHeaderSlot); /* Get a free header slot not used by
+ frames not processed yet. */
+
+ /* Assign the free slot to store a new header if there is one. */
+ hSbrHeader = &self->sbrHeader[elementIndex][thisHdrSlot];
+
+ pSbrChannel = hSbrElement->pSbrChannel;
+ stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0;
+
+ hFrameDataLeft = &self->pSbrElement[elementIndex]
+ ->pSbrChannel[0]
+ ->frameData[hSbrElement->useFrameSlot];
+ if (stereo) {
+ hFrameDataRight = &self->pSbrElement[elementIndex]
+ ->pSbrChannel[1]
+ ->frameData[hSbrElement->useFrameSlot];
+ }
+
+ /* store frameData; new parsed frameData possibly corrupted */
+ FDKmemcpy(&frameDataLeftCopy, hFrameDataLeft, sizeof(SBR_FRAME_DATA));
+ if (stereo) {
+ FDKmemcpy(&frameDataRightCopy, hFrameDataRight, sizeof(SBR_FRAME_DATA));
+ }
+
+ /* reset PS flag; will be set after PS was found */
+ self->flags &= ~SBRDEC_PS_DECODED;
+
+ if (hSbrHeader->status & SBRDEC_HDR_STAT_UPDATE) {
+ /* Got a new header from extern (e.g. from an ASC) */
+ headerStatus = HEADER_OK;
+ hSbrHeader->status &= ~SBRDEC_HDR_STAT_UPDATE;
+ } else if (thisHdrSlot != lastHdrSlot) {
+ /* Copy the last header into this slot otherwise the
+ header compare will trigger more HEADER_RESETs than needed. */
+ copySbrHeader(hSbrHeader, &self->sbrHeader[elementIndex][lastHdrSlot]);
+ }
+
+ /*
+ Check if bit stream data is valid and matches the element context
+ */
+ if (((prevElement != ID_SCE) && (prevElement != ID_CPE)) ||
+ prevElement != hSbrElement->elementID) {
+ /* In case of LFE we also land here, since there is no LFE SBR element (do
+ * upsampling only) */
+ fDoDecodeSbrData = 0;
+ }
+
+ if (fDoDecodeSbrData) {
+ if ((INT)FDKgetValidBits(hBs) <= 0) {
+ fDoDecodeSbrData = 0;
+ }
+ }
+
+ /*
+ SBR CRC-check
+ */
+ if (fDoDecodeSbrData) {
+ if (crcFlag) {
+ switch (self->coreCodec) {
+ case AOT_ER_AAC_ELD:
+ FDKpushFor(hBs, 10);
+ /* check sbrcrc later: we don't know the payload length now */
+ break;
+ case AOT_DRM_AAC:
+ case AOT_DRM_SURROUND:
+ drmSbrCrc = (USHORT)FDKreadBits(hBs, 8);
+ /* Setup CRC decoder */
+ FDKcrcInit(&crcInfo, 0x001d, 0xFFFF, 8);
+ /* Start CRC region */
+ crcReg = FDKcrcStartReg(&crcInfo, hBs, 0);
+ break;
+ default:
+ CRCLen = bsPayLen - 10; /* change: 0 => i */
+ if (CRCLen < 0) {
+ fDoDecodeSbrData = 0;
+ } else {
+ fDoDecodeSbrData = SbrCrcCheck(hBs, CRCLen);
+ }
+ break;
+ }
+ }
+ } /* if (fDoDecodeSbrData) */
+
+ /*
+ Read in the header data and issue a reset if change occured
+ */
+ if (fDoDecodeSbrData) {
+ int sbrHeaderPresent;
+
+ if (self->flags & (SBRDEC_SYNTAX_RSVD50 | SBRDEC_SYNTAX_USAC)) {
+ SBR_HEADER_DATA_BS_INFO newSbrInfo;
+ int sbrInfoPresent;
+
+ if (bs_interTes) {
+ self->flags |= SBRDEC_USAC_ITES;
+ } else {
+ self->flags &= ~SBRDEC_USAC_ITES;
+ }
+
+ if (fGlobalIndependencyFlag) {
+ self->flags |= SBRDEC_USAC_INDEP;
+ sbrInfoPresent = 1;
+ sbrHeaderPresent = 1;
+ } else {
+ self->flags &= ~SBRDEC_USAC_INDEP;
+ sbrInfoPresent = FDKreadBit(hBs);
+ if (sbrInfoPresent) {
+ sbrHeaderPresent = FDKreadBit(hBs);
+ } else {
+ sbrHeaderPresent = 0;
+ }
+ }
+
+ if (sbrInfoPresent) {
+ newSbrInfo.ampResolution = FDKreadBit(hBs);
+ newSbrInfo.xover_band = FDKreadBits(hBs, 4);
+ newSbrInfo.sbr_preprocessing = FDKreadBit(hBs);
+ if (bs_pvc) {
+ newSbrInfo.pvc_mode = FDKreadBits(hBs, 2);
+ /* bs_pvc_mode: 0 -> no PVC, 1 -> PVC mode 1, 2 -> PVC mode 2, 3 ->
+ * reserved */
+ if (newSbrInfo.pvc_mode > 2) {
+ headerStatus = HEADER_ERROR;
+ }
+ if (stereo && newSbrInfo.pvc_mode > 0) {
+ /* bs_pvc is always transmitted but pvc_mode is set to zero in case
+ * of stereo SBR. The config might be wrong but we cannot tell for
+ * sure. */
+ newSbrInfo.pvc_mode = 0;
+ }
+ } else {
+ newSbrInfo.pvc_mode = 0;
+ }
+ if (headerStatus != HEADER_ERROR) {
+ if (FDKmemcmp(&hSbrHeader->bs_info, &newSbrInfo,
+ sizeof(SBR_HEADER_DATA_BS_INFO))) {
+ /* in case of ampResolution and preprocessing change no full reset
+ * required */
+ /* HEADER reset would trigger HBE transposer reset which breaks
+ * eSbr_3_Eaa.mp4 */
+ if ((hSbrHeader->bs_info.pvc_mode != newSbrInfo.pvc_mode) ||
+ (hSbrHeader->bs_info.xover_band != newSbrInfo.xover_band)) {
+ headerStatus = HEADER_RESET;
+ } else {
+ headerStatus = HEADER_OK;
+ }
+
+ hSbrHeader->bs_info = newSbrInfo;
+ } else {
+ headerStatus = HEADER_OK;
+ }
+ }
+ }
+ if (headerStatus == HEADER_ERROR) {
+ /* Corrupt SBR info data, do not decode and switch to UPSAMPLING */
+ hSbrHeader->syncState = UPSAMPLING;
+ fDoDecodeSbrData = 0;
+ sbrHeaderPresent = 0;
+ }
+
+ if (sbrHeaderPresent && fDoDecodeSbrData) {
+ int useDfltHeader;
+
+ useDfltHeader = FDKreadBit(hBs);
+
+ if (useDfltHeader) {
+ sbrHeaderPresent = 0;
+ if (FDKmemcmp(&hSbrHeader->bs_data, &hSbrHeader->bs_dflt,
+ sizeof(SBR_HEADER_DATA_BS)) ||
+ hSbrHeader->syncState != SBR_ACTIVE) {
+ hSbrHeader->bs_data = hSbrHeader->bs_dflt;
+ headerStatus = HEADER_RESET;
+ }
+ }
+ }
+ } else {
+ sbrHeaderPresent = FDKreadBit(hBs);
+ }
+
+ if (sbrHeaderPresent) {
+ headerStatus = sbrGetHeaderData(hSbrHeader, hBs, self->flags, 1, 0);
+ }
+
+ if (headerStatus == HEADER_RESET) {
+ errorStatus = sbrDecoder_HeaderUpdate(
+ self, hSbrHeader, headerStatus, pSbrChannel, hSbrElement->nChannels);
+
+ if (errorStatus == SBRDEC_OK) {
+ hSbrHeader->syncState = SBR_HEADER;
+ } else {
+ hSbrHeader->syncState = SBR_NOT_INITIALIZED;
+ headerStatus = HEADER_ERROR;
+ }
+ }
+
+ if (errorStatus != SBRDEC_OK) {
+ fDoDecodeSbrData = 0;
+ }
+ } /* if (fDoDecodeSbrData) */
+
+ /*
+ Print debugging output only if state has changed
+ */
+
+ /* read frame data */
+ if ((hSbrHeader->syncState >= SBR_HEADER) && fDoDecodeSbrData) {
+ int sbrFrameOk;
+ /* read the SBR element data */
+ if (!stereo && (self->hParametricStereoDec != NULL)) {
+ /* update slot index for PS bitstream parsing */
+ self->hParametricStereoDec->bsLastSlot =
+ self->hParametricStereoDec->bsReadSlot;
+ self->hParametricStereoDec->bsReadSlot = hSbrElement->useFrameSlot;
+ }
+ sbrFrameOk = sbrGetChannelElement(
+ hSbrHeader, hFrameDataLeft, (stereo) ? hFrameDataRight : NULL,
+ &pSbrChannel[0]->prevFrameData,
+ pSbrChannel[0]->SbrDec.PvcStaticData.pvc_mode_last, hBs,
+ (stereo) ? NULL : self->hParametricStereoDec, self->flags,
+ self->pSbrElement[elementIndex]->transposerSettings.overlap);
+
+ if (!sbrFrameOk) {
+ fDoDecodeSbrData = 0;
+ } else {
+ INT valBits;
+
+ if (bsPayLen > 0) {
+ valBits = bsPayLen - ((INT)startPos - (INT)FDKgetValidBits(hBs));
+ } else {
+ valBits = (INT)FDKgetValidBits(hBs);
+ }
+
+ if (crcFlag) {
+ switch (self->coreCodec) {
+ case AOT_ER_AAC_ELD: {
+ /* late crc check for eld */
+ INT payloadbits =
+ (INT)startPos - (INT)FDKgetValidBits(hBs) - startPos;
+ INT crcLen = payloadbits - 10;
+ FDKpushBack(hBs, payloadbits);
+ fDoDecodeSbrData = SbrCrcCheck(hBs, crcLen);
+ FDKpushFor(hBs, crcLen);
+ } break;
+ case AOT_DRM_AAC:
+ case AOT_DRM_SURROUND:
+ /* End CRC region */
+ FDKcrcEndReg(&crcInfo, hBs, crcReg);
+ /* Check CRC */
+ if ((FDKcrcGetCRC(&crcInfo) ^ 0xFF) != drmSbrCrc) {
+ fDoDecodeSbrData = 0;
+ if (headerStatus != HEADER_NOT_PRESENT) {
+ headerStatus = HEADER_ERROR;
+ hSbrHeader->syncState = SBR_NOT_INITIALIZED;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* sanity check of remaining bits */
+ if (valBits < 0) {
+ fDoDecodeSbrData = 0;
+ } else {
+ switch (self->coreCodec) {
+ case AOT_SBR:
+ case AOT_PS:
+ case AOT_AAC_LC: {
+ /* This sanity check is only meaningful with General Audio
+ * bitstreams */
+ int alignBits = valBits & 0x7;
+
+ if (valBits > alignBits) {
+ fDoDecodeSbrData = 0;
+ }
+ } break;
+ default:
+ /* No sanity check available */
+ break;
+ }
+ }
+ }
+ } else {
+ /* The returned bit count will not be the actual payload size since we did
+ not parse the frame data. Return an error so that the caller can react
+ respectively. */
+ errorStatus = SBRDEC_PARSE_ERROR;
+ }
+
+ if (!fDoDecodeSbrData) {
+ /* Set error flag for this slot to trigger concealment */
+ setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_ERROR);
+ /* restore old frameData for concealment */
+ FDKmemcpy(hFrameDataLeft, &frameDataLeftCopy, sizeof(SBR_FRAME_DATA));
+ if (stereo) {
+ FDKmemcpy(hFrameDataRight, &frameDataRightCopy, sizeof(SBR_FRAME_DATA));
+ }
+ errorStatus = SBRDEC_PARSE_ERROR;
+ } else {
+ /* Everything seems to be ok so clear the error flag */
+ setFrameErrorFlag(self->pSbrElement[elementIndex], FRAME_OK);
+ }
+
+ if (!stereo) {
+ /* Turn coupling off explicitely to avoid access to absent right frame data
+ that might occur with corrupt bitstreams. */
+ hFrameDataLeft->coupling = COUPLING_OFF;
+ }
+
+bail:
+
+ if (self != NULL) {
+ if (self->flags & SBRDEC_SYNTAX_DRM) {
+ hBs = hBsOriginal;
+ }
+
+ if (errorStatus != SBRDEC_NOT_INITIALIZED) {
+ int useOldHdr =
+ ((headerStatus == HEADER_NOT_PRESENT) ||
+ (headerStatus == HEADER_ERROR) ||
+ (headerStatus == HEADER_RESET && errorStatus == SBRDEC_PARSE_ERROR))
+ ? 1
+ : 0;
+
+ if (!useOldHdr && (thisHdrSlot != lastHdrSlot) && (hSbrHeader != NULL)) {
+ useOldHdr |=
+ (compareSbrHeader(hSbrHeader,
+ &self->sbrHeader[elementIndex][lastHdrSlot]) == 0)
+ ? 1
+ : 0;
+ }
+
+ if (hSbrElement != NULL) {
+ if (useOldHdr != 0) {
+ /* Use the old header for this frame */
+ hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = lastHdrSlot;
+ } else {
+ /* Use the new header for this frame */
+ hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot] = thisHdrSlot;
+ }
+
+ /* Move frame pointer to the next slot which is up to be decoded/applied
+ * next */
+ hSbrElement->useFrameSlot =
+ (hSbrElement->useFrameSlot + 1) % (self->numDelayFrames + 1);
+ }
+ }
+ }
+
+ *count -= startPos - (INT)FDKgetValidBits(hBs);
+
+ return errorStatus;
+}
+
+/**
+ * \brief Render one SBR element into time domain signal.
+ * \param self SBR decoder handle
+ * \param timeData pointer to output buffer
+ * \param channelMapping pointer to UCHAR array where next 2 channel offsets are
+ * stored.
+ * \param elementIndex enumerating index of the SBR element to render.
+ * \param numInChannels number of channels from core coder.
+ * \param numOutChannels pointer to a location to return number of output
+ * channels.
+ * \param psPossible flag indicating if PS is possible or not.
+ * \return SBRDEC_OK if successfull, else error code
+ */
+static SBR_ERROR sbrDecoder_DecodeElement(
+ HANDLE_SBRDECODER self, QDOM_PCM *input, INT_PCM *timeData,
+ const int timeDataSize, const FDK_channelMapDescr *const mapDescr,
+ const int mapIdx, int channelIndex, const int elementIndex,
+ const int numInChannels, int *numOutChannels, const int psPossible) {
+ SBR_DECODER_ELEMENT *hSbrElement = self->pSbrElement[elementIndex];
+ HANDLE_SBR_CHANNEL *pSbrChannel =
+ self->pSbrElement[elementIndex]->pSbrChannel;
+ HANDLE_SBR_HEADER_DATA hSbrHeader =
+ &self->sbrHeader[elementIndex]
+ [hSbrElement->useHeaderSlot[hSbrElement->useFrameSlot]];
+ HANDLE_PS_DEC h_ps_d = self->hParametricStereoDec;
+
+ /* get memory for frame data from scratch */
+ SBR_FRAME_DATA *hFrameDataLeft = NULL;
+ SBR_FRAME_DATA *hFrameDataRight = NULL;
+
+ SBR_ERROR errorStatus = SBRDEC_OK;
+
+ INT strideOut, offset0 = 255, offset0_block = 0, offset1 = 255,
+ offset1_block = 0;
+ INT codecFrameSize = self->codecFrameSize;
+
+ int stereo = (hSbrElement->elementID == ID_CPE) ? 1 : 0;
+ int numElementChannels =
+ hSbrElement
+ ->nChannels; /* Number of channels of the current SBR element */
+
+ hFrameDataLeft =
+ &hSbrElement->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot];
+ if (stereo) {
+ hFrameDataRight =
+ &hSbrElement->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot];
+ }
+
+ if (self->flags & SBRDEC_FLUSH) {
+ if (self->numFlushedFrames > self->numDelayFrames) {
+ int hdrIdx;
+ /* No valid SBR payload available, hence switch to upsampling (in all
+ * headers) */
+ for (hdrIdx = 0; hdrIdx < ((1) + 1); hdrIdx += 1) {
+ self->sbrHeader[elementIndex][hdrIdx].syncState = UPSAMPLING;
+ }
+ } else {
+ /* Move frame pointer to the next slot which is up to be decoded/applied
+ * next */
+ hSbrElement->useFrameSlot =
+ (hSbrElement->useFrameSlot + 1) % (self->numDelayFrames + 1);
+ /* Update header and frame data pointer because they have already been set
+ */
+ hSbrHeader =
+ &self->sbrHeader[elementIndex]
+ [hSbrElement
+ ->useHeaderSlot[hSbrElement->useFrameSlot]];
+ hFrameDataLeft =
+ &hSbrElement->pSbrChannel[0]->frameData[hSbrElement->useFrameSlot];
+ if (stereo) {
+ hFrameDataRight =
+ &hSbrElement->pSbrChannel[1]->frameData[hSbrElement->useFrameSlot];
+ }
+ }
+ }
+
+ /* Update the header error flag */
+ hSbrHeader->frameErrorFlag =
+ hSbrElement->frameErrorFlag[hSbrElement->useFrameSlot];
+
+ /*
+ Prepare filterbank for upsampling if no valid bit stream data is available.
+ */
+ if (hSbrHeader->syncState == SBR_NOT_INITIALIZED) {
+ errorStatus =
+ initHeaderData(hSbrHeader, self->sampleRateIn, self->sampleRateOut,
+ self->downscaleFactor, codecFrameSize, self->flags,
+ 1 /* SET_DEFAULT_HDR */
+ );
+
+ if (errorStatus != SBRDEC_OK) {
+ return errorStatus;
+ }
+
+ hSbrHeader->syncState = UPSAMPLING;
+
+ errorStatus = sbrDecoder_HeaderUpdate(self, hSbrHeader, HEADER_NOT_PRESENT,
+ pSbrChannel, hSbrElement->nChannels);
+
+ if (errorStatus != SBRDEC_OK) {
+ hSbrHeader->syncState = SBR_NOT_INITIALIZED;
+ return errorStatus;
+ }
+ }
+
+ /* reset */
+ if (hSbrHeader->status & SBRDEC_HDR_STAT_RESET) {
+ int ch;
+ int applySbrProc = (hSbrHeader->syncState == SBR_ACTIVE ||
+ (hSbrHeader->frameErrorFlag == 0 &&
+ hSbrHeader->syncState == SBR_HEADER));
+ for (ch = 0; ch < numElementChannels; ch++) {
+ SBR_ERROR errorStatusTmp = SBRDEC_OK;
+
+ errorStatusTmp = resetSbrDec(
+ &pSbrChannel[ch]->SbrDec, hSbrHeader, &pSbrChannel[ch]->prevFrameData,
+ self->synDownsampleFac, self->flags, pSbrChannel[ch]->frameData);
+
+ if (errorStatusTmp != SBRDEC_OK) {
+ hSbrHeader->syncState = UPSAMPLING;
+ }
+ }
+ if (applySbrProc) {
+ hSbrHeader->status &= ~SBRDEC_HDR_STAT_RESET;
+ }
+ }
+
+ /* decoding */
+ if ((hSbrHeader->syncState == SBR_ACTIVE) ||
+ ((hSbrHeader->syncState == SBR_HEADER) &&
+ (hSbrHeader->frameErrorFlag == 0))) {
+ errorStatus = SBRDEC_OK;
+
+ decodeSbrData(hSbrHeader, hFrameDataLeft, &pSbrChannel[0]->prevFrameData,
+ (stereo) ? hFrameDataRight : NULL,
+ (stereo) ? &pSbrChannel[1]->prevFrameData : NULL);
+
+ /* Now we have a full parameter set and can do parameter
+ based concealment instead of plain upsampling. */
+ hSbrHeader->syncState = SBR_ACTIVE;
+ }
+
+ if (timeDataSize <
+ hSbrHeader->numberTimeSlots * hSbrHeader->timeStep *
+ self->pQmfDomain->globalConf.nBandsSynthesis *
+ (psPossible ? fMax(2, numInChannels) : numInChannels)) {
+ return SBRDEC_OUTPUT_BUFFER_TOO_SMALL;
+ }
+
+ {
+ self->flags &= ~SBRDEC_PS_DECODED;
+ C_ALLOC_SCRATCH_START(pPsScratch, struct PS_DEC_COEFFICIENTS, 1)
+
+ /* decode PS data if available */
+ if (h_ps_d != NULL && psPossible && (hSbrHeader->syncState == SBR_ACTIVE)) {
+ int applyPs = 1;
+
+ /* define which frame delay line slot to process */
+ h_ps_d->processSlot = hSbrElement->useFrameSlot;
+
+ applyPs = DecodePs(h_ps_d, hSbrHeader->frameErrorFlag, pPsScratch);
+ self->flags |= (applyPs) ? SBRDEC_PS_DECODED : 0;
+ }
+
+ offset0 = FDK_chMapDescr_getMapValue(mapDescr, channelIndex, mapIdx);
+ offset0_block = offset0 * codecFrameSize;
+ if (stereo || psPossible) {
+ /* the value of offset1 only matters if the condition is true, however if
+ it is not true channelIndex+1 may exceed the channel map resutling in an
+ error, though the value of offset1 is actually meaningless. This is
+ prevented here. */
+ offset1 = FDK_chMapDescr_getMapValue(mapDescr, channelIndex + 1, mapIdx);
+ offset1_block = offset1 * codecFrameSize;
+ }
+ /* Set strides for reading and writing */
+ if (psPossible)
+ strideOut = (numInChannels < 2) ? 2 : numInChannels;
+ else
+ strideOut = numInChannels;
+
+ /* use same buffers for left and right channel and apply PS per timeslot */
+ /* Process left channel */
+ sbr_dec(&pSbrChannel[0]->SbrDec, input + offset0_block, timeData + offset0,
+ (self->flags & SBRDEC_PS_DECODED) ? &pSbrChannel[1]->SbrDec : NULL,
+ timeData + offset1, strideOut, hSbrHeader, hFrameDataLeft,
+ &pSbrChannel[0]->prevFrameData,
+ (hSbrHeader->syncState == SBR_ACTIVE), h_ps_d, self->flags,
+ codecFrameSize);
+
+ if (stereo) {
+ /* Process right channel */
+ sbr_dec(&pSbrChannel[1]->SbrDec, input + offset1_block,
+ timeData + offset1, NULL, NULL, strideOut, hSbrHeader,
+ hFrameDataRight, &pSbrChannel[1]->prevFrameData,
+ (hSbrHeader->syncState == SBR_ACTIVE), NULL, self->flags,
+ codecFrameSize);
+ }
+
+ C_ALLOC_SCRATCH_END(pPsScratch, struct PS_DEC_COEFFICIENTS, 1)
+ }
+
+ if (h_ps_d != NULL) {
+ /* save PS status for next run */
+ h_ps_d->psDecodedPrv = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0;
+ }
+
+ if (psPossible && !(self->flags & SBRDEC_SKIP_QMF_SYN)) {
+ FDK_ASSERT(strideOut > 1);
+ if (!(self->flags & SBRDEC_PS_DECODED)) {
+ /* A decoder which is able to decode PS has to produce a stereo output
+ * even if no PS data is available. */
+ /* So copy left channel to right channel. */
+ int copyFrameSize =
+ codecFrameSize * self->pQmfDomain->QmfDomainOut->fb.no_channels;
+ copyFrameSize /= self->pQmfDomain->QmfDomainIn->fb.no_channels;
+ INT_PCM *ptr;
+ INT i;
+ FDK_ASSERT(strideOut == 2);
+
+ ptr = timeData;
+ for (i = copyFrameSize >> 1; i--;) {
+ INT_PCM tmp; /* This temporal variable is required because some
+ compilers can't do *ptr++ = *ptr++ correctly. */
+ tmp = *ptr++;
+ *ptr++ = tmp;
+ tmp = *ptr++;
+ *ptr++ = tmp;
+ }
+ }
+ *numOutChannels = 2; /* Output minimum two channels when PS is enabled. */
+ }
+
+ return errorStatus;
+}
+
+SBR_ERROR sbrDecoder_Apply(HANDLE_SBRDECODER self, INT_PCM *input,
+ INT_PCM *timeData, const int timeDataSize,
+ int *numChannels, int *sampleRate,
+ const FDK_channelMapDescr *const mapDescr,
+ const int mapIdx, const int coreDecodedOk,
+ UCHAR *psDecoded) {
+ SBR_ERROR errorStatus = SBRDEC_OK;
+
+ int psPossible;
+ int sbrElementNum;
+ int numCoreChannels;
+ int numSbrChannels = 0;
+
+ if ((self == NULL) || (timeData == NULL) || (numChannels == NULL) ||
+ (sampleRate == NULL) || (psDecoded == NULL) ||
+ !FDK_chMapDescr_isValid(mapDescr)) {
+ return SBRDEC_INVALID_ARGUMENT;
+ }
+
+ psPossible = *psDecoded;
+ numCoreChannels = *numChannels;
+ if (numCoreChannels <= 0) {
+ return SBRDEC_INVALID_ARGUMENT;
+ }
+
+ if (self->numSbrElements < 1) {
+ /* exit immediately to avoid access violations */
+ return SBRDEC_NOT_INITIALIZED;
+ }
+
+ /* Sanity check of allocated SBR elements. */
+ for (sbrElementNum = 0; sbrElementNum < self->numSbrElements;
+ sbrElementNum++) {
+ if (self->pSbrElement[sbrElementNum] == NULL) {
+ return SBRDEC_NOT_INITIALIZED;
+ }
+ }
+
+ if (self->numSbrElements != 1 || self->pSbrElement[0]->elementID != ID_SCE) {
+ psPossible = 0;
+ }
+
+ /* Make sure that even if no SBR data was found/parsed *psDecoded is returned
+ * 1 if psPossible was 0. */
+ if (psPossible == 0) {
+ self->flags &= ~SBRDEC_PS_DECODED;
+ }
+
+ /* replaces channel based reset inside sbr_dec() */
+ if (((self->flags & SBRDEC_LOW_POWER) ? 1 : 0) !=
+ ((self->pQmfDomain->globalConf.flags & QMF_FLAG_LP) ? 1 : 0)) {
+ if (self->flags & SBRDEC_LOW_POWER) {
+ self->pQmfDomain->globalConf.flags |= QMF_FLAG_LP;
+ self->pQmfDomain->globalConf.flags_requested |= QMF_FLAG_LP;
+ } else {
+ self->pQmfDomain->globalConf.flags &= ~QMF_FLAG_LP;
+ self->pQmfDomain->globalConf.flags_requested &= ~QMF_FLAG_LP;
+ }
+ if (FDK_QmfDomain_InitFilterBank(self->pQmfDomain, QMF_FLAG_KEEP_STATES)) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+ }
+ if (self->numSbrChannels > self->pQmfDomain->globalConf.nInputChannels) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ if (self->flags & SBRDEC_FLUSH) {
+ /* flushing is signalized, hence increment the flush frame counter */
+ self->numFlushedFrames++;
+ } else {
+ /* no flushing is signalized, hence reset the flush frame counter */
+ self->numFlushedFrames = 0;
+ }
+
+ /* Loop over SBR elements */
+ for (sbrElementNum = 0; sbrElementNum < self->numSbrElements;
+ sbrElementNum++) {
+ int numElementChan;
+
+ if (psPossible &&
+ self->pSbrElement[sbrElementNum]->pSbrChannel[1] == NULL) {
+ /* Disable PS and try decoding SBR mono. */
+ psPossible = 0;
+ }
+
+ numElementChan =
+ (self->pSbrElement[sbrElementNum]->elementID == ID_CPE) ? 2 : 1;
+
+ /* If core signal is bad then force upsampling */
+ if (!coreDecodedOk) {
+ setFrameErrorFlag(self->pSbrElement[sbrElementNum], FRAME_ERROR_ALLSLOTS);
+ }
+
+ errorStatus = sbrDecoder_DecodeElement(
+ self, input, timeData, timeDataSize, mapDescr, mapIdx, numSbrChannels,
+ sbrElementNum,
+ numCoreChannels, /* is correct even for USC SCI==2 case */
+ &numElementChan, psPossible);
+
+ if (errorStatus != SBRDEC_OK) {
+ goto bail;
+ }
+
+ numSbrChannels += numElementChan;
+
+ if (numSbrChannels >= numCoreChannels) {
+ break;
+ }
+ }
+
+ /* Update numChannels and samplerate */
+ /* Do not mess with output channels in case of USAC. numSbrChannels !=
+ * numChannels for stereoConfigIndex == 2 */
+ if (!(self->flags & SBRDEC_SYNTAX_USAC)) {
+ *numChannels = numSbrChannels;
+ }
+ *sampleRate = self->sampleRateOut;
+ *psDecoded = (self->flags & SBRDEC_PS_DECODED) ? 1 : 0;
+
+ /* Clear reset and flush flag because everything seems to be done
+ * successfully. */
+ self->flags &= ~SBRDEC_FORCE_RESET;
+ self->flags &= ~SBRDEC_FLUSH;
+
+bail:
+
+ return errorStatus;
+}
+
+SBR_ERROR sbrDecoder_Close(HANDLE_SBRDECODER *pSelf) {
+ HANDLE_SBRDECODER self = *pSelf;
+ int i;
+
+ if (self != NULL) {
+ if (self->hParametricStereoDec != NULL) {
+ DeletePsDec(&self->hParametricStereoDec);
+ }
+
+ for (i = 0; i < (8); i++) {
+ sbrDecoder_DestroyElement(self, i);
+ }
+
+ FreeRam_SbrDecoder(pSelf);
+ }
+
+ return SBRDEC_OK;
+}
+
+INT sbrDecoder_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_SBRDEC;
+ info->version =
+ LIB_VERSION(SBRDECODER_LIB_VL0, SBRDECODER_LIB_VL1, SBRDECODER_LIB_VL2);
+ LIB_VERSION_STRING(info);
+ info->build_date = SBRDECODER_LIB_BUILD_DATE;
+ info->build_time = SBRDECODER_LIB_BUILD_TIME;
+ info->title = SBRDECODER_LIB_TITLE;
+
+ /* Set flags */
+ info->flags = 0 | CAPF_SBR_HQ | CAPF_SBR_LP | CAPF_SBR_PS_MPEG |
+ CAPF_SBR_DRM_BS | CAPF_SBR_CONCEALMENT | CAPF_SBR_DRC |
+ CAPF_SBR_ELD_DOWNSCALE | CAPF_SBR_HBEHQ;
+ /* End of flags */
+
+ return 0;
+}
+
+UINT sbrDecoder_GetDelay(const HANDLE_SBRDECODER self) {
+ UINT outputDelay = 0;
+
+ if (self != NULL) {
+ UINT flags = self->flags;
+
+ /* See chapter 1.6.7.2 of ISO/IEC 14496-3 for the GA-SBR figures below. */
+
+ /* Are we initialized? */
+ if ((self->numSbrChannels > 0) && (self->numSbrElements > 0)) {
+ /* Add QMF synthesis delay */
+ if ((flags & SBRDEC_ELD_GRID) && IS_LOWDELAY(self->coreCodec)) {
+ /* Low delay SBR: */
+ if (!(flags & SBRDEC_SKIP_QMF_SYN)) {
+ outputDelay +=
+ (flags & SBRDEC_DOWNSAMPLE) ? 32 : 64; /* QMF synthesis */
+ if (flags & SBRDEC_LD_MPS_QMF) {
+ outputDelay += 32;
+ }
+ }
+ } else if (!IS_USAC(self->coreCodec)) {
+ /* By the method of elimination this is the GA (AAC-LC, HE-AAC, ...)
+ * branch: */
+ outputDelay += (flags & SBRDEC_DOWNSAMPLE) ? 481 : 962;
+ if (flags & SBRDEC_SKIP_QMF_SYN) {
+ outputDelay -= 257; /* QMF synthesis */
+ }
+ }
+ }
+ }
+
+ return (outputDelay);
+}
diff --git a/fdk-aac/libSBRdec/src/transcendent.h b/fdk-aac/libSBRdec/src/transcendent.h
new file mode 100644
index 0000000..0e815c2
--- /dev/null
+++ b/fdk-aac/libSBRdec/src/transcendent.h
@@ -0,0 +1,372 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief FDK Fixed Point Arithmetic Library Interface
+*/
+
+#ifndef TRANSCENDENT_H
+#define TRANSCENDENT_H
+
+#include "sbrdecoder.h"
+#include "sbr_rom.h"
+
+/************************************************************************/
+/*!
+ \brief Get number of octaves between frequencies a and b
+
+ The Result is scaled with 1/8.
+ The valid range for a and b is 1 to LOG_DUALIS_TABLE_SIZE.
+
+ \return ld(a/b) / 8
+*/
+/************************************************************************/
+static inline FIXP_SGL FDK_getNumOctavesDiv8(INT a, /*!< lower band */
+ INT b) /*!< upper band */
+{
+ return ((SHORT)((LONG)(CalcLdInt(b) - CalcLdInt(a)) >> (FRACT_BITS - 3)));
+}
+
+/************************************************************************/
+/*!
+ \brief Add two values given by mantissa and exponent.
+
+ Mantissas are in fract format with values between 0 and 1. <br>
+ The base for exponents is 2. Example: \f$ a = a\_m * 2^{a\_e} \f$<br>
+*/
+/************************************************************************/
+inline void FDK_add_MantExp(FIXP_SGL a_m, /*!< Mantissa of 1st operand a */
+ SCHAR a_e, /*!< Exponent of 1st operand a */
+ FIXP_SGL b_m, /*!< Mantissa of 2nd operand b */
+ SCHAR b_e, /*!< Exponent of 2nd operand b */
+ FIXP_SGL *ptrSum_m, /*!< Mantissa of result */
+ SCHAR *ptrSum_e) /*!< Exponent of result */
+{
+ FIXP_DBL accu;
+ int shift;
+ int shiftAbs;
+
+ FIXP_DBL shiftedMantissa;
+ FIXP_DBL otherMantissa;
+
+ /* Equalize exponents of the summands.
+ For the smaller summand, the exponent is adapted and
+ for compensation, the mantissa is shifted right. */
+
+ shift = (int)(a_e - b_e);
+
+ shiftAbs = (shift > 0) ? shift : -shift;
+ shiftAbs = (shiftAbs < DFRACT_BITS - 1) ? shiftAbs : DFRACT_BITS - 1;
+ shiftedMantissa = (shift > 0) ? (FX_SGL2FX_DBL(b_m) >> shiftAbs)
+ : (FX_SGL2FX_DBL(a_m) >> shiftAbs);
+ otherMantissa = (shift > 0) ? FX_SGL2FX_DBL(a_m) : FX_SGL2FX_DBL(b_m);
+ *ptrSum_e = (shift > 0) ? a_e : b_e;
+
+ accu = (shiftedMantissa >> 1) + (otherMantissa >> 1);
+ /* shift by 1 bit to avoid overflow */
+
+ if ((accu >= (FL2FXCONST_DBL(0.5f) - (FIXP_DBL)1)) ||
+ (accu <= FL2FXCONST_DBL(-0.5f)))
+ *ptrSum_e += 1;
+ else
+ accu = (shiftedMantissa + otherMantissa);
+
+ *ptrSum_m = FX_DBL2FX_SGL(accu);
+}
+
+inline void FDK_add_MantExp(FIXP_DBL a, /*!< Mantissa of 1st operand a */
+ SCHAR a_e, /*!< Exponent of 1st operand a */
+ FIXP_DBL b, /*!< Mantissa of 2nd operand b */
+ SCHAR b_e, /*!< Exponent of 2nd operand b */
+ FIXP_DBL *ptrSum, /*!< Mantissa of result */
+ SCHAR *ptrSum_e) /*!< Exponent of result */
+{
+ FIXP_DBL accu;
+ int shift;
+ int shiftAbs;
+
+ FIXP_DBL shiftedMantissa;
+ FIXP_DBL otherMantissa;
+
+ /* Equalize exponents of the summands.
+ For the smaller summand, the exponent is adapted and
+ for compensation, the mantissa is shifted right. */
+
+ shift = (int)(a_e - b_e);
+
+ shiftAbs = (shift > 0) ? shift : -shift;
+ shiftAbs = (shiftAbs < DFRACT_BITS - 1) ? shiftAbs : DFRACT_BITS - 1;
+ shiftedMantissa = (shift > 0) ? (b >> shiftAbs) : (a >> shiftAbs);
+ otherMantissa = (shift > 0) ? a : b;
+ *ptrSum_e = (shift > 0) ? a_e : b_e;
+
+ accu = (shiftedMantissa >> 1) + (otherMantissa >> 1);
+ /* shift by 1 bit to avoid overflow */
+
+ if ((accu >= (FL2FXCONST_DBL(0.5f) - (FIXP_DBL)1)) ||
+ (accu <= FL2FXCONST_DBL(-0.5f)))
+ *ptrSum_e += 1;
+ else
+ accu = (shiftedMantissa + otherMantissa);
+
+ *ptrSum = accu;
+}
+
+/************************************************************************/
+/*!
+ \brief Divide two values given by mantissa and exponent.
+
+ Mantissas are in fract format with values between 0 and 1. <br>
+ The base for exponents is 2. Example: \f$ a = a\_m * 2^{a\_e} \f$<br>
+
+ For performance reasons, the division is based on a table lookup
+ which limits accuracy.
+*/
+/************************************************************************/
+static inline void FDK_divide_MantExp(
+ FIXP_SGL a_m, /*!< Mantissa of dividend a */
+ SCHAR a_e, /*!< Exponent of dividend a */
+ FIXP_SGL b_m, /*!< Mantissa of divisor b */
+ SCHAR b_e, /*!< Exponent of divisor b */
+ FIXP_SGL *ptrResult_m, /*!< Mantissa of quotient a/b */
+ SCHAR *ptrResult_e) /*!< Exponent of quotient a/b */
+
+{
+ int preShift, postShift, index, shift;
+ FIXP_DBL ratio_m;
+ FIXP_SGL bInv_m = FL2FXCONST_SGL(0.0f);
+
+ preShift = CntLeadingZeros(FX_SGL2FX_DBL(b_m));
+
+ /*
+ Shift b into the range from 0..INV_TABLE_SIZE-1,
+
+ E.g. 10 bits must be skipped for INV_TABLE_BITS 8:
+ - leave 8 bits as index for table
+ - skip sign bit,
+ - skip first bit of mantissa, because this is always the same (>0.5)
+
+ We are dealing with energies, so we need not care
+ about negative numbers
+ */
+
+ /*
+ The first interval has half width so the lowest bit of the index is
+ needed for a doubled resolution.
+ */
+ shift = (FRACT_BITS - 2 - INV_TABLE_BITS - preShift);
+
+ index = (shift < 0) ? (LONG)b_m << (-shift) : (LONG)b_m >> shift;
+
+ /* The index has INV_TABLE_BITS +1 valid bits here. Clear the other bits. */
+ index &= (1 << (INV_TABLE_BITS + 1)) - 1;
+
+ /* Remove offset of half an interval */
+ index--;
+
+ /* Now the lowest bit is shifted out */
+ index = index >> 1;
+
+ /* Fetch inversed mantissa from table: */
+ bInv_m = (index < 0) ? bInv_m : FDK_sbrDecoder_invTable[index];
+
+ /* Multiply a with the inverse of b: */
+ ratio_m = (index < 0) ? FX_SGL2FX_DBL(a_m >> 1) : fMultDiv2(bInv_m, a_m);
+
+ postShift = CntLeadingZeros(ratio_m) - 1;
+
+ *ptrResult_m = FX_DBL2FX_SGL(ratio_m << postShift);
+ *ptrResult_e = a_e - b_e + 1 + preShift - postShift;
+}
+
+static inline void FDK_divide_MantExp(
+ FIXP_DBL a_m, /*!< Mantissa of dividend a */
+ SCHAR a_e, /*!< Exponent of dividend a */
+ FIXP_DBL b_m, /*!< Mantissa of divisor b */
+ SCHAR b_e, /*!< Exponent of divisor b */
+ FIXP_DBL *ptrResult_m, /*!< Mantissa of quotient a/b */
+ SCHAR *ptrResult_e) /*!< Exponent of quotient a/b */
+
+{
+ int preShift, postShift, index, shift;
+ FIXP_DBL ratio_m;
+ FIXP_SGL bInv_m = FL2FXCONST_SGL(0.0f);
+
+ preShift = CntLeadingZeros(b_m);
+
+ /*
+ Shift b into the range from 0..INV_TABLE_SIZE-1,
+
+ E.g. 10 bits must be skipped for INV_TABLE_BITS 8:
+ - leave 8 bits as index for table
+ - skip sign bit,
+ - skip first bit of mantissa, because this is always the same (>0.5)
+
+ We are dealing with energies, so we need not care
+ about negative numbers
+ */
+
+ /*
+ The first interval has half width so the lowest bit of the index is
+ needed for a doubled resolution.
+ */
+ shift = (DFRACT_BITS - 2 - INV_TABLE_BITS - preShift);
+
+ index = (shift < 0) ? (LONG)b_m << (-shift) : (LONG)b_m >> shift;
+
+ /* The index has INV_TABLE_BITS +1 valid bits here. Clear the other bits. */
+ index &= (1 << (INV_TABLE_BITS + 1)) - 1;
+
+ /* Remove offset of half an interval */
+ index--;
+
+ /* Now the lowest bit is shifted out */
+ index = index >> 1;
+
+ /* Fetch inversed mantissa from table: */
+ bInv_m = (index < 0) ? bInv_m : FDK_sbrDecoder_invTable[index];
+
+ /* Multiply a with the inverse of b: */
+ ratio_m = (index < 0) ? (a_m >> 1) : fMultDiv2(bInv_m, a_m);
+
+ postShift = CntLeadingZeros(ratio_m) - 1;
+
+ *ptrResult_m = ratio_m << postShift;
+ *ptrResult_e = a_e - b_e + 1 + preShift - postShift;
+}
+
+/*!
+ \brief Calculate the squareroot of a number given by mantissa and exponent
+
+ Mantissa is in fract format with values between 0 and 1. <br>
+ The base for the exponent is 2. Example: \f$ a = a\_m * 2^{a\_e} \f$<br>
+ The operand is addressed via pointers and will be overwritten with the result.
+
+ For performance reasons, the square root is based on a table lookup
+ which limits accuracy.
+*/
+static inline void FDK_sqrt_MantExp(
+ FIXP_DBL *mantissa, /*!< Pointer to mantissa */
+ SCHAR *exponent, const SCHAR *destScale) {
+ FIXP_DBL input_m = *mantissa;
+ int input_e = (int)*exponent;
+ FIXP_DBL result = FL2FXCONST_DBL(0.0f);
+ int result_e = -FRACT_BITS;
+
+ /* Call lookup square root, which does internally normalization. */
+ result = sqrtFixp_lookup(input_m, &input_e);
+ result_e = input_e;
+
+ /* Write result */
+ if (exponent == destScale) {
+ *mantissa = result;
+ *exponent = result_e;
+ } else {
+ int shift = result_e - *destScale;
+ *mantissa = (shift >= 0) ? result << (INT)fixMin(DFRACT_BITS - 1, shift)
+ : result >> (INT)fixMin(DFRACT_BITS - 1, -shift);
+ *exponent = *destScale;
+ }
+}
+
+#endif