aboutsummaryrefslogtreecommitdiffstats
path: root/libSBRenc/src/sbr_encoder.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2012-07-11 10:15:24 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2012-07-11 10:15:24 -0700
commit2228e360595641dd906bf1773307f43d304f5b2e (patch)
tree57f3d390ebb0782cc0de0fb984c8ea7e45b4f386 /libSBRenc/src/sbr_encoder.cpp
downloadfdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.tar.gz
fdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.tar.bz2
fdk-aac-dabplus-2228e360595641dd906bf1773307f43d304f5b2e.zip
Snapshot 2bda038c163298531d47394bc2c09e1409c5d0db
Change-Id: If584e579464f28b97d50e51fc76ba654a5536c54
Diffstat (limited to 'libSBRenc/src/sbr_encoder.cpp')
-rw-r--r--libSBRenc/src/sbr_encoder.cpp2237
1 files changed, 2237 insertions, 0 deletions
diff --git a/libSBRenc/src/sbr_encoder.cpp b/libSBRenc/src/sbr_encoder.cpp
new file mode 100644
index 0000000..0dcc1b2
--- /dev/null
+++ b/libSBRenc/src/sbr_encoder.cpp
@@ -0,0 +1,2237 @@
+
+/* -----------------------------------------------------------------------------------------------------------
+Software License for The Fraunhofer FDK AAC Codec Library for Android
+
+© Copyright 1995 - 2012 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
+----------------------------------------------------------------------------------------------------------- */
+
+/*************************** Fraunhofer IIS FDK Tools ***********************
+
+ Author(s): Andreas Ehret
+ Description: SBR encoder top level processing.
+
+******************************************************************************/
+
+#include "sbr_encoder.h"
+
+#include "sbr_ram.h"
+#include "sbr_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 3
+#define SBRENCODER_LIB_VL1 2
+#define SBRENCODER_LIB_VL2 1
+
+
+
+/***************************************************************************/
+/*
+ * SBR Delay balancing definitions.
+ */
+
+/*
+ input buffer (1ch)
+
+ |------------ 1537 -------------|-----|---------- 2048 -------------|
+ (core2sbr delay ) ds (read, core and ds area)
+*/
+
+#define DOWN_SMPL_FAC (2)
+
+#define SFL(fl) (fl*DOWN_SMPL_FAC) /* SBR frame length (hardcoded to downsample factor of 2) */
+#define STS(fl) (SFL(fl)/64) /* SBR Time Slots */
+
+#define DELAY_QMF_ANA (640 - 64) /* Full bandwidth */
+#define DELAY_QMF_ANAELD (32)
+#define DELAY_HYB_ANA (10*64) /* + 0.5 */
+#define DELAY_HYB_SYN (6*64 - 32)
+#define DELAY_QMF_SYNELD (32)
+#define DELAY_DEC_QMF (6*64) /* Decoder QMF overlap */
+#define DELAY_QMF_SYN (2) /* NO_POLY/2 */
+#define DELAY_QMF_DS (32) /* QMF synthesis for downsampled time signal */
+
+/* Delay in QMF paths */
+#define DELAY_SBR(fl) (DELAY_QMF_ANA + (64*STS(fl)-1) + DELAY_QMF_SYN)
+#define DELAY_PS(fl) (DELAY_QMF_ANA + DELAY_HYB_ANA + DELAY_DEC_QMF + (64*STS(fl)-1) + DELAY_HYB_SYN + DELAY_QMF_SYN)
+#define DELAY_ELDSBR(fl) (DELAY_QMF_ANAELD + (((fl)+((fl)/2))*2 - 1) + DELAY_QMF_SYNELD)
+
+/* Delay differences for SBR and SBR+PS */
+ #define MAX_DS_FILTER_DELAY (34) /* the additional max downsampler filter delay (source fs) */
+#define DELAY_AAC2SBR(fl) ((/*RESAMPLER +*/ /*(DELAY_AAC(fl)*2) + */ DELAY_QMF_ANA + DELAY_DEC_QMF + DELAY_QMF_SYN) - DELAY_SBR(fl)) /* 1537 */
+#define DELAY_ELD2SBR(fl) ((/*RESAMPLER +*/ /*(DELAY_ELD(fl)*2) + */ DELAY_QMF_ANAELD + DELAY_QMF_SYNELD) - DELAY_ELDSBR(fl))
+
+#define DELAY_AAC2PS(fl) ((DELAY_QMF_ANA + DELAY_QMF_DS + /*(DELAY_AAC(fl)*2)*/ + DELAY_QMF_ANA + DELAY_DEC_QMF + DELAY_HYB_SYN + DELAY_QMF_SYN) - DELAY_PS(fl)) /* 2048 - 463*2 */
+
+/* Assumption: that the sample delay resulting of of DELAY_AAC2PS is always smaller than the sample delay implied by DELAY_AAC2SBR */
+#define MAX_SAMPLE_DELAY (DELAY_AAC2SBR(1024) + MAX_DS_FILTER_DELAY)
+
+/***************************************************************************/
+
+
+
+#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, paramSetTop, bitRateClosestLowerIndex=-1, bitRateClosestUpperIndex=-1, found = 0;
+ UINT bitRateClosestUpper = 0, bitRateClosestLower=DISTANCE_CEIL_VALUE;
+
+ FDK_ASSERT(SBRENC_TUNING_SIZE == sizeof(sbrTuningTable)/sizeof(sbrTuningTable[0]));
+
+ if (core == AOT_ER_AAC_ELD) {
+ paramSetTop = SBRENC_TUNING_SIZE;
+ i = SBRENC_AACLC_TUNING_SIZE;
+ } else {
+ paramSetTop = SBRENC_AACLC_TUNING_SIZE;
+ i = 0;
+ }
+
+ for (; i < paramSetTop ; i++) {
+ if ( numChannels == sbrTuningTable [i].numChannels
+ && sampleRate == sbrTuningTable [i].sampleRate )
+ {
+ found = 1;
+ if ((bitrate >= sbrTuningTable [i].bitrateFrom) &&
+ (bitrate < sbrTuningTable [i].bitrateTo)) {
+ bitRateClosestLower = bitrate;
+ bitRateClosestUpper = bitrate;
+ //FDKprintf("entry %d\n", i);
+ 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 (pBitRateClosest != NULL)
+ {
+ /* Is there was at least one matching tuning entry found then 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 (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 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] */
+ AUDIO_OBJECT_TYPE core
+ )
+{
+ INT idx = INVALID_TABLE_IDX;
+ UINT sampleRateCore;
+
+ 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;
+ }
+
+ /* try DOWN_SMPL_FAC of the input sampling rate */
+ sampleRateCore = sampleRateInput/DOWN_SMPL_FAC;
+ 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 fsCore, /*! the core 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;
+ UINT sampleRate;
+
+ /* set the codec settings */
+ config->codecSettings.bitRate = bitRate;
+ config->codecSettings.nChannels = numChannels;
+ config->codecSettings.sampleFreq = fsCore;
+ config->codecSettings.transFac = transFac;
+ config->codecSettings.standardBitrate = standardBitrate;
+ sampleRate = fsCore * DOWN_SMPL_FAC;
+
+ 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 (sampleRate==44100 || sampleRate==48000) {
+ if (vbrMode<40) bitRate = 32000;
+ }
+ }
+ }
+
+ idx = getSbrTuningTableIndex(bitRate,numChannels,fsCore, 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;
+ }
+
+ 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 ;
+
+ /* 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 confifuration
+ returns: error status
+ input: - core codec type,
+ - fac of SBR to core frame length,
+ - core frame length
+ output: initialized SBR configuration
+
+*****************************************************************************/
+static UINT
+FDKsbrEnc_InitializeSbrDefaults (sbrConfigurationPtr config,
+ INT coreSbrFrameLenFac,
+ UINT codecGranuleLen)
+{
+ if ( (coreSbrFrameLenFac != 2) ||
+ (codecGranuleLen*coreSbrFrameLenFac > QMF_CHANNELS*QMF_MAX_TIME_SLOTS) )
+ return(1);
+
+ config->SendHeaderDataTime = 1000;
+ config->useWaveCoding = 0;
+ config->crcSbr = 0;
+ config->dynBwSupported = 1;
+ config->tran_thr = 13000;
+ config->parametricCoding = 1;
+
+ config->sbrFrameSize = codecGranuleLen * coreSbrFrameLenFac;
+
+
+ /* 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;
+ config->bDownSampledSbr = 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 */
+
+
+ /* 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<(6); el++)
+ {
+ if (hSbrEncoder->sbrElement[el]!=NULL) {
+ sbrEncoder_ElementClose(&hSbrEncoder->sbrElement[el]);
+ }
+ }
+
+ /* Close sbr Channels */
+ for (ch=0; ch<(6); 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 */
+ 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,
+ INT noQmfChannels)
+{
+ INT k0, k2;
+
+ if(FDKsbrEnc_FindStartAndStopBand(sbrConfigData->sampleFreq,
+ noQmfChannels,
+ sbrHeaderData->sbr_start_frequency,
+ sbrHeaderData->sbr_stop_frequency,
+ sbrHeaderData->sampleRateMode,
+ &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,
+ sbrHeaderData->sampleRateMode,
+ noQmfChannels))
+ 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 / noQmfChannels+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 interleaved */
+ UINT timeInStride, /*!< time buffer channel interleaving stride */
+ UINT *sbrDataBits, /*!< Size of SBR payload */
+ UCHAR *sbrData, /*!< SBR payload */
+ int clearOutput /*!< Do not consider any input signal */
+ )
+{
+ HANDLE_SBR_ELEMENT hSbrElement = hEnvEncoder->sbrElement[iElement];
+ 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,
+ hSbrElement->sbrConfigData.noQmfBands))
+ 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);
+
+ INT error = noError;
+
+ /* 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)
+ {
+ C_ALLOC_SCRATCH_START(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2);
+ QMF_SCALE_FACTOR tmpScale;
+ FIXP_DBL **pQmfReal, **pQmfImag;
+
+
+ /* Obtain pointers to QMF buffers. */
+ pQmfReal = sbrExtrEnv->rBuffer;
+ pQmfImag = sbrExtrEnv->iBuffer;
+
+ qmfAnalysisFiltering( hSbrElement->hQmfAnalysis[ch],
+ pQmfReal,
+ pQmfImag,
+ &tmpScale,
+ samples + hSbrElement->elInfo.ChannelIndex[ch],
+ timeInStride,
+ qmfWorkBuffer );
+
+ C_ALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2);
+
+ h_envChan->qmfScale = tmpScale.lb_scale + 7;
+
+ } /* fParametricStereo == 0 */
+
+
+ /*
+ Parametric Stereo processing
+ */
+ if (hSbrElement->elInfo.fParametricStereo)
+ {
+
+ /* 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],samples + hSbrElement->elInfo.ChannelIndex[1]};
+ error = FDKsbrEnc_PSEnc_ParametricStereoProcessing( hEnvEncoder->hParametricStereo,
+ pSamples,
+ timeInStride,
+ hSbrElement->hQmfAnalysis,
+ sbrExtrEnv->rBuffer,
+ sbrExtrEnv->iBuffer,
+ samples + hSbrElement->elInfo.ChannelIndex[ch],
+ &hEnvEncoder->qmfSynthesisPS,
+ &qmfScale,
+ psHeaderActive );
+ if (noError != error)
+ {
+ error = handBack(error);
+ }
+ 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->sbrChannel[1]->hEnvChannel,
+ &hSbrElement->CmonData,
+ eData,
+ fData,
+ clearOutput
+ );
+
+ /*
+ 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);
+
+
+ }
+
+
+/*******************************/
+
+ if (hEnvEncoder->fTimeDomainDownsampling)
+ {
+ int ch;
+ int nChannels = hSbrElement->sbrConfigData.nChannels;
+
+ for (ch=0; ch < nChannels; ch++)
+ {
+ INT nOutSamples;
+
+ FDKaacEnc_Downsample(&hSbrElement->sbrChannel[ch]->downSampler,
+ samples + hSbrElement->elInfo.ChannelIndex[ch] + hEnvEncoder->bufferOffset,
+ hSbrElement->sbrConfigData.frameSize,
+ timeInStride,
+ samples + hSbrElement->elInfo.ChannelIndex[ch],
+ &nOutSamples,
+ hEnvEncoder->nChannels);
+ }
+ } /* downsample */
+
+
+ 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 = 1;
+ 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:
+ timeSlots = 16;
+ break;
+ case 1920:
+ case 960:
+ 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,64,sbrConfigData->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 (params->sbrFrameSize) {
+ /* The factor of 2 is by definition. */
+ case 2048: tran_off = 8 + FRAME_MIDDLE_SLOT_2048 * timeStep; break;
+ case 1920: tran_off = 7 + FRAME_MIDDLE_SLOT_1920 * timeStep; break;
+ default: return 1; break;
+ }
+ }
+ 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.ldGrid
+ );
+
+ if(FDKsbrEnc_InitSbrTransientDetector (&hEnv->sbrTransientDetector,
+ 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));
+
+ hSbrEncoder->pSBRdynamic_RAM = (UCHAR*)GetRam_SbrDynamic_RAM();
+ hSbrEncoder->dynamicRam = hSbrEncoder->pSBRdynamic_RAM;
+
+
+ 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;
+ }
+ }
+
+ 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;
+ }
+
+ }
+
+ 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;
+ }
+ }
+
+ 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[(6)],
+ 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;
+ } /* coreEl */
+
+ 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 nBitstrDelay,
+ int nElement,
+ ULONG statesInitFlag
+ ,UCHAR *dynamic_RAM
+ )
+{
+ UCHAR *bitstreamBuffer;
+ int ch, i;
+
+ if ((params->codecSettings.nChannels < 1) || (params->codecSettings.nChannels > MAX_NUM_CHANNELS)){
+ return(1);
+ }
+
+ /* initialize the encoder handle and structs*/
+ bitstreamBuffer = hSbrElement->payloadDelayLine[nBitstrDelay];
+
+ /* init and set syntax flags */
+ hSbrElement->sbrConfigData.sbrSyntaxFlags = 0;
+
+ switch (aot) {
+ case AOT_DRM_MPEG_PS:
+ case AOT_DRM_SBR:
+ hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_SCALABLE;
+ hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_DRM_CRC;
+ hSbrElement->sbrConfigData.sbrSyntaxFlags |= SBR_SYNTAX_CRC;
+ break;
+ 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 = QMF_CHANNELS;
+ hSbrElement->sbrConfigData.noQmfSlots = params->sbrFrameSize/hSbrElement->sbrConfigData.noQmfBands;
+
+ FDKinitBitStream(&hSbrElement->CmonData.sbrBitbuf, bitstreamBuffer, MAX_PAYLOAD_SIZE*sizeof(UCHAR), 0, BS_WRITER);
+
+ /*
+ now initialize sbrConfigData, sbrHeaderData and sbrBitstreamData,
+ */
+ hSbrElement->sbrConfigData.nChannels = params->codecSettings.nChannels;
+
+ if(params->codecSettings.nChannels == 2)
+ hSbrElement->sbrConfigData.stereoMode = params->stereoMode;
+ else
+ hSbrElement->sbrConfigData.stereoMode = SBR_MONO;
+
+ hSbrElement->sbrConfigData.frameSize = params->sbrFrameSize;
+
+ /* implicit rule for sampleRateMode */
+ /* run in "multirate" mode where sbr fs is 2 * codec fs */
+ hSbrElement->sbrHeaderData.sampleRateMode = DUAL_RATE;
+ hSbrElement->sbrConfigData.sampleFreq = 2 * params->codecSettings.sampleFreq;
+
+ hSbrElement->sbrBitstreamData.CountSendHeaderData = 0;
+ if (params->SendHeaderDataTime > 0 ) {
+
+ hSbrElement->sbrBitstreamData.NrSendHeaderData = (INT)(params->SendHeaderDataTime * hSbrElement->sbrConfigData.sampleFreq
+ / (1000 * hSbrElement->sbrConfigData.frameSize));
+ hSbrElement->sbrBitstreamData.NrSendHeaderData = fixMax(hSbrElement->sbrBitstreamData.NrSendHeaderData,1);
+ }
+ else {
+ hSbrElement->sbrBitstreamData.NrSendHeaderData = 0;
+ }
+
+ hSbrElement->sbrHeaderData.sbr_data_extra = params->sbr_data_extra;
+ hSbrElement->sbrBitstreamData.HeaderActive = 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;
+
+ /* init freq band table */
+ if(updateFreqBandTable(&hSbrElement->sbrConfigData,
+ &hSbrElement->sbrHeaderData,
+ hSbrElement->sbrConfigData.noQmfBands))
+ {
+ 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 );
+ }
+
+ /* */
+ 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 = (1024*DOWN_SMPL_FAC);
+ 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
+ )
+{
+ 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->sbrElement[el]->sbrConfigData.nChannels,
+ NULL,
+ NULL,
+ 1
+ ))
+ return -1;
+ sbrEncoder_UpdateBuffers(hEnvEnc, timeBuffer);
+ }
+ }
+ return 0;
+}
+
+UINT sbrEncoder_LimitBitRate(UINT bitRate, UINT numChannels, UINT coreSampleRate, AUDIO_OBJECT_TYPE aot)
+{
+ UINT newBitRate;
+ INT index;
+
+ FDK_ASSERT(numChannels > 0 && numChannels <= 2);
+ if (aot == AOT_PS) {
+ if (numChannels == 2) {
+ index = getPsTuningTableIndex(bitRate, &newBitRate);
+ if (index == INVALID_TABLE_IDX) {
+ bitRate = newBitRate;
+ }
+ /* Set numChannels to 1 because for PS we need a SBR SCE (mono) element. */
+ numChannels = 1;
+ } else {
+ return 0;
+ }
+ }
+ index = getSbrTuningTableIndex(bitRate, numChannels, coreSampleRate, aot, &newBitRate);
+ if (index != INVALID_TABLE_IDX) {
+ newBitRate = bitRate;
+ }
+
+ return newBitRate;
+}
+
+
+INT sbrEncoder_Init(
+ HANDLE_SBR_ENCODER hSbrEncoder,
+ SBR_ELEMENT_INFO elInfo[(6)],
+ int noElements,
+ INT_PCM *inputBuffer,
+ INT *coreBandwidth,
+ INT *inputBufferOffset,
+ INT *numChannels,
+ INT *sampleRate,
+ INT *frameLength,
+ AUDIO_OBJECT_TYPE *aot,
+ int *delay,
+ int transformFactor,
+ ULONG statesInitFlag
+ )
+{
+ HANDLE_ERROR_INFO errorInfo = noError;
+ sbrConfiguration sbrConfig[(6)];
+ INT error = 0;
+ INT lowestBandwidth;
+ /* Save input parameters */
+ INT inputSampleRate = *sampleRate;
+ int coreFrameLength = *frameLength;
+ int inputBandWidth = *coreBandwidth;
+ int inputChannels = *numChannels;
+
+ int downsampledOffset = 0;
+ int sbrOffset = 0;
+ int downsamplerDelay = 0;
+ int downsample = 0;
+ int nBitstrDelay = 0;
+ int lowestSbrStartFreq, lowestSbrStopFreq;
+ int lowDelay = 0;
+ int usePs = 0;
+
+ /* check whether SBR setting is available for the current encoder configuration (bitrate, samplerate) */
+ if ( (*aot==AOT_PS) || (*aot==AOT_MP2_PS) || (*aot==AOT_DABPLUS_PS) || (*aot==AOT_DRM_MPEG_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 {
+ switch (*aot) {
+ case AOT_MP2_PS:
+ *aot = AOT_MP2_SBR;
+ break;
+ case AOT_DABPLUS_PS:
+ *aot = AOT_DABPLUS_SBR;
+ break;
+ case AOT_DRM_MPEG_PS:
+ *aot = AOT_DRM_SBR;
+ break;
+ case AOT_PS:
+ default:
+ *aot = AOT_SBR;
+ }
+ usePs = 0;
+ }
+ } /* usePs */
+
+ /* check whether SBR setting is available for the current encoder configuration (bitrate, samplerate) */
+ {
+ int delayDiff = 0;
+ 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, *aot) )
+ {
+ /* otherwise - change to AAC-LC */
+ switch (*aot) {
+ case AOT_MP2_SBR:
+ case AOT_MP2_PS:
+ *aot = AOT_MP2_AAC_LC;
+ break;
+ case AOT_DABPLUS_SBR:
+ case AOT_DABPLUS_PS:
+ *aot = AOT_DABPLUS_AAC_LC;
+ break;
+ case AOT_DRM_SBR:
+ case AOT_DRM_MPEG_PS:
+ *aot = AOT_DRM_AAC;
+ break;
+ case AOT_ER_AAC_ELD:
+ break;
+ case AOT_SBR:
+ case AOT_PS:
+ default:
+ *aot = AOT_AAC_LC;
+ }
+ error = 1;
+ goto bail;
+ }
+ }
+
+ *sampleRate /= DOWN_SMPL_FAC;
+
+ /* Determine Delay balancing and new encoder delay */
+ if (lowDelay) {
+ downsample = 1; /* activate downsampler */
+ delayDiff = (*delay*DOWN_SMPL_FAC) + DELAY_ELD2SBR(coreFrameLength);
+ *delay = DELAY_ELDSBR(coreFrameLength);
+ }
+ else if (usePs) {
+ delayDiff = (*delay*DOWN_SMPL_FAC) + DELAY_AAC2PS(coreFrameLength);
+ *delay = DELAY_PS(coreFrameLength);
+ }
+ else {
+ downsample = 1; /* activate downsampler */
+ delayDiff = (*delay*DOWN_SMPL_FAC) + DELAY_AAC2SBR(coreFrameLength);
+ *delay = DELAY_SBR(coreFrameLength);
+ }
+
+ /* Take care about downsampled data bound to the SBR path */
+ if (!downsample && delayDiff > 0) {
+ /*
+ * We must tweak the balancing into a situation where the downsampled path
+ * is the one to be delayed, because delaying the QMF domain input, also delays
+ * the downsampled audio, counteracting to the purpose of delay balancing.
+ */
+ while ( delayDiff > 0 )
+ {
+ /* Encoder delay increases */
+ *delay += coreFrameLength*DOWN_SMPL_FAC;
+ /* Add one frame delay to SBR path */
+ delayDiff -= coreFrameLength*DOWN_SMPL_FAC;
+ nBitstrDelay += 1;
+ }
+ } else {
+ *delay += fixp_abs(delayDiff);
+ }
+
+ if (delayDiff < 0) {
+ /* Delay AAC data */
+ delayDiff = -delayDiff;
+ /* Multiply downsampled offset by AAC core channels. Divide by 2 because of half samplerate of downsampled data. */
+ downsampledOffset = (delayDiff*(*numChannels))/DOWN_SMPL_FAC;
+ sbrOffset = 0;
+ } else {
+ /* Delay SBR input */
+ if ( delayDiff > (int)coreFrameLength*DOWN_SMPL_FAC )
+ {
+ /* Do bitstream frame-wise delay balancing if we have more than SBR framelength samples delay difference */
+ delayDiff -= coreFrameLength*DOWN_SMPL_FAC;
+ nBitstrDelay = 1;
+ }
+ /* Multiply input offset by input channels */
+ sbrOffset = delayDiff*(*numChannels);
+ downsampledOffset = 0;
+ }
+
+ hSbrEncoder->nBitstrDelay = nBitstrDelay;
+ hSbrEncoder->nChannels = *numChannels;
+ hSbrEncoder->frameSize = *frameLength*DOWN_SMPL_FAC;
+ hSbrEncoder->fTimeDomainDownsampling = downsample;
+ hSbrEncoder->estimateBitrate = 0;
+ hSbrEncoder->inputDataDelay = 0;
+
+
+ /* Open SBR elements */
+ el = -1;
+ lowestSbrStartFreq = lowestSbrStopFreq = 9999;
+ 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
+ */
+ FDKsbrEnc_InitializeSbrDefaults ( &sbrConfig[el],
+ DOWN_SMPL_FAC,
+ coreFrameLength);
+ /*
+ * Modify sbrConfig structure according to Element parameters
+ */
+ FDKsbrEnc_AdjustSbrSettings ( &sbrConfig[el],
+ elInfo[coreEl].bitRate,
+ elInfo[coreEl].nChannelsInEl,
+ *sampleRate,
+ transformFactor,
+ 24000,
+ 0,
+ 0, /* useSpeechConfig */
+ 0, /* lcsMode */
+ usePs, /* bParametricStereo */
+ *aot);
+
+ /* Find common frequency border for all SBR elements */
+ lowestSbrStartFreq = fixMin(lowestSbrStartFreq, sbrConfig[el].startFreq);
+ lowestSbrStopFreq = fixMin(lowestSbrStopFreq, 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 = lowestSbrStartFreq;
+ sbrConfig[el].stopFreq = lowestSbrStopFreq;
+
+ /* initialize SBR element, and get core bandwidth */
+ error = FDKsbrEnc_EnvInit(hSbrEncoder->sbrElement[el],
+ &sbrConfig[el],
+ &bandwidth,
+ *aot,
+ nBitstrDelay,
+ el,
+ statesInitFlag
+ ,hSbrEncoder->dynamicRam
+ );
+
+ if (error != 0) {
+ 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->fTimeDomainDownsampling)
+ {
+ for (el=0; el<hSbrEncoder->noElements; el++)
+ {
+ HANDLE_SBR_ELEMENT hSbrEl = hSbrEncoder->sbrElement[el];
+ INT Wc, ch;
+
+ /* Calculated required normalized cutoff frequency (Wc = 1.0 -> lowestBandwidth = inputSampleRate/2) */
+ Wc = (2*lowestBandwidth)*1000 / inputSampleRate;
+
+ for (ch=0; ch<hSbrEl->elInfo.nChannelsInEl; ch++)
+ {
+ FDKaacEnc_InitDownsampler (&hSbrEl->sbrChannel[ch]->downSampler, Wc, DOWN_SMPL_FAC);
+ }
+
+ FDK_ASSERT (hSbrEl->sbrChannel[0]->downSampler.delay <=MAX_DS_FILTER_DELAY && hSbrEl->sbrChannel[0]->downSampler.delay <=MAX_DS_FILTER_DELAY);
+ downsamplerDelay = hSbrEl->sbrChannel[0]->downSampler.delay;
+ } /* third element loop */
+
+ /* lfe */
+ FDKaacEnc_InitDownsampler (&hSbrEncoder->lfeDownSampler, 0, DOWN_SMPL_FAC);
+
+ /* Add the resampler additional delay to get the final delay and buffer offset values. */
+ if (sbrOffset > 0 || downsampledOffset <= ((downsamplerDelay * (*numChannels))/DOWN_SMPL_FAC)) {
+ sbrOffset += (downsamplerDelay - downsampledOffset) * (*numChannels) ;
+ *delay += downsamplerDelay - downsampledOffset;
+ downsampledOffset = 0;
+ } else {
+ downsampledOffset -= (downsamplerDelay * (*numChannels))/DOWN_SMPL_FAC;
+ sbrOffset = 0;
+ }
+
+ hSbrEncoder->inputDataDelay = downsamplerDelay;
+ }
+
+
+ /* Assign core encoder Bandwidth */
+ *coreBandwidth = lowestBandwidth;
+
+ /* Estimate sbr bitrate, 2.5 kBit/s per sbr channel */
+ hSbrEncoder->estimateBitrate += 2500 * (*numChannels);
+
+ /* initialize parametric stereo */
+ if (usePs)
+ {
+ PSENC_CONFIG psEncConfig;
+ FDK_ASSERT(hSbrEncoder->noElements == 1);
+ INT psTuningTableIdx = getPsTuningTableIndex(elInfo[0].bitRate, NULL);
+
+ psEncConfig.frameSize = *frameLength; //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 += ( (((*sampleRate) * 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);
+
+ if(noError != (errorInfo = PSEnc_Init( hSbrEncoder->hParametricStereo,
+ &psEncConfig,
+ hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfSlots,
+ hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands
+ ,hSbrEncoder->dynamicRam
+ )))
+ {
+ errorInfo = handBack(errorInfo);
+ }
+ }
+ }
+
+ hSbrEncoder->downsampledOffset = downsampledOffset;
+ hSbrEncoder->downmixSize = coreFrameLength*(*numChannels);
+ hSbrEncoder->bufferOffset = sbrOffset;
+ /* Delay Compensation: fill bitstream delay buffer with zero input signal */
+ if ( hSbrEncoder->nBitstrDelay > 0 )
+ {
+ error = FDKsbrEnc_DelayCompensation (hSbrEncoder, inputBuffer);
+ if (error != 0)
+ goto bail;
+ }
+
+ /* Set Output frame length */
+ *frameLength = coreFrameLength*DOWN_SMPL_FAC;
+ /* Input buffer offset */
+ *inputBufferOffset = fixMax(sbrOffset, downsampledOffset);
+
+
+ }
+
+ return error;
+
+bail:
+ /* Restore input settings */
+ *sampleRate = inputSampleRate;
+ *frameLength = coreFrameLength;
+ *numChannels = inputChannels;
+ *coreBandwidth = inputBandWidth;
+
+ return error;
+ }
+
+
+INT
+sbrEncoder_EncodeFrame( HANDLE_SBR_ENCODER hSbrEncoder,
+ INT_PCM *samples,
+ UINT timeInStride,
+ UINT sbrDataBits[(6)],
+ UCHAR sbrData[(6)][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,
+ timeInStride,
+ &sbrDataBits[el],
+ sbrData[el],
+ 0
+ );
+ if (error)
+ return error;
+ }
+ }
+
+ if ( (hSbrEncoder->lfeChIdx!=-1) && (hSbrEncoder->fTimeDomainDownsampling) )
+ {
+ INT nOutSamples;
+
+ FDKaacEnc_Downsample(&hSbrEncoder->lfeDownSampler,
+ samples + hSbrEncoder->downsampledOffset + hSbrEncoder->bufferOffset + hSbrEncoder->lfeChIdx,
+ hSbrEncoder->frameSize,
+ timeInStride,
+ samples + hSbrEncoder->downsampledOffset + hSbrEncoder->lfeChIdx,
+ &nOutSamples,
+ hSbrEncoder->nChannels);
+ } /* lfe downsampler */
+
+ return 0;
+}
+
+
+INT sbrEncoder_UpdateBuffers(
+ HANDLE_SBR_ENCODER hSbrEncoder,
+ INT_PCM *timeBuffer
+ )
+ {
+ if ( hSbrEncoder->downsampledOffset > 0 ) {
+ /* Move delayed downsampled data */
+ FDKmemcpy ( timeBuffer,
+ timeBuffer + hSbrEncoder->downmixSize,
+ sizeof(INT_PCM) * (hSbrEncoder->downsampledOffset) );
+ } else {
+ /* Move delayed input data */
+ FDKmemcpy ( timeBuffer,
+ timeBuffer + hSbrEncoder->nChannels * hSbrEncoder->frameSize,
+ sizeof(INT_PCM) * hSbrEncoder->bufferOffset );
+ }
+ 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_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_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);
+ info->build_date = __DATE__;
+ info->build_time = __TIME__;
+ info->title = "SBR Encoder";
+
+ /* Set flags */
+ info->flags = 0
+ | CAPF_SBR_HQ
+ | CAPF_SBR_PS_MPEG
+ ;
+ /* End of flags */
+
+ return 0;
+}