aboutsummaryrefslogtreecommitdiffstats
path: root/fdk-aac/libSBRenc/src/sbr_encoder.cpp
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
commit0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch)
treed07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libSBRenc/src/sbr_encoder.cpp
parentefe406d9724f959c8bc2a31802559ca6d41fd897 (diff)
downloadODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since that follows the android source releases, there is no place for a custom DAB+ patch there. So instead of having to maintain a patched fdk-aac that has to have the same .so version as the distribution package on which it is installed, we prefer having a separate fdk-aac-dab library to avoid collision. At that point, there's no reason to keep fdk-aac in a separate repository, as odr-audioenc is the only tool that needs DAB+ encoding support. Including it here simplifies installation, and makes it consistent with toolame-dab, also shipped in this repository. DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop, welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libSBRenc/src/sbr_encoder.cpp')
-rw-r--r--fdk-aac/libSBRenc/src/sbr_encoder.cpp2577
1 files changed, 2577 insertions, 0 deletions
diff --git a/fdk-aac/libSBRenc/src/sbr_encoder.cpp b/fdk-aac/libSBRenc/src/sbr_encoder.cpp
new file mode 100644
index 0000000..26257a1
--- /dev/null
+++ b/fdk-aac/libSBRenc/src/sbr_encoder.cpp
@@ -0,0 +1,2577 @@
+/* -----------------------------------------------------------------------------
+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 encoder library ******************************
+
+ Author(s): Andreas Ehret, Tobias Chalupka
+
+ Description: SBR encoder top level processing.
+
+*******************************************************************************/
+
+#include "sbr_encoder.h"
+
+#include "sbrenc_ram.h"
+#include "sbrenc_rom.h"
+#include "sbrenc_freq_sca.h"
+#include "env_bit.h"
+#include "cmondata.h"
+#include "sbr_misc.h"
+#include "sbr.h"
+#include "qmf.h"
+
+#include "ps_main.h"
+
+#define SBRENCODER_LIB_VL0 4
+#define SBRENCODER_LIB_VL1 0
+#define SBRENCODER_LIB_VL2 0
+
+/***************************************************************************/
+/*
+ * SBR Delay balancing definitions.
+ */
+
+/*
+ input buffer (1ch)
+
+ |------------ 1537 -------------|-----|---------- 2048 -------------|
+ (core2sbr delay ) ds (read, core and ds area)
+*/
+
+#define SFB(dwnsmp) \
+ (32 << (dwnsmp - \
+ 1)) /* SBR Frequency bands: 64 for dual-rate, 32 for single-rate */
+#define STS(fl) \
+ (((fl) == 1024) ? 32 \
+ : 30) /* SBR Time Slots: 32 for core frame length 1024, 30 \
+ for core frame length 960 */
+
+#define DELAY_QMF_ANA(dwnsmp) \
+ ((320 << ((dwnsmp)-1)) - (32 << ((dwnsmp)-1))) /* Full bandwidth */
+#define DELAY_HYB_ANA (10 * 64) /* + 0.5 */ /* */
+#define DELAY_HYB_SYN (6 * 64 - 32) /* */
+#define DELAY_QMF_POSTPROC(dwnsmp) \
+ (32 * (dwnsmp)) /* QMF postprocessing delay */
+#define DELAY_DEC_QMF(dwnsmp) (6 * SFB(dwnsmp)) /* Decoder QMF overlap */
+#define DELAY_QMF_SYN(dwnsmp) \
+ (1 << (dwnsmp - \
+ 1)) /* QMF_NO_POLY/2=2.5, rounded down to 2, half for single-rate */
+#define DELAY_QMF_DS (32) /* QMF synthesis for downsampled time signal */
+
+/* Delay in QMF paths */
+#define DELAY_SBR(fl, dwnsmp) \
+ (DELAY_QMF_ANA(dwnsmp) + (SFB(dwnsmp) * STS(fl) - 1) + DELAY_QMF_SYN(dwnsmp))
+#define DELAY_PS(fl, dwnsmp) \
+ (DELAY_QMF_ANA(dwnsmp) + DELAY_HYB_ANA + DELAY_DEC_QMF(dwnsmp) + \
+ (SFB(dwnsmp) * STS(fl) - 1) + DELAY_HYB_SYN + DELAY_QMF_SYN(dwnsmp))
+#define DELAY_ELDSBR(fl, dwnsmp) \
+ ((((fl) / 2) * (dwnsmp)) - 1 + DELAY_QMF_POSTPROC(dwnsmp))
+#define DELAY_ELDv2SBR(fl, dwnsmp) \
+ ((((fl) / 2) * (dwnsmp)) - 1 + 80 * (dwnsmp)) /* 80 is the delay caused \
+ by the sum of the CLD \
+ analysis and the MPSLD \
+ synthesis filterbank */
+
+/* Delay in core path (core and downsampler not taken into account) */
+#define DELAY_COREPATH_SBR(fl, dwnsmp) \
+ ((DELAY_QMF_ANA(dwnsmp) + DELAY_DEC_QMF(dwnsmp) + DELAY_QMF_SYN(dwnsmp)))
+#define DELAY_COREPATH_ELDSBR(fl, dwnsmp) ((DELAY_QMF_POSTPROC(dwnsmp)))
+#define DELAY_COREPATH_ELDv2SBR(fl, dwnsmp) (128 * (dwnsmp)) /* 4 slots */
+#define DELAY_COREPATH_PS(fl, dwnsmp) \
+ ((DELAY_QMF_ANA(dwnsmp) + DELAY_QMF_DS + \
+ /*(DELAY_AAC(fl)*2) + */ DELAY_QMF_ANA(dwnsmp) + DELAY_DEC_QMF(dwnsmp) + \
+ DELAY_HYB_SYN + DELAY_QMF_SYN(dwnsmp))) /* 2048 - 463*2 */
+
+/* Delay differences between SBR- and downsampled path for SBR and SBR+PS */
+#define DELAY_AAC2SBR(fl, dwnsmp) \
+ ((DELAY_COREPATH_SBR(fl, dwnsmp)) - DELAY_SBR((fl), (dwnsmp)))
+#define DELAY_ELD2SBR(fl, dwnsmp) \
+ ((DELAY_COREPATH_ELDSBR(fl, dwnsmp)) - DELAY_ELDSBR(fl, dwnsmp))
+#define DELAY_AAC2PS(fl, dwnsmp) \
+ ((DELAY_COREPATH_PS(fl, dwnsmp)) - DELAY_PS(fl, dwnsmp)) /* 2048 - 463*2 */
+
+/* Assumption: The sample delay resulting of of DELAY_AAC2PS is always smaller
+ * than the sample delay implied by DELAY_AAC2SBR */
+#define MAX_DS_FILTER_DELAY \
+ (5) /* the additional max downsampler filter delay (source fs) */
+#define MAX_SAMPLE_DELAY \
+ (DELAY_AAC2SBR(1024, 2) + MAX_DS_FILTER_DELAY) /* maximum delay: frame \
+ length of 1024 and \
+ dual-rate sbr */
+
+/***************************************************************************/
+
+/*************** Delay parameters for sbrEncoder_Init_delay() **************/
+typedef struct {
+ int dsDelay; /* the delay of the (time-domain) downsampler itself */
+ int delay; /* overall delay / samples */
+ int sbrDecDelay; /* SBR decoder's delay */
+ int corePathOffset; /* core path offset / samples; added by
+ sbrEncoder_Init_delay() */
+ int sbrPathOffset; /* SBR path offset / samples; added by
+ sbrEncoder_Init_delay() */
+ int bitstrDelay; /* bitstream delay / frames; added by sbrEncoder_Init_delay()
+ */
+ int delayInput2Core; /* delay of the input to the core / samples */
+} DELAY_PARAM;
+/***************************************************************************/
+
+#define INVALID_TABLE_IDX -1
+
+/***************************************************************************/
+/*!
+
+ \brief Selects the SBR tuning settings to use dependent on number of
+ channels, bitrate, sample rate and core coder
+
+ \return Index to the appropriate table
+
+****************************************************************************/
+#define DISTANCE_CEIL_VALUE 5000000
+static INT getSbrTuningTableIndex(
+ UINT bitrate, /*! the total bitrate in bits/sec */
+ UINT numChannels, /*! the number of channels for the core coder */
+ UINT sampleRate, /*! the sampling rate of the core coder */
+ AUDIO_OBJECT_TYPE core, UINT *pBitRateClosest) {
+ int i, bitRateClosestLowerIndex = -1, bitRateClosestUpperIndex = -1,
+ found = 0;
+ UINT bitRateClosestUpper = 0, bitRateClosestLower = DISTANCE_CEIL_VALUE;
+
+#define isForThisCore(i) \
+ ((sbrTuningTable[i].coreCoder == CODEC_AACLD && core == AOT_ER_AAC_ELD) || \
+ (sbrTuningTable[i].coreCoder == CODEC_AAC && core != AOT_ER_AAC_ELD))
+
+ for (i = 0; i < sbrTuningTableSize; i++) {
+ if (isForThisCore(i)) /* tuning table is for this core codec */
+ {
+ if (numChannels == sbrTuningTable[i].numChannels &&
+ sampleRate == sbrTuningTable[i].sampleRate) {
+ found = 1;
+ if ((bitrate >= sbrTuningTable[i].bitrateFrom) &&
+ (bitrate < sbrTuningTable[i].bitrateTo)) {
+ return i;
+ } else {
+ if (sbrTuningTable[i].bitrateFrom > bitrate) {
+ if (sbrTuningTable[i].bitrateFrom < bitRateClosestLower) {
+ bitRateClosestLower = sbrTuningTable[i].bitrateFrom;
+ bitRateClosestLowerIndex = i;
+ }
+ }
+ if (sbrTuningTable[i].bitrateTo <= bitrate) {
+ if (sbrTuningTable[i].bitrateTo > bitRateClosestUpper) {
+ bitRateClosestUpper = sbrTuningTable[i].bitrateTo - 1;
+ bitRateClosestUpperIndex = i;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (bitRateClosestUpperIndex >= 0) {
+ return bitRateClosestUpperIndex;
+ }
+
+ if (pBitRateClosest != NULL) {
+ /* If there was at least one matching tuning entry pick the least distance
+ * bit rate */
+ if (found) {
+ int distanceUpper = DISTANCE_CEIL_VALUE,
+ distanceLower = DISTANCE_CEIL_VALUE;
+ if (bitRateClosestLowerIndex >= 0) {
+ distanceLower =
+ sbrTuningTable[bitRateClosestLowerIndex].bitrateFrom - bitrate;
+ }
+ if (bitRateClosestUpperIndex >= 0) {
+ distanceUpper =
+ bitrate - sbrTuningTable[bitRateClosestUpperIndex].bitrateTo;
+ }
+ if (distanceUpper < distanceLower) {
+ *pBitRateClosest = bitRateClosestUpper;
+ } else {
+ *pBitRateClosest = bitRateClosestLower;
+ }
+ } else {
+ *pBitRateClosest = 0;
+ }
+ }
+
+ return INVALID_TABLE_IDX;
+}
+
+/***************************************************************************/
+/*!
+
+ \brief Selects the PS tuning settings to use dependent on bitrate
+ and core coder
+
+ \return Index to the appropriate table
+
+****************************************************************************/
+static INT getPsTuningTableIndex(UINT bitrate, UINT *pBitRateClosest) {
+ INT i, paramSets = sizeof(psTuningTable) / sizeof(psTuningTable[0]);
+ int bitRateClosestLowerIndex = -1, bitRateClosestUpperIndex = -1;
+ UINT bitRateClosestUpper = 0, bitRateClosestLower = DISTANCE_CEIL_VALUE;
+
+ for (i = 0; i < paramSets; i++) {
+ if ((bitrate >= psTuningTable[i].bitrateFrom) &&
+ (bitrate < psTuningTable[i].bitrateTo)) {
+ return i;
+ } else {
+ if (psTuningTable[i].bitrateFrom > bitrate) {
+ if (psTuningTable[i].bitrateFrom < bitRateClosestLower) {
+ bitRateClosestLower = psTuningTable[i].bitrateFrom;
+ bitRateClosestLowerIndex = i;
+ }
+ }
+ if (psTuningTable[i].bitrateTo <= bitrate) {
+ if (psTuningTable[i].bitrateTo > bitRateClosestUpper) {
+ bitRateClosestUpper = psTuningTable[i].bitrateTo - 1;
+ bitRateClosestUpperIndex = i;
+ }
+ }
+ }
+ }
+
+ if (bitRateClosestUpperIndex >= 0) {
+ return bitRateClosestUpperIndex;
+ }
+
+ if (pBitRateClosest != NULL) {
+ int distanceUpper = DISTANCE_CEIL_VALUE,
+ distanceLower = DISTANCE_CEIL_VALUE;
+ if (bitRateClosestLowerIndex >= 0) {
+ distanceLower =
+ sbrTuningTable[bitRateClosestLowerIndex].bitrateFrom - bitrate;
+ }
+ if (bitRateClosestUpperIndex >= 0) {
+ distanceUpper =
+ bitrate - sbrTuningTable[bitRateClosestUpperIndex].bitrateTo;
+ }
+ if (distanceUpper < distanceLower) {
+ *pBitRateClosest = bitRateClosestUpper;
+ } else {
+ *pBitRateClosest = bitRateClosestLower;
+ }
+ }
+
+ return INVALID_TABLE_IDX;
+}
+
+/***************************************************************************/
+/*!
+
+ \brief In case of downsampled SBR we may need to lower the stop freq
+ of a tuning setting to fit into the lower half of the
+ spectrum ( which is sampleRate/4 )
+
+ \return the adapted stop frequency index (-1 -> error)
+
+ \ingroup SbrEncCfg
+
+****************************************************************************/
+static INT FDKsbrEnc_GetDownsampledStopFreq(const INT sampleRateCore,
+ const INT startFreq, INT stopFreq,
+ const INT downSampleFactor) {
+ INT maxStopFreqRaw = sampleRateCore / 2;
+ INT startBand, stopBand;
+ HANDLE_ERROR_INFO err;
+
+ while (stopFreq > 0 && FDKsbrEnc_getSbrStopFreqRAW(stopFreq, sampleRateCore) >
+ maxStopFreqRaw) {
+ stopFreq--;
+ }
+
+ if (FDKsbrEnc_getSbrStopFreqRAW(stopFreq, sampleRateCore) > maxStopFreqRaw)
+ return -1;
+
+ err = FDKsbrEnc_FindStartAndStopBand(
+ sampleRateCore << (downSampleFactor - 1), sampleRateCore,
+ 32 << (downSampleFactor - 1), startFreq, stopFreq, &startBand, &stopBand);
+ if (err) return -1;
+
+ return stopFreq;
+}
+
+/***************************************************************************/
+/*!
+
+ \brief tells us, if for the given coreCoder, bitrate, number of channels
+ and input sampling rate an SBR setting is available. If yes, it
+ tells us also the core sampling rate we would need to run with
+
+ \return a flag indicating success: yes (1) or no (0)
+
+****************************************************************************/
+static UINT FDKsbrEnc_IsSbrSettingAvail(
+ UINT bitrate, /*! the total bitrate in bits/sec */
+ UINT vbrMode, /*! the vbr paramter, 0 means constant bitrate */
+ UINT numOutputChannels, /*! the number of channels for the core coder */
+ UINT sampleRateInput, /*! the input sample rate [in Hz] */
+ UINT sampleRateCore, /*! the core's sampling rate */
+ AUDIO_OBJECT_TYPE core) {
+ INT idx = INVALID_TABLE_IDX;
+
+ if (sampleRateInput < 16000) return 0;
+
+ if (bitrate == 0) {
+ /* map vbr quality to bitrate */
+ if (vbrMode < 30)
+ bitrate = 24000;
+ else if (vbrMode < 40)
+ bitrate = 28000;
+ else if (vbrMode < 60)
+ bitrate = 32000;
+ else if (vbrMode < 75)
+ bitrate = 40000;
+ else
+ bitrate = 48000;
+ bitrate *= numOutputChannels;
+ }
+
+ idx = getSbrTuningTableIndex(bitrate, numOutputChannels, sampleRateCore, core,
+ NULL);
+
+ return (idx == INVALID_TABLE_IDX ? 0 : 1);
+}
+
+/***************************************************************************/
+/*!
+
+ \brief Adjusts the SBR settings according to the chosen core coder
+ settings which are accessible via config->codecSettings
+
+ \return A flag indicating success: yes (1) or no (0)
+
+****************************************************************************/
+static UINT FDKsbrEnc_AdjustSbrSettings(
+ const sbrConfigurationPtr config, /*! output, modified */
+ UINT bitRate, /*! the total bitrate in bits/sec */
+ UINT numChannels, /*! the core coder number of channels */
+ UINT sampleRateCore, /*! the core coder sampling rate in Hz */
+ UINT sampleRateSbr, /*! the sbr coder sampling rate in Hz */
+ UINT transFac, /*! the short block to long block ratio */
+ UINT standardBitrate, /*! the standard bitrate per channel in bits/sec */
+ UINT vbrMode, /*! the vbr paramter, 0 poor quality .. 100 high quality*/
+ UINT useSpeechConfig, /*!< adapt tuning parameters for speech ? */
+ UINT lcsMode, /*! the low complexity stereo mode */
+ UINT bParametricStereo, /*!< use parametric stereo */
+ AUDIO_OBJECT_TYPE core) /* Core audio codec object type */
+{
+ INT idx = INVALID_TABLE_IDX;
+ /* set the core codec settings */
+ config->codecSettings.bitRate = bitRate;
+ config->codecSettings.nChannels = numChannels;
+ config->codecSettings.sampleFreq = sampleRateCore;
+ config->codecSettings.transFac = transFac;
+ config->codecSettings.standardBitrate = standardBitrate;
+
+ if (bitRate < 28000) {
+ config->threshold_AmpRes_FF_m = (FIXP_DBL)MAXVAL_DBL;
+ config->threshold_AmpRes_FF_e = 7;
+ } else if (bitRate >= 28000 && bitRate <= 48000) {
+ /* The float threshold is 75
+ 0.524288f is fractional part of RELAXATION, the quotaMatrix and therefore
+ tonality are scaled by this 2/3 is because the original implementation
+ divides the tonality values by 3, here it's divided by 2 128 compensates
+ the necessary shiftfactor of 7 */
+ config->threshold_AmpRes_FF_m =
+ FL2FXCONST_DBL(75.0f * 0.524288f / (2.0f / 3.0f) / 128.0f);
+ config->threshold_AmpRes_FF_e = 7;
+ } else if (bitRate > 48000) {
+ config->threshold_AmpRes_FF_m = FL2FXCONST_DBL(0);
+ config->threshold_AmpRes_FF_e = 0;
+ }
+
+ if (bitRate == 0) {
+ /* map vbr quality to bitrate */
+ if (vbrMode < 30)
+ bitRate = 24000;
+ else if (vbrMode < 40)
+ bitRate = 28000;
+ else if (vbrMode < 60)
+ bitRate = 32000;
+ else if (vbrMode < 75)
+ bitRate = 40000;
+ else
+ bitRate = 48000;
+ bitRate *= numChannels;
+ /* fix to enable mono vbrMode<40 @ 44.1 of 48kHz */
+ if (numChannels == 1) {
+ if (sampleRateSbr == 44100 || sampleRateSbr == 48000) {
+ if (vbrMode < 40) bitRate = 32000;
+ }
+ }
+ }
+
+ idx =
+ getSbrTuningTableIndex(bitRate, numChannels, sampleRateCore, core, NULL);
+
+ if (idx != INVALID_TABLE_IDX) {
+ config->startFreq = sbrTuningTable[idx].startFreq;
+ config->stopFreq = sbrTuningTable[idx].stopFreq;
+ if (useSpeechConfig) {
+ config->startFreq = sbrTuningTable[idx].startFreqSpeech;
+ config->stopFreq = sbrTuningTable[idx].stopFreqSpeech;
+ }
+
+ /* Adapt stop frequency in case of downsampled SBR - only 32 bands then */
+ if (1 == config->downSampleFactor) {
+ INT dsStopFreq = FDKsbrEnc_GetDownsampledStopFreq(
+ sampleRateCore, config->startFreq, config->stopFreq,
+ config->downSampleFactor);
+ if (dsStopFreq < 0) {
+ return 0;
+ }
+
+ config->stopFreq = dsStopFreq;
+ }
+
+ config->sbr_noise_bands = sbrTuningTable[idx].numNoiseBands;
+ if (core == AOT_ER_AAC_ELD) config->init_amp_res_FF = SBR_AMP_RES_1_5;
+ config->noiseFloorOffset = sbrTuningTable[idx].noiseFloorOffset;
+
+ config->ana_max_level = sbrTuningTable[idx].noiseMaxLevel;
+ config->stereoMode = sbrTuningTable[idx].stereoMode;
+ config->freqScale = sbrTuningTable[idx].freqScale;
+
+ if (numChannels == 1) {
+ /* stereo case */
+ switch (core) {
+ case AOT_AAC_LC:
+ if (bitRate <= (useSpeechConfig ? 24000U : 20000U)) {
+ config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency
+ resolution for
+ non-split frames */
+ config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency
+ resolution for split
+ frames */
+ }
+ break;
+ case AOT_ER_AAC_ELD:
+ if (bitRate < 36000)
+ config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency
+ resolution for split
+ frames */
+ if (bitRate < 26000) {
+ config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency
+ resolution for
+ non-split frames */
+ config->fResTransIsLow =
+ 1; /* for transient frames, set low frequency resolution */
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ /* stereo case */
+ switch (core) {
+ case AOT_AAC_LC:
+ if (bitRate <= 28000) {
+ config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency
+ resolution for
+ non-split frames */
+ config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency
+ resolution for split
+ frames */
+ }
+ break;
+ case AOT_ER_AAC_ELD:
+ if (bitRate < 72000) {
+ config->freq_res_fixfix[1] = FREQ_RES_LOW; /* set low frequency
+ resolution for split
+ frames */
+ }
+ if (bitRate < 52000) {
+ config->freq_res_fixfix[0] = FREQ_RES_LOW; /* set low frequency
+ resolution for
+ non-split frames */
+ config->fResTransIsLow =
+ 1; /* for transient frames, set low frequency resolution */
+ }
+ break;
+ default:
+ break;
+ }
+ if (bitRate <= 28000) {
+ /*
+ additionally restrict frequency resolution in FIXFIX frames
+ to further reduce SBR payload size */
+ config->freq_res_fixfix[0] = FREQ_RES_LOW;
+ config->freq_res_fixfix[1] = FREQ_RES_LOW;
+ }
+ }
+
+ /* adjust usage of parametric coding dependent on bitrate and speech config
+ * flag */
+ if (useSpeechConfig) config->parametricCoding = 0;
+
+ if (core == AOT_ER_AAC_ELD) {
+ if (bitRate < 28000) config->init_amp_res_FF = SBR_AMP_RES_3_0;
+ config->SendHeaderDataTime = -1;
+ }
+
+ if (numChannels == 1) {
+ if (bitRate < 16000) {
+ config->parametricCoding = 0;
+ }
+ } else {
+ if (bitRate < 20000) {
+ config->parametricCoding = 0;
+ }
+ }
+
+ config->useSpeechConfig = useSpeechConfig;
+
+ /* PS settings */
+ config->bParametricStereo = bParametricStereo;
+
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*****************************************************************************
+
+ functionname: FDKsbrEnc_InitializeSbrDefaults
+ description: initializes the SBR configuration
+ returns: error status
+ input: - core codec type,
+ - factor of SBR to core frame length,
+ - core frame length
+ output: initialized SBR configuration
+
+*****************************************************************************/
+static UINT FDKsbrEnc_InitializeSbrDefaults(sbrConfigurationPtr config,
+ INT downSampleFactor,
+ UINT codecGranuleLen,
+ const INT isLowDelay) {
+ if ((downSampleFactor < 1 || downSampleFactor > 2) ||
+ (codecGranuleLen * downSampleFactor > 64 * 32))
+ return (0); /* error */
+
+ config->SendHeaderDataTime = 1000;
+ config->useWaveCoding = 0;
+ config->crcSbr = 0;
+ config->dynBwSupported = 1;
+ if (isLowDelay)
+ config->tran_thr = 6000;
+ else
+ config->tran_thr = 13000;
+
+ config->parametricCoding = 1;
+
+ config->sbrFrameSize = codecGranuleLen * downSampleFactor;
+ config->downSampleFactor = downSampleFactor;
+
+ /* sbr default parameters */
+ config->sbr_data_extra = 0;
+ config->amp_res = SBR_AMP_RES_3_0;
+ config->tran_fc = 0;
+ config->tran_det_mode = 1;
+ config->spread = 1;
+ config->stat = 0;
+ config->e = 1;
+ config->deltaTAcrossFrames = 1;
+ config->dF_edge_1stEnv = FL2FXCONST_DBL(0.3f);
+ config->dF_edge_incr = FL2FXCONST_DBL(0.3f);
+
+ config->sbr_invf_mode = INVF_SWITCHED;
+ config->sbr_xpos_mode = XPOS_LC;
+ config->sbr_xpos_ctrl = SBR_XPOS_CTRL_DEFAULT;
+ config->sbr_xpos_level = 0;
+ config->useSaPan = 0;
+ config->dynBwEnabled = 0;
+
+ /* the following parameters are overwritten by the
+ FDKsbrEnc_AdjustSbrSettings() function since they are included in the
+ tuning table */
+ config->stereoMode = SBR_SWITCH_LRC;
+ config->ana_max_level = 6;
+ config->noiseFloorOffset = 0;
+ config->startFreq = 5; /* 5.9 respectively 6.0 kHz at fs = 44.1/48 kHz */
+ config->stopFreq = 9; /* 16.2 respectively 16.8 kHz at fs = 44.1/48 kHz */
+ config->freq_res_fixfix[0] = FREQ_RES_HIGH; /* non-split case */
+ config->freq_res_fixfix[1] = FREQ_RES_HIGH; /* split case */
+ config->fResTransIsLow = 0; /* for transient frames, set variable frequency
+ resolution according to freqResTable */
+
+ /* header_extra_1 */
+ config->freqScale = SBR_FREQ_SCALE_DEFAULT;
+ config->alterScale = SBR_ALTER_SCALE_DEFAULT;
+ config->sbr_noise_bands = SBR_NOISE_BANDS_DEFAULT;
+
+ /* header_extra_2 */
+ config->sbr_limiter_bands = SBR_LIMITER_BANDS_DEFAULT;
+ config->sbr_limiter_gains = SBR_LIMITER_GAINS_DEFAULT;
+ config->sbr_interpol_freq = SBR_INTERPOL_FREQ_DEFAULT;
+ config->sbr_smoothing_length = SBR_SMOOTHING_LENGTH_DEFAULT;
+
+ return 1;
+}
+
+/*****************************************************************************
+
+ functionname: DeleteEnvChannel
+ description: frees memory of one SBR channel
+ returns: -
+ input: handle of channel
+ output: released handle
+
+*****************************************************************************/
+static void deleteEnvChannel(HANDLE_ENV_CHANNEL hEnvCut) {
+ if (hEnvCut) {
+ FDKsbrEnc_DeleteTonCorrParamExtr(&hEnvCut->TonCorr);
+
+ FDKsbrEnc_deleteExtractSbrEnvelope(&hEnvCut->sbrExtractEnvelope);
+ }
+}
+
+/*****************************************************************************
+
+ functionname: sbrEncoder_ChannelClose
+ description: close the channel coding handle
+ returns:
+ input: phSbrChannel
+ output:
+
+*****************************************************************************/
+static void sbrEncoder_ChannelClose(HANDLE_SBR_CHANNEL hSbrChannel) {
+ if (hSbrChannel != NULL) {
+ deleteEnvChannel(&hSbrChannel->hEnvChannel);
+ }
+}
+
+/*****************************************************************************
+
+ functionname: sbrEncoder_ElementClose
+ description: close the channel coding handle
+ returns:
+ input: phSbrChannel
+ output:
+
+*****************************************************************************/
+static void sbrEncoder_ElementClose(HANDLE_SBR_ELEMENT *phSbrElement) {
+ HANDLE_SBR_ELEMENT hSbrElement = *phSbrElement;
+
+ if (hSbrElement != NULL) {
+ if (hSbrElement->sbrConfigData.v_k_master)
+ FreeRam_Sbr_v_k_master(&hSbrElement->sbrConfigData.v_k_master);
+ if (hSbrElement->sbrConfigData.freqBandTable[LO])
+ FreeRam_Sbr_freqBandTableLO(
+ &hSbrElement->sbrConfigData.freqBandTable[LO]);
+ if (hSbrElement->sbrConfigData.freqBandTable[HI])
+ FreeRam_Sbr_freqBandTableHI(
+ &hSbrElement->sbrConfigData.freqBandTable[HI]);
+
+ FreeRam_SbrElement(phSbrElement);
+ }
+ return;
+}
+
+void sbrEncoder_Close(HANDLE_SBR_ENCODER *phSbrEncoder) {
+ HANDLE_SBR_ENCODER hSbrEncoder = *phSbrEncoder;
+
+ if (hSbrEncoder != NULL) {
+ int el, ch;
+
+ for (el = 0; el < (8); el++) {
+ if (hSbrEncoder->sbrElement[el] != NULL) {
+ sbrEncoder_ElementClose(&hSbrEncoder->sbrElement[el]);
+ }
+ }
+
+ /* Close sbr Channels */
+ for (ch = 0; ch < (8); ch++) {
+ if (hSbrEncoder->pSbrChannel[ch]) {
+ sbrEncoder_ChannelClose(hSbrEncoder->pSbrChannel[ch]);
+ FreeRam_SbrChannel(&hSbrEncoder->pSbrChannel[ch]);
+ }
+
+ if (hSbrEncoder->QmfAnalysis[ch].FilterStates)
+ FreeRam_Sbr_QmfStatesAnalysis(
+ (FIXP_QAS **)&hSbrEncoder->QmfAnalysis[ch].FilterStates);
+ }
+
+ if (hSbrEncoder->hParametricStereo)
+ PSEnc_Destroy(&hSbrEncoder->hParametricStereo);
+ if (hSbrEncoder->qmfSynthesisPS.FilterStates)
+ FreeRam_PsQmfStatesSynthesis(
+ (FIXP_DBL **)&hSbrEncoder->qmfSynthesisPS.FilterStates);
+
+ /* Release Overlay */
+ if (hSbrEncoder->pSBRdynamic_RAM)
+ FreeRam_SbrDynamic_RAM((FIXP_DBL **)&hSbrEncoder->pSBRdynamic_RAM);
+
+ FreeRam_SbrEncoder(phSbrEncoder);
+ }
+}
+
+/*****************************************************************************
+
+ functionname: updateFreqBandTable
+ description: updates vk_master
+ returns: -
+ input: config handle
+ output: error info
+
+*****************************************************************************/
+static INT updateFreqBandTable(HANDLE_SBR_CONFIG_DATA sbrConfigData,
+ HANDLE_SBR_HEADER_DATA sbrHeaderData,
+ const INT downSampleFactor) {
+ INT k0, k2;
+
+ if (FDKsbrEnc_FindStartAndStopBand(
+ sbrConfigData->sampleFreq,
+ sbrConfigData->sampleFreq >> (downSampleFactor - 1),
+ sbrConfigData->noQmfBands, sbrHeaderData->sbr_start_frequency,
+ sbrHeaderData->sbr_stop_frequency, &k0, &k2))
+ return (1);
+
+ if (FDKsbrEnc_UpdateFreqScale(
+ sbrConfigData->v_k_master, &sbrConfigData->num_Master, k0, k2,
+ sbrHeaderData->freqScale, sbrHeaderData->alterScale))
+ return (1);
+
+ sbrHeaderData->sbr_xover_band = 0;
+
+ if (FDKsbrEnc_UpdateHiRes(sbrConfigData->freqBandTable[HI],
+ &sbrConfigData->nSfb[HI], sbrConfigData->v_k_master,
+ sbrConfigData->num_Master,
+ &sbrHeaderData->sbr_xover_band))
+ return (1);
+
+ FDKsbrEnc_UpdateLoRes(
+ sbrConfigData->freqBandTable[LO], &sbrConfigData->nSfb[LO],
+ sbrConfigData->freqBandTable[HI], sbrConfigData->nSfb[HI]);
+
+ sbrConfigData->xOverFreq =
+ (sbrConfigData->freqBandTable[LOW_RES][0] * sbrConfigData->sampleFreq /
+ sbrConfigData->noQmfBands +
+ 1) >>
+ 1;
+
+ return (0);
+}
+
+/*****************************************************************************
+
+ functionname: resetEnvChannel
+ description: resets parameters and allocates memory
+ returns: error status
+ input:
+ output: hEnv
+
+*****************************************************************************/
+static INT resetEnvChannel(HANDLE_SBR_CONFIG_DATA sbrConfigData,
+ HANDLE_SBR_HEADER_DATA sbrHeaderData,
+ HANDLE_ENV_CHANNEL hEnv) {
+ /* note !!! hEnv->encEnvData.noOfnoisebands will be updated later in function
+ * FDKsbrEnc_extractSbrEnvelope !!!*/
+ hEnv->TonCorr.sbrNoiseFloorEstimate.noiseBands =
+ sbrHeaderData->sbr_noise_bands;
+
+ if (FDKsbrEnc_ResetTonCorrParamExtr(
+ &hEnv->TonCorr, sbrConfigData->xposCtrlSwitch,
+ sbrConfigData->freqBandTable[HI][0], sbrConfigData->v_k_master,
+ sbrConfigData->num_Master, sbrConfigData->sampleFreq,
+ sbrConfigData->freqBandTable, sbrConfigData->nSfb,
+ sbrConfigData->noQmfBands))
+ return (1);
+
+ hEnv->sbrCodeNoiseFloor.nSfb[LO] =
+ hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands;
+ hEnv->sbrCodeNoiseFloor.nSfb[HI] =
+ hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands;
+
+ hEnv->sbrCodeEnvelope.nSfb[LO] = sbrConfigData->nSfb[LO];
+ hEnv->sbrCodeEnvelope.nSfb[HI] = sbrConfigData->nSfb[HI];
+
+ hEnv->encEnvData.noHarmonics = sbrConfigData->nSfb[HI];
+
+ hEnv->sbrCodeEnvelope.upDate = 0;
+ hEnv->sbrCodeNoiseFloor.upDate = 0;
+
+ return (0);
+}
+
+/* ****************************** FDKsbrEnc_SbrGetXOverFreq
+ * ******************************/
+/**
+ * @fn
+ * @brief calculates the closest possible crossover frequency
+ * @return the crossover frequency SBR accepts
+ *
+ */
+static INT FDKsbrEnc_SbrGetXOverFreq(
+ HANDLE_SBR_ELEMENT hEnv, /*!< handle to SBR encoder instance */
+ INT xoverFreq) /*!< from core coder suggested crossover frequency */
+{
+ INT band;
+ INT lastDiff, newDiff;
+ INT cutoffSb;
+
+ UCHAR *RESTRICT pVKMaster = hEnv->sbrConfigData.v_k_master;
+
+ /* Check if there is a matching cutoff frequency in the master table */
+ cutoffSb = (4 * xoverFreq * hEnv->sbrConfigData.noQmfBands /
+ hEnv->sbrConfigData.sampleFreq +
+ 1) >>
+ 1;
+ lastDiff = cutoffSb;
+ for (band = 0; band < hEnv->sbrConfigData.num_Master; band++) {
+ newDiff = fixp_abs((INT)pVKMaster[band] - cutoffSb);
+
+ if (newDiff >= lastDiff) {
+ band--;
+ break;
+ }
+
+ lastDiff = newDiff;
+ }
+
+ return ((pVKMaster[band] * hEnv->sbrConfigData.sampleFreq /
+ hEnv->sbrConfigData.noQmfBands +
+ 1) >>
+ 1);
+}
+
+/*****************************************************************************
+
+ functionname: FDKsbrEnc_EnvEncodeFrame
+ description: performs the sbr envelope calculation for one element
+ returns:
+ input:
+ output:
+
+*****************************************************************************/
+INT FDKsbrEnc_EnvEncodeFrame(
+ HANDLE_SBR_ENCODER hEnvEncoder, int iElement,
+ INT_PCM *samples, /*!< time samples, always deinterleaved */
+ UINT samplesBufSize, /*!< time buffer channel stride */
+ UINT *sbrDataBits, /*!< Size of SBR payload */
+ UCHAR *sbrData, /*!< SBR payload */
+ int clearOutput /*!< Do not consider any input signal */
+) {
+ HANDLE_SBR_ELEMENT hSbrElement = NULL;
+ FDK_CRCINFO crcInfo;
+ INT crcReg;
+ INT ch;
+ INT band;
+ INT cutoffSb;
+ INT newXOver;
+
+ if (hEnvEncoder == NULL) return -1;
+
+ hSbrElement = hEnvEncoder->sbrElement[iElement];
+
+ if (hSbrElement == NULL) return -1;
+
+ /* header bitstream handling */
+ HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData = &hSbrElement->sbrBitstreamData;
+
+ INT psHeaderActive = 0;
+ sbrBitstreamData->HeaderActive = 0;
+
+ /* Anticipate PS header because of internal PS bitstream delay in order to be
+ * in sync with SBR header. */
+ if (sbrBitstreamData->CountSendHeaderData ==
+ (sbrBitstreamData->NrSendHeaderData - 1)) {
+ psHeaderActive = 1;
+ }
+
+ /* Signal SBR header to be written into bitstream */
+ if (sbrBitstreamData->CountSendHeaderData == 0) {
+ sbrBitstreamData->HeaderActive = 1;
+ }
+
+ /* Increment header interval counter */
+ if (sbrBitstreamData->NrSendHeaderData == 0) {
+ sbrBitstreamData->CountSendHeaderData = 1;
+ } else {
+ if (sbrBitstreamData->CountSendHeaderData >= 0) {
+ sbrBitstreamData->CountSendHeaderData++;
+ sbrBitstreamData->CountSendHeaderData %=
+ sbrBitstreamData->NrSendHeaderData;
+ }
+ }
+
+ if (hSbrElement->CmonData.dynBwEnabled) {
+ INT i;
+ for (i = 4; i > 0; i--)
+ hSbrElement->dynXOverFreqDelay[i] = hSbrElement->dynXOverFreqDelay[i - 1];
+
+ hSbrElement->dynXOverFreqDelay[0] = hSbrElement->CmonData.dynXOverFreqEnc;
+ if (hSbrElement->dynXOverFreqDelay[1] > hSbrElement->dynXOverFreqDelay[2])
+ newXOver = hSbrElement->dynXOverFreqDelay[2];
+ else
+ newXOver = hSbrElement->dynXOverFreqDelay[1];
+
+ /* has the crossover frequency changed? */
+ if (hSbrElement->sbrConfigData.dynXOverFreq != newXOver) {
+ /* get corresponding master band */
+ cutoffSb = ((4 * newXOver * hSbrElement->sbrConfigData.noQmfBands /
+ hSbrElement->sbrConfigData.sampleFreq) +
+ 1) >>
+ 1;
+
+ for (band = 0; band < hSbrElement->sbrConfigData.num_Master; band++) {
+ if (cutoffSb == hSbrElement->sbrConfigData.v_k_master[band]) break;
+ }
+ FDK_ASSERT(band < hSbrElement->sbrConfigData.num_Master);
+
+ hSbrElement->sbrConfigData.dynXOverFreq = newXOver;
+ hSbrElement->sbrHeaderData.sbr_xover_band = band;
+ hSbrElement->sbrBitstreamData.HeaderActive = 1;
+ psHeaderActive = 1; /* ps header is one frame delayed */
+
+ /*
+ update vk_master table
+ */
+ if (updateFreqBandTable(&hSbrElement->sbrConfigData,
+ &hSbrElement->sbrHeaderData,
+ hEnvEncoder->downSampleFactor))
+ return (1);
+
+ /* reset SBR channels */
+ INT nEnvCh = hSbrElement->sbrConfigData.nChannels;
+ for (ch = 0; ch < nEnvCh; ch++) {
+ if (resetEnvChannel(&hSbrElement->sbrConfigData,
+ &hSbrElement->sbrHeaderData,
+ &hSbrElement->sbrChannel[ch]->hEnvChannel))
+ return (1);
+ }
+ }
+ }
+
+ /*
+ allocate space for dummy header and crc
+ */
+ crcReg = FDKsbrEnc_InitSbrBitstream(
+ &hSbrElement->CmonData,
+ hSbrElement->payloadDelayLine[hEnvEncoder->nBitstrDelay],
+ MAX_PAYLOAD_SIZE * sizeof(UCHAR), &crcInfo,
+ hSbrElement->sbrConfigData.sbrSyntaxFlags);
+
+ /* Temporal Envelope Data */
+ SBR_FRAME_TEMP_DATA _fData;
+ SBR_FRAME_TEMP_DATA *fData = &_fData;
+ SBR_ENV_TEMP_DATA eData[MAX_NUM_CHANNELS];
+
+ /* Init Temporal Envelope Data */
+ {
+ int i;
+
+ FDKmemclear(&eData[0], sizeof(SBR_ENV_TEMP_DATA));
+ FDKmemclear(&eData[1], sizeof(SBR_ENV_TEMP_DATA));
+ FDKmemclear(fData, sizeof(SBR_FRAME_TEMP_DATA));
+
+ for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) fData->res[i] = FREQ_RES_HIGH;
+ }
+
+ if (!clearOutput) {
+ /*
+ * Transform audio data into QMF domain
+ */
+ for (ch = 0; ch < hSbrElement->sbrConfigData.nChannels; ch++) {
+ HANDLE_ENV_CHANNEL h_envChan = &hSbrElement->sbrChannel[ch]->hEnvChannel;
+ HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &h_envChan->sbrExtractEnvelope;
+
+ if (hSbrElement->elInfo.fParametricStereo == 0) {
+ QMF_SCALE_FACTOR tmpScale;
+ FIXP_DBL **pQmfReal, **pQmfImag;
+ C_AALLOC_SCRATCH_START(qmfWorkBuffer, FIXP_DBL, 64 * 2)
+
+ /* Obtain pointers to QMF buffers. */
+ pQmfReal = sbrExtrEnv->rBuffer;
+ pQmfImag = sbrExtrEnv->iBuffer;
+
+ qmfAnalysisFiltering(
+ hSbrElement->hQmfAnalysis[ch], pQmfReal, pQmfImag, &tmpScale,
+ samples + hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize, 0,
+ 1, qmfWorkBuffer);
+
+ h_envChan->qmfScale = tmpScale.lb_scale + 7;
+
+ C_AALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, 64 * 2)
+
+ } /* fParametricStereo == 0 */
+
+ /*
+ Parametric Stereo processing
+ */
+ if (hSbrElement->elInfo.fParametricStereo) {
+ INT error = noError;
+
+ /* Limit Parametric Stereo to one instance */
+ FDK_ASSERT(ch == 0);
+
+ if (error == noError) {
+ /* parametric stereo processing:
+ - input:
+ o left and right time domain samples
+ - processing:
+ o stereo qmf analysis
+ o stereo hybrid analysis
+ o ps parameter extraction
+ o downmix + hybrid synthesis
+ - output:
+ o downmixed qmf data is written to sbrExtrEnv->rBuffer and
+ sbrExtrEnv->iBuffer
+ */
+ SCHAR qmfScale;
+ INT_PCM *pSamples[2] = {
+ samples + hSbrElement->elInfo.ChannelIndex[0] * samplesBufSize,
+ samples + hSbrElement->elInfo.ChannelIndex[1] * samplesBufSize};
+ error = FDKsbrEnc_PSEnc_ParametricStereoProcessing(
+ hEnvEncoder->hParametricStereo, pSamples, samplesBufSize,
+ hSbrElement->hQmfAnalysis, sbrExtrEnv->rBuffer,
+ sbrExtrEnv->iBuffer,
+ samples + hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize,
+ &hEnvEncoder->qmfSynthesisPS, &qmfScale, psHeaderActive);
+ h_envChan->qmfScale = (int)qmfScale;
+ }
+
+ } /* if (hEnvEncoder->hParametricStereo) */
+
+ /*
+
+ Extract Envelope relevant things from QMF data
+
+ */
+ FDKsbrEnc_extractSbrEnvelope1(&hSbrElement->sbrConfigData,
+ &hSbrElement->sbrHeaderData,
+ &hSbrElement->sbrBitstreamData, h_envChan,
+ &hSbrElement->CmonData, &eData[ch], fData);
+
+ } /* hEnvEncoder->sbrConfigData.nChannels */
+ }
+
+ /*
+ Process Envelope relevant things and calculate envelope data and write
+ payload
+ */
+ FDKsbrEnc_extractSbrEnvelope2(
+ &hSbrElement->sbrConfigData, &hSbrElement->sbrHeaderData,
+ (hSbrElement->elInfo.fParametricStereo) ? hEnvEncoder->hParametricStereo
+ : NULL,
+ &hSbrElement->sbrBitstreamData, &hSbrElement->sbrChannel[0]->hEnvChannel,
+ (hSbrElement->sbrConfigData.stereoMode != SBR_MONO)
+ ? &hSbrElement->sbrChannel[1]->hEnvChannel
+ : NULL,
+ &hSbrElement->CmonData, eData, fData, clearOutput);
+
+ hSbrElement->sbrBitstreamData.rightBorderFIX = 0;
+
+ /*
+ format payload, calculate crc
+ */
+ FDKsbrEnc_AssembleSbrBitstream(&hSbrElement->CmonData, &crcInfo, crcReg,
+ hSbrElement->sbrConfigData.sbrSyntaxFlags);
+
+ /*
+ save new payload, set to zero length if greater than MAX_PAYLOAD_SIZE
+ */
+ hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay] =
+ FDKgetValidBits(&hSbrElement->CmonData.sbrBitbuf);
+
+ if (hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay] >
+ (MAX_PAYLOAD_SIZE << 3))
+ hSbrElement->payloadDelayLineSize[hEnvEncoder->nBitstrDelay] = 0;
+
+ /* While filling the Delay lines, sbrData is NULL */
+ if (sbrData) {
+ *sbrDataBits = hSbrElement->payloadDelayLineSize[0];
+ FDKmemcpy(sbrData, hSbrElement->payloadDelayLine[0],
+ (hSbrElement->payloadDelayLineSize[0] + 7) >> 3);
+ }
+
+ /* delay header active flag */
+ if (hSbrElement->sbrBitstreamData.HeaderActive == 1) {
+ hSbrElement->sbrBitstreamData.HeaderActiveDelay =
+ 1 + hEnvEncoder->nBitstrDelay;
+ } else {
+ if (hSbrElement->sbrBitstreamData.HeaderActiveDelay > 0) {
+ hSbrElement->sbrBitstreamData.HeaderActiveDelay--;
+ }
+ }
+
+ return (0);
+}
+
+/*****************************************************************************
+
+ functionname: FDKsbrEnc_Downsample
+ description: performs downsampling and delay compensation of the core path
+ returns:
+ input:
+ output:
+
+*****************************************************************************/
+INT FDKsbrEnc_Downsample(
+ HANDLE_SBR_ENCODER hSbrEncoder,
+ INT_PCM *samples, /*!< time samples, always deinterleaved */
+ UINT samplesBufSize, /*!< time buffer size per channel */
+ UINT numChannels, /*!< number of channels */
+ UINT *sbrDataBits, /*!< Size of SBR payload */
+ UCHAR *sbrData, /*!< SBR payload */
+ int clearOutput /*!< Do not consider any input signal */
+) {
+ HANDLE_SBR_ELEMENT hSbrElement = NULL;
+ INT nOutSamples;
+ int el;
+ if (hSbrEncoder->downSampleFactor > 1) {
+ /* Do downsampling */
+
+ /* Loop over elements (LFE is handled later) */
+ for (el = 0; el < hSbrEncoder->noElements; el++) {
+ hSbrElement = hSbrEncoder->sbrElement[el];
+ if (hSbrEncoder->sbrElement[el] != NULL) {
+ if (hSbrEncoder->downsamplingMethod == SBRENC_DS_TIME) {
+ int ch;
+ int nChannels = hSbrElement->sbrConfigData.nChannels;
+
+ for (ch = 0; ch < nChannels; ch++) {
+ FDKaacEnc_Downsample(
+ &hSbrElement->sbrChannel[ch]->downSampler,
+ samples +
+ hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize +
+ hSbrEncoder->bufferOffset / numChannels,
+ hSbrElement->sbrConfigData.frameSize,
+ samples + hSbrElement->elInfo.ChannelIndex[ch] * samplesBufSize,
+ &nOutSamples);
+ }
+ }
+ }
+ }
+
+ /* Handle LFE (if existing) */
+ if (hSbrEncoder->lfeChIdx != -1) { /* lfe downsampler */
+ FDKaacEnc_Downsample(&hSbrEncoder->lfeDownSampler,
+ samples + hSbrEncoder->lfeChIdx * samplesBufSize +
+ hSbrEncoder->bufferOffset / numChannels,
+ hSbrEncoder->frameSize,
+ samples + hSbrEncoder->lfeChIdx * samplesBufSize,
+ &nOutSamples);
+ }
+ } else {
+ /* No downsampling. Still, some buffer shifting for correct delay */
+ int samples2Copy = hSbrEncoder->frameSize;
+ if (hSbrEncoder->bufferOffset / (int)numChannels < samples2Copy) {
+ for (int c = 0; c < (int)numChannels; c++) {
+ /* Do memmove while taking care of overlapping memory areas. (memcpy
+ does not necessarily take care) Distinguish between oeverlapping and
+ non overlapping version due to reasons of complexity. */
+ FDKmemmove(samples + c * samplesBufSize,
+ samples + c * samplesBufSize +
+ hSbrEncoder->bufferOffset / numChannels,
+ samples2Copy * sizeof(INT_PCM));
+ }
+ } else {
+ for (int c = 0; c < (int)numChannels; c++) {
+ /* Simple memcpy since the memory areas are not overlapping */
+ FDKmemcpy(samples + c * samplesBufSize,
+ samples + c * samplesBufSize +
+ hSbrEncoder->bufferOffset / numChannels,
+ samples2Copy * sizeof(INT_PCM));
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+
+ functionname: createEnvChannel
+ description: initializes parameters and allocates memory
+ returns: error status
+ input:
+ output: hEnv
+
+*****************************************************************************/
+
+static INT createEnvChannel(HANDLE_ENV_CHANNEL hEnv, INT channel,
+ UCHAR *dynamic_RAM) {
+ FDKmemclear(hEnv, sizeof(struct ENV_CHANNEL));
+
+ if (FDKsbrEnc_CreateTonCorrParamExtr(&hEnv->TonCorr, channel)) {
+ return (1);
+ }
+
+ if (FDKsbrEnc_CreateExtractSbrEnvelope(&hEnv->sbrExtractEnvelope, channel,
+ /*chan*/ 0, dynamic_RAM)) {
+ return (1);
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+
+ functionname: initEnvChannel
+ description: initializes parameters
+ returns: error status
+ input:
+ output:
+
+*****************************************************************************/
+static INT initEnvChannel(HANDLE_SBR_CONFIG_DATA sbrConfigData,
+ HANDLE_SBR_HEADER_DATA sbrHeaderData,
+ HANDLE_ENV_CHANNEL hEnv, sbrConfigurationPtr params,
+ ULONG statesInitFlag, INT chanInEl,
+ UCHAR *dynamic_RAM) {
+ int frameShift, tran_off = 0;
+ INT e;
+ INT tran_fc;
+ INT timeSlots, timeStep, startIndex;
+ INT noiseBands[2] = {3, 3};
+
+ e = 1 << params->e;
+
+ FDK_ASSERT(params->e >= 0);
+
+ hEnv->encEnvData.freq_res_fixfix[0] = params->freq_res_fixfix[0];
+ hEnv->encEnvData.freq_res_fixfix[1] = params->freq_res_fixfix[1];
+ hEnv->encEnvData.fResTransIsLow = params->fResTransIsLow;
+
+ hEnv->fLevelProtect = 0;
+
+ hEnv->encEnvData.ldGrid =
+ (sbrConfigData->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) ? 1 : 0;
+
+ hEnv->encEnvData.sbr_xpos_mode = (XPOS_MODE)params->sbr_xpos_mode;
+
+ if (hEnv->encEnvData.sbr_xpos_mode == XPOS_SWITCHED) {
+ /*
+ no other type than XPOS_MDCT or XPOS_SPEECH allowed,
+ but enable switching
+ */
+ sbrConfigData->switchTransposers = TRUE;
+ hEnv->encEnvData.sbr_xpos_mode = XPOS_MDCT;
+ } else {
+ sbrConfigData->switchTransposers = FALSE;
+ }
+
+ hEnv->encEnvData.sbr_xpos_ctrl = params->sbr_xpos_ctrl;
+
+ /* extended data */
+ if (params->parametricCoding) {
+ hEnv->encEnvData.extended_data = 1;
+ } else {
+ hEnv->encEnvData.extended_data = 0;
+ }
+
+ hEnv->encEnvData.extension_size = 0;
+
+ startIndex = QMF_FILTER_PROTOTYPE_SIZE - sbrConfigData->noQmfBands;
+
+ switch (params->sbrFrameSize) {
+ case 2304:
+ timeSlots = 18;
+ break;
+ case 2048:
+ case 1024:
+ case 512:
+ timeSlots = 16;
+ break;
+ case 1920:
+ case 960:
+ case 480:
+ timeSlots = 15;
+ break;
+ case 1152:
+ timeSlots = 9;
+ break;
+ default:
+ return (1); /* Illegal frame size */
+ }
+
+ timeStep = sbrConfigData->noQmfSlots / timeSlots;
+
+ if (FDKsbrEnc_InitTonCorrParamExtr(
+ params->sbrFrameSize, &hEnv->TonCorr, sbrConfigData, timeSlots,
+ params->sbr_xpos_ctrl, params->ana_max_level,
+ sbrHeaderData->sbr_noise_bands, params->noiseFloorOffset,
+ params->useSpeechConfig))
+ return (1);
+
+ hEnv->encEnvData.noOfnoisebands =
+ hEnv->TonCorr.sbrNoiseFloorEstimate.noNoiseBands;
+
+ noiseBands[0] = hEnv->encEnvData.noOfnoisebands;
+ noiseBands[1] = hEnv->encEnvData.noOfnoisebands;
+
+ hEnv->encEnvData.sbr_invf_mode = (INVF_MODE)params->sbr_invf_mode;
+
+ if (hEnv->encEnvData.sbr_invf_mode == INVF_SWITCHED) {
+ hEnv->encEnvData.sbr_invf_mode = INVF_MID_LEVEL;
+ hEnv->TonCorr.switchInverseFilt = TRUE;
+ } else {
+ hEnv->TonCorr.switchInverseFilt = FALSE;
+ }
+
+ tran_fc = params->tran_fc;
+
+ if (tran_fc == 0) {
+ tran_fc = fixMin(
+ 5000, FDKsbrEnc_getSbrStartFreqRAW(sbrHeaderData->sbr_start_frequency,
+ params->codecSettings.sampleFreq));
+ }
+
+ tran_fc =
+ (tran_fc * 4 * sbrConfigData->noQmfBands / sbrConfigData->sampleFreq +
+ 1) >>
+ 1;
+
+ if (sbrConfigData->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) {
+ frameShift = LD_PRETRAN_OFF;
+ tran_off = LD_PRETRAN_OFF + FRAME_MIDDLE_SLOT_512LD * timeStep;
+ } else {
+ frameShift = 0;
+ switch (timeSlots) {
+ /* The factor of 2 is by definition. */
+ case NUMBER_TIME_SLOTS_2048:
+ tran_off = 8 + FRAME_MIDDLE_SLOT_2048 * timeStep;
+ break;
+ case NUMBER_TIME_SLOTS_1920:
+ tran_off = 7 + FRAME_MIDDLE_SLOT_1920 * timeStep;
+ break;
+ default:
+ return 1;
+ }
+ }
+ if (FDKsbrEnc_InitExtractSbrEnvelope(
+ &hEnv->sbrExtractEnvelope, sbrConfigData->noQmfSlots,
+ sbrConfigData->noQmfBands, startIndex, timeSlots, timeStep, tran_off,
+ statesInitFlag, chanInEl, dynamic_RAM, sbrConfigData->sbrSyntaxFlags))
+ return (1);
+
+ if (FDKsbrEnc_InitSbrCodeEnvelope(&hEnv->sbrCodeEnvelope, sbrConfigData->nSfb,
+ params->deltaTAcrossFrames,
+ params->dF_edge_1stEnv,
+ params->dF_edge_incr))
+ return (1);
+
+ if (FDKsbrEnc_InitSbrCodeEnvelope(&hEnv->sbrCodeNoiseFloor, noiseBands,
+ params->deltaTAcrossFrames, 0, 0))
+ return (1);
+
+ sbrConfigData->initAmpResFF = params->init_amp_res_FF;
+
+ if (FDKsbrEnc_InitSbrHuffmanTables(&hEnv->encEnvData, &hEnv->sbrCodeEnvelope,
+ &hEnv->sbrCodeNoiseFloor,
+ sbrHeaderData->sbr_amp_res))
+ return (1);
+
+ FDKsbrEnc_initFrameInfoGenerator(
+ &hEnv->SbrEnvFrame, params->spread, e, params->stat, timeSlots,
+ hEnv->encEnvData.freq_res_fixfix, hEnv->encEnvData.fResTransIsLow,
+ hEnv->encEnvData.ldGrid);
+
+ if (sbrConfigData->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY)
+
+ {
+ INT bandwidth_qmf_slot =
+ (sbrConfigData->sampleFreq >> 1) / (sbrConfigData->noQmfBands);
+ if (FDKsbrEnc_InitSbrFastTransientDetector(
+ &hEnv->sbrFastTransientDetector, sbrConfigData->noQmfSlots,
+ bandwidth_qmf_slot, sbrConfigData->noQmfBands,
+ sbrConfigData->freqBandTable[0][0]))
+ return (1);
+ }
+
+ /* The transient detector has to be initialized also if the fast transient
+ detector was active, because the values from the transient detector
+ structure are used. */
+ if (FDKsbrEnc_InitSbrTransientDetector(
+ &hEnv->sbrTransientDetector, sbrConfigData->sbrSyntaxFlags,
+ sbrConfigData->frameSize, sbrConfigData->sampleFreq, params, tran_fc,
+ sbrConfigData->noQmfSlots, sbrConfigData->noQmfBands,
+ hEnv->sbrExtractEnvelope.YBufferWriteOffset,
+ hEnv->sbrExtractEnvelope.YBufferSzShift, frameShift, tran_off))
+ return (1);
+
+ sbrConfigData->xposCtrlSwitch = params->sbr_xpos_ctrl;
+
+ hEnv->encEnvData.noHarmonics = sbrConfigData->nSfb[HI];
+ hEnv->encEnvData.addHarmonicFlag = 0;
+
+ return (0);
+}
+
+INT sbrEncoder_Open(HANDLE_SBR_ENCODER *phSbrEncoder, INT nElements,
+ INT nChannels, INT supportPS) {
+ INT i;
+ INT errorStatus = 1;
+ HANDLE_SBR_ENCODER hSbrEncoder = NULL;
+
+ if (phSbrEncoder == NULL) {
+ goto bail;
+ }
+
+ hSbrEncoder = GetRam_SbrEncoder();
+ if (hSbrEncoder == NULL) {
+ goto bail;
+ }
+ FDKmemclear(hSbrEncoder, sizeof(SBR_ENCODER));
+
+ if (NULL ==
+ (hSbrEncoder->pSBRdynamic_RAM = (UCHAR *)GetRam_SbrDynamic_RAM())) {
+ goto bail;
+ }
+ hSbrEncoder->dynamicRam = hSbrEncoder->pSBRdynamic_RAM;
+
+ /* Create SBR elements */
+ for (i = 0; i < nElements; i++) {
+ hSbrEncoder->sbrElement[i] = GetRam_SbrElement(i);
+ if (hSbrEncoder->sbrElement[i] == NULL) {
+ goto bail;
+ }
+ FDKmemclear(hSbrEncoder->sbrElement[i], sizeof(SBR_ELEMENT));
+ hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[LO] =
+ GetRam_Sbr_freqBandTableLO(i);
+ hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[HI] =
+ GetRam_Sbr_freqBandTableHI(i);
+ hSbrEncoder->sbrElement[i]->sbrConfigData.v_k_master =
+ GetRam_Sbr_v_k_master(i);
+ if ((hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[LO] == NULL) ||
+ (hSbrEncoder->sbrElement[i]->sbrConfigData.freqBandTable[HI] == NULL) ||
+ (hSbrEncoder->sbrElement[i]->sbrConfigData.v_k_master == NULL)) {
+ goto bail;
+ }
+ }
+
+ /* Create SBR channels */
+ for (i = 0; i < nChannels; i++) {
+ hSbrEncoder->pSbrChannel[i] = GetRam_SbrChannel(i);
+ if (hSbrEncoder->pSbrChannel[i] == NULL) {
+ goto bail;
+ }
+
+ if (createEnvChannel(&hSbrEncoder->pSbrChannel[i]->hEnvChannel, i,
+ hSbrEncoder->dynamicRam)) {
+ goto bail;
+ }
+ }
+
+ /* Create QMF States */
+ for (i = 0; i < fixMax(nChannels, (supportPS) ? 2 : 0); i++) {
+ hSbrEncoder->QmfAnalysis[i].FilterStates = GetRam_Sbr_QmfStatesAnalysis(i);
+ if (hSbrEncoder->QmfAnalysis[i].FilterStates == NULL) {
+ goto bail;
+ }
+ }
+
+ /* Create Parametric Stereo handle */
+ if (supportPS) {
+ if (PSEnc_Create(&hSbrEncoder->hParametricStereo)) {
+ goto bail;
+ }
+
+ hSbrEncoder->qmfSynthesisPS.FilterStates = GetRam_PsQmfStatesSynthesis();
+ if (hSbrEncoder->qmfSynthesisPS.FilterStates == NULL) {
+ goto bail;
+ }
+ } /* supportPS */
+
+ *phSbrEncoder = hSbrEncoder;
+
+ errorStatus = 0;
+ return errorStatus;
+
+bail:
+ /* Close SBR encoder instance */
+ sbrEncoder_Close(&hSbrEncoder);
+ return errorStatus;
+}
+
+static INT FDKsbrEnc_Reallocate(HANDLE_SBR_ENCODER hSbrEncoder,
+ SBR_ELEMENT_INFO elInfo[(8)],
+ const INT noElements) {
+ INT totalCh = 0;
+ INT totalQmf = 0;
+ INT coreEl;
+ INT el = -1;
+
+ hSbrEncoder->lfeChIdx = -1; /* default value, until lfe found */
+
+ for (coreEl = 0; coreEl < noElements; coreEl++) {
+ /* SBR only handles SCE and CPE's */
+ if (elInfo[coreEl].elType == ID_SCE || elInfo[coreEl].elType == ID_CPE) {
+ el++;
+ } else {
+ if (elInfo[coreEl].elType == ID_LFE) {
+ hSbrEncoder->lfeChIdx = elInfo[coreEl].ChannelIndex[0];
+ }
+ continue;
+ }
+
+ SBR_ELEMENT_INFO *pelInfo = &elInfo[coreEl];
+ HANDLE_SBR_ELEMENT hSbrElement = hSbrEncoder->sbrElement[el];
+
+ int ch;
+ for (ch = 0; ch < pelInfo->nChannelsInEl; ch++) {
+ hSbrElement->sbrChannel[ch] = hSbrEncoder->pSbrChannel[totalCh];
+ totalCh++;
+ }
+ /* analysis QMF */
+ for (ch = 0;
+ ch < ((pelInfo->fParametricStereo) ? 2 : pelInfo->nChannelsInEl);
+ ch++) {
+ hSbrElement->elInfo.ChannelIndex[ch] = pelInfo->ChannelIndex[ch];
+ hSbrElement->hQmfAnalysis[ch] = &hSbrEncoder->QmfAnalysis[totalQmf++];
+ }
+
+ /* Copy Element info */
+ hSbrElement->elInfo.elType = pelInfo->elType;
+ hSbrElement->elInfo.instanceTag = pelInfo->instanceTag;
+ hSbrElement->elInfo.nChannelsInEl = pelInfo->nChannelsInEl;
+ hSbrElement->elInfo.fParametricStereo = pelInfo->fParametricStereo;
+ hSbrElement->elInfo.fDualMono = pelInfo->fDualMono;
+ } /* coreEl */
+
+ return 0;
+}
+
+/*****************************************************************************
+
+ functionname: FDKsbrEnc_bsBufInit
+ description: initializes bitstream buffer
+ returns: initialized bitstream buffer in env encoder
+ input:
+ output: hEnv
+
+*****************************************************************************/
+static INT FDKsbrEnc_bsBufInit(HANDLE_SBR_ELEMENT hSbrElement,
+ int nBitstrDelay) {
+ UCHAR *bitstreamBuffer;
+
+ /* initialize the bitstream buffer */
+ bitstreamBuffer = hSbrElement->payloadDelayLine[nBitstrDelay];
+ FDKinitBitStream(&hSbrElement->CmonData.sbrBitbuf, bitstreamBuffer,
+ MAX_PAYLOAD_SIZE * sizeof(UCHAR), 0, BS_WRITER);
+
+ return (0);
+}
+
+/*****************************************************************************
+
+ functionname: FDKsbrEnc_EnvInit
+ description: initializes parameters
+ returns: error status
+ input:
+ output: hEnv
+
+*****************************************************************************/
+static INT FDKsbrEnc_EnvInit(HANDLE_SBR_ELEMENT hSbrElement,
+ sbrConfigurationPtr params, INT *coreBandWith,
+ AUDIO_OBJECT_TYPE aot, int nElement,
+ const int headerPeriod, ULONG statesInitFlag,
+ const SBRENC_DS_TYPE downsamplingMethod,
+ UCHAR *dynamic_RAM) {
+ int ch, i;
+
+ if ((params->codecSettings.nChannels < 1) ||
+ (params->codecSettings.nChannels > MAX_NUM_CHANNELS)) {
+ return (1);
+ }
+
+ /* init and set syntax flags */
+ hSbrElement->sbrConfigData.sbrSyntaxFlags = 0;
+
+ switch (aot) {
+ case AOT_ER_AAC_ELD:
+ hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_LOW_DELAY;
+ break;
+ default:
+ break;
+ }
+ if (params->crcSbr) {
+ hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_CRC;
+ }
+
+ hSbrElement->sbrConfigData.noQmfBands = 64 >> (2 - params->downSampleFactor);
+ switch (hSbrElement->sbrConfigData.noQmfBands) {
+ case 64:
+ hSbrElement->sbrConfigData.noQmfSlots = params->sbrFrameSize >> 6;
+ break;
+ case 32:
+ hSbrElement->sbrConfigData.noQmfSlots = params->sbrFrameSize >> 5;
+ break;
+ default:
+ hSbrElement->sbrConfigData.noQmfSlots = params->sbrFrameSize >> 6;
+ return (2);
+ }
+
+ /*
+ now initialize sbrConfigData, sbrHeaderData and sbrBitstreamData,
+ */
+ hSbrElement->sbrConfigData.nChannels = params->codecSettings.nChannels;
+
+ if (params->codecSettings.nChannels == 2) {
+ if ((hSbrElement->elInfo.elType == ID_CPE) &&
+ ((hSbrElement->elInfo.fDualMono == 1))) {
+ hSbrElement->sbrConfigData.stereoMode = SBR_LEFT_RIGHT;
+ } else {
+ hSbrElement->sbrConfigData.stereoMode = params->stereoMode;
+ }
+ } else {
+ hSbrElement->sbrConfigData.stereoMode = SBR_MONO;
+ }
+
+ hSbrElement->sbrConfigData.frameSize = params->sbrFrameSize;
+
+ hSbrElement->sbrConfigData.sampleFreq =
+ params->downSampleFactor * params->codecSettings.sampleFreq;
+
+ hSbrElement->sbrBitstreamData.CountSendHeaderData = 0;
+ if (params->SendHeaderDataTime > 0) {
+ if (headerPeriod == -1) {
+ hSbrElement->sbrBitstreamData.NrSendHeaderData = (INT)(
+ params->SendHeaderDataTime * hSbrElement->sbrConfigData.sampleFreq /
+ (1000 * hSbrElement->sbrConfigData.frameSize));
+ hSbrElement->sbrBitstreamData.NrSendHeaderData =
+ fixMax(hSbrElement->sbrBitstreamData.NrSendHeaderData, 1);
+ } else {
+ /* assure header period at least once per second */
+ hSbrElement->sbrBitstreamData.NrSendHeaderData = fixMin(
+ fixMax(headerPeriod, 1), (hSbrElement->sbrConfigData.sampleFreq /
+ hSbrElement->sbrConfigData.frameSize));
+ }
+ } else {
+ hSbrElement->sbrBitstreamData.NrSendHeaderData = 0;
+ }
+
+ hSbrElement->sbrHeaderData.sbr_data_extra = params->sbr_data_extra;
+ hSbrElement->sbrBitstreamData.HeaderActive = 0;
+ hSbrElement->sbrBitstreamData.rightBorderFIX = 0;
+ hSbrElement->sbrHeaderData.sbr_start_frequency = params->startFreq;
+ hSbrElement->sbrHeaderData.sbr_stop_frequency = params->stopFreq;
+ hSbrElement->sbrHeaderData.sbr_xover_band = 0;
+ hSbrElement->sbrHeaderData.sbr_lc_stereo_mode = 0;
+
+ /* data_extra */
+ if (params->sbr_xpos_ctrl != SBR_XPOS_CTRL_DEFAULT)
+ hSbrElement->sbrHeaderData.sbr_data_extra = 1;
+
+ hSbrElement->sbrHeaderData.sbr_amp_res = (AMP_RES)params->amp_res;
+
+ /* header_extra_1 */
+ hSbrElement->sbrHeaderData.freqScale = params->freqScale;
+ hSbrElement->sbrHeaderData.alterScale = params->alterScale;
+ hSbrElement->sbrHeaderData.sbr_noise_bands = params->sbr_noise_bands;
+ hSbrElement->sbrHeaderData.header_extra_1 = 0;
+
+ if ((params->freqScale != SBR_FREQ_SCALE_DEFAULT) ||
+ (params->alterScale != SBR_ALTER_SCALE_DEFAULT) ||
+ (params->sbr_noise_bands != SBR_NOISE_BANDS_DEFAULT)) {
+ hSbrElement->sbrHeaderData.header_extra_1 = 1;
+ }
+
+ /* header_extra_2 */
+ hSbrElement->sbrHeaderData.sbr_limiter_bands = params->sbr_limiter_bands;
+ hSbrElement->sbrHeaderData.sbr_limiter_gains = params->sbr_limiter_gains;
+
+ if ((hSbrElement->sbrConfigData.sampleFreq > 48000) &&
+ (hSbrElement->sbrHeaderData.sbr_start_frequency >= 9)) {
+ hSbrElement->sbrHeaderData.sbr_limiter_gains = SBR_LIMITER_GAINS_INFINITE;
+ }
+
+ hSbrElement->sbrHeaderData.sbr_interpol_freq = params->sbr_interpol_freq;
+ hSbrElement->sbrHeaderData.sbr_smoothing_length =
+ params->sbr_smoothing_length;
+ hSbrElement->sbrHeaderData.header_extra_2 = 0;
+
+ if ((params->sbr_limiter_bands != SBR_LIMITER_BANDS_DEFAULT) ||
+ (params->sbr_limiter_gains != SBR_LIMITER_GAINS_DEFAULT) ||
+ (params->sbr_interpol_freq != SBR_INTERPOL_FREQ_DEFAULT) ||
+ (params->sbr_smoothing_length != SBR_SMOOTHING_LENGTH_DEFAULT)) {
+ hSbrElement->sbrHeaderData.header_extra_2 = 1;
+ }
+
+ /* other switches */
+ hSbrElement->sbrConfigData.useWaveCoding = params->useWaveCoding;
+ hSbrElement->sbrConfigData.useParametricCoding = params->parametricCoding;
+ hSbrElement->sbrConfigData.thresholdAmpResFF_m =
+ params->threshold_AmpRes_FF_m;
+ hSbrElement->sbrConfigData.thresholdAmpResFF_e =
+ params->threshold_AmpRes_FF_e;
+
+ /* init freq band table */
+ if (updateFreqBandTable(&hSbrElement->sbrConfigData,
+ &hSbrElement->sbrHeaderData,
+ params->downSampleFactor)) {
+ return (1);
+ }
+
+ /* now create envelope ext and QMF for each available channel */
+ for (ch = 0; ch < hSbrElement->sbrConfigData.nChannels; ch++) {
+ if (initEnvChannel(&hSbrElement->sbrConfigData, &hSbrElement->sbrHeaderData,
+ &hSbrElement->sbrChannel[ch]->hEnvChannel, params,
+ statesInitFlag, ch, dynamic_RAM)) {
+ return (1);
+ }
+
+ } /* nChannels */
+
+ /* reset and intialize analysis qmf */
+ for (ch = 0; ch < ((hSbrElement->elInfo.fParametricStereo)
+ ? 2
+ : hSbrElement->sbrConfigData.nChannels);
+ ch++) {
+ int err;
+ UINT qmfFlags =
+ (hSbrElement->sbrConfigData.sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY)
+ ? QMF_FLAG_CLDFB
+ : 0;
+ if (statesInitFlag)
+ qmfFlags &= ~QMF_FLAG_KEEP_STATES;
+ else
+ qmfFlags |= QMF_FLAG_KEEP_STATES;
+
+ err = qmfInitAnalysisFilterBank(
+ hSbrElement->hQmfAnalysis[ch],
+ (FIXP_QAS *)hSbrElement->hQmfAnalysis[ch]->FilterStates,
+ hSbrElement->sbrConfigData.noQmfSlots,
+ hSbrElement->sbrConfigData.noQmfBands,
+ hSbrElement->sbrConfigData.noQmfBands,
+ hSbrElement->sbrConfigData.noQmfBands, qmfFlags);
+ if (0 != err) {
+ return err;
+ }
+ }
+
+ /* */
+ hSbrElement->CmonData.xOverFreq = hSbrElement->sbrConfigData.xOverFreq;
+ hSbrElement->CmonData.dynBwEnabled =
+ (params->dynBwSupported && params->dynBwEnabled);
+ hSbrElement->CmonData.dynXOverFreqEnc =
+ FDKsbrEnc_SbrGetXOverFreq(hSbrElement, hSbrElement->CmonData.xOverFreq);
+ for (i = 0; i < 5; i++)
+ hSbrElement->dynXOverFreqDelay[i] = hSbrElement->CmonData.dynXOverFreqEnc;
+ hSbrElement->CmonData.sbrNumChannels = hSbrElement->sbrConfigData.nChannels;
+ hSbrElement->sbrConfigData.dynXOverFreq = hSbrElement->CmonData.xOverFreq;
+
+ /* Update Bandwith to be passed to the core encoder */
+ *coreBandWith = hSbrElement->CmonData.xOverFreq;
+
+ return (0);
+}
+
+INT sbrEncoder_GetInBufferSize(int noChannels) {
+ INT temp;
+
+ temp = (2048);
+ temp += 1024 + MAX_SAMPLE_DELAY;
+ temp *= noChannels;
+ temp *= sizeof(INT_PCM);
+ return temp;
+}
+
+/*
+ * Encode Dummy SBR payload frames to fill the delay lines.
+ */
+static INT FDKsbrEnc_DelayCompensation(HANDLE_SBR_ENCODER hEnvEnc,
+ INT_PCM *timeBuffer,
+ UINT timeBufferBufSize) {
+ int n, el;
+
+ for (n = hEnvEnc->nBitstrDelay; n > 0; n--) {
+ for (el = 0; el < hEnvEnc->noElements; el++) {
+ if (FDKsbrEnc_EnvEncodeFrame(
+ hEnvEnc, el,
+ timeBuffer + hEnvEnc->downsampledOffset / hEnvEnc->nChannels,
+ timeBufferBufSize, NULL, NULL, 1))
+ return -1;
+ }
+ sbrEncoder_UpdateBuffers(hEnvEnc, timeBuffer, timeBufferBufSize);
+ }
+ return 0;
+}
+
+UINT sbrEncoder_LimitBitRate(UINT bitRate, UINT numChannels,
+ UINT coreSampleRate, AUDIO_OBJECT_TYPE aot) {
+ UINT newBitRate = bitRate;
+ INT index;
+
+ FDK_ASSERT(numChannels > 0 && numChannels <= 2);
+ if (aot == AOT_PS) {
+ if (numChannels == 1) {
+ index = getPsTuningTableIndex(bitRate, &newBitRate);
+ if (index == INVALID_TABLE_IDX) {
+ bitRate = newBitRate;
+ }
+ } else {
+ return 0;
+ }
+ }
+ index = getSbrTuningTableIndex(bitRate, numChannels, coreSampleRate, aot,
+ &newBitRate);
+ if (index != INVALID_TABLE_IDX) {
+ newBitRate = bitRate;
+ }
+
+ return newBitRate;
+}
+
+UINT sbrEncoder_IsSingleRatePossible(AUDIO_OBJECT_TYPE aot) {
+ UINT isPossible = (AOT_PS == aot) ? 0 : 1;
+ return isPossible;
+}
+
+/*****************************************************************************/
+/* */
+/*functionname: sbrEncoder_Init_delay */
+/*description: Determine Delay balancing and new encoder delay */
+/* */
+/*returns: - error status */
+/*input: - frame length of the core (i.e. e.g. AAC) */
+/* - number of channels */
+/* - downsample factor (1 for downsampled, 2 for dual-rate SBR) */
+/* - low delay presence */
+/* - ps presence */
+/* - downsampling method: QMF-, time domain or no downsampling */
+/* - various delay values (see DELAY_PARAM struct description) */
+/* */
+/*Example: Delay balancing for a HE-AACv1 encoder (time-domain downsampling) */
+/*========================================================================== */
+/* */
+/* +--------+ +--------+ +--------+ +--------+ +--------+ */
+/* |core | |ds 2:1 | |AAC | |QMF | |QMF | */
+/* +-+path +------------+ +-+core +-+analysis+-+overlap +-+ */
+/* | |offset | | | | | |32 bands| | | | */
+/* | +--------+ +--------+ +--------+ +--------+ +--------+ | */
+/* | core path +-------++ */
+/* | |QMF | */
+/*->+ +synth. +-> */
+/* | |64 bands| */
+/* | +-------++ */
+/* | +--------+ +--------+ +--------+ +--------+ | */
+/* | |SBR path| |QMF | |subband | |bs delay| | */
+/* +-+offset +-+analysis+-+sample +-+(full +-----------------------+ */
+/* | | |64 bands| |buffer | | frames)| */
+/* +--------+ +--------+ +--------+ +--------+ */
+/* SBR path */
+/* */
+/*****************************************************************************/
+static INT sbrEncoder_Init_delay(
+ const int coreFrameLength, /* input */
+ const int numChannels, /* input */
+ const int downSampleFactor, /* input */
+ const int lowDelay, /* input */
+ const int usePs, /* input */
+ const int is212, /* input */
+ const SBRENC_DS_TYPE downsamplingMethod, /* input */
+ DELAY_PARAM *hDelayParam /* input/output */
+) {
+ int delayCorePath = 0; /* delay in core path */
+ int delaySbrPath = 0; /* delay difference in QMF aka SBR path */
+ int delayInput2Core = 0; /* delay from the input to the core */
+ int delaySbrDec = 0; /* delay of the decoder's SBR module */
+
+ int delayCore = hDelayParam->delay; /* delay of the core */
+
+ /* Added delay by the SBR delay initialization */
+ int corePathOffset = 0; /* core path */
+ int sbrPathOffset = 0; /* sbr path */
+ int bitstreamDelay = 0; /* sbr path, framewise */
+
+ int flCore = coreFrameLength; /* core frame length */
+
+ int returnValue = 0; /* return value - 0 means: no error */
+
+ /* 1) Calculate actual delay for core and SBR path */
+ if (is212) {
+ delayCorePath = DELAY_COREPATH_ELDv2SBR(flCore, downSampleFactor);
+ delaySbrPath = DELAY_ELDv2SBR(flCore, downSampleFactor);
+ delaySbrDec = ((flCore) / 2) * (downSampleFactor);
+ } else if (lowDelay) {
+ delayCorePath = DELAY_COREPATH_ELDSBR(flCore, downSampleFactor);
+ delaySbrPath = DELAY_ELDSBR(flCore, downSampleFactor);
+ delaySbrDec = DELAY_QMF_POSTPROC(downSampleFactor);
+ } else if (usePs) {
+ delayCorePath = DELAY_COREPATH_PS(flCore, downSampleFactor);
+ delaySbrPath = DELAY_PS(flCore, downSampleFactor);
+ delaySbrDec = DELAY_COREPATH_SBR(flCore, downSampleFactor);
+ } else {
+ delayCorePath = DELAY_COREPATH_SBR(flCore, downSampleFactor);
+ delaySbrPath = DELAY_SBR(flCore, downSampleFactor);
+ delaySbrDec = DELAY_COREPATH_SBR(flCore, downSampleFactor);
+ }
+ delayCorePath += delayCore * downSampleFactor;
+ delayCorePath +=
+ (downsamplingMethod == SBRENC_DS_TIME) ? hDelayParam->dsDelay : 0;
+
+ /* 2) Manage coupling of paths */
+ if (downsamplingMethod == SBRENC_DS_QMF && delayCorePath > delaySbrPath) {
+ /* In case of QMF downsampling, both paths are coupled, i.e. the SBR path
+ offset would be added to both the SBR path and to the core path
+ as well, thus making it impossible to achieve delay balancing.
+ To overcome that problem, a framewise delay is added to the SBR path
+ first, until the overall delay of the core path is shorter than
+ the delay of the SBR path. When this is achieved, the missing delay
+ difference can be added as downsampled offset to the core path.
+ */
+ while (delayCorePath > delaySbrPath) {
+ /* Add one frame delay to SBR path */
+ delaySbrPath += flCore * downSampleFactor;
+ bitstreamDelay += 1;
+ }
+ }
+
+ /* 3) Calculate necessary additional delay to balance the paths */
+ if (delayCorePath > delaySbrPath) {
+ /* Delay QMF input */
+ while (delayCorePath > delaySbrPath + (int)flCore * (int)downSampleFactor) {
+ /* Do bitstream frame-wise delay balancing if there are
+ more than SBR framelength samples delay difference */
+ delaySbrPath += flCore * downSampleFactor;
+ bitstreamDelay += 1;
+ }
+ /* Multiply input offset by input channels */
+ corePathOffset = 0;
+ sbrPathOffset = (delayCorePath - delaySbrPath) * numChannels;
+ } else {
+ /* Delay AAC data */
+ /* Multiply downsampled offset by AAC core channels. Divide by 2 because of
+ half samplerate of downsampled data. */
+ corePathOffset = ((delaySbrPath - delayCorePath) * numChannels) >>
+ (downSampleFactor - 1);
+ sbrPathOffset = 0;
+ }
+
+ /* 4) Calculate delay from input to core */
+ if (usePs) {
+ delayInput2Core =
+ (DELAY_QMF_ANA(downSampleFactor) + DELAY_QMF_DS + DELAY_HYB_SYN) +
+ (downSampleFactor * corePathOffset) + 1;
+ } else if (downsamplingMethod == SBRENC_DS_TIME) {
+ delayInput2Core = corePathOffset + hDelayParam->dsDelay;
+ } else {
+ delayInput2Core = corePathOffset;
+ }
+
+ /* 6) Set output parameters */
+ hDelayParam->delay = FDKmax(delayCorePath, delaySbrPath); /* overall delay */
+ hDelayParam->sbrDecDelay = delaySbrDec; /* SBR decoder delay */
+ hDelayParam->delayInput2Core = delayInput2Core; /* delay input - core */
+ hDelayParam->bitstrDelay = bitstreamDelay; /* bitstream delay, in frames */
+ hDelayParam->corePathOffset = corePathOffset; /* offset added to core path */
+ hDelayParam->sbrPathOffset = sbrPathOffset; /* offset added to SBR path */
+
+ return returnValue;
+}
+
+/*****************************************************************************
+
+ functionname: sbrEncoder_Init
+ description: initializes the SBR encoder
+ returns: error status
+
+*****************************************************************************/
+INT sbrEncoder_Init(HANDLE_SBR_ENCODER hSbrEncoder,
+ SBR_ELEMENT_INFO elInfo[(8)], int noElements,
+ INT_PCM *inputBuffer, UINT inputBufferBufSize,
+ INT *coreBandwidth, INT *inputBufferOffset,
+ INT *numChannels, const UINT syntaxFlags,
+ INT *coreSampleRate, UINT *downSampleFactor,
+ INT *frameLength, AUDIO_OBJECT_TYPE aot, int *delay,
+ int transformFactor, const int headerPeriod,
+ ULONG statesInitFlag) {
+ HANDLE_ERROR_INFO errorInfo = noError;
+ sbrConfiguration sbrConfig[(8)];
+ INT error = 0;
+ INT lowestBandwidth;
+ /* Save input parameters */
+ INT inputSampleRate = *coreSampleRate;
+ int coreFrameLength = *frameLength;
+ int inputBandWidth = *coreBandwidth;
+ int inputChannels = *numChannels;
+
+ SBRENC_DS_TYPE downsamplingMethod = SBRENC_DS_NONE;
+ int highestSbrStartFreq, highestSbrStopFreq;
+ int lowDelay = 0;
+ int usePs = 0;
+ int is212 = 0;
+
+ DELAY_PARAM delayParam;
+
+ /* check whether SBR setting is available for the current encoder
+ * configuration (bitrate, samplerate) */
+ if (!sbrEncoder_IsSingleRatePossible(aot)) {
+ *downSampleFactor = 2;
+ }
+
+ if (aot == AOT_PS || aot == AOT_DABPLUS_PS) {
+ usePs = 1;
+ }
+ if (aot == AOT_ER_AAC_ELD) {
+ lowDelay = 1;
+ } else if (aot == AOT_ER_AAC_LD) {
+ error = 1;
+ goto bail;
+ }
+
+ /* Parametric Stereo */
+ if (usePs) {
+ if (*numChannels == 2 && noElements == 1) {
+ /* Override Element type in case of Parametric stereo */
+ elInfo[0].elType = ID_SCE;
+ elInfo[0].fParametricStereo = 1;
+ elInfo[0].nChannelsInEl = 1;
+ /* core encoder gets downmixed mono signal */
+ *numChannels = 1;
+ } else {
+ error = 1;
+ goto bail;
+ }
+ } /* usePs */
+
+ /* set the core's sample rate */
+ switch (*downSampleFactor) {
+ case 1:
+ *coreSampleRate = inputSampleRate;
+ downsamplingMethod = SBRENC_DS_NONE;
+ break;
+ case 2:
+ *coreSampleRate = inputSampleRate >> 1;
+ downsamplingMethod = usePs ? SBRENC_DS_QMF : SBRENC_DS_TIME;
+ break;
+ default:
+ *coreSampleRate = inputSampleRate >> 1;
+ return 0; /* return error */
+ }
+
+ /* check whether SBR setting is available for the current encoder
+ * configuration (bitrate, coreSampleRate) */
+ {
+ int el, coreEl;
+
+ /* Check if every element config is feasible */
+ for (coreEl = 0; coreEl < noElements; coreEl++) {
+ /* SBR only handles SCE and CPE's */
+ if (elInfo[coreEl].elType != ID_SCE && elInfo[coreEl].elType != ID_CPE) {
+ continue;
+ }
+ /* check if desired configuration is available */
+ if (!FDKsbrEnc_IsSbrSettingAvail(elInfo[coreEl].bitRate, 0,
+ elInfo[coreEl].nChannelsInEl,
+ inputSampleRate, *coreSampleRate, aot)) {
+ error = 1;
+ goto bail;
+ }
+ }
+
+ hSbrEncoder->nChannels = *numChannels;
+ hSbrEncoder->frameSize = coreFrameLength * *downSampleFactor;
+ hSbrEncoder->downsamplingMethod = downsamplingMethod;
+ hSbrEncoder->downSampleFactor = *downSampleFactor;
+ hSbrEncoder->estimateBitrate = 0;
+ hSbrEncoder->inputDataDelay = 0;
+ is212 = ((aot == AOT_ER_AAC_ELD) && (syntaxFlags & AC_LD_MPS)) ? 1 : 0;
+
+ /* Open SBR elements */
+ el = -1;
+ highestSbrStartFreq = highestSbrStopFreq = 0;
+ lowestBandwidth = 99999;
+
+ /* Loop through each core encoder element and get a matching SBR element
+ * config */
+ for (coreEl = 0; coreEl < noElements; coreEl++) {
+ /* SBR only handles SCE and CPE's */
+ if (elInfo[coreEl].elType == ID_SCE || elInfo[coreEl].elType == ID_CPE) {
+ el++;
+ } else {
+ continue;
+ }
+
+ /* Set parametric Stereo Flag. */
+ if (usePs) {
+ elInfo[coreEl].fParametricStereo = 1;
+ } else {
+ elInfo[coreEl].fParametricStereo = 0;
+ }
+
+ /*
+ * Init sbrConfig structure
+ */
+ if (!FDKsbrEnc_InitializeSbrDefaults(&sbrConfig[el], *downSampleFactor,
+ coreFrameLength, IS_LOWDELAY(aot))) {
+ error = 1;
+ goto bail;
+ }
+
+ /*
+ * Modify sbrConfig structure according to Element parameters
+ */
+ if (!FDKsbrEnc_AdjustSbrSettings(
+ &sbrConfig[el], elInfo[coreEl].bitRate,
+ elInfo[coreEl].nChannelsInEl, *coreSampleRate, inputSampleRate,
+ transformFactor, 24000, 0, 0, /* useSpeechConfig */
+ 0, /* lcsMode */
+ usePs, /* bParametricStereo */
+ aot)) {
+ error = 1;
+ goto bail;
+ }
+
+ /* Find common frequency border for all SBR elements */
+ highestSbrStartFreq =
+ fixMax(highestSbrStartFreq, sbrConfig[el].startFreq);
+ highestSbrStopFreq = fixMax(highestSbrStopFreq, sbrConfig[el].stopFreq);
+
+ } /* first element loop */
+
+ /* Set element count (can be less than core encoder element count) */
+ hSbrEncoder->noElements = el + 1;
+
+ FDKsbrEnc_Reallocate(hSbrEncoder, elInfo, noElements);
+
+ for (el = 0; el < hSbrEncoder->noElements; el++) {
+ int bandwidth = *coreBandwidth;
+
+ /* Use lowest common bandwidth */
+ sbrConfig[el].startFreq = highestSbrStartFreq;
+ sbrConfig[el].stopFreq = highestSbrStopFreq;
+
+ /* initialize SBR element, and get core bandwidth */
+ error = FDKsbrEnc_EnvInit(hSbrEncoder->sbrElement[el], &sbrConfig[el],
+ &bandwidth, aot, el, headerPeriod,
+ statesInitFlag, hSbrEncoder->downsamplingMethod,
+ hSbrEncoder->dynamicRam);
+
+ if (error != 0) {
+ error = 2;
+ goto bail;
+ }
+
+ /* Get lowest core encoder bandwidth to be returned later. */
+ lowestBandwidth = fixMin(lowestBandwidth, bandwidth);
+
+ } /* second element loop */
+
+ /* Initialize a downsampler for each channel in each SBR element */
+ if (hSbrEncoder->downsamplingMethod == SBRENC_DS_TIME) {
+ for (el = 0; el < hSbrEncoder->noElements; el++) {
+ HANDLE_SBR_ELEMENT hSbrEl = hSbrEncoder->sbrElement[el];
+ INT Wc, ch;
+
+ Wc = 500; /* Cutoff frequency with full bandwidth */
+
+ for (ch = 0; ch < hSbrEl->elInfo.nChannelsInEl; ch++) {
+ FDKaacEnc_InitDownsampler(&hSbrEl->sbrChannel[ch]->downSampler, Wc,
+ *downSampleFactor);
+ FDK_ASSERT(hSbrEl->sbrChannel[ch]->downSampler.delay <=
+ MAX_DS_FILTER_DELAY);
+ }
+ } /* third element loop */
+
+ /* lfe */
+ FDKaacEnc_InitDownsampler(&hSbrEncoder->lfeDownSampler, 0,
+ *downSampleFactor);
+ }
+
+ /* Get delay information */
+ delayParam.dsDelay =
+ hSbrEncoder->sbrElement[0]->sbrChannel[0]->downSampler.delay;
+ delayParam.delay = *delay;
+
+ error = sbrEncoder_Init_delay(coreFrameLength, *numChannels,
+ *downSampleFactor, lowDelay, usePs, is212,
+ downsamplingMethod, &delayParam);
+
+ if (error != 0) {
+ error = 3;
+ goto bail;
+ }
+
+ hSbrEncoder->nBitstrDelay = delayParam.bitstrDelay;
+ hSbrEncoder->sbrDecDelay = delayParam.sbrDecDelay;
+ hSbrEncoder->inputDataDelay = delayParam.delayInput2Core;
+
+ /* Assign core encoder Bandwidth */
+ *coreBandwidth = lowestBandwidth;
+
+ /* Estimate sbr bitrate, 2.5 kBit/s per sbr channel */
+ hSbrEncoder->estimateBitrate += 2500 * (*numChannels);
+
+ /* Initialize bitstream buffer for each element */
+ for (el = 0; el < hSbrEncoder->noElements; el++) {
+ FDKsbrEnc_bsBufInit(hSbrEncoder->sbrElement[el], delayParam.bitstrDelay);
+ }
+
+ /* initialize parametric stereo */
+ if (usePs) {
+ PSENC_CONFIG psEncConfig;
+ FDK_ASSERT(hSbrEncoder->noElements == 1);
+ INT psTuningTableIdx = getPsTuningTableIndex(elInfo[0].bitRate, NULL);
+
+ psEncConfig.frameSize = coreFrameLength; // sbrConfig.sbrFrameSize;
+ psEncConfig.qmfFilterMode = 0;
+ psEncConfig.sbrPsDelay = 0;
+
+ /* tuning parameters */
+ if (psTuningTableIdx != INVALID_TABLE_IDX) {
+ psEncConfig.nStereoBands = psTuningTable[psTuningTableIdx].nStereoBands;
+ psEncConfig.maxEnvelopes = psTuningTable[psTuningTableIdx].nEnvelopes;
+ psEncConfig.iidQuantErrorThreshold =
+ (FIXP_DBL)psTuningTable[psTuningTableIdx].iidQuantErrorThreshold;
+
+ /* calculation is not quite linear, increased number of envelopes causes
+ * more bits */
+ /* assume avg. 50 bits per frame for 10 stereo bands / 1 envelope
+ * configuration */
+ hSbrEncoder->estimateBitrate +=
+ ((((*coreSampleRate) * 5 * psEncConfig.nStereoBands *
+ psEncConfig.maxEnvelopes) /
+ hSbrEncoder->frameSize));
+
+ } else {
+ error = ERROR(CDI, "Invalid ps tuning table index.");
+ goto bail;
+ }
+
+ qmfInitSynthesisFilterBank(
+ &hSbrEncoder->qmfSynthesisPS,
+ (FIXP_DBL *)hSbrEncoder->qmfSynthesisPS.FilterStates,
+ hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfSlots,
+ hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands >> 1,
+ hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands >> 1,
+ hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands >> 1,
+ (statesInitFlag) ? 0 : QMF_FLAG_KEEP_STATES);
+
+ if (errorInfo == noError) {
+ /* update delay */
+ psEncConfig.sbrPsDelay =
+ FDKsbrEnc_GetEnvEstDelay(&hSbrEncoder->sbrElement[0]
+ ->sbrChannel[0]
+ ->hEnvChannel.sbrExtractEnvelope);
+
+ errorInfo =
+ PSEnc_Init(hSbrEncoder->hParametricStereo, &psEncConfig,
+ hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfSlots,
+ hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands,
+ hSbrEncoder->dynamicRam);
+ }
+ }
+
+ hSbrEncoder->downsampledOffset = delayParam.corePathOffset;
+ hSbrEncoder->bufferOffset = delayParam.sbrPathOffset;
+ *delay = delayParam.delay;
+
+ { hSbrEncoder->downmixSize = coreFrameLength * (*numChannels); }
+
+ /* Delay Compensation: fill bitstream delay buffer with zero input signal */
+ if (hSbrEncoder->nBitstrDelay > 0) {
+ error = FDKsbrEnc_DelayCompensation(hSbrEncoder, inputBuffer,
+ inputBufferBufSize);
+ if (error != 0) goto bail;
+ }
+
+ /* Set Output frame length */
+ *frameLength = coreFrameLength * *downSampleFactor;
+ /* Input buffer offset */
+ *inputBufferOffset =
+ fixMax(delayParam.sbrPathOffset, delayParam.corePathOffset);
+ }
+
+ return error;
+
+bail:
+ /* Restore input settings */
+ *coreSampleRate = inputSampleRate;
+ *frameLength = coreFrameLength;
+ *numChannels = inputChannels;
+ *coreBandwidth = inputBandWidth;
+
+ return error;
+}
+
+INT sbrEncoder_EncodeFrame(HANDLE_SBR_ENCODER hSbrEncoder, INT_PCM *samples,
+ UINT samplesBufSize, UINT sbrDataBits[(8)],
+ UCHAR sbrData[(8)][MAX_PAYLOAD_SIZE]) {
+ INT error;
+ int el;
+
+ for (el = 0; el < hSbrEncoder->noElements; el++) {
+ if (hSbrEncoder->sbrElement[el] != NULL) {
+ error = FDKsbrEnc_EnvEncodeFrame(
+ hSbrEncoder, el,
+ samples + hSbrEncoder->downsampledOffset / hSbrEncoder->nChannels,
+ samplesBufSize, &sbrDataBits[el], sbrData[el], 0);
+ if (error) return error;
+ }
+ }
+
+ error = FDKsbrEnc_Downsample(
+ hSbrEncoder,
+ samples + hSbrEncoder->downsampledOffset / hSbrEncoder->nChannels,
+ samplesBufSize, hSbrEncoder->nChannels, &sbrDataBits[el], sbrData[el], 0);
+ if (error) return error;
+
+ return 0;
+}
+
+INT sbrEncoder_UpdateBuffers(HANDLE_SBR_ENCODER hSbrEncoder,
+ INT_PCM *timeBuffer, UINT timeBufferBufSize) {
+ if (hSbrEncoder->downsampledOffset > 0) {
+ int c;
+ int nd = hSbrEncoder->downmixSize / hSbrEncoder->nChannels;
+
+ for (c = 0; c < hSbrEncoder->nChannels; c++) {
+ /* Move delayed downsampled data */
+ FDKmemcpy(timeBuffer + timeBufferBufSize * c,
+ timeBuffer + timeBufferBufSize * c + nd,
+ sizeof(INT_PCM) *
+ (hSbrEncoder->downsampledOffset / hSbrEncoder->nChannels));
+ }
+ } else {
+ int c;
+
+ for (c = 0; c < hSbrEncoder->nChannels; c++) {
+ /* Move delayed input data */
+ FDKmemcpy(
+ timeBuffer + timeBufferBufSize * c,
+ timeBuffer + timeBufferBufSize * c + hSbrEncoder->frameSize,
+ sizeof(INT_PCM) * hSbrEncoder->bufferOffset / hSbrEncoder->nChannels);
+ }
+ }
+ if (hSbrEncoder->nBitstrDelay > 0) {
+ int el;
+
+ for (el = 0; el < hSbrEncoder->noElements; el++) {
+ FDKmemmove(
+ hSbrEncoder->sbrElement[el]->payloadDelayLine[0],
+ hSbrEncoder->sbrElement[el]->payloadDelayLine[1],
+ sizeof(UCHAR) * (hSbrEncoder->nBitstrDelay * MAX_PAYLOAD_SIZE));
+
+ FDKmemmove(&hSbrEncoder->sbrElement[el]->payloadDelayLineSize[0],
+ &hSbrEncoder->sbrElement[el]->payloadDelayLineSize[1],
+ sizeof(UINT) * (hSbrEncoder->nBitstrDelay));
+ }
+ }
+ return 0;
+}
+
+INT sbrEncoder_SendHeader(HANDLE_SBR_ENCODER hSbrEncoder) {
+ INT error = -1;
+ if (hSbrEncoder) {
+ int el;
+ for (el = 0; el < hSbrEncoder->noElements; el++) {
+ if ((hSbrEncoder->noElements == 1) &&
+ (hSbrEncoder->sbrElement[0]->elInfo.fParametricStereo == 1)) {
+ hSbrEncoder->sbrElement[el]->sbrBitstreamData.CountSendHeaderData =
+ hSbrEncoder->sbrElement[el]->sbrBitstreamData.NrSendHeaderData - 1;
+ } else {
+ hSbrEncoder->sbrElement[el]->sbrBitstreamData.CountSendHeaderData = 0;
+ }
+ }
+ error = 0;
+ }
+ return error;
+}
+
+INT sbrEncoder_ContainsHeader(HANDLE_SBR_ENCODER hSbrEncoder) {
+ INT sbrHeader = 1;
+ if (hSbrEncoder) {
+ int el;
+ for (el = 0; el < hSbrEncoder->noElements; el++) {
+ sbrHeader &=
+ (hSbrEncoder->sbrElement[el]->sbrBitstreamData.HeaderActiveDelay == 1)
+ ? 1
+ : 0;
+ }
+ }
+ return sbrHeader;
+}
+
+INT sbrEncoder_GetHeaderDelay(HANDLE_SBR_ENCODER hSbrEncoder) {
+ INT delay = -1;
+
+ if (hSbrEncoder) {
+ if ((hSbrEncoder->noElements == 1) &&
+ (hSbrEncoder->sbrElement[0]->elInfo.fParametricStereo == 1)) {
+ delay = hSbrEncoder->nBitstrDelay + 1;
+ } else {
+ delay = hSbrEncoder->nBitstrDelay;
+ }
+ }
+ return delay;
+}
+INT sbrEncoder_GetBsDelay(HANDLE_SBR_ENCODER hSbrEncoder) {
+ INT delay = -1;
+
+ if (hSbrEncoder) {
+ delay = hSbrEncoder->nBitstrDelay;
+ }
+ return delay;
+}
+
+INT sbrEncoder_SAPPrepare(HANDLE_SBR_ENCODER hSbrEncoder) {
+ INT error = -1;
+ if (hSbrEncoder) {
+ int el;
+ for (el = 0; el < hSbrEncoder->noElements; el++) {
+ hSbrEncoder->sbrElement[el]->sbrBitstreamData.rightBorderFIX = 1;
+ }
+ error = 0;
+ }
+ return error;
+}
+
+INT sbrEncoder_GetEstimateBitrate(HANDLE_SBR_ENCODER hSbrEncoder) {
+ INT estimateBitrate = 0;
+
+ if (hSbrEncoder) {
+ estimateBitrate += hSbrEncoder->estimateBitrate;
+ }
+
+ return estimateBitrate;
+}
+
+INT sbrEncoder_GetInputDataDelay(HANDLE_SBR_ENCODER hSbrEncoder) {
+ INT delay = -1;
+
+ if (hSbrEncoder) {
+ delay = hSbrEncoder->inputDataDelay;
+ }
+ return delay;
+}
+
+INT sbrEncoder_GetSbrDecDelay(HANDLE_SBR_ENCODER hSbrEncoder) {
+ INT delay = -1;
+
+ if (hSbrEncoder) {
+ delay = hSbrEncoder->sbrDecDelay;
+ }
+ return delay;
+}
+
+INT sbrEncoder_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_SBRENC;
+ info->version =
+ LIB_VERSION(SBRENCODER_LIB_VL0, SBRENCODER_LIB_VL1, SBRENCODER_LIB_VL2);
+ LIB_VERSION_STRING(info);
+#ifdef __ANDROID__
+ info->build_date = "";
+ info->build_time = "";
+#else
+ info->build_date = __DATE__;
+ info->build_time = __TIME__;
+#endif
+ info->title = "SBR Encoder";
+
+ /* Set flags */
+ info->flags = 0 | CAPF_SBR_HQ | CAPF_SBR_PS_MPEG;
+ /* End of flags */
+
+ return 0;
+}