diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2012-07-11 10:15:24 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2012-07-11 10:15:24 -0700 |
commit | 2228e360595641dd906bf1773307f43d304f5b2e (patch) | |
tree | 57f3d390ebb0782cc0de0fb984c8ea7e45b4f386 /libSBRenc/src/sbr_encoder.cpp | |
download | fdk-aac-2228e360595641dd906bf1773307f43d304f5b2e.tar.gz fdk-aac-2228e360595641dd906bf1773307f43d304f5b2e.tar.bz2 fdk-aac-2228e360595641dd906bf1773307f43d304f5b2e.zip |
Snapshot 2bda038c163298531d47394bc2c09e1409c5d0db
Change-Id: If584e579464f28b97d50e51fc76ba654a5536c54
Diffstat (limited to 'libSBRenc/src/sbr_encoder.cpp')
-rw-r--r-- | libSBRenc/src/sbr_encoder.cpp | 2237 |
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; +} |