diff options
author | Dave Burke <daveburke@google.com> | 2012-04-17 09:51:45 -0700 |
---|---|---|
committer | Dave Burke <daveburke@google.com> | 2012-04-17 23:04:43 -0700 |
commit | 9bf37cc9712506b2483650c82d3c41152337ef7e (patch) | |
tree | 77db44e2bae06e3d144b255628be2b7a55c581d3 /libSBRenc | |
parent | a37315fe10ee143d6d0b28c19d41a476a23e63ea (diff) | |
download | ODR-AudioEnc-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.gz ODR-AudioEnc-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.bz2 ODR-AudioEnc-9bf37cc9712506b2483650c82d3c41152337ef7e.zip |
Fraunhofer AAC codec.
License boilerplate update to follow.
Change-Id: I2810460c11a58b6d148d84673cc031f3685e79b5
Diffstat (limited to 'libSBRenc')
46 files changed, 20606 insertions, 0 deletions
diff --git a/libSBRenc/Android.mk b/libSBRenc/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/libSBRenc/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/libSBRenc/include/sbr_encoder.h b/libSBRenc/include/sbr_encoder.h new file mode 100644 index 0000000..d54582d --- /dev/null +++ b/libSBRenc/include/sbr_encoder.h @@ -0,0 +1,322 @@ +/*************************** Fraunhofer IIS *********************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): + Description: SBR encoder top level processing prototype + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __SBR_ENCODER_H +#define __SBR_ENCODER_H + +#include "common_fix.h" +#include "FDK_audio.h" + +#include "FDK_bitstream.h" + +/* core coder helpers */ +#define MAX_TRANS_FAC 8 +#define MAX_CODEC_FRAME_RATIO 2 +#define MAX_PAYLOAD_SIZE 256 + +typedef struct +{ + INT bitRate; + INT nChannels; + INT sampleFreq; + INT transFac; + INT standardBitrate; +} CODEC_PARAM; + +typedef enum +{ + SBR_MONO, + SBR_LEFT_RIGHT, + SBR_COUPLING, + SBR_SWITCH_LRC +} SBR_STEREO_MODE; + +/* bitstream syntax flags */ +enum +{ + SBR_SYNTAX_LOW_DELAY = 0x0001, + SBR_SYNTAX_SCALABLE = 0x0002, + SBR_SYNTAX_CRC = 0x0004, + SBR_SYNTAX_DRM_CRC = 0x0008 +}; + +typedef struct +{ + UINT bitrateFrom; /*!< inclusive */ + UINT bitrateTo; /*!< exclusive */ + + USHORT sampleRate; /*!< */ + UCHAR numChannels; /*!< */ + + UCHAR startFreq; /*!< bs_start_freq */ + UCHAR startFreqSpeech; /*!< bs_start_freq for speech config flag */ + UCHAR stopFreq; /*!< bs_stop_freq */ + UCHAR stopFreqSpeech; /*!< bs_stop_freq for speech config flag */ + + UCHAR numNoiseBands; /*!< */ + UCHAR noiseFloorOffset; /*!< */ + SCHAR noiseMaxLevel; /*!< */ + SBR_STEREO_MODE stereoMode; /*!< */ + UCHAR freqScale; /*!< */ +} sbrTuningTable_t; + +typedef struct sbrConfiguration +{ + /* + core coder dependent configurations + */ + CODEC_PARAM codecSettings; /*!< Core coder settings. To be set from core coder. */ + INT SendHeaderDataTime; /*!< SBR header send update frequency in ms. */ + INT useWaveCoding; /*!< Flag: usage of wavecoding tool. */ + INT crcSbr; /*!< Flag: usage of SBR-CRC. */ + INT dynBwSupported; /*!< Flag: support for dynamic bandwidth in this combination. */ + INT parametricCoding; /*!< Flag: usage of parametric coding tool. */ + int freq_res_fixfix[3]; /*!< Frequency resolution of envelopes in frame class FIXFIX + 0=1 Env; 1=2 Env; 2=4 Env; */ + /* + core coder dependent tuning parameters + */ + INT tran_thr; /*!< SBR transient detector threshold (* 100). */ + INT noiseFloorOffset; /*!< Noise floor offset. */ + UINT useSpeechConfig; /*!< Flag: adapt tuning parameters according to speech. */ + + + + /* + core coder independent configurations + */ + INT sbrFrameSize; /*!< SBR frame size in samples. Will be calculated from core coder settings. */ + INT sbr_data_extra; /*!< Flag usage of data extra. */ + INT amp_res; /*!< Amplitude resolution. */ + INT ana_max_level; /*!< Noise insertion maximum level. */ + INT tran_fc; /*!< Transient detector start frequency. */ + INT tran_det_mode; /*!< Transient detector mode. */ + INT spread; /*!< Flag: usage of SBR spread. */ + INT stat; /*!< Flag: usage of static framing. */ + INT e; /*!< Number of envelopes when static framing is chosen. */ + SBR_STEREO_MODE stereoMode; /*!< SBR stereo mode. */ + INT deltaTAcrossFrames; /*!< Flag: allow time-delta coding. */ + FIXP_DBL dF_edge_1stEnv; /*!< Extra fraction delta-F coding is allowed to be more expensive. */ + FIXP_DBL dF_edge_incr; /*!< Increment dF_edge_1stEnv this much if dT-coding was used this frame. */ + INT sbr_invf_mode; /*!< Inverse filtering mode. */ + INT sbr_xpos_mode; /*!< Transposer mode. */ + INT sbr_xpos_ctrl; /*!< Transposer control. */ + INT sbr_xpos_level; /*!< Transposer 3rd order level. */ + INT startFreq; /*!< The start frequency table index. */ + INT stopFreq; /*!< The stop frequency table index. */ + INT useSaPan; /*!< Flag: usage of SAPAN stereo. */ + INT dynBwEnabled; /*!< Flag: usage of dynamic bandwidth. */ + INT bParametricStereo; /*!< Flag: usage of parametric stereo coding tool. */ + INT bDownSampledSbr; /*!< Signal downsampled SBR is used. */ + + /* + header_extra1 configuration + */ + UCHAR freqScale; /*!< Frequency grouping. */ + INT alterScale; /*!< Scale resolution. */ + INT sbr_noise_bands; /*!< Number of noise bands. */ + + + /* + header_extra2 configuration + */ + INT sbr_limiter_bands; /*!< Number of limiter bands. */ + INT sbr_limiter_gains; /*!< Gain of limiter. */ + INT sbr_interpol_freq; /*!< Flag: use interpolation in freq. direction. */ + INT sbr_smoothing_length; /*!< Flag: choose length 4 or 0 (=on, off). */ + UCHAR init_amp_res_FF; +} sbrConfiguration, *sbrConfigurationPtr ; + +typedef struct +{ + UINT sbrSyntaxFlags; /**< SBR syntax flags derived from AOT. */ + INT nChannels; /**< Number of channels. */ + + INT nSfb[2]; /**< Number of SBR scalefactor bands for LO_RES and HI_RES (?) */ + INT num_Master; /**< Number of elements in v_k_master. */ + INT sampleFreq; /**< SBR sampling frequency. */ + INT frameSize; + INT xOverFreq; /**< The SBR start frequency. */ + INT dynXOverFreq; /**< Used crossover frequency when dynamic bandwidth is enabled. */ + INT noQmfBands; /**< Number of QMF frequency bands. */ + INT noQmfSlots; /**< Number of QMF slots. */ + + UCHAR *freqBandTable[2]; /**< Frequency table for low and hires, only MAX_FREQ_COEFFS/2 +1 coeefs actually needed for lowres. */ + UCHAR *v_k_master; /**< Master BandTable where freqBandTable is derived from. */ + + + SBR_STEREO_MODE stereoMode; + INT noEnvChannels; /**< Number of envelope channels. */ + + INT useWaveCoding; /**< Flag indicates whether to use wave coding at all. */ + INT useParametricCoding; /**< Flag indicates whether to use para coding at all. */ + INT xposCtrlSwitch; /**< Flag indicates whether to switch xpos ctrl on the fly. */ + INT switchTransposers; /**< Flag indicates whether to switch xpos on the fly . */ + UCHAR initAmpResFF; +} SBR_CONFIG_DATA; + +typedef SBR_CONFIG_DATA *HANDLE_SBR_CONFIG_DATA; + +typedef struct { + MP4_ELEMENT_ID elType; + INT bitRate; + int instanceTag; + UCHAR fParametricStereo; + UCHAR nChannelsInEl; + UCHAR ChannelIndex[2]; +} SBR_ELEMENT_INFO; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SBR_ENCODER *HANDLE_SBR_ENCODER; + +/** + * \brief Get the max required input buffer size including delay balancing space + * for N audio channels. + * \param noChannels Number of audio channels. + * \return Max required input buffer size in bytes. + */ +INT sbrEncoder_GetInBufferSize(int noChannels); + +INT sbrEncoder_Open( + HANDLE_SBR_ENCODER *phSbrEncoder, + INT nElements, + INT nChannels, + INT supportPS + ); + +/** + * \brief Initialize SBR Encoder instance. + * \param phSbrEncoder Pointer to a SBR Encoder instance. + * \param elInfo Structure that describes the element/channel arrangement. + * \param noElements Amount of elements described in elInfo. + * \param inputBuffer Pointer to the encoder audio buffer + * \param bandwidth Returns the core audio encoder bandwidth (output) + * \param bufferOffset Returns the offset for the audio input data in order to do delay balancing. + * \param numChannels Input: Encoder input channels. output: core encoder channels. + * \param sampleRate Input: Encoder samplerate. output core encoder samplerate. + * \param frameLength Input: Encoder frameLength. output core encoder frameLength. + * \param aot Input: Desired AOT. output AOT to be used after parameter checking. + * \param delay Input: core encoder delay. Output: total delay because of SBR. + * \param transformFactor The core encoder transform factor (blockswitching). + * \return 0 on success, and non-zero if failed. + */ +INT sbrEncoder_Init( HANDLE_SBR_ENCODER hSbrEncoder, + SBR_ELEMENT_INFO elInfo[(6)], + int noElements, + INT_PCM *inputBuffer, + INT *bandwidth, + INT *bufferOffset, + INT *numChannels, + INT *sampleRate, + INT *frameLength, + AUDIO_OBJECT_TYPE *aot, + int *delay, + int transformFactor, + ULONG statesInitFlag + ); + +/** + * \brief Do delay line buffers housekeeping. To be called after each encoded audio frame. + * \param hEnvEnc SBR Encoder handle. + * \param timeBuffer Pointer to the encoder audio buffer. + * \return 0 on success, and non-zero if failed. + */ +INT sbrEncoder_UpdateBuffers(HANDLE_SBR_ENCODER hEnvEnc, + INT_PCM *timeBuffer + ); + +/** + * \brief Close SBR encoder instance. + * \param phEbrEncoder Handle of SBR encoder instance to be closed. + * \return void + */ +void sbrEncoder_Close(HANDLE_SBR_ENCODER *phEbrEncoder); + +/** + * \brief Encode SBR data of one complete audio frame. + * \param hEnvEncoder Handle of SBR encoder instance. + * \param samples Time samples, always interleaved. + * \param timeInStride Channel stride factor of samples buffer. + * \param sbrDataBits Size of SBR payload in bits. + * \param sbrData SBR payload. + * \return 0 on success, and non-zero if failed. + */ +INT sbrEncoder_EncodeFrame(HANDLE_SBR_ENCODER hEnvEncoder, + INT_PCM *samples, + UINT timeInStride, + UINT sbrDataBits[(6)], + UCHAR sbrData[(6)][MAX_PAYLOAD_SIZE] + ); + +/** + * \brief Write SBR headers of one SBR element. + * \param sbrEncoder Handle of the SBR encoder instance. + * \param hBs Handle of bit stream handle to write SBR header to. + * \param element_index Index of the SBR element which header should be written. + * \param fSendHeaders Flag indicating that the SBR encoder should send more headers in the SBR payload or not. + * \return void + */ +void sbrEncoder_GetHeader(SBR_ENCODER *sbrEncoder, + HANDLE_FDK_BITSTREAM hBs, + INT element_index, + int fSendHeaders); + +/** + * \brief SBR encoder bitrate estimation. + * \param hSbrEncoder SBR encoder handle. + * \return Estimated bitrate. + */ +INT sbrEncoder_GetEstimateBitrate(HANDLE_SBR_ENCODER hSbrEncoder); + + +/** + * \brief Delay between input data and downsampled output data. + * \param hSbrEncoder SBR encoder handle. + * \return Delay. + */ +INT sbrEncoder_GetInputDataDelay(HANDLE_SBR_ENCODER hSbrEncoder); + +/** + * \brief Get decoder library version info. + * \param info Pointer to an allocated LIB_INFO struct, where library info is written to. + * \return 0 on sucess. + */ +INT sbrEncoder_GetLibInfo(LIB_INFO *info); + +void sbrPrintRAM(void); + +void sbrPrintROM(void); + +#ifdef __cplusplus + } +#endif + +#endif /* ifndef __SBR_MAIN_H */ diff --git a/libSBRenc/src/Android.mk b/libSBRenc/src/Android.mk new file mode 100644 index 0000000..55d5d4e --- /dev/null +++ b/libSBRenc/src/Android.mk @@ -0,0 +1,36 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := \ + bit_sbr.cpp \ + env_bit.cpp \ + fram_gen.cpp \ + mh_det.cpp \ + ps_bitenc.cpp \ + ps_encode.cpp \ + resampler.cpp \ + sbr_encoder.cpp \ + sbr_ram.cpp \ + ton_corr.cpp \ + code_env.cpp \ + env_est.cpp \ + invf_est.cpp \ + nf_est.cpp \ + psenc_hybrid.cpp \ + ps_main.cpp \ + sbrenc_freq_sca.cpp \ + sbr_misc.cpp \ + sbr_rom.cpp \ + tran_det.cpp + +LOCAL_CFLAGS := -DANDROID + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../../libFDK/include \ + $(LOCAL_PATH)/../../libSYS/include + +LOCAL_MODULE:= libSBRenc + +include $(BUILD_STATIC_LIBRARY) diff --git a/libSBRenc/src/bit_sbr.cpp b/libSBRenc/src/bit_sbr.cpp new file mode 100644 index 0000000..4088c35 --- /dev/null +++ b/libSBRenc/src/bit_sbr.cpp @@ -0,0 +1,1001 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief SBR bit writing routines $Revision: 36867 $ +*/ + + +#include "bit_sbr.h" + +#include "code_env.h" +#include "cmondata.h" +#include "sbr.h" + +#include "ps_main.h" + +typedef enum { + SBR_ID_SCE = 1, + SBR_ID_CPE +} SBR_ELEMENT_TYPE; + + +static INT encodeSbrData (HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_COMMON_DATA cmonData, + SBR_ELEMENT_TYPE sbrElem, + INT coupling, + UINT sbrSyntaxFlags); + +static INT encodeSbrHeader (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_COMMON_DATA cmonData); + + +static INT encodeSbrHeaderData (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_FDK_BITSTREAM hBitStream); + +static INT encodeSbrSingleChannelElement (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream + ,HANDLE_PARAMETRIC_STEREO hParametricStereo + ,UINT sbrSyntaxFlags + ); + + + +static INT encodeSbrChannelPairElement (HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitStream, + INT coupling); + + +static INT encodeSbrGrid (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream); + +static int encodeLowDelaySbrGrid ( HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, + int transmitFreqs); + +static INT encodeSbrDtdf (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream); + +static INT writeNoiseLevelData (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, + INT coupling); + +static INT writeEnvelopeData (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, + INT coupling); + +static INT writeSyntheticCodingData (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream); + + +static INT encodeExtendedData (HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitStream); + + + +static INT getSbrExtendedDataSize (HANDLE_PARAMETRIC_STEREO hParametricStereo); + +/***************************************************************************** + + functionname: FDKsbrEnc_WriteEnvSingleChannelElement + description: writes pure SBR single channel data element + returns: number of bits written + input: + output: + +*****************************************************************************/ +INT +FDKsbrEnc_WriteEnvSingleChannelElement( + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_COMMON_DATA cmonData, + UINT sbrSyntaxFlags + ) + +{ + INT payloadBits = 0; + + cmonData->sbrHdrBits = 0; + cmonData->sbrDataBits = 0; + + /* write pure sbr data */ + if (sbrEnvData != NULL) { + + /* write header */ + payloadBits += encodeSbrHeader (sbrHeaderData, + sbrBitstreamData, + cmonData); + + + /* write data */ + payloadBits += encodeSbrData (sbrEnvData, + NULL, + hParametricStereo, + cmonData, + SBR_ID_SCE, + 0, + sbrSyntaxFlags); + + } + return payloadBits; +} + +/***************************************************************************** + + functionname: FDKsbrEnc_WriteEnvChannelPairElement + description: writes pure SBR channel pair data element + returns: number of bits written + input: + output: + +*****************************************************************************/ +INT +FDKsbrEnc_WriteEnvChannelPairElement (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_COMMON_DATA cmonData, + UINT sbrSyntaxFlags) + +{ + INT payloadBits = 0; + cmonData->sbrHdrBits = 0; + cmonData->sbrDataBits = 0; + + /* write pure sbr data */ + if ((sbrEnvDataLeft != NULL) && (sbrEnvDataRight != NULL)) { + + /* write header */ + payloadBits += encodeSbrHeader (sbrHeaderData, + sbrBitstreamData, + cmonData); + + /* write data */ + payloadBits += encodeSbrData (sbrEnvDataLeft, + sbrEnvDataRight, + hParametricStereo, + cmonData, + SBR_ID_CPE, + sbrHeaderData->coupling, + sbrSyntaxFlags); + + } + return payloadBits; +} + +INT +FDKsbrEnc_CountSbrChannelPairElement (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_COMMON_DATA cmonData, + UINT sbrSyntaxFlags) +{ + INT payloadBits; + INT bitPos = FDKgetValidBits(&cmonData->sbrBitbuf); + + payloadBits = FDKsbrEnc_WriteEnvChannelPairElement(sbrHeaderData, + hParametricStereo, + sbrBitstreamData, + sbrEnvDataLeft, + sbrEnvDataRight, + cmonData, + sbrSyntaxFlags); + + FDKpushBack(&cmonData->sbrBitbuf, (FDKgetValidBits(&cmonData->sbrBitbuf) - bitPos) ); + + return payloadBits; +} + + +void sbrEncoder_GetHeader(SBR_ENCODER *sbrEncoder, + HANDLE_FDK_BITSTREAM hBs, + INT element_index, + int fSendHeaders) +{ + int bits; + + bits = encodeSbrHeaderData (&sbrEncoder->sbrElement[element_index]->sbrHeaderData, hBs); + + if (fSendHeaders == 0) { + /* Prevent header being embedded into the SBR payload. */ + sbrEncoder->sbrElement[element_index]->sbrBitstreamData.NrSendHeaderData = -1; + sbrEncoder->sbrElement[element_index]->sbrBitstreamData.HeaderActive = 0; + sbrEncoder->sbrElement[element_index]->sbrBitstreamData.CountSendHeaderData = -1; + } +} + + +/***************************************************************************** + + functionname: encodeSbrHeader + description: encodes SBR Header information + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +encodeSbrHeader (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_COMMON_DATA cmonData) +{ + INT payloadBits = 0; + + if (sbrBitstreamData->HeaderActive) { + payloadBits += FDKwriteBits (&cmonData->sbrBitbuf, 1, 1); + payloadBits += encodeSbrHeaderData (sbrHeaderData, + &cmonData->sbrBitbuf); + } + else { + payloadBits += FDKwriteBits (&cmonData->sbrBitbuf, 0, 1); + } + + cmonData->sbrHdrBits = payloadBits; + + return payloadBits; +} + + + +/***************************************************************************** + + functionname: encodeSbrHeaderData + description: writes sbr_header() + bs_protocol_version through bs_header_extra_2 + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +encodeSbrHeaderData (HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_FDK_BITSTREAM hBitStream) + +{ + INT payloadBits = 0; + if (sbrHeaderData != NULL) { + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_amp_res, + SI_SBR_AMP_RES_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_start_frequency, + SI_SBR_START_FREQ_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_stop_frequency, + SI_SBR_STOP_FREQ_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_xover_band, + SI_SBR_XOVER_BAND_BITS); + + payloadBits += FDKwriteBits (hBitStream, 0, + SI_SBR_RESERVED_BITS); + + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->header_extra_1, + SI_SBR_HEADER_EXTRA_1_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->header_extra_2, + SI_SBR_HEADER_EXTRA_2_BITS); + + + if (sbrHeaderData->header_extra_1) { + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->freqScale, + SI_SBR_FREQ_SCALE_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->alterScale, + SI_SBR_ALTER_SCALE_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_noise_bands, + SI_SBR_NOISE_BANDS_BITS); + } /* sbrHeaderData->header_extra_1 */ + + if (sbrHeaderData->header_extra_2) { + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_limiter_bands, + SI_SBR_LIMITER_BANDS_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_limiter_gains, + SI_SBR_LIMITER_GAINS_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_interpol_freq, + SI_SBR_INTERPOL_FREQ_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrHeaderData->sbr_smoothing_length, + SI_SBR_SMOOTHING_LENGTH_BITS); + + } /* sbrHeaderData->header_extra_2 */ + } /* sbrHeaderData != NULL */ + + return payloadBits; +} + + +/***************************************************************************** + + functionname: encodeSbrData + description: encodes sbr Data information + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +encodeSbrData (HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_COMMON_DATA cmonData, + SBR_ELEMENT_TYPE sbrElem, + INT coupling, + UINT sbrSyntaxFlags) +{ + INT payloadBits = 0; + + switch (sbrElem) { + case SBR_ID_SCE: + payloadBits += encodeSbrSingleChannelElement (sbrEnvDataLeft, &cmonData->sbrBitbuf, hParametricStereo, sbrSyntaxFlags); + break; + case SBR_ID_CPE: + payloadBits += encodeSbrChannelPairElement (sbrEnvDataLeft, sbrEnvDataRight, hParametricStereo, &cmonData->sbrBitbuf, coupling); + break; + default: + /* we never should apply SBR to any other element type */ + FDK_ASSERT (0); + } + + cmonData->sbrDataBits = payloadBits; + + return payloadBits; +} + +#define MODE_FREQ_TANS 1 +#define MODE_NO_FREQ_TRAN 0 +#define LD_TRANSMISSION MODE_FREQ_TANS +static int encodeFreqs (int mode) { + return ((mode & MODE_FREQ_TANS) ? 1 : 0); +} + + +/***************************************************************************** + + functionname: encodeSbrSingleChannelElement + description: encodes sbr SCE information + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +encodeSbrSingleChannelElement (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream + ,HANDLE_PARAMETRIC_STEREO hParametricStereo + ,UINT sbrSyntaxFlags + ) +{ + INT i, payloadBits = 0; + + payloadBits += FDKwriteBits (hBitStream, 0, SI_SBR_DATA_EXTRA_BITS); /* no reserved bits */ + + if (sbrEnvData->ldGrid) { + if ( sbrEnvData->hSbrBSGrid->frameClass != FIXFIXonly ) { + /* encode normal SbrGrid */ + payloadBits += encodeSbrGrid (sbrEnvData, hBitStream); + } else { + /* use FIXFIXonly frame Grid */ + payloadBits += encodeLowDelaySbrGrid ( sbrEnvData, hBitStream, encodeFreqs(LD_TRANSMISSION)); + } + } + else + { + if (sbrSyntaxFlags & SBR_SYNTAX_SCALABLE) { + payloadBits += FDKwriteBits (hBitStream, 1, SI_SBR_COUPLING_BITS); + } + payloadBits += encodeSbrGrid (sbrEnvData, hBitStream); + } + + payloadBits += encodeSbrDtdf (sbrEnvData, hBitStream); + + for (i = 0; i < sbrEnvData->noOfnoisebands; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->sbr_invf_mode_vec[i], SI_SBR_INVF_MODE_BITS); + } + + payloadBits += writeEnvelopeData (sbrEnvData, hBitStream, 0); + payloadBits += writeNoiseLevelData (sbrEnvData, hBitStream, 0); + + payloadBits += writeSyntheticCodingData (sbrEnvData,hBitStream); + + payloadBits += encodeExtendedData(hParametricStereo, hBitStream); + + return payloadBits; +} + + +/***************************************************************************** + + functionname: encodeSbrChannelPairElement + description: encodes sbr CPE information + returns: + input: + output: + +*****************************************************************************/ +static INT +encodeSbrChannelPairElement (HANDLE_SBR_ENV_DATA sbrEnvDataLeft, + HANDLE_SBR_ENV_DATA sbrEnvDataRight, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitStream, + INT coupling) +{ + INT payloadBits = 0; + INT i = 0; + + payloadBits += FDKwriteBits (hBitStream, 0, SI_SBR_DATA_EXTRA_BITS); /* no reserved bits */ + + payloadBits += FDKwriteBits (hBitStream, coupling, SI_SBR_COUPLING_BITS); + + if (coupling) { + if (sbrEnvDataLeft->ldGrid) { + if ( sbrEnvDataLeft->hSbrBSGrid->frameClass != FIXFIXonly ) { + /* normal SbrGrid */ + payloadBits += encodeSbrGrid (sbrEnvDataLeft, hBitStream); + + } else { + /* FIXFIXonly frame Grid */ + payloadBits += encodeLowDelaySbrGrid ( sbrEnvDataLeft, hBitStream, encodeFreqs(LD_TRANSMISSION)); + } + } else + payloadBits += encodeSbrGrid (sbrEnvDataLeft, hBitStream); + + payloadBits += encodeSbrDtdf (sbrEnvDataLeft, hBitStream); + payloadBits += encodeSbrDtdf (sbrEnvDataRight, hBitStream); + + for (i = 0; i < sbrEnvDataLeft->noOfnoisebands; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvDataLeft->sbr_invf_mode_vec[i], SI_SBR_INVF_MODE_BITS); + } + + payloadBits += writeEnvelopeData (sbrEnvDataLeft, hBitStream,1); + payloadBits += writeNoiseLevelData (sbrEnvDataLeft, hBitStream,1); + payloadBits += writeEnvelopeData (sbrEnvDataRight, hBitStream,1); + payloadBits += writeNoiseLevelData (sbrEnvDataRight, hBitStream,1); + + payloadBits += writeSyntheticCodingData (sbrEnvDataLeft,hBitStream); + payloadBits += writeSyntheticCodingData (sbrEnvDataRight,hBitStream); + + } else { /* no coupling */ + FDK_ASSERT(sbrEnvDataLeft->ldGrid == sbrEnvDataRight->ldGrid); + + if (sbrEnvDataLeft->ldGrid || sbrEnvDataRight->ldGrid) { + /* sbrEnvDataLeft (left channel) */ + if ( sbrEnvDataLeft->hSbrBSGrid->frameClass != FIXFIXonly) { + /* no FIXFIXonly Frame so we dont need encodeLowDelaySbrGrid */ + /* normal SbrGrid */ + payloadBits += encodeSbrGrid (sbrEnvDataLeft, hBitStream); + + } else { + /* FIXFIXonly frame Grid */ + payloadBits += encodeLowDelaySbrGrid ( sbrEnvDataLeft, hBitStream, encodeFreqs(LD_TRANSMISSION)); + } + + /* sbrEnvDataRight (right channel) */ + if ( sbrEnvDataRight->hSbrBSGrid->frameClass != FIXFIXonly) { + /* no FIXFIXonly Frame so we dont need encodeLowDelaySbrGrid */ + /* normal SbrGrid */ + payloadBits += encodeSbrGrid (sbrEnvDataRight, hBitStream); + + } else { + /* FIXFIXonly frame Grid */ + payloadBits += encodeLowDelaySbrGrid ( sbrEnvDataRight, hBitStream, encodeFreqs(LD_TRANSMISSION)); + } + } else + { + payloadBits += encodeSbrGrid (sbrEnvDataLeft, hBitStream); + payloadBits += encodeSbrGrid (sbrEnvDataRight, hBitStream); + } + payloadBits += encodeSbrDtdf (sbrEnvDataLeft, hBitStream); + payloadBits += encodeSbrDtdf (sbrEnvDataRight, hBitStream); + + for (i = 0; i < sbrEnvDataLeft->noOfnoisebands; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvDataLeft->sbr_invf_mode_vec[i], + SI_SBR_INVF_MODE_BITS); + } + for (i = 0; i < sbrEnvDataRight->noOfnoisebands; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvDataRight->sbr_invf_mode_vec[i], + SI_SBR_INVF_MODE_BITS); + } + + payloadBits += writeEnvelopeData (sbrEnvDataLeft, hBitStream,0); + payloadBits += writeEnvelopeData (sbrEnvDataRight, hBitStream,0); + payloadBits += writeNoiseLevelData (sbrEnvDataLeft, hBitStream,0); + payloadBits += writeNoiseLevelData (sbrEnvDataRight, hBitStream,0); + + payloadBits += writeSyntheticCodingData (sbrEnvDataLeft,hBitStream); + payloadBits += writeSyntheticCodingData (sbrEnvDataRight,hBitStream); + + } /* coupling */ + + payloadBits += encodeExtendedData(hParametricStereo, hBitStream); + + return payloadBits; +} + +static INT ceil_ln2(INT x) +{ + INT tmp=-1; + while((1<<++tmp) < x); + return(tmp); +} + + +/***************************************************************************** + + functionname: encodeSbrGrid + description: if hBitStream != NULL writes bits that describes the + time/frequency grouping of a frame; else counts them only + returns: number of bits written or counted + input: + output: + +*****************************************************************************/ +static INT +encodeSbrGrid (HANDLE_SBR_ENV_DATA sbrEnvData, HANDLE_FDK_BITSTREAM hBitStream) +{ + INT payloadBits = 0; + INT i, temp; + INT bufferFrameStart = sbrEnvData->hSbrBSGrid->bufferFrameStart; + INT numberTimeSlots = sbrEnvData->hSbrBSGrid->numberTimeSlots; + + if (sbrEnvData->ldGrid) + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hSbrBSGrid->frameClass, + SBR_CLA_BITS_LD); + else + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hSbrBSGrid->frameClass, + SBR_CLA_BITS); + + switch (sbrEnvData->hSbrBSGrid->frameClass) { + case FIXFIXonly: + FDK_ASSERT(0 /* Fatal error in encodeSbrGrid! */); + break; + case FIXFIX: + temp = ceil_ln2(sbrEnvData->hSbrBSGrid->bs_num_env); + payloadBits += FDKwriteBits (hBitStream, temp, SBR_ENV_BITS); + if ((sbrEnvData->ldGrid) && (sbrEnvData->hSbrBSGrid->bs_num_env==1)) + payloadBits += FDKwriteBits(hBitStream, sbrEnvData->currentAmpResFF, SI_SBR_AMP_RES_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->v_f[0], SBR_RES_BITS); + + break; + + case FIXVAR: + case VARFIX: + if (sbrEnvData->hSbrBSGrid->frameClass == FIXVAR) + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord - (bufferFrameStart + numberTimeSlots); + else + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord - bufferFrameStart; + + payloadBits += FDKwriteBits (hBitStream, temp, SBR_ABS_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->n, SBR_NUM_BITS); + + for (i = 0; i < sbrEnvData->hSbrBSGrid->n; i++) { + temp = (sbrEnvData->hSbrBSGrid->bs_rel_bord[i] - 2) >> 1; + payloadBits += FDKwriteBits (hBitStream, temp, SBR_REL_BITS); + } + + temp = ceil_ln2(sbrEnvData->hSbrBSGrid->n + 2); + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->p, temp); + + for (i = 0; i < sbrEnvData->hSbrBSGrid->n + 1; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->v_f[i], + SBR_RES_BITS); + } + break; + + case VARVAR: + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord_0 - bufferFrameStart; + payloadBits += FDKwriteBits (hBitStream, temp, SBR_ABS_BITS); + temp = sbrEnvData->hSbrBSGrid->bs_abs_bord_1 - (bufferFrameStart + numberTimeSlots); + payloadBits += FDKwriteBits (hBitStream, temp, SBR_ABS_BITS); + + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->bs_num_rel_0, SBR_NUM_BITS); + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->bs_num_rel_1, SBR_NUM_BITS); + + for (i = 0; i < sbrEnvData->hSbrBSGrid->bs_num_rel_0; i++) { + temp = (sbrEnvData->hSbrBSGrid->bs_rel_bord_0[i] - 2) >> 1; + payloadBits += FDKwriteBits (hBitStream, temp, SBR_REL_BITS); + } + + for (i = 0; i < sbrEnvData->hSbrBSGrid->bs_num_rel_1; i++) { + temp = (sbrEnvData->hSbrBSGrid->bs_rel_bord_1[i] - 2) >> 1; + payloadBits += FDKwriteBits (hBitStream, temp, SBR_REL_BITS); + } + + temp = ceil_ln2(sbrEnvData->hSbrBSGrid->bs_num_rel_0 + + sbrEnvData->hSbrBSGrid->bs_num_rel_1 + 2); + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->p, temp); + + temp = sbrEnvData->hSbrBSGrid->bs_num_rel_0 + + sbrEnvData->hSbrBSGrid->bs_num_rel_1 + 1; + + for (i = 0; i < temp; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->v_fLR[i], + SBR_RES_BITS); + } + break; + } + + return payloadBits; +} + +#define SBR_CLA_BITS_LD 1 +/***************************************************************************** + + functionname: encodeLowDelaySbrGrid + description: if hBitStream != NULL writes bits that describes the + time/frequency grouping of a frame; + else counts them only + (this function only write the FIXFIXonly Bitstream data) + returns: number of bits written or counted + input: + output: + +*****************************************************************************/ +static int +encodeLowDelaySbrGrid ( HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream, + int transmitFreqs + ) +{ + int payloadBits = 0; + int i; + + /* write FIXFIXonly Grid */ + /* write frameClass [1 bit] for FIXFIXonly Grid */ + payloadBits += FDKwriteBits(hBitStream, 1, SBR_CLA_BITS_LD); + + /* absolute Borders are fix: 0,X,X,X,nTimeSlots; so we dont have to transmit them */ + /* only transmit the transient position! */ + /* with this info (b1) we can reconstruct the Frame on Decoder side : */ + /* border[0] = 0; border[1] = b1; border[2]=b1+2; border[3] = nrTimeSlots */ + + /* use 3 or 4bits for transient border (border) */ + if (sbrEnvData->hSbrBSGrid->numberTimeSlots == 8) + payloadBits += FDKwriteBits ( hBitStream, sbrEnvData->hSbrBSGrid->bs_abs_bord, 3); + else + payloadBits += FDKwriteBits ( hBitStream, sbrEnvData->hSbrBSGrid->bs_abs_bord, 4); + + if (transmitFreqs) { + /* write FreqRes grid */ + for (i = 0; i < sbrEnvData->hSbrBSGrid->bs_num_env; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->hSbrBSGrid->v_f[i], SBR_RES_BITS); + } + } + + return payloadBits; +} + +/***************************************************************************** + + functionname: encodeSbrDtdf + description: writes bits that describes the direction of the envelopes of a frame + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +encodeSbrDtdf (HANDLE_SBR_ENV_DATA sbrEnvData, HANDLE_FDK_BITSTREAM hBitStream) +{ + INT i, payloadBits = 0, noOfNoiseEnvelopes; + + noOfNoiseEnvelopes = sbrEnvData->noOfEnvelopes > 1 ? 2 : 1; + + for (i = 0; i < sbrEnvData->noOfEnvelopes; ++i) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->domain_vec[i], SBR_DIR_BITS); + } + for (i = 0; i < noOfNoiseEnvelopes; ++i) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->domain_vec_noise[i], SBR_DIR_BITS); + } + + return payloadBits; +} + + +/***************************************************************************** + + functionname: writeNoiseLevelData + description: writes bits corresponding to the noise-floor-level + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +writeNoiseLevelData (HANDLE_SBR_ENV_DATA sbrEnvData, HANDLE_FDK_BITSTREAM hBitStream, INT coupling) +{ + INT j, i, payloadBits = 0; + INT nNoiseEnvelopes = sbrEnvData->noOfEnvelopes > 1 ? 2 : 1; + + for (i = 0; i < nNoiseEnvelopes; i++) { + switch (sbrEnvData->domain_vec_noise[i]) { + case FREQ: + if (coupling && sbrEnvData->balance) { + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->sbr_noise_levels[i * sbrEnvData->noOfnoisebands], + sbrEnvData->si_sbr_start_noise_bits_balance); + } else { + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->sbr_noise_levels[i * sbrEnvData->noOfnoisebands], + sbrEnvData->si_sbr_start_noise_bits); + } + + for (j = 1 + i * sbrEnvData->noOfnoisebands; j < (sbrEnvData->noOfnoisebands * (1 + i)); j++) { + if (coupling) { + if (sbrEnvData->balance) { + /* coupling && balance */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseBalanceFreqC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11], + sbrEnvData->hufftableNoiseBalanceFreqL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11]); + } else { + /* coupling && !balance */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseLevelFreqC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11], + sbrEnvData->hufftableNoiseLevelFreqL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11]); + } + } else { + /* !coupling */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseFreqC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11], + sbrEnvData->hufftableNoiseFreqL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11]); + } + } + break; + + case TIME: + for (j = i * sbrEnvData->noOfnoisebands; j < (sbrEnvData->noOfnoisebands * (1 + i)); j++) { + if (coupling) { + if (sbrEnvData->balance) { + /* coupling && balance */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseBalanceTimeC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11], + sbrEnvData->hufftableNoiseBalanceTimeL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV_BALANCE11]); + } else { + /* coupling && !balance */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseLevelTimeC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11], + sbrEnvData->hufftableNoiseLevelTimeL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11]); + } + } else { + /* !coupling */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableNoiseLevelTimeC[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11], + sbrEnvData->hufftableNoiseLevelTimeL[sbrEnvData->sbr_noise_levels[j] + + CODE_BOOK_SCF_LAV11]); + } + } + break; + } + } + return payloadBits; +} + + +/***************************************************************************** + + functionname: writeEnvelopeData + description: writes bits corresponding to the envelope + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT +writeEnvelopeData (HANDLE_SBR_ENV_DATA sbrEnvData, HANDLE_FDK_BITSTREAM hBitStream, INT coupling) +{ + INT payloadBits = 0, j, i, delta; + + for (j = 0; j < sbrEnvData->noOfEnvelopes; j++) { /* loop over all envelopes */ + if (sbrEnvData->domain_vec[j] == FREQ) { + if (coupling && sbrEnvData->balance) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->ienvelope[j][0], sbrEnvData->si_sbr_start_env_bits_balance); + } else { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->ienvelope[j][0], sbrEnvData->si_sbr_start_env_bits); + } + } + + for (i = 1 - sbrEnvData->domain_vec[j]; i < sbrEnvData->noScfBands[j]; i++) { + delta = sbrEnvData->ienvelope[j][i]; + if (coupling && sbrEnvData->balance) { + FDK_ASSERT (fixp_abs (delta) <= sbrEnvData->codeBookScfLavBalance); + } else { + FDK_ASSERT (fixp_abs (delta) <= sbrEnvData->codeBookScfLav); + } + if (coupling) { + if (sbrEnvData->balance) { + if (sbrEnvData->domain_vec[j]) { + /* coupling && balance && TIME */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableBalanceTimeC[delta + sbrEnvData->codeBookScfLavBalance], + sbrEnvData->hufftableBalanceTimeL[delta + sbrEnvData->codeBookScfLavBalance]); + } else { + /* coupling && balance && FREQ */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableBalanceFreqC[delta + sbrEnvData->codeBookScfLavBalance], + sbrEnvData->hufftableBalanceFreqL[delta + sbrEnvData->codeBookScfLavBalance]); + } + } else { + if (sbrEnvData->domain_vec[j]) { + /* coupling && !balance && TIME */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableLevelTimeC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData->hufftableLevelTimeL[delta + sbrEnvData->codeBookScfLav]); + } else { + /* coupling && !balance && FREQ */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableLevelFreqC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData->hufftableLevelFreqL[delta + sbrEnvData->codeBookScfLav]); + } + } + } else { + if (sbrEnvData->domain_vec[j]) { + /* !coupling && TIME */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableTimeC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData->hufftableTimeL[delta + sbrEnvData->codeBookScfLav]); + } else { + /* !coupling && FREQ */ + payloadBits += FDKwriteBits (hBitStream, + sbrEnvData->hufftableFreqC[delta + sbrEnvData->codeBookScfLav], + sbrEnvData->hufftableFreqL[delta + sbrEnvData->codeBookScfLav]); + } + } + } + } + return payloadBits; +} + + +/***************************************************************************** + + functionname: encodeExtendedData + description: writes bits corresponding to the extended data + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT encodeExtendedData (HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitStream) +{ + INT extDataSize; + INT payloadBits = 0; + + extDataSize = getSbrExtendedDataSize(hParametricStereo); + + + if (extDataSize != 0) { + INT maxExtSize = (1<<SI_SBR_EXTENSION_SIZE_BITS) - 1; + INT writtenNoBits = 0; /* needed to byte align the extended data */ + + payloadBits += FDKwriteBits (hBitStream, 1, SI_SBR_EXTENDED_DATA_BITS); + FDK_ASSERT(extDataSize <= SBR_EXTENDED_DATA_MAX_CNT); + + if (extDataSize < maxExtSize) { + payloadBits += FDKwriteBits (hBitStream, extDataSize, SI_SBR_EXTENSION_SIZE_BITS); + } else { + payloadBits += FDKwriteBits (hBitStream, maxExtSize, SI_SBR_EXTENSION_SIZE_BITS); + payloadBits += FDKwriteBits (hBitStream, extDataSize - maxExtSize, SI_SBR_EXTENSION_ESC_COUNT_BITS); + } + + /* parametric coding signalled here? */ + if(hParametricStereo){ + writtenNoBits += FDKwriteBits (hBitStream, EXTENSION_ID_PS_CODING, SI_SBR_EXTENSION_ID_BITS); + writtenNoBits += FDKsbrEnc_PSEnc_WritePSData(hParametricStereo, hBitStream); + } + + payloadBits += writtenNoBits; + + /* byte alignment */ + writtenNoBits = writtenNoBits%8; + if(writtenNoBits) + payloadBits += FDKwriteBits(hBitStream, 0, (8 - writtenNoBits)); + } else { + payloadBits += FDKwriteBits (hBitStream, 0, SI_SBR_EXTENDED_DATA_BITS); + } + + return payloadBits; +} + + +/***************************************************************************** + + functionname: writeSyntheticCodingData + description: writes bits corresponding to the "synthetic-coding"-extension + returns: number of bits written + input: + output: + +*****************************************************************************/ +static INT writeSyntheticCodingData (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_FDK_BITSTREAM hBitStream) + +{ + INT i; + INT payloadBits = 0; + + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->addHarmonicFlag, 1); + + if (sbrEnvData->addHarmonicFlag) { + for (i = 0; i < sbrEnvData->noHarmonics; i++) { + payloadBits += FDKwriteBits (hBitStream, sbrEnvData->addHarmonic[i], 1); + } + } + + return payloadBits; +} + +/***************************************************************************** + + functionname: getSbrExtendedDataSize + description: counts the number of bits needed for encoding the + extended data (including extension id) + + returns: number of bits needed for the extended data + input: + output: + +*****************************************************************************/ +static INT +getSbrExtendedDataSize (HANDLE_PARAMETRIC_STEREO hParametricStereo) +{ + INT extDataBits = 0; + + /* add your new extended data counting methods here */ + + /* + no extended data + */ + + if(hParametricStereo){ + /* PS extended data */ + extDataBits += SI_SBR_EXTENSION_ID_BITS; + extDataBits += FDKsbrEnc_PSEnc_WritePSData(hParametricStereo, NULL); + } + + return (extDataBits+7) >> 3; +} + + + + + diff --git a/libSBRenc/src/bit_sbr.h b/libSBRenc/src/bit_sbr.h new file mode 100644 index 0000000..1cda60b --- /dev/null +++ b/libSBRenc/src/bit_sbr.h @@ -0,0 +1,203 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief SBR bit writing $Revision: 36867 $ +*/ +#ifndef __BIT_SBR_H +#define __BIT_SBR_H + +#include "sbr_def.h" +#include "cmondata.h" +#include "fram_gen.h" + +struct SBR_ENV_DATA; + +struct SBR_BITSTREAM_DATA +{ + INT TotalBits; + INT PayloadBits; + INT FillBits; + INT HeaderActive; + INT NrSendHeaderData; /**< input from commandline */ + INT CountSendHeaderData; /**< modulo count. If < 0 then no counting is done (no SBR headers) */ +}; + +typedef struct SBR_BITSTREAM_DATA *HANDLE_SBR_BITSTREAM_DATA; + +struct SBR_HEADER_DATA +{ + AMP_RES sbr_amp_res; + INT sbr_start_frequency; + INT sbr_stop_frequency; + INT sbr_xover_band; + INT sbr_noise_bands; + INT sbr_data_extra; + INT header_extra_1; + INT header_extra_2; + INT sbr_lc_stereo_mode; + INT sbr_limiter_bands; + INT sbr_limiter_gains; + INT sbr_interpol_freq; + INT sbr_smoothing_length; + INT alterScale; + INT freqScale; + + /* + element of sbrdata + */ + SR_MODE sampleRateMode; + + /* + element of channelpairelement + */ + INT coupling; + INT prev_coupling; + + /* + element of singlechannelelement + */ + +}; +typedef struct SBR_HEADER_DATA *HANDLE_SBR_HEADER_DATA; + +struct SBR_ENV_DATA +{ + + INT sbr_xpos_ctrl; + INT freq_res_fixfix; + + + INVF_MODE sbr_invf_mode; + INVF_MODE sbr_invf_mode_vec[MAX_NUM_NOISE_VALUES]; + + XPOS_MODE sbr_xpos_mode; + + INT ienvelope[MAX_ENVELOPES][MAX_FREQ_COEFFS]; + + INT codeBookScfLavBalance; + INT codeBookScfLav; + const INT *hufftableTimeC; + const INT *hufftableFreqC; + const UCHAR *hufftableTimeL; + const UCHAR *hufftableFreqL; + + const INT *hufftableLevelTimeC; + const INT *hufftableBalanceTimeC; + const INT *hufftableLevelFreqC; + const INT *hufftableBalanceFreqC; + const UCHAR *hufftableLevelTimeL; + const UCHAR *hufftableBalanceTimeL; + const UCHAR *hufftableLevelFreqL; + const UCHAR *hufftableBalanceFreqL; + + + const UCHAR *hufftableNoiseTimeL; + const INT *hufftableNoiseTimeC; + const UCHAR *hufftableNoiseFreqL; + const INT *hufftableNoiseFreqC; + + const UCHAR *hufftableNoiseLevelTimeL; + const INT *hufftableNoiseLevelTimeC; + const UCHAR *hufftableNoiseBalanceTimeL; + const INT *hufftableNoiseBalanceTimeC; + const UCHAR *hufftableNoiseLevelFreqL; + const INT *hufftableNoiseLevelFreqC; + const UCHAR *hufftableNoiseBalanceFreqL; + const INT *hufftableNoiseBalanceFreqC; + + HANDLE_SBR_GRID hSbrBSGrid; + + INT noHarmonics; + INT addHarmonicFlag; + UCHAR addHarmonic[MAX_FREQ_COEFFS]; + + + /* calculated helper vars */ + INT si_sbr_start_env_bits_balance; + INT si_sbr_start_env_bits; + INT si_sbr_start_noise_bits_balance; + INT si_sbr_start_noise_bits; + + INT noOfEnvelopes; + INT noScfBands[MAX_ENVELOPES]; + INT domain_vec[MAX_ENVELOPES]; + INT domain_vec_noise[MAX_ENVELOPES]; + SCHAR sbr_noise_levels[MAX_FREQ_COEFFS]; + INT noOfnoisebands; + + INT balance; + AMP_RES init_sbr_amp_res; + AMP_RES currentAmpResFF; + + /* extended data */ + INT extended_data; + INT extension_size; + INT extension_id; + UCHAR extended_data_buffer[SBR_EXTENDED_DATA_MAX_CNT]; + + UCHAR ldGrid; +}; +typedef struct SBR_ENV_DATA *HANDLE_SBR_ENV_DATA; + + + +INT FDKsbrEnc_WriteEnvSingleChannelElement(struct SBR_HEADER_DATA *sbrHeaderData, + struct T_PARAMETRIC_STEREO *hParametricStereo, + struct SBR_BITSTREAM_DATA *sbrBitstreamData, + struct SBR_ENV_DATA *sbrEnvData, + struct COMMON_DATA *cmonData, + UINT sbrSyntaxFlags); + + +INT FDKsbrEnc_WriteEnvChannelPairElement(struct SBR_HEADER_DATA *sbrHeaderData, + struct T_PARAMETRIC_STEREO *hParametricStereo, + struct SBR_BITSTREAM_DATA *sbrBitstreamData, + struct SBR_ENV_DATA *sbrEnvDataLeft, + struct SBR_ENV_DATA *sbrEnvDataRight, + struct COMMON_DATA *cmonData, + UINT sbrSyntaxFlags); + + + +INT FDKsbrEnc_CountSbrChannelPairElement (struct SBR_HEADER_DATA *sbrHeaderData, + struct T_PARAMETRIC_STEREO *hParametricStereo, + struct SBR_BITSTREAM_DATA *sbrBitstreamData, + struct SBR_ENV_DATA *sbrEnvDataLeft, + struct SBR_ENV_DATA *sbrEnvDataRight, + struct COMMON_DATA *cmonData, + UINT sbrSyntaxFlags); + + + +/* debugging and tuning functions */ + +/*#define SBR_ENV_STATISTICS */ + + +/*#define SBR_PAYLOAD_MONITOR*/ + +#endif diff --git a/libSBRenc/src/cmondata.h b/libSBRenc/src/cmondata.h new file mode 100644 index 0000000..b5f1c85 --- /dev/null +++ b/libSBRenc/src/cmondata.h @@ -0,0 +1,52 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief Core Coder's and SBR's shared data structure definition $Revision: 36847 $ +*/ +#ifndef __SBR_CMONDATA_H +#define __SBR_CMONDATA_H + +#include "FDK_bitstream.h" + + +struct COMMON_DATA { + INT sbrHdrBits; /**< number of SBR header bits */ + INT sbrDataBits; /**< number of SBR data bits */ + INT sbrFillBits; /**< number of SBR fill bits */ + FDK_BITSTREAM sbrBitbuf; /**< the SBR data bitbuffer */ + FDK_BITSTREAM tmpWriteBitbuf; /**< helper var for writing header*/ + INT xOverFreq; /**< the SBR crossover frequency */ + INT dynBwEnabled; /**< indicates if dynamic bandwidth is enabled */ + INT sbrNumChannels; /**< number of channels (meaning mono or stereo) */ + INT dynXOverFreqEnc; /**< encoder dynamic crossover frequency */ +}; + +typedef struct COMMON_DATA *HANDLE_COMMON_DATA; + + + +#endif diff --git a/libSBRenc/src/code_env.cpp b/libSBRenc/src/code_env.cpp new file mode 100644 index 0000000..430b868 --- /dev/null +++ b/libSBRenc/src/code_env.cpp @@ -0,0 +1,584 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "code_env.h" +#include "sbr_rom.h" + +/***************************************************************************** + + functionname: FDKsbrEnc_InitSbrHuffmanTables + description: initializes Huffman Tables dependent on chosen amp_res + returns: error handle + input: + output: + +*****************************************************************************/ +INT +FDKsbrEnc_InitSbrHuffmanTables (HANDLE_SBR_ENV_DATA sbrEnvData, + HANDLE_SBR_CODE_ENVELOPE henv, + HANDLE_SBR_CODE_ENVELOPE hnoise, + AMP_RES amp_res) +{ + if ( (!henv) || (!hnoise) || (!sbrEnvData) ) + return (1); /* not init. */ + + sbrEnvData->init_sbr_amp_res = amp_res; + + switch (amp_res) { + case SBR_AMP_RES_3_0: + /*envelope data*/ + + /*Level/Pan - coding */ + sbrEnvData->hufftableLevelTimeC = v_Huff_envelopeLevelC11T; + sbrEnvData->hufftableLevelTimeL = v_Huff_envelopeLevelL11T; + sbrEnvData->hufftableBalanceTimeC = bookSbrEnvBalanceC11T; + sbrEnvData->hufftableBalanceTimeL = bookSbrEnvBalanceL11T; + + sbrEnvData->hufftableLevelFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableLevelFreqL = v_Huff_envelopeLevelL11F; + sbrEnvData->hufftableBalanceFreqC = bookSbrEnvBalanceC11F; + sbrEnvData->hufftableBalanceFreqL = bookSbrEnvBalanceL11F; + + /*Right/Left - coding */ + sbrEnvData->hufftableTimeC = v_Huff_envelopeLevelC11T; + sbrEnvData->hufftableTimeL = v_Huff_envelopeLevelL11T; + sbrEnvData->hufftableFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableFreqL = v_Huff_envelopeLevelL11F; + + sbrEnvData->codeBookScfLavBalance = CODE_BOOK_SCF_LAV_BALANCE11; + sbrEnvData->codeBookScfLav = CODE_BOOK_SCF_LAV11; + + sbrEnvData->si_sbr_start_env_bits = SI_SBR_START_ENV_BITS_AMP_RES_3_0; + sbrEnvData->si_sbr_start_env_bits_balance = SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_3_0; + break; + + case SBR_AMP_RES_1_5: + /*envelope data*/ + + /*Level/Pan - coding */ + sbrEnvData->hufftableLevelTimeC = v_Huff_envelopeLevelC10T; + sbrEnvData->hufftableLevelTimeL = v_Huff_envelopeLevelL10T; + sbrEnvData->hufftableBalanceTimeC = bookSbrEnvBalanceC10T; + sbrEnvData->hufftableBalanceTimeL = bookSbrEnvBalanceL10T; + + sbrEnvData->hufftableLevelFreqC = v_Huff_envelopeLevelC10F; + sbrEnvData->hufftableLevelFreqL = v_Huff_envelopeLevelL10F; + sbrEnvData->hufftableBalanceFreqC = bookSbrEnvBalanceC10F; + sbrEnvData->hufftableBalanceFreqL = bookSbrEnvBalanceL10F; + + /*Right/Left - coding */ + sbrEnvData->hufftableTimeC = v_Huff_envelopeLevelC10T; + sbrEnvData->hufftableTimeL = v_Huff_envelopeLevelL10T; + sbrEnvData->hufftableFreqC = v_Huff_envelopeLevelC10F; + sbrEnvData->hufftableFreqL = v_Huff_envelopeLevelL10F; + + sbrEnvData->codeBookScfLavBalance = CODE_BOOK_SCF_LAV_BALANCE10; + sbrEnvData->codeBookScfLav = CODE_BOOK_SCF_LAV10; + + sbrEnvData->si_sbr_start_env_bits = SI_SBR_START_ENV_BITS_AMP_RES_1_5; + sbrEnvData->si_sbr_start_env_bits_balance = SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_1_5; + break; + + default: + return (1); /* undefined amp_res mode */ + } + + /* these are common to both amp_res values */ + /*Noise data*/ + + /*Level/Pan - coding */ + sbrEnvData->hufftableNoiseLevelTimeC = v_Huff_NoiseLevelC11T; + sbrEnvData->hufftableNoiseLevelTimeL = v_Huff_NoiseLevelL11T; + sbrEnvData->hufftableNoiseBalanceTimeC = bookSbrNoiseBalanceC11T; + sbrEnvData->hufftableNoiseBalanceTimeL = bookSbrNoiseBalanceL11T; + + sbrEnvData->hufftableNoiseLevelFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableNoiseLevelFreqL = v_Huff_envelopeLevelL11F; + sbrEnvData->hufftableNoiseBalanceFreqC = bookSbrEnvBalanceC11F; + sbrEnvData->hufftableNoiseBalanceFreqL = bookSbrEnvBalanceL11F; + + + /*Right/Left - coding */ + sbrEnvData->hufftableNoiseTimeC = v_Huff_NoiseLevelC11T; + sbrEnvData->hufftableNoiseTimeL = v_Huff_NoiseLevelL11T; + sbrEnvData->hufftableNoiseFreqC = v_Huff_envelopeLevelC11F; + sbrEnvData->hufftableNoiseFreqL = v_Huff_envelopeLevelL11F; + + sbrEnvData->si_sbr_start_noise_bits = SI_SBR_START_NOISE_BITS_AMP_RES_3_0; + sbrEnvData->si_sbr_start_noise_bits_balance = SI_SBR_START_NOISE_BITS_BALANCE_AMP_RES_3_0; + + + /* init envelope tables and codebooks */ + henv->codeBookScfLavBalanceTime = sbrEnvData->codeBookScfLavBalance; + henv->codeBookScfLavBalanceFreq = sbrEnvData->codeBookScfLavBalance; + henv->codeBookScfLavLevelTime = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavLevelFreq = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavTime = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavFreq = sbrEnvData->codeBookScfLav; + + henv->hufftableLevelTimeL = sbrEnvData->hufftableLevelTimeL; + henv->hufftableBalanceTimeL = sbrEnvData->hufftableBalanceTimeL; + henv->hufftableTimeL = sbrEnvData->hufftableTimeL; + henv->hufftableLevelFreqL = sbrEnvData->hufftableLevelFreqL; + henv->hufftableBalanceFreqL = sbrEnvData->hufftableBalanceFreqL; + henv->hufftableFreqL = sbrEnvData->hufftableFreqL; + + henv->codeBookScfLavFreq = sbrEnvData->codeBookScfLav; + henv->codeBookScfLavTime = sbrEnvData->codeBookScfLav; + + henv->start_bits = sbrEnvData->si_sbr_start_env_bits; + henv->start_bits_balance = sbrEnvData->si_sbr_start_env_bits_balance; + + + /* init noise tables and codebooks */ + + hnoise->codeBookScfLavBalanceTime = CODE_BOOK_SCF_LAV_BALANCE11; + hnoise->codeBookScfLavBalanceFreq = CODE_BOOK_SCF_LAV_BALANCE11; + hnoise->codeBookScfLavLevelTime = CODE_BOOK_SCF_LAV11; + hnoise->codeBookScfLavLevelFreq = CODE_BOOK_SCF_LAV11; + hnoise->codeBookScfLavTime = CODE_BOOK_SCF_LAV11; + hnoise->codeBookScfLavFreq = CODE_BOOK_SCF_LAV11; + + hnoise->hufftableLevelTimeL = sbrEnvData->hufftableNoiseLevelTimeL; + hnoise->hufftableBalanceTimeL = sbrEnvData->hufftableNoiseBalanceTimeL; + hnoise->hufftableTimeL = sbrEnvData->hufftableNoiseTimeL; + hnoise->hufftableLevelFreqL = sbrEnvData->hufftableNoiseLevelFreqL; + hnoise->hufftableBalanceFreqL = sbrEnvData->hufftableNoiseBalanceFreqL; + hnoise->hufftableFreqL = sbrEnvData->hufftableNoiseFreqL; + + + hnoise->start_bits = sbrEnvData->si_sbr_start_noise_bits; + hnoise->start_bits_balance = sbrEnvData->si_sbr_start_noise_bits_balance; + + /* No delta coding in time from the previous frame due to 1.5dB FIx-FIX rule */ + henv->upDate = 0; + hnoise->upDate = 0; + return (0); +} + +/******************************************************************************* + Functionname: indexLow2High + ******************************************************************************* + + Description: Nice small patch-functions in order to cope with non-factor-2 + ratios between high-res and low-res + + Arguments: INT offset, INT index, FREQ_RES res + + Return: INT + +*******************************************************************************/ +static INT indexLow2High(INT offset, INT index, FREQ_RES res) +{ + + if(res == FREQ_RES_LOW) + { + if (offset >= 0) + { + if (index < offset) + return(index); + else + return(2*index - offset); + } + else + { + offset = -offset; + if (index < offset) + return(2*index+index); + else + return(2*index + offset); + } + } + else + return(index); +} + + + +/******************************************************************************* + Functionname: mapLowResEnergyVal + ******************************************************************************* + + Description: + + Arguments: INT currVal,INT* prevData, INT offset, INT index, FREQ_RES res + + Return: none + +*******************************************************************************/ +static void mapLowResEnergyVal(SCHAR currVal, SCHAR* prevData, INT offset, INT index, FREQ_RES res) +{ + + if(res == FREQ_RES_LOW) + { + if (offset >= 0) + { + if(index < offset) + prevData[index] = currVal; + else + { + prevData[2*index - offset] = currVal; + prevData[2*index+1 - offset] = currVal; + } + } + else + { + offset = -offset; + if (index < offset) + { + prevData[3*index] = currVal; + prevData[3*index+1] = currVal; + prevData[3*index+2] = currVal; + } + else + { + prevData[2*index + offset] = currVal; + prevData[2*index + 1 + offset] = currVal; + } + } + } + else + prevData[index] = currVal; +} + + + +/******************************************************************************* + Functionname: computeBits + ******************************************************************************* + + Description: + + Arguments: INT delta, + INT codeBookScfLavLevel, + INT codeBookScfLavBalance, + const UCHAR * hufftableLevel, + const UCHAR * hufftableBalance, INT coupling, INT channel) + + Return: INT + +*******************************************************************************/ +static INT +computeBits (SCHAR *delta, + INT codeBookScfLavLevel, + INT codeBookScfLavBalance, + const UCHAR * hufftableLevel, + const UCHAR * hufftableBalance, INT coupling, INT channel) +{ + INT index; + INT delta_bits = 0; + + if (coupling) { + if (channel == 1) + { + if (*delta < 0) + index = fixMax(*delta, -codeBookScfLavBalance); + else + index = fixMin(*delta, codeBookScfLavBalance); + + if (index != *delta) { + *delta = index; + return (10000); + } + + delta_bits = hufftableBalance[index + codeBookScfLavBalance]; + } + else { + if (*delta < 0) + index = fixMax(*delta, -codeBookScfLavLevel); + else + index = fixMin(*delta, codeBookScfLavLevel); + + if (index != *delta) { + *delta = index; + return (10000); + } + delta_bits = hufftableLevel[index + codeBookScfLavLevel]; + } + } + else { + if (*delta < 0) + index = fixMax(*delta, -codeBookScfLavLevel); + else + index = fixMin(*delta, codeBookScfLavLevel); + + if (index != *delta) { + *delta = index; + return (10000); + } + delta_bits = hufftableLevel[index + codeBookScfLavLevel]; + } + + return (delta_bits); +} + + + + +/******************************************************************************* + Functionname: FDKsbrEnc_codeEnvelope + ******************************************************************************* + + Description: + + Arguments: INT *sfb_nrg, + const FREQ_RES *freq_res, + SBR_CODE_ENVELOPE * h_sbrCodeEnvelope, + INT *directionVec, INT scalable, INT nEnvelopes, INT channel, + INT headerActive) + + Return: none + h_sbrCodeEnvelope->sfb_nrg_prev is modified ! + sfb_nrg is modified + h_sbrCodeEnvelope->update is modfied ! + *directionVec is modified + +*******************************************************************************/ +void +FDKsbrEnc_codeEnvelope(SCHAR *sfb_nrg, + const FREQ_RES *freq_res, + SBR_CODE_ENVELOPE *h_sbrCodeEnvelope, + INT *directionVec, + INT coupling, + INT nEnvelopes, + INT channel, + INT headerActive) +{ + INT i, no_of_bands, band; + FIXP_DBL tmp1,tmp2,tmp3,dF_edge_1stEnv; + SCHAR *ptr_nrg; + + INT codeBookScfLavLevelTime; + INT codeBookScfLavLevelFreq; + INT codeBookScfLavBalanceTime; + INT codeBookScfLavBalanceFreq; + const UCHAR *hufftableLevelTimeL; + const UCHAR *hufftableBalanceTimeL; + const UCHAR *hufftableLevelFreqL; + const UCHAR *hufftableBalanceFreqL; + + INT offset = h_sbrCodeEnvelope->offset; + INT envDataTableCompFactor; + + INT delta_F_bits = 0, delta_T_bits = 0; + INT use_dT; + + SCHAR delta_F[MAX_FREQ_COEFFS]; + SCHAR delta_T[MAX_FREQ_COEFFS]; + SCHAR last_nrg, curr_nrg; + + tmp1 = FL2FXCONST_DBL(0.5f) >> (DFRACT_BITS-16-1); + tmp2 = h_sbrCodeEnvelope->dF_edge_1stEnv >> (DFRACT_BITS-16); + tmp3 = (FIXP_DBL)(((INT)(LONG)h_sbrCodeEnvelope->dF_edge_incr*h_sbrCodeEnvelope->dF_edge_incr_fac) >> (DFRACT_BITS-16)); + + dF_edge_1stEnv = tmp1 + tmp2 + tmp3; + + if (coupling) { + codeBookScfLavLevelTime = h_sbrCodeEnvelope->codeBookScfLavLevelTime; + codeBookScfLavLevelFreq = h_sbrCodeEnvelope->codeBookScfLavLevelFreq; + codeBookScfLavBalanceTime = h_sbrCodeEnvelope->codeBookScfLavBalanceTime; + codeBookScfLavBalanceFreq = h_sbrCodeEnvelope->codeBookScfLavBalanceFreq; + hufftableLevelTimeL = h_sbrCodeEnvelope->hufftableLevelTimeL; + hufftableBalanceTimeL = h_sbrCodeEnvelope->hufftableBalanceTimeL; + hufftableLevelFreqL = h_sbrCodeEnvelope->hufftableLevelFreqL; + hufftableBalanceFreqL = h_sbrCodeEnvelope->hufftableBalanceFreqL; + } + else { + codeBookScfLavLevelTime = h_sbrCodeEnvelope->codeBookScfLavTime; + codeBookScfLavLevelFreq = h_sbrCodeEnvelope->codeBookScfLavFreq; + codeBookScfLavBalanceTime = h_sbrCodeEnvelope->codeBookScfLavTime; + codeBookScfLavBalanceFreq = h_sbrCodeEnvelope->codeBookScfLavFreq; + hufftableLevelTimeL = h_sbrCodeEnvelope->hufftableTimeL; + hufftableBalanceTimeL = h_sbrCodeEnvelope->hufftableTimeL; + hufftableLevelFreqL = h_sbrCodeEnvelope->hufftableFreqL; + hufftableBalanceFreqL = h_sbrCodeEnvelope->hufftableFreqL; + } + + if(coupling == 1 && channel == 1) + envDataTableCompFactor = 1; /*should be one when the new huffman-tables are ready*/ + else + envDataTableCompFactor = 0; + + + if (h_sbrCodeEnvelope->deltaTAcrossFrames == 0) + h_sbrCodeEnvelope->upDate = 0; + + /* no delta coding in time in case of a header */ + if (headerActive) + h_sbrCodeEnvelope->upDate = 0; + + + for (i = 0; i < nEnvelopes; i++) + { + if (freq_res[i] == FREQ_RES_HIGH) + no_of_bands = h_sbrCodeEnvelope->nSfb[FREQ_RES_HIGH]; + else + no_of_bands = h_sbrCodeEnvelope->nSfb[FREQ_RES_LOW]; + + + ptr_nrg = sfb_nrg; + curr_nrg = *ptr_nrg; + + delta_F[0] = curr_nrg >> envDataTableCompFactor; + + if (coupling && channel == 1) + delta_F_bits = h_sbrCodeEnvelope->start_bits_balance; + else + delta_F_bits = h_sbrCodeEnvelope->start_bits; + + + if(h_sbrCodeEnvelope->upDate != 0) + { + delta_T[0] = (curr_nrg - h_sbrCodeEnvelope->sfb_nrg_prev[0]) >> envDataTableCompFactor; + + delta_T_bits = computeBits (&delta_T[0], + codeBookScfLavLevelTime, + codeBookScfLavBalanceTime, + hufftableLevelTimeL, + hufftableBalanceTimeL, coupling, channel); + } + + + mapLowResEnergyVal(curr_nrg, h_sbrCodeEnvelope->sfb_nrg_prev, offset, 0, freq_res[i]); + + /* ensure that nrg difference is not higher than codeBookScfLavXXXFreq */ + if ( coupling && channel == 1 ) { + for (band = no_of_bands - 1; band > 0; band--) { + if ( ptr_nrg[band] - ptr_nrg[band-1] > codeBookScfLavBalanceFreq ) { + ptr_nrg[band-1] = ptr_nrg[band] - codeBookScfLavBalanceFreq; + } + } + for (band = 1; band < no_of_bands; band++) { + if ( ptr_nrg[band-1] - ptr_nrg[band] > codeBookScfLavBalanceFreq ) { + ptr_nrg[band] = ptr_nrg[band-1] - codeBookScfLavBalanceFreq; + } + } + } + else { + for (band = no_of_bands - 1; band > 0; band--) { + if ( ptr_nrg[band] - ptr_nrg[band-1] > codeBookScfLavLevelFreq ) { + ptr_nrg[band-1] = ptr_nrg[band] - codeBookScfLavLevelFreq; + } + } + for (band = 1; band < no_of_bands; band++) { + if ( ptr_nrg[band-1] - ptr_nrg[band] > codeBookScfLavLevelFreq ) { + ptr_nrg[band] = ptr_nrg[band-1] - codeBookScfLavLevelFreq; + } + } + } + + + /* Coding loop*/ + for (band = 1; band < no_of_bands; band++) + { + last_nrg = (*ptr_nrg); + ptr_nrg++; + curr_nrg = (*ptr_nrg); + + delta_F[band] = (curr_nrg - last_nrg) >> envDataTableCompFactor; + + delta_F_bits += computeBits (&delta_F[band], + codeBookScfLavLevelFreq, + codeBookScfLavBalanceFreq, + hufftableLevelFreqL, + hufftableBalanceFreqL, coupling, channel); + + if(h_sbrCodeEnvelope->upDate != 0) + { + delta_T[band] = curr_nrg - h_sbrCodeEnvelope->sfb_nrg_prev[indexLow2High(offset, band, freq_res[i])]; + delta_T[band] = delta_T[band] >> envDataTableCompFactor; + } + + mapLowResEnergyVal(curr_nrg, h_sbrCodeEnvelope->sfb_nrg_prev, offset, band, freq_res[i]); + + if(h_sbrCodeEnvelope->upDate != 0) + { + delta_T_bits += computeBits (&delta_T[band], + codeBookScfLavLevelTime, + codeBookScfLavBalanceTime, + hufftableLevelTimeL, + hufftableBalanceTimeL, coupling, channel); + } + } + + /* Replace sfb_nrg with deltacoded samples and set flag */ + if (i == 0) { + INT tmp_bits; + tmp_bits = (((delta_T_bits * dF_edge_1stEnv) >> (DFRACT_BITS-18)) + (FIXP_DBL)1) >> 1; + use_dT = (h_sbrCodeEnvelope->upDate != 0 && (delta_F_bits > tmp_bits)); + } + else + use_dT = (delta_T_bits < delta_F_bits && h_sbrCodeEnvelope->upDate != 0); + + if (use_dT) + { + directionVec[i] = TIME; + FDKmemcpy (sfb_nrg, delta_T, no_of_bands * sizeof (SCHAR)); + } + else { + h_sbrCodeEnvelope->upDate = 0; + directionVec[i] = FREQ; + FDKmemcpy (sfb_nrg, delta_F, no_of_bands * sizeof (SCHAR)); + } + sfb_nrg += no_of_bands; + h_sbrCodeEnvelope->upDate = 1; + } + +} + + +/******************************************************************************* + Functionname: FDKsbrEnc_InitSbrCodeEnvelope + ******************************************************************************* + + Description: + + Arguments: + + Return: + +*******************************************************************************/ +INT +FDKsbrEnc_InitSbrCodeEnvelope (HANDLE_SBR_CODE_ENVELOPE h_sbrCodeEnvelope, + INT *nSfb, + INT deltaTAcrossFrames, + FIXP_DBL dF_edge_1stEnv, + FIXP_DBL dF_edge_incr) +{ + + FDKmemclear(h_sbrCodeEnvelope,sizeof(SBR_CODE_ENVELOPE)); + + h_sbrCodeEnvelope->deltaTAcrossFrames = deltaTAcrossFrames; + h_sbrCodeEnvelope->dF_edge_1stEnv = dF_edge_1stEnv; + h_sbrCodeEnvelope->dF_edge_incr = dF_edge_incr; + h_sbrCodeEnvelope->dF_edge_incr_fac = 0; + h_sbrCodeEnvelope->upDate = 0; + h_sbrCodeEnvelope->nSfb[FREQ_RES_LOW] = nSfb[FREQ_RES_LOW]; + h_sbrCodeEnvelope->nSfb[FREQ_RES_HIGH] = nSfb[FREQ_RES_HIGH]; + h_sbrCodeEnvelope->offset = 2*h_sbrCodeEnvelope->nSfb[FREQ_RES_LOW] - h_sbrCodeEnvelope->nSfb[FREQ_RES_HIGH]; + + return (0); +} diff --git a/libSBRenc/src/code_env.h b/libSBRenc/src/code_env.h new file mode 100644 index 0000000..debcd65 --- /dev/null +++ b/libSBRenc/src/code_env.h @@ -0,0 +1,97 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief DPCM Envelope coding $Revision: 36867 $ +*/ + +#ifndef __CODE_ENV_H +#define __CODE_ENV_H + +#include "sbr_def.h" +#include "bit_sbr.h" +#include "fram_gen.h" + +typedef struct +{ + INT offset; + INT upDate; + INT nSfb[2]; + SCHAR sfb_nrg_prev[MAX_FREQ_COEFFS]; + INT deltaTAcrossFrames; + FIXP_DBL dF_edge_1stEnv; + FIXP_DBL dF_edge_incr; + INT dF_edge_incr_fac; + + + INT codeBookScfLavTime; + INT codeBookScfLavFreq; + + INT codeBookScfLavLevelTime; + INT codeBookScfLavLevelFreq; + INT codeBookScfLavBalanceTime; + INT codeBookScfLavBalanceFreq; + + INT start_bits; + INT start_bits_balance; + + + const UCHAR *hufftableTimeL; + const UCHAR *hufftableFreqL; + + const UCHAR *hufftableLevelTimeL; + const UCHAR *hufftableBalanceTimeL; + const UCHAR *hufftableLevelFreqL; + const UCHAR *hufftableBalanceFreqL; +} +SBR_CODE_ENVELOPE; +typedef SBR_CODE_ENVELOPE *HANDLE_SBR_CODE_ENVELOPE; + + + +void +FDKsbrEnc_codeEnvelope (SCHAR *sfb_nrg, + const FREQ_RES *freq_res, + SBR_CODE_ENVELOPE * h_sbrCodeEnvelope, + INT *directionVec, INT coupling, INT nEnvelopes, INT channel, + INT headerActive); + +INT +FDKsbrEnc_InitSbrCodeEnvelope (HANDLE_SBR_CODE_ENVELOPE h_sbrCodeEnvelope, + INT *nSfb, + INT deltaTAcrossFrames, + FIXP_DBL dF_edge_1stEnv, + FIXP_DBL dF_edge_incr); + +/* void deleteSbrCodeEnvelope (HANDLE_SBR_CODE_ENVELOPE h_sbrCodeEnvelope); */ + +INT +FDKsbrEnc_InitSbrHuffmanTables (struct SBR_ENV_DATA* sbrEnvData, + HANDLE_SBR_CODE_ENVELOPE henv, + HANDLE_SBR_CODE_ENVELOPE hnoise, + AMP_RES amp_res); + +#endif diff --git a/libSBRenc/src/env_bit.cpp b/libSBRenc/src/env_bit.cpp new file mode 100644 index 0000000..1f8c48f --- /dev/null +++ b/libSBRenc/src/env_bit.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Remaining SBR Bit Writing Routines +*/ + +#include "env_bit.h" +#include "cmondata.h" + + +#ifndef min +#define min(a,b) ( a < b ? a:b) +#endif + +#ifndef max +#define max(a,b) ( a > b ? a:b) +#endif + +/* ***************************** crcAdvance **********************************/ +/** + * @fn + * @brief updates crc data register + * @return none + * + * This function updates the crc register + * + */ +static void crcAdvance(USHORT crcPoly, + USHORT crcMask, + USHORT *crc, + ULONG bValue, + INT bBits + ) +{ + INT i; + USHORT flag; + + for (i=bBits-1; i>=0; i--) { + flag = ((*crc) & crcMask) ? (1) : (0) ; + flag ^= (bValue & (1<<i)) ? (1) : (0) ; + + (*crc)<<=1; + if(flag) (*crc) ^= crcPoly; + } +} + + +/* ***************************** FDKsbrEnc_InitSbrBitstream **********************************/ +/** + * @fn + * @brief Inittialisation of sbr bitstream, write of dummy header and CRC + * @return none + * + * + * + */ + +INT FDKsbrEnc_InitSbrBitstream(HANDLE_COMMON_DATA hCmonData, + UCHAR *memoryBase, /*!< Pointer to bitstream buffer */ + INT memorySize, /*!< Length of bitstream buffer in bytes */ + HANDLE_FDK_CRCINFO hCrcInfo, + UINT sbrSyntaxFlags) /*!< SBR syntax flags */ +{ + INT crcRegion = 0; + + /* reset bit buffer */ + FDKresetBitbuffer(&hCmonData->sbrBitbuf, BS_WRITER); + + FDKinitBitStream(&hCmonData->tmpWriteBitbuf, memoryBase, + memorySize, 0, BS_WRITER); + + if (sbrSyntaxFlags & SBR_SYNTAX_CRC) { + if (sbrSyntaxFlags & SBR_SYNTAX_DRM_CRC) + { /* Init and start CRC region */ + FDKwriteBits (&hCmonData->sbrBitbuf, 0x0, SI_SBR_DRM_CRC_BITS); + FDKcrcInit( hCrcInfo, 0x001d, 0xFFFF, SI_SBR_DRM_CRC_BITS ); + crcRegion = FDKcrcStartReg( hCrcInfo, &hCmonData->sbrBitbuf, 0 ); + } else { + FDKwriteBits (&hCmonData->sbrBitbuf, 0x0, SI_SBR_CRC_BITS); + } + } + + return (crcRegion); +} + + +/* ************************** FDKsbrEnc_AssembleSbrBitstream *******************************/ +/** + * @fn + * @brief Formats the SBR payload + * @return nothing + * + * Also the CRC will be calculated here. + * + */ + +void +FDKsbrEnc_AssembleSbrBitstream( HANDLE_COMMON_DATA hCmonData, + HANDLE_FDK_CRCINFO hCrcInfo, + INT crcRegion, + UINT sbrSyntaxFlags) +{ + USHORT crcReg = SBR_CRCINIT; + INT numCrcBits,i; + + /* check if SBR is present */ + if ( hCmonData==NULL ) + return; + + hCmonData->sbrFillBits = 0; /* Fill bits are written only for GA streams */ + + if ( sbrSyntaxFlags & SBR_SYNTAX_DRM_CRC ) + { + /* + * Calculate and write DRM CRC + */ + FDKcrcEndReg( hCrcInfo, &hCmonData->sbrBitbuf, crcRegion ); + FDKwriteBits( &hCmonData->tmpWriteBitbuf, FDKcrcGetCRC(hCrcInfo)^0xFF, SI_SBR_DRM_CRC_BITS ); + } + else + { + if ( !(sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) ) + { + /* Do alignment here, because its defined as part of the sbr_extension_data */ + int sbrLoad = hCmonData->sbrHdrBits + hCmonData->sbrDataBits; + + if ( sbrSyntaxFlags & SBR_SYNTAX_CRC ) { + sbrLoad += SI_SBR_CRC_BITS; + } + + sbrLoad += 4; /* Do byte Align with 4 bit offset. ISO/IEC 14496-3:2005(E) page 39. */ + + hCmonData->sbrFillBits = (8 - (sbrLoad % 8)) % 8; + + /* + append fill bits + */ + FDKwriteBits(&hCmonData->sbrBitbuf, 0, hCmonData->sbrFillBits ); + + FDK_ASSERT(FDKgetValidBits(&hCmonData->sbrBitbuf) % 8 == 4); + } + + /* + calculate crc + */ + if ( sbrSyntaxFlags & SBR_SYNTAX_CRC ) { + FDK_BITSTREAM tmpCRCBuf = hCmonData->sbrBitbuf; + FDKresetBitbuffer( &tmpCRCBuf, BS_READER ); + + numCrcBits = hCmonData->sbrHdrBits + hCmonData->sbrDataBits + hCmonData->sbrFillBits; + + for(i=0;i<numCrcBits;i++){ + INT bit; + bit = FDKreadBits(&tmpCRCBuf,1); + crcAdvance(SBR_CRC_POLY,SBR_CRC_MASK,&crcReg,bit,1); + } + crcReg &= (SBR_CRC_RANGE); + + /* + * Write CRC data. + */ + FDKwriteBits (&hCmonData->tmpWriteBitbuf, crcReg, SI_SBR_CRC_BITS); + } + } + + FDKsyncCache(&hCmonData->tmpWriteBitbuf); +} + diff --git a/libSBRenc/src/env_bit.h b/libSBRenc/src/env_bit.h new file mode 100644 index 0000000..60d9990 --- /dev/null +++ b/libSBRenc/src/env_bit.h @@ -0,0 +1,68 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Remaining SBR Bit Writing Routines +*/ + +#ifndef BIT_ENV_H +#define BIT_ENV_H + +#include "sbr_encoder.h" +#include "FDK_crc.h" + +/* G(x) = x^10 + x^9 + x^5 + x^4 + x + 1 */ +#define SBR_CRC_POLY (0x0233) +#define SBR_CRC_MASK (0x0200) +#define SBR_CRC_RANGE (0x03FF) +#define SBR_CRC_MAXREGS 1 +#define SBR_CRCINIT (0x0) + + +#define SI_SBR_CRC_ENABLE_BITS 0 +#define SI_SBR_CRC_BITS 10 +#define SI_SBR_DRM_CRC_BITS 8 + + +struct COMMON_DATA; + +INT FDKsbrEnc_InitSbrBitstream(struct COMMON_DATA *hCmonData, + UCHAR *memoryBase, + INT memorySize, + HANDLE_FDK_CRCINFO hCrcInfo, + UINT sbrSyntaxFlags); + +void +FDKsbrEnc_AssembleSbrBitstream (struct COMMON_DATA *hCmonData, + HANDLE_FDK_CRCINFO hCrcInfo, + INT crcReg, + UINT sbrSyntaxFlags); + + + + + +#endif /* #ifndef BIT_ENV_H */ diff --git a/libSBRenc/src/env_est.cpp b/libSBRenc/src/env_est.cpp new file mode 100644 index 0000000..0b7f7b0 --- /dev/null +++ b/libSBRenc/src/env_est.cpp @@ -0,0 +1,1834 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +#include "env_est.h" +#include "tran_det.h" + +#include "qmf.h" + +#include "fram_gen.h" +#include "bit_sbr.h" +#include "cmondata.h" +#include "sbr_ram.h" + + +#include "genericStds.h" + +#define QUANT_ERROR_THRES 200 +#define Y_NRG_SCALE 5 /* noCols = 32 -> shift(5) */ + + +static const UCHAR panTable[2][10] = { { 0, 2, 4, 6, 8,12,16,20,24}, + { 0, 2, 4, 8,12, 0, 0, 0, 0 } }; +static const UCHAR maxIndex[2] = {9, 5}; + + +/***************************************************************************/ +/*! + + \brief Calculates energy form real and imaginary part of + the QMF subsamples + + \return none + +****************************************************************************/ +LNK_SECTION_CODE_L1 +static void +FDKsbrEnc_getEnergyFromCplxQmfData(FIXP_DBL **RESTRICT energyValues,/*!< the result of the operation */ + FIXP_DBL **RESTRICT realValues, /*!< the real part of the QMF subsamples */ + FIXP_DBL **RESTRICT imagValues, /*!< the imaginary part of the QMF subsamples */ + INT numberBands, /*!< number of QMF bands */ + INT numberCols, /*!< number of QMF subsamples */ + INT *qmfScale, /*!< sclefactor of QMF subsamples */ + INT *energyScale) /*!< scalefactor of energies */ +{ + int j, k; + int scale; + FIXP_DBL max_val = FL2FXCONST_DBL(0.0f); + + /* Get Scratch buffer */ + C_ALLOC_SCRATCH_START(tmpNrg, FIXP_DBL, QMF_CHANNELS*QMF_MAX_TIME_SLOTS/2); + + FDK_ASSERT(numberBands <= QMF_CHANNELS); + FDK_ASSERT(numberCols <= QMF_MAX_TIME_SLOTS); + + /* Get max possible scaling of QMF data */ + scale = DFRACT_BITS; + for (k=0; k<numberCols; k++) { + scale = fixMin(scale, fixMin(getScalefactor(realValues[k], numberBands), getScalefactor(imagValues[k], numberBands))); + } + + /* Tweak scaling stability for zero signal to non-zero signal transitions */ + if (scale >= DFRACT_BITS-1) { + scale = (FRACT_BITS-1-*qmfScale); + } + /* prevent scaling of QFM values to -1.f */ + scale = fixMax(0,scale-1); + + /* Update QMF scale */ + *qmfScale += scale; + + /* + Calculate energy of each time slot pair, max energy + and shift QMF values as far as possible to the left. + */ + { + FIXP_DBL *nrgValues = tmpNrg; + for (k=0; k<numberCols; k+=2) + { + /* Load band vector addresses of 2 consecutive timeslots */ + FIXP_DBL *RESTRICT r0 = realValues[k]; + FIXP_DBL *RESTRICT i0 = imagValues[k]; + FIXP_DBL *RESTRICT r1 = realValues[k+1]; + FIXP_DBL *RESTRICT i1 = imagValues[k+1]; + for (j=0; j<numberBands; j++) + { + FIXP_DBL energy; + FIXP_DBL tr0,tr1,ti0,ti1; + + /* Read QMF values of 2 timeslots */ + tr0 = r0[j]; tr1 = r1[j]; ti0 = i0[j]; ti1 = i1[j]; + + /* Scale QMF Values and Calc Energy of both timeslots */ + tr0 <<= scale; + ti0 <<= scale; + energy = fPow2AddDiv2(fPow2Div2(tr0), ti0) >> 1; + + tr1 <<= scale; + ti1 <<= scale; + energy += fPow2AddDiv2(fPow2Div2(tr1), ti1) >> 1; + + /* Write timeslot pair energy to scratch */ + *nrgValues++ = energy; + max_val = fixMax(max_val, energy); + + /* Write back scaled QMF values */ + r0[j] = tr0; r1[j] = tr1; i0[j] = ti0; i1[j] = ti1; + } + } + } + /* energyScale: scalefactor energies of current frame */ + *energyScale = 2*(*qmfScale)-1; /* if qmfScale > 0: nr of right shifts otherwise nr of left shifts */ + + /* Scale timeslot pair energies and write to output buffer */ + scale = CountLeadingBits(max_val); + { + FIXP_DBL *nrgValues = tmpNrg; + for (k=0; k<numberCols>>1; k++) { + scaleValues(energyValues[k], nrgValues, numberBands, scale); + nrgValues += numberBands; + } + *energyScale += scale; + } + + /* Free Scratch buffer */ + C_ALLOC_SCRATCH_END(tmpNrg, FIXP_DBL, QMF_CHANNELS*QMF_MAX_TIME_SLOTS/2); +} + +LNK_SECTION_CODE_L1 +static void +FDKsbrEnc_getEnergyFromCplxQmfDataFull(FIXP_DBL **RESTRICT energyValues,/*!< the result of the operation */ + FIXP_DBL **RESTRICT realValues, /*!< the real part of the QMF subsamples */ + FIXP_DBL **RESTRICT imagValues, /*!< the imaginary part of the QMF subsamples */ + int numberBands, /*!< number of QMF bands */ + int numberCols, /*!< number of QMF subsamples */ + int *qmfScale, /*!< sclefactor of QMF subsamples */ + int *energyScale) /*!< scalefactor of energies */ +{ + int j, k; + int scale; + FIXP_DBL max_val = FL2FXCONST_DBL(0.0f); + + /* Get Scratch buffer */ + C_ALLOC_SCRATCH_START(tmpNrg, FIXP_DBL, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2); + + FDK_ASSERT(numberBands <= QMF_CHANNELS); + FDK_ASSERT(numberCols <= QMF_MAX_TIME_SLOTS/2); + + /* Get max possible scaling of QMF data */ + scale = DFRACT_BITS; + for (k=0; k<numberCols; k++) { + scale = fixMin(scale, fixMin(getScalefactor(realValues[k], numberBands), getScalefactor(imagValues[k], numberBands))); + } + + /* Tweak scaling stability for zero signal to non-zero signal transitions */ + if (scale >= DFRACT_BITS-1) { + scale = (FRACT_BITS-1-*qmfScale); + } + /* prevent scaling of QFM values to -1.f */ + scale = fixMax(0,scale-1); + + /* Update QMF scale */ + *qmfScale += scale; + + /* + Calculate energy of each time slot pair, max energy + and shift QMF values as far as possible to the left. + */ + { + FIXP_DBL *nrgValues = tmpNrg; + for (k=0; k<numberCols; k++) + { + /* Load band vector addresses of 2 consecutive timeslots */ + FIXP_DBL *RESTRICT r0 = realValues[k]; + FIXP_DBL *RESTRICT i0 = imagValues[k]; + for (j=0; j<numberBands; j++) + { + FIXP_DBL energy; + FIXP_DBL tr0,ti0; + + /* Read QMF values of 2 timeslots */ + tr0 = r0[j]; ti0 = i0[j]; + + /* Scale QMF Values and Calc Energy of both timeslots */ + tr0 <<= scale; + ti0 <<= scale; + energy = fPow2AddDiv2(fPow2Div2(tr0), ti0); + *nrgValues++ = energy; + + max_val = fixMax(max_val, energy); + + /* Write back scaled QMF values */ + r0[j] = tr0; i0[j] = ti0; + } + } + } + /* energyScale: scalefactor energies of current frame */ + *energyScale = 2*(*qmfScale)-1; /* if qmfScale > 0: nr of right shifts otherwise nr of left shifts */ + + /* Scale timeslot pair energies and write to output buffer */ + scale = CountLeadingBits(max_val); + { + FIXP_DBL *nrgValues = tmpNrg; + for (k=0; k<numberCols; k++) { + scaleValues(energyValues[k], nrgValues, numberBands, scale); + nrgValues += numberBands; + } + *energyScale += scale; + } + + /* Free Scratch buffer */ + C_ALLOC_SCRATCH_END(tmpNrg, FIXP_DBL, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2); +} + +/***************************************************************************/ +/*! + + \brief Quantisation of the panorama value (balance) + + \return the quantized pan value + +****************************************************************************/ +static INT +mapPanorama(INT nrgVal, /*! integer value of the energy */ + INT ampRes, /*! amplitude resolution [1.5/3dB] */ + INT *quantError /*! quantization error of energy val*/ + ) +{ + int i; + INT min_val, val; + UCHAR panIndex; + INT sign; + + sign = nrgVal > 0 ? 1 : -1; + + nrgVal *= sign; + + min_val = FDK_INT_MAX; + panIndex = 0; + for (i = 0; i < maxIndex[ampRes]; i++) { + val = fixp_abs ((nrgVal - (INT)panTable[ampRes][i])); + + if (val < min_val) { + min_val = val; + panIndex = i; + } + } + + *quantError=min_val; + + return panTable[ampRes][maxIndex[ampRes]-1] + sign * panTable[ampRes][panIndex]; +} + + +/***************************************************************************/ +/*! + + \brief Quantisation of the noise floor levels + + \return void + +****************************************************************************/ +static void +sbrNoiseFloorLevelsQuantisation(SCHAR *RESTRICT iNoiseLevels, /*! quantized noise levels */ + FIXP_DBL *RESTRICT NoiseLevels, /*! the noise levels */ + INT coupling /*! the coupling flag */ + ) +{ + INT i; + INT tmp, dummy; + + /* Quantisation, similar to sfb quant... */ + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) { + /* tmp = NoiseLevels[i] > (PFLOAT)30.0f ? 30: (INT) (NoiseLevels[i] + (PFLOAT)0.5); */ + /* 30>>6 = 0.46875 */ + if ((FIXP_DBL)NoiseLevels[i] > FL2FXCONST_DBL(0.46875f)) { + tmp = 30; + } + else { + /* tmp = (INT)((FIXP_DBL)NoiseLevels[i] + (FL2FXCONST_DBL(0.5f)>>(*/ /* FRACT_BITS+ */ /* 6-1)));*/ + /* tmp = tmp >> (DFRACT_BITS-1-6); */ /* conversion to integer happens here */ + /* rounding is done by shifting one bit less than necessary to the right, adding '1' and then shifting the final bit */ + tmp = ((((INT)NoiseLevels[i])>>(DFRACT_BITS-1-LD_DATA_SHIFT)) ); /* conversion to integer */ + if (tmp != 0) + tmp += 1; + } + + if (coupling) { + tmp = tmp < -30 ? -30 : tmp; + tmp = mapPanorama (tmp,1,&dummy); + } + iNoiseLevels[i] = tmp; + } +} + +/***************************************************************************/ +/*! + + \brief Calculation of noise floor for coupling + + \return void + +****************************************************************************/ +static void +coupleNoiseFloor(FIXP_DBL *RESTRICT noise_level_left, /*! noise level left (modified)*/ + FIXP_DBL *RESTRICT noise_level_right /*! noise level right (modified)*/ + ) +{ + FIXP_DBL cmpValLeft,cmpValRight; + INT i; + FIXP_DBL temp1,temp2; + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) { + + /* Calculation of the power function using ld64: + z = x^y; + z' = CalcLd64(z) = y*CalcLd64(x)/64; + z = CalcInvLd64(z'); + */ + cmpValLeft = NOISE_FLOOR_OFFSET_64 - noise_level_left[i]; + cmpValRight = NOISE_FLOOR_OFFSET_64 - noise_level_right[i]; + + if (cmpValRight < FL2FXCONST_DBL(0.0f)) { + temp1 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_right[i]); + } + else { + temp1 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_right[i]); + temp1 = temp1 << (DFRACT_BITS-1-LD_DATA_SHIFT-1); /* INT to fract conversion of result, if input of CalcInvLdData is positiv */ + } + + if (cmpValLeft < FL2FXCONST_DBL(0.0f)) { + temp2 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_left[i]); + } + else { + temp2 = CalcInvLdData(NOISE_FLOOR_OFFSET_64 - noise_level_left[i]); + temp2 = temp2 << (DFRACT_BITS-1-LD_DATA_SHIFT-1); /* INT to fract conversion of result, if input of CalcInvLdData is positiv */ + } + + + if ((cmpValLeft < FL2FXCONST_DBL(0.0f)) && (cmpValRight < FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>1) + (temp2>>1)))); /* no scaling needed! both values are dfract */ + noise_level_right[i] = CalcLdData(temp2) - CalcLdData(temp1); + } + + if ((cmpValLeft >= FL2FXCONST_DBL(0.0f)) && (cmpValRight >= FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>1) + (temp2>>1))) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = CalcLdData(temp2) - CalcLdData(temp1); + } + + if ((cmpValLeft >= FL2FXCONST_DBL(0.0f)) && (cmpValRight < FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>(7+1)) + (temp2>>1))) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = (CalcLdData(temp2) + FL2FXCONST_DBL(0.109375f)) - CalcLdData(temp1); + } + + if ((cmpValLeft < FL2FXCONST_DBL(0.0f)) && (cmpValRight >= FL2FXCONST_DBL(0.0f))) { + noise_level_left[i] = NOISE_FLOOR_OFFSET_64 - (CalcLdData(((temp1>>1) + (temp2>>(7+1)))) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + noise_level_right[i] = CalcLdData(temp2) - (CalcLdData(temp1) + FL2FXCONST_DBL(0.109375f)); /* scaled with 7/64 */ + } + } +} + +/***************************************************************************/ +/*! + + \brief Calculation of energy starting in lower band (li) up to upper band (ui) + over slots (start_pos) to (stop_pos) + + \return void + +****************************************************************************/ +static FIXP_DBL +getEnvSfbEnergy(INT li, /*! lower band */ + INT ui, /*! upper band */ + INT start_pos, /*! start slot */ + INT stop_pos, /*! stop slot */ + INT border_pos, /*! slots scaling border */ + FIXP_DBL **YBuffer, /*! sfb energy buffer */ + INT YBufferSzShift, /*! Energy buffer index scale */ + INT scaleNrg0, /*! scaling of lower slots */ + INT scaleNrg1) /*! scaling of upper slots */ +{ + /* use dynamic scaling for outer energy loop; + energies are critical and every bit is important */ + int sc0, sc1, k, l; + + FIXP_DBL nrgSum, nrg1, nrg2, accu1, accu2; + INT dynScale, dynScale1, dynScale2; + if(ui-li==0) dynScale = DFRACT_BITS-1; + else + dynScale = CalcLdInt(ui-li)>>(DFRACT_BITS-1-LD_DATA_SHIFT); + + sc0 = fixMin(scaleNrg0,Y_NRG_SCALE); sc1 = fixMin(scaleNrg1,Y_NRG_SCALE); + /* dynScale{1,2} is set such that the right shift below is positive */ + dynScale1 = fixMin((scaleNrg0-sc0),dynScale); + dynScale2 = fixMin((scaleNrg1-sc1),dynScale); + nrgSum = accu1 = accu2 = (FIXP_DBL)0; + + for (k = li; k < ui; k++) { + nrg1 = nrg2 = (FIXP_DBL)0; + for (l = start_pos; l < border_pos; l++) { + nrg1 += YBuffer[l>>YBufferSzShift][k] >> sc0; + } + for (; l < stop_pos; l++) { + nrg2 += YBuffer[l>>YBufferSzShift][k] >> sc1; + } + accu1 += (nrg1>>dynScale1); + accu2 += (nrg2>>dynScale2); + } + /* This shift factor is always positive. See comment above. */ + nrgSum += ( accu1 >> fixMin((scaleNrg0-sc0-dynScale1),(DFRACT_BITS-1)) ) + + ( accu2 >> fixMin((scaleNrg1-sc1-dynScale2),(DFRACT_BITS-1)) ); + + return nrgSum; +} + +/***************************************************************************/ +/*! + + \brief Energy compensation in missing harmonic mode + + \return void + +****************************************************************************/ +static FIXP_DBL +mhLoweringEnergy(FIXP_DBL nrg, INT M) +{ + /* + Compensating for the fact that we in the decoder map the "average energy to every QMF + band, and use this when we calculate the boost-factor. Since the mapped energy isn't + the average energy but the maximum energy in case of missing harmonic creation, we will + in the boost function calculate that too much limiting has been applied and hence we will + boost the signal although it isn't called for. Hence we need to compensate for this by + lowering the transmitted energy values for the sines so they will get the correct level + after the boost is applied. + */ + if(M > 2){ + INT tmpScale; + tmpScale = CountLeadingBits(nrg); + nrg <<= tmpScale; + nrg = fMult(nrg, FL2FXCONST_DBL(0.398107267f)); /* The maximum boost is 1.584893, so the maximum attenuation should be square(1/1.584893) = 0.398107267 */ + nrg >>= tmpScale; + } + else{ + if(M > 1){ + nrg >>= 1; + } + } + + return nrg; +} + +/***************************************************************************/ +/*! + + \brief Energy compensation in none missing harmonic mode + + \return void + +****************************************************************************/ +static FIXP_DBL +nmhLoweringEnergy(FIXP_DBL nrg, FIXP_DBL nrgSum, INT M) +{ + if (nrg>FL2FXCONST_DBL(0)) { + int sc=0; + /* gain = nrgSum / (nrg*(M+1)) */ + FIXP_DBL gain = fMult(fDivNorm(nrgSum, nrg, &sc), GetInvInt(M+1)); + + /* reduce nrg if gain smaller 1.f */ + if ( !((sc>=0) && ( gain > ((FIXP_DBL)MAXVAL_DBL>>sc) )) ) { + nrg = fMult(scaleValue(gain,sc), nrg); + } + } + return nrg; +} + +/***************************************************************************/ +/*! + + \brief calculates the envelope values from the energies, depending on + framing and stereo mode + + \return void + +****************************************************************************/ +static void +calculateSbrEnvelope (FIXP_DBL **RESTRICT YBufferLeft, /*! energy buffer left */ + FIXP_DBL **RESTRICT YBufferRight, /*! energy buffer right */ + int *RESTRICT YBufferScaleLeft, /*! scale energy buffer left */ + int *RESTRICT YBufferScaleRight, /*! scale energy buffer right */ + const SBR_FRAME_INFO *frame_info, /*! frame info vector */ + SCHAR *RESTRICT sfb_nrgLeft, /*! sfb energy buffer left */ + SCHAR *RESTRICT sfb_nrgRight, /*! sfb energy buffer right */ + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_ENV_CHANNEL h_sbr, /*! envelope channel handle */ + SBR_STEREO_MODE stereoMode, /*! stereo coding mode */ + INT* maxQuantError, /*! maximum quantization error, for panorama. */ + int YBufferSzShift) /*! Energy buffer index scale */ + +{ + int i, j, m = 0; + INT no_of_bands, start_pos, stop_pos, li, ui; + FREQ_RES freq_res; + + INT ca = 2 - h_sbr->encEnvData.init_sbr_amp_res; + INT oneBitLess = 0; + if (ca == 2) + oneBitLess = 1; /* LD_DATA_SHIFT => ld64 scaling; one bit less for rounding */ + + INT quantError; + INT nEnvelopes = frame_info->nEnvelopes; + INT short_env = frame_info->shortEnv - 1; + INT timeStep = h_sbr->sbrExtractEnvelope.time_step; + INT commonScale,scaleLeft0,scaleLeft1; + INT scaleRight0=0,scaleRight1=0; + + commonScale = fixMin(YBufferScaleLeft[0],YBufferScaleLeft[1]); + + if (stereoMode == SBR_COUPLING) { + commonScale = fixMin(commonScale,YBufferScaleRight[0]); + commonScale = fixMin(commonScale,YBufferScaleRight[1]); + } + + commonScale = commonScale - 7; + + scaleLeft0 = YBufferScaleLeft[0] - commonScale; + scaleLeft1 = YBufferScaleLeft[1] - commonScale ; + FDK_ASSERT ((scaleLeft0 >= 0) && (scaleLeft1 >= 0)); + + if (stereoMode == SBR_COUPLING) { + scaleRight0 = YBufferScaleRight[0] - commonScale; + scaleRight1 = YBufferScaleRight[1] - commonScale; + FDK_ASSERT ((scaleRight0 >= 0) && (scaleRight1 >= 0)); + *maxQuantError = 0; + } + + for (i = 0; i < nEnvelopes; i++) { + + FIXP_DBL pNrgLeft[QMF_MAX_TIME_SLOTS]; + FIXP_DBL pNrgRight[QMF_MAX_TIME_SLOTS]; + FIXP_DBL envNrgLeft = FL2FXCONST_DBL(0.0f); + FIXP_DBL envNrgRight = FL2FXCONST_DBL(0.0f); + int missingHarmonic[QMF_MAX_TIME_SLOTS]; + int count[QMF_MAX_TIME_SLOTS]; + + start_pos = timeStep * frame_info->borders[i]; + stop_pos = timeStep * frame_info->borders[i + 1]; + freq_res = frame_info->freqRes[i]; + no_of_bands = h_con->nSfb[freq_res]; + + if (i == short_env) { + stop_pos -= fixMax(2, timeStep); /* consider at least 2 QMF slots less for short envelopes (envelopes just before transients) */ + } + + for (j = 0; j < no_of_bands; j++) { + FIXP_DBL nrgLeft = FL2FXCONST_DBL(0.0f); + FIXP_DBL nrgRight = FL2FXCONST_DBL(0.0f); + + li = h_con->freqBandTable[freq_res][j]; + ui = h_con->freqBandTable[freq_res][j + 1]; + + if(freq_res == FREQ_RES_HIGH){ + if(j == 0 && ui-li > 1){ + li++; + } + } + else{ + if(j == 0 && ui-li > 2){ + li++; + } + } + + /* + Find out whether a sine will be missing in the scale-factor + band that we're currently processing. + */ + missingHarmonic[j] = 0; + + if(h_sbr->encEnvData.addHarmonicFlag){ + + if(freq_res == FREQ_RES_HIGH){ + if(h_sbr->encEnvData.addHarmonic[j]){ /*A missing sine in the current band*/ + missingHarmonic[j] = 1; + } + } + else{ + INT i; + INT startBandHigh = 0; + INT stopBandHigh = 0; + + while(h_con->freqBandTable[FREQ_RES_HIGH][startBandHigh] < h_con->freqBandTable[FREQ_RES_LOW][j]) + startBandHigh++; + while(h_con->freqBandTable[FREQ_RES_HIGH][stopBandHigh] < h_con->freqBandTable[FREQ_RES_LOW][j + 1]) + stopBandHigh++; + + for(i = startBandHigh; i<stopBandHigh; i++){ + if(h_sbr->encEnvData.addHarmonic[i]){ + missingHarmonic[j] = 1; + } + } + } + } + + /* + If a sine is missing in a scalefactorband, with more than one qmf channel + use the nrg from the channel with the largest nrg rather than the mean. + Compensate for the boost calculation in the decdoder. + */ + int border_pos = fixMin(stop_pos, h_sbr->sbrExtractEnvelope.YBufferWriteOffset<<YBufferSzShift); + + if(missingHarmonic[j]){ + + int k; + count[j] = stop_pos - start_pos; + nrgLeft = FL2FXCONST_DBL(0.0f); + + for (k = li; k < ui; k++) { + FIXP_DBL tmpNrg; + tmpNrg = getEnvSfbEnergy(k, + k+1, + start_pos, + stop_pos, + border_pos, + YBufferLeft, + YBufferSzShift, + scaleLeft0, + scaleLeft1); + + nrgLeft = fixMax(nrgLeft, tmpNrg); + } + + /* Energy lowering compensation */ + nrgLeft = mhLoweringEnergy(nrgLeft, ui-li); + + if (stereoMode == SBR_COUPLING) { + + nrgRight = FL2FXCONST_DBL(0.0f); + + for (k = li; k < ui; k++) { + FIXP_DBL tmpNrg; + tmpNrg = getEnvSfbEnergy(k, + k+1, + start_pos, + stop_pos, + border_pos, + YBufferRight, + YBufferSzShift, + scaleRight0, + scaleRight1); + + nrgRight = fixMax(nrgRight, tmpNrg); + } + + /* Energy lowering compensation */ + nrgRight = mhLoweringEnergy(nrgRight, ui-li); + } + } /* end missingHarmonic */ + else{ + count[j] = (stop_pos - start_pos) * (ui - li); + + nrgLeft = getEnvSfbEnergy(li, + ui, + start_pos, + stop_pos, + border_pos, + YBufferLeft, + YBufferSzShift, + scaleLeft0, + scaleLeft1); + + if (stereoMode == SBR_COUPLING) { + nrgRight = getEnvSfbEnergy(li, + ui, + start_pos, + stop_pos, + border_pos, + YBufferRight, + YBufferSzShift, + scaleRight0, + scaleRight1); + } + } /* !missingHarmonic */ + + /* save energies */ + pNrgLeft[j] = nrgLeft; + pNrgRight[j] = nrgRight; + envNrgLeft += nrgLeft; + envNrgRight += nrgRight; + + } /* j */ + + for (j = 0; j < no_of_bands; j++) { + + FIXP_DBL nrgLeft2 = FL2FXCONST_DBL(0.0f); + FIXP_DBL nrgLeft = pNrgLeft[j]; + FIXP_DBL nrgRight = pNrgRight[j]; + + /* None missing harmonic Energy lowering compensation */ + if(!missingHarmonic[j] && h_sbr->fLevelProtect) { + /* in case of missing energy in base band, + reduce reference energy to prevent overflows in decoder output */ + nrgLeft = nmhLoweringEnergy(nrgLeft, envNrgLeft, no_of_bands); + if (stereoMode == SBR_COUPLING) { + nrgRight = nmhLoweringEnergy(nrgRight, envNrgRight, no_of_bands); + } + } + + if (stereoMode == SBR_COUPLING) { + /* calc operation later with log */ + nrgLeft2 = nrgLeft; + nrgLeft = (nrgRight + nrgLeft) >> 1; + } + + /* nrgLeft = f20_log2(nrgLeft / (PFLOAT)(count * h_sbr->sbrQmf.no_channels))+(PFLOAT)44; */ + /* If nrgLeft == 0 then the Log calculations below do fail. */ + if (nrgLeft > FL2FXCONST_DBL(0.0f)) + { + FIXP_DBL tmp0,tmp1,tmp2,tmp3; + INT tmpScale; + + tmpScale = CountLeadingBits(nrgLeft); + nrgLeft = nrgLeft << tmpScale; + + tmp0 = CalcLdData(nrgLeft); /* scaled by 1/64 */ + tmp1 = ((FIXP_DBL) (commonScale+tmpScale)) << (DFRACT_BITS-1-LD_DATA_SHIFT-1); /* scaled by 1/64 */ + tmp2 = ((FIXP_DBL)(count[j]*h_con->noQmfBands)) << (DFRACT_BITS-1-14-1); + tmp2 = CalcLdData(tmp2); /* scaled by 1/64 */ + tmp3 = FL2FXCONST_DBL(0.6875f-0.21875f-0.015625f)>>1; /* scaled by 1/64 */ + + nrgLeft = ((tmp0-tmp2)>>1) + (tmp3 - tmp1); + } else { + nrgLeft = FL2FXCONST_DBL(-1.0f); + } + + /* ld64 to integer conversion */ + nrgLeft = fixMin(fixMax(nrgLeft,FL2FXCONST_DBL(0.0f)),FL2FXCONST_DBL(0.5f)); + nrgLeft = (FIXP_DBL)(LONG)nrgLeft >> (DFRACT_BITS-1-LD_DATA_SHIFT-1-oneBitLess-1); + sfb_nrgLeft[m] = ((INT)nrgLeft+1)>>1; /* rounding */ + + if (stereoMode == SBR_COUPLING) { + FIXP_DBL scaleFract; + + if (nrgRight != FL2FXCONST_DBL(0.0f)) { + int sc0 = CountLeadingBits(nrgLeft2); + int sc1 = CountLeadingBits(nrgRight); + + scaleFract = ((FIXP_DBL)(sc0-sc1)) << (DFRACT_BITS-1-LD_DATA_SHIFT); /* scale value in ld64 representation */ + nrgRight = CalcLdData(nrgLeft2<<sc0) - CalcLdData(nrgRight<<sc1) - scaleFract; + } + else + nrgRight = FL2FXCONST_DBL(0.5f); /* ld64(4294967296.0f) */ + + /* ld64 to integer conversion */ + nrgRight = (FIXP_DBL)(LONG)(nrgRight) >> (DFRACT_BITS-1-LD_DATA_SHIFT-1-oneBitLess); + nrgRight = (nrgRight+(FIXP_DBL)1)>>1; /* rounding */ + + sfb_nrgRight[m] = mapPanorama (nrgRight,h_sbr->encEnvData.init_sbr_amp_res,&quantError); + + *maxQuantError = fixMax(quantError, *maxQuantError); + } + + m++; + } /* j */ + + /* Do energy compensation for sines that are present in two + QMF-bands in the original, but will only occur in one band in + the decoder due to the synthetic sine coding.*/ + if (h_con->useParametricCoding) { + m-=no_of_bands; + for (j = 0; j < no_of_bands; j++) { + if (freq_res==FREQ_RES_HIGH && h_sbr->sbrExtractEnvelope.envelopeCompensation[j]){ + sfb_nrgLeft[m] -= (ca * fixp_abs((INT)h_sbr->sbrExtractEnvelope.envelopeCompensation[j])); + } + sfb_nrgLeft[m] = fixMax(0, sfb_nrgLeft[m]); + m++; + } + } /* useParametricCoding */ + + } /* i*/ +} + +/* + * Update QMF buffers + */ +static void FDKsbrEnc_updateRIBuffers(HANDLE_ENV_CHANNEL h_envChan) +{ + int i; + + /* rBufferWriteOffset ist always 0, do we need this ? */ + for (i = 0; i < h_envChan->sbrExtractEnvelope.rBufferWriteOffset; i++) { + FIXP_DBL *temp; + + temp = h_envChan->sbrExtractEnvelope.rBuffer[i]; + h_envChan->sbrExtractEnvelope.rBuffer[i] = h_envChan->sbrExtractEnvelope.rBuffer[i + h_envChan->sbrExtractEnvelope.no_cols]; + h_envChan->sbrExtractEnvelope.rBuffer[i + h_envChan->sbrExtractEnvelope.no_cols] = temp; + + temp = h_envChan->sbrExtractEnvelope.iBuffer[i]; + h_envChan->sbrExtractEnvelope.iBuffer[i] = h_envChan->sbrExtractEnvelope.iBuffer[i + h_envChan->sbrExtractEnvelope.no_cols]; + h_envChan->sbrExtractEnvelope.iBuffer[i + h_envChan->sbrExtractEnvelope.no_cols] = temp; + } +} + +/***************************************************************************/ +/*! + + \brief calculates the noise floor and the envelope values from the + energies, depending on framing and stereo mode + + FDKsbrEnc_extractSbrEnvelope is the main function for encoding and writing the + envelope and the noise floor. The function includes the following processes: + + -Analysis subband filtering. + -Encoding SA and pan parameters (if enabled). + -Transient detection. + +****************************************************************************/ + +LNK_SECTION_CODE_L1 +void +FDKsbrEnc_extractSbrEnvelope1 ( + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_ENV_CHANNEL hEnvChan, + HANDLE_COMMON_DATA hCmonData, + SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData + ) +{ + + HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &hEnvChan->sbrExtractEnvelope; + + if (sbrExtrEnv->YBufferSzShift == 0) + FDKsbrEnc_getEnergyFromCplxQmfDataFull(&sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset], + sbrExtrEnv->rBuffer + sbrExtrEnv->rBufferReadOffset, + sbrExtrEnv->iBuffer + sbrExtrEnv->rBufferReadOffset, + h_con->noQmfBands, + sbrExtrEnv->no_cols, + &hEnvChan->qmfScale, + &sbrExtrEnv->YBufferScale[1]); + else + FDKsbrEnc_getEnergyFromCplxQmfData(&sbrExtrEnv->YBuffer[sbrExtrEnv->YBufferWriteOffset], + sbrExtrEnv->rBuffer + sbrExtrEnv->rBufferReadOffset, + sbrExtrEnv->iBuffer + sbrExtrEnv->rBufferReadOffset, + h_con->noQmfBands, + sbrExtrEnv->no_cols, + &hEnvChan->qmfScale, + &sbrExtrEnv->YBufferScale[1]); + + + + /* + Precalculation of Tonality Quotas COEFF Transform OK + */ + FDKsbrEnc_CalculateTonalityQuotas(&hEnvChan->TonCorr, + sbrExtrEnv->rBuffer+ sbrExtrEnv->rBufferWriteOffset, + sbrExtrEnv->iBuffer+ sbrExtrEnv->rBufferWriteOffset, + h_con->freqBandTable[HI][h_con->nSfb[HI]], + hEnvChan->qmfScale); + + + + /* + Transient detection COEFF Transform OK + */ + FDKsbrEnc_transientDetect(&hEnvChan->sbrTransientDetector, + sbrExtrEnv->YBuffer, + sbrExtrEnv->YBufferScale, + eData->transient_info, + sbrExtrEnv->YBufferWriteOffset, + sbrExtrEnv->YBufferSzShift, + sbrExtrEnv->time_step, + hEnvChan->SbrEnvFrame.frameMiddleSlot); + + + + /* + Generate flags for 2 env in a FIXFIX-frame. + Remove this function to get always 1 env per FIXFIX-frame. + */ + + /* + frame Splitter COEFF Transform OK + */ + FDKsbrEnc_frameSplitter(sbrExtrEnv->YBuffer, + sbrExtrEnv->YBufferScale, + &hEnvChan->sbrTransientDetector, + h_con->freqBandTable[1], + eData->transient_info, + sbrExtrEnv->YBufferWriteOffset, + sbrExtrEnv->YBufferSzShift, + h_con->nSfb[1], + sbrExtrEnv->time_step, + sbrExtrEnv->no_cols); + + + + FDKsbrEnc_updateRIBuffers(hEnvChan); +} + +/***************************************************************************/ +/*! + + \brief calculates the noise floor and the envelope values from the + energies, depending on framing and stereo mode + + FDKsbrEnc_extractSbrEnvelope is the main function for encoding and writing the + envelope and the noise floor. The function includes the following processes: + + -Determine time/frequency division of current granule. + -Sending transient info to bitstream. + -Set amp_res to 1.5 dB if the current frame contains only one envelope. + -Lock dynamic bandwidth frequency change if the next envelope not starts on a + frame boundary. + -MDCT transposer (needed to detect where harmonics will be missing). + -Spectrum Estimation (used for pulse train and missing harmonics detection). + -Pulse train detection. + -Inverse Filtering detection. + -Waveform Coding. + -Missing Harmonics detection. + -Extract envelope of current frame. + -Noise floor estimation. + -Noise floor quantisation and coding. + -Encode envelope of current frame. + -Send the encoded data to the bitstream. + -Write to bitstream. + +****************************************************************************/ + +LNK_SECTION_CODE_L1 +void +FDKsbrEnc_extractSbrEnvelope2 ( + HANDLE_SBR_CONFIG_DATA h_con, /*! handle to config data */ + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_ENV_CHANNEL h_envChan0, + HANDLE_ENV_CHANNEL h_envChan1, + HANDLE_COMMON_DATA hCmonData, + SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData, + int clearOutput + ) +{ + HANDLE_ENV_CHANNEL h_envChan[MAX_NUM_CHANNELS] = {h_envChan0, h_envChan1}; + int ch, i, j, c, YSzShift = h_envChan[0]->sbrExtractEnvelope.YBufferSzShift; + + SBR_STEREO_MODE stereoMode = h_con->stereoMode; + int nChannels = h_con->nChannels; + const int *v_tuning; + static const int v_tuningHEAAC[6] = { 0, 2, 4, 0, 0, 0 }; + + static const int v_tuningELD[6] = { 0, 2, 3, 0, 0, 0 }; + + if (h_con->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) + v_tuning = v_tuningELD; + else + v_tuning = v_tuningHEAAC; + + + /* + Select stereo mode. + */ + if (stereoMode == SBR_COUPLING) { + if (eData[0].transient_info[1] && eData[1].transient_info[1]) { + eData[0].transient_info[0] = fixMin(eData[1].transient_info[0], eData[0].transient_info[0]); + eData[1].transient_info[0] = eData[0].transient_info[0]; + } + else { + if (eData[0].transient_info[1] && !eData[1].transient_info[1]) { + eData[1].transient_info[0] = eData[0].transient_info[0]; + } + else { + if (!eData[0].transient_info[1] && eData[1].transient_info[1]) + eData[0].transient_info[0] = eData[1].transient_info[0]; + else { + eData[0].transient_info[0] = fixMax(eData[1].transient_info[0], eData[0].transient_info[0]); + eData[1].transient_info[0] = eData[0].transient_info[0]; + } + } + } + } + + /* + Determine time/frequency division of current granule + */ + eData[0].frame_info = FDKsbrEnc_frameInfoGenerator(&h_envChan[0]->SbrEnvFrame, + eData[0].transient_info, + h_envChan[0]->sbrExtractEnvelope.pre_transient_info, + h_envChan[0]->encEnvData.ldGrid, + v_tuning); + + h_envChan[0]->encEnvData.hSbrBSGrid = &h_envChan[0]->SbrEnvFrame.SbrGrid; + + /* AAC LD patch for transient prediction */ + if (h_envChan[0]->encEnvData.ldGrid && eData[0].transient_info[2]) { + /* if next frame will start with transient, set shortEnv to numEnvelopes(shortend Envelope = shortEnv-1)*/ + h_envChan[0]->SbrEnvFrame.SbrFrameInfo.shortEnv = h_envChan[0]->SbrEnvFrame.SbrFrameInfo.nEnvelopes; + } + + + switch (stereoMode) { + case SBR_LEFT_RIGHT: + case SBR_SWITCH_LRC: + eData[1].frame_info = FDKsbrEnc_frameInfoGenerator(&h_envChan[1]->SbrEnvFrame, + eData[1].transient_info, + h_envChan[1]->sbrExtractEnvelope.pre_transient_info, + h_envChan[1]->encEnvData.ldGrid, + v_tuning); + + h_envChan[1]->encEnvData.hSbrBSGrid = &h_envChan[1]->SbrEnvFrame.SbrGrid; + + if (h_envChan[1]->encEnvData.ldGrid && eData[1].transient_info[2]) { + /* if next frame will start with transient, set shortEnv to numEnvelopes(shortend Envelope = shortEnv-1)*/ + h_envChan[1]->SbrEnvFrame.SbrFrameInfo.shortEnv = h_envChan[1]->SbrEnvFrame.SbrFrameInfo.nEnvelopes; + } + + /* compare left and right frame_infos */ + if (eData[0].frame_info->nEnvelopes != eData[1].frame_info->nEnvelopes) { + stereoMode = SBR_LEFT_RIGHT; + } else { + for (i = 0; i < eData[0].frame_info->nEnvelopes + 1; i++) { + if (eData[0].frame_info->borders[i] != eData[1].frame_info->borders[i]) { + stereoMode = SBR_LEFT_RIGHT; + break; + } + } + for (i = 0; i < eData[0].frame_info->nEnvelopes; i++) { + if (eData[0].frame_info->freqRes[i] != eData[1].frame_info->freqRes[i]) { + stereoMode = SBR_LEFT_RIGHT; + break; + } + } + if (eData[0].frame_info->shortEnv != eData[1].frame_info->shortEnv) { + stereoMode = SBR_LEFT_RIGHT; + } + } + break; + case SBR_COUPLING: + eData[1].frame_info = eData[0].frame_info; + h_envChan[1]->encEnvData.hSbrBSGrid = &h_envChan[0]->SbrEnvFrame.SbrGrid; + break; + case SBR_MONO: + /* nothing to do */ + break; + default: + FDK_ASSERT (0); + } + + + for (ch = 0; ch < nChannels;ch++) + { + HANDLE_ENV_CHANNEL hEnvChan = h_envChan[ch]; + HANDLE_SBR_EXTRACT_ENVELOPE sbrExtrEnv = &hEnvChan->sbrExtractEnvelope; + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + + + /* + Send transient info to bitstream and store for next call + */ + sbrExtrEnv->pre_transient_info[0] = ed->transient_info[0];/* tran_pos */ + sbrExtrEnv->pre_transient_info[1] = ed->transient_info[1];/* tran_flag */ + hEnvChan->encEnvData.noOfEnvelopes = ed->nEnvelopes = ed->frame_info->nEnvelopes; /* number of envelopes of current frame */ + + /* + Check if the current frame is divided into one envelope only. If so, set the amplitude + resolution to 1.5 dB, otherwise may set back to chosen value + */ + if( ( hEnvChan->encEnvData.hSbrBSGrid->frameClass == FIXFIX ) + && ( ed->nEnvelopes == 1 ) ) + { + + if (hEnvChan->encEnvData.ldGrid) + hEnvChan->encEnvData.currentAmpResFF = (AMP_RES)h_con->initAmpResFF; + else + hEnvChan->encEnvData.currentAmpResFF = SBR_AMP_RES_1_5; + + if ( hEnvChan->encEnvData.currentAmpResFF != hEnvChan->encEnvData.init_sbr_amp_res) { + + FDKsbrEnc_InitSbrHuffmanTables(&hEnvChan->encEnvData, + &hEnvChan->sbrCodeEnvelope, + &hEnvChan->sbrCodeNoiseFloor, + hEnvChan->encEnvData.currentAmpResFF); + } + } + else { + if(sbrHeaderData->sbr_amp_res != hEnvChan->encEnvData.init_sbr_amp_res ) { + + FDKsbrEnc_InitSbrHuffmanTables(&hEnvChan->encEnvData, + &hEnvChan->sbrCodeEnvelope, + &hEnvChan->sbrCodeNoiseFloor, + sbrHeaderData->sbr_amp_res); + } + } + + if (!clearOutput) { + + /* + Tonality correction parameter extraction (inverse filtering level, noise floor additional sines). + */ + FDKsbrEnc_TonCorrParamExtr(&hEnvChan->TonCorr, + hEnvChan->encEnvData.sbr_invf_mode_vec, + ed->noiseFloor, + &hEnvChan->encEnvData.addHarmonicFlag, + hEnvChan->encEnvData.addHarmonic, + sbrExtrEnv->envelopeCompensation, + ed->frame_info, + ed->transient_info, + h_con->freqBandTable[HI], + h_con->nSfb[HI], + hEnvChan->encEnvData.sbr_xpos_mode, + h_con->sbrSyntaxFlags); + + } + + /* Low energy in low band fix */ + if ( hEnvChan->sbrTransientDetector.prevLowBandEnergy < hEnvChan->sbrTransientDetector.prevHighBandEnergy && hEnvChan->sbrTransientDetector.prevHighBandEnergy > FL2FX_DBL(0.03)) + { + int i; + + hEnvChan->fLevelProtect = 1; + + for (i=0; i<MAX_NUM_NOISE_VALUES; i++) + hEnvChan->encEnvData.sbr_invf_mode_vec[i] = INVF_HIGH_LEVEL; + } else { + hEnvChan->fLevelProtect = 0; + } + + hEnvChan->encEnvData.sbr_invf_mode = hEnvChan->encEnvData.sbr_invf_mode_vec[0]; + + hEnvChan->encEnvData.noOfnoisebands = hEnvChan->TonCorr.sbrNoiseFloorEstimate.noNoiseBands; + + + } /* ch */ + + + + /* + Save number of scf bands per envelope + */ + for (ch = 0; ch < nChannels;ch++) { + for (i = 0; i < eData[ch].nEnvelopes; i++){ + h_envChan[ch]->encEnvData.noScfBands[i] = + (eData[ch].frame_info->freqRes[i] == FREQ_RES_HIGH ? h_con->nSfb[FREQ_RES_HIGH] : h_con->nSfb[FREQ_RES_LOW]); + } + } + + /* + Extract envelope of current frame. + */ + switch (stereoMode) { + case SBR_MONO: + calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, + h_con, h_envChan[0], SBR_MONO, NULL, YSzShift); + break; + case SBR_LEFT_RIGHT: + calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, + h_con, h_envChan[0], SBR_MONO, NULL, YSzShift); + calculateSbrEnvelope (h_envChan[1]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, NULL, + eData[1].frame_info,eData[1].sfb_nrg, NULL, + h_con, h_envChan[1], SBR_MONO, NULL, YSzShift); + break; + case SBR_COUPLING: + calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, h_envChan[1]->sbrExtractEnvelope.YBuffer, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, h_envChan[1]->sbrExtractEnvelope.YBufferScale, + eData[0].frame_info, eData[0].sfb_nrg, eData[1].sfb_nrg, + h_con, h_envChan[0], SBR_COUPLING, &fData->maxQuantError, YSzShift); + break; + case SBR_SWITCH_LRC: + calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, NULL, + eData[0].frame_info, eData[0].sfb_nrg, NULL, + h_con, h_envChan[0], SBR_MONO, NULL, YSzShift); + calculateSbrEnvelope (h_envChan[1]->sbrExtractEnvelope.YBuffer, NULL, + h_envChan[1]->sbrExtractEnvelope.YBufferScale, NULL, + eData[1].frame_info, eData[1].sfb_nrg, NULL, + h_con, h_envChan[1], SBR_MONO,NULL, YSzShift); + calculateSbrEnvelope (h_envChan[0]->sbrExtractEnvelope.YBuffer, h_envChan[1]->sbrExtractEnvelope.YBuffer, + h_envChan[0]->sbrExtractEnvelope.YBufferScale, h_envChan[1]->sbrExtractEnvelope.YBufferScale, + eData[0].frame_info, eData[0].sfb_nrg_coupling, eData[1].sfb_nrg_coupling, + h_con, h_envChan[0], SBR_COUPLING, &fData->maxQuantError, YSzShift); + break; + } + + + + /* + Noise floor quantisation and coding. + */ + + switch (stereoMode) { + case SBR_MONO: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level, eData[0].noiseFloor, 0); + + FDKsbrEnc_codeEnvelope(eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + break; + case SBR_LEFT_RIGHT: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level,eData[0].noiseFloor, 0); + + FDKsbrEnc_codeEnvelope (eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level,eData[1].noiseFloor, 0); + + FDKsbrEnc_codeEnvelope (eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 0, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + break; + + case SBR_COUPLING: + coupleNoiseFloor(eData[0].noiseFloor,eData[1].noiseFloor); + + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level,eData[0].noiseFloor, 0); + + FDKsbrEnc_codeEnvelope (eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 1, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level,eData[1].noiseFloor, 1); + + FDKsbrEnc_codeEnvelope (eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 1, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 1, + sbrBitstreamData->HeaderActive); + + break; + case SBR_SWITCH_LRC: + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level,eData[0].noiseFloor, 0); + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level,eData[1].noiseFloor, 0); + coupleNoiseFloor(eData[0].noiseFloor,eData[1].noiseFloor); + sbrNoiseFloorLevelsQuantisation(eData[0].noise_level_coupling,eData[0].noiseFloor, 0); + sbrNoiseFloorLevelsQuantisation(eData[1].noise_level_coupling,eData[1].noiseFloor, 1); + break; + } + + + + /* + Encode envelope of current frame. + */ + switch (stereoMode) { + case SBR_MONO: + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + break; + case SBR_LEFT_RIGHT: + sbrHeaderData->coupling = 0; + + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + + + FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, + h_envChan[1]->encEnvData.domain_vec, + sbrHeaderData->coupling, + eData[1].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + break; + case SBR_COUPLING: + sbrHeaderData->coupling = 1; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + + FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, + sbrHeaderData->coupling, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, + h_envChan[1]->encEnvData.domain_vec, + sbrHeaderData->coupling, + eData[1].frame_info->nEnvelopes, 1, + sbrBitstreamData->HeaderActive); + break; + case SBR_SWITCH_LRC: + { + INT payloadbitsLR; + INT payloadbitsCOUPLING; + + SCHAR sfbNrgPrevTemp[MAX_NUM_CHANNELS][MAX_FREQ_COEFFS]; + SCHAR noisePrevTemp[MAX_NUM_CHANNELS][MAX_NUM_NOISE_COEFFS]; + INT upDateNrgTemp[MAX_NUM_CHANNELS]; + INT upDateNoiseTemp[MAX_NUM_CHANNELS]; + INT domainVecTemp[MAX_NUM_CHANNELS][MAX_ENVELOPES]; + INT domainVecNoiseTemp[MAX_NUM_CHANNELS][MAX_ENVELOPES]; + + INT tempFlagRight = 0; + INT tempFlagLeft = 0; + + /* + Store previous values, in order to be able to "undo" what is being done. + */ + + for(ch = 0; ch < nChannels;ch++){ + FDKmemcpy (sfbNrgPrevTemp[ch], h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev, + MAX_FREQ_COEFFS * sizeof (SCHAR)); + + FDKmemcpy (noisePrevTemp[ch], h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev, + MAX_NUM_NOISE_COEFFS * sizeof (SCHAR)); + + upDateNrgTemp[ch] = h_envChan[ch]->sbrCodeEnvelope.upDate; + upDateNoiseTemp[ch] = h_envChan[ch]->sbrCodeNoiseFloor.upDate; + + /* + forbid time coding in the first envelope in case of a different + previous stereomode + */ + if(sbrHeaderData->prev_coupling){ + h_envChan[ch]->sbrCodeEnvelope.upDate = 0; + h_envChan[ch]->sbrCodeNoiseFloor.upDate = 0; + } + } /* ch */ + + + /* + Code ordinary Left/Right stereo + */ + FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, 0, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, + h_envChan[1]->encEnvData.domain_vec, 0, + eData[1].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + + c = 0; + for (i = 0; i < eData[0].nEnvelopes; i++) { + for (j = 0; j < h_envChan[0]->encEnvData.noScfBands[i]; j++) + { + h_envChan[0]->encEnvData.ienvelope[i][j] = eData[0].sfb_nrg[c]; + h_envChan[1]->encEnvData.ienvelope[i][j] = eData[1].sfb_nrg[c]; + c++; + } + } + + + + FDKsbrEnc_codeEnvelope (eData[0].noise_level, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 0, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[0]->encEnvData.sbr_noise_levels[i] = eData[0].noise_level[i]; + + + FDKsbrEnc_codeEnvelope (eData[1].noise_level, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 0, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[1]->encEnvData.sbr_noise_levels[i] = eData[1].noise_level[i]; + + + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + + payloadbitsLR = FDKsbrEnc_CountSbrChannelPairElement (sbrHeaderData, + hParametricStereo, + sbrBitstreamData, + &h_envChan[0]->encEnvData, + &h_envChan[1]->encEnvData, + hCmonData, + h_con->sbrSyntaxFlags); + + /* + swap saved stored with current values + */ + for(ch = 0; ch < nChannels;ch++){ + INT itmp; + for(i=0;i<MAX_FREQ_COEFFS;i++){ + /* + swap sfb energies + */ + itmp = h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev[i]; + h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev[i]=sfbNrgPrevTemp[ch][i]; + sfbNrgPrevTemp[ch][i]=itmp; + } + for(i=0;i<MAX_NUM_NOISE_COEFFS;i++){ + /* + swap noise energies + */ + itmp = h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev[i]; + h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev[i]=noisePrevTemp[ch][i]; + noisePrevTemp[ch][i]=itmp; + } + /* swap update flags */ + itmp = h_envChan[ch]->sbrCodeEnvelope.upDate; + h_envChan[ch]->sbrCodeEnvelope.upDate=upDateNrgTemp[ch]; + upDateNrgTemp[ch] = itmp; + + itmp = h_envChan[ch]->sbrCodeNoiseFloor.upDate; + h_envChan[ch]->sbrCodeNoiseFloor.upDate=upDateNoiseTemp[ch]; + upDateNoiseTemp[ch]=itmp; + + /* + save domain vecs + */ + FDKmemcpy(domainVecTemp[ch],h_envChan[ch]->encEnvData.domain_vec,sizeof(INT)*MAX_ENVELOPES); + FDKmemcpy(domainVecNoiseTemp[ch],h_envChan[ch]->encEnvData.domain_vec_noise,sizeof(INT)*MAX_ENVELOPES); + + /* + forbid time coding in the first envelope in case of a different + previous stereomode + */ + + if(!sbrHeaderData->prev_coupling){ + h_envChan[ch]->sbrCodeEnvelope.upDate = 0; + h_envChan[ch]->sbrCodeNoiseFloor.upDate = 0; + } + } /* ch */ + + + /* + Coupling + */ + + FDKsbrEnc_codeEnvelope (eData[0].sfb_nrg_coupling, eData[0].frame_info->freqRes, + &h_envChan[0]->sbrCodeEnvelope, + h_envChan[0]->encEnvData.domain_vec, 1, + eData[0].frame_info->nEnvelopes, 0, + sbrBitstreamData->HeaderActive); + + FDKsbrEnc_codeEnvelope (eData[1].sfb_nrg_coupling, eData[1].frame_info->freqRes, + &h_envChan[1]->sbrCodeEnvelope, + h_envChan[1]->encEnvData.domain_vec, 1, + eData[1].frame_info->nEnvelopes, 1, + sbrBitstreamData->HeaderActive); + + + c = 0; + for (i = 0; i < eData[0].nEnvelopes; i++) { + for (j = 0; j < h_envChan[0]->encEnvData.noScfBands[i]; j++) { + h_envChan[0]->encEnvData.ienvelope[i][j] = eData[0].sfb_nrg_coupling[c]; + h_envChan[1]->encEnvData.ienvelope[i][j] = eData[1].sfb_nrg_coupling[c]; + c++; + } + } + + FDKsbrEnc_codeEnvelope (eData[0].noise_level_coupling, fData->res, + &h_envChan[0]->sbrCodeNoiseFloor, + h_envChan[0]->encEnvData.domain_vec_noise, 1, + (eData[0].frame_info->nEnvelopes > 1 ? 2 : 1), 0, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[0]->encEnvData.sbr_noise_levels[i] = eData[0].noise_level_coupling[i]; + + + FDKsbrEnc_codeEnvelope (eData[1].noise_level_coupling, fData->res, + &h_envChan[1]->sbrCodeNoiseFloor, + h_envChan[1]->encEnvData.domain_vec_noise, 1, + (eData[1].frame_info->nEnvelopes > 1 ? 2 : 1), 1, + sbrBitstreamData->HeaderActive); + + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++) + h_envChan[1]->encEnvData.sbr_noise_levels[i] = eData[1].noise_level_coupling[i]; + + sbrHeaderData->coupling = 1; + + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + + tempFlagLeft = h_envChan[0]->encEnvData.addHarmonicFlag; + tempFlagRight = h_envChan[1]->encEnvData.addHarmonicFlag; + + payloadbitsCOUPLING = + FDKsbrEnc_CountSbrChannelPairElement (sbrHeaderData, + hParametricStereo, + sbrBitstreamData, + &h_envChan[0]->encEnvData, + &h_envChan[1]->encEnvData, + hCmonData, + h_con->sbrSyntaxFlags); + + + h_envChan[0]->encEnvData.addHarmonicFlag = tempFlagLeft; + h_envChan[1]->encEnvData.addHarmonicFlag = tempFlagRight; + + if (payloadbitsCOUPLING < payloadbitsLR) { + + /* + copy coded coupling envelope and noise data to l/r + */ + for(ch = 0; ch < nChannels;ch++){ + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + FDKmemcpy (ed->sfb_nrg, ed->sfb_nrg_coupling, + MAX_NUM_ENVELOPE_VALUES * sizeof (SCHAR)); + FDKmemcpy (ed->noise_level, ed->noise_level_coupling, + MAX_NUM_NOISE_VALUES * sizeof (SCHAR)); + } + + sbrHeaderData->coupling = 1; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 1; + } + else{ + /* + restore saved l/r items + */ + for(ch = 0; ch < nChannels;ch++){ + + FDKmemcpy (h_envChan[ch]->sbrCodeEnvelope.sfb_nrg_prev, + sfbNrgPrevTemp[ch], MAX_FREQ_COEFFS * sizeof (SCHAR)); + + h_envChan[ch]->sbrCodeEnvelope.upDate = upDateNrgTemp[ch]; + + FDKmemcpy (h_envChan[ch]->sbrCodeNoiseFloor.sfb_nrg_prev, + noisePrevTemp[ch], MAX_NUM_NOISE_COEFFS * sizeof (SCHAR)); + + FDKmemcpy (h_envChan[ch]->encEnvData.domain_vec,domainVecTemp[ch],sizeof(INT)*MAX_ENVELOPES); + FDKmemcpy (h_envChan[ch]->encEnvData.domain_vec_noise,domainVecNoiseTemp[ch],sizeof(INT)*MAX_ENVELOPES); + + h_envChan[ch]->sbrCodeNoiseFloor.upDate = upDateNoiseTemp[ch]; + } + + sbrHeaderData->coupling = 0; + h_envChan[0]->encEnvData.balance = 0; + h_envChan[1]->encEnvData.balance = 0; + } + } + break; + } /* switch */ + + + /* tell the envelope encoders how long it has been, since we last sent + a frame starting with a dF-coded envelope */ + if (stereoMode == SBR_MONO ) { + if (h_envChan[0]->encEnvData.domain_vec[0] == TIME) + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac++; + else + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + } + else { + if (h_envChan[0]->encEnvData.domain_vec[0] == TIME || + h_envChan[1]->encEnvData.domain_vec[0] == TIME) { + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac++; + h_envChan[1]->sbrCodeEnvelope.dF_edge_incr_fac++; + } + else { + h_envChan[0]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + h_envChan[1]->sbrCodeEnvelope.dF_edge_incr_fac = 0; + } + } + + /* + Send the encoded data to the bitstream + */ + for(ch = 0; ch < nChannels;ch++){ + SBR_ENV_TEMP_DATA *ed = &eData[ch]; + c = 0; + for (i = 0; i < ed->nEnvelopes; i++) { + for (j = 0; j < h_envChan[ch]->encEnvData.noScfBands[i]; j++) { + h_envChan[ch]->encEnvData.ienvelope[i][j] = ed->sfb_nrg[c]; + + c++; + } + } + for (i = 0; i < MAX_NUM_NOISE_VALUES; i++){ + h_envChan[ch]->encEnvData.sbr_noise_levels[i] = ed->noise_level[i]; + } + }/* ch */ + + + /* + Write bitstream + */ + if (nChannels == 2) { + FDKsbrEnc_WriteEnvChannelPairElement(sbrHeaderData, + hParametricStereo, + sbrBitstreamData, + &h_envChan[0]->encEnvData, + &h_envChan[1]->encEnvData, + hCmonData, + h_con->sbrSyntaxFlags); + } + else { + FDKsbrEnc_WriteEnvSingleChannelElement(sbrHeaderData, + hParametricStereo, + sbrBitstreamData, + &h_envChan[0]->encEnvData, + hCmonData, + h_con->sbrSyntaxFlags); + } + + /* + * Update buffers. + */ + for (ch=0; ch<nChannels; ch++) + { + int YBufferLength = h_envChan[ch]->sbrExtractEnvelope.no_cols >> h_envChan[ch]->sbrExtractEnvelope.YBufferSzShift; + for (i = 0; i < h_envChan[ch]->sbrExtractEnvelope.YBufferWriteOffset; i++) { + FDKmemcpy(h_envChan[ch]->sbrExtractEnvelope.YBuffer[i], + h_envChan[ch]->sbrExtractEnvelope.YBuffer[i + YBufferLength], + sizeof(FIXP_DBL)*QMF_CHANNELS); + } + h_envChan[ch]->sbrExtractEnvelope.YBufferScale[0] = h_envChan[ch]->sbrExtractEnvelope.YBufferScale[1]; + } + + sbrHeaderData->prev_coupling = sbrHeaderData->coupling; +} + +/***************************************************************************/ +/*! + + \brief creates an envelope extractor handle + + \return error status + +****************************************************************************/ +INT +FDKsbrEnc_CreateExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, + INT channel + ,INT chInEl + ,UCHAR* dynamic_RAM + ) +{ + INT i; + FIXP_DBL* YBuffer = GetRam_Sbr_envYBuffer(channel); + + FDKmemclear(hSbrCut,sizeof(SBR_EXTRACT_ENVELOPE)); + hSbrCut->p_YBuffer = YBuffer; + + + for (i = 0; i < (QMF_MAX_TIME_SLOTS>>1); i++) { + hSbrCut->YBuffer[i] = YBuffer + (i*QMF_CHANNELS); + } + FIXP_DBL *YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM); + INT n=0; + for (; i < QMF_MAX_TIME_SLOTS; i++,n++) { + hSbrCut->YBuffer[i] = YBufferDyn + (n*QMF_CHANNELS); + } + + FIXP_DBL* rBuffer = GetRam_Sbr_envRBuffer(0, dynamic_RAM); + FIXP_DBL* iBuffer = GetRam_Sbr_envIBuffer(0, dynamic_RAM); + + for (i = 0; i < QMF_MAX_TIME_SLOTS; i++) { + hSbrCut->rBuffer[i] = rBuffer + (i*QMF_CHANNELS); + hSbrCut->iBuffer[i] = iBuffer + (i*QMF_CHANNELS); + } + + return 0; +} + + +/***************************************************************************/ +/*! + + \brief Initialize an envelope extractor instance. + + \return error status + +****************************************************************************/ +INT +FDKsbrEnc_InitExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, + int no_cols, + int no_rows, + int start_index, + int time_slots, + int time_step, + int tran_off, + ULONG statesInitFlag + ,int chInEl + ,UCHAR* dynamic_RAM + ,UINT sbrSyntaxFlags + ) +{ + int YBufferLength, rBufferLength; + int i; + + if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + int off = TRANSIENT_OFFSET_LD; +#ifndef FULL_DELAY + hSbrCut->YBufferWriteOffset = (no_cols>>1)+off*time_step; +#else + hSbrCut->YBufferWriteOffset = no_cols+off*time_step; +#endif + } else + { + hSbrCut->YBufferWriteOffset = tran_off*time_step; + } + hSbrCut->rBufferWriteOffset = 0; + hSbrCut->rBufferReadOffset = 0; + + + YBufferLength = hSbrCut->YBufferWriteOffset + no_cols; + rBufferLength = hSbrCut->rBufferWriteOffset + no_cols; + + hSbrCut->pre_transient_info[0] = 0; + hSbrCut->pre_transient_info[1] = 0; + + + hSbrCut->no_cols = no_cols; + hSbrCut->no_rows = no_rows; + hSbrCut->start_index = start_index; + + hSbrCut->time_slots = time_slots; + hSbrCut->time_step = time_step; + + //FDK_ASSERT(rBufferLength == no_cols); + //FDK_ASSERT(YBufferLength == 2*no_cols); + FDK_ASSERT(no_rows <= QMF_CHANNELS); + + /* Use half the Energy values if time step is 2 or greater */ + if (time_step >= 2) + hSbrCut->YBufferSzShift = 1; + else + hSbrCut->YBufferSzShift = 0; + + YBufferLength >>= hSbrCut->YBufferSzShift; + hSbrCut->YBufferWriteOffset >>= hSbrCut->YBufferSzShift; + + FDK_ASSERT(YBufferLength<=QMF_MAX_TIME_SLOTS); + + FIXP_DBL *YBufferDyn = GetRam_Sbr_envYBuffer(chInEl, dynamic_RAM); + INT n=0; + for (i=(QMF_MAX_TIME_SLOTS>>1); i < QMF_MAX_TIME_SLOTS; i++,n++) { + hSbrCut->YBuffer[i] = YBufferDyn + (n*QMF_CHANNELS); + } + + if(statesInitFlag) { + for (i=0; i<YBufferLength; i++) { + FDKmemclear( hSbrCut->YBuffer[i],QMF_CHANNELS*sizeof(FIXP_DBL)); + } + } + + for (i = 0; i < rBufferLength; i++) { + FDKmemclear( hSbrCut->rBuffer[i],QMF_CHANNELS*sizeof(FIXP_DBL)); + FDKmemclear( hSbrCut->iBuffer[i],QMF_CHANNELS*sizeof(FIXP_DBL)); + } + + FDKmemclear (hSbrCut->envelopeCompensation,sizeof(UCHAR)*MAX_FREQ_COEFFS); + + if(statesInitFlag) { + hSbrCut->YBufferScale[0] = hSbrCut->YBufferScale[1] = FRACT_BITS-1; + } + + return (0); +} + + + + +/***************************************************************************/ +/*! + + \brief deinitializes an envelope extractor handle + + \return void + +****************************************************************************/ + +void +FDKsbrEnc_deleteExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut) +{ + + if (hSbrCut) { + FreeRam_Sbr_envYBuffer(&hSbrCut->p_YBuffer); + } +} + +INT +FDKsbrEnc_GetEnvEstDelay(HANDLE_SBR_EXTRACT_ENVELOPE hSbr) +{ + return hSbr->no_rows*((hSbr->YBufferWriteOffset)*2 + /* mult 2 because nrg's are grouped half */ + hSbr->rBufferWriteOffset - hSbr->rBufferReadOffset ); /* in reference hold half spec and calc nrg's on overlapped spec */ + +} + + + + diff --git a/libSBRenc/src/env_est.h b/libSBRenc/src/env_est.h new file mode 100644 index 0000000..5aa66ee --- /dev/null +++ b/libSBRenc/src/env_est.h @@ -0,0 +1,167 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief Envelope estimation structs and prototypes $Revision: 36847 $ +*/ +#ifndef __ENV_EST_H +#define __ENV_EST_H + +#include "sbr_def.h" +#include "sbr_encoder.h" /* SBR econfig structs */ +#include "ps_main.h" +#include "bit_sbr.h" +#include "fram_gen.h" +#include "tran_det.h" +#include "code_env.h" +#include "ton_corr.h" + +typedef struct +{ + FIXP_DBL *rBuffer[QMF_MAX_TIME_SLOTS]; + FIXP_DBL *iBuffer[QMF_MAX_TIME_SLOTS]; + + FIXP_DBL *p_YBuffer; + + FIXP_DBL *YBuffer[QMF_MAX_TIME_SLOTS]; + int YBufferScale[2]; + + UCHAR envelopeCompensation[MAX_FREQ_COEFFS]; + UCHAR pre_transient_info[2]; + + + int YBufferWriteOffset; + int YBufferSzShift; + int rBufferReadOffset; + int rBufferWriteOffset; + + int no_cols; + int no_rows; + int start_index; + + int time_slots; + int time_step; +} +SBR_EXTRACT_ENVELOPE; +typedef SBR_EXTRACT_ENVELOPE *HANDLE_SBR_EXTRACT_ENVELOPE; + +struct ENV_CHANNEL +{ + SBR_TRANSIENT_DETECTOR sbrTransientDetector; + SBR_CODE_ENVELOPE sbrCodeEnvelope; + SBR_CODE_ENVELOPE sbrCodeNoiseFloor; + SBR_EXTRACT_ENVELOPE sbrExtractEnvelope; + + + SBR_ENVELOPE_FRAME SbrEnvFrame; + SBR_TON_CORR_EST TonCorr; + + struct SBR_ENV_DATA encEnvData; + + int qmfScale; + UCHAR fLevelProtect; +}; +typedef struct ENV_CHANNEL *HANDLE_ENV_CHANNEL; + +/************ Function Declarations ***************/ + +INT +FDKsbrEnc_CreateExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, + INT channel + ,INT chInEl + ,UCHAR* dynamic_RAM + ); + + +INT +FDKsbrEnc_InitExtractSbrEnvelope ( + HANDLE_SBR_EXTRACT_ENVELOPE hSbr, + int no_cols, + int no_rows, + int start_index, + int time_slots, int time_step, int tran_off, + ULONG statesInitFlag + ,int chInEl + ,UCHAR* dynamic_RAM + ,UINT sbrSyntaxFlags + ); + +void FDKsbrEnc_deleteExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut); + +typedef struct { + FREQ_RES res[MAX_NUM_NOISE_VALUES]; + int maxQuantError; + +} SBR_FRAME_TEMP_DATA; + +typedef struct { + const SBR_FRAME_INFO *frame_info; + FIXP_DBL noiseFloor[MAX_NUM_NOISE_VALUES]; + SCHAR sfb_nrg_coupling[MAX_NUM_ENVELOPE_VALUES]; /* only used if stereomode = SWITCH_L_R_C */ + SCHAR sfb_nrg[MAX_NUM_ENVELOPE_VALUES]; + SCHAR noise_level_coupling[MAX_NUM_NOISE_VALUES]; /* only used if stereomode = SWITCH_L_R_C */ + SCHAR noise_level[MAX_NUM_NOISE_VALUES]; + UCHAR transient_info[3]; + UCHAR nEnvelopes; +} SBR_ENV_TEMP_DATA; + +/* + * Extract features from QMF data. Afterwards, the QMF data is not required anymore. + */ +void +FDKsbrEnc_extractSbrEnvelope1( + HANDLE_SBR_CONFIG_DATA h_con, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_ENV_CHANNEL h_envChan, + HANDLE_COMMON_DATA cmonData, + SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData + ); + + +/* + * Process the previously features extracted by FDKsbrEnc_extractSbrEnvelope1 + * and create/encode SBR envelopes. + */ +void +FDKsbrEnc_extractSbrEnvelope2( + HANDLE_SBR_CONFIG_DATA h_con, + HANDLE_SBR_HEADER_DATA sbrHeaderData, + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_SBR_BITSTREAM_DATA sbrBitstreamData, + HANDLE_ENV_CHANNEL sbrEnvChannel0, + HANDLE_ENV_CHANNEL sbrEnvChannel1, + HANDLE_COMMON_DATA cmonData, + SBR_ENV_TEMP_DATA *eData, + SBR_FRAME_TEMP_DATA *fData, + int clearOutput + ); + +INT +FDKsbrEnc_GetEnvEstDelay(HANDLE_SBR_EXTRACT_ENVELOPE hSbr); + +#endif diff --git a/libSBRenc/src/fram_gen.cpp b/libSBRenc/src/fram_gen.cpp new file mode 100644 index 0000000..710b13e --- /dev/null +++ b/libSBRenc/src/fram_gen.cpp @@ -0,0 +1,2015 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +#include "fram_gen.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +static const SBR_FRAME_INFO frameInfo1_2048 = { + 1, + { 0, 16}, + {FREQ_RES_HIGH}, + 0, + 1, + {0, 16} }; + +static const SBR_FRAME_INFO frameInfo2_2048 = { + 2, + { 0, 8, 16}, + {FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 8, 16} }; + +static const SBR_FRAME_INFO frameInfo4_2048 = { + 4, + { 0, 4, 8, 12, 16}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 8, 16} }; + +static const SBR_FRAME_INFO frameInfo1_2304 = { + 1, + { 0, 18}, + {FREQ_RES_HIGH}, + 0, + 1, + { 0, 18} }; + +static const SBR_FRAME_INFO frameInfo2_2304 = { + 2, + { 0, 9, 18}, + {FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 9, 18} }; + +static const SBR_FRAME_INFO frameInfo4_2304 = { + 4, + { 0, 5, 9, 14, 18}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 9, 18} }; + +static const SBR_FRAME_INFO frameInfo1_1920 = { + 1, + { 0, 15}, + {FREQ_RES_HIGH}, + 0, + 1, + { 0, 15} }; + +static const SBR_FRAME_INFO frameInfo2_1920 = { + 2, + { 0, 8, 15}, + {FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 8, 15} }; + +static const SBR_FRAME_INFO frameInfo4_1920 = { + 4, + { 0, 4, 8, 12, 15}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 8, 15} }; + +static const SBR_FRAME_INFO frameInfo1_1152 = { + 1, + { 0, 9}, + {FREQ_RES_HIGH}, + 0, + 1, + { 0, 9} }; + +static const SBR_FRAME_INFO frameInfo2_1152 = { + 2, + { 0, 5, 9}, + {FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 5, 9} }; + +static const SBR_FRAME_INFO frameInfo4_1152 = { + 4, + { 0, 2, 5, + 7, 9}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + { 0, 5, 9} }; + + +/* AACLD frame info */ +static const SBR_FRAME_INFO frameInfo1_512LD = { + 1, + {0, 8}, + {FREQ_RES_HIGH}, + 0, + 1, + {0, 8}}; + +static const SBR_FRAME_INFO frameInfo2_512LD = { + 2, + {0, 4, 8}, + {FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + {0, 4, 8}}; + +static const SBR_FRAME_INFO frameInfo4_512LD = { + 4, + {0, 2, 4, 6, 8}, + {FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}, + 0, + 2, + {0, 4, 8}}; + +static int +calcFillLengthMax (int tranPos, /*!< input : transient position (ref: tran det) */ + int numberTimeSlots /*!< input : number of timeslots */ + ); + +static void +fillFrameTran (const int *v_tuningSegm, /*!< tuning: desired segment lengths */ + const int *v_tuningFreq, /*!< tuning: desired frequency resolutions */ + int tran, /*!< input : position of transient */ + int *v_bord, /*!< memNew: borders */ + int *length_v_bord, /*!< memNew: # borders */ + int *v_freq, /*!< memNew: frequency resolutions */ + int *length_v_freq, /*!< memNew: # frequency resolutions */ + int *bmin, /*!< hlpNew: first mandatory border */ + int *bmax /*!< hlpNew: last mandatory border */ + ); + +static void fillFramePre (INT dmax, INT *v_bord, INT *length_v_bord, + INT *v_freq, INT *length_v_freq, INT bmin, + INT rest); + +static void fillFramePost (INT *parts, INT *d, INT dmax, INT *v_bord, + INT *length_v_bord, INT *v_freq, + INT *length_v_freq, INT bmax, + INT bufferFrameStart, INT numberTimeSlots, INT fmax); + +static void fillFrameInter (INT *nL, const int *v_tuningSegm, INT *v_bord, + INT *length_v_bord, INT bmin, INT *v_freq, + INT *length_v_freq, INT *v_bordFollow, + INT *length_v_bordFollow, INT *v_freqFollow, + INT *length_v_freqFollow, INT i_fillFollow, + INT dmin, INT dmax, INT numberTimeSlots); + +static void calcFrameClass (FRAME_CLASS *frameClass, FRAME_CLASS *frameClassOld, INT tranFlag, + INT *spreadFlag); + +static void specialCase (INT *spreadFlag, INT allowSpread, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT *length_v_freq, + INT *parts, INT d); + +static void calcCmonBorder (INT *i_cmon, INT *i_tran, INT *v_bord, + INT *length_v_bord, INT tran, + INT bufferFrameStart, INT numberTimeSlots); + +static void keepForFollowUp (INT *v_bordFollow, INT *length_v_bordFollow, + INT *v_freqFollow, INT *length_v_freqFollow, + INT *i_tranFollow, INT *i_fillFollow, + INT *v_bord, INT *length_v_bord, INT *v_freq, + INT i_cmon, INT i_tran, INT parts, INT numberTimeSlots); + +static void calcCtrlSignal (HANDLE_SBR_GRID hSbrGrid, FRAME_CLASS frameClass, + INT *v_bord, INT length_v_bord, INT *v_freq, + INT length_v_freq, INT i_cmon, INT i_tran, + INT spreadFlag, INT nL); + +static void ctrlSignal2FrameInfo (HANDLE_SBR_GRID hSbrGrid, + HANDLE_SBR_FRAME_INFO hFrameInfo, + INT freq_res_fixfix); + + +/* table for 8 time slot index */ +static const int envelopeTable_8 [8][5] = { +/* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ +/* borders from left to right side; -1 = not in use */ + /*[|T-|------]*/ { 2, 0, 0, 1, -1 }, + /*[|-T-|-----]*/ { 2, 0, 0, 2, -1 }, + /*[--|T-|----]*/ { 3, 1, 1, 2, 4 }, + /*[---|T-|---]*/ { 3, 1, 1, 3, 5 }, + /*[----|T-|--]*/ { 3, 1, 1, 4, 6 }, + /*[-----|T--|]*/ { 2, 1, 1, 5, -1 }, + /*[------|T-|]*/ { 2, 1, 1, 6, -1 }, + /*[-------|T|]*/ { 2, 1, 1, 7, -1 }, +}; + +/* table for 16 time slot index */ +static const int envelopeTable_16 [16][6] = { + /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ + /* length from left to right side; -1 = not in use */ + /*[|T---|------------|]*/ { 2, 0, 0, 4, -1, -1}, + /*[|-T---|-----------|]*/ { 2, 0, 0, 5, -1, -1}, + /*[|--|T---|----------]*/ { 3, 1, 1, 2, 6, -1}, + /*[|---|T---|---------]*/ { 3, 1, 1, 3, 7, -1}, + /*[|----|T---|--------]*/ { 3, 1, 1, 4, 8, -1}, + /*[|-----|T---|-------]*/ { 3, 1, 1, 5, 9, -1}, + /*[|------|T---|------]*/ { 3, 1, 1, 6, 10, -1}, + /*[|-------|T---|-----]*/ { 3, 1, 1, 7, 11, -1}, + /*[|--------|T---|----]*/ { 3, 1, 1, 8, 12, -1}, + /*[|---------|T---|---]*/ { 3, 1, 1, 9, 13, -1}, + /*[|----------|T---|--]*/ { 3, 1, 1,10, 14, -1}, + /*[|-----------|T----|]*/ { 2, 1, 1,11, -1, -1}, + /*[|------------|T---|]*/ { 2, 1, 1,12, -1, -1}, + /*[|-------------|T--|]*/ { 2, 1, 1,13, -1, -1}, + /*[|--------------|T-|]*/ { 2, 1, 1,14, -1, -1}, + /*[|---------------|T|]*/ { 2, 1, 1,15, -1, -1}, +}; + +/* table for 15 time slot index */ +static const int envelopeTable_15 [15][6] = { + /* transientIndex nEnv, tranIdx, shortEnv, border1, border2, ... */ + /* length from left to right side; -1 = not in use */ + /*[|T---|------------]*/ { 2, 0, 0, 4, -1, -1}, + /*[|-T---|-----------]*/ { 2, 0, 0, 5, -1, -1}, + /*[|--|T---|---------]*/ { 3, 1, 1, 2, 6, -1}, + /*[|---|T---|--------]*/ { 3, 1, 1, 3, 7, -1}, + /*[|----|T---|-------]*/ { 3, 1, 1, 4, 8, -1}, + /*[|-----|T---|------]*/ { 3, 1, 1, 5, 9, -1}, + /*[|------|T---|-----]*/ { 3, 1, 1, 6, 10, -1}, + /*[|-------|T---|----]*/ { 3, 1, 1, 7, 11, -1}, + /*[|--------|T---|---]*/ { 3, 1, 1, 8, 12, -1}, + /*[|---------|T---|--]*/ { 3, 1, 1, 9, 13, -1}, + /*[|----------|T----|]*/ { 2, 1, 1,10, -1, -1}, + /*[|-----------|T---|]*/ { 2, 1, 1,11, -1, -1}, + /*[|------------|T--|]*/ { 2, 1, 1,12, -1, -1}, + /*[|-------------|T-|]*/ { 2, 1, 1,13, -1, -1}, + /*[|--------------|T|]*/ { 2, 1, 1,14, -1, -1}, +}; + +static const int minFrameTranDistance = 4; + +static const FREQ_RES freqRes_table_8[] = {FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, + FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH}; + +static const FREQ_RES freqRes_table_16[16] = { + /* size of envelope */ +/* 0-4 */ FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, FREQ_RES_LOW, +/* 5-9 */ FREQ_RES_LOW, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, +/* 10-16 */ FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, FREQ_RES_HIGH, + FREQ_RES_HIGH }; + +static void generateFixFixOnly ( HANDLE_SBR_FRAME_INFO hSbrFrameInfo, + HANDLE_SBR_GRID hSbrGrid, + int tranPosInternal, + int numberTimeSlots + ); + + +/*! + Functionname: FDKsbrEnc_frameInfoGenerator + + Description: produces the FRAME_INFO struct for the current frame + + Arguments: hSbrEnvFrame - pointer to sbr envelope handle + v_pre_transient_info - pointer to transient info vector + v_transient_info - pointer to previous transient info vector + v_tuning - pointer to tuning vector + + Return: frame_info - pointer to SBR_FRAME_INFO struct + +*******************************************************************************/ +HANDLE_SBR_FRAME_INFO +FDKsbrEnc_frameInfoGenerator (HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + UCHAR *v_transient_info, + UCHAR *v_transient_info_pre, + int ldGrid, + const int *v_tuning) +{ + INT numEnv, tranPosInternal=0, bmin=0, bmax=0, parts, d, i_cmon=0, i_tran=0, nL; + INT fmax = 0; + + INT *v_bord = hSbrEnvFrame->v_bord; + INT *v_freq = hSbrEnvFrame->v_freq; + INT *v_bordFollow = hSbrEnvFrame->v_bordFollow; + INT *v_freqFollow = hSbrEnvFrame->v_freqFollow; + + + INT *length_v_bordFollow = &hSbrEnvFrame->length_v_bordFollow; + INT *length_v_freqFollow = &hSbrEnvFrame->length_v_freqFollow; + INT *length_v_bord = &hSbrEnvFrame->length_v_bord; + INT *length_v_freq = &hSbrEnvFrame->length_v_freq; + INT *spreadFlag = &hSbrEnvFrame->spreadFlag; + INT *i_tranFollow = &hSbrEnvFrame->i_tranFollow; + INT *i_fillFollow = &hSbrEnvFrame->i_fillFollow; + FRAME_CLASS *frameClassOld = &hSbrEnvFrame->frameClassOld; + FRAME_CLASS frameClass = FIXFIX; + + + INT allowSpread = hSbrEnvFrame->allowSpread; + INT numEnvStatic = hSbrEnvFrame->numEnvStatic; + INT staticFraming = hSbrEnvFrame->staticFraming; + INT dmin = hSbrEnvFrame->dmin; + INT dmax = hSbrEnvFrame->dmax; + + INT bufferFrameStart = hSbrEnvFrame->SbrGrid.bufferFrameStart; + INT numberTimeSlots = hSbrEnvFrame->SbrGrid.numberTimeSlots; + INT frameMiddleSlot = hSbrEnvFrame->frameMiddleSlot; + + INT tranPos = v_transient_info[0]; + INT tranFlag = v_transient_info[1]; + + const int *v_tuningSegm = v_tuning; + const int *v_tuningFreq = v_tuning + 3; + + hSbrEnvFrame->v_tuningSegm = v_tuningSegm; + INT freq_res_fixfix = hSbrEnvFrame->freq_res_fixfix; + + if (ldGrid) { + /* in case there was a transient at the very end of the previous frame, start with a transient envelope */ + if(v_transient_info_pre[1] && (numberTimeSlots - v_transient_info_pre[0] < minFrameTranDistance)){ + tranFlag = 1; + tranPos = 0; + } + } + + /* + * Synopsis: + * + * The frame generator creates the time-/frequency-grid for one SBR frame. + * Input signals are provided by the transient detector and the frame + * splitter (transientDetectNew() & FrameSplitter() in tran_det.c). The + * framing is controlled by adjusting tuning parameters stored in + * FRAME_GEN_TUNING. The parameter values are dependent on frame lengths + * and bitrates, and may in the future be signal dependent. + * + * The envelope borders are stored for frame generator internal use in + * aBorders. The contents of aBorders represent positions along the time + * axis given in the figures in fram_gen.h (the "frame-generator" rows). + * The unit is "time slot". The figures in fram_gen.h also define the + * detection ranges for the transient detector. For every border in + * aBorders, there is a corresponding entry in aFreqRes, which defines the + * frequency resolution of the envelope following (delimited by) the + * border. + * + * When no transients are present, FIXFIX class frames are used. The + * frame splitter decides whether to use one or two envelopes in the + * FIXFIX frame. "Sparse transients" (separated by a few frames without + * transients) are handeled by [FIXVAR, VARFIX] pairs or (depending on + * tuning and transient position relative the nominal frame boundaries) + * by [FIXVAR, VARVAR, VARFIX] triples. "Tight transients" (in + * consecutive frames) are handeled by [..., VARVAR, VARVAR, ...] + * sequences. + * + * The generator assumes that transients are "sparse", and designs + * borders for [FIXVAR, VARFIX] pairs right away, where the first frame + * corresponds to the present frame. At the next call of the generator + * it is known whether the transient actually is "sparse" or not. If + * 'yes', the already calculated VARFIX borders are used. If 'no', new + * borders, meeting the requirements of the "tight" transient, are + * calculated. + * + * The generator produces two outputs: A "clear-text bitstream" stored in + * SBR_GRID, and a straight-forward representation of the grid stored in + * SBR_FRAME_INFO. The former is subsequently converted to the actual + * bitstream sbr_grid() (encodeSbrGrid() in bit_sbr.c). The latter is + * used by other encoder functions, such as the envelope estimator + * (calculateSbrEnvelope() in env_est.c) and the noise floor and missing + * harmonics detector (TonCorrParamExtr() in nf_est.c). + */ + + if (staticFraming) { + /*-------------------------------------------------------------------------- + Ignore transient detector + ---------------------------------------------------------------------------*/ + + frameClass = FIXFIX; + numEnv = numEnvStatic; /* {1,2,4,8} */ + *frameClassOld = FIXFIX; /* for change to dyn */ + hSbrEnvFrame->SbrGrid.bs_num_env = numEnv; + hSbrEnvFrame->SbrGrid.frameClass = frameClass; + } + else { + /*-------------------------------------------------------------------------- + Calculate frame class to use + ---------------------------------------------------------------------------*/ + calcFrameClass (&frameClass, frameClassOld, tranFlag, spreadFlag); + + /* patch for new frame class FIXFIXonly for AAC LD */ + if (tranFlag && ldGrid) { + frameClass = FIXFIXonly; + *frameClassOld = FIXFIX; + } + + /* + * every transient is processed below by inserting + * + * - one border at the onset of the transient + * - one or more "decay borders" (after the onset of the transient) + * - optionally one "attack border" (before the onset of the transient) + * + * those borders are referred to as "mandatory borders" and are + * defined by the 'segmentLength' array in FRAME_GEN_TUNING + * + * the frequency resolutions of the corresponding envelopes are + * defined by the 'segmentRes' array in FRAME_GEN_TUNING + */ + + /*-------------------------------------------------------------------------- + Design frame (or follow-up old design) + ---------------------------------------------------------------------------*/ + if (tranFlag) { /* Always for FixVar, often but not always for VarVar */ + /*-------------------------------------------------------------------------- + Design part of T/F-grid around the new transient + ---------------------------------------------------------------------------*/ + + tranPosInternal = frameMiddleSlot + tranPos + bufferFrameStart ; /* FH 00-06-26 */ + /* + add mandatory borders around transient + */ + + fillFrameTran ( v_tuningSegm, + v_tuningFreq, + tranPosInternal, + v_bord, + length_v_bord, + v_freq, + length_v_freq, + &bmin, + &bmax ); + + /* make sure we stay within the maximum SBR frame overlap */ + fmax = calcFillLengthMax(tranPos, numberTimeSlots); + } + + switch (frameClass) { + + case FIXFIXonly: + FDK_ASSERT(ldGrid); + tranPosInternal = tranPos; + generateFixFixOnly ( &(hSbrEnvFrame->SbrFrameInfo), + &(hSbrEnvFrame->SbrGrid), + tranPosInternal, + numberTimeSlots + ); + + return &(hSbrEnvFrame->SbrFrameInfo); + + case FIXVAR: + + /*-------------------------------------------------------------------------- + Design remaining parts of T/F-grid (assuming next frame is VarFix) + ---------------------------------------------------------------------------*/ + + /*-------------------------------------------------------------------------- + Fill region before new transient: + ---------------------------------------------------------------------------*/ + fillFramePre (dmax, v_bord, length_v_bord, v_freq, length_v_freq, + bmin, bmin - bufferFrameStart); /* FH 00-06-26 */ + + /*-------------------------------------------------------------------------- + Fill region after new transient: + ---------------------------------------------------------------------------*/ + fillFramePost (&parts, &d, dmax, v_bord, length_v_bord, v_freq, + length_v_freq, bmax, bufferFrameStart, numberTimeSlots, fmax); + + /*-------------------------------------------------------------------------- + Take care of special case: + ---------------------------------------------------------------------------*/ + if (parts == 1 && d < dmin) /* no fill, short last envelope */ + specialCase (spreadFlag, allowSpread, v_bord, length_v_bord, + v_freq, length_v_freq, &parts, d); + + /*-------------------------------------------------------------------------- + Calculate common border (split-point) + ---------------------------------------------------------------------------*/ + calcCmonBorder (&i_cmon, &i_tran, v_bord, length_v_bord, tranPosInternal, + bufferFrameStart, numberTimeSlots); /* FH 00-06-26 */ + + /*-------------------------------------------------------------------------- + Extract data for proper follow-up in next frame + ---------------------------------------------------------------------------*/ + keepForFollowUp (v_bordFollow, length_v_bordFollow, v_freqFollow, + length_v_freqFollow, i_tranFollow, i_fillFollow, + v_bord, length_v_bord, v_freq, i_cmon, i_tran, parts, numberTimeSlots); /* FH 00-06-26 */ + + /*-------------------------------------------------------------------------- + Calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal (&hSbrEnvFrame->SbrGrid, frameClass, + v_bord, *length_v_bord, v_freq, *length_v_freq, + i_cmon, i_tran, *spreadFlag, DC); + break; + case VARFIX: + /*-------------------------------------------------------------------------- + Follow-up old transient - calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal (&hSbrEnvFrame->SbrGrid, frameClass, + v_bordFollow, *length_v_bordFollow, v_freqFollow, + *length_v_freqFollow, DC, *i_tranFollow, + *spreadFlag, DC); + break; + case VARVAR: + if (*spreadFlag) { /* spread across three frames */ + /*-------------------------------------------------------------------------- + Follow-up old transient - calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal (&hSbrEnvFrame->SbrGrid, + frameClass, v_bordFollow, *length_v_bordFollow, + v_freqFollow, *length_v_freqFollow, DC, + *i_tranFollow, *spreadFlag, DC); + + *spreadFlag = 0; + + /*-------------------------------------------------------------------------- + Extract data for proper follow-up in next frame + ---------------------------------------------------------------------------*/ + v_bordFollow[0] = hSbrEnvFrame->SbrGrid.bs_abs_bord_1 - numberTimeSlots; /* FH 00-06-26 */ + v_freqFollow[0] = 1; + *length_v_bordFollow = 1; + *length_v_freqFollow = 1; + + *i_tranFollow = -DC; + *i_fillFollow = -DC; + } + else { + /*-------------------------------------------------------------------------- + Design remaining parts of T/F-grid (assuming next frame is VarFix) + adapt or fill region before new transient: + ---------------------------------------------------------------------------*/ + fillFrameInter (&nL, v_tuningSegm, v_bord, length_v_bord, bmin, + v_freq, length_v_freq, v_bordFollow, + length_v_bordFollow, v_freqFollow, + length_v_freqFollow, *i_fillFollow, dmin, dmax, + numberTimeSlots); + + /*-------------------------------------------------------------------------- + Fill after transient: + ---------------------------------------------------------------------------*/ + fillFramePost (&parts, &d, dmax, v_bord, length_v_bord, v_freq, + length_v_freq, bmax, bufferFrameStart, numberTimeSlots, fmax); + + /*-------------------------------------------------------------------------- + Take care of special case: + ---------------------------------------------------------------------------*/ + if (parts == 1 && d < dmin) /*% no fill, short last envelope */ + specialCase (spreadFlag, allowSpread, v_bord, length_v_bord, + v_freq, length_v_freq, &parts, d); + + /*-------------------------------------------------------------------------- + Calculate common border (split-point) + ---------------------------------------------------------------------------*/ + calcCmonBorder (&i_cmon, &i_tran, v_bord, length_v_bord, tranPosInternal, + bufferFrameStart, numberTimeSlots); + + /*-------------------------------------------------------------------------- + Extract data for proper follow-up in next frame + ---------------------------------------------------------------------------*/ + keepForFollowUp (v_bordFollow, length_v_bordFollow, + v_freqFollow, length_v_freqFollow, + i_tranFollow, i_fillFollow, v_bord, + length_v_bord, v_freq, i_cmon, i_tran, parts, numberTimeSlots); + + /*-------------------------------------------------------------------------- + Calculate control signal + ---------------------------------------------------------------------------*/ + calcCtrlSignal (&hSbrEnvFrame->SbrGrid, + frameClass, v_bord, *length_v_bord, v_freq, + *length_v_freq, i_cmon, i_tran, 0, nL); + } + break; + case FIXFIX: + if (tranPos == 0) + numEnv = 1; + else + numEnv = 2; + + hSbrEnvFrame->SbrGrid.bs_num_env = numEnv; + hSbrEnvFrame->SbrGrid.frameClass = frameClass; + + break; + default: + FDK_ASSERT(0); + } + } + + /*------------------------------------------------------------------------- + Convert control signal to frame info struct + ---------------------------------------------------------------------------*/ + ctrlSignal2FrameInfo (&hSbrEnvFrame->SbrGrid, + &hSbrEnvFrame->SbrFrameInfo, + freq_res_fixfix); + + return &hSbrEnvFrame->SbrFrameInfo; +} + + +/***************************************************************************/ +/*! + \brief Gnerates frame info for FIXFIXonly frame class used for low delay version + + \return nothing + ****************************************************************************/ +static void generateFixFixOnly ( HANDLE_SBR_FRAME_INFO hSbrFrameInfo, + HANDLE_SBR_GRID hSbrGrid, + int tranPosInternal, + int numberTimeSlots + ) +{ + int nEnv, i, k=0, tranIdx; + const int *pTable = NULL; + const FREQ_RES *freqResTable = NULL; + + switch (numberTimeSlots) { + case 8: + pTable = envelopeTable_8[tranPosInternal]; + freqResTable = freqRes_table_8; + break; + case 15: + pTable = envelopeTable_15[tranPosInternal]; + freqResTable = freqRes_table_16; + break; + case 16: + pTable = envelopeTable_16[tranPosInternal]; + freqResTable = freqRes_table_16; + break; + } + + /* look number of envolpes in table */ + nEnv = pTable[0]; + /* look up envolpe distribution in table */ + for (i=1; i<nEnv; i++) + hSbrFrameInfo->borders[i] = pTable[i+2]; + + /* open and close frame border */ + hSbrFrameInfo->borders[0] = 0; + hSbrFrameInfo->borders[nEnv] = numberTimeSlots; + + /* adjust segment-frequency-resolution according to the segment-length */ + for (i=0; i<nEnv; i++){ + k = hSbrFrameInfo->borders[i+1] - hSbrFrameInfo->borders[i]; + hSbrFrameInfo->freqRes[i] = freqResTable[k]; + //hSbrFrameInfo->freqRes[i] = (k < tuning.minEnvSize4highRes) ? FREQ_RES_LOW : FREQ_RES_HIGH; + hSbrGrid->v_f[i] = freqResTable[k]; + } + + hSbrFrameInfo->nEnvelopes = nEnv; + hSbrFrameInfo->shortEnv = pTable[2]; + /* transient idx */ + tranIdx = pTable[1]; + + /* add noise floors */ + hSbrFrameInfo->bordersNoise[0] = 0; + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[tranIdx?tranIdx:1]; + hSbrFrameInfo->bordersNoise[2] = numberTimeSlots; + hSbrFrameInfo->nNoiseEnvelopes = 2; + + hSbrGrid->frameClass = FIXFIXonly; + hSbrGrid->bs_abs_bord = tranPosInternal; + hSbrGrid->bs_num_env = nEnv; + +} + + + +/******************************************************************************* + Functionname: FDKsbrEnc_initFrameInfoGenerator + ******************************************************************************* + + Description: + + Arguments: hSbrEnvFrame - pointer to sbr envelope handle + allowSpread - commandline parameter + numEnvStatic - commandline parameter + staticFraming - commandline parameter + + Return: none + +*******************************************************************************/ +void +FDKsbrEnc_initFrameInfoGenerator (HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + INT allowSpread, + INT numEnvStatic, + INT staticFraming, + INT timeSlots, + INT freq_res_fixfix + ,int ldGrid + ) + +{ /* FH 00-06-26 */ + + FDKmemclear(hSbrEnvFrame,sizeof(SBR_ENVELOPE_FRAME )); + + + /* Initialisation */ + hSbrEnvFrame->frameClassOld = FIXFIX; + hSbrEnvFrame->spreadFlag = 0; + + hSbrEnvFrame->allowSpread = allowSpread; + hSbrEnvFrame->numEnvStatic = numEnvStatic; + hSbrEnvFrame->staticFraming = staticFraming; + hSbrEnvFrame->freq_res_fixfix = freq_res_fixfix; + + hSbrEnvFrame->length_v_bord = 0; + hSbrEnvFrame->length_v_bordFollow = 0; + + hSbrEnvFrame->length_v_freq = 0; + hSbrEnvFrame->length_v_freqFollow = 0; + + hSbrEnvFrame->i_tranFollow = 0; + hSbrEnvFrame->i_fillFollow = 0; + + hSbrEnvFrame->SbrGrid.numberTimeSlots = timeSlots; + + if (ldGrid) { + /*case CODEC_AACLD:*/ + hSbrEnvFrame->dmin = 2; + hSbrEnvFrame->dmax = 16; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_512LD; + /* + hSbrEnvFrame->v_tuningSegm[0] = 0; + hSbrEnvFrame->v_tuningSegm[1] = 2; + hSbrEnvFrame->v_tuningSegm[2] = 3; + */ + /*break;*/ + } else + switch(timeSlots){ + case NUMBER_TIME_SLOTS_1920: + hSbrEnvFrame->dmin = 4; + hSbrEnvFrame->dmax = 12; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_1920; + break; + case NUMBER_TIME_SLOTS_2048: + hSbrEnvFrame->dmin = 4; + hSbrEnvFrame->dmax = 12; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_2048; + break; + case NUMBER_TIME_SLOTS_1152: + hSbrEnvFrame->dmin = 2; + hSbrEnvFrame->dmax = 8; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_1152; + break; + case NUMBER_TIME_SLOTS_2304: + hSbrEnvFrame->dmin = 4; + hSbrEnvFrame->dmax = 15; + hSbrEnvFrame->SbrGrid.bufferFrameStart = 0; + hSbrEnvFrame->frameMiddleSlot = FRAME_MIDDLE_SLOT_2304; + break; + default: + FDK_ASSERT(0); + } + +} + + +/******************************************************************************* + Functionname: deleteFrameInfoGenerator + ******************************************************************************* + + Description: + + Arguments: hSbrEnvFrame - HANDLE_SBR_ENVELOPE_FRAME + + Return: none + +*******************************************************************************/ + + +/******************************************************************************* + Functionname: fillFrameTran + ******************************************************************************* + + Description: Add mandatory borders, as described by the tuning vector + and the current transient position + + Arguments: + modified: + v_bord - int pointer to v_bord vector + length_v_bord - length of v_bord vector + v_freq - int pointer to v_freq vector + length_v_freq - length of v_freq vector + bmin - int pointer to bmin (call by reference) + bmax - int pointer to bmax (call by reference) + not modified: + tran - position of transient + v_tuningSegm - int pointer to v_tuningSegm vector + v_tuningFreq - int pointer to v_tuningFreq vector + + Return: none + +*******************************************************************************/ +static void +fillFrameTran (const int *v_tuningSegm, /*!< tuning: desired segment lengths */ + const int *v_tuningFreq, /*!< tuning: desired frequency resolutions */ + int tran, /*!< input : position of transient */ + int *v_bord, /*!< memNew: borders */ + int *length_v_bord, /*!< memNew: # borders */ + int *v_freq, /*!< memNew: frequency resolutions */ + int *length_v_freq, /*!< memNew: # frequency resolutions */ + int *bmin, /*!< hlpNew: first mandatory border */ + int *bmax /*!< hlpNew: last mandatory border */ + ) +{ + int bord, i; + + *length_v_bord = 0; + *length_v_freq = 0; + + /* add attack env leading border (optional) */ + if (v_tuningSegm[0]) { + /* v_bord = [(Ba)] start of attack env */ + FDKsbrEnc_AddRight (v_bord, length_v_bord, (tran - v_tuningSegm[0])); + + /* v_freq = [(Fa)] res of attack env */ + FDKsbrEnc_AddRight (v_freq, length_v_freq, v_tuningFreq[0]); + } + + /* add attack env trailing border/first decay env leading border */ + bord = tran; + FDKsbrEnc_AddRight (v_bord, length_v_bord, tran); /* v_bord = [(Ba),Bd1] */ + + /* add first decay env trailing border/2:nd decay env leading border */ + if (v_tuningSegm[1]) { + bord += v_tuningSegm[1]; + + /* v_bord = [(Ba),Bd1,Bd2] */ + FDKsbrEnc_AddRight (v_bord, length_v_bord, bord); + + /* v_freq = [(Fa),Fd1] */ + FDKsbrEnc_AddRight (v_freq, length_v_freq, v_tuningFreq[1]); + } + + /* add 2:nd decay env trailing border (optional) */ + if (v_tuningSegm[2] != 0) { + bord += v_tuningSegm[2]; + + /* v_bord = [(Ba),Bd1, Bd2,(Bd3)] */ + FDKsbrEnc_AddRight (v_bord, length_v_bord, bord); + + /* v_freq = [(Fa),Fd1,(Fd2)] */ + FDKsbrEnc_AddRight (v_freq, length_v_freq, v_tuningFreq[2]); + } + + /* v_freq = [(Fa),Fd1,(Fd2),1] */ + FDKsbrEnc_AddRight (v_freq, length_v_freq, 1); + + + /* calc min and max values of mandatory borders */ + *bmin = v_bord[0]; + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] < *bmin) + *bmin = v_bord[i]; + + *bmax = v_bord[0]; + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] > *bmax) + *bmax = v_bord[i]; + +} + + + +/******************************************************************************* + Functionname: fillFramePre + ******************************************************************************* + + Description: Add borders before mandatory borders, if needed + + Arguments: + modified: + v_bord - int pointer to v_bord vector + length_v_bord - length of v_bord vector + v_freq - int pointer to v_freq vector + length_v_freq - length of v_freq vector + not modified: + dmax - int value + bmin - int value + rest - int value + + Return: none + +*******************************************************************************/ +static void +fillFramePre (INT dmax, + INT *v_bord, INT *length_v_bord, + INT *v_freq, INT *length_v_freq, + INT bmin, INT rest) +{ + /* + input state: + v_bord = [(Ba),Bd1, Bd2 ,(Bd3)] + v_freq = [(Fa),Fd1,(Fd2),1 ] + */ + + INT parts, d, j, S, s = 0, segm, bord; + + /* + start with one envelope + */ + + parts = 1; + d = rest; + + /* + calc # of additional envelopes and corresponding lengths + */ + + while (d > dmax) { + parts++; + + segm = rest / parts; + S = (segm - 2)>>1; + s = fixMin (8, 2 * S + 2); + d = rest - (parts - 1) * s; + } + + /* + add borders before mandatory borders + */ + + bord = bmin; + + for (j = 0; j <= parts - 2; j++) { + bord = bord - s; + + /* v_bord = [...,(Bf),(Ba),Bd1, Bd2 ,(Bd3)] */ + FDKsbrEnc_AddLeft (v_bord, length_v_bord, bord); + + /* v_freq = [...,(1 ),(Fa),Fd1,(Fd2), 1 ] */ + FDKsbrEnc_AddLeft (v_freq, length_v_freq, 1); + } +} + +/***************************************************************************/ +/*! + \brief Overlap control + + Calculate max length of trailing fill segments, such that we always get a + border within the frame overlap region + + \return void + +****************************************************************************/ +static int +calcFillLengthMax (int tranPos, /*!< input : transient position (ref: tran det) */ + int numberTimeSlots /*!< input : number of timeslots */ + ) +{ + int fmax; + + /* + calculate transient position within envelope buffer + */ + switch (numberTimeSlots) + { + case NUMBER_TIME_SLOTS_2048: + if (tranPos < 4) + fmax = 6; + else if (tranPos == 4 || tranPos == 5) + fmax = 4; + else + fmax = 8; + break; + + case NUMBER_TIME_SLOTS_1920: + if (tranPos < 4) + fmax = 5; + else if (tranPos == 4 || tranPos == 5) + fmax = 3; + else + fmax = 7; + break; + + default: + fmax = 8; + break; + } + + return fmax; +} + +/******************************************************************************* + Functionname: fillFramePost + ******************************************************************************* + + Description: -Add borders after mandatory borders, if needed + Make a preliminary design of next frame, + assuming no transient is present there + + Arguments: + modified: + parts - int pointer to parts (call by reference) + d - int pointer to d (call by reference) + v_bord - int pointer to v_bord vector + length_v_bord - length of v_bord vector + v_freq - int pointer to v_freq vector + length_v_freq - length of v_freq vector + not modified: + bmax - int value + dmax - int value + + Return: none + +*******************************************************************************/ +static void +fillFramePost (INT *parts, INT *d, INT dmax, INT *v_bord, INT *length_v_bord, + INT *v_freq, INT *length_v_freq, INT bmax, + INT bufferFrameStart, INT numberTimeSlots, INT fmax) +{ + INT j, rest, segm, S, s = 0, bord; + + /* + input state: + v_bord = [...,(Bf),(Ba),Bd1, Bd2 ,(Bd3)] + v_freq = [...,(1 ),(Fa),Fd1,(Fd2),1 ] + */ + + rest = bufferFrameStart + 2 * numberTimeSlots - bmax; + *d = rest; + + if (*d > 0) { + *parts = 1; /* start with one envelope */ + + /* calc # of additional envelopes and corresponding lengths */ + + while (*d > dmax) { + *parts = *parts + 1; + + segm = rest / (*parts); + S = (segm - 2)>>1; + s = fixMin (fmax, 2 * S + 2); + *d = rest - (*parts - 1) * s; + } + + /* add borders after mandatory borders */ + + bord = bmax; + for (j = 0; j <= *parts - 2; j++) { + bord += s; + + /* v_bord = [...,(Bf),(Ba),Bd1, Bd2 ,(Bd3),(Bf)] */ + FDKsbrEnc_AddRight (v_bord, length_v_bord, bord); + + /* v_freq = [...,(1 ),(Fa),Fd1,(Fd2), 1 , 1! ,1] */ + FDKsbrEnc_AddRight (v_freq, length_v_freq, 1); + } + } + else { + *parts = 1; + + /* remove last element from v_bord and v_freq */ + + *length_v_bord = *length_v_bord - 1; + *length_v_freq = *length_v_freq - 1; + + } +} + + + +/******************************************************************************* + Functionname: fillFrameInter + ******************************************************************************* + + Description: + + Arguments: nL - + v_tuningSegm - + v_bord - + length_v_bord - + bmin - + v_freq - + length_v_freq - + v_bordFollow - + length_v_bordFollow - + v_freqFollow - + length_v_freqFollow - + i_fillFollow - + dmin - + dmax - + + Return: none + +*******************************************************************************/ +static void +fillFrameInter (INT *nL, const int *v_tuningSegm, INT *v_bord, INT *length_v_bord, + INT bmin, INT *v_freq, INT *length_v_freq, INT *v_bordFollow, + INT *length_v_bordFollow, INT *v_freqFollow, + INT *length_v_freqFollow, INT i_fillFollow, INT dmin, + INT dmax, INT numberTimeSlots) +{ + INT middle, b_new, numBordFollow, bordMaxFollow, i; + + if (numberTimeSlots != NUMBER_TIME_SLOTS_1152) { + + /* % remove fill borders: */ + if (i_fillFollow >= 1) { + *length_v_bordFollow = i_fillFollow; + *length_v_freqFollow = i_fillFollow; + } + + numBordFollow = *length_v_bordFollow; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + + /* remove even more borders if needed */ + middle = bmin - bordMaxFollow; + while (middle < 0) { + numBordFollow--; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + middle = bmin - bordMaxFollow; + } + + *length_v_bordFollow = numBordFollow; + *length_v_freqFollow = numBordFollow; + *nL = numBordFollow - 1; + + b_new = *length_v_bord; + + + if (middle <= dmax) { + if (middle >= dmin) { /* concatenate */ + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, *length_v_freqFollow); + } + + else { + if (v_tuningSegm[0] != 0) { /* remove one new border and concatenate */ + *length_v_bord = b_new - 1; + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + + *length_v_freq = b_new - 1; + FDKsbrEnc_AddVecLeft (v_freq + 1, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } + else { + if (*length_v_bordFollow > 1) { /* remove one old border and concatenate */ + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow - 1); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, + *length_v_bordFollow - 1); + + *nL = *nL - 1; + } + else { /* remove new "transient" border and concatenate */ + + for (i = 0; i < *length_v_bord - 1; i++) + v_bord[i] = v_bord[i + 1]; + + for (i = 0; i < *length_v_freq - 1; i++) + v_freq[i] = v_freq[i + 1]; + + *length_v_bord = b_new - 1; + *length_v_freq = b_new - 1; + + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } + } + } + } + else { /* middle > dmax */ + + fillFramePre (dmax, v_bord, length_v_bord, v_freq, length_v_freq, bmin, + middle); + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, *length_v_freqFollow); + } + + + } + else { /* numberTimeSlots==NUMBER_TIME_SLOTS_1152 */ + + INT l,m; + + + /*------------------------------------------------------------------------ + remove fill borders + ------------------------------------------------------------------------*/ + if (i_fillFollow >= 1) { + *length_v_bordFollow = i_fillFollow; + *length_v_freqFollow = i_fillFollow; + } + + numBordFollow = *length_v_bordFollow; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + + /*------------------------------------------------------------------------ + remove more borders if necessary to eliminate overlap + ------------------------------------------------------------------------*/ + + /* check for overlap */ + middle = bmin - bordMaxFollow; + + /* intervals: + i) middle < 0 : overlap, must remove borders + ii) 0 <= middle < dmin : no overlap but too tight, must remove borders + iii) dmin <= middle <= dmax : ok, just concatenate + iv) dmax <= middle : too wide, must add borders + */ + + /* first remove old non-fill-borders... */ + while (middle < 0) { + + /* ...but don't remove all of them */ + if (numBordFollow == 1) + break; + + numBordFollow--; + bordMaxFollow = v_bordFollow[numBordFollow - 1]; + middle = bmin - bordMaxFollow; + } + + /* if this isn't enough, remove new non-fill borders */ + if (middle < 0) + { + for (l = 0, m = 0 ; l < *length_v_bord ; l++) + { + if(v_bord[l]> bordMaxFollow) + { + v_bord[m] = v_bord[l]; + v_freq[m] = v_freq[l]; + m++; + } + } + + *length_v_bord = l; + *length_v_freq = l; + + bmin = v_bord[0]; + + } + + /*------------------------------------------------------------------------ + update modified follow-up data + ------------------------------------------------------------------------*/ + + *length_v_bordFollow = numBordFollow; + *length_v_freqFollow = numBordFollow; + + /* left relative borders correspond to follow-up */ + *nL = numBordFollow - 1; + + /*------------------------------------------------------------------------ + take care of intervals ii through iv + ------------------------------------------------------------------------*/ + + /* now middle should be >= 0 */ + middle = bmin - bordMaxFollow; + + if (middle <= dmin) /* (ii) */ + { + b_new = *length_v_bord; + + if (v_tuningSegm[0] != 0) + { + /* remove new "luxury" border and concatenate */ + *length_v_bord = b_new - 1; + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + + *length_v_freq = b_new - 1; + FDKsbrEnc_AddVecLeft (v_freq + 1, length_v_freq, v_freqFollow, + *length_v_freqFollow); + + } + else if (*length_v_bordFollow > 1) + { + /* remove old border and concatenate */ + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow - 1); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, + *length_v_bordFollow - 1); + + *nL = *nL - 1; + } + else + { + /* remove new border and concatenate */ + for (i = 0; i < *length_v_bord - 1; i++) + v_bord[i] = v_bord[i + 1]; + + for (i = 0; i < *length_v_freq - 1; i++) + v_freq[i] = v_freq[i + 1]; + + *length_v_bord = b_new - 1; + *length_v_freq = b_new - 1; + + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, + *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, + *length_v_freqFollow); + } + } + else if ((middle >= dmin) && (middle <= dmax)) /* (iii) */ + { + /* concatenate */ + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, *length_v_freqFollow); + + } + else /* (iv) */ + { + fillFramePre (dmax, v_bord, length_v_bord, v_freq, length_v_freq, bmin, + middle); + FDKsbrEnc_AddVecLeft (v_bord, length_v_bord, v_bordFollow, *length_v_bordFollow); + FDKsbrEnc_AddVecLeft (v_freq, length_v_freq, v_freqFollow, *length_v_freqFollow); + } + } +} + + + +/******************************************************************************* + Functionname: calcFrameClass + ******************************************************************************* + + Description: + + Arguments: INT* frameClass, INT* frameClassOld, INT tranFlag, INT* spreadFlag) + + Return: none + +*******************************************************************************/ +static void +calcFrameClass (FRAME_CLASS *frameClass, FRAME_CLASS *frameClassOld, INT tranFlag, + INT *spreadFlag) +{ + + switch (*frameClassOld) { + case FIXFIXonly: + case FIXFIX: + if (tranFlag) *frameClass = FIXVAR; + else *frameClass = FIXFIX; + break; + case FIXVAR: + if (tranFlag) { *frameClass = VARVAR; *spreadFlag = 0; } + else { + if (*spreadFlag) *frameClass = VARVAR; + else *frameClass = VARFIX; + } + break; + case VARFIX: + if (tranFlag) *frameClass = FIXVAR; + else *frameClass = FIXFIX; + break; + case VARVAR: + if (tranFlag) { *frameClass = VARVAR; *spreadFlag = 0; } + else { + if (*spreadFlag) *frameClass = VARVAR; + else *frameClass = VARFIX; + } + break; + }; + + *frameClassOld = *frameClass; +} + + + +/******************************************************************************* + Functionname: specialCase + ******************************************************************************* + + Description: + + Arguments: spreadFlag + allowSpread + v_bord + length_v_bord + v_freq + length_v_freq + parts + d + + Return: none + +*******************************************************************************/ +static void +specialCase (INT *spreadFlag, INT allowSpread, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT *length_v_freq, INT *parts, + INT d) +{ + INT L; + + L = *length_v_bord; + + if (allowSpread) { /* add one "step 8" */ + *spreadFlag = 1; + FDKsbrEnc_AddRight (v_bord, length_v_bord, v_bord[L - 1] + 8); + FDKsbrEnc_AddRight (v_freq, length_v_freq, 1); + (*parts)++; + } + else { + if (d == 1) { /* stretch one slot */ + *length_v_bord = L - 1; + *length_v_freq = L - 1; + } + else { + if ((v_bord[L - 1] - v_bord[L - 2]) > 2) { /* compress one quant step */ + v_bord[L - 1] = v_bord[L - 1] - 2; + v_freq[*length_v_freq - 1] = 0; /* use low res for short segment */ + } + } + } +} + + + +/******************************************************************************* + Functionname: calcCmonBorder + ******************************************************************************* + + Description: + + Arguments: i_cmon + i_tran + v_bord + length_v_bord + tran + + Return: none + +*******************************************************************************/ +static void +calcCmonBorder (INT *i_cmon, INT *i_tran, INT *v_bord, INT *length_v_bord, + INT tran, INT bufferFrameStart, INT numberTimeSlots) +{ /* FH 00-06-26 */ + INT i; + + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] >= bufferFrameStart + numberTimeSlots) { /* FH 00-06-26 */ + *i_cmon = i; + break; + } + + /* keep track of transient: */ + for (i = 0; i < *length_v_bord; i++) + if (v_bord[i] >= tran) { + *i_tran = i; + break; + } + else + *i_tran = EMPTY; +} + +/******************************************************************************* + Functionname: keepForFollowUp + ******************************************************************************* + + Description: + + Arguments: v_bordFollow + length_v_bordFollow + v_freqFollow + length_v_freqFollow + i_tranFollow + i_fillFollow + v_bord + length_v_bord + v_freq + i_cmon + i_tran + parts) + + Return: none + +*******************************************************************************/ +static void +keepForFollowUp (INT *v_bordFollow, INT *length_v_bordFollow, + INT *v_freqFollow, INT *length_v_freqFollow, + INT *i_tranFollow, INT *i_fillFollow, INT *v_bord, + INT *length_v_bord, INT *v_freq, INT i_cmon, INT i_tran, + INT parts, INT numberTimeSlots) +{ /* FH 00-06-26 */ + INT L, i, j; + + L = *length_v_bord; + + (*length_v_bordFollow) = 0; + (*length_v_freqFollow) = 0; + + for (j = 0, i = i_cmon; i < L; i++, j++) { + v_bordFollow[j] = v_bord[i] - numberTimeSlots; /* FH 00-06-26 */ + v_freqFollow[j] = v_freq[i]; + (*length_v_bordFollow)++; + (*length_v_freqFollow)++; + } + if (i_tran != EMPTY) + *i_tranFollow = i_tran - i_cmon; + else + *i_tranFollow = EMPTY; + *i_fillFollow = L - (parts - 1) - i_cmon; + +} + +/******************************************************************************* + Functionname: calcCtrlSignal + ******************************************************************************* + + Description: + + Arguments: hSbrGrid + frameClass + v_bord + length_v_bord + v_freq + length_v_freq + i_cmon + i_tran + spreadFlag + nL + + Return: none + +*******************************************************************************/ +static void +calcCtrlSignal (HANDLE_SBR_GRID hSbrGrid, + FRAME_CLASS frameClass, INT *v_bord, INT length_v_bord, INT *v_freq, + INT length_v_freq, INT i_cmon, INT i_tran, INT spreadFlag, + INT nL) +{ + + + INT i, r, a, n, p, b, aL, aR, ntot, nmax, nR; + + INT *v_f = hSbrGrid->v_f; + INT *v_fLR = hSbrGrid->v_fLR; + INT *v_r = hSbrGrid->bs_rel_bord; + INT *v_rL = hSbrGrid->bs_rel_bord_0; + INT *v_rR = hSbrGrid->bs_rel_bord_1; + + INT length_v_r = 0; + INT length_v_rR = 0; + INT length_v_rL = 0; + + switch (frameClass) { + case FIXVAR: + /* absolute border: */ + + a = v_bord[i_cmon]; + + /* relative borders: */ + length_v_r = 0; + i = i_cmon; + + while (i >= 1) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_r, &length_v_r, r); + i--; + } + + + /* number of relative borders: */ + n = length_v_r; + + + /* freq res: */ + for (i = 0; i < i_cmon; i++) + v_f[i] = v_freq[i_cmon - 1 - i]; + v_f[i_cmon] = 1; + + /* pointer: */ + p = (i_cmon >= i_tran && i_tran != EMPTY) ? (i_cmon - i_tran + 1) : (0) ; + + hSbrGrid->frameClass = frameClass; + hSbrGrid->bs_abs_bord = a; + hSbrGrid->n = n; + hSbrGrid->p = p; + + break; + case VARFIX: + /* absolute border: */ + a = v_bord[0]; + + /* relative borders: */ + length_v_r = 0; + + for (i = 1; i < length_v_bord; i++) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_r, &length_v_r, r); + } + + /* number of relative borders: */ + n = length_v_r; + + /* freq res: */ + FDKmemcpy (v_f, v_freq, length_v_freq * sizeof (INT)); + + + /* pointer: */ + p = (i_tran >= 0 && i_tran != EMPTY) ? (i_tran + 1) : (0) ; + + hSbrGrid->frameClass = frameClass; + hSbrGrid->bs_abs_bord = a; + hSbrGrid->n = n; + hSbrGrid->p = p; + + break; + case VARVAR: + if (spreadFlag) { + /* absolute borders: */ + b = length_v_bord; + + aL = v_bord[0]; + aR = v_bord[b - 1]; + + + /* number of relative borders: */ + ntot = b - 2; + + nmax = 2; /* n: {0,1,2} */ + if (ntot > nmax) { + nL = nmax; + nR = ntot - nmax; + } + else { + nL = ntot; + nR = 0; + } + + /* relative borders: */ + length_v_rL = 0; + for (i = 1; i <= nL; i++) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_rL, &length_v_rL, r); + } + + length_v_rR = 0; + i = b - 1; + while (i >= b - nR) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_rR, &length_v_rR, r); + i--; + } + + /* pointer (only one due to constraint in frame info): */ + p = (i_tran > 0 && i_tran != EMPTY) ? (b - i_tran) : (0) ; + + /* freq res: */ + + for (i = 0; i < b - 1; i++) + v_fLR[i] = v_freq[i]; + } + else { + + length_v_bord = i_cmon + 1; + length_v_freq = i_cmon + 1; + + + /* absolute borders: */ + b = length_v_bord; + + aL = v_bord[0]; + aR = v_bord[b - 1]; + + /* number of relative borders: */ + ntot = b - 2; + nR = ntot - nL; + + /* relative borders: */ + length_v_rL = 0; + for (i = 1; i <= nL; i++) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_rL, &length_v_rL, r); + } + + length_v_rR = 0; + i = b - 1; + while (i >= b - nR) { + r = v_bord[i] - v_bord[i - 1]; + FDKsbrEnc_AddRight (v_rR, &length_v_rR, r); + i--; + } + + /* pointer (only one due to constraint in frame info): */ + p = (i_cmon >= i_tran && i_tran != EMPTY) ? (i_cmon - i_tran + 1) : (0) ; + + /* freq res: */ + for (i = 0; i < b - 1; i++) + v_fLR[i] = v_freq[i]; + } + + hSbrGrid->frameClass = frameClass; + hSbrGrid->bs_abs_bord_0 = aL; + hSbrGrid->bs_abs_bord_1 = aR; + hSbrGrid->bs_num_rel_0 = nL; + hSbrGrid->bs_num_rel_1 = nR; + hSbrGrid->p = p; + + break; + + default: + /* do nothing */ + break; + } +} + +/******************************************************************************* + Functionname: createDefFrameInfo + ******************************************************************************* + + Description: Copies the default (static) frameInfo structs to the frameInfo + passed by reference; only used for FIXFIX frames + + Arguments: hFrameInfo - HANLDE_SBR_FRAME_INFO + nEnv - INT + nTimeSlots - INT + + Return: none; hSbrFrameInfo contains a copy of the default frameInfo + + Written: 2002/02/05 Andreas Schneider, CT + Revised: +*******************************************************************************/ +static void +createDefFrameInfo(HANDLE_SBR_FRAME_INFO hSbrFrameInfo, INT nEnv, INT nTimeSlots) +{ + switch (nEnv) { + case 1: + switch (nTimeSlots) { + case NUMBER_TIME_SLOTS_1920: + FDKmemcpy (hSbrFrameInfo, &frameInfo1_1920, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2048: + FDKmemcpy (hSbrFrameInfo, &frameInfo1_2048, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_1152: + FDKmemcpy (hSbrFrameInfo, &frameInfo1_1152, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2304: + FDKmemcpy (hSbrFrameInfo, &frameInfo1_2304, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_512LD: + FDKmemcpy (hSbrFrameInfo, &frameInfo1_512LD, sizeof (SBR_FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 2: + switch (nTimeSlots) { + case NUMBER_TIME_SLOTS_1920: + FDKmemcpy (hSbrFrameInfo, &frameInfo2_1920, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2048: + FDKmemcpy (hSbrFrameInfo, &frameInfo2_2048, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_1152: + FDKmemcpy (hSbrFrameInfo, &frameInfo2_1152, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2304: + FDKmemcpy (hSbrFrameInfo, &frameInfo2_2304, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_512LD: + FDKmemcpy (hSbrFrameInfo, &frameInfo2_512LD, sizeof (SBR_FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + case 4: + switch (nTimeSlots) { + case NUMBER_TIME_SLOTS_1920: + FDKmemcpy (hSbrFrameInfo, &frameInfo4_1920, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2048: + FDKmemcpy (hSbrFrameInfo, &frameInfo4_2048, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_1152: + FDKmemcpy (hSbrFrameInfo, &frameInfo4_1152, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_2304: + FDKmemcpy (hSbrFrameInfo, &frameInfo4_2304, sizeof (SBR_FRAME_INFO)); + break; + case NUMBER_TIME_SLOTS_512LD: + FDKmemcpy (hSbrFrameInfo, &frameInfo4_512LD, sizeof (SBR_FRAME_INFO)); + break; + default: + FDK_ASSERT(0); + } + break; + default: + FDK_ASSERT(0); + } +} + + +/******************************************************************************* + Functionname: ctrlSignal2FrameInfo + ******************************************************************************* + + Description: Calculates frame_info struct from control signal. + + Arguments: hSbrGrid - source + hSbrFrameInfo - destination + + Return: void; hSbrFrameInfo contains the updated FRAME_INFO struct + +*******************************************************************************/ +static void +ctrlSignal2FrameInfo (HANDLE_SBR_GRID hSbrGrid, + HANDLE_SBR_FRAME_INFO hSbrFrameInfo, + INT freq_res_fixfix) +{ + INT nEnv = 0, border = 0, i, k, p /*?*/; + INT *v_r = hSbrGrid->bs_rel_bord; + INT *v_f = hSbrGrid->v_f; + + FRAME_CLASS frameClass = hSbrGrid->frameClass; + INT bufferFrameStart = hSbrGrid->bufferFrameStart; + INT numberTimeSlots = hSbrGrid->numberTimeSlots; + + switch (frameClass) { + case FIXFIX: + createDefFrameInfo(hSbrFrameInfo, hSbrGrid->bs_num_env, numberTimeSlots); + + /* At this point all frequency resolutions are set to FREQ_RES_HIGH, so + * only if freq_res_fixfix is set to FREQ_RES_LOW, they all have to be + * changed. + * snd */ + if (freq_res_fixfix == FREQ_RES_LOW) { + for (i = 0; i < hSbrFrameInfo->nEnvelopes; i++) { + hSbrFrameInfo->freqRes[i] = FREQ_RES_LOW; + } + } + /* ELD: store current frequency resolution */ + hSbrGrid->v_f[0] = hSbrFrameInfo->freqRes[0]; + break; + + case FIXVAR: + case VARFIX: + nEnv = hSbrGrid->n + 1; /* read n [SBR_NUM_BITS bits] */ /*? snd*/ + FDK_ASSERT(nEnv <= MAX_ENVELOPES_FIXVAR_VARFIX); + + hSbrFrameInfo->nEnvelopes = nEnv; + + border = hSbrGrid->bs_abs_bord; /* read the absolute border */ + + if (nEnv == 1) + hSbrFrameInfo->nNoiseEnvelopes = 1; + else + hSbrFrameInfo->nNoiseEnvelopes = 2; + + break; + + default: + /* do nothing */ + break; + } + + switch (frameClass) { + case FIXVAR: + hSbrFrameInfo->borders[0] = bufferFrameStart; /* start-position of 1st envelope */ + + hSbrFrameInfo->borders[nEnv] = border; + + for (k = 0, i = nEnv - 1; k < nEnv - 1; k++, i--) { + border -= v_r[k]; + hSbrFrameInfo->borders[i] = border; + } + + /* make either envelope nr. nEnv + 1 - p short; or don't shorten if p == 0 */ + p = hSbrGrid->p; + if (p == 0) { + hSbrFrameInfo->shortEnv = 0; + } else { + hSbrFrameInfo->shortEnv = nEnv + 1 - p; + } + + for (k = 0, i = nEnv - 1; k < nEnv; k++, i--) { + hSbrFrameInfo->freqRes[i] = (FREQ_RES)v_f[k]; + } + + /* if either there is no short envelope or the last envelope is short... */ + if (p == 0 || p == 1) { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv - 1]; + } else { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[hSbrFrameInfo->shortEnv]; + } + + break; + + case VARFIX: + /* in this case 'border' indicates the start of the 1st envelope */ + hSbrFrameInfo->borders[0] = border; + + for (k = 0; k < nEnv - 1; k++) { + border += v_r[k]; + hSbrFrameInfo->borders[k + 1] = border; + } + + hSbrFrameInfo->borders[nEnv] = bufferFrameStart + numberTimeSlots; + + p = hSbrGrid->p; + if (p == 0 || p == 1) { + hSbrFrameInfo->shortEnv = 0; + } else { + hSbrFrameInfo->shortEnv = p - 1; + } + + for (k = 0; k < nEnv; k++) { + hSbrFrameInfo->freqRes[k] = (FREQ_RES)v_f[k]; + } + + switch (p) { + case 0: + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[1]; + break; + case 1: + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv - 1]; + break; + default: + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[hSbrFrameInfo->shortEnv]; + break; + } + break; + + case VARVAR: + nEnv = hSbrGrid->bs_num_rel_0 + hSbrGrid->bs_num_rel_1 + 1; + FDK_ASSERT(nEnv <= MAX_ENVELOPES_VARVAR); /* just to be sure */ + hSbrFrameInfo->nEnvelopes = nEnv; + + hSbrFrameInfo->borders[0] = border = hSbrGrid->bs_abs_bord_0; + + for (k = 0, i = 1; k < hSbrGrid->bs_num_rel_0; k++, i++) { + border += hSbrGrid->bs_rel_bord_0[k]; + hSbrFrameInfo->borders[i] = border; + } + + border = hSbrGrid->bs_abs_bord_1; + hSbrFrameInfo->borders[nEnv] = border; + + for (k = 0, i = nEnv - 1; k < hSbrGrid->bs_num_rel_1; k++, i--) { + border -= hSbrGrid->bs_rel_bord_1[k]; + hSbrFrameInfo->borders[i] = border; + } + + p = hSbrGrid->p; + if (p == 0) { + hSbrFrameInfo->shortEnv = 0; + } else { + hSbrFrameInfo->shortEnv = nEnv + 1 - p; + } + + for (k = 0; k < nEnv; k++) { + hSbrFrameInfo->freqRes[k] = (FREQ_RES)hSbrGrid->v_fLR[k]; + } + + if (nEnv == 1) { + hSbrFrameInfo->nNoiseEnvelopes = 1; + hSbrFrameInfo->bordersNoise[0] = hSbrGrid->bs_abs_bord_0; + hSbrFrameInfo->bordersNoise[1] = hSbrGrid->bs_abs_bord_1; + } else { + hSbrFrameInfo->nNoiseEnvelopes = 2; + hSbrFrameInfo->bordersNoise[0] = hSbrGrid->bs_abs_bord_0; + + if (p == 0 || p == 1) { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv - 1]; + } else { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[hSbrFrameInfo->shortEnv]; + } + hSbrFrameInfo->bordersNoise[2] = hSbrGrid->bs_abs_bord_1; + } + break; + + default: + /* do nothing */ + break; + } + + if (frameClass == VARFIX || frameClass == FIXVAR) { + hSbrFrameInfo->bordersNoise[0] = hSbrFrameInfo->borders[0]; + if (nEnv == 1) { + hSbrFrameInfo->bordersNoise[1] = hSbrFrameInfo->borders[nEnv]; + } else { + hSbrFrameInfo->bordersNoise[2] = hSbrFrameInfo->borders[nEnv]; + } + } +} + diff --git a/libSBRenc/src/fram_gen.h b/libSBRenc/src/fram_gen.h new file mode 100644 index 0000000..3301e77 --- /dev/null +++ b/libSBRenc/src/fram_gen.h @@ -0,0 +1,249 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Framing generator prototypes and structs $Revision: 36847 $ +*/ +#ifndef _FRAM_GEN_H +#define _FRAM_GEN_H + +#include "sbr_def.h" /* for MAX_ENVELOPES and MAX_NOISE_ENVELOPES in struct FRAME_INFO and CODEC_TYPE */ + +#define MAX_ENVELOPES_VARVAR MAX_ENVELOPES /*!< worst case number of envelopes in a VARVAR frame */ +#define MAX_ENVELOPES_FIXVAR_VARFIX 4 /*!< worst case number of envelopes in VARFIX and FIXVAR frames */ +#define MAX_NUM_REL 3 /*!< maximum number of relative borders in any VAR frame */ + +/* SBR frame class definitions */ +typedef enum { + FIXFIX = 0, /*!< bs_frame_class: leading and trailing frame borders are fixed */ + FIXVAR, /*!< bs_frame_class: leading frame border is fixed, trailing frame border is variable */ + VARFIX, /*!< bs_frame_class: leading frame border is variable, trailing frame border is fixed */ + VARVAR /*!< bs_frame_class: leading and trailing frame borders are variable */ + ,FIXFIXonly /*!< bs_frame_class: leading border fixed (0), trailing border fixed (nrTimeSlots) and encased borders are dynamically derived from the tranPos */ +}FRAME_CLASS; + + +/* helper constants */ +#define DC 4711 /*!< helper constant: don't care */ +#define EMPTY (-99) /*!< helper constant: empty */ + + +/* system constants: AAC+SBR, DRM Frame-Length */ +#define FRAME_MIDDLE_SLOT_1920 4 +#define NUMBER_TIME_SLOTS_1920 15 + +#define LD_PRETRAN_OFF 3 +#define FRAME_MIDDLE_SLOT_512LD 0 +#define NUMBER_TIME_SLOTS_512LD 8 +#define TRANSIENT_OFFSET_LD 0 + + + +/* +system constants: AAC+SBR or aacPRO (hybrid format), Standard Frame-Length, Multi-Rate +--------------------------------------------------------------------------- +Number of slots (numberTimeSlots): 16 (NUMBER_TIME_SLOTS_2048) +Detector-offset (frameMiddleSlot): 4 +Overlap : 3 +Buffer-offset : 8 (BUFFER_FRAME_START_2048 = 0) + + + |<------------tranPos---------->| + |c|d|e|f|0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f| + FixFix | | + FixVar | :<- ->: + VarFix :<- ->: | + VarVar :<- ->: :<- ->: + 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 +................................................................................ + +|-|-|-|-|-|-|-|-B-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-B-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-| + +frame-generator:0 16 24 32 +analysis-buffer:8 24 32 40 +*/ +#define FRAME_MIDDLE_SLOT_2048 4 +#define NUMBER_TIME_SLOTS_2048 16 + + +/* +system constants: mp3PRO, Multi-Rate & Single-Rate +-------------------------------------------------- +Number of slots (numberTimeSlots): 9 (NUMBER_TIME_SLOTS_1152) +Detector-offset (frameMiddleSlot): 4 (FRAME_MIDDLE_SLOT_1152) +Overlap : 3 +Buffer-offset : 4.5 (BUFFER_FRAME_START_1152 = 0) + + + |<----tranPos---->| + |5|6|7|8|0|1|2|3|4|5|6|7|8| + FixFix | | + FixVar | :<- ->: + VarFix :<- ->: | + VarVar :<- ->: :<- ->: + 0 1 2 3 4 5 6 7 8 0 1 2 3 + ............................................. + + -|-|-|-|-B-|-|-|-|-|-|-|-|-B-|-|-|-|-|-|-|-|-| + +frame-generator: 0 9 13 18 +analysis-buffer: 4.5 13.5 22.5 +*/ +#define FRAME_MIDDLE_SLOT_1152 4 +#define NUMBER_TIME_SLOTS_1152 9 + + +/* system constants: Layer2+SBR */ +#define FRAME_MIDDLE_SLOT_2304 8 +#define NUMBER_TIME_SLOTS_2304 18 + + +/*! + \struct SBR_GRID + \brief sbr_grid() signals to be converted to bitstream elements + + The variables hold the signals (e.g. lengths and numbers) in "clear text" +*/ + +typedef struct +{ + /* system constants */ + INT bufferFrameStart; /*!< frame generator vs analysis buffer time alignment (currently set to 0, offset added elsewhere) */ + INT numberTimeSlots; /*!< number of SBR timeslots per frame */ + + /* will be adjusted for every frame */ + FRAME_CLASS frameClass; /*!< SBR frame class */ + INT bs_num_env; /*!< bs_num_env, number of envelopes for FIXFIX */ + INT bs_abs_bord; /*!< bs_abs_bord, absolute border for VARFIX and FIXVAR */ + INT n; /*!< number of relative borders for VARFIX and FIXVAR */ + INT p; /*!< pointer-to-transient-border */ + INT bs_rel_bord[MAX_NUM_REL]; /*!< bs_rel_bord, relative borders for all VAR */ + INT v_f[MAX_ENVELOPES_FIXVAR_VARFIX]; /*!< envelope frequency resolutions for FIXVAR and VARFIX */ + + INT bs_abs_bord_0; /*!< bs_abs_bord_0, leading absolute border for VARVAR */ + INT bs_abs_bord_1; /*!< bs_abs_bord_1, trailing absolute border for VARVAR */ + INT bs_num_rel_0; /*!< bs_num_rel_0, number of relative borders associated with leading absolute border for VARVAR */ + INT bs_num_rel_1; /*!< bs_num_rel_1, number of relative borders associated with trailing absolute border for VARVAR */ + INT bs_rel_bord_0[MAX_NUM_REL]; /*!< bs_rel_bord_0, relative borders associated with leading absolute border for VARVAR */ + INT bs_rel_bord_1[MAX_NUM_REL]; /*!< bs_rel_bord_1, relative borders associated with trailing absolute border for VARVAR */ + INT v_fLR[MAX_ENVELOPES_VARVAR]; /*!< envelope frequency resolutions for VARVAR */ + +} +SBR_GRID; +typedef SBR_GRID *HANDLE_SBR_GRID; + + + +/*! + \struct SBR_FRAME_INFO + \brief time/frequency grid description for one frame +*/ +typedef struct +{ + INT nEnvelopes; /*!< number of envelopes */ + INT borders[MAX_ENVELOPES+1]; /*!< envelope borders in SBR timeslots */ + FREQ_RES freqRes[MAX_ENVELOPES]; /*!< frequency resolution of each envelope */ + INT shortEnv; /*!< number of an envelope to be shortened (starting at 1) or 0 for no shortened envelope */ + INT nNoiseEnvelopes; /*!< number of noise floors */ + INT bordersNoise[MAX_NOISE_ENVELOPES+1];/*!< noise floor borders in SBR timeslots */ +} +SBR_FRAME_INFO; +/* WARNING: When rearranging the elements of this struct keep in mind that the static + * initializations in the corresponding C-file have to be rearranged as well! + * snd 2002/01/23 + */ +typedef SBR_FRAME_INFO *HANDLE_SBR_FRAME_INFO; + + +/*! + \struct SBR_ENVELOPE_FRAME + \brief frame generator main struct + + Contains tuning parameters, time/frequency grid description, sbr_grid() bitstream elements, and generator internal signals +*/ +typedef struct +{ + /* system constants */ + INT frameMiddleSlot; /*!< transient detector offset in SBR timeslots */ + + /* basic tuning parameters */ + INT staticFraming; /*!< 1: run static framing in time, i.e. exclusive use of bs_frame_class = FIXFIX */ + INT numEnvStatic; /*!< number of envelopes per frame for static framing */ + INT freq_res_fixfix; /*!< envelope frequency resolution to use for bs_frame_class = FIXFIX */ + + /* expert tuning parameters */ + const int *v_tuningSegm; /*!< segment lengths to use around transient */ + const int *v_tuningFreq; /*!< frequency resolutions to use around transient */ + INT dmin; /*!< minimum length of dependent segments */ + INT dmax; /*!< maximum length of dependent segments */ + INT allowSpread; /*!< 1: allow isolated transient to influence grid of 3 consecutive frames */ + + /* internally used signals */ + FRAME_CLASS frameClassOld; /*!< frame class used for previous frame */ + INT spreadFlag; /*!< 1: use VARVAR instead of VARFIX to follow up old transient */ + + INT v_bord[2 * MAX_ENVELOPES_VARVAR + 1]; /*!< borders for current frame and preliminary borders for next frame (fixed borders excluded) */ + INT length_v_bord; /*!< helper variable: length of v_bord */ + INT v_freq[2 * MAX_ENVELOPES_VARVAR + 1]; /*!< frequency resolutions for current frame and preliminary resolutions for next frame */ + INT length_v_freq; /*!< helper variable: length of v_freq */ + + INT v_bordFollow[MAX_ENVELOPES_VARVAR]; /*!< preliminary borders for current frame (calculated during previous frame) */ + INT length_v_bordFollow; /*!< helper variable: length of v_bordFollow */ + INT i_tranFollow; /*!< points to transient border in v_bordFollow (may be negative, see keepForFollowUp()) */ + INT i_fillFollow; /*!< points to first fill border in v_bordFollow */ + INT v_freqFollow[MAX_ENVELOPES_VARVAR]; /*!< preliminary frequency resolutions for current frame (calculated during previous frame) */ + INT length_v_freqFollow; /*!< helper variable: length of v_freqFollow */ + + + /* externally needed signals */ + SBR_GRID SbrGrid; /*!< sbr_grid() signals to be converted to bitstream elements */ + SBR_FRAME_INFO SbrFrameInfo; /*!< time/frequency grid description for one frame */ +} +SBR_ENVELOPE_FRAME; +typedef SBR_ENVELOPE_FRAME *HANDLE_SBR_ENVELOPE_FRAME; + + + +void +FDKsbrEnc_initFrameInfoGenerator (HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + INT allowSpread, + INT numEnvStatic, + INT staticFraming, + INT timeSlots, + INT freq_res_fixfix + ,int ldGrid + ); + +/* void deleteFrameInfoGenerator (HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame); */ + +HANDLE_SBR_FRAME_INFO +FDKsbrEnc_frameInfoGenerator (HANDLE_SBR_ENVELOPE_FRAME hSbrEnvFrame, + UCHAR *v_transient_info, + UCHAR *v_transient_info_pre, + int ldGrid, + const int *v_tuning); + +#endif diff --git a/libSBRenc/src/invf_est.cpp b/libSBRenc/src/invf_est.cpp new file mode 100644 index 0000000..4f4670c --- /dev/null +++ b/libSBRenc/src/invf_est.cpp @@ -0,0 +1,472 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "invf_est.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +#define MAX_NUM_REGIONS 10 +#define SCALE_FAC_QUO 512.0f +#define SCALE_FAC_NRG 256.0f + +#ifndef min +#define min(a,b) ( a < b ? a:b) +#endif + +#ifndef max +#define max(a,b) ( a > b ? a:b) +#endif + +static const FIXP_DBL quantStepsSbr[4] = { 0x00400000, 0x02800000, 0x03800000, 0x04c00000 } ; /* table scaled with SCALE_FAC_QUO */ +static const FIXP_DBL quantStepsOrig[4] = { 0x00000000, 0x00c00000, 0x01c00000, 0x02800000 } ; /* table scaled with SCALE_FAC_QUO */ +static const FIXP_DBL nrgBorders[4] = { 0x0c800000, 0x0f000000, 0x11800000, 0x14000000 } ; /* table scaled with SCALE_FAC_NRG */ + +static const DETECTOR_PARAMETERS detectorParamsAAC = { + quantStepsSbr, + quantStepsOrig, + nrgBorders, + 4, /* Number of borders SBR. */ + 4, /* Number of borders orig. */ + 4, /* Number of borders Nrg. */ + { /* Region space. */ + {INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF, INVF_OFF}, /* | */ + {INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */ + },/*------------------------ regionOrig ---------------------------------*/ + { /* Region space transient. */ + {INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */ + },/*------------------------ regionOrig ---------------------------------*/ + {-4, -3, -2, -1, 0} /* Reduction factor of the inverse filtering for low energies.*/ +}; + +static const FIXP_DBL hysteresis = 0x00400000 ; /* Delta value for hysteresis. scaled with SCALE_FAC_QUO */ + +/* + * AAC+SBR PARAMETERS for Speech + *********************************/ +static const DETECTOR_PARAMETERS detectorParamsAACSpeech = { + quantStepsSbr, + quantStepsOrig, + nrgBorders, + 4, /* Number of borders SBR. */ + 4, /* Number of borders orig. */ + 4, /* Number of borders Nrg. */ + { /* Region space. */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */ + },/*------------------------ regionOrig ---------------------------------*/ + { /* Region space transient. */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_LOW_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* regionSbr */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF}, /* | */ + {INVF_HIGH_LEVEL, INVF_HIGH_LEVEL, INVF_MID_LEVEL, INVF_OFF, INVF_OFF} /* | */ + },/*------------------------ regionOrig ---------------------------------*/ + {-4, -3, -2, -1, 0} /* Reduction factor of the inverse filtering for low energies.*/ +}; + +/* + * Smoothing filters. + ************************/ +typedef const FIXP_DBL FIR_FILTER[5]; + +static const FIR_FILTER fir_0 = { 0x7fffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } ; +static const FIR_FILTER fir_1 = { 0x2aaaaa80, 0x555554ff, 0x00000000, 0x00000000, 0x00000000 } ; +static const FIR_FILTER fir_2 = { 0x10000000, 0x30000000, 0x40000000, 0x00000000, 0x00000000 } ; +static const FIR_FILTER fir_3 = { 0x077f80e8, 0x199999a0, 0x2bb3b240, 0x33333340, 0x00000000 } ; +static const FIR_FILTER fir_4 = { 0x04130598, 0x0ebdb000, 0x1becfa60, 0x2697a4c0, 0x2aaaaa80 } ; + + +static const FIR_FILTER *const fir_table[5] = { + &fir_0, + &fir_1, + &fir_2, + &fir_3, + &fir_4 +}; + +/**************************************************************************/ +/*! + \brief Calculates the values used for the detector. + + + \return none + +*/ +/**************************************************************************/ +static void +calculateDetectorValues(FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the tonality values of the original. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + FIXP_DBL *nrgVector, /*!< Energy vector. */ + DETECTOR_VALUES *detectorValues, /*!< pointer to DETECTOR_VALUES struct. */ + INT startChannel, /*!< Start channel. */ + INT stopChannel, /*!< Stop channel. */ + INT startIndex, /*!< Start index. */ + INT stopIndex, /*!< Stop index. */ + INT numberOfStrongest /*!< The number of sorted tonal components to be considered. */ + ) +{ + INT i,temp, j; + + const FIXP_DBL* filter = *fir_table[INVF_SMOOTHING_LENGTH]; + FIXP_DBL origQuotaMeanStrongest, sbrQuotaMeanStrongest; + FIXP_DBL origQuota, sbrQuota; + FIXP_DBL invIndex, invChannel, invTemp; + FIXP_DBL quotaVecOrig[64], quotaVecSbr[64]; + + FDKmemclear(quotaVecOrig,64*sizeof(FIXP_DBL)); + FDKmemclear(quotaVecSbr,64*sizeof(FIXP_DBL)); + + invIndex = GetInvInt(stopIndex-startIndex); + invChannel = GetInvInt(stopChannel-startChannel); + + /* + Calculate the mean value, over the current time segment, for the original, the HFR + and the difference, over all channels in the current frequency range. + NOTE: the averaging is done on the values quota/(1 - quota + RELAXATION). + */ + + /* The original, the sbr signal and the total energy */ + detectorValues->avgNrg = FL2FXCONST_DBL(0.0f); + for(j=startIndex; j<stopIndex; j++) { + for(i=startChannel; i<stopChannel; i++) { + quotaVecOrig[i] += fMult(quotaMatrixOrig[j][i], invIndex); + + if(indexVector[i] != -1) + quotaVecSbr[i] += fMult(quotaMatrixOrig[j][indexVector[i]], invIndex); + } + detectorValues->avgNrg += fMult(nrgVector[j], invIndex); + } + + /* + Calculate the mean value, over the current frequency range, for the original, the HFR + and the difference. Also calculate the same mean values for the three vectors, but only + includeing the x strongest copmponents. + */ + + origQuota = FL2FXCONST_DBL(0.0f); + sbrQuota = FL2FXCONST_DBL(0.0f); + for(i=startChannel; i<stopChannel; i++) { + origQuota += fMultDiv2(quotaVecOrig[i], invChannel); + sbrQuota += fMultDiv2(quotaVecSbr[i], invChannel); + } + + /* + Calculate the mean value for the x strongest components + */ + FDKsbrEnc_Shellsort_fract(quotaVecOrig+startChannel,stopChannel-startChannel); + FDKsbrEnc_Shellsort_fract(quotaVecSbr+startChannel,stopChannel-startChannel); + + origQuotaMeanStrongest = FL2FXCONST_DBL(0.0f); + sbrQuotaMeanStrongest = FL2FXCONST_DBL(0.0f); + + temp = min(stopChannel - startChannel, numberOfStrongest); + invTemp = GetInvInt(temp); + + for(i=0; i<temp; i++) { + origQuotaMeanStrongest += fMultDiv2(quotaVecOrig[i + stopChannel - temp], invTemp); + sbrQuotaMeanStrongest += fMultDiv2(quotaVecSbr[i + stopChannel - temp], invTemp); + } + + /* + The value for the strongest component + */ + detectorValues->origQuotaMax = quotaVecOrig[stopChannel - 1]; + detectorValues->sbrQuotaMax = quotaVecSbr[stopChannel - 1]; + + /* + Buffer values + */ + FDKmemmove(detectorValues->origQuotaMean, detectorValues->origQuotaMean + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL)); + FDKmemmove(detectorValues->sbrQuotaMean, detectorValues->sbrQuotaMean + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL)); + FDKmemmove(detectorValues->origQuotaMeanStrongest, detectorValues->origQuotaMeanStrongest + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL)); + FDKmemmove(detectorValues->sbrQuotaMeanStrongest, detectorValues->sbrQuotaMeanStrongest + 1, INVF_SMOOTHING_LENGTH*sizeof(FIXP_DBL)); + + detectorValues->origQuotaMean[INVF_SMOOTHING_LENGTH] = origQuota<<1; + detectorValues->sbrQuotaMean[INVF_SMOOTHING_LENGTH] = sbrQuota<<1; + detectorValues->origQuotaMeanStrongest[INVF_SMOOTHING_LENGTH] = origQuotaMeanStrongest<<1; + detectorValues->sbrQuotaMeanStrongest[INVF_SMOOTHING_LENGTH] = sbrQuotaMeanStrongest<<1; + + /* + Filter values + */ + detectorValues->origQuotaMeanFilt = FL2FXCONST_DBL(0.0f); + detectorValues->sbrQuotaMeanFilt = FL2FXCONST_DBL(0.0f); + detectorValues->origQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f); + detectorValues->sbrQuotaMeanStrongestFilt = FL2FXCONST_DBL(0.0f); + + for(i=0;i<INVF_SMOOTHING_LENGTH+1;i++) { + detectorValues->origQuotaMeanFilt += fMult(detectorValues->origQuotaMean[i], filter[i]); + detectorValues->sbrQuotaMeanFilt += fMult(detectorValues->sbrQuotaMean[i], filter[i]); + detectorValues->origQuotaMeanStrongestFilt += fMult(detectorValues->origQuotaMeanStrongest[i], filter[i]); + detectorValues->sbrQuotaMeanStrongestFilt += fMult(detectorValues->sbrQuotaMeanStrongest[i], filter[i]); + } +} + +/**************************************************************************/ +/*! + \brief Returns the region in which the input value belongs. + + + + \return region. + +*/ +/**************************************************************************/ +static INT +findRegion(FIXP_DBL currVal, /*!< The current value. */ + const FIXP_DBL *borders, /*!< The border of the regions. */ + const INT numBorders /*!< The number of borders. */ + ) +{ + INT i; + + if(currVal < borders[0]){ + return 0; + } + + for(i = 1; i < numBorders; i++){ + if( currVal >= borders[i-1] && currVal < borders[i]){ + return i; + } + } + + if(currVal >= borders[numBorders-1]){ + return numBorders; + } + + return 0; /* We never get here, it's just to avoid compiler warnings.*/ +} + +/**************************************************************************/ +/*! + \brief Makes a clever decision based on the quota vector. + + + \return decision on which invf mode to use + +*/ +/**************************************************************************/ +static INVF_MODE +decisionAlgorithm(const DETECTOR_PARAMETERS *detectorParams, /*!< Struct with the detector parameters. */ + DETECTOR_VALUES *detectorValues, /*!< Struct with the detector values. */ + INT transientFlag, /*!< Flag indicating if there is a transient present.*/ + INT* prevRegionSbr, /*!< The previous region in which the Sbr value was. */ + INT* prevRegionOrig /*!< The previous region in which the Orig value was. */ + ) +{ + INT invFiltLevel, regionSbr, regionOrig, regionNrg; + + /* + Current thresholds. + */ + const FIXP_DBL *quantStepsSbr = detectorParams->quantStepsSbr; + const FIXP_DBL *quantStepsOrig = detectorParams->quantStepsOrig; + const FIXP_DBL *nrgBorders = detectorParams->nrgBorders; + const INT numRegionsSbr = detectorParams->numRegionsSbr; + const INT numRegionsOrig = detectorParams->numRegionsOrig; + const INT numRegionsNrg = detectorParams->numRegionsNrg; + + FIXP_DBL quantStepsSbrTmp[MAX_NUM_REGIONS]; + FIXP_DBL quantStepsOrigTmp[MAX_NUM_REGIONS]; + + /* + Current detector values. + */ + FIXP_DBL origQuotaMeanFilt; + FIXP_DBL sbrQuotaMeanFilt; + FIXP_DBL nrg; + + /* 0.375 = 3.0 / 8.0; 0.31143075889 = log2(RELAXATION)/64.0; 0.625 = log(16)/64.0; 0.6875 = 44/64.0 */ + origQuotaMeanFilt = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(max(detectorValues->origQuotaMeanFilt,(FIXP_DBL)1)) + FL2FXCONST_DBL(0.31143075889f)))) << 0; /* scaled by 1/2^9 */ + sbrQuotaMeanFilt = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(max(detectorValues->sbrQuotaMeanFilt,(FIXP_DBL)1)) + FL2FXCONST_DBL(0.31143075889f)))) << 0; /* scaled by 1/2^9 */ + /* If energy is zero then we will get different results for different word lengths. */ + nrg = (fMultDiv2(FL2FXCONST_DBL(2.f*0.375f), (FIXP_DBL)(CalcLdData(detectorValues->avgNrg+(FIXP_DBL)1) + FL2FXCONST_DBL(0.0625f) + FL2FXCONST_DBL(0.6875f)))) << 0; /* scaled by 1/2^8; 2^44 -> qmf energy scale */ + + FDKmemcpy(quantStepsSbrTmp,quantStepsSbr,numRegionsSbr*sizeof(FIXP_DBL)); + FDKmemcpy(quantStepsOrigTmp,quantStepsOrig,numRegionsOrig*sizeof(FIXP_DBL)); + + if(*prevRegionSbr < numRegionsSbr) + quantStepsSbrTmp[*prevRegionSbr] = quantStepsSbr[*prevRegionSbr] + hysteresis; + if(*prevRegionSbr > 0) + quantStepsSbrTmp[*prevRegionSbr - 1] = quantStepsSbr[*prevRegionSbr - 1] - hysteresis; + + if(*prevRegionOrig < numRegionsOrig) + quantStepsOrigTmp[*prevRegionOrig] = quantStepsOrig[*prevRegionOrig] + hysteresis; + if(*prevRegionOrig > 0) + quantStepsOrigTmp[*prevRegionOrig - 1] = quantStepsOrig[*prevRegionOrig - 1] - hysteresis; + + regionSbr = findRegion(sbrQuotaMeanFilt, quantStepsSbrTmp, numRegionsSbr); + regionOrig = findRegion(origQuotaMeanFilt, quantStepsOrigTmp, numRegionsOrig); + regionNrg = findRegion(nrg,nrgBorders,numRegionsNrg); + + *prevRegionSbr = regionSbr; + *prevRegionOrig = regionOrig; + + /* Use different settings if a transient is present*/ + invFiltLevel = (transientFlag == 1) ? detectorParams->regionSpaceTransient[regionSbr][regionOrig] + : detectorParams->regionSpace[regionSbr][regionOrig]; + + /* Compensate for low energy.*/ + invFiltLevel = max(invFiltLevel + detectorParams->EnergyCompFactor[regionNrg],0); + + return (INVF_MODE) (invFiltLevel); +} + +/**************************************************************************/ +/*! + \brief Estiamtion of the inverse filtering level required + in the decoder. + + A second order LPC is calculated for every filterbank channel, using + the covariance method. THe ratio between the energy of the predicted + signal and the energy of the non-predictable signal is calcualted. + + \return none. + +*/ +/**************************************************************************/ +void +FDKsbrEnc_qmfInverseFilteringDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, /*!< Handle to the SBR_INV_FILT_EST struct. */ + FIXP_DBL **quotaMatrix, /*!< The matrix holding the tonality values of the original. */ + FIXP_DBL *nrgVector, /*!< The energy vector. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + INT startIndex, /*!< Start index. */ + INT stopIndex, /*!< Stop index. */ + INT transientFlag, /*!< Flag indicating if a transient is present or not.*/ + INVF_MODE* infVec /*!< Vector holding the inverse filtering levels. */ + ) +{ + INT band; + + /* + * Do the inverse filtering level estimation. + *****************************************************/ + for(band = 0 ; band < hInvFilt->noDetectorBands; band++){ + INT startChannel = hInvFilt->freqBandTableInvFilt[band]; + INT stopChannel = hInvFilt->freqBandTableInvFilt[band+1]; + + + calculateDetectorValues( quotaMatrix, + indexVector, + nrgVector, + &hInvFilt->detectorValues[band], + startChannel, + stopChannel, + startIndex, + stopIndex, + hInvFilt->numberOfStrongest); + + infVec[band]= decisionAlgorithm( hInvFilt->detectorParams, + &hInvFilt->detectorValues[band], + transientFlag, + &hInvFilt->prevRegionSbr[band], + &hInvFilt->prevRegionOrig[band]); + } + +} + + +/**************************************************************************/ +/*! + \brief Initialize an instance of the inverse filtering level estimator. + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_initInvFiltDetector (HANDLE_SBR_INV_FILT_EST hInvFilt, /*!< Pointer to a handle to the SBR_INV_FILT_EST struct. */ + INT* freqBandTableDetector, /*!< Frequency band table for the inverse filtering. */ + INT numDetectorBands, /*!< Number of inverse filtering bands. */ + UINT useSpeechConfig /*!< Flag: adapt tuning parameters according to speech*/ + ) +{ + INT i; + + FDKmemclear( hInvFilt,sizeof(SBR_INV_FILT_EST)); + + hInvFilt->detectorParams = (useSpeechConfig) ? &detectorParamsAACSpeech + : &detectorParamsAAC ; + + hInvFilt->noDetectorBandsMax = numDetectorBands; + + /* + Memory initialisation + */ + for(i=0;i<hInvFilt->noDetectorBandsMax;i++){ + FDKmemclear(&hInvFilt->detectorValues[i], sizeof(DETECTOR_VALUES)); + hInvFilt->prevInvfMode[i] = INVF_OFF; + hInvFilt->prevRegionOrig[i] = 0; + hInvFilt->prevRegionSbr[i] = 0; + } + + /* + Reset the inverse fltering detector. + */ + FDKsbrEnc_resetInvFiltDetector(hInvFilt, + freqBandTableDetector, + hInvFilt->noDetectorBandsMax); + + return (0); +} + + +/**************************************************************************/ +/*! + \brief resets sbr inverse filtering structure. + + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_resetInvFiltDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, /*!< Handle to the SBR_INV_FILT_EST struct. */ + INT* freqBandTableDetector, /*!< Frequency band table for the inverse filtering. */ + INT numDetectorBands) /*!< Number of inverse filtering bands. */ +{ + + hInvFilt->numberOfStrongest = 1; + FDKmemcpy(hInvFilt->freqBandTableInvFilt,freqBandTableDetector,(numDetectorBands+1)*sizeof(INT)); + hInvFilt->noDetectorBands = numDetectorBands; + + return (0); +} + + diff --git a/libSBRenc/src/invf_est.h b/libSBRenc/src/invf_est.h new file mode 100644 index 0000000..da020f5 --- /dev/null +++ b/libSBRenc/src/invf_est.h @@ -0,0 +1,119 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Inverse Filtering detection prototypes $Revision: 36847 $ +*/ +#ifndef _INV_FILT_DET_H +#define _INV_FILT_DET_H + +#include "sbr_encoder.h" +#include "sbr_def.h" + +#define INVF_SMOOTHING_LENGTH 2 + +typedef struct +{ + const FIXP_DBL *quantStepsSbr; + const FIXP_DBL *quantStepsOrig; + const FIXP_DBL *nrgBorders; + INT numRegionsSbr; + INT numRegionsOrig; + INT numRegionsNrg; + INVF_MODE regionSpace[5][5]; + INVF_MODE regionSpaceTransient[5][5]; + INT EnergyCompFactor[5]; + +}DETECTOR_PARAMETERS; + +typedef struct +{ + FIXP_DBL origQuotaMean[INVF_SMOOTHING_LENGTH+1]; + FIXP_DBL sbrQuotaMean[INVF_SMOOTHING_LENGTH+1]; + FIXP_DBL origQuotaMeanStrongest[INVF_SMOOTHING_LENGTH+1]; + FIXP_DBL sbrQuotaMeanStrongest[INVF_SMOOTHING_LENGTH+1]; + + FIXP_DBL origQuotaMeanFilt; + FIXP_DBL sbrQuotaMeanFilt; + FIXP_DBL origQuotaMeanStrongestFilt; + FIXP_DBL sbrQuotaMeanStrongestFilt; + + FIXP_DBL origQuotaMax; + FIXP_DBL sbrQuotaMax; + + FIXP_DBL avgNrg; +}DETECTOR_VALUES; + + + +typedef struct +{ + INT numberOfStrongest; + + INT prevRegionSbr[MAX_NUM_NOISE_VALUES]; + INT prevRegionOrig[MAX_NUM_NOISE_VALUES]; + + INT freqBandTableInvFilt[MAX_NUM_NOISE_VALUES]; + INT noDetectorBands; + INT noDetectorBandsMax; + + const DETECTOR_PARAMETERS *detectorParams; + + INVF_MODE prevInvfMode[MAX_NUM_NOISE_VALUES]; + DETECTOR_VALUES detectorValues[MAX_NUM_NOISE_VALUES]; + + FIXP_DBL nrgAvg; + FIXP_DBL wmQmf[MAX_NUM_NOISE_VALUES]; +} +SBR_INV_FILT_EST; + +typedef SBR_INV_FILT_EST *HANDLE_SBR_INV_FILT_EST; + +void +FDKsbrEnc_qmfInverseFilteringDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, + FIXP_DBL ** quotaMatrix, + FIXP_DBL *nrgVector, + SCHAR *indexVector, + INT startIndex, + INT stopIndex, + INT transientFlag, + INVF_MODE* infVec); + +INT +FDKsbrEnc_initInvFiltDetector (HANDLE_SBR_INV_FILT_EST hInvFilt, + INT* freqBandTableDetector, + INT numDetectorBands, + UINT useSpeechConfig); + +/* void deleteInvFiltDetector (HANDLE_SBR_INV_FILT_EST hInvFilt); */ + +INT +FDKsbrEnc_resetInvFiltDetector(HANDLE_SBR_INV_FILT_EST hInvFilt, + INT* freqBandTableDetector, + INT numDetectorBands); + +#endif /* _QMF_INV_FILT_H */ + diff --git a/libSBRenc/src/mh_det.cpp b/libSBRenc/src/mh_det.cpp new file mode 100644 index 0000000..8b6c1a0 --- /dev/null +++ b/libSBRenc/src/mh_det.cpp @@ -0,0 +1,1381 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "mh_det.h" + +#include "sbr_ram.h" +#include "sbr_misc.h" + + +#include "genericStds.h" + +#define SFM_SHIFT 2 /* Attention: SFM_SCALE depends on SFM_SHIFT */ +#define SFM_SCALE (MAXVAL_DBL >> SFM_SHIFT) /* 1.0 >> SFM_SHIFT */ + + +/*!< Detector Parameters for AAC core codec. */ +static const DETECTOR_PARAMETERS_MH paramsAac = { +9, /*!< deltaTime */ +{ +FL2FXCONST_DBL(20.0f*RELAXATION_FLOAT), /*!< thresHoldDiff */ +FL2FXCONST_DBL(1.26f*RELAXATION_FLOAT), /*!< thresHoldDiffGuide */ +FL2FXCONST_DBL(15.0f*RELAXATION_FLOAT), /*!< thresHoldTone */ +FL2FXCONST_DBL((1.0f/15.0f)*RELAXATION_FLOAT), /*!< invThresHoldTone */ +FL2FXCONST_DBL(1.26f*RELAXATION_FLOAT), /*!< thresHoldToneGuide */ +FL2FXCONST_DBL(0.3f)>>SFM_SHIFT, /*!< sfmThresSbr */ +FL2FXCONST_DBL(0.1f)>>SFM_SHIFT, /*!< sfmThresOrig */ +FL2FXCONST_DBL(0.3f), /*!< decayGuideOrig */ +FL2FXCONST_DBL(0.5f), /*!< decayGuideDiff */ +FL2FXCONST_DBL(-0.000112993269), /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresMaxLD64 */ +FL2FXCONST_DBL(-0.000112993269), /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresBelowLD64 */ +FL2FXCONST_DBL(-0.005030126483f) /* LD64(FL2FXCONST_DBL(0.8f)) */ /*!< derivThresAboveLD64 */ +}, +50 /*!< maxComp */ +}; + +/*!< Detector Parameters for AAC LD core codec. */ +static const DETECTOR_PARAMETERS_MH paramsAacLd = { +16, /*!< Delta time. */ +{ +FL2FXCONST_DBL(25.0f*RELAXATION_FLOAT), /*!< thresHoldDiff */ +FL2FXCONST_DBL(1.26f*RELAXATION_FLOAT), /*!< tresHoldDiffGuide */ +FL2FXCONST_DBL(15.0f*RELAXATION_FLOAT), /*!< thresHoldTone */ +FL2FXCONST_DBL((1.0f/15.0f)*RELAXATION_FLOAT), /*!< invThresHoldTone */ +FL2FXCONST_DBL(1.26f*RELAXATION_FLOAT), /*!< thresHoldToneGuide */ +FL2FXCONST_DBL(0.3f)>>SFM_SHIFT, /*!< sfmThresSbr */ +FL2FXCONST_DBL(0.1f)>>SFM_SHIFT, /*!< sfmThresOrig */ +FL2FXCONST_DBL(0.3f), /*!< decayGuideOrig */ +FL2FXCONST_DBL(0.2f), /*!< decayGuideDiff */ +FL2FXCONST_DBL(-0.000112993269), /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresMaxLD64 */ +FL2FXCONST_DBL(-0.000112993269), /* LD64(FL2FXCONST_DBL(0.995f)) */ /*!< derivThresBelowLD64 */ +FL2FXCONST_DBL(-0.005030126483f) /* LD64(FL2FXCONST_DBL(0.8f)) */ /*!< derivThresAboveLD64 */ +}, +50 /*!< maxComp */ +}; + + +/**************************************************************************/ +/*! + \brief Calculates the difference in tonality between original and SBR + for a given time and frequency region. + + The values for pDiffMapped2Scfb are scaled by RELAXATION + + \return none. + +*/ +/**************************************************************************/ +static void diff(FIXP_DBL *RESTRICT pTonalityOrig, + FIXP_DBL *pDiffMapped2Scfb, + const UCHAR *RESTRICT pFreqBandTable, + INT nScfb, + SCHAR *indexVector) +{ + UCHAR i, ll, lu, k; + FIXP_DBL maxValOrig, maxValSbr, tmp; + INT scale; + + for(i=0; i < nScfb; i++){ + ll = pFreqBandTable[i]; + lu = pFreqBandTable[i+1]; + + maxValOrig = FL2FXCONST_DBL(0.0f); + maxValSbr = FL2FXCONST_DBL(0.0f); + + for(k=ll;k<lu;k++){ + maxValOrig = fixMax(maxValOrig, pTonalityOrig[k]); + maxValSbr = fixMax(maxValSbr, pTonalityOrig[indexVector[k]]); + } + + if ((maxValSbr >= RELAXATION)) { + tmp = fDivNorm(maxValOrig, maxValSbr, &scale); + pDiffMapped2Scfb[i] = scaleValue(fMult(tmp,RELAXATION_FRACT), fixMax(-(DFRACT_BITS-1),(scale-RELAXATION_SHIFT))); + } + else { + pDiffMapped2Scfb[i] = maxValOrig; + } + } +} + + +/**************************************************************************/ +/*! + \brief Calculates a flatness measure of the tonality measures. + + Calculation of the power function and using scalefactor for basis: + Using log2: + z = (2^k * x)^y; + z' = CalcLd(z) = y*CalcLd(x) + y*k; + z = CalcInvLd(z'); + + Using ld64: + z = (2^k * x)^y; + z' = CalcLd64(z) = y*CalcLd64(x)/64 + y*k/64; + z = CalcInvLd64(z'); + + The values pSfmOrigVec and pSfmSbrVec are scaled by the factor 1/4.0 + + \return none. + +*/ +/**************************************************************************/ +static void calculateFlatnessMeasure(FIXP_DBL *pQuotaBuffer, + SCHAR *indexVector, + FIXP_DBL *pSfmOrigVec, + FIXP_DBL *pSfmSbrVec, + const UCHAR *pFreqBandTable, + INT nSfb) +{ + INT i,j; + FIXP_DBL invBands,tmp1,tmp2; + INT shiftFac0,shiftFacSum0; + INT shiftFac1,shiftFacSum1; + FIXP_DBL accu; + + for(i=0;i<nSfb;i++) + { + INT ll = pFreqBandTable[i]; + INT lu = pFreqBandTable[i+1]; + pSfmOrigVec[i] = (FIXP_DBL)(MAXVAL_DBL>>2); + pSfmSbrVec[i] = (FIXP_DBL)(MAXVAL_DBL>>2); + + if(lu - ll > 1){ + FIXP_DBL amOrig,amTransp,gmOrig,gmTransp,sfmOrig,sfmTransp; + invBands = GetInvInt(lu-ll); + shiftFacSum0 = 0; + shiftFacSum1 = 0; + amOrig = amTransp = FL2FXCONST_DBL(0.0f); + gmOrig = gmTransp = (FIXP_DBL)MAXVAL_DBL; + + for(j= ll; j<lu; j++) { + sfmOrig = pQuotaBuffer[j]; + sfmTransp = pQuotaBuffer[indexVector[j]]; + + amOrig += fMult(sfmOrig, invBands); + amTransp += fMult(sfmTransp, invBands); + + shiftFac0 = CountLeadingBits(sfmOrig); + shiftFac1 = CountLeadingBits(sfmTransp); + + gmOrig = fMult(gmOrig, sfmOrig<<shiftFac0); + gmTransp = fMult(gmTransp, sfmTransp<<shiftFac1); + + shiftFacSum0 += shiftFac0; + shiftFacSum1 += shiftFac1; + } + + if (gmOrig > FL2FXCONST_DBL(0.0f)) { + + tmp1 = CalcLdData(gmOrig); /* CalcLd64(x)/64 */ + tmp1 = fMult(invBands, tmp1); /* y*CalcLd64(x)/64 */ + + /* y*k/64 */ + accu = (FIXP_DBL)-shiftFacSum0 << (DFRACT_BITS-1-8); + tmp2 = fMultDiv2(invBands, accu) << (2+1); + + tmp2 = tmp1 + tmp2; /* y*CalcLd64(x)/64 + y*k/64 */ + gmOrig = CalcInvLdData(tmp2); /* CalcInvLd64(z'); */ + } + else { + gmOrig = FL2FXCONST_DBL(0.0f); + } + + if (gmTransp > FL2FXCONST_DBL(0.0f)) { + + tmp1 = CalcLdData(gmTransp); /* CalcLd64(x)/64 */ + tmp1 = fMult(invBands, tmp1); /* y*CalcLd64(x)/64 */ + + /* y*k/64 */ + accu = (FIXP_DBL)-shiftFacSum1 << (DFRACT_BITS-1-8); + tmp2 = fMultDiv2(invBands, accu) << (2+1); + + tmp2 = tmp1 + tmp2; /* y*CalcLd64(x)/64 + y*k/64 */ + gmTransp = CalcInvLdData(tmp2); /* CalcInvLd64(z'); */ + } + else { + gmTransp = FL2FXCONST_DBL(0.0f); + } + if ( amOrig != FL2FXCONST_DBL(0.0f) ) + pSfmOrigVec[i] = FDKsbrEnc_LSI_divide_scale_fract(gmOrig,amOrig,SFM_SCALE); + + if ( amTransp != FL2FXCONST_DBL(0.0f) ) + pSfmSbrVec[i] = FDKsbrEnc_LSI_divide_scale_fract(gmTransp,amTransp,SFM_SCALE); + } + } +} + +/**************************************************************************/ +/*! + \brief Calculates the input to the missing harmonics detection. + + + \return none. + +*/ +/**************************************************************************/ +static void calculateDetectorInput(FIXP_DBL **RESTRICT pQuotaBuffer, /*!< Pointer to tonality matrix. */ + SCHAR *RESTRICT indexVector, + FIXP_DBL **RESTRICT tonalityDiff, + FIXP_DBL **RESTRICT pSfmOrig, + FIXP_DBL **RESTRICT pSfmSbr, + const UCHAR *freqBandTable, + INT nSfb, + INT noEstPerFrame, + INT move) +{ + INT est; + + /* + New estimate. + */ + for (est=0; est < noEstPerFrame; est++) { + + diff(pQuotaBuffer[est+move], + tonalityDiff[est+move], + freqBandTable, + nSfb, + indexVector); + + calculateFlatnessMeasure(pQuotaBuffer[est+ move], + indexVector, + pSfmOrig[est + move], + pSfmSbr[est + move], + freqBandTable, + nSfb); + } +} + + +/**************************************************************************/ +/*! + \brief Checks that the detection is not due to a LP filter + + This function determines if a newly detected missing harmonics is not + in fact just a low-pass filtere input signal. If so, the detection is + removed. + + \return none. + +*/ +/**************************************************************************/ +static void removeLowPassDetection(UCHAR *RESTRICT pAddHarmSfb, + UCHAR **RESTRICT pDetectionVectors, + INT start, + INT stop, + INT nSfb, + const UCHAR *RESTRICT pFreqBandTable, + FIXP_DBL *RESTRICT pNrgVector, + THRES_HOLDS mhThresh) + +{ + INT i,est; + INT maxDerivPos = pFreqBandTable[nSfb]; + INT numBands = pFreqBandTable[nSfb]; + FIXP_DBL nrgLow,nrgHigh; + FIXP_DBL nrgLD64,nrgLowLD64,nrgHighLD64,nrgDiffLD64; + FIXP_DBL valLD64,maxValLD64,maxValAboveLD64; + INT bLPsignal = 0; + + maxValLD64 = FL2FXCONST_DBL(-1.0f); + for(i = numBands - 1 - 2; i > pFreqBandTable[0];i--){ + nrgLow = pNrgVector[i]; + nrgHigh = pNrgVector[i + 2]; + + if(nrgLow != FL2FXCONST_DBL(0.0f) && nrgLow > nrgHigh){ + nrgLowLD64 = CalcLdData(nrgLow>>1); + nrgDiffLD64 = CalcLdData((nrgLow>>1)-(nrgHigh>>1)); + valLD64 = nrgDiffLD64-nrgLowLD64; + if(valLD64 > maxValLD64){ + maxDerivPos = i; + maxValLD64 = valLD64; + } + if(maxValLD64 > mhThresh.derivThresMaxLD64) { + break; + } + } + } + + /* Find the largest "gradient" above. (should be relatively flat, hence we expect a low value + if the signal is LP.*/ + maxValAboveLD64 = FL2FXCONST_DBL(-1.0f); + for(i = numBands - 1 - 2; i > maxDerivPos + 2;i--){ + nrgLow = pNrgVector[i]; + nrgHigh = pNrgVector[i + 2]; + + if(nrgLow != FL2FXCONST_DBL(0.0f) && nrgLow > nrgHigh){ + nrgLowLD64 = CalcLdData(nrgLow>>1); + nrgDiffLD64 = CalcLdData((nrgLow>>1)-(nrgHigh>>1)); + valLD64 = nrgDiffLD64-nrgLowLD64; + if(valLD64 > maxValAboveLD64){ + maxValAboveLD64 = valLD64; + } + } + else { + if(nrgHigh != FL2FXCONST_DBL(0.0f) && nrgHigh > nrgLow){ + nrgHighLD64 = CalcLdData(nrgHigh>>1); + nrgDiffLD64 = CalcLdData((nrgHigh>>1)-(nrgLow>>1)); + valLD64 = nrgDiffLD64-nrgHighLD64; + if(valLD64 > maxValAboveLD64){ + maxValAboveLD64 = valLD64; + } + } + } + } + + if(maxValLD64 > mhThresh.derivThresMaxLD64 && maxValAboveLD64 < mhThresh.derivThresAboveLD64){ + bLPsignal = 1; + + for(i = maxDerivPos - 1; i > maxDerivPos - 5 && i >= 0 ; i--){ + if(pNrgVector[i] != FL2FXCONST_DBL(0.0f) && pNrgVector[i] > pNrgVector[maxDerivPos + 2]){ + nrgDiffLD64 = CalcLdData((pNrgVector[i]>>1)-(pNrgVector[maxDerivPos + 2]>>1)); + nrgLD64 = CalcLdData(pNrgVector[i]>>1); + valLD64 = nrgDiffLD64-nrgLD64; + if(valLD64 < mhThresh.derivThresBelowLD64) { + bLPsignal = 0; + break; + } + } + else{ + bLPsignal = 0; + break; + } + } + } + + if(bLPsignal){ + for(i=0;i<nSfb;i++){ + if(maxDerivPos >= pFreqBandTable[i] && maxDerivPos < pFreqBandTable[i+1]) + break; + } + + if(pAddHarmSfb[i]){ + pAddHarmSfb[i] = 0; + for(est = start; est < stop ; est++){ + pDetectionVectors[est][i] = 0; + } + } + } +} + +/**************************************************************************/ +/*! + \brief Checks if it is allowed to detect a missing tone, that wasn't + detected previously. + + + \return newDetectionAllowed flag. + +*/ +/**************************************************************************/ +static INT isDetectionOfNewToneAllowed(const SBR_FRAME_INFO *pFrameInfo, + INT *pDetectionStartPos, + INT noEstPerFrame, + INT prevTransientFrame, + INT prevTransientPos, + INT prevTransientFlag, + INT transientPosOffset, + INT transientFlag, + INT transientPos, + INT deltaTime, + HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector) +{ + INT transientFrame, newDetectionAllowed; + + + /* Determine if this is a frame where a transient starts... + * If the transient flag was set the previous frame but not the + * transient frame flag, the transient frame flag is set in the current frame. + *****************************************************************************/ + transientFrame = 0; + if(transientFlag){ + if(transientPos + transientPosOffset < pFrameInfo->borders[pFrameInfo->nEnvelopes]) + transientFrame = 1; + if(noEstPerFrame > 1){ + if(transientPos + transientPosOffset > h_sbrMissingHarmonicsDetector->timeSlots >> 1){ + *pDetectionStartPos = noEstPerFrame; + } + else{ + *pDetectionStartPos = noEstPerFrame >> 1; + } + + } + else{ + *pDetectionStartPos = noEstPerFrame; + } + } + else{ + if(prevTransientFlag && !prevTransientFrame){ + transientFrame = 1; + *pDetectionStartPos = 0; + } + } + + /* + * Determine if detection of new missing harmonics are allowed. + * If the frame contains a transient it's ok. If the previous + * frame contained a transient it needs to be sufficiently close + * to the start of the current frame. + ****************************************************************/ + newDetectionAllowed = 0; + if(transientFrame){ + newDetectionAllowed = 1; + } + else { + if(prevTransientFrame && + fixp_abs(pFrameInfo->borders[0] - (prevTransientPos + transientPosOffset - + h_sbrMissingHarmonicsDetector->timeSlots)) < deltaTime) + newDetectionAllowed = 1; + *pDetectionStartPos = 0; + } + + h_sbrMissingHarmonicsDetector->previousTransientFlag = transientFlag; + h_sbrMissingHarmonicsDetector->previousTransientFrame = transientFrame; + h_sbrMissingHarmonicsDetector->previousTransientPos = transientPos; + + return (newDetectionAllowed); +} + + +/**************************************************************************/ +/*! + \brief Cleans up the detection after a transient. + + + \return none. + +*/ +/**************************************************************************/ +static void transientCleanUp(FIXP_DBL **quotaBuffer, + INT nSfb, + UCHAR **detectionVectors, + UCHAR *pAddHarmSfb, + UCHAR *pPrevAddHarmSfb, + INT ** signBuffer, + const UCHAR *pFreqBandTable, + INT start, + INT stop, + INT newDetectionAllowed, + FIXP_DBL *pNrgVector, + THRES_HOLDS mhThresh) +{ + INT i,j,li, ui,est; + + for(est=start; est < stop; est++) { + for(i=0; i<nSfb; i++) { + pAddHarmSfb[i] = pAddHarmSfb[i] || detectionVectors[est][i]; + } + } + + if(newDetectionAllowed == 1){ + /* + * Check for duplication of sines located + * on the border of two scf-bands. + *************************************************/ + for(i=0;i<nSfb-1;i++) { + li = pFreqBandTable[i]; + ui = pFreqBandTable[i+1]; + + /* detection in adjacent channels.*/ + if(pAddHarmSfb[i] && pAddHarmSfb[i+1]) { + FIXP_DBL maxVal1, maxVal2; + INT maxPos1, maxPos2, maxPosTime1, maxPosTime2; + + li = pFreqBandTable[i]; + ui = pFreqBandTable[i+1]; + + /* Find maximum tonality in the the two scf bands.*/ + maxPosTime1 = start; + maxPos1 = li; + maxVal1 = quotaBuffer[start][li]; + for(est = start; est < stop; est++){ + for(j = li; j<ui; j++){ + if(quotaBuffer[est][j] > maxVal1){ + maxVal1 = quotaBuffer[est][j]; + maxPos1 = j; + maxPosTime1 = est; + } + } + } + + li = pFreqBandTable[i+1]; + ui = pFreqBandTable[i+2]; + + /* Find maximum tonality in the the two scf bands.*/ + maxPosTime2 = start; + maxPos2 = li; + maxVal2 = quotaBuffer[start][li]; + for(est = start; est < stop; est++){ + for(j = li; j<ui; j++){ + if(quotaBuffer[est][j] > maxVal2){ + maxVal2 = quotaBuffer[est][j]; + maxPos2 = j; + maxPosTime2 = est; + } + } + } + + /* If the maximum values are in adjacent QMF-channels, we need to remove + the lowest of the two.*/ + if(maxPos2-maxPos1 < 2){ + + if(pPrevAddHarmSfb[i] == 1 && pPrevAddHarmSfb[i+1] == 0){ + /* Keep the lower, remove the upper.*/ + pAddHarmSfb[i+1] = 0; + for(est=start; est<stop; est++){ + detectionVectors[est][i+1] = 0; + } + } + else{ + if(pPrevAddHarmSfb[i] == 0 && pPrevAddHarmSfb[i+1] == 1){ + /* Keep the upper, remove the lower.*/ + pAddHarmSfb[i] = 0; + for(est=start; est<stop; est++){ + detectionVectors[est][i] = 0; + } + } + else{ + /* If the maximum values are in adjacent QMF-channels, and if the signs indicate that it is the same sine, + we need to remove the lowest of the two.*/ + if(maxVal1 > maxVal2){ + if(signBuffer[maxPosTime1][maxPos2] < 0 && signBuffer[maxPosTime1][maxPos1] > 0){ + /* Keep the lower, remove the upper.*/ + pAddHarmSfb[i+1] = 0; + for(est=start; est<stop; est++){ + detectionVectors[est][i+1] = 0; + } + } + } + else{ + if(signBuffer[maxPosTime2][maxPos2] < 0 && signBuffer[maxPosTime2][maxPos1] > 0){ + /* Keep the upper, remove the lower.*/ + pAddHarmSfb[i] = 0; + for(est=start; est<stop; est++){ + detectionVectors[est][i] = 0; + } + } + } + } + } + } + } + } + + /* Make sure that the detection is not the cut-off of a low pass filter. */ + removeLowPassDetection(pAddHarmSfb, + detectionVectors, + start, + stop, + nSfb, + pFreqBandTable, + pNrgVector, + mhThresh); + } + else { + /* + * If a missing harmonic wasn't missing the previous frame + * the transient-flag needs to be set in order to be allowed to detect it. + *************************************************************************/ + for(i=0;i<nSfb;i++){ + if(pAddHarmSfb[i] - pPrevAddHarmSfb[i] > 0) + pAddHarmSfb[i] = 0; + } + } +} + + +/**************************************************************************/ +/*! + \brief Do detection for one tonality estimate. + + + \return none. + +*/ +/**************************************************************************/ +static void detection(FIXP_DBL *quotaBuffer, + FIXP_DBL *pDiffVecScfb, + INT nSfb, + UCHAR *pHarmVec, + const UCHAR *pFreqBandTable, + FIXP_DBL *sfmOrig, + FIXP_DBL *sfmSbr, + GUIDE_VECTORS guideVectors, + GUIDE_VECTORS newGuideVectors, + THRES_HOLDS mhThresh) +{ + + INT i,j,ll, lu; + FIXP_DBL thresTemp,thresOrig; + + /* + * Do detection on the difference vector, i.e. the difference between + * the original and the transposed. + *********************************************************************/ + for(i=0;i<nSfb;i++){ + + thresTemp = (guideVectors.guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)) + ? fixMax(fMult(mhThresh.decayGuideDiff,guideVectors.guideVectorDiff[i]), mhThresh.thresHoldDiffGuide) + : mhThresh.thresHoldDiff; + + thresTemp = fixMin(thresTemp, mhThresh.thresHoldDiff); + + if(pDiffVecScfb[i] > thresTemp){ + pHarmVec[i] = 1; + newGuideVectors.guideVectorDiff[i] = pDiffVecScfb[i]; + } + else{ + /* If the guide wasn't zero, but the current level is to low, + start tracking the decay on the tone in the original rather + than the difference.*/ + if(guideVectors.guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)){ + guideVectors.guideVectorOrig[i] = mhThresh.thresHoldToneGuide; + } + } + } + + /* + * Trace tones in the original signal that at one point + * have been detected because they will be replaced by + * multiple tones in the sbr signal. + ****************************************************/ + + for(i=0;i<nSfb;i++){ + ll = pFreqBandTable[i]; + lu = pFreqBandTable[i+1]; + + thresOrig = fixMax(fMult(guideVectors.guideVectorOrig[i], mhThresh.decayGuideOrig), mhThresh.thresHoldToneGuide); + thresOrig = fixMin(thresOrig, mhThresh.thresHoldTone); + + if(guideVectors.guideVectorOrig[i] != FL2FXCONST_DBL(0.0f)){ + for(j= ll;j<lu;j++){ + if(quotaBuffer[j] > thresOrig){ + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[j]; + } + } + } + } + + /* + * Check for multiple sines in the transposed signal, + * where there is only one in the original. + ****************************************************/ + thresOrig = mhThresh.thresHoldTone; + + for(i=0;i<nSfb;i++){ + ll = pFreqBandTable[i]; + lu = pFreqBandTable[i+1]; + + if(pHarmVec[i] == 0){ + if(lu -ll > 1){ + for(j= ll;j<lu;j++){ + if(quotaBuffer[j] > thresOrig && (sfmSbr[i] > mhThresh.sfmThresSbr && sfmOrig[i] < mhThresh.sfmThresOrig)){ + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[j]; + } + } + } + else{ + if(i < nSfb -1){ + ll = pFreqBandTable[i]; + + if(i>0){ + if(quotaBuffer[ll] > mhThresh.thresHoldTone && (pDiffVecScfb[i+1] < mhThresh.invThresHoldTone || pDiffVecScfb[i-1] < mhThresh.invThresHoldTone)){ + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[ll]; + } + } + else{ + if(quotaBuffer[ll] > mhThresh.thresHoldTone && pDiffVecScfb[i+1] < mhThresh.invThresHoldTone){ + pHarmVec[i] = 1; + newGuideVectors.guideVectorOrig[i] = quotaBuffer[ll]; + } + } + } + } + } + } +} + + +/**************************************************************************/ +/*! + \brief Do detection for every tonality estimate, using forward prediction. + + + \return none. + +*/ +/**************************************************************************/ +static void detectionWithPrediction(FIXP_DBL **quotaBuffer, + FIXP_DBL **pDiffVecScfb, + INT ** signBuffer, + INT nSfb, + const UCHAR* pFreqBandTable, + FIXP_DBL **sfmOrig, + FIXP_DBL **sfmSbr, + UCHAR **detectionVectors, + UCHAR *pPrevAddHarmSfb, + GUIDE_VECTORS *guideVectors, + INT noEstPerFrame, + INT detectionStart, + INT totNoEst, + INT newDetectionAllowed, + INT *pAddHarmFlag, + UCHAR *pAddHarmSfb, + FIXP_DBL *pNrgVector, + const DETECTOR_PARAMETERS_MH *mhParams) +{ + INT est = 0,i; + INT start; + + FDKmemclear(pAddHarmSfb,nSfb*sizeof(UCHAR)); + + if(newDetectionAllowed){ + + if(totNoEst > 1){ + start = detectionStart; + + if (start != 0) { + FDKmemcpy(guideVectors[start].guideVectorDiff,guideVectors[0].guideVectorDiff,nSfb*sizeof(FIXP_DBL)); + FDKmemcpy(guideVectors[start].guideVectorOrig,guideVectors[0].guideVectorOrig,nSfb*sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[start-1].guideVectorDetected,nSfb*sizeof(UCHAR)); + } + } + else{ + start = 0; + } + } + else{ + start = 0; + } + + + for(est = start; est < totNoEst; est++){ + + /* + * Do detection on the current frame using + * guide-info from the previous. + *******************************************/ + if(est > 0){ + FDKmemcpy(guideVectors[est].guideVectorDetected,detectionVectors[est-1],nSfb*sizeof(UCHAR)); + } + + FDKmemclear(detectionVectors[est], nSfb*sizeof(UCHAR)); + + if(est < totNoEst-1){ + FDKmemclear(guideVectors[est+1].guideVectorDiff,nSfb*sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est+1].guideVectorOrig,nSfb*sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est+1].guideVectorDetected,nSfb*sizeof(UCHAR)); + + detection(quotaBuffer[est], + pDiffVecScfb[est], + nSfb, + detectionVectors[est], + pFreqBandTable, + sfmOrig[est], + sfmSbr[est], + guideVectors[est], + guideVectors[est+1], + mhParams->thresHolds); + } + else{ + FDKmemclear(guideVectors[est].guideVectorDiff,nSfb*sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est].guideVectorOrig,nSfb*sizeof(FIXP_DBL)); + FDKmemclear(guideVectors[est].guideVectorDetected,nSfb*sizeof(UCHAR)); + + detection(quotaBuffer[est], + pDiffVecScfb[est], + nSfb, + detectionVectors[est], + pFreqBandTable, + sfmOrig[est], + sfmSbr[est], + guideVectors[est], + guideVectors[est], + mhParams->thresHolds); + } + } + + + /* Clean up the detection.*/ + transientCleanUp(quotaBuffer, + nSfb, + detectionVectors, + pAddHarmSfb, + pPrevAddHarmSfb, + signBuffer, + pFreqBandTable, + start, + totNoEst, + newDetectionAllowed, + pNrgVector, + mhParams->thresHolds); + + + /* Set flag... */ + *pAddHarmFlag = 0; + for(i=0; i<nSfb; i++){ + if(pAddHarmSfb[i]){ + *pAddHarmFlag = 1; + break; + } + } + + FDKmemcpy(pPrevAddHarmSfb, pAddHarmSfb, nSfb*sizeof(UCHAR)); + FDKmemcpy(guideVectors[0].guideVectorDetected,pAddHarmSfb,nSfb*sizeof(INT)); + + for(i=0; i<nSfb ; i++){ + + guideVectors[0].guideVectorDiff[i] = FL2FXCONST_DBL(0.0f); + guideVectors[0].guideVectorOrig[i] = FL2FXCONST_DBL(0.0f); + + if(pAddHarmSfb[i] == 1){ + /* If we had a detection use the guide-value in the next frame from the last estimate were the detection + was done.*/ + for(est=start; est < totNoEst; est++){ + if(guideVectors[est].guideVectorDiff[i] != FL2FXCONST_DBL(0.0f)){ + guideVectors[0].guideVectorDiff[i] = guideVectors[est].guideVectorDiff[i]; + } + if(guideVectors[est].guideVectorOrig[i] != FL2FXCONST_DBL(0.0f)){ + guideVectors[0].guideVectorOrig[i] = guideVectors[est].guideVectorOrig[i]; + } + } + } + } + +} + + +/**************************************************************************/ +/*! + \brief Calculates a compensation vector for the energy data. + + This function calculates a compensation vector for the energy data (i.e. + envelope data) that is calculated elsewhere. This is since, one sine on + the border of two scalefactor bands, will be replace by one sine in the + middle of either scalefactor band. However, since the sine that is replaced + will influence the energy estimate in both scalefactor bands (in the envelops + calculation function) a compensation value is required in order to avoid + noise substitution in the decoder next to the synthetic sine. + + \return none. + +*/ +/**************************************************************************/ +static void calculateCompVector(UCHAR *pAddHarmSfb, + FIXP_DBL **pTonalityMatrix, + INT ** pSignMatrix, + UCHAR *pEnvComp, + INT nSfb, + const UCHAR *freqBandTable, + INT totNoEst, + INT maxComp, + UCHAR *pPrevEnvComp, + INT newDetectionAllowed) +{ + + INT scfBand,est,l,ll,lu,maxPosF,maxPosT; + FIXP_DBL maxVal; + INT compValue; + FIXP_DBL tmp; + + FDKmemclear(pEnvComp,nSfb*sizeof(UCHAR)); + + for(scfBand=0; scfBand < nSfb; scfBand++){ + + if(pAddHarmSfb[scfBand]){ /* A missing sine was detected */ + ll = freqBandTable[scfBand]; + lu = freqBandTable[scfBand+1]; + + maxPosF = 0; /* First find the maximum*/ + maxPosT = 0; + maxVal = FL2FXCONST_DBL(0.0f); + + for(est=0;est<totNoEst;est++){ + for(l=ll; l<lu; l++){ + if(pTonalityMatrix[est][l] > maxVal){ + maxVal = pTonalityMatrix[est][l]; + maxPosF = l; + maxPosT = est; + } + } + } + + /* + * If the maximum tonality is at the lower border of the + * scalefactor band, we check the sign of the adjacent channels + * to see if this sine is shared by the lower channel. If so, the + * energy of the single sine will be present in two scalefactor bands + * in the SBR data, which will cause problems in the decoder, when we + * add a sine to just one of the channels. + *********************************************************************/ + if(maxPosF == ll && scfBand){ + if(!pAddHarmSfb[scfBand - 1]) { /* No detection below*/ + if (pSignMatrix[maxPosT][maxPosF - 1] > 0 && pSignMatrix[maxPosT][maxPosF] < 0) { + /* The comp value is calulated as the tonallity value, i.e we want to + reduce the envelope data for this channel with as much as the tonality + that is spread from the channel above. (ld64(RELAXATION) = 0.31143075889) */ + tmp = fixp_abs((FIXP_DBL)CalcLdData(pTonalityMatrix[maxPosT][maxPosF - 1]) + RELAXATION_LD64); + tmp = (tmp >> (DFRACT_BITS-1-LD_DATA_SHIFT-1)) + (FIXP_DBL)1; /* shift one bit less for rounding */ + compValue = ((INT)(LONG)tmp) >> 1; + + /* limit the comp-value*/ + if (compValue > maxComp) + compValue = maxComp; + + pEnvComp[scfBand-1] = compValue; + } + } + } + + /* + * Same as above, but for the upper end of the scalefactor-band. + ***************************************************************/ + if(maxPosF == lu-1 && scfBand+1 < nSfb){ /* Upper border*/ + if(!pAddHarmSfb[scfBand + 1]) { + if (pSignMatrix[maxPosT][maxPosF] > 0 && pSignMatrix[maxPosT][maxPosF + 1] < 0) { + tmp = fixp_abs((FIXP_DBL)CalcLdData(pTonalityMatrix[maxPosT][maxPosF + 1]) + RELAXATION_LD64); + tmp = (tmp >> (DFRACT_BITS-1-LD_DATA_SHIFT-1)) + (FIXP_DBL)1; /* shift one bit less for rounding */ + compValue = ((INT)(LONG)tmp) >> 1; + + if (compValue > maxComp) + compValue = maxComp; + + pEnvComp[scfBand+1] = compValue; + } + } + } + } + } + + if(newDetectionAllowed == 0){ + for(scfBand=0;scfBand<nSfb;scfBand++){ + if(pEnvComp[scfBand] != 0 && pPrevEnvComp[scfBand] == 0) + pEnvComp[scfBand] = 0; + } + } + + /* remember the value for the next frame.*/ + FDKmemcpy(pPrevEnvComp,pEnvComp,nSfb*sizeof(UCHAR)); +} + + +/**************************************************************************/ +/*! + \brief Detects where strong tonal components will be missing after + HFR in the decoder. + + + \return none. + +*/ +/**************************************************************************/ +void +FDKsbrEnc_SbrMissingHarmonicsDetectorQmf(HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMHDet, + FIXP_DBL ** pQuotaBuffer, + INT ** pSignBuffer, + SCHAR* indexVector, + const SBR_FRAME_INFO *pFrameInfo, + const UCHAR* pTranInfo, + INT* pAddHarmonicsFlag, + UCHAR* pAddHarmonicsScaleFactorBands, + const UCHAR* freqBandTable, + INT nSfb, + UCHAR* envelopeCompensation, + FIXP_DBL *pNrgVector) +{ + INT transientFlag = pTranInfo[1]; + INT transientPos = pTranInfo[0]; + INT newDetectionAllowed; + INT transientDetStart = 0; + + UCHAR ** detectionVectors = h_sbrMHDet->detectionVectors; + INT move = h_sbrMHDet->move; + INT noEstPerFrame = h_sbrMHDet->noEstPerFrame; + INT totNoEst = h_sbrMHDet->totNoEst; + INT prevTransientFlag = h_sbrMHDet->previousTransientFlag; + INT prevTransientFrame = h_sbrMHDet->previousTransientFrame; + INT transientPosOffset = h_sbrMHDet->transientPosOffset; + INT prevTransientPos = h_sbrMHDet->previousTransientPos; + GUIDE_VECTORS* guideVectors = h_sbrMHDet->guideVectors; + INT deltaTime = h_sbrMHDet->mhParams->deltaTime; + INT maxComp = h_sbrMHDet->mhParams->maxComp; + + int est; + + /* + Buffer values. + */ + FDK_ASSERT(move<=(MAX_NO_OF_ESTIMATES>>1)); + FDK_ASSERT(noEstPerFrame<=(MAX_NO_OF_ESTIMATES>>1)); + + FIXP_DBL *sfmSbr[MAX_NO_OF_ESTIMATES]; + FIXP_DBL *sfmOrig[MAX_NO_OF_ESTIMATES]; + FIXP_DBL *tonalityDiff[MAX_NO_OF_ESTIMATES]; + + for (est=0; est < MAX_NO_OF_ESTIMATES/2; est++) { + sfmSbr[est] = h_sbrMHDet->sfmSbr[est]; + sfmOrig[est] = h_sbrMHDet->sfmOrig[est]; + tonalityDiff[est] = h_sbrMHDet->tonalityDiff[est]; + } + + C_ALLOC_SCRATCH_START(scratch_mem, FIXP_DBL, (3*MAX_NO_OF_ESTIMATES/2*MAX_FREQ_COEFFS)); + FIXP_DBL *scratch = scratch_mem; + for (; est < MAX_NO_OF_ESTIMATES; est++) { + sfmSbr[est] = scratch; scratch+=MAX_FREQ_COEFFS; + sfmOrig[est] = scratch; scratch+=MAX_FREQ_COEFFS; + tonalityDiff[est] = scratch; scratch+=MAX_FREQ_COEFFS; + } + + + + /* Determine if we're allowed to detect "missing harmonics" that wasn't detected before. + In order to be allowed to do new detection, there must be a transient in the current + frame, or a transient in the previous frame sufficiently close to the current frame. */ + newDetectionAllowed = isDetectionOfNewToneAllowed(pFrameInfo, + &transientDetStart, + noEstPerFrame, + prevTransientFrame, + prevTransientPos, + prevTransientFlag, + transientPosOffset, + transientFlag, + transientPos, + deltaTime, + h_sbrMHDet); + + /* Calulate the variables that will be used subsequently for the actual detection */ + calculateDetectorInput(pQuotaBuffer, + indexVector, + tonalityDiff, + sfmOrig, + sfmSbr, + freqBandTable, + nSfb, + noEstPerFrame, + move); + + /* Do the actual detection using information from previous detections */ + detectionWithPrediction(pQuotaBuffer, + tonalityDiff, + pSignBuffer, + nSfb, + freqBandTable, + sfmOrig, + sfmSbr, + detectionVectors, + h_sbrMHDet->guideScfb, + guideVectors, + noEstPerFrame, + transientDetStart, + totNoEst, + newDetectionAllowed, + pAddHarmonicsFlag, + pAddHarmonicsScaleFactorBands, + pNrgVector, + h_sbrMHDet->mhParams); + + /* Calculate the comp vector, so that the energy can be + compensated for a sine between two QMF-bands. */ + calculateCompVector(pAddHarmonicsScaleFactorBands, + pQuotaBuffer, + pSignBuffer, + envelopeCompensation, + nSfb, + freqBandTable, + totNoEst, + maxComp, + h_sbrMHDet->prevEnvelopeCompensation, + newDetectionAllowed); + + for (est=0; est < move; est++) { + FDKmemcpy(tonalityDiff[est], tonalityDiff[est + noEstPerFrame], sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemcpy(sfmOrig[est], sfmOrig[est + noEstPerFrame], sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemcpy(sfmSbr[est], sfmSbr[est + noEstPerFrame], sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + } + C_ALLOC_SCRATCH_END(scratch, FIXP_DBL, (3*MAX_NO_OF_ESTIMATES/2*MAX_FREQ_COEFFS)); + + +} + +/**************************************************************************/ +/*! + \brief Initialize an instance of the missing harmonics detector. + + + \return errorCode, noError if OK. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_CreateSbrMissingHarmonicsDetector ( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, + INT chan) +{ + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; + INT i; + + UCHAR* detectionVectors = GetRam_Sbr_detectionVectors(chan); + UCHAR* guideVectorDetected = GetRam_Sbr_guideVectorDetected(chan); + FIXP_DBL* guideVectorDiff = GetRam_Sbr_guideVectorDiff(chan); + FIXP_DBL* guideVectorOrig = GetRam_Sbr_guideVectorOrig(chan); + + FDKmemclear (hs,sizeof(SBR_MISSING_HARMONICS_DETECTOR)); + + hs->prevEnvelopeCompensation = GetRam_Sbr_prevEnvelopeCompensation(chan); + hs->guideScfb = GetRam_Sbr_guideScfb(chan); + + for(i=0; i<MAX_NO_OF_ESTIMATES; i++) { + hs->guideVectors[i].guideVectorDiff = guideVectorDiff + (i*MAX_FREQ_COEFFS); + hs->guideVectors[i].guideVectorOrig = guideVectorOrig + (i*MAX_FREQ_COEFFS); + hs->detectionVectors[i] = detectionVectors + (i*MAX_FREQ_COEFFS); + hs->guideVectors[i].guideVectorDetected = guideVectorDetected + (i*MAX_FREQ_COEFFS); + } + + return 0; +} + + +/**************************************************************************/ +/*! + \brief Initialize an instance of the missing harmonics detector. + + + \return errorCode, noError if OK. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_InitSbrMissingHarmonicsDetector ( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, + INT sampleFreq, + INT frameSize, + INT nSfb, + INT qmfNoChannels, + INT totNoEst, + INT move, + INT noEstPerFrame, + UINT sbrSyntaxFlags + ) +{ + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; + int i; + + FDK_ASSERT(totNoEst <= MAX_NO_OF_ESTIMATES); + + switch(frameSize){ + case 2048: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_2048; + hs->timeSlots = NUMBER_TIME_SLOTS_2048; + break; + case 1920: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_1920; + hs->timeSlots = NUMBER_TIME_SLOTS_1920; + break; + case 1024: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + hs->timeSlots = 16; + break; + case 960: + hs->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + hs->timeSlots = 15; + break; + default: + return -1; + } + + if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + hs->mhParams = ¶msAacLd; + } else + hs->mhParams = ¶msAac; + + hs->qmfNoChannels = qmfNoChannels; + hs->sampleFreq = sampleFreq; + hs->nSfb = nSfb; + + hs->totNoEst = totNoEst; + hs->move = move; + hs->noEstPerFrame = noEstPerFrame; + + for(i=0; i<totNoEst; i++) { + FDKmemclear (hs->guideVectors[i].guideVectorDiff,sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemclear (hs->guideVectors[i].guideVectorOrig,sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemclear (hs->detectionVectors[i],sizeof(UCHAR)*MAX_FREQ_COEFFS); + FDKmemclear (hs->guideVectors[i].guideVectorDetected,sizeof(UCHAR)*MAX_FREQ_COEFFS); + } + + //for(i=0; i<totNoEst/2; i++) { + for(i=0; i<MAX_NO_OF_ESTIMATES/2; i++) { + FDKmemclear (hs->tonalityDiff[i],sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemclear (hs->sfmOrig[i],sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + FDKmemclear (hs->sfmSbr[i],sizeof(FIXP_DBL)*MAX_FREQ_COEFFS); + } + + FDKmemclear ( hs->prevEnvelopeCompensation, sizeof(UCHAR)*MAX_FREQ_COEFFS); + FDKmemclear ( hs->guideScfb, sizeof(UCHAR)*MAX_FREQ_COEFFS); + + hs->previousTransientFlag = 0; + hs->previousTransientFrame = 0; + hs->previousTransientPos = 0; + + return (0); +} + +/**************************************************************************/ +/*! + \brief Deletes an instance of the missing harmonics detector. + + + \return none. + +*/ +/**************************************************************************/ +void +FDKsbrEnc_DeleteSbrMissingHarmonicsDetector(HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet) +{ + if (hSbrMHDet) { + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hs = hSbrMHDet; + + FreeRam_Sbr_detectionVectors(&hs->detectionVectors[0]); + FreeRam_Sbr_guideVectorDetected(&hs->guideVectors[0].guideVectorDetected); + FreeRam_Sbr_guideVectorDiff(&hs->guideVectors[0].guideVectorDiff); + FreeRam_Sbr_guideVectorOrig(&hs->guideVectors[0].guideVectorOrig); + FreeRam_Sbr_prevEnvelopeCompensation(&hs->prevEnvelopeCompensation); + FreeRam_Sbr_guideScfb(&hs->guideScfb); + + } +} + +/**************************************************************************/ +/*! + \brief Resets an instance of the missing harmonics detector. + + + \return error code, noError if OK. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_ResetSbrMissingHarmonicsDetector (HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMissingHarmonicsDetector, + INT nSfb) +{ + int i; + FIXP_DBL tempGuide[MAX_FREQ_COEFFS]; + UCHAR tempGuideInt[MAX_FREQ_COEFFS]; + INT nSfbPrev; + + nSfbPrev = hSbrMissingHarmonicsDetector->nSfb; + hSbrMissingHarmonicsDetector->nSfb = nSfb; + + FDKmemcpy( tempGuideInt, hSbrMissingHarmonicsDetector->guideScfb, nSfbPrev * sizeof(UCHAR) ); + + if ( nSfb > nSfbPrev ) { + for ( i = 0; i < (nSfb - nSfbPrev); i++ ) { + hSbrMissingHarmonicsDetector->guideScfb[i] = 0; + } + + for ( i = 0; i < nSfbPrev; i++ ) { + hSbrMissingHarmonicsDetector->guideScfb[i + (nSfb - nSfbPrev)] = tempGuideInt[i]; + } + } + else { + for ( i = 0; i < nSfb; i++ ) { + hSbrMissingHarmonicsDetector->guideScfb[i] = tempGuideInt[i + (nSfbPrev-nSfb)]; + } + } + + FDKmemcpy ( tempGuide, hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff, nSfbPrev * sizeof(FIXP_DBL) ); + + if (nSfb > nSfbPrev ) { + for ( i = 0; i < (nSfb - nSfbPrev); i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i] = FL2FXCONST_DBL(0.0f); + } + + for ( i = 0; i < nSfbPrev; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i + (nSfb - nSfbPrev)] = tempGuide[i]; + } + } + else { + for ( i = 0; i < nSfb; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDiff[i] = tempGuide[i + (nSfbPrev-nSfb)]; + } + } + + FDKmemcpy ( tempGuide, hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig, nSfbPrev * sizeof(FIXP_DBL) ); + + if ( nSfb > nSfbPrev ) { + for ( i = 0; i< (nSfb - nSfbPrev); i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i] = FL2FXCONST_DBL(0.0f); + } + + for ( i = 0; i < nSfbPrev; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i + (nSfb - nSfbPrev)] = tempGuide[i]; + } + } + else { + for ( i = 0; i < nSfb; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorOrig[i] = tempGuide[i + (nSfbPrev-nSfb)]; + } + } + + FDKmemcpy ( tempGuideInt, hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected, nSfbPrev * sizeof(UCHAR) ); + + if ( nSfb > nSfbPrev ) { + for ( i = 0; i < (nSfb - nSfbPrev); i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i] = 0; + } + + for ( i = 0; i < nSfbPrev; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i + (nSfb - nSfbPrev)] = tempGuideInt[i]; + } + } + else { + for ( i = 0; i < nSfb; i++ ) { + hSbrMissingHarmonicsDetector->guideVectors[0].guideVectorDetected[i] = tempGuideInt[i + (nSfbPrev-nSfb)]; + } + } + + FDKmemcpy ( tempGuideInt, hSbrMissingHarmonicsDetector->prevEnvelopeCompensation, nSfbPrev * sizeof(UCHAR) ); + + if ( nSfb > nSfbPrev ) { + for ( i = 0; i < (nSfb - nSfbPrev); i++ ) { + hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i] = 0; + } + + for ( i = 0; i < nSfbPrev; i++ ) { + hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i + (nSfb - nSfbPrev)] = tempGuideInt[i]; + } + } + else { + for ( i = 0; i < nSfb; i++ ) { + hSbrMissingHarmonicsDetector->prevEnvelopeCompensation[i] = tempGuideInt[i + (nSfbPrev-nSfb)]; + } + } + + return 0; +} + diff --git a/libSBRenc/src/mh_det.h b/libSBRenc/src/mh_det.h new file mode 100644 index 0000000..3c4ca7d --- /dev/null +++ b/libSBRenc/src/mh_det.h @@ -0,0 +1,138 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief missing harmonics detection header file $Revision: 36847 $ +*/ + +#ifndef __MH_DETECT_H +#define __MH_DETECT_H + +#include "sbr_encoder.h" +#include "fram_gen.h" + +typedef struct +{ + FIXP_DBL thresHoldDiff; /*!< threshold for tonality difference */ + FIXP_DBL thresHoldDiffGuide; /*!< threshold for tonality difference for the guide */ + FIXP_DBL thresHoldTone; /*!< threshold for tonality for a sine */ + FIXP_DBL invThresHoldTone; + FIXP_DBL thresHoldToneGuide; /*!< threshold for tonality for a sine for the guide */ + FIXP_DBL sfmThresSbr; /*!< tonality flatness measure threshold for the SBR signal.*/ + FIXP_DBL sfmThresOrig; /*!< tonality flatness measure threshold for the original signal.*/ + FIXP_DBL decayGuideOrig; /*!< decay value of the tonality value of the guide for the tone. */ + FIXP_DBL decayGuideDiff; /*!< decay value of the tonality value of the guide for the tonality difference. */ + FIXP_DBL derivThresMaxLD64; /*!< threshold for detecting LP character in a signal. */ + FIXP_DBL derivThresBelowLD64; /*!< threshold for detecting LP character in a signal. */ + FIXP_DBL derivThresAboveLD64; /*!< threshold for detecting LP character in a signal. */ +}THRES_HOLDS; + +typedef struct +{ + INT deltaTime; /*!< maximum allowed transient distance (from frame border in number of qmf subband sample) + for a frame to be considered a transient frame.*/ + THRES_HOLDS thresHolds; /*!< the thresholds used for detection. */ + INT maxComp; /*!< maximum alllowed compensation factor for the envelope data. */ +}DETECTOR_PARAMETERS_MH; + +typedef struct +{ + FIXP_DBL *guideVectorDiff; + FIXP_DBL *guideVectorOrig; + UCHAR* guideVectorDetected; +}GUIDE_VECTORS; + + +typedef struct +{ + INT qmfNoChannels; + INT nSfb; + INT sampleFreq; + INT previousTransientFlag; + INT previousTransientFrame; + INT previousTransientPos; + + INT noVecPerFrame; + INT transientPosOffset; + + INT move; + INT totNoEst; + INT noEstPerFrame; + INT timeSlots; + + UCHAR *guideScfb; + UCHAR *prevEnvelopeCompensation; + UCHAR *detectionVectors[MAX_NO_OF_ESTIMATES]; + FIXP_DBL tonalityDiff[MAX_NO_OF_ESTIMATES/2][MAX_FREQ_COEFFS]; + FIXP_DBL sfmOrig[MAX_NO_OF_ESTIMATES/2][MAX_FREQ_COEFFS]; + FIXP_DBL sfmSbr[MAX_NO_OF_ESTIMATES/2][MAX_FREQ_COEFFS]; + const DETECTOR_PARAMETERS_MH *mhParams; + GUIDE_VECTORS guideVectors[MAX_NO_OF_ESTIMATES]; +} +SBR_MISSING_HARMONICS_DETECTOR; + +typedef SBR_MISSING_HARMONICS_DETECTOR *HANDLE_SBR_MISSING_HARMONICS_DETECTOR; + +void +FDKsbrEnc_SbrMissingHarmonicsDetectorQmf(HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector, + FIXP_DBL ** pQuotaBuffer, + INT ** pSignBuffer, + SCHAR *indexVector, + const SBR_FRAME_INFO *pFrameInfo, + const UCHAR* pTranInfo, + INT* pAddHarmonicsFlag, + UCHAR* pAddHarmonicsScaleFactorBands, + const UCHAR* freqBandTable, + INT nSfb, + UCHAR * envelopeCompensation, + FIXP_DBL *pNrgVector); + +INT +FDKsbrEnc_CreateSbrMissingHarmonicsDetector ( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMHDet, + INT chan); + +INT +FDKsbrEnc_InitSbrMissingHarmonicsDetector( + HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector, + INT sampleFreq, + INT frameSize, + INT nSfb, + INT qmfNoChannels, + INT totNoEst, + INT move, + INT noEstPerFrame, + UINT sbrSyntaxFlags); + +void +FDKsbrEnc_DeleteSbrMissingHarmonicsDetector (HANDLE_SBR_MISSING_HARMONICS_DETECTOR h_sbrMissingHarmonicsDetector); + + +INT +FDKsbrEnc_ResetSbrMissingHarmonicsDetector (HANDLE_SBR_MISSING_HARMONICS_DETECTOR hSbrMissingHarmonicsDetector, + INT nSfb); + +#endif diff --git a/libSBRenc/src/nf_est.cpp b/libSBRenc/src/nf_est.cpp new file mode 100644 index 0000000..168698d --- /dev/null +++ b/libSBRenc/src/nf_est.cpp @@ -0,0 +1,518 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "nf_est.h" + +#include "sbr_misc.h" + +#include "genericStds.h" + +/* smoothFilter[4] = {0.05857864376269f, 0.2f, 0.34142135623731f, 0.4f}; */ +static const FIXP_DBL smoothFilter[4] = { 0x077f813d, 0x19999995, 0x2bb3b1f5, 0x33333335 }; + +/* static const INT smoothFilterLength = 4; */ + +static const FIXP_DBL QuantOffset = (INT)0xfc000000; /* ld64(0.25) */ + +#ifndef min +#define min(a,b) ( a < b ? a:b) +#endif + +#ifndef max +#define max(a,b) ( a > b ? a:b) +#endif + +#define NOISE_FLOOR_OFFSET_SCALING (3) + + + +/**************************************************************************/ +/*! + \brief The function applies smoothing to the noise levels. + + + + \return none + +*/ +/**************************************************************************/ +static void +smoothingOfNoiseLevels(FIXP_DBL *NoiseLevels, /*!< pointer to noise-floor levels.*/ + INT nEnvelopes, /*!< Number of noise floor envelopes.*/ + INT noNoiseBands, /*!< Number of noise bands for every noise floor envelope. */ + FIXP_DBL prevNoiseLevels[NF_SMOOTHING_LENGTH][MAX_NUM_NOISE_VALUES],/*!< Previous noise floor envelopes. */ + const FIXP_DBL *smoothFilter, /*!< filter used for smoothing the noise floor levels. */ + INT transientFlag) /*!< flag indicating if a transient is present*/ + +{ + INT i,band,env; + FIXP_DBL accu; + + for(env = 0; env < nEnvelopes; env++){ + if(transientFlag){ + for (i = 0; i < NF_SMOOTHING_LENGTH; i++){ + FDKmemcpy(prevNoiseLevels[i],NoiseLevels+env*noNoiseBands,noNoiseBands*sizeof(FIXP_DBL)); + } + } + else { + for (i = 1; i < NF_SMOOTHING_LENGTH; i++){ + FDKmemcpy(prevNoiseLevels[i - 1],prevNoiseLevels[i],noNoiseBands*sizeof(FIXP_DBL)); + } + FDKmemcpy(prevNoiseLevels[NF_SMOOTHING_LENGTH - 1],NoiseLevels+env*noNoiseBands,noNoiseBands*sizeof(FIXP_DBL)); + } + + for (band = 0; band < noNoiseBands; band++){ + accu = FL2FXCONST_DBL(0.0f); + for (i = 0; i < NF_SMOOTHING_LENGTH; i++){ + accu += fMultDiv2(smoothFilter[i], prevNoiseLevels[i][band]); + } + FDK_ASSERT( (band + env*noNoiseBands) < MAX_NUM_NOISE_VALUES); + NoiseLevels[band+ env*noNoiseBands] = accu<<1; + } + } +} + +/**************************************************************************/ +/*! + \brief Does the noise floor level estiamtion. + + The noiseLevel samples are scaled by the factor 0.25 + + \return none + +*/ +/**************************************************************************/ +static void +qmfBasedNoiseFloorDetection(FIXP_DBL *noiseLevel, /*!< Pointer to vector to store the noise levels in.*/ + FIXP_DBL ** quotaMatrixOrig, /*!< Matrix holding the quota values of the original. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + INT startIndex, /*!< Start index. */ + INT stopIndex, /*!< Stop index. */ + INT startChannel, /*!< Start channel of the current noise floor band.*/ + INT stopChannel, /*!< Stop channel of the current noise floor band. */ + FIXP_DBL ana_max_level, /*!< Maximum level of the adaptive noise.*/ + FIXP_DBL noiseFloorOffset, /*!< Noise floor offset. */ + INT missingHarmonicFlag, /*!< Flag indicating if a strong tonal component is missing.*/ + FIXP_DBL weightFac, /*!< Weightening factor for the difference between orig and sbr. */ + INVF_MODE diffThres, /*!< Threshold value to control the inverse filtering decision.*/ + INVF_MODE inverseFilteringLevel) /*!< Inverse filtering level of the current band.*/ +{ + INT scale, l, k; + FIXP_DBL meanOrig=FL2FXCONST_DBL(0.0f), meanSbr=FL2FXCONST_DBL(0.0f), diff; + FIXP_DBL invIndex = GetInvInt(stopIndex-startIndex); + FIXP_DBL invChannel = GetInvInt(stopChannel-startChannel); + FIXP_DBL accu; + + /* + Calculate the mean value, over the current time segment, for the original, the HFR + and the difference, over all channels in the current frequency range. + */ + + if(missingHarmonicFlag == 1){ + for(l = startChannel; l < stopChannel;l++){ + /* tonalityOrig */ + accu = FL2FXCONST_DBL(0.0f); + for(k = startIndex ; k < stopIndex; k++){ + accu += fMultDiv2(quotaMatrixOrig[k][l], invIndex); + } + meanOrig = fixMax(meanOrig,(accu<<1)); + + /* tonalitySbr */ + accu = FL2FXCONST_DBL(0.0f); + for(k = startIndex ; k < stopIndex; k++){ + accu += fMultDiv2(quotaMatrixOrig[k][indexVector[l]], invIndex); + } + meanSbr = fixMax(meanSbr,(accu<<1)); + + } + } + else{ + for(l = startChannel; l < stopChannel;l++){ + /* tonalityOrig */ + accu = FL2FXCONST_DBL(0.0f); + for(k = startIndex ; k < stopIndex; k++){ + accu += fMultDiv2(quotaMatrixOrig[k][l], invIndex); + } + meanOrig += fMult((accu<<1), invChannel); + + /* tonalitySbr */ + accu = FL2FXCONST_DBL(0.0f); + for(k = startIndex ; k < stopIndex; k++){ + accu += fMultDiv2(quotaMatrixOrig[k][indexVector[l]], invIndex); + } + meanSbr += fMult((accu<<1), invChannel); + } + } + + /* Small fix to avoid noise during silent passages.*/ + if( meanOrig <= FL2FXCONST_DBL(0.000976562f*RELAXATION_FLOAT) && + meanSbr <= FL2FXCONST_DBL(0.000976562f*RELAXATION_FLOAT) ) + { + meanOrig = FL2FXCONST_DBL(101.5936673f*RELAXATION_FLOAT); + meanSbr = FL2FXCONST_DBL(101.5936673f*RELAXATION_FLOAT); + } + + meanOrig = fixMax(meanOrig,RELAXATION); + meanSbr = fixMax(meanSbr,RELAXATION); + + if (missingHarmonicFlag == 1 || + inverseFilteringLevel == INVF_MID_LEVEL || + inverseFilteringLevel == INVF_LOW_LEVEL || + inverseFilteringLevel == INVF_OFF || + inverseFilteringLevel <= diffThres) + { + diff = RELAXATION; + } + else { + accu = fDivNorm(meanSbr, meanOrig, &scale); + + diff = fixMax( RELAXATION, + fMult(RELAXATION_FRACT,fMult(weightFac,accu)) >>( RELAXATION_SHIFT-scale ) ) ; + } + + /* + * noise Level is now a positive value, i.e. + * the more harmonic the signal is the higher noise level, + * this makes no sense so we change the sign. + *********************************************************/ + accu = fDivNorm(diff, meanOrig, &scale); + scale -= 2; + + if ( (scale>0) && (accu > ((FIXP_DBL)MAXVAL_DBL)>>scale) ) { + *noiseLevel = (FIXP_DBL)MAXVAL_DBL; + } + else { + *noiseLevel = scaleValue(accu, scale); + } + + /* + * Add a noise floor offset to compensate for bias in the detector + *****************************************************************/ + if(!missingHarmonicFlag) + *noiseLevel = fMult(*noiseLevel, noiseFloorOffset)<<(NOISE_FLOOR_OFFSET_SCALING); + + /* + * check to see that we don't exceed the maximum allowed level + **************************************************************/ + *noiseLevel = fixMin(*noiseLevel, ana_max_level); /* ana_max_level is scaled with factor 0.25 */ +} + +/**************************************************************************/ +/*! + \brief Does the noise floor level estiamtion. + The function calls the Noisefloor estimation function + for the time segments decided based upon the transient + information. The block is always divided into one or two segments. + + + \return none + +*/ +/**************************************************************************/ +void +FDKsbrEnc_sbrNoiseFloorEstimateQmf(HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + const SBR_FRAME_INFO *frame_info, /*!< Time frequency grid of the current frame. */ + FIXP_DBL *noiseLevels, /*!< Pointer to vector to store the noise levels in.*/ + FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the quota values of the original. */ + SCHAR *indexVector, /*!< Index vector to obtain the patched data. */ + INT missingHarmonicsFlag, /*!< Flag indicating if a strong tonal component will be missing. */ + INT startIndex, /*!< Start index. */ + int numberOfEstimatesPerFrame, /*!< The number of tonality estimates per frame. */ + int transientFrame, /*!< A flag indicating if a transient is present. */ + INVF_MODE* pInvFiltLevels, /*!< Pointer to the vector holding the inverse filtering levels. */ + UINT sbrSyntaxFlags + ) + +{ + + INT nNoiseEnvelopes, startPos[2], stopPos[2], env, band; + + INT noNoiseBands = h_sbrNoiseFloorEstimate->noNoiseBands; + INT *freqBandTable = h_sbrNoiseFloorEstimate->freqBandTableQmf; + + nNoiseEnvelopes = frame_info->nNoiseEnvelopes; + + if (sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + nNoiseEnvelopes = 1; + startPos[0] = startIndex; + stopPos[0] = startIndex + min(numberOfEstimatesPerFrame,2); + } else + if(nNoiseEnvelopes == 1){ + startPos[0] = startIndex; + stopPos[0] = startIndex + 2; + } + else{ + startPos[0] = startIndex; + stopPos[0] = startIndex + 1; + startPos[1] = startIndex + 1; + stopPos[1] = startIndex + 2; + } + + /* + * Estimate the noise floor. + **************************************/ + for(env = 0; env < nNoiseEnvelopes; env++){ + for(band = 0; band < noNoiseBands; band++){ + FDK_ASSERT( (band + env*noNoiseBands) < MAX_NUM_NOISE_VALUES); + qmfBasedNoiseFloorDetection(&noiseLevels[band + env*noNoiseBands], + quotaMatrixOrig, + indexVector, + startPos[env], + stopPos[env], + freqBandTable[band], + freqBandTable[band+1], + h_sbrNoiseFloorEstimate->ana_max_level, + h_sbrNoiseFloorEstimate->noiseFloorOffset[band], + missingHarmonicsFlag, + h_sbrNoiseFloorEstimate->weightFac, + h_sbrNoiseFloorEstimate->diffThres, + pInvFiltLevels[band]); + } + } + + + /* + * Smoothing of the values. + **************************/ + smoothingOfNoiseLevels(noiseLevels, + nNoiseEnvelopes, + h_sbrNoiseFloorEstimate->noNoiseBands, + h_sbrNoiseFloorEstimate->prevNoiseLevels, + h_sbrNoiseFloorEstimate->smoothFilter, + transientFrame); + + + /* quantisation*/ + for(env = 0; env < nNoiseEnvelopes; env++){ + for(band = 0; band < noNoiseBands; band++){ + FDK_ASSERT( (band + env*noNoiseBands) < MAX_NUM_NOISE_VALUES); + noiseLevels[band + env*noNoiseBands] = + (FIXP_DBL)NOISE_FLOOR_OFFSET_64 - (FIXP_DBL)CalcLdData(noiseLevels[band + env*noNoiseBands]+(FIXP_DBL)1) + QuantOffset; + } + } +} + +/**************************************************************************/ +/*! + \brief + + + \return errorCode, noError if successful + +*/ +/**************************************************************************/ +static INT +downSampleLoRes(INT *v_result, /*!< */ + INT num_result, /*!< */ + const UCHAR *freqBandTableRef,/*!< */ + INT num_Ref) /*!< */ +{ + INT step; + INT i,j; + INT org_length,result_length; + INT v_index[MAX_FREQ_COEFFS/2]; + + /* init */ + org_length=num_Ref; + result_length=num_result; + + v_index[0]=0; /* Always use left border */ + i=0; + while(org_length > 0) /* Create downsample vector */ + { + i++; + step=org_length/result_length; /* floor; */ + org_length=org_length - step; + result_length--; + v_index[i]=v_index[i-1]+step; + } + + if(i != num_result ) /* Should never happen */ + return (1);/* error downsampling */ + + for(j=0;j<=i;j++) /* Use downsample vector to index LoResolution vector. */ + { + v_result[j]=freqBandTableRef[v_index[j]]; + } + + return (0); +} + +/**************************************************************************/ +/*! + \brief Initialize an instance of the noise floor level estimation module. + + + \return errorCode, noError if successful + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_InitSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + const UCHAR *freqBandTable, /*!< Frequany band table. */ + INT nSfb, /*!< Number of frequency bands. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + INT timeSlots, /*!< Number of time slots in a frame. */ + UINT useSpeechConfig /*!< Flag: adapt tuning parameters according to speech */ + ) +{ + INT i, qexp, qtmp; + FIXP_DBL tmp, exp; + + FDKmemclear(h_sbrNoiseFloorEstimate,sizeof(SBR_NOISE_FLOOR_ESTIMATE)); + + h_sbrNoiseFloorEstimate->smoothFilter = smoothFilter; + if (useSpeechConfig) { + h_sbrNoiseFloorEstimate->weightFac = (FIXP_DBL)MAXVAL_DBL; + h_sbrNoiseFloorEstimate->diffThres = INVF_LOW_LEVEL; + } + else { + h_sbrNoiseFloorEstimate->weightFac = FL2FXCONST_DBL(0.25f); + h_sbrNoiseFloorEstimate->diffThres = INVF_MID_LEVEL; + } + + h_sbrNoiseFloorEstimate->timeSlots = timeSlots; + h_sbrNoiseFloorEstimate->noiseBands = noiseBands; + + /* h_sbrNoiseFloorEstimate->ana_max_level is scaled by 0.25 */ + switch(ana_max_level) + { + case 6: + h_sbrNoiseFloorEstimate->ana_max_level = (FIXP_DBL)MAXVAL_DBL; + break; + case 3: + h_sbrNoiseFloorEstimate->ana_max_level = FL2FXCONST_DBL(0.5); + break; + case -3: + h_sbrNoiseFloorEstimate->ana_max_level = FL2FXCONST_DBL(0.125); + break; + default: + /* Should not enter here */ + h_sbrNoiseFloorEstimate->ana_max_level = (FIXP_DBL)MAXVAL_DBL; + break; + } + + /* + calculate number of noise bands and allocate + */ + if(FDKsbrEnc_resetSbrNoiseFloorEstimate(h_sbrNoiseFloorEstimate,freqBandTable,nSfb)) + return(1); + + if(noiseFloorOffset == 0) { + tmp = ((FIXP_DBL)MAXVAL_DBL)>>NOISE_FLOOR_OFFSET_SCALING; + } + else { + FDK_ASSERT(noiseFloorOffset<=8); /* because of NOISE_FLOOR_OFFSET_SCALING */ + + /* Assumes the noise floor offset in tuning table are in q31 */ + /* Currently the table contains only 0 for noise floor offset */ + /* Change the qformat here when non-zero values would be filled */ + exp = fDivNorm((FIXP_DBL)noiseFloorOffset, 3, &qexp); + tmp = fPow(2, DFRACT_BITS-1, exp, qexp, &qtmp); + tmp = scaleValue(tmp, qtmp-NOISE_FLOOR_OFFSET_SCALING); + } + + for(i=0;i<h_sbrNoiseFloorEstimate->noNoiseBands;i++) { + h_sbrNoiseFloorEstimate->noiseFloorOffset[i] = tmp; + } + + return (0); +} + +/**************************************************************************/ +/*! + \brief Resets the current instance of the noise floor estiamtion + module. + + + \return errorCode, noError if successful + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_resetSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + const UCHAR *freqBandTable, /*!< Frequany band table. */ + INT nSfb) /*!< Number of bands in the frequency band table. */ +{ + INT k2,kx; + + /* + * Calculate number of noise bands + ***********************************/ + k2=freqBandTable[nSfb]; + kx=freqBandTable[0]; + if(h_sbrNoiseFloorEstimate->noiseBands == 0){ + h_sbrNoiseFloorEstimate->noNoiseBands = 1; + } + else{ + /* + * Calculate number of noise bands 1,2 or 3 bands/octave + ********************************************************/ + FIXP_DBL tmp, ratio, lg2; + INT ratio_e, qlg2; + + ratio = fDivNorm(k2, kx, &ratio_e); + lg2 = fLog2(ratio, ratio_e, &qlg2); + tmp = fMult((FIXP_DBL)(h_sbrNoiseFloorEstimate->noiseBands<<24), lg2); + tmp = scaleValue(tmp, qlg2-23); + + h_sbrNoiseFloorEstimate->noNoiseBands = (INT)((tmp + (FIXP_DBL)1) >> 1); + + if (h_sbrNoiseFloorEstimate->noNoiseBands > MAX_NUM_NOISE_COEFFS) + h_sbrNoiseFloorEstimate->noNoiseBands = MAX_NUM_NOISE_COEFFS; + + if( h_sbrNoiseFloorEstimate->noNoiseBands==0) + h_sbrNoiseFloorEstimate->noNoiseBands=1; + } + + + return(downSampleLoRes(h_sbrNoiseFloorEstimate->freqBandTableQmf, + h_sbrNoiseFloorEstimate->noNoiseBands, + freqBandTable,nSfb)); +} + +/**************************************************************************/ +/*! + \brief Deletes the current instancce of the noise floor level + estimation module. + + + \return none + +*/ +/**************************************************************************/ +void +FDKsbrEnc_deleteSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate) /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ +{ + + if (h_sbrNoiseFloorEstimate) { + /* + nothing to do + */ + } +} diff --git a/libSBRenc/src/nf_est.h b/libSBRenc/src/nf_est.h new file mode 100644 index 0000000..ba9fb86 --- /dev/null +++ b/libSBRenc/src/nf_est.h @@ -0,0 +1,89 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +****************************************************************************/ +/*! + \file + \brief Noise floor estimation structs and prototypes $Revision: 36867 $ +*/ + +#ifndef __NF_EST_H +#define __NF_EST_H + +#include "sbr_encoder.h" +#include "fram_gen.h" + +#define NF_SMOOTHING_LENGTH 4 /*!< Smoothing length of the noise floors. */ + +typedef struct +{ + FIXP_DBL prevNoiseLevels[NF_SMOOTHING_LENGTH][MAX_NUM_NOISE_VALUES]; /*!< The previous noise levels. */ + FIXP_DBL noiseFloorOffset[MAX_NUM_NOISE_VALUES]; /*!< Noise floor offset, scaled with NOISE_FLOOR_OFFSET_SCALING */ + const FIXP_DBL *smoothFilter; /*!< Smoothing filter to use. */ + FIXP_DBL ana_max_level; /*!< Max level allowed. */ + FIXP_DBL weightFac; /*!< Weightening factor for the difference between orig and sbr. */ + INT freqBandTableQmf[MAX_NUM_NOISE_VALUES + 1]; /*!< Frequncy band table for the noise floor bands.*/ + INT noNoiseBands; /*!< Number of noisebands. */ + INT noiseBands; /*!< NoiseBands switch 4 bit.*/ + INT timeSlots; /*!< Number of timeslots in a frame. */ + INVF_MODE diffThres; /*!< Threshold value to control the inverse filtering decision */ +} +SBR_NOISE_FLOOR_ESTIMATE; + +typedef SBR_NOISE_FLOOR_ESTIMATE *HANDLE_SBR_NOISE_FLOOR_ESTIMATE; + +void +FDKsbrEnc_sbrNoiseFloorEstimateQmf(HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + const SBR_FRAME_INFO *frame_info, /*!< Time frequency grid of the current frame. */ + FIXP_DBL *noiseLevels, /*!< Pointer to vector to store the noise levels in.*/ + FIXP_DBL **quotaMatrixOrig, /*!< Matrix holding the quota values of the original. */ + SCHAR* indexVector, /*!< Index vector to obtain the patched data. */ + INT missingHarmonicsFlag, /*!< Flag indicating if a strong tonal component will be missing. */ + INT startIndex, /*!< Start index. */ + int numberOfEstimatesPerFrame, /*!< The number of tonality estimates per frame. */ + INT transientFrame, /*!< A flag indicating if a transient is present. */ + INVF_MODE* pInvFiltLevels, /*!< Pointer to the vector holding the inverse filtering levels. */ + UINT sbrSyntaxFlags + ); + +INT +FDKsbrEnc_InitSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + const UCHAR *freqBandTable, /*!< Frequany band table. */ + INT nSfb, /*!< Number of frequency bands. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + INT timeSlots, /*!< Number of time slots in a frame. */ + UINT useSpeechConfig /*!< Flag: adapt tuning parameters according to speech */ + ); + +INT +FDKsbrEnc_resetSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate, /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + const UCHAR *freqBandTable, /*!< Frequany band table. */ + INT nSfb); /*!< Number of bands in the frequency band table. */ + +void +FDKsbrEnc_deleteSbrNoiseFloorEstimate (HANDLE_SBR_NOISE_FLOOR_ESTIMATE h_sbrNoiseFloorEstimate); /*!< Handle to SBR_NOISE_FLOOR_ESTIMATE struct */ + +#endif diff --git a/libSBRenc/src/ps_bitenc.cpp b/libSBRenc/src/ps_bitenc.cpp new file mode 100644 index 0000000..960229b --- /dev/null +++ b/libSBRenc/src/ps_bitenc.cpp @@ -0,0 +1,635 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: N. Rettelbach + contents/description: Parametric Stereo bitstream encoder + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "ps_main.h" + + +#include "ps_const.h" +#include "ps_bitenc.h" + +static +inline UCHAR FDKsbrEnc_WriteBits_ps(HANDLE_FDK_BITSTREAM hBitStream, UINT value, + const UINT numberOfBits) +{ + /* hBitStream == NULL happens here intentionally */ + if(hBitStream!=NULL){ + FDKwriteBits(hBitStream, value, numberOfBits); + } + return numberOfBits; +} + +#define SI_SBR_EXTENSION_SIZE_BITS 4 +#define SI_SBR_EXTENSION_ESC_COUNT_BITS 8 +#define SI_SBR_EXTENSION_ID_BITS 2 +#define EXTENSION_ID_PS_CODING 2 +#define PS_EXT_ID_V0 0 + +static const INT iidDeltaCoarse_Offset = 14; +static const INT iidDeltaCoarse_MaxVal = 28; +static const INT iidDeltaFine_Offset = 30; +static const INT iidDeltaFine_MaxVal = 60; + +/* PS Stereo Huffmantable: iidDeltaFreqCoarse */ +static const UINT iidDeltaFreqCoarse_Length[] = +{ + 17, 17, 17, 17, 16, 15, 13, 10, 9, 7, + 6, 5, 4, 3, 1, 3, 4, 5, 6, 6, + 8, 11, 13, 14, 14, 15, 17, 18, 18 +}; +static const UINT iidDeltaFreqCoarse_Code[] = +{ + 0x0001fffb, 0x0001fffc, 0x0001fffd, 0x0001fffa, 0x0000fffc, 0x00007ffc, 0x00001ffd, 0x000003fe, 0x000001fe, 0x0000007e, + 0x0000003c, 0x0000001d, 0x0000000d, 0x00000005, 0000000000, 0x00000004, 0x0000000c, 0x0000001c, 0x0000003d, 0x0000003e, + 0x000000fe, 0x000007fe, 0x00001ffc, 0x00003ffc, 0x00003ffd, 0x00007ffd, 0x0001fffe, 0x0003fffe, 0x0003ffff +}; + +/* PS Stereo Huffmantable: iidDeltaFreqFine */ +static const UINT iidDeltaFreqFine_Length[] = +{ + 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, + 18, 17, 17, 16, 16, 15, 14, 14, 13, 12, + 12, 11, 10, 10, 8, 7, 6, 5, 4, 3, + 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 11, 12, 13, 14, 14, 15, 16, 16, 17, 17, + 18, 17, 18, 18, 18, 18, 18, 18, 18, 18, + 18 +}; +static const UINT iidDeltaFreqFine_Code[] = +{ + 0x0001feb4, 0x0001feb5, 0x0001fd76, 0x0001fd77, 0x0001fd74, 0x0001fd75, 0x0001fe8a, 0x0001fe8b, 0x0001fe88, 0x0000fe80, + 0x0001feb6, 0x0000fe82, 0x0000feb8, 0x00007f42, 0x00007fae, 0x00003faf, 0x00001fd1, 0x00001fe9, 0x00000fe9, 0x000007ea, + 0x000007fb, 0x000003fb, 0x000001fb, 0x000001ff, 0x0000007c, 0x0000003c, 0x0000001c, 0x0000000c, 0000000000, 0x00000001, + 0x00000001, 0x00000002, 0x00000001, 0x0000000d, 0x0000001d, 0x0000003d, 0x0000007d, 0x000000fc, 0x000001fc, 0x000003fc, + 0x000003f4, 0x000007eb, 0x00000fea, 0x00001fea, 0x00001fd6, 0x00003fd0, 0x00007faf, 0x00007f43, 0x0000feb9, 0x0000fe83, + 0x0001feb7, 0x0000fe81, 0x0001fe89, 0x0001fe8e, 0x0001fe8f, 0x0001fe8c, 0x0001fe8d, 0x0001feb2, 0x0001feb3, 0x0001feb0, + 0x0001feb1 +}; + +/* PS Stereo Huffmantable: iidDeltaTimeCoarse */ +static const UINT iidDeltaTimeCoarse_Length[] = +{ + 19, 19, 19, 20, 20, 20, 17, 15, 12, 10, + 8, 6, 4, 2, 1, 3, 5, 7, 9, 11, + 13, 14, 17, 19, 20, 20, 20, 20, 20 +}; +static const UINT iidDeltaTimeCoarse_Code[] = +{ + 0x0007fff9, 0x0007fffa, 0x0007fffb, 0x000ffff8, 0x000ffff9, 0x000ffffa, 0x0001fffd, 0x00007ffe, 0x00000ffe, 0x000003fe, + 0x000000fe, 0x0000003e, 0x0000000e, 0x00000002, 0000000000, 0x00000006, 0x0000001e, 0x0000007e, 0x000001fe, 0x000007fe, + 0x00001ffe, 0x00003ffe, 0x0001fffc, 0x0007fff8, 0x000ffffb, 0x000ffffc, 0x000ffffd, 0x000ffffe, 0x000fffff +}; + +/* PS Stereo Huffmantable: iidDeltaTimeFine */ +static const UINT iidDeltaTimeFine_Length[] = +{ + 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, + 15, 15, 15, 15, 15, 14, 14, 13, 13, 13, + 12, 12, 11, 10, 9, 9, 7, 6, 5, 3, + 1, 2, 5, 6, 7, 8, 9, 10, 11, 11, + 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16 +}; +static const UINT iidDeltaTimeFine_Code[] = +{ + 0x00004ed4, 0x00004ed5, 0x00004ece, 0x00004ecf, 0x00004ecc, 0x00004ed6, 0x00004ed8, 0x00004f46, 0x00004f60, 0x00002718, + 0x00002719, 0x00002764, 0x00002765, 0x0000276d, 0x000027b1, 0x000013b7, 0x000013d6, 0x000009c7, 0x000009e9, 0x000009ed, + 0x000004ee, 0x000004f7, 0x00000278, 0x00000139, 0x0000009a, 0x0000009f, 0x00000020, 0x00000011, 0x0000000a, 0x00000003, + 0x00000001, 0000000000, 0x0000000b, 0x00000012, 0x00000021, 0x0000004c, 0x0000009b, 0x0000013a, 0x00000279, 0x00000270, + 0x000004ef, 0x000004e2, 0x000009ea, 0x000009d8, 0x000013d7, 0x000013d0, 0x000027b2, 0x000027a2, 0x0000271a, 0x0000271b, + 0x00004f66, 0x00004f67, 0x00004f61, 0x00004f47, 0x00004ed9, 0x00004ed7, 0x00004ecd, 0x00004ed2, 0x00004ed3, 0x00004ed0, + 0x00004ed1 +}; + +static const INT iccDelta_Offset = 7; +static const INT iccDelta_MaxVal = 14; +/* PS Stereo Huffmantable: iccDeltaFreq */ +static const UINT iccDeltaFreq_Length[] = +{ + 14, 14, 12, 10, 7, 5, 3, 1, 2, 4, + 6, 8, 9, 11, 13 +}; +static const UINT iccDeltaFreq_Code[] = +{ + 0x00003fff, 0x00003ffe, 0x00000ffe, 0x000003fe, 0x0000007e, 0x0000001e, 0x00000006, 0000000000, 0x00000002, 0x0000000e, + 0x0000003e, 0x000000fe, 0x000001fe, 0x000007fe, 0x00001ffe +}; + +/* PS Stereo Huffmantable: iccDeltaTime */ +static const UINT iccDeltaTime_Length[] = +{ + 14, 13, 11, 9, 7, 5, 3, 1, 2, 4, + 6, 8, 10, 12, 14 +}; +static const UINT iccDeltaTime_Code[] = +{ + 0x00003ffe, 0x00001ffe, 0x000007fe, 0x000001fe, 0x0000007e, 0x0000001e, 0x00000006, 0000000000, 0x00000002, 0x0000000e, + 0x0000003e, 0x000000fe, 0x000003fe, 0x00000ffe, 0x00003fff +}; + + + +static const INT ipdDelta_Offset = 0; +static const INT ipdDelta_MaxVal = 7; +/* PS Stereo Huffmantable: ipdDeltaFreq */ +static const UINT ipdDeltaFreq_Length[] = +{ + 1, 3, 4, 4, 4, 4, 4, 4 +}; +static const UINT ipdDeltaFreq_Code[] = +{ + 0x00000001, 0000000000, 0x00000006, 0x00000004, 0x00000002, 0x00000003, 0x00000005, 0x00000007 +}; + +/* PS Stereo Huffmantable: ipdDeltaTime */ +static const UINT ipdDeltaTime_Length[] = +{ + 1, 3, 4, 5, 5, 4, 4, 3 +}; +static const UINT ipdDeltaTime_Code[] = +{ + 0x00000001, 0x00000002, 0x00000002, 0x00000003, 0x00000002, 0000000000, 0x00000003, 0x00000003 +}; + + +static const INT opdDelta_Offset = 0; +static const INT opdDelta_MaxVal = 7; +/* PS Stereo Huffmantable: opdDeltaFreq */ +static const UINT opdDeltaFreq_Length[] = +{ + 1, 3, 4, 4, 5, 5, 4, 3 +}; +static const UINT opdDeltaFreq_Code[] = +{ + 0x00000001, 0x00000001, 0x00000006, 0x00000004, 0x0000000f, 0x0000000e, 0x00000005, 0000000000, +}; + +/* PS Stereo Huffmantable: opdDeltaTime */ +static const UINT opdDeltaTime_Length[] = +{ + 1, 3, 4, 5, 5, 4, 4, 3 +}; +static const UINT opdDeltaTime_Code[] = +{ + 0x00000001, 0x00000002, 0x00000001, 0x00000007, 0x00000006, 0000000000, 0x00000002, 0x00000003 +}; + +static const INT psBands[] = +{ + PS_BANDS_COARSE, + PS_BANDS_MID, + PS_BANDS_FINE +}; + +static INT getNoBands(PS_RESOLUTION mode) +{ + if(mode>=6) + return 0; + + if(mode>=3) + mode = (PS_RESOLUTION)(mode-3); + + return psBands[mode]; +} + +static INT getIIDRes(INT iidMode) +{ + if(iidMode<3) + return PS_IID_RES_COARSE; + else + return PS_IID_RES_FINE; +} + +static INT +encodeDeltaFreq(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *val, + const INT nBands, + const UINT *codeTable, + const UINT *lengthTable, + const INT tableOffset, + const INT maxVal, + INT *error) +{ + INT bitCnt = 0; + INT lastVal = 0; + INT band; + + for(band=0;band<nBands;band++) { + INT delta = (val[band] - lastVal) + tableOffset; + lastVal = val[band]; + if( (delta>maxVal) || (delta<0) ) { + *error = 1; + delta = delta>0?maxVal:0; + } + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, codeTable[delta], lengthTable[delta]); + } + + return bitCnt; +} + +static INT +encodeDeltaTime(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *val, + const INT *valLast, + const INT nBands, + const UINT *codeTable, + const UINT *lengthTable, + const INT tableOffset, + const INT maxVal, + INT *error) +{ + INT bitCnt = 0; + INT band; + + for(band=0;band<nBands;band++) { + INT delta = (val[band] - valLast[band]) + tableOffset; + if( (delta>maxVal) || (delta<0) ) { + *error = 1; + delta = delta>0?maxVal:0; + } + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, codeTable[delta], lengthTable[delta]); + } + + return bitCnt; +} + +INT FDKsbrEnc_EncodeIid(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *iidVal, + const INT *iidValLast, + const INT nBands, + const PS_IID_RESOLUTION res, + const PS_DELTA mode, + INT *error) +{ + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + bitCnt = 0; + + switch(mode) { + case PS_DELTA_FREQ: + switch(res) { + case PS_IID_RES_COARSE: + codeTable = iidDeltaFreqCoarse_Code; + lengthTable = iidDeltaFreqCoarse_Length; + bitCnt += encodeDeltaFreq(hBitBuf, iidVal, nBands, codeTable, + lengthTable, iidDeltaCoarse_Offset, + iidDeltaCoarse_MaxVal, error); + break; + case PS_IID_RES_FINE: + codeTable = iidDeltaFreqFine_Code; + lengthTable = iidDeltaFreqFine_Length; + bitCnt += encodeDeltaFreq(hBitBuf, iidVal, nBands, codeTable, + lengthTable, iidDeltaFine_Offset, + iidDeltaFine_MaxVal, error); + break; + default: + *error = 1; + } + break; + + case PS_DELTA_TIME: + switch(res) { + case PS_IID_RES_COARSE: + codeTable = iidDeltaTimeCoarse_Code; + lengthTable = iidDeltaTimeCoarse_Length; + bitCnt += encodeDeltaTime(hBitBuf, iidVal, iidValLast, nBands, codeTable, + lengthTable, iidDeltaCoarse_Offset, + iidDeltaCoarse_MaxVal, error); + break; + case PS_IID_RES_FINE: + codeTable = iidDeltaTimeFine_Code; + lengthTable = iidDeltaTimeFine_Length; + bitCnt += encodeDeltaTime(hBitBuf, iidVal, iidValLast, nBands, codeTable, + lengthTable, iidDeltaFine_Offset, + iidDeltaFine_MaxVal, error); + break; + default: + *error = 1; + } + break; + + default: + *error = 1; + } + + return bitCnt; +} + + +INT FDKsbrEnc_EncodeIcc(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *iccVal, + const INT *iccValLast, + const INT nBands, + const PS_DELTA mode, + INT *error) +{ + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + switch(mode) { + case PS_DELTA_FREQ: + codeTable = iccDeltaFreq_Code; + lengthTable = iccDeltaFreq_Length; + bitCnt += encodeDeltaFreq(hBitBuf, iccVal, nBands, codeTable, + lengthTable, iccDelta_Offset, iccDelta_MaxVal, error); + break; + + case PS_DELTA_TIME: + codeTable = iccDeltaTime_Code; + lengthTable = iccDeltaTime_Length; + + bitCnt += encodeDeltaTime(hBitBuf, iccVal, iccValLast, nBands, codeTable, + lengthTable, iccDelta_Offset, iccDelta_MaxVal, error); + break; + + default: + *error = 1; + } + + return bitCnt; +} + +INT FDKsbrEnc_EncodeIpd(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *ipdVal, + const INT *ipdValLast, + const INT nBands, + const PS_DELTA mode, + INT *error) +{ + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + switch(mode) { + case PS_DELTA_FREQ: + codeTable = ipdDeltaFreq_Code; + lengthTable = ipdDeltaFreq_Length; + bitCnt += encodeDeltaFreq(hBitBuf, ipdVal, nBands, codeTable, + lengthTable, ipdDelta_Offset, ipdDelta_MaxVal, error); + break; + + case PS_DELTA_TIME: + codeTable = ipdDeltaTime_Code; + lengthTable = ipdDeltaTime_Length; + + bitCnt += encodeDeltaTime(hBitBuf, ipdVal, ipdValLast, nBands, codeTable, + lengthTable, ipdDelta_Offset, ipdDelta_MaxVal, error); + break; + + default: + *error = 1; + } + + return bitCnt; +} + +INT FDKsbrEnc_EncodeOpd(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *opdVal, + const INT *opdValLast, + const INT nBands, + const PS_DELTA mode, + INT *error) +{ + const UINT *codeTable; + const UINT *lengthTable; + INT bitCnt = 0; + + switch(mode) { + case PS_DELTA_FREQ: + codeTable = opdDeltaFreq_Code; + lengthTable = opdDeltaFreq_Length; + bitCnt += encodeDeltaFreq(hBitBuf, opdVal, nBands, codeTable, + lengthTable, opdDelta_Offset, opdDelta_MaxVal, error); + break; + + case PS_DELTA_TIME: + codeTable = opdDeltaTime_Code; + lengthTable = opdDeltaTime_Length; + + bitCnt += encodeDeltaTime(hBitBuf, opdVal, opdValLast, nBands, codeTable, + lengthTable, opdDelta_Offset, opdDelta_MaxVal, error); + break; + + default: + *error = 1; + } + + return bitCnt; +} + +static INT encodeIpdOpd(HANDLE_PS_OUT psOut, + HANDLE_FDK_BITSTREAM hBitBuf ) +{ + INT bitCnt = 0; + INT error = 0; + INT env; + + FDKsbrEnc_WriteBits_ps(hBitBuf, psOut->enableIpdOpd, 1); + + if(psOut->enableIpdOpd==1) { + INT *ipdLast = psOut->ipdLast; + INT *opdLast = psOut->opdLast; + + for(env=0; env<psOut->nEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->deltaIPD[env], 1); + bitCnt += FDKsbrEnc_EncodeIpd( hBitBuf, + psOut->ipd[env], + ipdLast, + getNoBands((PS_RESOLUTION)psOut->iidMode), + psOut->deltaIPD[env], + &error); + + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->deltaOPD[env], 1); + bitCnt += FDKsbrEnc_EncodeOpd( hBitBuf, + psOut->opd[env], + opdLast, + getNoBands((PS_RESOLUTION)psOut->iidMode), + psOut->deltaOPD[env], + &error ); + } + /* reserved bit */ + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, 0, 1); + } + + + return bitCnt; +} + +static INT getEnvIdx(const INT nEnvelopes, const INT frameClass) +{ + INT envIdx = 0; + + switch(nEnvelopes) { + case 0: + envIdx = 0; + break; + + case 1: + if (frameClass==0) + envIdx = 1; + else + envIdx = 0; + break; + + case 2: + if (frameClass==0) + envIdx = 2; + else + envIdx = 1; + break; + + case 3: + envIdx = 2; + break; + + case 4: + envIdx = 3; + break; + + default: + /* unsupported number of envelopes */ + envIdx = 0; + } + + return envIdx; +} + + +static INT encodePSExtension(const HANDLE_PS_OUT psOut, + HANDLE_FDK_BITSTREAM hBitBuf ) +{ + INT bitCnt = 0; + + if(psOut->enableIpdOpd==1) { + INT ipdOpdBits = 0; + INT extSize = (2 + encodeIpdOpd(psOut,NULL)+7)>>3; + + if(extSize<15) { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, extSize, 4); + } + else { + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, 15 , 4); + bitCnt += FDKsbrEnc_WriteBits_ps(hBitBuf, (extSize-15), 8); + } + + /* write ipd opd data */ + ipdOpdBits += FDKsbrEnc_WriteBits_ps(hBitBuf, PS_EXT_ID_V0, 2); + ipdOpdBits += encodeIpdOpd(psOut, hBitBuf ); + + /* byte align the ipd opd data */ + if(ipdOpdBits%8) + ipdOpdBits += FDKsbrEnc_WriteBits_ps(hBitBuf, 0, (8-(ipdOpdBits%8)) ); + + bitCnt += ipdOpdBits; + } + + return (bitCnt); +} + +INT FDKsbrEnc_WritePSBitstream(const HANDLE_PS_OUT psOut, + HANDLE_FDK_BITSTREAM hBitBuf ) +{ + INT psExtEnable = 0; + INT bitCnt = 0; + INT error = 0; + INT env; + + if(psOut != NULL){ + + /* PS HEADER */ + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->enablePSHeader, 1); + + if(psOut->enablePSHeader) { + + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->enableIID, 1); + if(psOut->enableIID) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->iidMode, 3); + } + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->enableICC, 1); + if(psOut->enableICC) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->iccMode, 3); + } + if(psOut->enableIpdOpd) { + psExtEnable = 1; + } + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psExtEnable, 1); + } + + /* Frame class, number of envelopes */ + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->frameClass, 1); + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, getEnvIdx(psOut->nEnvelopes, psOut->frameClass), 2); + + if(psOut->frameClass==1) { + for(env=0; env<psOut->nEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->frameBorder[env], 5); + } + } + + if(psOut->enableIID==1) { + INT *iidLast = psOut->iidLast; + for(env=0; env<psOut->nEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->deltaIID[env], 1); + bitCnt += FDKsbrEnc_EncodeIid( hBitBuf, + psOut->iid[env], + iidLast, + getNoBands((PS_RESOLUTION)psOut->iidMode), + (PS_IID_RESOLUTION)getIIDRes(psOut->iidMode), + psOut->deltaIID[env], + &error ); + + iidLast = psOut->iid[env]; + } + } + + if(psOut->enableICC==1) { + INT *iccLast = psOut->iccLast; + for(env=0; env<psOut->nEnvelopes; env++) { + bitCnt += FDKsbrEnc_WriteBits_ps( hBitBuf, psOut->deltaICC[env], 1); + bitCnt += FDKsbrEnc_EncodeIcc( hBitBuf, + psOut->icc[env], + iccLast, + getNoBands((PS_RESOLUTION)psOut->iccMode), + psOut->deltaICC[env], + &error); + + iccLast = psOut->icc[env]; + } + } + + if(psExtEnable!=0) { + bitCnt += encodePSExtension(psOut, hBitBuf); + } + + } /* if(psOut != NULL) */ + + return bitCnt; +} + diff --git a/libSBRenc/src/ps_bitenc.h b/libSBRenc/src/ps_bitenc.h new file mode 100644 index 0000000..f91eb57 --- /dev/null +++ b/libSBRenc/src/ps_bitenc.h @@ -0,0 +1,115 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: N. Rettelbach + contents/description: Parametric Stereo bitstream encoder + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "ps_main.h" +#include "ps_const.h" +#include "FDK_bitstream.h" + +#ifndef PS_BITENC_H +#define PS_BITENC_H + +typedef struct T_PS_OUT { + + INT enablePSHeader; + INT enableIID; + INT iidMode; + INT enableICC; + INT iccMode; + INT enableIpdOpd; + + INT frameClass; + INT nEnvelopes; + /* ENV data */ + INT frameBorder[PS_MAX_ENVELOPES]; + + /* iid data */ + PS_DELTA deltaIID[PS_MAX_ENVELOPES]; + INT iid[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iidLast[PS_MAX_BANDS]; + + /* icc data */ + PS_DELTA deltaICC[PS_MAX_ENVELOPES]; + INT icc[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iccLast[PS_MAX_BANDS]; + + /* ipd data */ + PS_DELTA deltaIPD[PS_MAX_ENVELOPES]; + INT ipd[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT ipdLast[PS_MAX_BANDS]; + + /* opd data */ + PS_DELTA deltaOPD[PS_MAX_ENVELOPES]; + INT opd[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT opdLast[PS_MAX_BANDS]; + +} PS_OUT, *HANDLE_PS_OUT; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +INT FDKsbrEnc_EncodeIid(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *iidVal, + const INT *iidValLast, + const INT nBands, + const PS_IID_RESOLUTION res, + const PS_DELTA mode, + INT *error); + +INT FDKsbrEnc_EncodeIcc(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *iccVal, + const INT *iccValLast, + const INT nBands, + const PS_DELTA mode, + INT *error); + +INT FDKsbrEnc_EncodeIpd(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *ipdVal, + const INT *ipdValLast, + const INT nBands, + const PS_DELTA mode, + INT *error); + +INT FDKsbrEnc_EncodeOpd(HANDLE_FDK_BITSTREAM hBitBuf, + const INT *opdVal, + const INT *opdValLast, + const INT nBands, + const PS_DELTA mode, + INT *error); + +INT FDKsbrEnc_WritePSBitstream(const HANDLE_PS_OUT psOut, + HANDLE_FDK_BITSTREAM hBitBuf); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* #ifndef PS_BITENC_H */ diff --git a/libSBRenc/src/ps_const.h b/libSBRenc/src/ps_const.h new file mode 100644 index 0000000..20fcc88 --- /dev/null +++ b/libSBRenc/src/ps_const.h @@ -0,0 +1,65 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: N. Rettelbach + contents/description: Parametric Stereo constants + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#ifndef PS_CONST_H +#define PS_CONST_H + +typedef enum { + PS_RES_COARSE = 0, + PS_RES_MID = 1, + PS_RES_FINE = 2 +} PS_RESOLUTION; + +typedef enum { + PS_BANDS_COARSE = 10, + PS_BANDS_MID = 20, + PS_BANDS_FINE = 34, + PS_MAX_BANDS = PS_BANDS_FINE +} PS_BANDS; + +typedef enum { + PS_IID_RES_COARSE=0, + PS_IID_RES_FINE +} PS_IID_RESOLUTION; + +typedef enum { + PS_ICC_ROT_A=0, + PS_ICC_ROT_B +} PS_ICC_ROTATION_MODE; + +typedef enum { + PS_DELTA_FREQ, + PS_DELTA_TIME +} PS_DELTA; + + +typedef enum { + PS_MAX_ENVELOPES = 4 + +} PS_CONSTS; + +#endif diff --git a/libSBRenc/src/ps_encode.cpp b/libSBRenc/src/ps_encode.cpp new file mode 100644 index 0000000..1f78d66 --- /dev/null +++ b/libSBRenc/src/ps_encode.cpp @@ -0,0 +1,1068 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial Authors: M. Neuendorf, N. Rettelbach, M. Multrus + Contents/Description: PS parameter extraction, encoding + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +/*! + \file + \brief PS parameter extraction, encoding functions $Revision: 36847 $ +*/ + +#include "ps_main.h" + + +#include "sbr_ram.h" +#include "ps_encode.h" + +#include "qmf.h" + +#include "ps_const.h" +#include "sbr_misc.h" + +#include "genericStds.h" + + +inline void FDKsbrEnc_addFIXP_DBL(const FIXP_DBL *X, const FIXP_DBL *Y, FIXP_DBL *Z, INT n) +{ + for (INT i=0; i<n; i++) + Z[i] = (X[i]>>1) + (Y[i]>>1); +} + +#define LOG10_2_10 3.01029995664f /* 10.0f*log10(2.f) */ + +static const INT iidGroupBordersLoRes[QMF_GROUPS_LO_RES + SUBQMF_GROUPS_LO_RES + 1] = +{ + 0, 1, 2, 3, 4, 5, /* 6 subqmf subbands - 0th qmf subband */ + 6, 7, /* 2 subqmf subbands - 1st qmf subband */ + 8, 9, /* 2 subqmf subbands - 2nd qmf subband */ + 10, 11, 12, 13, 14, 15, 16, 18, 21, 25, 30, 42, 71 +}; + +static const UCHAR iidGroupWidthLdLoRes[QMF_GROUPS_LO_RES + SUBQMF_GROUPS_LO_RES] = +{ + 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, + 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 4, 5 +}; + + +static const INT subband2parameter20[QMF_GROUPS_LO_RES + SUBQMF_GROUPS_LO_RES] = +{ + 1, 0, 0, 1, 2, 3, /* 6 subqmf subbands - 0th qmf subband */ + 4, 5, /* 2 subqmf subbands - 1st qmf subband */ + 6, 7, /* 2 subqmf subbands - 2nd qmf subband */ + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 +}; + + + +typedef enum { + MAX_TIME_DIFF_FRAMES = 20, + MAX_PS_NOHEADER_CNT = 10, + MAX_NOENV_CNT = 10, + DO_NOT_USE_THIS_MODE = 0x7FFFFF +} __PS_CONSTANTS; + + + +static const FIXP_DBL iidQuant_fx[15] = { + 0xce000000, 0xdc000000, 0xe4000000, 0xec000000, 0xf2000000, 0xf8000000, 0xfc000000, 0x00000000, + 0x04000000, 0x08000000, 0x0e000000, 0x14000000, 0x1c000000, 0x24000000, 0x32000000 +}; + +static const FIXP_DBL iidQuantFine_fx[31] = { + 0x9c000001, 0xa6000001, 0xb0000001, 0xba000001, 0xc4000000, 0xce000000, 0xd4000000, 0xda000000, + 0xe0000000, 0xe6000000, 0xec000000, 0xf0000000, 0xf4000000, 0xf8000000, 0xfc000000, 0x00000000, + 0x04000000, 0x08000000, 0x0c000000, 0x10000000, 0x14000000, 0x1a000000, 0x20000000, 0x26000000, + 0x2c000000, 0x32000000, 0x3c000000, 0x45ffffff, 0x4fffffff, 0x59ffffff, 0x63ffffff +}; + + + +static const FIXP_DBL iccQuant[8] = { + 0x7fffffff, 0x77ef9d7f, 0x6babc97f, 0x4ceaf27f, 0x2f0ed3c0, 0x00000000, 0xb49ba601, 0x80000000 +}; + + + + +/* + name: static HANDLE_ERROR_INFO CreatePSData() + description: Creates struct (buffer) to store ps data + returns: error code of type HANDLE_ERROR_INFO + input: none + output: - HANDLE_PS_DATA *hPsData: according handle +*/ +static HANDLE_ERROR_INFO CreatePSData(HANDLE_PS_DATA *hPsData) +{ + HANDLE_ERROR_INFO error = noError; + + *hPsData = GetRam_PsData(); + if (*hPsData==NULL) { + error = 1; + goto bail; + } + FDKmemclear(*hPsData,sizeof(PS_DATA)); + +bail: + return error; +} + + +/* + name: static HANDLE_ERROR_INFO DestroyPSData() + description: frees according data handle + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PS_DATA *hPsData + output: none +*/ +static HANDLE_ERROR_INFO DestroyPSData(HANDLE_PS_DATA *phPsData) +{ + FreeRam_PsData(phPsData); + + return noError; +} + + +static HANDLE_ERROR_INFO InitPSData(HANDLE_PS_DATA hPsData) +{ + INT i, env; + HANDLE_ERROR_INFO error = noError; + + if(hPsData != NULL){ + + FDKmemclear(hPsData,sizeof(PS_DATA)); + + for (i=0; i<PS_MAX_BANDS; i++) { + hPsData->iidIdxLast[i] = 0; + hPsData->iccIdxLast[i] = 0; + } + + hPsData->iidEnable = hPsData->iidEnableLast = 0; + hPsData->iccEnable = hPsData->iccEnableLast = 0; + hPsData->iidQuantMode = hPsData->iidQuantModeLast = PS_IID_RES_COARSE; + hPsData->iccQuantMode = hPsData->iccQuantModeLast = PS_ICC_ROT_A; + + for(env=0; env<PS_MAX_ENVELOPES; env++) { + hPsData->iccDiffMode[env] = PS_DELTA_FREQ; + hPsData->iccDiffMode[env] = PS_DELTA_FREQ; + + for (i=0; i<PS_MAX_BANDS; i++) { + hPsData->iidIdx[env][i] = 0; + hPsData->iccIdx[env][i] = 0; + } + } + + hPsData->nEnvelopesLast = 0; + + hPsData->headerCnt = MAX_PS_NOHEADER_CNT; + hPsData->iidTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->iccTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->noEnvCnt = MAX_NOENV_CNT; + } else { + error = ERROR(CDI, "Unable to write to hPsData."); + } + + return error; +} + +static FIXP_DBL quantizeCoef( const FIXP_DBL *RESTRICT input, + const INT nBands, + const FIXP_DBL *RESTRICT quantTable, + const INT idxOffset, + const INT nQuantSteps, + INT *RESTRICT quantOut) +{ + INT idx, band; + FIXP_DBL quantErr = FL2FXCONST_DBL(0.f); + + for (band=0; band<nBands;band++) { + for(idx=0; idx<nQuantSteps-1; idx++){ + if( fixp_abs((input[band]>>1)-(quantTable[idx+1]>>1)) > + fixp_abs((input[band]>>1)-(quantTable[idx]>>1)) ) + { + break; + } + } + quantErr += (fixp_abs(input[band]-quantTable[idx])>>PS_QUANT_SCALE); /* don't scale before subtraction; diff smaller (64-25)/64 */ + quantOut[band] = idx - idxOffset; + } + + return quantErr; +} + +static INT getICCMode(const INT nBands, + const INT rotType) +{ + INT mode = 0; + + switch(nBands) { + case PS_BANDS_COARSE: + mode = PS_RES_COARSE; + break; + case PS_BANDS_MID: + mode = PS_RES_MID; + break; + case PS_BANDS_FINE: + mode = PS_RES_FINE; + break; + default: + mode = 0; + } + if(rotType==PS_ICC_ROT_B){ + mode += 3; + } + + return mode; +} + + +static INT getIIDMode(const INT nBands, + const INT iidRes) +{ + INT mode = 0; + + switch(nBands) { + case PS_BANDS_COARSE: + mode = PS_RES_COARSE; + break; + case PS_BANDS_MID: + mode = PS_RES_MID; + break; + case PS_BANDS_FINE: + mode = PS_RES_FINE; + break; + default: + mode = 0; + break; + } + + if(iidRes == PS_IID_RES_FINE){ + mode += 3; + } + + return mode; +} + + +static INT envelopeReducible(FIXP_DBL iid[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL icc[PS_MAX_ENVELOPES][PS_MAX_BANDS], + INT psBands, + INT nEnvelopes) +{ + #define THRESH_SCALE 7 + + INT reducible = 1; /* true */ + INT e = 0, b = 0; + FIXP_DBL dIid = FL2FXCONST_DBL(0.f); + FIXP_DBL dIcc = FL2FXCONST_DBL(0.f); + + FIXP_DBL iidErrThreshold, iccErrThreshold; + FIXP_DBL iidMeanError, iccMeanError; + + /* square values to prevent sqrt, + multiply bands to prevent division; bands shifted DFRACT_BITS instead (DFRACT_BITS-1) because fMultDiv2 used*/ + iidErrThreshold = fMultDiv2 ( FL2FXCONST_DBL(6.5f*6.5f/(IID_SCALE_FT*IID_SCALE_FT)), (FIXP_DBL)(psBands<<((DFRACT_BITS)-THRESH_SCALE)) ); + iccErrThreshold = fMultDiv2 ( FL2FXCONST_DBL(0.75f*0.75f), (FIXP_DBL)(psBands<<((DFRACT_BITS)-THRESH_SCALE)) ); + + if (nEnvelopes <= 1) { + reducible = 0; + } else { + + /* mean error criterion */ + for (e=0; (e < nEnvelopes/2) && (reducible!=0 ) ; e++) { + iidMeanError = iccMeanError = FL2FXCONST_DBL(0.f); + for(b=0; b<psBands; b++) { + dIid = (iid[2*e][b]>>1) - (iid[2*e+1][b]>>1); /* scale 1 bit; squared -> 2 bit */ + dIcc = (icc[2*e][b]>>1) - (icc[2*e+1][b]>>1); + iidMeanError += fPow2Div2(dIid)>>(5-1); /* + (bands=20) scale = 5 */ + iccMeanError += fPow2Div2(dIcc)>>(5-1); + } /* --> scaling = 7 bit = THRESH_SCALE !! */ + + /* instead sqrt values are squared! + instead of division, multiply threshold with psBands + scaling necessary!! */ + + /* quit as soon as threshold is reached */ + if ( (iidMeanError > (iidErrThreshold)) || + (iccMeanError > (iccErrThreshold)) ) { + reducible = 0; + } + } + } /* nEnvelopes != 1 */ + + return reducible; +} + + +static void processIidData(PS_DATA *psData, + FIXP_DBL iid[PS_MAX_ENVELOPES][PS_MAX_BANDS], + const INT psBands, + const INT nEnvelopes, + const FIXP_DBL quantErrorThreshold) +{ + INT iidIdxFine [PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iidIdxCoarse[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + + FIXP_DBL errIID = FL2FXCONST_DBL(0.f); + FIXP_DBL errIIDFine = FL2FXCONST_DBL(0.f); + INT bitsIidFreq = 0; + INT bitsIidTime = 0; + INT bitsFineTot = 0; + INT bitsCoarseTot = 0; + INT error = 0; + INT env, band; + INT diffMode[PS_MAX_ENVELOPES], diffModeFine[PS_MAX_ENVELOPES]; + INT loudnDiff = 0; + INT iidTransmit = 0; + + + bitsIidFreq = bitsIidTime = 0; + + /* Quantize IID coefficients */ + for(env=0;env<nEnvelopes; env++) { + errIID += quantizeCoef(iid[env], psBands, iidQuant_fx, 7, 15, iidIdxCoarse[env]); + errIIDFine += quantizeCoef(iid[env], psBands, iidQuantFine_fx, 15, 31, iidIdxFine[env]); + } + + + /* normalize error to number of envelopes, ps bands + errIID /= psBands*nEnvelopes; + errIIDFine /= psBands*nEnvelopes; */ + + + /* Check if IID coefficients should be used in this frame */ + psData->iidEnable = 0; + for(env=0;env<nEnvelopes; env++) { + for(band=0;band<psBands;band++) { + loudnDiff += fixp_abs(iidIdxCoarse[env][band]); + iidTransmit ++; + } + } + + if(loudnDiff > fMultI(FL2FXCONST_DBL(0.7f),iidTransmit)){ /* 0.7f empiric value */ + psData->iidEnable = 1; + } + + /* if iid not active -> RESET data */ + if(psData->iidEnable==0) { + psData->iidTimeCnt = MAX_TIME_DIFF_FRAMES; + for(env=0;env<nEnvelopes; env++) { + psData->iidDiffMode[env] = PS_DELTA_FREQ; + FDKmemclear(psData->iidIdx[env], sizeof(INT)*psBands); + } + return; + } + + /* count COARSE quantization bits for first envelope*/ + bitsIidFreq = FDKsbrEnc_EncodeIid(NULL, iidIdxCoarse[0], NULL, psBands, PS_IID_RES_COARSE, PS_DELTA_FREQ, &error); + + if( (psData->iidTimeCnt>=MAX_TIME_DIFF_FRAMES) || (psData->iidQuantModeLast==PS_IID_RES_FINE) ) { + bitsIidTime = DO_NOT_USE_THIS_MODE; + } + else { + bitsIidTime = FDKsbrEnc_EncodeIid(NULL, iidIdxCoarse[0], psData->iidIdxLast, psBands, PS_IID_RES_COARSE, PS_DELTA_TIME, &error); + } + + /* decision DELTA_FREQ vs DELTA_TIME */ + if(bitsIidTime>bitsIidFreq) { + diffMode[0] = PS_DELTA_FREQ; + bitsCoarseTot = bitsIidFreq; + } + else { + diffMode[0] = PS_DELTA_TIME; + bitsCoarseTot = bitsIidTime; + } + + /* count COARSE quantization bits for following envelopes*/ + for(env=1;env<nEnvelopes; env++) { + bitsIidFreq = FDKsbrEnc_EncodeIid(NULL, iidIdxCoarse[env], NULL, psBands, PS_IID_RES_COARSE, PS_DELTA_FREQ, &error); + bitsIidTime = FDKsbrEnc_EncodeIid(NULL, iidIdxCoarse[env], iidIdxCoarse[env-1], psBands, PS_IID_RES_COARSE, PS_DELTA_TIME, &error); + + /* decision DELTA_FREQ vs DELTA_TIME */ + if(bitsIidTime>bitsIidFreq) { + diffMode[env] = PS_DELTA_FREQ; + bitsCoarseTot += bitsIidFreq; + } + else { + diffMode[env] = PS_DELTA_TIME; + bitsCoarseTot += bitsIidTime; + } + } + + + /* count FINE quantization bits for first envelope*/ + bitsIidFreq = FDKsbrEnc_EncodeIid(NULL, iidIdxFine[0], NULL, psBands, PS_IID_RES_FINE, PS_DELTA_FREQ, &error); + + if( (psData->iidTimeCnt>=MAX_TIME_DIFF_FRAMES) || (psData->iidQuantModeLast==PS_IID_RES_COARSE) ) { + bitsIidTime = DO_NOT_USE_THIS_MODE; + } + else { + bitsIidTime = FDKsbrEnc_EncodeIid(NULL, iidIdxFine[0], psData->iidIdxLast, psBands, PS_IID_RES_FINE, PS_DELTA_TIME, &error); + } + + /* decision DELTA_FREQ vs DELTA_TIME */ + if(bitsIidTime>bitsIidFreq) { + diffModeFine[0] = PS_DELTA_FREQ; + bitsFineTot = bitsIidFreq; + } + else { + diffModeFine[0] = PS_DELTA_TIME; + bitsFineTot = bitsIidTime; + } + + /* count FINE quantization bits for following envelopes*/ + for(env=1;env<nEnvelopes; env++) { + bitsIidFreq = FDKsbrEnc_EncodeIid(NULL, iidIdxFine[env], NULL, psBands, PS_IID_RES_FINE, PS_DELTA_FREQ, &error); + bitsIidTime = FDKsbrEnc_EncodeIid(NULL, iidIdxFine[env], iidIdxFine[env-1], psBands, PS_IID_RES_FINE, PS_DELTA_TIME, &error); + + /* decision DELTA_FREQ vs DELTA_TIME */ + if(bitsIidTime>bitsIidFreq) { + diffModeFine[env] = PS_DELTA_FREQ; + bitsFineTot += bitsIidFreq; + } + else { + diffModeFine[env] = PS_DELTA_TIME; + bitsFineTot += bitsIidTime; + } + } + + if(bitsFineTot == bitsCoarseTot){ + /* if same number of bits is needed, use the quantization with lower error */ + if(errIIDFine < errIID){ + bitsCoarseTot = DO_NOT_USE_THIS_MODE; + } else { + bitsFineTot = DO_NOT_USE_THIS_MODE; + } + } else { + /* const FIXP_DBL minThreshold = FL2FXCONST_DBL(0.2f/(IID_SCALE_FT*PS_QUANT_SCALE_FT)*(psBands*nEnvelopes)); */ + const FIXP_DBL minThreshold = (FIXP_DBL)((LONG)0x00019999 * (psBands*nEnvelopes)); + + /* decision RES_FINE vs RES_COARSE */ + /* test if errIIDFine*quantErrorThreshold < errIID */ + /* shiftVal 2 comes from scaling of quantErrorThreshold */ + if(fixMax(((errIIDFine>>1)+(minThreshold>>1))>>1, fMult(quantErrorThreshold,errIIDFine)) < (errIID>>2) ) { + bitsCoarseTot = DO_NOT_USE_THIS_MODE; + } + else if(fixMax(((errIID>>1)+(minThreshold>>1))>>1, fMult(quantErrorThreshold,errIID)) < (errIIDFine>>2) ) { + bitsFineTot = DO_NOT_USE_THIS_MODE; + } + } + + /* decision RES_FINE vs RES_COARSE */ + if(bitsFineTot<bitsCoarseTot) { + psData->iidQuantMode = PS_IID_RES_FINE; + for(env=0;env<nEnvelopes; env++) { + psData->iidDiffMode[env] = diffModeFine[env]; + FDKmemcpy(psData->iidIdx[env], iidIdxFine[env], psBands*sizeof(INT)); + } + } + else { + psData->iidQuantMode = PS_IID_RES_COARSE; + for(env=0;env<nEnvelopes; env++) { + psData->iidDiffMode[env] = diffMode[env]; + FDKmemcpy(psData->iidIdx[env], iidIdxCoarse[env], psBands*sizeof(INT)); + } + } + + /* Count DELTA_TIME encoding streaks */ + for(env=0;env<nEnvelopes; env++) { + if(psData->iidDiffMode[env]==PS_DELTA_TIME) + psData->iidTimeCnt++; + else + psData->iidTimeCnt=0; + } +} + + +static INT similarIid(PS_DATA *psData, + const INT psBands, + const INT nEnvelopes) +{ + const INT diffThr = (psData->iidQuantMode == PS_IID_RES_COARSE) ? 2 : 3; + const INT sumDiffThr = diffThr * psBands/4; + INT similar = 0; + INT diff = 0; + INT sumDiff = 0; + INT env = 0; + INT b = 0; + if ((nEnvelopes == psData->nEnvelopesLast) && (nEnvelopes==1)) { + similar = 1; + for (env=0; env<nEnvelopes; env++) { + sumDiff = 0; + b = 0; + do { + diff = fixp_abs(psData->iidIdx[env][b] - psData->iidIdxLast[b]); + sumDiff += diff; + if ( (diff > diffThr) /* more than x quantization steps in any band */ + || (sumDiff > sumDiffThr) ) { /* more than x quantisations steps overall difference */ + similar = 0; + } + b++; + } while ((b<psBands) && (similar>0)); + } + } /* nEnvelopes==1 */ + + return similar; +} + + +static INT similarIcc(PS_DATA *psData, + const INT psBands, + const INT nEnvelopes) +{ + const INT diffThr = 2; + const INT sumDiffThr = diffThr * psBands/4; + INT similar = 0; + INT diff = 0; + INT sumDiff = 0; + INT env = 0; + INT b = 0; + if ((nEnvelopes == psData->nEnvelopesLast) && (nEnvelopes==1)) { + similar = 1; + for (env=0; env<nEnvelopes; env++) { + sumDiff = 0; + b = 0; + do { + diff = fixp_abs(psData->iccIdx[env][b] - psData->iccIdxLast[b]); + sumDiff += diff; + if ( (diff > diffThr) /* more than x quantisation step in any band */ + || (sumDiff > sumDiffThr) ) { /* more than x quantisations steps overall difference */ + similar = 0; + } + b++; + } while ((b<psBands) && (similar>0)); + } + } /* nEnvelopes==1 */ + + return similar; +} + +static void processIccData(PS_DATA *psData, + FIXP_DBL icc[PS_MAX_ENVELOPES][PS_MAX_BANDS], /* const input values: unable to declare as const, since it does not poINT to const memory */ + const INT psBands, + const INT nEnvelopes) +{ + FIXP_DBL errICC = FL2FXCONST_DBL(0.f); + INT env, band; + INT bitsIccFreq, bitsIccTime; + INT error = 0; + INT inCoherence=0, iccTransmit=0; + INT *iccIdxLast; + + iccIdxLast = psData->iccIdxLast; + + /* Quantize ICC coefficients */ + for(env=0;env<nEnvelopes; env++) { + errICC += quantizeCoef(icc[env], psBands, iccQuant, 0, 8, psData->iccIdx[env]); + } + + /* Check if ICC coefficients should be used */ + psData->iccEnable = 0; + for(env=0;env<nEnvelopes; env++) { + for(band=0;band<psBands;band++) { + inCoherence += psData->iccIdx[env][band]; + iccTransmit ++; + } + } + if(inCoherence > fMultI(FL2FXCONST_DBL(0.5f),iccTransmit)){ /* 0.5f empiric value */ + psData->iccEnable = 1; + } + + if(psData->iccEnable==0) { + psData->iccTimeCnt = MAX_TIME_DIFF_FRAMES; + for(env=0;env<nEnvelopes; env++) { + psData->iccDiffMode[env] = PS_DELTA_FREQ; + FDKmemclear(psData->iccIdx[env], sizeof(INT)*psBands); + } + return; + } + + for(env=0;env<nEnvelopes; env++) { + bitsIccFreq = FDKsbrEnc_EncodeIcc(NULL, psData->iccIdx[env], NULL, psBands, PS_DELTA_FREQ, &error); + + if(psData->iccTimeCnt<MAX_TIME_DIFF_FRAMES) { + bitsIccTime = FDKsbrEnc_EncodeIcc(NULL, psData->iccIdx[env], iccIdxLast, psBands, PS_DELTA_TIME, &error); + } + else { + bitsIccTime = DO_NOT_USE_THIS_MODE; + } + + if(bitsIccFreq>bitsIccTime) { + psData->iccDiffMode[env] = PS_DELTA_TIME; + psData->iccTimeCnt++; + } + else { + psData->iccDiffMode[env] = PS_DELTA_FREQ; + psData->iccTimeCnt=0; + } + iccIdxLast = psData->iccIdx[env]; + } +} + +static void calculateIID(FIXP_DBL ldPwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL ldPwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL iid[PS_MAX_ENVELOPES][PS_MAX_BANDS], + INT nEnvelopes, + INT psBands) +{ + INT i=0; + INT env=0; + for(env=0; env<nEnvelopes;env++) { + for (i=0; i<psBands; i++) { + + /* iid[env][i] = 10.0f*(float)log10(pwrL[env][i]/pwrR[env][i]); + */ + FIXP_DBL IID = fMultDiv2( FL2FXCONST_DBL(LOG10_2_10/IID_SCALE_FT), (ldPwrL[env][i]-ldPwrR[env][i]) ); + + IID = fixMin( IID, (FIXP_DBL)(FL2FXCONST_DBL( 1.f)>>(LD_DATA_SHIFT+1)) ); + IID = fixMax( IID, (FIXP_DBL)(FL2FXCONST_DBL(-1.f)>>(LD_DATA_SHIFT+1)) ); + iid[env][i] = IID << (LD_DATA_SHIFT+1); + } + } +} + +static void calculateICC(FIXP_DBL ldPwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL ldPwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL pwrCr[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL pwrCi[PS_MAX_ENVELOPES][PS_MAX_BANDS], + FIXP_DBL icc[PS_MAX_ENVELOPES][PS_MAX_BANDS], + INT nEnvelopes, + INT psBands) +{ + INT i = 0; + INT env = 0; + INT border = psBands; + + switch (psBands) { + case PS_BANDS_COARSE: + border = 5; + break; + case PS_BANDS_MID: + border = 11; + break; + case PS_BANDS_FINE: + border = 16; + break; + default: + break; + } + + /* :TRICKY: ndf 20041012 It is unclear which formula should be used here. + The first one does not quite correspond to the scientific formula for coherence. + The second formula is correct mathematically speaking but returns values in the range of [0 1], + where the MPEG standard allows quantization down to -1. This then doesnt seem to make sense. */ + /* ndf 20041119 According to rtb/hrr the 1. formula will interpret small time + delays as incoherence whereas the 2. formula will consider only truly + uncorrelated signals as incoherent. */ + + for(env=0; env<nEnvelopes;env++) { + for (i=0; i<border; i++) { + + /* icc[env][i] = min( pwrCr[env][i] / (float) sqrt(pwrL[env][i] * pwrR[env][i]) , 1.f); + */ + FIXP_DBL ICC, invNrg = CalcInvLdData ( -((ldPwrL[env][i]>>1) + (ldPwrR[env][i]>>1) + (FIXP_DBL)1) ); + INT scale, invScale = CountLeadingBits(invNrg); + + scale = (DFRACT_BITS-1) - invScale; + ICC = fMult(pwrCr[env][i], invNrg<<invScale) ; + icc[env][i] = SATURATE_LEFT_SHIFT(ICC, scale, DFRACT_BITS); + } + + for (; i<psBands; i++) { + INT sc1, sc2; + FIXP_DBL cNrgR, cNrgI, ICC; + + sc1 = CountLeadingBits( fixMax(fixp_abs(pwrCr[env][i]),fixp_abs(pwrCi[env][i])) ) ; + cNrgR = fPow2Div2((pwrCr[env][i]<<sc1)); /* squared nrg's expect explicit scaling */ + cNrgI = fPow2Div2((pwrCi[env][i]<<sc1)); + + ICC = CalcInvLdData( (CalcLdData((cNrgR + cNrgI)>>1)>>1) - (FIXP_DBL)((sc1-1)<<(DFRACT_BITS-1-LD_DATA_SHIFT)) ); + + FIXP_DBL invNrg = CalcInvLdData ( -((ldPwrL[env][i]>>1) + (ldPwrR[env][i]>>1) + (FIXP_DBL)1) ); + sc1 = CountLeadingBits(invNrg); + invNrg <<= sc1; + + sc2 = CountLeadingBits(ICC); + ICC = fMult(ICC<<sc2,invNrg); + + sc1 = ( (DFRACT_BITS-1) - sc1 - sc2 ); + if (sc1 < 0) { + ICC >>= -sc1; + } + else { + if (ICC >= ((FIXP_DBL)MAXVAL_DBL>>sc1) ) + ICC = (FIXP_DBL)MAXVAL_DBL; + else + ICC <<= sc1; + } + + icc[env][i] = ICC; + } + } +} + +void FDKsbrEnc_initPsBandNrgScale(HANDLE_PS_ENCODE hPsEncode) +{ + INT group, bin; + INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; + + FDKmemclear(hPsEncode->psBandNrgScale, PS_MAX_BANDS*sizeof(SCHAR)); + + for (group=0; group < nIidGroups; group++) { + /* Translate group to bin */ + bin = hPsEncode->subband2parameterIndex[group]; + + /* Translate from 20 bins to 10 bins */ + if (hPsEncode->psEncMode == PS_BANDS_COARSE) { + bin = bin>>1; + } + + hPsEncode->psBandNrgScale[bin] = (hPsEncode->psBandNrgScale[bin]==0) + ? (hPsEncode->iidGroupWidthLd[group] + 5) + : (fixMax(hPsEncode->iidGroupWidthLd[group],hPsEncode->psBandNrgScale[bin]) + 1) ; + + } +} + +HANDLE_ERROR_INFO FDKsbrEnc_CreatePSEncode(HANDLE_PS_ENCODE *phPsEncode){ + + HANDLE_ERROR_INFO error = noError; + + HANDLE_PS_ENCODE hPsEncode = GetRam_PsEncode(); + FDKmemclear(hPsEncode,sizeof(PS_ENCODE)); + + if(error == noError){ + if(noError != (error = CreatePSData(&hPsEncode->hPsData))){ + error = handBack(error); + } + } + + *phPsEncode = hPsEncode; + + return error; +} + +HANDLE_ERROR_INFO FDKsbrEnc_InitPSEncode(HANDLE_PS_ENCODE hPsEncode, const PS_BANDS psEncMode, const FIXP_DBL iidQuantErrorThreshold){ + + HANDLE_ERROR_INFO error = noError; + + if(error == noError){ + if(noError != (InitPSData(hPsEncode->hPsData))){ + error = handBack(error); + } + } + + if(error == noError){ + switch(psEncMode){ + case PS_BANDS_COARSE: + case PS_BANDS_MID: + hPsEncode->nQmfIidGroups = QMF_GROUPS_LO_RES; + hPsEncode->nSubQmfIidGroups = SUBQMF_GROUPS_LO_RES; + FDKmemcpy(hPsEncode->iidGroupBorders, iidGroupBordersLoRes, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups + 1)*sizeof(INT)); + FDKmemcpy(hPsEncode->subband2parameterIndex, subband2parameter20, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups) *sizeof(INT)); + FDKmemcpy(hPsEncode->iidGroupWidthLd, iidGroupWidthLdLoRes, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups) *sizeof(UCHAR)); + break; + case PS_BANDS_FINE: + FDK_ASSERT(0); /* we don't support this mode! */ + + break; + default: + error = ERROR(CDI, "Invalid stereo band configuration."); + break; + } + } + + if(error == noError){ + hPsEncode->psEncMode = psEncMode; + hPsEncode->iidQuantErrorThreshold = iidQuantErrorThreshold; + FDKsbrEnc_initPsBandNrgScale(hPsEncode); + } + + return error; +} + + +HANDLE_ERROR_INFO FDKsbrEnc_DestroyPSEncode(HANDLE_PS_ENCODE *phPsEncode){ + + HANDLE_ERROR_INFO error = noError; + + if(error == noError){ + DestroyPSData(&(*phPsEncode)->hPsData); + FreeRam_PsEncode(phPsEncode); + } + + return error; +} + +typedef struct { + FIXP_DBL pwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL pwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL ldPwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL ldPwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL pwrCr[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL pwrCi[PS_MAX_ENVELOPES][PS_MAX_BANDS]; +} PS_PWR_DATA; + +HANDLE_ERROR_INFO FDKsbrEnc_PSEncode(HANDLE_PS_ENCODE RESTRICT hPsEncode, + HANDLE_PS_OUT RESTRICT hPsOut, + HANDLE_PS_CHANNEL_DATA RESTRICT hChanDatal, + HANDLE_PS_CHANNEL_DATA RESTRICT hChanDatar, + UCHAR *RESTRICT dynBandScale, + UINT maxEnvelopes, + const int sendHeader) +{ + HANDLE_ERROR_INFO error = noError; + HANDLE_PS_DATA hPsData = hPsEncode->hPsData; + HANDLE_PS_HYBRID_DATA hHybDatal = hChanDatal->hHybData; + HANDLE_PS_HYBRID_DATA hHybDatar = hChanDatar->hHybData; + FIXP_QMF **RESTRICT lr = NULL, **RESTRICT li = NULL, **RESTRICT rr = NULL, **RESTRICT ri = NULL; + FIXP_DBL iid [PS_MAX_ENVELOPES][PS_MAX_BANDS]; + FIXP_DBL icc [PS_MAX_ENVELOPES][PS_MAX_BANDS]; + int envBorder[PS_MAX_ENVELOPES+1]; + + int group, bin, border, col, subband, band; + int i = 0; + + int env = 0; + int psBands = (int) hPsEncode->psEncMode; + int frameSize = FDKsbrEnc_GetHybridFrameSize(hHybDatal); /* same as FDKsbrEnc_GetHybridFrameSize(hHybDatar) */ + int nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; + int nEnvelopes = fixMin(maxEnvelopes, (UINT)PS_MAX_ENVELOPES); + + C_ALLOC_SCRATCH_START(pwrData, PS_PWR_DATA, 1); + + + for(env=0; env<nEnvelopes+1;env++) { + envBorder[env] = fMultI(GetInvInt(nEnvelopes),frameSize*env); + } + + for(env=0; env<nEnvelopes;env++) { + INT nHybridQmfOffset = 0; + int descale = 0; + + /* clear energy array */ + for (band=0; band<psBands; band++) { + pwrData->pwrL[env][band] = pwrData->pwrR[env][band] = pwrData->pwrCr[env][band] = pwrData->pwrCi[env][band] = FIXP_DBL(1); + } + + /**** calculate energies and correlation ****/ + + /* start with hybrid data */ + lr = hHybDatal->rHybData; li = hHybDatal->iHybData; + rr = hHybDatar->rHybData; ri = hHybDatar->iHybData; + UCHAR switched = 0; + + for (group=0; group < nIidGroups; group++) { + /* Translate group to bin */ + bin = hPsEncode->subband2parameterIndex[group]; + + /* Translate from 20 bins to 10 bins */ + if (hPsEncode->psEncMode == PS_BANDS_COARSE) { + bin >>= 1; + } + + if (!switched && group == hPsEncode->nSubQmfIidGroups) { + /* switch to qmf data */ + lr = hChanDatal->hPsQmfData->rQmfData; li = hChanDatal->hPsQmfData->iQmfData; + rr = hChanDatar->hPsQmfData->rQmfData; ri = hChanDatar->hPsQmfData->iQmfData; + /* calc offset between hybrid subsubbands and qmf bands */ + nHybridQmfOffset = FDKsbrEnc_GetNumberHybridQmfBands(hHybDatal) - FDKsbrEnc_GetNumberHybridBands(hHybDatal); + switched = 1; + } + + /* determine group border */ + int bScale = 2*descale + hPsEncode->psBandNrgScale[bin]; + border = hPsEncode->iidGroupBorders[group+1]; + + FIXP_DBL pwrL_env_bin = pwrData->pwrL[env][bin]; + FIXP_DBL pwrR_env_bin = pwrData->pwrR[env][bin]; + FIXP_DBL pwrCr_env_bin = pwrData->pwrCr[env][bin]; + FIXP_DBL pwrCi_env_bin = pwrData->pwrCi[env][bin]; + int scale = (int)dynBandScale[bin]; + for (col=envBorder[env]; col<envBorder[env+1]; col++) { + for (subband = hPsEncode->iidGroupBorders[group]; subband < border; subband++) { + FIXP_QMF l_real = (lr[col][subband + nHybridQmfOffset]) << scale; + FIXP_QMF l_imag = (li[col][subband + nHybridQmfOffset]) << scale; + FIXP_QMF r_real = (rr[col][subband + nHybridQmfOffset]) << scale; + FIXP_QMF r_imag = (ri[col][subband + nHybridQmfOffset]) << scale; + + pwrL_env_bin += (fPow2Div2(l_real) + fPow2Div2(l_imag)) >> bScale; + pwrR_env_bin += (fPow2Div2(r_real) + fPow2Div2(r_imag)) >> bScale; + pwrCr_env_bin += (fMultDiv2(l_real, r_real) + fMultDiv2(l_imag, r_imag)) >> bScale; + pwrCi_env_bin += (fMultDiv2(r_real, l_imag) - fMultDiv2(l_real, r_imag)) >> bScale; + } + } + /* assure, nrg's of left and right channel are not negative; necessary on 16 bit multiply units */ + pwrData->pwrL[env][bin] = fixMax((FIXP_DBL)0,pwrL_env_bin); + pwrData->pwrR[env][bin] = fixMax((FIXP_DBL)0,pwrR_env_bin); + + pwrData->pwrCr[env][bin] = pwrCr_env_bin; + pwrData->pwrCi[env][bin] = pwrCi_env_bin; + + } /* nIidGroups */ + + /* calc logarithmic energy */ + LdDataVector(pwrData->pwrL[env], pwrData->ldPwrL[env], psBands); + LdDataVector(pwrData->pwrR[env], pwrData->ldPwrR[env], psBands); + + } /* nEnvelopes */ + + + /* calculate iid and icc */ + calculateIID(pwrData->ldPwrL, pwrData->ldPwrR, iid, nEnvelopes, psBands); + calculateICC(pwrData->ldPwrL, pwrData->ldPwrR, pwrData->pwrCr, pwrData->pwrCi, icc, nEnvelopes, psBands); + + + + /*** Envelope Reduction ***/ + while (envelopeReducible(iid,icc,psBands,nEnvelopes)) { + int e=0; + /* sum energies of two neighboring envelopes */ + nEnvelopes >>= 1; + for (e=0; e<nEnvelopes; e++) { + FDKsbrEnc_addFIXP_DBL(pwrData->pwrL[2*e], pwrData->pwrL[2*e+1], pwrData->pwrL[e], psBands); + FDKsbrEnc_addFIXP_DBL(pwrData->pwrR[2*e], pwrData->pwrR[2*e+1], pwrData->pwrR[e], psBands); + FDKsbrEnc_addFIXP_DBL(pwrData->pwrCr[2*e],pwrData->pwrCr[2*e+1],pwrData->pwrCr[e],psBands); + FDKsbrEnc_addFIXP_DBL(pwrData->pwrCi[2*e],pwrData->pwrCi[2*e+1],pwrData->pwrCi[e],psBands); + + /* calc logarithmic energy */ + LdDataVector(pwrData->pwrL[e], pwrData->ldPwrL[e], psBands); + LdDataVector(pwrData->pwrR[e], pwrData->ldPwrR[e], psBands); + + /* reduce number of envelopes and adjust borders */ + envBorder[e] = envBorder[2*e]; + } + envBorder[nEnvelopes] = envBorder[2*nEnvelopes]; + + /* re-calculate iid and icc */ + calculateIID(pwrData->ldPwrL, pwrData->ldPwrR, iid, nEnvelopes, psBands); + calculateICC(pwrData->ldPwrL, pwrData->ldPwrR, pwrData->pwrCr, pwrData->pwrCi, icc, nEnvelopes, psBands); + } + + + /* */ + if(sendHeader) { + hPsData->headerCnt = MAX_PS_NOHEADER_CNT; + hPsData->iidTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->iccTimeCnt = MAX_TIME_DIFF_FRAMES; + hPsData->noEnvCnt = MAX_NOENV_CNT; + } + + /*** Parameter processing, quantisation etc ***/ + processIidData(hPsData, iid, psBands, nEnvelopes, hPsEncode->iidQuantErrorThreshold); + processIccData(hPsData, icc, psBands, nEnvelopes); + + + /*** Initialize output struct ***/ + + /* PS Header on/off ? */ + if( (hPsData->headerCnt<MAX_PS_NOHEADER_CNT) + && ( (hPsData->iidQuantMode == hPsData->iidQuantModeLast) && (hPsData->iccQuantMode == hPsData->iccQuantModeLast) ) + && ( (hPsData->iidEnable == hPsData->iidEnableLast) && (hPsData->iccEnable == hPsData->iccEnableLast) ) ) { + hPsOut->enablePSHeader = 0; + } + else { + hPsOut->enablePSHeader = 1; + hPsData->headerCnt = 0; + } + + /* nEnvelopes = 0 ? */ + if ( (hPsData->noEnvCnt < MAX_NOENV_CNT) + && (similarIid(hPsData, psBands, nEnvelopes)) + && (similarIcc(hPsData, psBands, nEnvelopes)) ) { + hPsOut->nEnvelopes = nEnvelopes = 0; + hPsData->noEnvCnt++; + } else { + hPsData->noEnvCnt = 0; + } + + + + if (nEnvelopes>0) { + + hPsOut->enableIID = hPsData->iidEnable; + hPsOut->iidMode = getIIDMode(psBands, hPsData->iidQuantMode); + + hPsOut->enableICC = hPsData->iccEnable; + hPsOut->iccMode = getICCMode(psBands, hPsData->iccQuantMode); + + hPsOut->enableIpdOpd = 0; + hPsOut->frameClass = 0; + hPsOut->nEnvelopes = nEnvelopes; + + for(env=0; env<nEnvelopes; env++) { + hPsOut->frameBorder[env] = envBorder[env+1]; + } + + for(env=0; env<hPsOut->nEnvelopes; env++) { + hPsOut->deltaIID[env] = (PS_DELTA)hPsData->iidDiffMode[env]; + + for(band=0; band<psBands; band++) { + hPsOut->iid[env][band] = hPsData->iidIdx[env][band]; + } + } + + for(env=0; env<hPsOut->nEnvelopes; env++) { + hPsOut->deltaICC[env] = (PS_DELTA)hPsData->iccDiffMode[env]; + for(band=0; band<psBands; band++) { + hPsOut->icc[env][band] = hPsData->iccIdx[env][band]; + } + } + + /* IPD OPD not supported right now */ + FDKmemclear(hPsOut->ipd, PS_MAX_ENVELOPES*PS_MAX_BANDS*sizeof(PS_DELTA)); + for(env=0; env<PS_MAX_ENVELOPES; env++) { + hPsOut->deltaIPD[env] = PS_DELTA_FREQ; + hPsOut->deltaOPD[env] = PS_DELTA_FREQ; + } + + FDKmemclear(hPsOut->ipdLast, PS_MAX_BANDS*sizeof(INT)); + FDKmemclear(hPsOut->opdLast, PS_MAX_BANDS*sizeof(INT)); + + for(band=0; band<PS_MAX_BANDS; band++) { + hPsOut->iidLast[band] = hPsData->iidIdxLast[band]; + hPsOut->iccLast[band] = hPsData->iccIdxLast[band]; + } + + /* save iids and iccs for differential time coding in the next frame */ + hPsData->nEnvelopesLast = nEnvelopes; + hPsData->iidEnableLast = hPsData->iidEnable; + hPsData->iccEnableLast = hPsData->iccEnable; + hPsData->iidQuantModeLast = hPsData->iidQuantMode; + hPsData->iccQuantModeLast = hPsData->iccQuantMode; + for (i=0; i<psBands; i++) { + hPsData->iidIdxLast[i] = hPsData->iidIdx[nEnvelopes-1][i]; + hPsData->iccIdxLast[i] = hPsData->iccIdx[nEnvelopes-1][i]; + } + } /* Envelope > 0 */ + + + C_ALLOC_SCRATCH_END(pwrData, PS_PWR_DATA, 1) + + return error; +} + diff --git a/libSBRenc/src/ps_encode.h b/libSBRenc/src/ps_encode.h new file mode 100644 index 0000000..6ce9d1f --- /dev/null +++ b/libSBRenc/src/ps_encode.h @@ -0,0 +1,117 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: M. Neuendorf, N. Rettelbach, M. Multrus + contents/description: PS Parameter extraction, encoding + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +/*! + \file + \brief PS parameter extraction, encoding functions $Revision: 36847 $ +*/ + +#ifndef __INCLUDED_PS_ENCODE_H +#define __INCLUDED_PS_ENCODE_H + +#include "ps_const.h" +#include "ps_bitenc.h" +#include "psenc_hybrid.h" + +#define IID_SCALE_FT (64.f) /* maxVal in Quant tab is +/- 50 */ +#define IID_SCALE 6 /* maxVal in Quant tab is +/- 50 */ +#define IID_MAXVAL (1<<IID_SCALE) + +#define PS_QUANT_SCALE_FT (64.f) /* error smaller (64-25)/64 * 20 bands * 4 env -> QuantScale 64 */ +#define PS_QUANT_SCALE 6 /* error smaller (64-25)/64 * 20 bands * 4 env -> QuantScale 6 bit */ + + +#define QMF_GROUPS_LO_RES 12 +#define SUBQMF_GROUPS_LO_RES 10 +#define QMF_GROUPS_HI_RES 18 +#define SUBQMF_GROUPS_HI_RES 30 + + +typedef struct T_PS_DATA { + + INT iidEnable; + INT iidEnableLast; + INT iidQuantMode; + INT iidQuantModeLast; + INT iidDiffMode[PS_MAX_ENVELOPES]; + INT iidIdx [PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iidIdxLast [PS_MAX_BANDS]; + + INT iccEnable; + INT iccEnableLast; + INT iccQuantMode; + INT iccQuantModeLast; + INT iccDiffMode[PS_MAX_ENVELOPES]; + INT iccIdx [PS_MAX_ENVELOPES][PS_MAX_BANDS]; + INT iccIdxLast [PS_MAX_BANDS]; + + INT nEnvelopesLast; + + INT headerCnt; + INT iidTimeCnt; + INT iccTimeCnt; + INT noEnvCnt; + +} PS_DATA, *HANDLE_PS_DATA; + + +typedef struct T_PS_ENCODE{ + + HANDLE_PS_DATA hPsData; + + PS_BANDS psEncMode; + INT nQmfIidGroups; + INT nSubQmfIidGroups; + INT iidGroupBorders[QMF_GROUPS_HI_RES + SUBQMF_GROUPS_HI_RES + 1]; + INT subband2parameterIndex[QMF_GROUPS_HI_RES + SUBQMF_GROUPS_HI_RES]; + UCHAR iidGroupWidthLd[QMF_GROUPS_HI_RES + SUBQMF_GROUPS_HI_RES]; + FIXP_DBL iidQuantErrorThreshold; + + UCHAR psBandNrgScale [PS_MAX_BANDS]; + +} PS_ENCODE; + + +typedef struct T_PS_ENCODE *HANDLE_PS_ENCODE; +typedef struct T_PS_CHANNEL_DATA *HANDLE_PS_CHANNEL_DATA; + +HANDLE_ERROR_INFO FDKsbrEnc_CreatePSEncode(HANDLE_PS_ENCODE *phPsEncode); + +HANDLE_ERROR_INFO FDKsbrEnc_InitPSEncode(HANDLE_PS_ENCODE hPsEncode, const PS_BANDS psEncMode, const FIXP_DBL iidQuantErrorThreshold); + +HANDLE_ERROR_INFO FDKsbrEnc_DestroyPSEncode(HANDLE_PS_ENCODE *phPsEncode); + + +HANDLE_ERROR_INFO FDKsbrEnc_PSEncode(HANDLE_PS_ENCODE hPsEncode, + HANDLE_PS_OUT hPsOut, + HANDLE_PS_CHANNEL_DATA hChanDatal, + HANDLE_PS_CHANNEL_DATA hChanDatar, + UCHAR *dynBandScale, + UINT maxEnvelopes, + const int sendHeader); + +#endif diff --git a/libSBRenc/src/ps_main.cpp b/libSBRenc/src/ps_main.cpp new file mode 100644 index 0000000..c2b19d8 --- /dev/null +++ b/libSBRenc/src/ps_main.cpp @@ -0,0 +1,1079 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial Authors: M. Multrus + Contents/Description: PS Wrapper, Downmix + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "ps_main.h" + + +/* Includes ******************************************************************/ + +#include "ps_const.h" +#include "ps_bitenc.h" + +#include "sbr_ram.h" + + + +/* Function declarations ****************************************************/ +static void psFindBestScaling(HANDLE_PARAMETRIC_STEREO hParametricStereo, + UCHAR *dynBandScale, + FIXP_QMF *maxBandValue, + SCHAR *dmxScale); + +/* + name: static HANDLE_ERROR_INFO CreatePSQmf() + description: Creates struct (buffer) to store qmf data + returns: error code of type HANDLE_ERROR_INFO + input: - INT nCols: number of qmf samples stored in regular qmf buffer + - INT nRows: number qmf channels + - INT hybridFilterDelay: delay in qmf samples of hybrid filter + output: - HANDLE_PS_QMF_DATA *hPsQmfData: according handle +*/ +static HANDLE_ERROR_INFO CreatePSQmf(HANDLE_PS_QMF_DATA *phPsQmfData, INT ch) +{ + HANDLE_ERROR_INFO error = noError; + HANDLE_PS_QMF_DATA hPsQmfData = GetRam_PsQmfData(ch); + if (hPsQmfData==NULL) { + error = 1; + goto bail; + } + FDKmemclear(hPsQmfData, sizeof(PS_QMF_DATA)); + + hPsQmfData->rQmfData[0] = GetRam_PsRqmf(ch); + hPsQmfData->iQmfData[0] = GetRam_PsIqmf(ch); + + if ( (hPsQmfData->rQmfData[0]==NULL) || (hPsQmfData->iQmfData[0]==NULL) ) { + error = 1; + goto bail; + } + + +bail: + *phPsQmfData = hPsQmfData; + return error; +} + +static HANDLE_ERROR_INFO InitPSQmf(HANDLE_PS_QMF_DATA hPsQmfData, INT nCols, INT nRows, INT hybridFilterDelay, INT ch, UCHAR *dynamic_RAM) +{ + INT i, bufferLength = 0; + + hPsQmfData->nCols = nCols; + hPsQmfData->nRows = nRows; + hPsQmfData->bufferReadOffset = QMF_READ_OFFSET; + hPsQmfData->bufferReadOffsetHybrid = HYBRID_READ_OFFSET; /* calc read offset for hybrid analysis in qmf samples */ + hPsQmfData->bufferWriteOffset = hPsQmfData->bufferReadOffsetHybrid + hybridFilterDelay; + hPsQmfData->bufferLength = bufferLength = hPsQmfData->bufferWriteOffset + nCols; + + FDK_ASSERT(PSENC_QMF_BUFFER_LENGTH>=bufferLength); + + for(i=0; i<bufferLength; i++) { + hPsQmfData->rQmfData[i] = FDKsbrEnc_SliceRam_PsRqmf(hPsQmfData->rQmfData[0], dynamic_RAM, ch, i, nCols); + hPsQmfData->iQmfData[i] = FDKsbrEnc_SliceRam_PsIqmf(hPsQmfData->iQmfData[0], dynamic_RAM, ch, i, nCols); + } + + for(i=0; i<bufferLength; i++){ + FDKmemclear(hPsQmfData->rQmfData[i], (sizeof(FIXP_QMF)*QMF_CHANNELS)); + FDKmemclear(hPsQmfData->iQmfData[i], (sizeof(FIXP_QMF)*QMF_CHANNELS)); + } + + return noError; +} + + +/* + name: static HANDLE_ERROR_INFO CreatePSChannel() + description: Creates PS channel struct + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PS_HYBRID_CONFIG hHybConfig: config structure for hybrid filter bank + output: - HANDLE_PS_CHANNEL_DATA *hPsChannelData +*/ +static HANDLE_ERROR_INFO CreatePSChannel(HANDLE_PS_CHANNEL_DATA *hPsChannelData, + INT ch + ) +{ + HANDLE_ERROR_INFO error = noError; + + (*hPsChannelData) = GetRam_PsChData(ch); + + if (*hPsChannelData==NULL) { + error = 1; + goto bail; + } + FDKmemclear(*hPsChannelData, sizeof(PS_CHANNEL_DATA)); + + + if (error == noError) { + if (noError != (error = FDKsbrEnc_CreateHybridFilterBank(&(*hPsChannelData)->hHybAna, + ch ))) + { + goto bail; + } + } + if (error == noError) { + if (noError != (error = FDKsbrEnc_CreateHybridData( &((*hPsChannelData)->hHybData), + ch))) { + goto bail; + } + } + if(error == noError){ + if(noError != (error = CreatePSQmf(&((*hPsChannelData)->hPsQmfData), ch))) + { + goto bail; + } + } +bail: + return error; +} + +static HANDLE_ERROR_INFO InitPSChannel(HANDLE_PS_CHANNEL_DATA hPsChannelData, + HANDLE_PS_HYBRID_CONFIG hHybConfig, + INT noQmfSlots, + INT noQmfBands + ,INT ch, + UCHAR *dynamic_RAM + ) +{ + HANDLE_ERROR_INFO error = noError; + INT hybridFilterDelay = 0; + + if (error == noError) { + if (noError != (error = FDKsbrEnc_InitHybridFilterBank(hPsChannelData->hHybAna, + hHybConfig, + noQmfSlots ))) + { + error = handBack(error); + } + } + + if(error == noError){ + hybridFilterDelay = FDKsbrEnc_GetHybridFilterDelay(hPsChannelData->hHybAna); + hPsChannelData->psChannelDelay = hybridFilterDelay * noQmfBands; + } + + if (error == noError) { + if (noError != (error = FDKsbrEnc_InitHybridData( hPsChannelData->hHybData, + hHybConfig, + noQmfSlots))) + { + error = handBack(error); + } + } + + if(error == noError){ + if(noError != (error = InitPSQmf(hPsChannelData->hPsQmfData, + noQmfSlots, + noQmfBands, + hybridFilterDelay + ,ch, + dynamic_RAM + ))) + { + error = handBack(error); + } + } + + return error; +} + + +/* + name: static HANDLE_ERROR_INFO PSEnc_Create() + description: Creates PS struct + returns: error code of type HANDLE_ERROR_INFO + input: HANDLE_PSENC_CONFIG hPsEncConfig: configuration + output: HANDLE_PARAMETRIC_STEREO *hParametricStereo + +*/ +HANDLE_ERROR_INFO +PSEnc_Create(HANDLE_PARAMETRIC_STEREO *phParametricStereo) +{ + HANDLE_ERROR_INFO error = noError; + INT i; + HANDLE_PARAMETRIC_STEREO hParametricStereo = GetRam_ParamStereo(); + + if (hParametricStereo==NULL) { + error = 1; + goto bail; + } + + FDKmemclear(hParametricStereo,sizeof(PARAMETRIC_STEREO)); + + hParametricStereo->qmfDelayRealRef = GetRam_PsEnvRBuffer(0); + hParametricStereo->qmfDelayImagRef = GetRam_PsEnvIBuffer(0); + + if ( (hParametricStereo->qmfDelayRealRef==NULL) || (hParametricStereo->qmfDelayImagRef==NULL) ) { + error = 1; + goto bail; + } + + for (i = 0; i < (QMF_MAX_TIME_SLOTS>>1); i++) { + hParametricStereo->qmfDelayReal[i] = hParametricStereo->qmfDelayRealRef + (i*QMF_CHANNELS); + hParametricStereo->qmfDelayImag[i] = hParametricStereo->qmfDelayImagRef + (i*QMF_CHANNELS); + } + + for(i=0; i<MAX_PS_CHANNELS; i++){ + if(noError != (error = CreatePSChannel(&hParametricStereo->hPsChannelData[i], + i + ))) + { + goto bail; + } + } + + + if(noError != (error = FDKsbrEnc_CreatePSEncode(&hParametricStereo->hPsEncode))) { + error = 1; + goto bail; + } + + hParametricStereo->hHybridConfig = GetRam_PsHybConfig(); /* allocate memory */ + + /* calc PS_OUT values and delay one frame ! */ + hParametricStereo->hPsOut[0] = GetRam_PsOut(0); + hParametricStereo->hPsOut[1] = GetRam_PsOut(1); + if ( (hParametricStereo->hHybridConfig==NULL) || (hParametricStereo->hPsOut[0]==NULL) || (hParametricStereo->hPsOut[1]==NULL) ) { + error = 1; + goto bail; + } + +bail: + *phParametricStereo = hParametricStereo; + return error; +} + +HANDLE_ERROR_INFO +PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_PSENC_CONFIG hPsEncConfig, + INT noQmfSlots, + INT noQmfBands + ,UCHAR *dynamic_RAM + ) +{ + HANDLE_ERROR_INFO error = noError; + INT i; + INT tmpDelay = 0; + + if(error == noError){ + if(hPsEncConfig == NULL){ + error = ERROR(CDI, "Invalid configuration handle."); + } + } + + hParametricStereo->initPS = 1; + hParametricStereo->noQmfSlots = noQmfSlots; + hParametricStereo->noQmfBands = noQmfBands; + + for (i = 0; i < hParametricStereo->noQmfSlots>>1; i++) { + FDKmemclear( hParametricStereo->qmfDelayReal[i],QMF_CHANNELS*sizeof(FIXP_DBL)); + FDKmemclear( hParametricStereo->qmfDelayImag[i],QMF_CHANNELS*sizeof(FIXP_DBL)); + } + hParametricStereo->qmfDelayScale = FRACT_BITS-1; + + if(error == noError) { + PS_BANDS nHybridSubbands = (PS_BANDS)0; + + switch(hPsEncConfig->nStereoBands){ + case PSENC_STEREO_BANDS_10: + nHybridSubbands = PS_BANDS_COARSE; + break; + case PSENC_STEREO_BANDS_20: + nHybridSubbands = PS_BANDS_MID; + break; + case PSENC_STEREO_BANDS_34: + /* nHybridSubbands = PS_BANDS_FINE; */ + FDK_ASSERT(0); /* we don't support this mode! */ + break; + default: + nHybridSubbands = (PS_BANDS)0; + break; + } + /* create configuration for hybrid filter bank */ + FDKmemclear(hParametricStereo->hHybridConfig,sizeof(PS_HYBRID_CONFIG)); + if(noError != (error = FDKsbrEnc_CreateHybridConfig(&hParametricStereo->hHybridConfig, nHybridSubbands))) { + error = handBack(error); + } + } + + + tmpDelay = 0; + for(i=0; i<MAX_PS_CHANNELS; i++) { + + if(error == noError){ + if(noError != (error = InitPSChannel( hParametricStereo->hPsChannelData[i], + hParametricStereo->hHybridConfig, + hParametricStereo->noQmfSlots, + hParametricStereo->noQmfBands + ,i, + dynamic_RAM + ))) + { + error = handBack(error); + } + } + + if(error == noError){ + /* sum up delay in samples for all channels (should be the same for all channels) */ + tmpDelay += hParametricStereo->hPsChannelData[i]->psChannelDelay; + } + } + + if(error == noError){ + /* determine average delay */ + hParametricStereo->psDelay = tmpDelay/MAX_PS_CHANNELS; + } + + if(error == noError){ + if ( (hPsEncConfig->maxEnvelopes < PSENC_NENV_1) + || (hPsEncConfig->maxEnvelopes > PSENC_NENV_MAX) ) { + hPsEncConfig->maxEnvelopes = PSENC_NENV_DEFAULT; + } + hParametricStereo->maxEnvelopes = hPsEncConfig->maxEnvelopes; + } + + if(error == noError){ + if(noError != (error = FDKsbrEnc_InitPSEncode(hParametricStereo->hPsEncode, (PS_BANDS) hPsEncConfig->nStereoBands, hPsEncConfig->iidQuantErrorThreshold))){ + error = handBack(error); + } + } + + /* clear buffer */ + FDKmemclear(hParametricStereo->hPsOut[0], sizeof(PS_OUT)); + FDKmemclear(hParametricStereo->hPsOut[1], sizeof(PS_OUT)); + + /* clear scaling buffer */ + FDKmemclear(hParametricStereo->dynBandScale, sizeof(UCHAR)*PS_MAX_BANDS); + FDKmemclear(hParametricStereo->maxBandValue, sizeof(FIXP_QMF)*PS_MAX_BANDS); + + return error; +} + + + +/* + name: static HANDLE_ERROR_INFO DestroyPSQmf + description: destroy PS qmf buffers + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PS_QMF_DATA *hPsQmfData + output: none +*/ + +static HANDLE_ERROR_INFO DestroyPSQmf(HANDLE_PS_QMF_DATA* phPsQmfData) +{ + HANDLE_PS_QMF_DATA hPsQmfData = *phPsQmfData; + + if(hPsQmfData) { + FreeRam_PsRqmf(hPsQmfData->rQmfData); + FreeRam_PsIqmf(hPsQmfData->iQmfData); + FreeRam_PsQmfData(phPsQmfData); + } + + return noError; +} + + + +/* + name: static HANDLE_ERROR_INFO DestroyPSChannel + description: destroy PS channel data + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PS_CHANNEL_DATA *hPsChannelDAta + output: none +*/ + + +static HANDLE_ERROR_INFO DestroyPSChannel(HANDLE_PS_CHANNEL_DATA *phPsChannelData){ + + HANDLE_ERROR_INFO error = noError; + HANDLE_PS_CHANNEL_DATA hPsChannelData = *phPsChannelData; + + if(hPsChannelData != NULL){ + + DestroyPSQmf(&hPsChannelData->hPsQmfData); + + FDKsbrEnc_DeleteHybridFilterBank(&hPsChannelData->hHybAna); + + FDKsbrEnc_DestroyHybridData(&hPsChannelData->hHybData); + + FreeRam_PsChData(phPsChannelData); + } + + return error; +} + + +/* + name: static HANDLE_ERROR_INFO PSEnc_Destroy + description: destroy PS encoder handle + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO *hParametricStereo + output: none +*/ + +HANDLE_ERROR_INFO +PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO *phParametricStereo){ + + HANDLE_ERROR_INFO error = noError; + HANDLE_PARAMETRIC_STEREO hParametricStereo = *phParametricStereo; + INT i; + + if(hParametricStereo != NULL){ + for(i=0; i<MAX_PS_CHANNELS; i++){ + DestroyPSChannel(&(hParametricStereo->hPsChannelData[i])); + } + FreeRam_PsEnvRBuffer(&hParametricStereo->qmfDelayRealRef); + FreeRam_PsEnvIBuffer(&hParametricStereo->qmfDelayImagRef); + + FDKsbrEnc_DestroyPSEncode(&hParametricStereo->hPsEncode); + + FreeRam_PsOut(&hParametricStereo->hPsOut[0]); + FreeRam_PsOut(&hParametricStereo->hPsOut[1]); + + FreeRam_PsHybConfig(&hParametricStereo->hHybridConfig); + FreeRam_ParamStereo(phParametricStereo); + } + + return error; +} + +/* + name: static HANDLE_ERROR_INFO UpdatePSQmfData + description: updates buffer containing qmf data first/second halve + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo + output: - HANDLE_PARAMETRIC_STEREO hParametricStereo with updated qmf data +*/ + +static HANDLE_ERROR_INFO +UpdatePSQmfData_first(HANDLE_PARAMETRIC_STEREO hParametricStereo) +{ + HANDLE_ERROR_INFO error = noError; + int i, ch; + for (ch=0; ch<MAX_PS_CHANNELS; ch++) { + /* get qmf buffers */ + FIXP_QMF **RESTRICT realQmfData = hParametricStereo->hPsChannelData[ch]->hPsQmfData->rQmfData + QMF_READ_OFFSET; + FIXP_QMF **RESTRICT imagQmfData = hParametricStereo->hPsChannelData[ch]->hPsQmfData->iQmfData + QMF_READ_OFFSET; + + /* get needed parameters */ + INT nCols = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nCols; + INT nRows = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nRows; + + /* move processed buffer data nCols qmf samples forward */ + for(i=0; i<HYBRID_READ_OFFSET; i++){ + FDKmemcpy (realQmfData[i], realQmfData[i + nCols], sizeof(FIXP_QMF)*nRows ); + FDKmemcpy (imagQmfData[i], imagQmfData[i + nCols], sizeof(FIXP_QMF)*nRows ); + } + } + + return error; +} + +HANDLE_ERROR_INFO +UpdatePSQmfData_second(HANDLE_PARAMETRIC_STEREO hParametricStereo) +{ + HANDLE_ERROR_INFO error = noError; + int i, ch; + for (ch=0; ch<MAX_PS_CHANNELS; ch++) { + /* get qmf buffers */ + FIXP_QMF **RESTRICT realQmfData = hParametricStereo->hPsChannelData[ch]->hPsQmfData->rQmfData + QMF_READ_OFFSET; + FIXP_QMF **RESTRICT imagQmfData = hParametricStereo->hPsChannelData[ch]->hPsQmfData->iQmfData + QMF_READ_OFFSET; + + /* get needed parameters */ + INT writeOffset = hParametricStereo->hPsChannelData[ch]->hPsQmfData->bufferWriteOffset; + INT nCols = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nCols; + INT nRows = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nRows; + + /* move processed buffer data nCols qmf samples forward */ + for(i=HYBRID_READ_OFFSET; i<writeOffset; i++){ + FDKmemcpy (realQmfData[i], realQmfData[i + nCols], sizeof(FIXP_QMF)*nRows ); + FDKmemcpy (imagQmfData[i], imagQmfData[i + nCols], sizeof(FIXP_QMF)*nRows ); + } + } + + return error; +} + + + +/* + name: static HANDLE_ERROR_INFO UpdatePSHybridData + description: updates buffer containg PS hybrid data + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo + output: - HANDLE_PARAMETRIC_STEREO hParametricStereo with updated hybrid data +*/ + +static HANDLE_ERROR_INFO UpdatePSHybridData(HANDLE_PARAMETRIC_STEREO hParametricStereo) +{ + INT i, ch; + + for (ch=0; ch<MAX_PS_CHANNELS; ch++) { + HANDLE_PS_HYBRID_DATA hHybData = hParametricStereo->hPsChannelData[ch]->hHybData; + FIXP_QMF **realHybridData = hHybData->rHybData + HYBRID_DATA_READ_OFFSET; + FIXP_QMF **imagHybridData = hHybData->iHybData + HYBRID_DATA_READ_OFFSET; + INT writeOffset = hHybData->hybDataWriteOffset; + INT frameSize = hHybData->frameSize; + + for(i=0; i<writeOffset; i++){ + FDKmemcpy (realHybridData[i], realHybridData[i + frameSize], sizeof(FIXP_QMF)*HYBRID_NUM_BANDS ); + FDKmemcpy (imagHybridData[i], imagHybridData[i + frameSize], sizeof(FIXP_QMF)*HYBRID_NUM_BANDS ); + } + } + + return noError; +} + + +/* + name: static HANDLE_ERROR_INFO ExtractPSParameters + description: PS parameter extraction + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo + output: - HANDLE_PARAMETRIC_STEREO hParametricStereo PS parameter +*/ + +static HANDLE_ERROR_INFO +ExtractPSParameters(HANDLE_PARAMETRIC_STEREO hParametricStereo, const int sendHeader){ + + HANDLE_ERROR_INFO error = noError; + + if(error == noError){ + if(hParametricStereo == NULL){ + error = ERROR(CDI, "Invalid handle hParametricStereo."); + } + } + + /* call ps encode function */ + if(error == noError){ + if (hParametricStereo->initPS){ + *hParametricStereo->hPsOut[1] = *hParametricStereo->hPsOut[0]; + } + *hParametricStereo->hPsOut[0] = *hParametricStereo->hPsOut[1]; + + if(noError != (error = FDKsbrEnc_PSEncode(hParametricStereo->hPsEncode, + hParametricStereo->hPsOut[1], + hParametricStereo->hPsChannelData[0], + hParametricStereo->hPsChannelData[1], + hParametricStereo->dynBandScale, + hParametricStereo->maxEnvelopes, + sendHeader))){ + error = handBack(error); + } + if (hParametricStereo->initPS){ + *hParametricStereo->hPsOut[0] = *hParametricStereo->hPsOut[1]; + hParametricStereo->initPS = 0; + } + } + + return error; +} + + +/* + name: static HANDLE_ERROR_INFO DownmixPSQmfData + description: energy weighted downmix and hybrid synthesis + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo containing left and right channel qmf data + output: - HANDLE_PARAMETRIC_STEREO with updated qmf data buffer, hybrid data buffer + - FIXP_QMF **mixRealQmfData: pointer to buffer containing downmixed (real) qmf data + - FIXP_QMF **mixImagQmfData: pointer to buffer containing downmixed (imag) qmf data +*/ + +static HANDLE_ERROR_INFO +DownmixPSQmfData(HANDLE_PARAMETRIC_STEREO hParametricStereo, FIXP_QMF **RESTRICT mixRealQmfData, + FIXP_QMF **RESTRICT mixImagQmfData, SCHAR *downmixScale) +{ + HANDLE_ERROR_INFO error = noError; + int n, k; + int dynQmfScale, adjQmfScale; + int nQmfSamples=0, nQmfBands=0, nHybridQmfBands=0; + FIXP_QMF **RESTRICT leftRealQmfData = NULL; + FIXP_QMF **RESTRICT leftImagQmfData = NULL; + FIXP_QMF **RESTRICT rightRealQmfData = NULL; + FIXP_QMF **RESTRICT rightImagQmfData = NULL; + FIXP_QMF **RESTRICT leftRealHybridQmfData = NULL; + FIXP_QMF **RESTRICT leftImagHybridQmfData = NULL; + FIXP_QMF **RESTRICT rightRealHybridQmfData = NULL; + FIXP_QMF **RESTRICT rightImagHybridQmfData = NULL; + + if(hParametricStereo == NULL){ + error = ERROR(CDI, "Invalid handle hParametricStereo."); + } + + if(error == noError){ + /* Update first part of qmf buffers... + no whole buffer update possible; downmix is inplace */ + if(noError != (error = UpdatePSQmfData_first(hParametricStereo))){ + error = handBack(error); + } + } + + if(error == noError){ + /* get buffers: synchronize QMF buffers and hybrid buffers to compensate hybrid filter delay */ + /* hybrid filter bank looks nHybridFilterDelay qmf samples forward */ + leftRealQmfData = hParametricStereo->hPsChannelData[0]->hPsQmfData->rQmfData + HYBRID_READ_OFFSET; + leftImagQmfData = hParametricStereo->hPsChannelData[0]->hPsQmfData->iQmfData + HYBRID_READ_OFFSET; + rightRealQmfData = hParametricStereo->hPsChannelData[1]->hPsQmfData->rQmfData + HYBRID_READ_OFFSET; + rightImagQmfData = hParametricStereo->hPsChannelData[1]->hPsQmfData->iQmfData + HYBRID_READ_OFFSET; + + leftRealHybridQmfData = hParametricStereo->hPsChannelData[0]->hHybData->rHybData + HYBRID_WRITE_OFFSET; + leftImagHybridQmfData = hParametricStereo->hPsChannelData[0]->hHybData->iHybData + HYBRID_WRITE_OFFSET; + rightRealHybridQmfData = hParametricStereo->hPsChannelData[1]->hHybData->rHybData + HYBRID_WRITE_OFFSET; + rightImagHybridQmfData = hParametricStereo->hPsChannelData[1]->hHybData->iHybData + HYBRID_WRITE_OFFSET; + + /* get number of needed parameters */ + nQmfSamples = hParametricStereo->hPsChannelData[0]->hPsQmfData->nCols; + nQmfBands = hParametricStereo->hPsChannelData[0]->hPsQmfData->nRows; + nHybridQmfBands = FDKsbrEnc_GetNumberHybridQmfBands(hParametricStereo->hPsChannelData[0]->hHybData); + + /* define scalings */ + adjQmfScale = hParametricStereo->hPsChannelData[0]->hHybData->sf_fixpHybrid + - hParametricStereo->hPsChannelData[0]->psQmfScale; + + dynQmfScale = fixMax(0, hParametricStereo->dmxScale-1); /* scale one bit more for addition of left and right */ + + *downmixScale = hParametricStereo->hPsChannelData[0]->hHybData->sf_fixpHybrid - dynQmfScale + 1; + + const FIXP_DBL maxStereoScaleFactor = FL2FXCONST_DBL(2.0f/2.f); + + for(n = 0; n<nQmfSamples; n++){ + INT hybridDataOffset = 0; + + for(k = 0; k<nQmfBands; k++){ + INT l, nHybridSubBands; + FIXP_DBL tmpMixReal, tmpMixImag; + + if(k < nHybridQmfBands){ + /* process sub-subbands from hybrid qmf */ + nHybridSubBands = FDKsbrEnc_GetHybridResolution(hParametricStereo->hPsChannelData[0]->hHybData, k); + } else { + /* process qmf data */ + nHybridSubBands = 1; + } + + tmpMixReal = FL2FXCONST_DBL(0.f); + tmpMixImag = FL2FXCONST_DBL(0.f); + + for(l=0; l<nHybridSubBands; l++) { + int dynScale, sc; /* scaling */ + FIXP_QMF tmpLeftReal, tmpRightReal, tmpLeftImag, tmpRightImag; + FIXP_DBL tmpScaleFactor, stereoScaleFactor; + + if(k < nHybridQmfBands){ + /* process sub-subbands from hybrid qmf */ + tmpLeftReal = (leftRealHybridQmfData[n][hybridDataOffset + l]); + tmpLeftImag = (leftImagHybridQmfData[n][hybridDataOffset + l]); + tmpRightReal = (rightRealHybridQmfData[n][hybridDataOffset + l]); + tmpRightImag = (rightImagHybridQmfData[n][hybridDataOffset + l]); + dynScale = dynQmfScale; + } else { + /* process qmf data */ + tmpLeftReal = leftRealQmfData[n][k]; + tmpLeftImag = leftImagQmfData[n][k]; + tmpRightReal = rightRealQmfData[n][k]; + tmpRightImag = rightImagQmfData[n][k]; + dynScale = dynQmfScale-adjQmfScale; + } + + sc = fixMax(0,CntLeadingZeros( fixMax(fixMax(fixp_abs(tmpLeftReal),fixp_abs(tmpLeftImag)),fixMax(fixp_abs(tmpRightReal),fixp_abs(tmpRightImag))) )-2); + + tmpLeftReal <<= sc; tmpLeftImag <<= sc; + tmpRightReal <<= sc; tmpRightImag <<= sc; + dynScale = fixMin(sc-dynScale,DFRACT_BITS-1); + + /* calc stereo scale factor to avoid loss of energy in bands */ + /* stereo scale factor = min(2.0f, sqrt( (abs(l(k, n)^2 + abs(r(k, n)^2 )))/(0.5f*abs(l(k, n) + r(k, n))) )) */ + stereoScaleFactor = fPow2Div2(tmpLeftReal) + fPow2Div2(tmpLeftImag) + + fPow2Div2(tmpRightReal) + fPow2Div2(tmpRightImag) ; + + /* might be that tmpScaleFactor becomes negative, so fabs(.) */ + tmpScaleFactor = fixp_abs(stereoScaleFactor + fMult(tmpLeftReal,tmpRightReal) + fMult(tmpLeftImag,tmpRightImag)); + + /* min(2.0f, sqrt(stereoScaleFactor/(0.5f*tmpScaleFactor))) */ + if ( (stereoScaleFactor>>1) < fMult(maxStereoScaleFactor,tmpScaleFactor) ) { + + int sc_num = CountLeadingBits(stereoScaleFactor) ; + int sc_denum = CountLeadingBits(tmpScaleFactor) ; + sc = -(sc_num-sc_denum); + + tmpScaleFactor = schur_div((stereoScaleFactor<<(sc_num))>>1, + tmpScaleFactor<<sc_denum, + 16) ; + + /* prevent odd scaling for next sqrt calculation */ + if (sc&0x1) { + sc++; + tmpScaleFactor>>=1; + } + stereoScaleFactor = sqrtFixp(tmpScaleFactor); + stereoScaleFactor <<= (sc>>1); + } + else { + stereoScaleFactor = maxStereoScaleFactor; + } + + /* write data to output */ + tmpMixReal += fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftReal + tmpRightReal))>>dynScale; + tmpMixImag += fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftImag + tmpRightImag))>>dynScale; + } + + mixRealQmfData[n][k] = tmpMixReal; + mixImagQmfData[n][k] = tmpMixImag; + + hybridDataOffset += nHybridSubBands; + } + } + } /* if(error == noError) */ + + + if(error == noError){ + /* ... and update the hybrid data */ + if(noError != (error = UpdatePSHybridData(hParametricStereo))){ + error = handBack(error); + } + } + + return error; +} + + +/* + name: INT FDKsbrEnc_PSEnc_WritePSData() + description: writes ps_data() element to bitstream (hBitstream), returns number of written bits; + returns number of written bits only, if hBitstream == NULL + returns: number of bits in ps_data() + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo containing extracted ps parameters + output: - HANDLE_FDK_BITSTREAM containing ps_data() element +*/ + +INT +FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo, HANDLE_FDK_BITSTREAM hBitstream) +{ + + INT nBitsWritten = 0; + + if(hParametricStereo != NULL){ + nBitsWritten = FDKsbrEnc_WritePSBitstream(hParametricStereo->hPsOut[0], hBitstream); + } + + return nBitsWritten; +} + + +/* + name: static HANDLE_ERROR_INFO PSHybridAnalysis() + description: hybrid analysis filter bank of lowest qmf banks + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo containing qmf samples + output: - HANDLE_PARAMETRIC STEREO hParametricStereo also containing hybrid data +*/ + +static HANDLE_ERROR_INFO +PSHybridAnalysis(HANDLE_PARAMETRIC_STEREO hParametricStereo){ + + HANDLE_ERROR_INFO error = noError; + int ch; + + if(hParametricStereo == NULL){ + error = ERROR(CDI, "Invalid handle hParametricStereo."); + } + + for (ch=0; ch<MAX_PS_CHANNELS; ch++) { + if(error == noError){ + if(noError != (error = HybridAnalysis(hParametricStereo->hPsChannelData[ch]->hHybAna, + hParametricStereo->hPsChannelData[ch]->hPsQmfData->rQmfData + HYBRID_READ_OFFSET, + hParametricStereo->hPsChannelData[ch]->hPsQmfData->iQmfData + HYBRID_READ_OFFSET, + hParametricStereo->hPsChannelData[ch]->psQmfScale, + hParametricStereo->hPsChannelData[ch]->hHybData->rHybData + HYBRID_WRITE_OFFSET, + hParametricStereo->hPsChannelData[ch]->hHybData->iHybData + HYBRID_WRITE_OFFSET, + &hParametricStereo->hPsChannelData[ch]->hHybData->sf_fixpHybrid))){ + error = handBack(error); + } + } + } + + return error; +} + +/* + name: HANDLE_ERROR_INFO FDKsbrEnc_PSEnc_ParametricStereoProcessing + description: Complete PS Processing: + qmf + hybrid analysis of time domain data (left and right channel), + PS parameter extraction + downmix of qmf data + returns: error code of type HANDLE_ERROR_INFO + input: - HANDLE_PARAMETRIC_STEREO hParametricStereo + output: - HANDLE_PARAMETRIC STEREO hParametricStereo containing extracted PS parameters + - FIXP_DBL **qmfDataReal: Pointer to buffer containing downmixed, real qmf data + - FIXP_DBL **qmfDataImag: Pointer to buffer containing downmixed, imag qmf data + - INT_PCM **downsampledOutSignal: Pointer to buffer containing downmixed time signal + - SCHAR *qmfScale: Updated scale value for the QMF downmix data + +*/ + +HANDLE_ERROR_INFO +FDKsbrEnc_PSEnc_ParametricStereoProcessing(HANDLE_PARAMETRIC_STEREO hParametricStereo, + FIXP_QMF **RESTRICT qmfDataReal, + FIXP_QMF **RESTRICT qmfDataImag, + INT qmfOffset, + INT_PCM *downsampledOutSignal, + HANDLE_QMF_FILTER_BANK sbrSynthQmf, + SCHAR *qmfScale, + const int sendHeader) +{ + HANDLE_ERROR_INFO error = noError; + FIXP_QMF **downmixedRealQmfData = qmfDataReal+qmfOffset; + FIXP_QMF **downmixedImagQmfData = qmfDataImag+qmfOffset; + SCHAR dmScale = 0; + INT noQmfBands = hParametricStereo->noQmfBands; + + + if (error == noError) { + /* do ps hybrid analysis */ + if(noError != (error = PSHybridAnalysis(hParametricStereo))){ + error = handBack(error); + } + } + + /* find best scaling in new QMF and Hybrid data */ + psFindBestScaling( hParametricStereo, + hParametricStereo->dynBandScale, + hParametricStereo->maxBandValue, + &hParametricStereo->dmxScale ) ; + + + if(error == noError){ + /* extract the ps parameters */ + if(noError != (error = ExtractPSParameters(hParametricStereo, sendHeader))){ + error = handBack(error); + } + } + + if(error == noError){ + /* downmix and hybrid synthesis */ + if(noError != (error = DownmixPSQmfData(hParametricStereo, downmixedRealQmfData, downmixedImagQmfData, &dmScale))){ + error = handBack(error); + } + } + + + if (error == noError) + { + C_ALLOC_SCRATCH_START(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); + /* + + QMF synthesis including downsampling + + */ + QMF_SCALE_FACTOR tmpScale; + int scale = -dmScale; + tmpScale.lb_scale = scale; + tmpScale.ov_lb_scale = scale; + tmpScale.hb_scale = scale; + tmpScale.ov_hb_scale = 0; + + qmfSynthesisFiltering( sbrSynthQmf, + downmixedRealQmfData, + downmixedImagQmfData, + &tmpScale, + 0, + downsampledOutSignal, + 1, + qmfWorkBuffer ); + + C_ALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); + + + } + + /* scaling in sbr module differs -> scaling update */ + *qmfScale = -dmScale + 7; + + + /* + * Do PS to SBR QMF data transfer/scaling buffer shifting, delay lines etc. + */ + { + INT noQmfSlots2 = hParametricStereo->noQmfSlots>>1; + + FIXP_QMF r_tmp1; + FIXP_QMF i_tmp1; + FIXP_QMF **delayQmfReal = hParametricStereo->qmfDelayReal; + FIXP_QMF **delayQmfImag = hParametricStereo->qmfDelayImag; + INT scale, i, j; + + if (hParametricStereo->qmfDelayScale > *qmfScale) { + scale = hParametricStereo->qmfDelayScale - *qmfScale; + + for (i=0; i<noQmfSlots2; i++) { + for (j=0; j<noQmfBands; j++) { + r_tmp1 = qmfDataReal[i][j]; + i_tmp1 = qmfDataImag[i][j]; + + qmfDataReal[i][j] = delayQmfReal[i][j] >> scale; + qmfDataImag[i][j] = delayQmfImag[i][j] >> scale; + delayQmfReal[i][j] = qmfDataReal[i+noQmfSlots2][j]; + delayQmfImag[i][j] = qmfDataImag[i+noQmfSlots2][j]; + qmfDataReal[i+noQmfSlots2][j] = r_tmp1; + qmfDataImag[i+noQmfSlots2][j] = i_tmp1; + } + } + hParametricStereo->qmfDelayScale = *qmfScale; + } + else { + scale = *qmfScale - hParametricStereo->qmfDelayScale; + for (i=0; i<noQmfSlots2; i++) { + for (j=0; j<noQmfBands; j++) { + r_tmp1 = qmfDataReal[i][j]; + i_tmp1 = qmfDataImag[i][j]; + + qmfDataReal[i][j] = delayQmfReal[i][j]; + qmfDataImag[i][j] = delayQmfImag[i][j]; + delayQmfReal[i][j] = qmfDataReal[i+noQmfSlots2][j]; + delayQmfImag[i][j] = qmfDataImag[i+noQmfSlots2][j]; + qmfDataReal[i+noQmfSlots2][j] = r_tmp1 >> scale; + qmfDataImag[i+noQmfSlots2][j] = i_tmp1 >> scale; + } + } + scale = *qmfScale; + *qmfScale = hParametricStereo->qmfDelayScale; + hParametricStereo->qmfDelayScale = scale; + } + } + + return error; +} + +static void psFindBestScaling(HANDLE_PARAMETRIC_STEREO hParametricStereo, + UCHAR *RESTRICT dynBandScale, + FIXP_QMF *RESTRICT maxBandValue, + SCHAR *RESTRICT dmxScale) +{ + HANDLE_PS_ENCODE hPsEncode = hParametricStereo->hPsEncode; + HANDLE_PS_HYBRID_DATA hHybDatal = hParametricStereo->hPsChannelData[0]->hHybData; + + INT group, bin, border, col, band; + INT frameSize = FDKsbrEnc_GetHybridFrameSize(hHybDatal); /* same as FDKsbrEnc_GetHybridFrameSize(hHybDatar) */ + INT psBands = (INT) hPsEncode->psEncMode; + INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; + + FIXP_QMF **lr = hParametricStereo->hPsChannelData[0]->hHybData->rHybData; + FIXP_QMF **li = hParametricStereo->hPsChannelData[0]->hHybData->iHybData; + FIXP_QMF **rr = hParametricStereo->hPsChannelData[1]->hHybData->rHybData; + FIXP_QMF **ri = hParametricStereo->hPsChannelData[1]->hHybData->iHybData; + FIXP_QMF **lrBuffer = hParametricStereo->hPsChannelData[0]->hPsQmfData->rQmfData; + FIXP_QMF **liBuffer = hParametricStereo->hPsChannelData[0]->hPsQmfData->iQmfData; + FIXP_QMF **rrBuffer = hParametricStereo->hPsChannelData[1]->hPsQmfData->rQmfData; + FIXP_QMF **riBuffer = hParametricStereo->hPsChannelData[1]->hPsQmfData->iQmfData; + + /* group wise scaling */ + FIXP_QMF maxVal [2][PS_MAX_BANDS]; + FIXP_QMF maxValue = FL2FXCONST_DBL(0.f); + + INT nHybridQmfOffset = 0; + + UCHAR switched = 0; + + FDKmemclear(maxVal, sizeof(maxVal)); + + /* start with hybrid data */ + for (group=0; group < nIidGroups; group++) { + /* Translate group to bin */ + bin = hPsEncode->subband2parameterIndex[group]; + + if (!switched && group == hPsEncode->nSubQmfIidGroups) { + /* switch to qmf data */ + lr = lrBuffer; li = liBuffer; + rr = rrBuffer; ri = riBuffer; + + /* calc offset between hybrid subsubbands and qmf bands */ + nHybridQmfOffset = FDKsbrEnc_GetNumberHybridQmfBands(hHybDatal) - FDKsbrEnc_GetNumberHybridBands(hHybDatal); + switched = 1; + } + + /* Translate from 20 bins to 10 bins */ + if (hPsEncode->psEncMode == PS_BANDS_COARSE) { + bin >>= 1; + } + + /* determine group border */ + border = hPsEncode->iidGroupBorders[group+1]; + + /* QMF downmix scaling */ + { + FIXP_QMF tmp = maxVal[0][bin]; + int i; + for (col=HYBRID_READ_OFFSET; col<frameSize; col++) { + FIXP_QMF *pLR = &lr[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pLI = &li[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pRR = &rr[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pRI = &ri[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + for (i = 0; i<border-hPsEncode->iidGroupBorders[group]; i++) { + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLR++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLI++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRR++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRI++)); + } + } + maxVal[0][bin] = tmp; + + tmp = maxVal[1][bin]; + for (col=frameSize; col<HYBRID_READ_OFFSET+frameSize; col++) { + FIXP_QMF *pLR = &lr[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pLI = &li[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pRR = &rr[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + FIXP_QMF *pRI = &ri[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; + for (i = 0; i<border-hPsEncode->iidGroupBorders[group]; i++) { + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLR++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLI++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRR++)); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRI++)); + } + } + maxVal[1][bin] = tmp; + } + } /* nIidGroups */ + + /* convert maxSpec to maxScaling, find scaling space */ + for (band=0; band<psBands; band++) { +#ifndef MULT_16x16 + dynBandScale[band] = CountLeadingBits(fixMax(maxVal[0][band],maxBandValue[band])); +#else + dynBandScale[band] = fixMax(0,CountLeadingBits(fixMax(maxVal[0][band],maxBandValue[band]))-FRACT_BITS); +#endif + maxValue = fixMax(maxValue,fixMax(maxVal[0][band],maxVal[1][band])); + maxBandValue[band] = fixMax(maxVal[0][band], maxVal[1][band]); + } + + /* calculate maximal scaling for QMF downmix */ +#ifndef MULT_16x16 + *dmxScale = fixMin(DFRACT_BITS, CountLeadingBits(maxValue)); +#else + *dmxScale = fixMax(0,fixMin(FRACT_BITS, CountLeadingBits(FX_QMF2FX_DBL(maxValue)))); +#endif + +} + diff --git a/libSBRenc/src/ps_main.h b/libSBRenc/src/ps_main.h new file mode 100644 index 0000000..b2fac92 --- /dev/null +++ b/libSBRenc/src/ps_main.h @@ -0,0 +1,160 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial Authors: Markus Multrus + Contents/Description: PS Wrapper, Downmix header file + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#ifndef __INCLUDED_PS_MAIN_H +#define __INCLUDED_PS_MAIN_H + +/* Includes ******************************************************************/ +#include "sbr_def.h" +#include "psenc_hybrid.h" +#include "ps_encode.h" +#include "FDK_bitstream.h" + +/* Data Types ****************************************************************/ +typedef enum { + PSENC_STEREO_BANDS_INVALID = 0, + PSENC_STEREO_BANDS_10 = 10, + PSENC_STEREO_BANDS_20 = 20, + PSENC_STEREO_BANDS_34 = 34 +} PSENC_STEREO_BANDS_CONFIG; + +typedef enum { + PSENC_NENV_1 = 1, + PSENC_NENV_2 = 2, + PSENC_NENV_4 = 4, + PSENC_NENV_DEFAULT = PSENC_NENV_2, + PSENC_NENV_MAX = PSENC_NENV_4 +} PSENC_NENV_CONFIG; + +#define MAX_PS_CHANNELS ( 2 ) +#define PSENC_QMF_BUFFER_LENGTH ( 48 ) + +typedef struct { + + UINT bitrateFrom; /* inclusive */ + UINT bitrateTo; /* exclusive */ + PSENC_STEREO_BANDS_CONFIG nStereoBands; + PSENC_NENV_CONFIG nEnvelopes; + LONG iidQuantErrorThreshold; /* quantization threshold to switch between coarse and fine iid quantization */ + +} psTuningTable_t; + +/* Function / Class Declarations *********************************************/ + +typedef struct T_PS_QMF_DATA +{ + FIXP_QMF *rQmfData[PSENC_QMF_BUFFER_LENGTH]; + FIXP_QMF *iQmfData[PSENC_QMF_BUFFER_LENGTH]; + INT nCols; + INT nRows; + INT bufferReadOffset; + INT bufferReadOffsetHybrid; + INT bufferWriteOffset; + INT bufferLength; +} PS_QMF_DATA, *HANDLE_PS_QMF_DATA; + +typedef struct T_PS_CHANNEL_DATA { + HANDLE_PS_QMF_DATA hPsQmfData; + + int psQmfScale; + HANDLE_PS_HYBRID_DATA hHybData; + HANDLE_PS_HYBRID hHybAna; + INT psChannelDelay; /* delay in samples */ +} PS_CHANNEL_DATA, *HANDLE_PS_CHANNEL_DATA; + +typedef struct T_PARAMETRIC_STEREO { + + HANDLE_PS_HYBRID_CONFIG hHybridConfig; + HANDLE_PS_CHANNEL_DATA hPsChannelData[MAX_PS_CHANNELS]; + HANDLE_PS_ENCODE hPsEncode; + HANDLE_PS_OUT hPsOut[2]; + + FIXP_QMF *qmfDelayReal[QMF_MAX_TIME_SLOTS>>1]; + FIXP_QMF *qmfDelayImag[QMF_MAX_TIME_SLOTS>>1]; + FIXP_QMF *qmfDelayRealRef; + FIXP_QMF *qmfDelayImagRef; + int qmfDelayScale; + + INT psDelay; + UINT maxEnvelopes; + UCHAR dynBandScale[PS_MAX_BANDS]; + FIXP_DBL maxBandValue[PS_MAX_BANDS]; + SCHAR dmxScale; + INT initPS; + INT noQmfSlots; + INT noQmfBands; + +} PARAMETRIC_STEREO; + + + +typedef struct T_PSENC_CONFIG { + + INT frameSize; + INT qmfFilterMode; + INT sbrPsDelay; + PSENC_STEREO_BANDS_CONFIG nStereoBands; + PSENC_NENV_CONFIG maxEnvelopes; + FIXP_DBL iidQuantErrorThreshold; + +} PSENC_CONFIG, *HANDLE_PSENC_CONFIG; + +typedef struct T_PARAMETRIC_STEREO *HANDLE_PARAMETRIC_STEREO; + + +HANDLE_ERROR_INFO +PSEnc_Create(HANDLE_PARAMETRIC_STEREO *phParametricStereo); + +HANDLE_ERROR_INFO +PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_PSENC_CONFIG hPsEncConfig, + INT noQmfSlots, + INT noQmfBands + ,UCHAR *dynamic_RAM + ); + +HANDLE_ERROR_INFO +UpdatePSQmfData_second(HANDLE_PARAMETRIC_STEREO hParametricStereo); + +HANDLE_ERROR_INFO +PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO *hParametricStereo); + + +HANDLE_ERROR_INFO +FDKsbrEnc_PSEnc_ParametricStereoProcessing(HANDLE_PARAMETRIC_STEREO hParametricStereo, + FIXP_QMF **RESTRICT qmfRealData, + FIXP_QMF **RESTRICT qmfImagData, + INT qmfOffset, + INT_PCM *downsampledOutSignal, + HANDLE_QMF_FILTER_BANK sbrSynthQmf, + SCHAR *qmfScale, + const int sendHeader); + +INT +FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo, HANDLE_FDK_BITSTREAM hBitstream); + +#endif /* __INCLUDED_PS_MAIN_H */ diff --git a/libSBRenc/src/psenc_hybrid.cpp b/libSBRenc/src/psenc_hybrid.cpp new file mode 100644 index 0000000..a314678 --- /dev/null +++ b/libSBRenc/src/psenc_hybrid.cpp @@ -0,0 +1,836 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: M. Neuendorf, M. Multrus + contents/description: hybrid analysis filter bank + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "psenc_hybrid.h" + + +/* Includes ******************************************************************/ + +#include "psenc_hybrid.h" +#include "sbr_ram.h" + +#include "fft.h" + +#include "genericStds.h" + +/* Defines *******************************************************************/ + +#define HYBRID_SCALE 4 + +/*//#define FAST_FILTER2 +#define FAST_FILTER4 +#define FAST_FILTER8 +#define FAST_FILTER12 +*/ +#define HYBRID_INVERSE_ORDER ( 0x0F000000 ) +#define HYBRID_INVERSE_MASK ( ~HYBRID_INVERSE_ORDER ) + +//#define REAL ( 0 ) +//#define CPLX ( 1 ) + +#define cos0Pi FL2FXCONST_DBL( 1.f) +#define sin0Pi FL2FXCONST_DBL( 0.f) +#define cos1Pi FL2FXCONST_DBL(-1.f) +#define sin1Pi FL2FXCONST_DBL( 0.f) +#define cos1Pi_2 FL2FXCONST_DBL( 0.f) +#define sin1Pi_2 FL2FXCONST_DBL( 1.f) +#define cos1Pi_3 FL2FXCONST_DBL( 0.5f) +#define sin1Pi_3 FL2FXCONST_DBL( 0.86602540378444f) + +#define cos0Pi_4 cos0Pi +#define cos1Pi_4 FL2FXCONST_DBL(0.70710678118655f) +#define cos2Pi_4 cos1Pi_2 +#define cos3Pi_4 (-cos1Pi_4) +#define cos4Pi_4 (-cos0Pi_4) +#define cos5Pi_4 cos3Pi_4 +#define cos6Pi_4 cos2Pi_4 + +#define sin0Pi_4 sin0Pi +#define sin1Pi_4 FL2FXCONST_DBL(0.70710678118655f) +#define sin2Pi_4 sin1Pi_2 +#define sin3Pi_4 sin1Pi_4 +#define sin4Pi_4 sin0Pi_4 +#define sin5Pi_4 (-sin3Pi_4) +#define sin6Pi_4 (-sin2Pi_4) + +#define cos0Pi_8 cos0Pi +#define cos1Pi_8 FL2FXCONST_DBL(0.92387953251129f) +#define cos2Pi_8 cos1Pi_4 +#define cos3Pi_8 FL2FXCONST_DBL(0.38268343236509f) +#define cos4Pi_8 cos2Pi_4 +#define cos5Pi_8 (-cos3Pi_8) +#define cos6Pi_8 (-cos2Pi_8) + +#define sin0Pi_8 sin0Pi +#define sin1Pi_8 cos3Pi_8 +#define sin2Pi_8 sin1Pi_4 +#define sin3Pi_8 cos1Pi_8 +#define sin4Pi_8 sin2Pi_4 +#define sin5Pi_8 sin3Pi_8 +#define sin6Pi_8 sin1Pi_4 + +#define cos0Pi_12 cos0Pi +#define cos1Pi_12 FL2FXCONST_DBL(0.96592582628906f) +#define cos2Pi_12 FL2FXCONST_DBL(0.86602540378444f) +#define cos3Pi_12 cos1Pi_4 +#define cos4Pi_12 cos1Pi_3 +#define cos5Pi_12 FL2FXCONST_DBL(0.25881904510252f) +#define cos6Pi_12 cos1Pi_2 + +#define sin0Pi_12 sin0Pi +#define sin1Pi_12 cos5Pi_12 +#define sin2Pi_12 cos4Pi_12 +#define sin3Pi_12 sin1Pi_4 +#define sin4Pi_12 sin1Pi_3 +#define sin5Pi_12 cos1Pi_12 +#define sin6Pi_12 sin1Pi_2 + +#define FFT_IDX_R(a) (2*a) +#define FFT_IDX_I(a) (2*a+1) + + +/* Constants *****************************************************************/ + +/* static const UINT noQmfBandsInHybrid34 = 5; */ + +static const INT aHybridResolution10[] = { HYBRID_6_CPLX, + HYBRID_2_REAL | HYBRID_INVERSE_ORDER, + HYBRID_2_REAL }; + +static const INT aHybridResolution20[] = { HYBRID_6_CPLX, + HYBRID_2_REAL | HYBRID_INVERSE_ORDER, + HYBRID_2_REAL }; + +/*static const INT aHybridResolution34[] = { HYBRID_12_CPLX, + HYBRID_8_CPLX, + HYBRID_4_CPLX, + HYBRID_4_CPLX, + HYBRID_4_CPLX };*/ + +static const FIXP_DBL p8_13_20[HYBRID_FILTER_LENGTH] = +{ + FL2FXCONST_DBL(0.00746082949812f), FL2FXCONST_DBL(0.02270420949825f), FL2FXCONST_DBL(0.04546865930473f), FL2FXCONST_DBL(0.07266113929591f), + FL2FXCONST_DBL(0.09885108575264f), FL2FXCONST_DBL(0.11793710567217f), FL2FXCONST_DBL(0.125f ), FL2FXCONST_DBL(0.11793710567217f), + FL2FXCONST_DBL(0.09885108575264f), FL2FXCONST_DBL(0.07266113929591f), FL2FXCONST_DBL(0.04546865930473f), FL2FXCONST_DBL(0.02270420949825f), + FL2FXCONST_DBL(0.00746082949812f) +}; + +static const FIXP_DBL p2_13_20[HYBRID_FILTER_LENGTH] = +{ + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL( 0.01899487526049f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(-0.07293139167538f), + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL( 0.30596630545168f), FL2FXCONST_DBL(0.5f), FL2FXCONST_DBL( 0.30596630545168f), + FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(-0.07293139167538f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL( 0.01899487526049f), + FL2FXCONST_DBL(0.0f) +}; + + +/*static const float p12_13_34[HYBRID_FILTER_LENGTH] = +{ + 0.04081179924692, 0.03812810994926, 0.05144908135699, 0.06399831151592, + 0.07428313801106, 0.08100347892914, 0.08333333333333, 0.08100347892914, + 0.07428313801106, 0.06399831151592, 0.05144908135699, 0.03812810994926, + 0.04081179924692 +}; + +static const float p8_13_34[HYBRID_FILTER_LENGTH] = +{ + 0.01565675600122, 0.03752716391991, 0.05417891378782, 0.08417044116767, + 0.10307344158036, 0.12222452249753, 0.12500000000000, 0.12222452249753, + 0.10307344158036, 0.08417044116767, 0.05417891378782, 0.03752716391991, + 0.01565675600122 +}; + +static const float p4_13_34[HYBRID_FILTER_LENGTH] = +{ + -0.05908211155639, -0.04871498374946, 0.0, 0.07778723915851, + 0.16486303567403, 0.23279856662996, 0.25, 0.23279856662996, + 0.16486303567403, 0.07778723915851, 0.0, -0.04871498374946, + -0.05908211155639 +};*/ + + +/* Function / Class Implementation *******************************************/ + + + +/*****************************************************************************/ +/* **** FILTERBANK CONFIG **** */ + +HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridConfig(HANDLE_PS_HYBRID_CONFIG *phHybConfig, + PS_BANDS mode) +{ + HANDLE_ERROR_INFO error = noError; + HANDLE_PS_HYBRID_CONFIG h = NULL; + UINT k = 0; + + if (error == noError) { + h = *phHybConfig; /* Simplify your life */ + h->mode = mode; + + switch (mode) { + case PS_BANDS_MID: + h->noQmfBandsInHybrid = NO_QMF_BANDS_HYBRID_20; + for (k=0; k<h->noQmfBandsInHybrid; k++) { + h->aHybridResolution[k] = aHybridResolution20[k]; + } + break; + + case PS_BANDS_FINE: + /*h->noQmfBandsInHybrid = noQmfBandsInHybrid34; + for (k=0; k<h->noQmfBandsInHybrid; k++) { + h->aHybridResolution[k] = aHybridResolution34[k]; + }*/ + FDK_ASSERT(0); /* we don't support! */ + break; + + case PS_BANDS_COARSE: + h->noQmfBandsInHybrid = NO_QMF_BANDS_HYBRID_10; + for (k=0; k<h->noQmfBandsInHybrid; k++) { + h->aHybridResolution[k] = aHybridResolution10[k]; + } + break; + + default: + error = ERROR(CDI, "Invalid hybrid filter bank configuration."); + break; + } + } + + return error; +} + +/*****************************************************************************/ +/* **** FILTERBANK DATA **** */ + +HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridData(HANDLE_PS_HYBRID_DATA *phHybData, + INT ch) +{ + HANDLE_ERROR_INFO error = noError; + int k; + + HANDLE_PS_HYBRID_DATA hHybData = GetRam_HybData(ch); + if (hHybData==NULL) { + error = 1; + goto bail; + } + + FDKmemclear(hHybData, sizeof(PS_HYBRID_DATA)); + + hHybData->rHybData[0] = GetRam_PsRhyb(ch); + hHybData->iHybData[0] = GetRam_PsIhyb(ch); + if ( (hHybData->rHybData[0]==NULL) || (hHybData->iHybData[0]==NULL) ) { + error = 1; + goto bail; + } + + + + for (k=1; k<(HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET); k++) { + hHybData->rHybData[k] = hHybData->rHybData[0] + (k*HYBRID_NUM_BANDS); + hHybData->iHybData[k] = hHybData->iHybData[0] + (k*HYBRID_NUM_BANDS); + } + +bail: + *phHybData = hHybData; + return error; +} + + +HANDLE_ERROR_INFO FDKsbrEnc_InitHybridData(HANDLE_PS_HYBRID_DATA hHybData, + HANDLE_PS_HYBRID_CONFIG hHybConfig, + INT frameSize) +{ + HANDLE_ERROR_INFO error = noError; + INT nHybridBands = 0; + INT k = 0; + INT noBands = 0; + const INT *hybridRes = NULL; + + if (hHybConfig != NULL) { + noBands = hHybConfig->noQmfBandsInHybrid; + hybridRes = hHybConfig->aHybridResolution; + } + + for (k=0; k<noBands; k++) { + nHybridBands += (hybridRes[k] & HYBRID_INVERSE_MASK); + } + FDK_ASSERT (HYBRID_NUM_BANDS>=nHybridBands); + + hHybData->hybDataReadOffset = HYBRID_DATA_READ_OFFSET; + hHybData->hybDataWriteOffset = HYBRID_WRITEOFFSET; + + for (k=0; k<(HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET); k++) { + FDKmemclear(hHybData->rHybData[k], sizeof(FIXP_QMF)*HYBRID_NUM_BANDS); + FDKmemclear(hHybData->iHybData[k], sizeof(FIXP_QMF)*HYBRID_NUM_BANDS); + } + + hHybData->frameSize = frameSize; + hHybData->nHybridBands = nHybridBands; + hHybData->nHybridQmfBands = noBands; + + /* store hybrid resoltion in hybrid data handle */ + FDK_ASSERT (HYBRID_MAX_QMF_BANDS>=hHybData->nHybridQmfBands); + for(k = 0; k<hHybData->nHybridQmfBands; k++){ + hHybData->nHybridResolution[k] = (hybridRes[k] & HYBRID_INVERSE_MASK); + } + + return error; +} + +HANDLE_ERROR_INFO FDKsbrEnc_DestroyHybridData(HANDLE_PS_HYBRID_DATA* phHybData) +{ + HANDLE_PS_HYBRID_DATA hHybData = *phHybData; + + if (hHybData!=NULL) { + FreeRam_PsRhyb(&hHybData->rHybData[0]); + FreeRam_PsIhyb(&hHybData->iHybData[0]); + FreeRam_HybData(phHybData); + } + + return noError; +} + +/*** Access functions ***/ + +/* return hybrid band resolution of qmf band 'qmfBand' */ +INT FDKsbrEnc_GetHybridResolution(HANDLE_PS_HYBRID_DATA h, INT qmfBand){ + + INT nHybridResolution = 0; + + if(h->nHybridResolution){ + nHybridResolution = h->nHybridResolution[qmfBand]; + } + + return nHybridResolution; +} + +/*****************************************************************************/ +/* **** FILTERBANK **** */ + +/* + 2 channel filter + Filter Coefs: + 0.0, + 0.01899487526049, + 0.0, + -0.07293139167538, + 0.0, + 0.30596630545168, + 0.5, + 0.30596630545168, + 0.0, + -0.07293139167538, + 0.0, + 0.01899487526049, + 0.0 + + + Filter design: + h[q,n] = g[n] * cos(2pi/2 * q * (n-6) ); n = 0..12, q = 0,1; + + -> h[0,n] = g[n] * 1; + -> h[1,n] = g[n] * pow(-1,n); + +*/ + +static void dualChannelFiltering(const FIXP_QMF *RESTRICT pQmfReal, + const FIXP_QMF *RESTRICT pQmfImag, + FIXP_QMF **RESTRICT mHybridReal, + FIXP_QMF **RESTRICT mHybridImag, + INT nSamples) +{ + INT i; + + for(i = 0; i < nSamples; i++) { + FIXP_DBL r1, r3, r5, r6; + FIXP_DBL i1, i3, i5, i6; + + /* symmetric filter coefficients + scaleValue same as used in eightChannelFiltering (HYBRID_SCALE = 4) + */ + r1 = fMultDiv2(p2_13_20[1], (FIXP_QMF)((pQmfReal[1+i]>>1) + (pQmfReal[11+i]>>1)) ) >> 2; + r3 = fMultDiv2(p2_13_20[3], (FIXP_QMF)((pQmfReal[3+i]>>1) + (pQmfReal[ 9+i]>>1)) ) >> 2; + r5 = fMultDiv2(p2_13_20[5], (FIXP_QMF)((pQmfReal[5+i]>>1) + (pQmfReal[ 7+i]>>1)) ) >> 2; + r6 = fMultDiv2(p2_13_20[6], (FIXP_QMF) (pQmfReal[6+i]>>1) ) >> 2; + + i1 = fMultDiv2(p2_13_20[1], (FIXP_QMF)((pQmfImag[1+i]>>1) + (pQmfImag[11+i]>>1)) ) >> 2; + i3 = fMultDiv2(p2_13_20[3], (FIXP_QMF)((pQmfImag[3+i]>>1) + (pQmfImag[ 9+i]>>1)) ) >> 2; + i5 = fMultDiv2(p2_13_20[5], (FIXP_QMF)((pQmfImag[5+i]>>1) + (pQmfImag[ 7+i]>>1)) ) >> 2; + i6 = fMultDiv2(p2_13_20[6], (FIXP_QMF) (pQmfImag[6+i]>>1) ) >> 2; + + mHybridReal[i][0] = FX_DBL2FX_QMF(r1 + r3 + r5 + r6); + mHybridImag[i][0] = FX_DBL2FX_QMF(i1 + i3 + i5 + i6); + + mHybridReal[i][1] = FX_DBL2FX_QMF(- r1 - r3 - r5 + r6); + mHybridImag[i][1] = FX_DBL2FX_QMF(- i1 - i3 - i5 + i6); + } +} + +/* + 8 channel filter + + Implementation using a FFT of length 8 + + prototype filter coefficients: + 0.00746082949812 0.02270420949825 0.04546865930473 0.07266113929591 0.09885108575264 0.11793710567217 + 0.125 + 0.11793710567217 0.09885108575264 0.07266113929591 0.04546865930473 0.02270420949825 0.00746082949812 + + Filter design: + N = 13; Q = 8; + h[q,n] = g[n] * exp(j * 2 * pi / Q * (q + .5) * (n - 6)); n = 0..(N-1), q = 0..(Q-1); + + Time Signal: x[t]; + Filter Bank Output + y[q,t] = conv(x[t],h[q,t]) = conv(h[q,t],x[t]) = sum(x[k] * h[q, t - k] ) = sum(h[q, k] * x[t - k] ); k = 0..(N-1); + + y[q,t] = x[t - 12]*h[q, 12] + x[t - 11]*h[q, 11] + x[t - 10]*h[q, 10] + x[t - 9]*h[q, 9] + + x[t - 8]*h[q, 8] + x[t - 7]*h[q, 7] + + x[t - 6]*h[q, 6] + + x[t - 5]*h[q, 5] + x[t - 4]*h[q, 4] + + x[t - 3]*h[q, 3] + x[t - 2]*h[q, 2] + x[t - 1]*h[q, 1] + x[t - 0]*h[q, 0]; + + h'[q, n] = h[q,(N-1)-n] = g[n] * exp(j * 2 * pi / Q * (q + .5) * (6 - n)); n = 0..(N-1), q = 0..(Q-1); + + y[q,t] = x[t - 12]*h'[q, 0] + x[t - 11]*h'[q, 1] + x[t - 10]*h'[q, 2] + x[t - 9]*h'[q, 3] + + x[t - 8]*h'[q, 4] + x[t - 7]*h'[q, 5] + + x[t - 6]*h'[q, 6] + + x[t - 5]*h'[q, 7] + x[t - 4]*h'[q, 8] + + x[t - 3]*h'[q, 9] + x[t - 2]*h'[q, 10] + x[t - 1]*h'[q, 11] + x[t - 0]*h'[q, 12]; + + Try to split off FFT Modulation Term: + FFT(x[t], q) = sum(x[t+k]*exp(-j*2*pi/N *q * k)) + c m + Step 1: h'[q,n] = g[n] * ( exp(j * 2 * pi / 8 * .5 * (6 - n)) ) * ( exp (j * 2 * pi / 8 * q * (6 - n)) ); + + h'[q,n] = g[n] *c[n] * m[q,n]; (see above) + c[n] = exp( j * 2 * pi / 8 * .5 * (6 - n) ); + m[q,n] = exp( j * 2 * pi / 8 * q * (6 - n) ); + + y[q,t] = x[t - 0]*g[0]*c[0]*m[q,0] + x[t - 1]*g[1]*c[ 1]*m[q, 1] + ... + ... + x[t - 12]*g[2]*c[12]*m[q,12]; + + | + n m *exp(-j*2*pi) | n' fft +------------------------------------------------------------------------------------------------------------------------- + 0 exp( j * 2 * pi / 8 * q * 6) -> exp(-j * 2 * pi / 8 * q * 2) | 2 exp(-j * 2 * pi / 8 * q * 0) + 1 exp( j * 2 * pi / 8 * q * 5) -> exp(-j * 2 * pi / 8 * q * 3) | 3 exp(-j * 2 * pi / 8 * q * 1) + 2 exp( j * 2 * pi / 8 * q * 4) -> exp(-j * 2 * pi / 8 * q * 4) | 4 exp(-j * 2 * pi / 8 * q * 2) + 3 exp( j * 2 * pi / 8 * q * 3) -> exp(-j * 2 * pi / 8 * q * 5) | 5 exp(-j * 2 * pi / 8 * q * 3) + 4 exp( j * 2 * pi / 8 * q * 2) -> exp(-j * 2 * pi / 8 * q * 6) | 6 exp(-j * 2 * pi / 8 * q * 4) + 5 exp( j * 2 * pi / 8 * q * 1) -> exp(-j * 2 * pi / 8 * q * 7) | 7 exp(-j * 2 * pi / 8 * q * 5) + 6 exp( j * 2 * pi / 8 * q * 0) | 0 exp(-j * 2 * pi / 8 * q * 6) + 7 exp(-j * 2 * pi / 8 * q * 1) | 1 exp(-j * 2 * pi / 8 * q * 7) + 8 exp(-j * 2 * pi / 8 * q * 2) | 2 + 9 exp(-j * 2 * pi / 8 * q * 3) | 3 + 10 exp(-j * 2 * pi / 8 * q * 4) | 4 + 11 exp(-j * 2 * pi / 8 * q * 5) | 5 + 12 exp(-j * 2 * pi / 8 * q * 6) | 6 + + + now use fft modulation coefficients + m[6] = = fft[0] + m[7] = = fft[1] + m[8] = m[ 0] = fft[2] + m[9] = m[ 1] = fft[3] + m[10] = m[ 2] = fft[4] + m[11] = m[ 3] = fft[5] + m[12] = m[ 4] = fft[6] + m[ 5] = fft[7] + + y[q,t] = ( x[t- 6]*g[ 6]*c[ 6] ) * fft[q,0] + + ( x[t- 7]*g[ 7]*c[ 7] ) * fft[q,1] + + ( x[t- 0]*g[ 0]*c[ 0] + x[t- 8]*g[ 8]*c[ 8] ) * fft[q,2] + + ( x[t- 1]*g[ 1]*c[ 1] + x[t- 9]*g[ 9]*c[ 9] ) * fft[q,3] + + ( x[t- 2]*g[ 2]*c[ 2] + x[t-10]*g[10]*c[10] ) * fft[q,4] + + ( x[t- 3]*g[ 3]*c[ 3] + x[t-11]*g[11]*c[11] ) * fft[q,5] + + ( x[t- 4]*g[ 4]*c[ 4] + x[t-12]*g[12]*c[12] ) * fft[q,6] + + ( x[t- 5]*g[ 5]*c[ 5] ) * fft[q,7]; + + pre twiddle factors c[n] = exp(j * 2 * pi / 8 * .5 * (6 - n)); + n c] | n c[n] | n c[n] +--------------------------------------------------------------------------------------------------- + 0 exp( j * 6 * pi / 8) | 1 exp( j * 5 * pi / 8) | 2 exp( j * 4 * pi / 8) + 3 exp( j * 3 * pi / 8) | 4 exp( j * 2 * pi / 8) | 5 exp( j * 1 * pi / 8) + 6 exp( j * 0 * pi / 8) | 7 exp(-j * 1 * pi / 8) | 8 exp(-j * 2 * pi / 8) + 9 exp(-j * 3 * pi / 8) | 10 exp(-j * 4 * pi / 8) | 11 exp(-j * 5 * pi / 8) + 12 exp(-j * 6 * pi / 8) | | + +*/ + +static const FIXP_DBL cr[13] = +{ cos6Pi_8, cos5Pi_8, cos4Pi_8, + cos3Pi_8, cos2Pi_8, cos1Pi_8, + cos0Pi_8, + cos1Pi_8, cos2Pi_8, cos3Pi_8, + cos4Pi_8, cos5Pi_8, cos6Pi_8 +}; + +static const FIXP_DBL ci[13] = +{ + sin6Pi_8, sin5Pi_8, sin4Pi_8, + sin3Pi_8, sin2Pi_8, sin1Pi_8, + sin0Pi_8, + -sin1Pi_8, -sin2Pi_8, -sin3Pi_8, + -sin4Pi_8, -sin5Pi_8, -sin6Pi_8 +}; + + +static void eightChannelFiltering(const FIXP_QMF *pQmfReal, + const FIXP_QMF *pQmfImag, + FIXP_DBL *fft, + FIXP_QMF **mHybridReal, + FIXP_QMF **mHybridImag, + INT nSamples, + const FIXP_DBL *p) +{ + INT i, bin; + for(i = 0; i < nSamples; i++) { + /* pre twiddeling + scaling 4 = 2 (fMultDiv2) + 2 (dit_fft) scaling (HYBRID_SCALE = 4) + */ + fft[FFT_IDX_R(0)] = fMultDiv2(p[6], fMultSubDiv2(fMultDiv2(cr[6], pQmfReal[6+i]), ci[6], pQmfImag[6+i])); + fft[FFT_IDX_I(0)] = fMultDiv2(p[6], fMultAddDiv2(fMultDiv2(ci[6], pQmfReal[6+i]), cr[6], pQmfImag[6+i])); + + fft[FFT_IDX_R(1)] = fMultDiv2(p[7], fMultSubDiv2(fMultDiv2(cr[7], pQmfReal[7+i]), ci[7], pQmfImag[7+i])); + fft[FFT_IDX_I(1)] = fMultDiv2(p[7], fMultAddDiv2(fMultDiv2(ci[7], pQmfReal[7+i]), cr[7], pQmfImag[7+i])); + + fft[FFT_IDX_R(2)] = ( fMultDiv2(p[ 0], fMultSubDiv2(fMultDiv2(cr[0], pQmfReal[ 0+i]), ci[0], pQmfImag[ 0+i]))+ + fMultDiv2(p[ 8], fMultSubDiv2(fMultDiv2(cr[8], pQmfReal[ 8+i]), ci[8], pQmfImag[ 8+i])) ); + fft[FFT_IDX_I(2)] = ( fMultDiv2(p[ 0], fMultAddDiv2(fMultDiv2(ci[0], pQmfReal[ 0+i]), cr[0], pQmfImag[ 0+i]))+ + fMultDiv2(p[ 8], fMultAddDiv2(fMultDiv2(ci[8], pQmfReal[ 8+i]), cr[8], pQmfImag[ 8+i])) ); + + fft[FFT_IDX_R(3)] = ( fMultDiv2(p[ 1], fMultSubDiv2(fMultDiv2(cr[1], pQmfReal[ 1+i]), ci[1], pQmfImag[ 1+i]))+ + fMultDiv2(p[ 9], fMultSubDiv2(fMultDiv2(cr[9], pQmfReal[ 9+i]), ci[9], pQmfImag[ 9+i])) ); + fft[FFT_IDX_I(3)] = ( fMultDiv2(p[ 1], fMultAddDiv2(fMultDiv2(ci[1], pQmfReal[ 1+i]), cr[1], pQmfImag[ 1+i]))+ + fMultDiv2(p[ 9], fMultAddDiv2(fMultDiv2(ci[9], pQmfReal[ 9+i]), cr[9], pQmfImag[ 9+i])) ); + + fft[FFT_IDX_R(4)] = ( fMultDiv2(p[ 2], fMultSubDiv2( fMultDiv2(cr[2], pQmfReal[ 2+i]), ci[2], pQmfImag[ 2+i]))+ + fMultDiv2(p[10], fMultSubDiv2(fMultDiv2(cr[10], pQmfReal[10+i]), ci[10], pQmfImag[10+i])) ); + fft[FFT_IDX_I(4)] = ( fMultDiv2(p[ 2], fMultAddDiv2( fMultDiv2(ci[2], pQmfReal[ 2+i]), cr[2], pQmfImag[ 2+i]))+ + fMultDiv2(p[10], fMultAddDiv2(fMultDiv2(ci[10], pQmfReal[10+i]), cr[10], pQmfImag[10+i])) ); + + fft[FFT_IDX_R(5)] = ( fMultDiv2(p[ 3], fMultSubDiv2( fMultDiv2(cr[3], pQmfReal[ 3+i]), ci[3], pQmfImag[ 3+i]))+ + fMultDiv2(p[11], fMultSubDiv2(fMultDiv2(cr[11], pQmfReal[11+i]), ci[11], pQmfImag[11+i])) ); + fft[FFT_IDX_I(5)] = ( fMultDiv2(p[ 3], fMultAddDiv2( fMultDiv2(ci[3], pQmfReal[ 3+i]), cr[3], pQmfImag[ 3+i]))+ + fMultDiv2(p[11], fMultAddDiv2(fMultDiv2(ci[11], pQmfReal[11+i]), cr[11], pQmfImag[11+i])) ); + + fft[FFT_IDX_R(6)] = ( fMultDiv2(p[ 4], fMultSubDiv2( fMultDiv2(cr[4], pQmfReal[ 4+i]), ci[4], pQmfImag[ 4+i]))+ + fMultDiv2(p[12], fMultSubDiv2(fMultDiv2(cr[12], pQmfReal[12+i]), ci[12], pQmfImag[12+i])) ); + fft[FFT_IDX_I(6)] = ( fMultDiv2(p[ 4], fMultAddDiv2( fMultDiv2(ci[4], pQmfReal[ 4+i]), cr[4], pQmfImag[ 4+i]))+ + fMultDiv2(p[12], fMultAddDiv2(fMultDiv2(ci[12], pQmfReal[12+i]), cr[12], pQmfImag[12+i])) ); + + fft[FFT_IDX_R(7)] = fMultDiv2(p[5], fMultSubDiv2(fMultDiv2(cr[5], pQmfReal[5+i]), ci[5], pQmfImag[5+i])); + fft[FFT_IDX_I(7)] = fMultDiv2(p[5], fMultAddDiv2(fMultDiv2(ci[5], pQmfReal[5+i]), cr[5], pQmfImag[5+i])); + + /* fft modulation */ + fft_8(fft); + + /* resort fft data INTo output array*/ + for(bin=0; bin<8;bin++ ) { + mHybridReal[i][bin] = FX_DBL2FX_QMF(fft[FFT_IDX_R(bin)]); + mHybridImag[i][bin] = FX_DBL2FX_QMF(fft[FFT_IDX_I(bin)]); + } + } +} + +/**************************************************************************//** +HybridAnalysis +******************************************************************************/ + +HANDLE_ERROR_INFO +HybridAnalysis ( HANDLE_PS_HYBRID hHybrid, /*!< Handle to HYBRID struct. */ + FIXP_QMF *const *const mQmfReal, /*!< The real part of the QMF-matrix. */ + FIXP_QMF *const *const mQmfImag, /*!< The imaginary part of the QMF-matrix. */ + SCHAR sf_fixpQmf, /*!< Qmf scale factor */ + FIXP_QMF **mHybridReal, /*!< The real part of the hybrid-matrix. */ + FIXP_QMF **mHybridImag, /*!< The imaginary part of the hybrid-matrix. */ + SCHAR *sf_fixpHybrid) /*!< Hybrid scale factor */ +{ + HANDLE_ERROR_INFO error = noError; + INT n, band; + INT hybridRes; + INT chOffset = 0; + /* INT usedStereoBands = hHybrid->mode; */ /*!< indicates which 8 band filter to use */ + INT frameSize = hHybrid->frameSize; + INT hybridFilterDelay = hHybrid->hybridFilterDelay; + + for(band = 0; band < hHybrid->nQmfBands; band++) { /* loop all qmf bands */ + + if(error == noError){ + hybridRes = hHybrid->pResolution[band]; + + /* Create working buffer. */ + /* Copy stored samples to working buffer. */ + FDKmemcpy(hHybrid->pWorkReal, hHybrid->mQmfBufferReal[band], + hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); + FDKmemcpy(hHybrid->pWorkImag, hHybrid->mQmfBufferImag[band], + hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); + + /* Append new samples to working buffer. */ + for(n = 0; n < frameSize; n++) { + hHybrid->pWorkReal [hHybrid->qmfBufferMove + n] = mQmfReal [n + hybridFilterDelay] [band]; + hHybrid->pWorkImag [hHybrid->qmfBufferMove + n] = mQmfImag [n + hybridFilterDelay] [band]; + } + + /* Store samples for next frame. */ + FDKmemcpy(hHybrid->mQmfBufferReal[band], hHybrid->pWorkReal + frameSize, + hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); + FDKmemcpy(hHybrid->mQmfBufferImag[band], hHybrid->pWorkImag + frameSize, + hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); + + + switch(hybridRes) { + case HYBRID_2_REAL: + dualChannelFiltering( hHybrid->pWorkReal, + hHybrid->pWorkImag, + hHybrid->mTempReal, + hHybrid->mTempImag, + frameSize); + + /* copy data to output buffer */ + for(n = 0; n < frameSize; n++) { + FDKmemcpy(&mHybridReal[n][chOffset], hHybrid->mTempReal[n], + (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); + FDKmemcpy(&mHybridImag[n][chOffset], hHybrid->mTempImag[n], + (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); + } + break; + + case HYBRID_2_REAL | HYBRID_INVERSE_ORDER: + dualChannelFiltering( hHybrid->pWorkReal, + hHybrid->pWorkImag, + hHybrid->mTempReal, + hHybrid->mTempImag, + frameSize); + + /* copy and resort data */ + for ( n = 0; n < frameSize; n++ ) + { + mHybridReal[n][chOffset + 0] = hHybrid->mTempReal[n][1] ; + mHybridReal[n][chOffset + 1] = hHybrid->mTempReal[n][0] ; + mHybridImag[n][chOffset + 0] = hHybrid->mTempImag[n][1] ; + mHybridImag[n][chOffset + 1] = hHybrid->mTempImag[n][0] ; + } + break; + + case HYBRID_6_CPLX: + eightChannelFiltering( hHybrid->pWorkReal, + hHybrid->pWorkImag, + hHybrid->fft, + hHybrid->mTempReal, + hHybrid->mTempImag, + frameSize, + /*(usedStereoBands==PS_BANDS_FINE)?p8_13_34:*/p8_13_20); + + /* do the shuffle */ + for ( n = 0; n < frameSize; n++ ) + { + /* add data ... */ + hHybrid->mTempReal[n][2] += hHybrid->mTempReal[n][5]; + hHybrid->mTempImag[n][2] += hHybrid->mTempImag[n][5]; + hHybrid->mTempReal[n][3] += hHybrid->mTempReal[n][4]; + hHybrid->mTempImag[n][3] += hHybrid->mTempImag[n][4]; + + /* shuffle and copy to output buffer */ + mHybridReal[n][chOffset + 0] = hHybrid->mTempReal[n][6] ; + mHybridReal[n][chOffset + 1] = hHybrid->mTempReal[n][7] ; + mHybridReal[n][chOffset + 2] = hHybrid->mTempReal[n][0] ; + mHybridReal[n][chOffset + 3] = hHybrid->mTempReal[n][1] ; + mHybridReal[n][chOffset + 4] = hHybrid->mTempReal[n][2] ; + mHybridReal[n][chOffset + 5] = hHybrid->mTempReal[n][3] ; + + mHybridImag[n][chOffset + 0] = hHybrid->mTempImag[n][6] ; + mHybridImag[n][chOffset + 1] = hHybrid->mTempImag[n][7] ; + mHybridImag[n][chOffset + 2] = hHybrid->mTempImag[n][0] ; + mHybridImag[n][chOffset + 3] = hHybrid->mTempImag[n][1] ; + mHybridImag[n][chOffset + 4] = hHybrid->mTempImag[n][2] ; + mHybridImag[n][chOffset + 5] = hHybrid->mTempImag[n][3] ; + } + break; + + case HYBRID_8_CPLX: + eightChannelFiltering( hHybrid->pWorkReal, + hHybrid->pWorkImag, + hHybrid->fft, + hHybrid->mTempReal, + hHybrid->mTempImag, + frameSize, + /*(usedStereoBands==PS_BANDS_FINE)?p8_13_34:*/p8_13_20); + + /* copy data to output buffer */ + for(n = 0; n < frameSize; n++) { + FDKmemcpy(&mHybridReal[n][chOffset], hHybrid->mTempReal[n], + (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); + FDKmemcpy(&mHybridImag[n][chOffset], hHybrid->mTempImag[n], + (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); + } + break; + + default: + error = ERROR(CDI, "Invalid filter bank configuration."); + break; + } + /* prepare next run by incresing chOffset */ + chOffset += hybridRes & HYBRID_INVERSE_MASK; + } + } + + *sf_fixpHybrid = sf_fixpQmf + HYBRID_SCALE; + + return error; +} + +/**************************************************************************//** + FDKsbrEnc_CreateHybridFilterBank +******************************************************************************/ +HANDLE_ERROR_INFO +FDKsbrEnc_CreateHybridFilterBank ( HANDLE_PS_HYBRID *phHybrid, /*!< Pointer to handle to HYBRID struct. */ + INT ch) /*!< Current channel */ +{ + HANDLE_ERROR_INFO error = noError; + INT i; + HANDLE_PS_HYBRID hs = GetRam_PsHybrid(ch); /* allocate memory */ + if (hs==NULL) { + error = 1; + goto bail; + } + + hs->fft = GetRam_PsHybFFT(); + + /* alloc working memory */ + hs->pWorkReal = GetRam_PsHybWkReal(); + hs->pWorkImag = GetRam_PsHybWkImag(); + + if ( (hs->fft==NULL) || (hs->pWorkReal==NULL) || (hs->pWorkImag==NULL) ) { + error = 1; + goto bail; + } + + /* Allocate buffers */ + for (i = 0; i < HYBRID_FRAMESIZE; i++) { + hs->mTempReal[i] = GetRam_PsMtmpReal(i); + hs->mTempImag[i] = GetRam_PsMtmpImag(i); + if ( (hs->mTempReal[i]==NULL) || (hs->mTempImag[i]==NULL) ) { + error = 1; + goto bail; + } + } + +bail: + *phHybrid = hs; + return error; +} + +HANDLE_ERROR_INFO +FDKsbrEnc_InitHybridFilterBank ( HANDLE_PS_HYBRID hs, /*!< Handle to HYBRID struct. */ + HANDLE_PS_HYBRID_CONFIG hHybConfig, /*!< Configuration hanlde for filter bank */ + INT frameSize) /*!< Number of QMF slots */ +{ + HANDLE_ERROR_INFO error = noError; + INT i; + INT maxNoChannels = HYBRID_12_CPLX, noBands; + PS_BANDS mode; + const INT *RESTRICT pResolution; + + /* filter bank configuration */ + mode = hHybConfig->mode; + noBands = hHybConfig->noQmfBandsInHybrid; + pResolution = hHybConfig->aHybridResolution; + + /* assign resolution, check for valid values */ + for (i = 0; i < noBands; i++) { + if(error == noError){ + if( pResolution[i] != HYBRID_12_CPLX && + pResolution[i] != HYBRID_8_CPLX && + pResolution[i] != HYBRID_6_CPLX && + pResolution[i] != HYBRID_2_REAL && + pResolution[i] != (HYBRID_2_REAL | HYBRID_INVERSE_ORDER) && + pResolution[i] != HYBRID_4_CPLX ){ + error = ERROR(CDI, "Invalid filter bank resolution"); + } + } + hs->pResolution[i] = pResolution[i]; + if((pResolution[i] & HYBRID_INVERSE_MASK) > maxNoChannels){ + maxNoChannels = pResolution[i] & HYBRID_INVERSE_MASK; + } + } + FDK_ASSERT (MAX_HYBRID_RES>=maxNoChannels); /* check size of mTempReal/Imag */ + + /* assign parameters */ + hs->mode = mode; + hs->nQmfBands = noBands; + hs->frameSize = frameSize; + hs->frameSizeInit = frameSize; + hs->qmfBufferMove = HYBRID_FILTER_LENGTH - 1; + hs->hybridFilterDelay = HYBRID_FILTER_LENGTH/2; + + FDK_ASSERT (HYBRID_FRAMESIZE>=hs->frameSize); + FDK_ASSERT (QMF_BUFFER_MOVE>=hs->qmfBufferMove); + + return error; +} + + +/**************************************************************************//** + FDKsbrEnc_DeleteHybridFilterBank +******************************************************************************/ + +HANDLE_ERROR_INFO +FDKsbrEnc_DeleteHybridFilterBank ( HANDLE_PS_HYBRID* phHybrid ) /*!< Pointer to handle to HYBRID struct. */ +{ + int i; + HANDLE_PS_HYBRID hHybrid = *phHybrid; + + if (hHybrid!=NULL) { + if (hHybrid->fft) + FreeRam_PsHybFFT(&hHybrid->fft); + if (hHybrid->pWorkReal) + FreeRam_PsHybWkReal(&hHybrid->pWorkReal); + if (hHybrid->pWorkImag) + FreeRam_PsHybWkImag(&hHybrid->pWorkImag); + + for (i = 0; i < HYBRID_FRAMESIZE; i++) { + if (hHybrid->mTempReal[i]) + FreeRam_PsMtmpReal(&hHybrid->mTempReal[i]); + if (hHybrid->mTempImag[i]) + FreeRam_PsMtmpImag(&hHybrid->mTempImag[i]); + } + + FreeRam_PsHybrid(phHybrid); + } + + return noError; +} + +/*** Access functions ***/ +INT FDKsbrEnc_GetHybridFilterDelay(HANDLE_PS_HYBRID hHybrid){ + + return hHybrid->hybridFilterDelay; +} + diff --git a/libSBRenc/src/psenc_hybrid.h b/libSBRenc/src/psenc_hybrid.h new file mode 100644 index 0000000..79e600d --- /dev/null +++ b/libSBRenc/src/psenc_hybrid.h @@ -0,0 +1,182 @@ +/***************************** MPEG Audio Encoder *************************** + + (C) Copyright Fraunhofer IIS (2004-2005) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Initial author: M. Neuendorf, M. Multrus + contents/description: hypbrid filter bank (prototypes) + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#ifndef __hybrid_h +#define __hybrid_h + +/* Includes ******************************************************************/ +#include "sbr_def.h" +#include "ps_const.h" + +#include "qmf.h" + +/* Data Types ****************************************************************/ + +typedef enum { + HYBRID_2_REAL = 2, + HYBRID_4_CPLX = 4, + HYBRID_6_CPLX = 6, + HYBRID_8_CPLX = 8, + HYBRID_12_CPLX = 12 +} HYBRID_RES; + +#define MAX_HYBRID_RES (HYBRID_12_CPLX) + +/* Defines *******************************************************************/ +#define MAX_QMF_BANDS_IN_HYBRID (5) +#define MAX_IID_GROUPS (50) /* NO_IID_GROUPS_HI_RES */ + +#define HYBRID_FILTER_LENGTH ( 13 ) + +#define HYBRID_FRAMESIZE ( QMF_MAX_TIME_SLOTS ) +#define HYBRID_WRITEOFFSET ( 10 ) +#define HYBRID_NUM_BANDS ( 10 ) + +#define NO_QMF_BANDS_HYBRID_10 ( 3 ) +#define NO_QMF_BANDS_HYBRID_20 ( 3 ) +#define HYBRID_MAX_QMF_BANDS ( NO_QMF_BANDS_HYBRID_20 ) + +#define QMF_BUFFER_MOVE ( HYBRID_FILTER_LENGTH - 1 ) + + +/* Data Types ****************************************************************/ +typedef struct PS_HYBRID_CONFIG_tag { + PS_BANDS mode; + + UINT noQmfBandsInHybrid; + INT aHybridResolution[MAX_QMF_BANDS_IN_HYBRID]; /* valid entries from 0 to noQmfBandsInHybrid */ + +} PS_HYBRID_CONFIG, *HANDLE_PS_HYBRID_CONFIG; + +typedef struct PS_HYBRID_tag +{ + PS_BANDS mode; + INT nQmfBands; + INT frameSizeInit; + INT frameSize; + INT pResolution[HYBRID_MAX_QMF_BANDS]; + INT qmfBufferMove; + INT hybridFilterDelay; + + FIXP_DBL *fft; + + FIXP_QMF *pWorkReal; /**< Working arrays for Qmf samples. */ + FIXP_QMF *pWorkImag; + + FIXP_QMF mQmfBufferReal[HYBRID_MAX_QMF_BANDS][QMF_BUFFER_MOVE]; /**< Stores old Qmf samples. */ + FIXP_QMF mQmfBufferImag[HYBRID_MAX_QMF_BANDS][QMF_BUFFER_MOVE]; + FIXP_QMF *mTempReal[HYBRID_FRAMESIZE]; /**< Temporary matrices for filter bank output. */ + FIXP_QMF *mTempImag[HYBRID_FRAMESIZE]; + +} PS_HYBRID; + +typedef struct PS_HYBRID_DATA_tag { + INT frameSize; + INT nHybridBands; + INT nHybridQmfBands; + INT nHybridResolution [HYBRID_MAX_QMF_BANDS]; + + FIXP_QMF* rHybData [(HYBRID_FRAMESIZE + HYBRID_WRITEOFFSET)]; + FIXP_QMF* iHybData [(HYBRID_FRAMESIZE + HYBRID_WRITEOFFSET)]; + SCHAR sf_fixpHybrid; + + INT hybDataReadOffset; + INT hybDataWriteOffset; + +} PS_HYBRID_DATA; + + +typedef struct PS_HYBRID_DATA_tag *HANDLE_PS_HYBRID_DATA; +typedef struct PS_HYBRID_tag *HANDLE_PS_HYBRID; + + + +/* Function Declarations *********************************************/ + +/*****************************************************************************/ +/* **** FILTERBANK CONFIG **** */ + +HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridConfig(HANDLE_PS_HYBRID_CONFIG *phHybConfig, + PS_BANDS mode); + +/*****************************************************************************/ +/* **** FILTERBANK DATA **** */ + +HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridData(HANDLE_PS_HYBRID_DATA *phHybData, + INT ch); + +HANDLE_ERROR_INFO FDKsbrEnc_InitHybridData(HANDLE_PS_HYBRID_DATA hHybData, + HANDLE_PS_HYBRID_CONFIG hHybConfig, + INT frameSize); + +HANDLE_ERROR_INFO FDKsbrEnc_DestroyHybridData(HANDLE_PS_HYBRID_DATA* phHybData); + +inline INT FDKsbrEnc_GetHybridFrameSize(HANDLE_PS_HYBRID_DATA h) { + return h->frameSize; +} + +inline INT FDKsbrEnc_GetNumberHybridBands(HANDLE_PS_HYBRID_DATA h) { + return h->nHybridBands; +} + +inline INT FDKsbrEnc_GetNumberHybridQmfBands(HANDLE_PS_HYBRID_DATA h) { + return h->nHybridQmfBands; +} + +INT FDKsbrEnc_GetHybridResolution(HANDLE_PS_HYBRID_DATA h, INT qmfBand); + + + +/*****************************************************************************/ +/* **** FILTERBANK **** */ + +HANDLE_ERROR_INFO +FDKsbrEnc_CreateHybridFilterBank ( HANDLE_PS_HYBRID *phHybrid, + INT ch ); + +HANDLE_ERROR_INFO +FDKsbrEnc_InitHybridFilterBank ( HANDLE_PS_HYBRID hHybrid, + HANDLE_PS_HYBRID_CONFIG hHybConfig, + INT frameSize ); + +HANDLE_ERROR_INFO +FDKsbrEnc_DeleteHybridFilterBank ( HANDLE_PS_HYBRID* phHybrid ); + +HANDLE_ERROR_INFO +HybridAnalysis ( HANDLE_PS_HYBRID hHybrid, + FIXP_QMF *const * const mQmfReal, + FIXP_QMF *const * const mQmfImag, + SCHAR sf_fixpQmf, + FIXP_QMF **mHybridReal, + FIXP_QMF **mHybridImag, + SCHAR *sf_fixpHybrid); + + +INT +FDKsbrEnc_GetHybridFilterDelay(HANDLE_PS_HYBRID hHybrid); + +#endif /*__hybrid_h*/ diff --git a/libSBRenc/src/resampler.cpp b/libSBRenc/src/resampler.cpp new file mode 100644 index 0000000..0dacc0e --- /dev/null +++ b/libSBRenc/src/resampler.cpp @@ -0,0 +1,450 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +/*! + \file + \brief FDK resampler tool box:$Revision: 11752 $ + \author M. Werner +*/ + +#include "resampler.h" + +#include "genericStds.h" + + +/**************************************************************************/ +/* BIQUAD Filter Specifications */ +/**************************************************************************/ + +#define B1 0 +#define B2 1 +#define A1 2 +#define A2 3 + +#define BQC(x) FL2FXCONST_SGL(x/2) + + +struct FILTER_PARAM { + const FIXP_SGL *coeffa; /*! SOS matrix One row/section. Scaled using BQC(). Order of coefficients: B1,B2,A1,A2. B0=A0=1.0 */ + FIXP_DBL g; /*! overall gain */ + int Wc; /*! normalized passband bandwidth at input samplerate * 1000 */ + int noCoeffs; /*! number of filter coeffs */ + int delay; /*! delay in samples at input samplerate */ +}; + +#define BIQUAD_COEFSTEP 4 + +/** + *\brief Low Pass + Wc = 0,5, order 30, Stop Band -96dB. Wc criteria is "almost 0dB passband", not the usual -3db gain point. + [b,a]=cheby2(30,96,0.505) + [sos,g]=tf2sos(b,a) + bandwidth 0.48 + */ +static const FIXP_SGL sos48[] = { + BQC(1.98941075681938), BQC(0.999999996890811), BQC(0.863264527201963), BQC( 0.189553799960663), + BQC(1.90733804822445), BQC(1.00000001736189), BQC(0.836321575841691), BQC( 0.203505809266564), + BQC(1.75616665495325), BQC(0.999999946079721), BQC(0.784699225121588), BQC( 0.230471265506986), + BQC(1.55727745512726), BQC(1.00000011737815), BQC(0.712515423588351), BQC( 0.268752723900498), + BQC(1.33407591943643), BQC(0.999999795953228), BQC(0.625059117330989), BQC( 0.316194685288965), + BQC(1.10689898412458), BQC(1.00000035057114), BQC(0.52803514366398), BQC( 0.370517843224669), + BQC(0.89060371078454), BQC(0.999999343962822), BQC(0.426920462165257), BQC( 0.429608200207746), + BQC(0.694438261209433), BQC( 1.0000008629792), BQC(0.326530699561716), BQC( 0.491714450654174), + BQC(0.523237800935322), BQC(1.00000101349782), BQC(0.230829556274851), BQC( 0.555559034843281), + BQC(0.378631165929563), BQC(0.99998986482665), BQC(0.142906422036095), BQC( 0.620338874442411), + BQC(0.260786911308437), BQC(1.00003261460178), BQC(0.0651008576256505), BQC( 0.685759923926262), + BQC(0.168409429188098), BQC(0.999933049695828), BQC(-0.000790067789975562), BQC( 0.751905896602325), + BQC(0.100724533818628), BQC(1.00009472669872), BQC(-0.0533772830257041), BQC( 0.81930744384525), + BQC(0.0561434357867363), BQC(0.999911636304276), BQC(-0.0913550299236405), BQC( 0.88883625875915), + BQC(0.0341680678662057), BQC(1.00003667508676), BQC(-0.113405185536697), BQC( 0.961756638268446) +}; + +#ifdef RS_BIQUAD_SCATTERGAIN +static const FIXP_DBL g48 = FL2FXCONST_DBL(0.67436532061161992682404480717671 - 0.001); +#else +static const FIXP_DBL g48 = FL2FXCONST_DBL(0.002712866530047) - (FIXP_DBL)0x8000; +#endif + +static const struct FILTER_PARAM param_set48 = { + sos48, + g48, + 480, + 15, + 4 /* LF 2 */ +}; + +/** + *\brief Low Pass + Wc = 0,5, order 24, Stop Band -96dB. Wc criteria is "almost 0dB passband", not the usual -3db gain point. + [b,a]=cheby2(24,96,0.5) + [sos,g]=tf2sos(b,a) + bandwidth 0.45 + */ +static const FIXP_SGL sos45[] = { + BQC(1.982962601444), BQC(1.00000000007504), BQC(0.646113303737836), BQC( 0.10851149979981), + BQC(1.85334094281111), BQC(0.999999999677192), BQC(0.612073220102006), BQC( 0.130022141698044), + BQC(1.62541051415425), BQC(1.00000000080398), BQC(0.547879702855959), BQC( 0.171165825133192), + BQC(1.34554656923247), BQC(0.9999999980169), BQC(0.460373914508491), BQC( 0.228677463376354), + BQC(1.05656568503116), BQC(1.00000000569363), BQC(0.357891894038287), BQC( 0.298676843912185), + BQC(0.787967587877312), BQC(0.999999984415017), BQC(0.248826893211877), BQC( 0.377441803512978), + BQC(0.555480971120497), BQC(1.00000003583307), BQC(0.140614263345315), BQC( 0.461979302213679), + BQC(0.364986207070964), BQC(0.999999932084303), BQC(0.0392669446074516), BQC( 0.55033451180825), + BQC(0.216827267631558), BQC(1.00000010534682), BQC(-0.0506232228865103), BQC( 0.641691581560946), + BQC(0.108951672277119), BQC(0.999999871167516), BQC(-0.125584840183225), BQC( 0.736367748771803), + BQC(0.0387988607229035), BQC(1.00000011205574), BQC(-0.182814849097974), BQC( 0.835802108714964), + BQC(0.0042866175809225), BQC(0.999999954830813), BQC(-0.21965740617151), BQC( 0.942623047782363) +}; + +#ifdef RS_BIQUAD_SCATTERGAIN +static const FIXP_DBL g45 = FL2FXCONST_DBL(0.60547428891341319051142629706723 - 0.001); +#else +static const FIXP_DBL g45 = FL2FXCONST_DBL(0.00242743980909524) - (FIXP_DBL)0x8000; +#endif + +static const struct FILTER_PARAM param_set45 = { + sos45, + g45, + 450, + 12, + 4 /* LF 2 */ +}; + +/* + Created by Octave 2.1.73, Mon Oct 13 17:31:32 2008 CEST + Wc = 0,5, order 16, Stop Band -96dB damping. + [b,a]=cheby2(16,96,0.5) + [sos,g]=tf2sos(b,a) + bandwidth = 0.41 + */ + +static const FIXP_SGL sos41[] = +{ + BQC(1.96193625292), BQC(0.999999999999964), BQC(0.169266178786789), BQC(0.0128823300475907), + BQC(1.68913437662092), BQC(1.00000000000053), BQC(0.124751503206552), BQC(0.0537472273950989), + BQC(1.27274692366017), BQC(0.999999999995674), BQC(0.0433108625178357), BQC(0.131015753236317), + BQC(0.85214175088395), BQC(1.00000000001813), BQC(-0.0625658152550408), BQC(0.237763778993806), + BQC(0.503841579939009), BQC(0.999999999953223), BQC(-0.179176128722865), BQC(0.367475236424474), + BQC(0.249990711986162), BQC(1.00000000007952), BQC(-0.294425165824676), BQC(0.516594857170212), + BQC(0.087971668680286), BQC(0.999999999915528), BQC(-0.398956566777928), BQC(0.686417767801123), + BQC(0.00965373325350294), BQC(1.00000000003744), BQC(-0.48579173764817), BQC(0.884931534239068) +}; + +#ifdef RS_BIQUAD_SCATTERGAIN +static const FIXP_DBL g41 = FL2FXCONST_DBL(0.44578514476476679750811222123569); +#else +static const FIXP_DBL g41 = FL2FXCONST_DBL(0.00155956951169248); +#endif + +static const struct FILTER_PARAM param_set41 = { + sos41, + g41, + 410, + 8, + 5 /* LF 3 */ +}; + +/* + # Created by Octave 2.1.73, Mon Oct 13 17:55:33 2008 CEST + Wc = 0,5, order 12, Stop Band -96dB damping. + [b,a]=cheby2(12,96,0.5); + [sos,g]=tf2sos(b,a) +*/ +static const FIXP_SGL sos35[] = +{ + BQC(1.93299325235762), BQC(0.999999999999985), BQC(-0.140733187246596), BQC(0.0124139497836062), + BQC(1.4890416764109), BQC(1.00000000000011), BQC(-0.198215402588504), BQC(0.0746730616584138), + BQC(0.918450161309795), BQC(0.999999999999619), BQC(-0.30133912791941), BQC(0.192276468839529), + BQC(0.454877024246818), BQC(1.00000000000086), BQC(-0.432337328809815), BQC(0.356852933642815), + BQC(0.158017147118507), BQC(0.999999999998876), BQC(-0.574817494249777), BQC(0.566380436970833), + BQC(0.0171834649478749), BQC(1.00000000000055), BQC(-0.718581178041165), BQC(0.83367484487889) +}; + +#ifdef RS_BIQUAD_SCATTERGAIN +static const FIXP_DBL g35 = FL2FXCONST_DBL(0.34290853574973898694521267606792); +#else +static const FIXP_DBL g35 = FL2FXCONST_DBL(0.00162580994125131); +#endif + +static const struct FILTER_PARAM param_set35 = { + sos35, + g35, + 350, + 6, + 4 +}; + +/* + # Created by Octave 2.1.73, Mon Oct 13 18:15:38 2008 CEST + Wc = 0,5, order 8, Stop Band -96dB damping. + [b,a]=cheby2(8,96,0.5); + [sos,g]=tf2sos(b,a) +*/ +static const FIXP_SGL sos25[] = +{ + BQC(1.85334094301225), BQC(1.0), BQC(-0.702127214212663), BQC(0.132452403998767), + BQC(1.056565682167), BQC(0.999999999999997), BQC(-0.789503667880785), BQC(0.236328693569128), + BQC(0.364986307455489), BQC(0.999999999999996), BQC(-0.955191189843375), BQC(0.442966457936379), + BQC(0.0387985751642125), BQC(1.0), BQC(-1.19817786088084), BQC(0.770493895456328) +}; + +#ifdef RS_BIQUAD_SCATTERGAIN +static const FIXP_DBL g25 = FL2FXCONST_DBL(0.17533917408936346960080259950471); +#else +static const FIXP_DBL g25 = FL2FXCONST_DBL(0.000945182835294559); +#endif + +static const struct FILTER_PARAM param_set25 = { + sos25, + g25, + 250, + 4, + 5 +}; + +/* Must be sorted in descending order */ +static const struct FILTER_PARAM *const filter_paramSet[] = { + ¶m_set48, + ¶m_set45, + ¶m_set41, + ¶m_set35, + ¶m_set25 +}; + + +/**************************************************************************/ +/* Resampler Functions */ +/**************************************************************************/ + + +/*! + \brief Reset downsampler instance and clear delay lines + + \return success of operation +*/ + +INT FDKaacEnc_InitDownsampler(DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + int Wc, /*!< normalized cutoff freq * 1000* */ + int ratio) /*!< downsampler ratio (only 2 supported at the momment) */ + +{ + UINT i; + const struct FILTER_PARAM *currentSet=NULL; + + FDK_ASSERT(ratio == 2); + FDKmemclear(DownSampler->downFilter.states, sizeof(DownSampler->downFilter.states)); + DownSampler->downFilter.ptr = 0; + + /* + find applicable parameter set + */ + currentSet = filter_paramSet[0]; + for(i=1;i<sizeof(filter_paramSet)/sizeof(struct FILTER_PARAM *);i++){ + if (filter_paramSet[i]->Wc <= Wc) { + break; + } + currentSet = filter_paramSet[i]; + } + + DownSampler->downFilter.coeffa = currentSet->coeffa; + + + DownSampler->downFilter.gain = currentSet->g; + FDK_ASSERT(currentSet->noCoeffs <= MAXNR_SECTIONS*2); + + DownSampler->downFilter.noCoeffs = currentSet->noCoeffs; + DownSampler->delay = currentSet->delay; + DownSampler->downFilter.Wc = currentSet->Wc; + + DownSampler->ratio = ratio; + DownSampler->pending = ratio-1; + return(1); +} + + +/*! + \brief faster simple folding operation + Filter: + H(z) = A(z)/B(z) + with + A(z) = a[0]*z^0 + a[1]*z^1 + a[2]*z^2 ... a[n]*z^n + + \return filtered value +*/ + +static inline INT_PCM AdvanceFilter(LP_FILTER *downFilter, /*!< pointer to iir filter instance */ + INT_PCM *pInput, /*!< input of filter */ + int downRatio, + int inStride) +{ + INT_PCM output; + int i, n; + + +#ifdef RS_BIQUAD_SCATTERGAIN +#define BIQUAD_SCALE 3 +#else +#define BIQUAD_SCALE 12 +#endif + + FIXP_DBL y = FL2FXCONST_DBL(0.0f); + FIXP_DBL input; + + for (n=0; n<downRatio; n++) + { + FIXP_BQS (*states)[2] = downFilter->states; + const FIXP_SGL *coeff = downFilter->coeffa; + int s1,s2; + + s1 = downFilter->ptr; + s2 = s1 ^ 1; + +#if (SAMPLE_BITS == 16) + input = ((FIXP_DBL)pInput[n*inStride]) << (DFRACT_BITS-SAMPLE_BITS-BIQUAD_SCALE); +#elif (SAMPLE_BITS == 32) + input = pInput[n*inStride] >> BIQUAD_SCALE; +#else +#error NOT IMPLEMENTED +#endif + +#ifndef RS_BIQUAD_SCATTERGAIN /* Merged Direct form I */ + + FIXP_BQS state1, state2, state1b, state2b; + + state1 = states[0][s1]; + state2 = states[0][s2]; + + /* Loop over sections */ + for (i=0; i<downFilter->noCoeffs; i++) + { + FIXP_DBL state0; + + /* Load merged states (from next section) */ + state1b = states[i+1][s1]; + state2b = states[i+1][s2]; + + state0 = input + fMult(state1, coeff[B1]) + fMult(state2, coeff[B2]); + y = state0 - fMult(state1b, coeff[A1]) - fMult(state2b, coeff[A2]); + + /* Store new feed forward merge state */ + states[i+1][s2] = y<<1; + /* Store new feed backward state */ + states[i][s2] = input<<1; + + /* Feedback output to next section. */ + input = y; + + /* Transfer merged states */ + state1 = state1b; + state2 = state2b; + + /* Step to next coef set */ + coeff += BIQUAD_COEFSTEP; + } + downFilter->ptr ^= 1; + } + /* Apply global gain */ + y = fMult(y, downFilter->gain); + +#else /* Direct form II */ + + /* Loop over sections */ + for (i=0; i<downFilter->noCoeffs; i++) + { + FIXP_BQS state1, state2; + FIXP_DBL state0; + + /* Load states */ + state1 = states[i][s1]; + state2 = states[i][s2]; + + state0 = input - fMult(state1, coeff[A1]) - fMult(state2, coeff[A2]); + y = state0 + fMult(state1, coeff[B1]) + fMult(state2, coeff[B2]); + /* Apply scattered gain */ + y = fMult(y, downFilter->gain); + + /* Store new state in normalized form */ +#ifdef RS_BIQUAD_STATES16 + /* Do not saturate any state value ! The result would be unacceptable. Rounding makes SNR around 10dB better. */ + states[i][s2] = (FIXP_BQS)(LONG)((state0 + (FIXP_DBL)(1<<(DFRACT_BITS-FRACT_BITS-2))) >> (DFRACT_BITS-FRACT_BITS-1)); +#else + states[i][s2] = state0<<1; +#endif + + /* Feedback output to next section. */ + input=y; + + /* Step to next coef set */ + coeff += BIQUAD_COEFSTEP; + } + downFilter->ptr ^= 1; + } + +#endif + + /* Apply final gain/scaling to output */ +#if (SAMPLE_BITS == 16) + output = (INT_PCM) SATURATE_RIGHT_SHIFT(y+(FIXP_DBL)(1<<(DFRACT_BITS-SAMPLE_BITS-BIQUAD_SCALE-1)), DFRACT_BITS-SAMPLE_BITS-BIQUAD_SCALE, SAMPLE_BITS); + //output = (INT_PCM) SATURATE_RIGHT_SHIFT(y, DFRACT_BITS-SAMPLE_BITS-BIQUAD_SCALE, SAMPLE_BITS); +#else + output = SATURATE_LEFT_SHIFT(y, BIQUAD_SCALE, SAMPLE_BITS); +#endif + + + return output; +} + + + + +/*! + \brief FDKaacEnc_Downsample numInSamples of type INT_PCM + Returns number of output samples in numOutSamples + + \return success of operation +*/ + +INT FDKaacEnc_Downsample(DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + INT_PCM *inSamples, /*!< pointer to input samples */ + INT numInSamples, /*!< number of input samples */ + INT inStride, /*!< increment of input samples */ + INT_PCM *outSamples, /*!< pointer to output samples */ + INT *numOutSamples, /*!< pointer tp number of output samples */ + INT outStride /*!< increment of output samples */ + ) +{ + INT i; + *numOutSamples=0; + + for(i=0; i<numInSamples; i+=DownSampler->ratio) + { + *outSamples = AdvanceFilter(&(DownSampler->downFilter), &inSamples[i*inStride], DownSampler->ratio, inStride); + outSamples += outStride; + } + *numOutSamples = numInSamples/DownSampler->ratio; + + return 0; +} + diff --git a/libSBRenc/src/resampler.h b/libSBRenc/src/resampler.h new file mode 100644 index 0000000..0815ba9 --- /dev/null +++ b/libSBRenc/src/resampler.h @@ -0,0 +1,109 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +#ifndef __RESAMPLER_H +#define __RESAMPLER_H +/*! + \file + \brief Fixed Point Resampler Tool Box $Revision: 11752 $ +*/ + +/*! + \mainpage Fixed Point Resampler Library Documentation + + Information in this SDK is subject to change without notice. Companies, + names, and data used in examples herein are fictitious unless otherwise + noted. + + Product and corporate names may be trademarks or registered trademarks + of other companies. They are used for explanation only, with no intent + to infringe. + + No part of this publication may be reproduced or utilized in any form or + by any means, electronic or mechanical, including photocopying and + microfilm, without permission in writing from the publisher. +*/ + +#include "common_fix.h" + + +/**************************************************************************/ +/* BIQUAD Filter Structure */ +/**************************************************************************/ + +#define MAXNR_SECTIONS (15) + +#ifdef RS_BIQUAD_STATES16 +typedef FIXP_SGL FIXP_BQS; +#else +typedef FIXP_DBL FIXP_BQS; +#endif + +typedef struct +{ + FIXP_BQS states[MAXNR_SECTIONS+1][2]; /*! state buffer */ + const FIXP_SGL *coeffa; /*! pointer to filter coeffs */ + FIXP_DBL gain; /*! overall gain factor */ + int Wc; /*! normalized cutoff freq * 1000 */ + int noCoeffs; /*! number of filter coeffs sets */ + int ptr; /*! index to rinbuffers */ +} LP_FILTER; + + +/**************************************************************************/ +/* Downsampler Structure */ +/**************************************************************************/ + +typedef struct +{ + LP_FILTER downFilter; /*! filter instance */ + int ratio; /*! downsampling ration */ + int delay; /*! downsampling delay (source fs) */ + int pending; /*! number of pending output samples */ +} DOWNSAMPLER; + + +/** + * \brief Initialized a given downsampler structure. + */ +INT FDKaacEnc_InitDownsampler(DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + INT Wc, /*!< normalized cutoff freq * 1000 */ + INT ratio); /*!< downsampler ratio */ + +/** + * \brief Downsample a set of audio samples. numInSamples must be at least equal to the + * downsampler ratio. + */ +INT FDKaacEnc_Downsample(DOWNSAMPLER *DownSampler, /*!< pointer to downsampler instance */ + INT_PCM *inSamples, /*!< pointer to input samples */ + INT numInSamples, /*!< number of input samples */ + INT inStride, /*!< increment of input samples */ + INT_PCM *outSamples, /*!< pointer to output samples */ + INT *numOutSamples, /*!< pointer tp number of output samples */ + INT outstride); /*!< increment of output samples */ + + + +#endif /* __RESAMPLER_H */ diff --git a/libSBRenc/src/sbr.h b/libSBRenc/src/sbr.h new file mode 100644 index 0000000..40a3953 --- /dev/null +++ b/libSBRenc/src/sbr.h @@ -0,0 +1,107 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Main SBR structs definitions $Revision: 36847 $ +*/ + +#ifndef __SBR_H +#define __SBR_H + +#include "fram_gen.h" +#include "bit_sbr.h" +#include "tran_det.h" +#include "code_env.h" +#include "env_est.h" +#include "cmondata.h" + +#include "qmf.h" +#include "resampler.h" + +#include "ton_corr.h" + + +/* SBR bitstream delay */ + #define DELAY_FRAMES 2 + +typedef struct { + struct ENV_CHANNEL hEnvChannel; + //INT_PCM *pDSOutBuffer; /**< Pointer to downsampled audio output of SBR encoder */ + DOWNSAMPLER downSampler; + +} SBR_CHANNEL; +typedef SBR_CHANNEL* HANDLE_SBR_CHANNEL; + +typedef struct { + HANDLE_SBR_CHANNEL sbrChannel[2]; + QMF_FILTER_BANK *hQmfAnalysis[2]; + SBR_CONFIG_DATA sbrConfigData; + SBR_HEADER_DATA sbrHeaderData; + SBR_BITSTREAM_DATA sbrBitstreamData; + COMMON_DATA CmonData; + INT dynXOverFreqDelay[5]; /**< to delay a frame (I don't like it that much that way - hrc) */ + SBR_ELEMENT_INFO elInfo; + + UCHAR payloadDelayLine[1+DELAY_FRAMES][MAX_PAYLOAD_SIZE]; + UINT payloadDelayLineSize[1+DELAY_FRAMES]; /* Sizes in bits */ + +} SBR_ELEMENT; +typedef SBR_ELEMENT* HANDLE_SBR_ELEMENT; + +struct SBR_ENCODER +{ + HANDLE_SBR_ELEMENT sbrElement[(6)]; + HANDLE_SBR_CHANNEL pSbrChannel[(6)]; + QMF_FILTER_BANK QmfAnalysis[(6)]; + DOWNSAMPLER lfeDownSampler; + int lfeChIdx; /* -1 default for no lfe, else assign channel index */ + int noElements; /* Number of elements */ + int nChannels; /* Total channel count across all elements. */ + int frameSize; /* SBR framelength. */ + int bufferOffset; /* Offset for SBR parameter extraction in time domain input buffer. */ + int downsampledOffset; /* Offset of downsampled/mixed output for core encoder. */ + int downmixSize; /* Size in samples of downsampled/mixed output for core encoder. */ + int fTimeDomainDownsampling; /* Flag signalling time domain downsampling instead of QMF downsampling. */ + int nBitstrDelay; /* Amount of SBR frames to be delayed in bitstream domain. */ + INT estimateBitrate; /* estimate bitrate of SBR encoder */ + INT inputDataDelay; /* delay caused by downsampler, in/out buffer at sbrEncoder_EncodeFrame */ + + UCHAR* dynamicRam; + UCHAR* pSBRdynamic_RAM; + + HANDLE_PSENC_CONFIG hPsEncConfig; + HANDLE_PARAMETRIC_STEREO hParametricStereo; + QMF_FILTER_BANK qmfSynthesisPS; + + /* parameters describing allocation volume of present instance */ + INT maxElements; + INT maxChannels; + INT supportPS; + +} ; + + +#endif /* __SBR_H */ diff --git a/libSBRenc/src/sbr_def.h b/libSBRenc/src/sbr_def.h new file mode 100644 index 0000000..592c1e0 --- /dev/null +++ b/libSBRenc/src/sbr_def.h @@ -0,0 +1,228 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief SBR main definitions $Revision: 36847 $ +*/ +#ifndef __SBR_DEF_H +#define __SBR_DEF_H + +#include "common_fix.h" + +#define noError 0 +#define HANDLE_ERROR_INFO INT +#define ERROR(a,b) 1 +#define handBack + +/* #define SBR_ENV_STATISTICS_BITRATE */ +#undef SBR_ENV_STATISTICS_BITRATE + +/* #define SBR_ENV_STATISTICS */ +#undef SBR_ENV_STATISTICS + +/* #define SBR_PAYLOAD_MONITOR */ +#undef SBR_PAYLOAD_MONITOR + +#define SWAP(a,b) tempr=a, a=b, b=tempr +#define TRUE 1 +#define FALSE 0 + + +/* Constants */ +#define EPS 1e-12 +#define LOG2 0.69314718056f /* natural logarithm of 2 */ +#define ILOG2 1.442695041f /* 1/LOG2 */ +#define RELAXATION_FLOAT (1e-6f) +#define RELAXATION (FL2FXCONST_DBL(RELAXATION_FLOAT)) +#define RELAXATION_FRACT (FL2FXCONST_DBL(0.524288f)) /* 0.524288f is fractional part of RELAXATION */ +#define RELAXATION_SHIFT (19) +#define RELAXATION_LD64 (FL2FXCONST_DBL(0.31143075889f))/* (ld64(RELAXATION) */ + +/************ Definitions ***************/ +#define SBR_COMP_MODE_DELTA 0 +#define SBR_COMP_MODE_CTS 1 + +#define MAX_NUM_CHANNELS 2 + +#define MAX_NOISE_ENVELOPES 2 +#define MAX_NUM_NOISE_COEFFS 5 +#define MAX_NUM_NOISE_VALUES (MAX_NUM_NOISE_COEFFS*MAX_NOISE_ENVELOPES) + +#define MAX_NUM_ENVELOPE_VALUES (MAX_ENVELOPES * MAX_FREQ_COEFFS) +#define MAX_ENVELOPES 5 +#define MAX_FREQ_COEFFS 48 + +#define MAX_FREQ_COEFFS_FS44100 35 +#define MAX_FREQ_COEFFS_FS48000 32 + + +#define QMF_CHANNELS 64 +#define QMF_FILTER_LENGTH 640 +#define QMF_MAX_TIME_SLOTS 32 +#define NO_OF_ESTIMATES_LC 4 +#define NO_OF_ESTIMATES_LD 3 +#define MAX_NO_OF_ESTIMATES 4 + + +#define NOISE_FLOOR_OFFSET 6 +#define NOISE_FLOOR_OFFSET_64 (FL2FXCONST_DBL(0.09375f)) + +#define LOW_RES 0 +#define HIGH_RES 1 + +#define LO 0 +#define HI 1 + +#define LENGTH_SBR_FRAME_INFO 35 /* 19 */ + +#define SBR_NSFB_LOW_RES 9 /* 8 */ +#define SBR_NSFB_HIGH_RES 18 /* 16 */ + + +#define SBR_XPOS_CTRL_DEFAULT 2 + +#define SBR_FREQ_SCALE_DEFAULT 2 +#define SBR_ALTER_SCALE_DEFAULT 1 +#define SBR_NOISE_BANDS_DEFAULT 2 + +#define SBR_LIMITER_BANDS_DEFAULT 2 +#define SBR_LIMITER_GAINS_DEFAULT 2 +#define SBR_LIMITER_GAINS_INFINITE 3 +#define SBR_INTERPOL_FREQ_DEFAULT 1 +#define SBR_SMOOTHING_LENGTH_DEFAULT 0 + + +/* sbr_header */ +#define SI_SBR_AMP_RES_BITS 1 +#define SI_SBR_COUPLING_BITS 1 +#define SI_SBR_START_FREQ_BITS 4 +#define SI_SBR_STOP_FREQ_BITS 4 +#define SI_SBR_XOVER_BAND_BITS 3 +#define SI_SBR_RESERVED_BITS 2 +#define SI_SBR_DATA_EXTRA_BITS 1 +#define SI_SBR_HEADER_EXTRA_1_BITS 1 +#define SI_SBR_HEADER_EXTRA_2_BITS 1 + +/* sbr_header extra 1 */ +#define SI_SBR_FREQ_SCALE_BITS 2 +#define SI_SBR_ALTER_SCALE_BITS 1 +#define SI_SBR_NOISE_BANDS_BITS 2 + +/* sbr_header extra 2 */ +#define SI_SBR_LIMITER_BANDS_BITS 2 +#define SI_SBR_LIMITER_GAINS_BITS 2 +#define SI_SBR_INTERPOL_FREQ_BITS 1 +#define SI_SBR_SMOOTHING_LENGTH_BITS 1 + +/* sbr_grid */ +#define SBR_CLA_BITS 2 /*!< size of bs_frame_class */ +#define SBR_CLA_BITS_LD 1 /*!< size of bs_frame_class */ +#define SBR_ENV_BITS 2 /*!< size of bs_num_env_raw */ +#define SBR_ABS_BITS 2 /*!< size of bs_abs_bord_raw for HE-AAC */ +#define SBR_NUM_BITS 2 /*!< size of bs_num_rel */ +#define SBR_REL_BITS 2 /*!< size of bs_rel_bord_raw */ +#define SBR_RES_BITS 1 /*!< size of bs_freq_res_flag */ +#define SBR_DIR_BITS 1 /*!< size of bs_df_flag */ + + +/* sbr_data */ +#define SI_SBR_INVF_MODE_BITS 2 + + +#define SI_SBR_START_ENV_BITS_AMP_RES_3_0 6 +#define SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_3_0 5 +#define SI_SBR_START_NOISE_BITS_AMP_RES_3_0 5 +#define SI_SBR_START_NOISE_BITS_BALANCE_AMP_RES_3_0 5 + +#define SI_SBR_START_ENV_BITS_AMP_RES_1_5 7 +#define SI_SBR_START_ENV_BITS_BALANCE_AMP_RES_1_5 6 + + +#define SI_SBR_EXTENDED_DATA_BITS 1 +#define SI_SBR_EXTENSION_SIZE_BITS 4 +#define SI_SBR_EXTENSION_ESC_COUNT_BITS 8 +#define SI_SBR_EXTENSION_ID_BITS 2 + +#define SBR_EXTENDED_DATA_MAX_CNT (15+255) + +#define EXTENSION_ID_PS_CODING 2 + +/* Envelope coding constants */ +#define FREQ 0 +#define TIME 1 + + +/* huffman tables */ +#define CODE_BOOK_SCF_LAV00 60 +#define CODE_BOOK_SCF_LAV01 31 +#define CODE_BOOK_SCF_LAV10 60 +#define CODE_BOOK_SCF_LAV11 31 +#define CODE_BOOK_SCF_LAV_BALANCE11 12 +#define CODE_BOOK_SCF_LAV_BALANCE10 24 + +typedef enum +{ + SBR_AMP_RES_1_5=0, + SBR_AMP_RES_3_0 +} +AMP_RES; + +typedef enum +{ + XPOS_MDCT, + XPOS_MDCT_CROSS, + XPOS_LC, + XPOS_RESERVED, + XPOS_SWITCHED /* not a real choice but used here to control behaviour */ +} +XPOS_MODE; + +typedef enum +{ + INVF_OFF = 0, + INVF_LOW_LEVEL, + INVF_MID_LEVEL, + INVF_HIGH_LEVEL, + INVF_SWITCHED /* not a real choice but used here to control behaviour */ +} +INVF_MODE; + +typedef enum +{ + SINGLE_RATE, + DUAL_RATE +} +SR_MODE; + +typedef enum +{ + FREQ_RES_LOW = 0, + FREQ_RES_HIGH +} +FREQ_RES; + + +#endif diff --git a/libSBRenc/src/sbr_encoder.cpp b/libSBRenc/src/sbr_encoder.cpp new file mode 100644 index 0000000..9c3cf37 --- /dev/null +++ b/libSBRenc/src/sbr_encoder.cpp @@ -0,0 +1,2109 @@ +/*************************** Fraunhofer IIS FDK Tools *********************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Andreas Ehret + Description: SBR encoder top level processing. + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ +#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" +#include "psenc_hybrid.h" + +#define SBRENCODER_LIB_VL0 3 +#define SBRENCODER_LIB_VL1 2 +#define SBRENCODER_LIB_VL2 0 + + + +/***************************************************************************/ +/* + * 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 + +****************************************************************************/ +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 + ) +{ + int i, paramSetTop; + + if (core == AOT_ER_AAC_ELD) { + paramSetTop = SBRENC_TUNING_SIZE; + i = 126; + } else { + paramSetTop = 126; + i = 0; + } + + for (; i < paramSetTop ; i++) { + if (numChannels == sbrTuningTable [i].numChannels) { + if ((sampleRate == sbrTuningTable [i].sampleRate) && + (bitrate >= sbrTuningTable [i].bitrateFrom) && + (bitrate < sbrTuningTable [i].bitrateTo)) { + return i ; + } + } + } + + 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){ + + INT i, paramSets = sizeof (psTuningTable) / sizeof (psTuningTable [0]); + + for (i = 0 ; i < paramSets ; i++) { + if ((bitrate >= psTuningTable [i].bitrateFrom) && + (bitrate < psTuningTable [i].bitrateTo)) { + return i ; + } + } + + 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); + + 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); + + 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) { + + /* deleteFrameInfoGenerator (&hEnvCut->SbrEnvFrame); */ + + + + /* deleteSbrCodeEnvelope (&hEnvCut->sbrCodeEnvelope); */ + + /* deleteSbrCodeEnvelope (&hEnvCut->sbrCodeNoiseFloor); */ + + FDKsbrEnc_DeleteTonCorrParamExtr(&hEnvCut->TonCorr); + + FDKsbrEnc_deleteExtractSbrEnvelope (&hEnvCut->sbrExtractEnvelope); + + //FreeRam_EnvChannel(phEnvCut); + } + +} + + +/***************************************************************************** + + 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->hPsEncConfig) + FreeRam_PsEncConf(&hSbrEncoder->hPsEncConfig); + 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+sbrExtrEnv->rBufferWriteOffset; + pQmfImag = sbrExtrEnv->iBuffer+sbrExtrEnv->rBufferWriteOffset; + + 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) + { + int psCh; + + /* Parametric Stereo QMF buffer preprocessing: copy previous qmf data down */ + UpdatePSQmfData_second(hEnvEncoder->hParametricStereo); + + for (psCh = 0; psCh<2; psCh ++) + { + C_ALLOC_SCRATCH_START(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); + HANDLE_PS_QMF_DATA hPsQmfData = hEnvEncoder->hParametricStereo->hPsChannelData[psCh]->hPsQmfData; + QMF_SCALE_FACTOR tmpScale; + + + qmfAnalysisFiltering( hSbrElement->hQmfAnalysis[psCh], + hPsQmfData->rQmfData + hPsQmfData->bufferWriteOffset, + hPsQmfData->iQmfData + hPsQmfData->bufferWriteOffset, + &tmpScale, + samples + hSbrElement->elInfo.ChannelIndex[psCh], + timeInStride, + qmfWorkBuffer ); + + C_ALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); + + hEnvEncoder->hParametricStereo->hPsChannelData[psCh]->psQmfScale = -tmpScale.lb_scale; + } + + + /* 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; + error = FDKsbrEnc_PSEnc_ParametricStereoProcessing( hEnvEncoder->hParametricStereo, + sbrExtrEnv->rBuffer, + sbrExtrEnv->iBuffer, + sbrExtrEnv->rBufferWriteOffset, + 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) { + hSbrEncoder->hPsEncConfig = GetRam_PsEncConf(); + if (hSbrEncoder->hPsEncConfig==NULL) { + goto bail; + } + + 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; +} + + +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) + { + FDK_ASSERT(hSbrEncoder->noElements == 1); + INT psTuningTableIdx = getPsTuningTableIndex(elInfo[0].bitRate); //sbrConfig.codecSettings.bitRate); + + hSbrEncoder->hPsEncConfig->frameSize = *frameLength; //sbrConfig.sbrFrameSize; + hSbrEncoder->hPsEncConfig->qmfFilterMode = 0; + hSbrEncoder->hPsEncConfig->sbrPsDelay = 0; + + /* tuning parameters */ + if (psTuningTableIdx != INVALID_TABLE_IDX) { + hSbrEncoder->hPsEncConfig->nStereoBands = psTuningTable[psTuningTableIdx].nStereoBands; + hSbrEncoder->hPsEncConfig->maxEnvelopes = psTuningTable[psTuningTableIdx].nEnvelopes; + hSbrEncoder->hPsEncConfig->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 * hSbrEncoder->hPsEncConfig->nStereoBands * hSbrEncoder->hPsEncConfig->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 */ + hSbrEncoder->hPsEncConfig->sbrPsDelay = FDKsbrEnc_GetEnvEstDelay(&hSbrEncoder->sbrElement[0]->sbrChannel[0]->hEnvChannel.sbrExtractEnvelope); + + if(noError != (errorInfo = PSEnc_Init( hSbrEncoder->hParametricStereo, + hSbrEncoder->hPsEncConfig, + 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; +} diff --git a/libSBRenc/src/sbr_misc.cpp b/libSBRenc/src/sbr_misc.cpp new file mode 100644 index 0000000..b602e99 --- /dev/null +++ b/libSBRenc/src/sbr_misc.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Sbr miscellaneous helper functions $Revision: 36847 $ +*/ +#include "sbr_misc.h" + + +void FDKsbrEnc_Shellsort_fract (FIXP_DBL *in, INT n) +{ + FIXP_DBL v; + INT i, j; + INT inc = 1; + + do + inc = 3 * inc + 1; + while (inc <= n); + + do { + inc = inc / 3; + for (i = inc + 1; i <= n; i++) { + v = in[i-1]; + j = i; + while (in[j-inc-1] > v) { + in[j-1] = in[j-inc-1]; + j -= inc; + if (j <= inc) + break; + } + in[j-1] = v; + } + } while (inc > 1); + +} + +/* Sorting routine */ +void FDKsbrEnc_Shellsort_int (INT *in, INT n) +{ + + INT i, j, v; + INT inc = 1; + + do + inc = 3 * inc + 1; + while (inc <= n); + + do { + inc = inc / 3; + for (i = inc + 1; i <= n; i++) { + v = in[i-1]; + j = i; + while (in[j-inc-1] > v) { + in[j-1] = in[j-inc-1]; + j -= inc; + if (j <= inc) + break; + } + in[j-1] = v; + } + } while (inc > 1); + +} + + + +/******************************************************************************* + Functionname: FDKsbrEnc_AddVecLeft + ******************************************************************************* + + Description: + + Arguments: INT* dst, INT* length_dst, INT* src, INT length_src + + Return: none + +*******************************************************************************/ +void +FDKsbrEnc_AddVecLeft (INT *dst, INT *length_dst, INT *src, INT length_src) +{ + INT i; + + for (i = length_src - 1; i >= 0; i--) + FDKsbrEnc_AddLeft (dst, length_dst, src[i]); +} + + +/******************************************************************************* + Functionname: FDKsbrEnc_AddLeft + ******************************************************************************* + + Description: + + Arguments: INT* vector, INT* length_vector, INT value + + Return: none + +*******************************************************************************/ +void +FDKsbrEnc_AddLeft (INT *vector, INT *length_vector, INT value) +{ + INT i; + + for (i = *length_vector; i > 0; i--) + vector[i] = vector[i - 1]; + vector[0] = value; + (*length_vector)++; +} + + +/******************************************************************************* + Functionname: FDKsbrEnc_AddRight + ******************************************************************************* + + Description: + + Arguments: INT* vector, INT* length_vector, INT value + + Return: none + +*******************************************************************************/ +void +FDKsbrEnc_AddRight (INT *vector, INT *length_vector, INT value) +{ + vector[*length_vector] = value; + (*length_vector)++; +} + + + +/******************************************************************************* + Functionname: FDKsbrEnc_AddVecRight + ******************************************************************************* + + Description: + + Arguments: INT* dst, INT* length_dst, INT* src, INT length_src) + + Return: none + +*******************************************************************************/ +void +FDKsbrEnc_AddVecRight (INT *dst, INT *length_dst, INT *src, INT length_src) +{ + INT i; + for (i = 0; i < length_src; i++) + FDKsbrEnc_AddRight (dst, length_dst, src[i]); +} + + +/***************************************************************************** + + functionname: FDKsbrEnc_LSI_divide_scale_fract + + description: Calculates division with best precision and scales the result. + + return: num*scale/denom + +*****************************************************************************/ +FIXP_DBL FDKsbrEnc_LSI_divide_scale_fract(FIXP_DBL num, FIXP_DBL denom, FIXP_DBL scale) +{ + FIXP_DBL tmp = FL2FXCONST_DBL(0.0f); + if (num != FL2FXCONST_DBL(0.0f)) { + + INT shiftCommon; + INT shiftNum = CountLeadingBits(num); + INT shiftDenom = CountLeadingBits(denom); + INT shiftScale = CountLeadingBits(scale); + + num = num << shiftNum; + scale = scale << shiftScale; + + tmp = fMultDiv2(num,scale); + + if ( denom > (tmp >> fixMin(shiftNum+shiftScale-1,(DFRACT_BITS-1))) ) { + denom = denom << shiftDenom; + tmp = schur_div(tmp,denom,15); + shiftCommon = fixMin((shiftNum-shiftDenom+shiftScale-1),(DFRACT_BITS-1)); + if (shiftCommon < 0) + tmp <<= -shiftCommon; + else + tmp >>= shiftCommon; + } + else { + tmp = /*FL2FXCONST_DBL(1.0)*/ (FIXP_DBL)MAXVAL_DBL; + } + } + + return (tmp); +} + diff --git a/libSBRenc/src/sbr_misc.h b/libSBRenc/src/sbr_misc.h new file mode 100644 index 0000000..37ec8e3 --- /dev/null +++ b/libSBRenc/src/sbr_misc.h @@ -0,0 +1,48 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Sbr miscellaneous helper functions prototypes $Revision: 36847 $ + \author +*/ + +#ifndef _SBR_MISC_H +#define _SBR_MISC_H + +#include "sbr_encoder.h" + +/* Sorting routines */ +void FDKsbrEnc_Shellsort_fract (FIXP_DBL *in, INT n); +void FDKsbrEnc_Shellsort_int (INT *in, INT n); + +void FDKsbrEnc_AddLeft (INT *vector, INT *length_vector, INT value); +void FDKsbrEnc_AddRight (INT *vector, INT *length_vector, INT value); +void FDKsbrEnc_AddVecLeft (INT *dst, INT *length_dst, INT *src, INT length_src); +void FDKsbrEnc_AddVecRight (INT *dst, INT *length_vector_dst, INT *src, INT length_src); + +FIXP_DBL FDKsbrEnc_LSI_divide_scale_fract(FIXP_DBL num, FIXP_DBL denom, FIXP_DBL scale); + +#endif diff --git a/libSBRenc/src/sbr_ram.cpp b/libSBRenc/src/sbr_ram.cpp new file mode 100644 index 0000000..289270c --- /dev/null +++ b/libSBRenc/src/sbr_ram.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Memory layout + $Revision: 36847 $ + + This module declares all static and dynamic memory spaces +*/ +#include "sbr_ram.h" + +#include "sbr.h" +#include "genericStds.h" + +C_ALLOC_MEM (Ram_SbrDynamic_RAM, FIXP_DBL, ((SBR_ENC_DYN_RAM_SIZE)/sizeof(FIXP_DBL))) + +/*! + \name StaticSbrData + + Static memory areas, must not be overwritten in other sections of the encoder +*/ +/* @{ */ + +/*! static sbr encoder instance for one encoder (2 channels) + all major static and dynamic memory areas are located + in module sbr_ram and sbr rom +*/ +C_ALLOC_MEM (Ram_SbrEncoder, SBR_ENCODER, 1) +C_ALLOC_MEM2(Ram_SbrChannel, SBR_CHANNEL, 1, (6)) +C_ALLOC_MEM2(Ram_SbrElement, SBR_ELEMENT, 1, (6)) + +/*! Filter states for QMF-analysis. <br> + Dimension: #MAXNRSBRCHANNELS * #SBR_QMF_FILTER_LENGTH +*/ +C_AALLOC_MEM2_L (Ram_Sbr_QmfStatesAnalysis, FIXP_QAS, QMF_FILTER_LENGTH, (6), SECT_DATA_L1) + + +/*! Matrix holding the quota values for all estimates, all channels + Dimension #MAXNRSBRCHANNELS * +#SBR_QMF_CHANNELS* #MAX_NO_OF_ESTIMATES +*/ +C_ALLOC_MEM2_L (Ram_Sbr_quotaMatrix, FIXP_DBL, (MAX_NO_OF_ESTIMATES*QMF_CHANNELS), (6), SECT_DATA_L1) + +/*! Matrix holding the sign values for all estimates, all channels + Dimension #MAXNRSBRCHANNELS * +#SBR_QMF_CHANNELS* #MAX_NO_OF_ESTIMATES +*/ +C_ALLOC_MEM2 (Ram_Sbr_signMatrix, INT, (MAX_NO_OF_ESTIMATES*QMF_CHANNELS), (6)) + +/*! Frequency band table (low res) <br> + Dimension #MAX_FREQ_COEFFS/2+1 +*/ +C_ALLOC_MEM2 (Ram_Sbr_freqBandTableLO, UCHAR, (MAX_FREQ_COEFFS/2+1), (6)) + +/*! Frequency band table (high res) <br> + Dimension #MAX_FREQ_COEFFS +1 +*/ +C_ALLOC_MEM2 (Ram_Sbr_freqBandTableHI, UCHAR, (MAX_FREQ_COEFFS+1), (6)) + +/*! vk matser table <br> + Dimension #MAX_FREQ_COEFFS +1 +*/ +C_ALLOC_MEM2 (Ram_Sbr_v_k_master, UCHAR, (MAX_FREQ_COEFFS+1), (6)) + + +/* + Missing harmonics detection +*/ + +/*! sbr_detectionVectors <br> + Dimension #MAX_NUM_CHANNELS*#MAX_NO_OF_ESTIMATES*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2 (Ram_Sbr_detectionVectors, UCHAR, (MAX_NO_OF_ESTIMATES*MAX_FREQ_COEFFS), (6)) + +/*! sbr_prevCompVec[ <br> + Dimension #MAX_NUM_CHANNELS*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2 (Ram_Sbr_prevEnvelopeCompensation, UCHAR, MAX_FREQ_COEFFS, (6)) +/*! sbr_guideScfb[ <br> + Dimension #MAX_NUM_CHANNELS*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2 (Ram_Sbr_guideScfb, UCHAR, MAX_FREQ_COEFFS, (6)) + +/*! sbr_guideVectorDetected <br> + Dimension #MAX_NUM_CHANNELS*#MAX_NO_OF_ESTIMATES*#MAX_FREQ_COEFFS] +*/ +C_ALLOC_MEM2 (Ram_Sbr_guideVectorDetected, UCHAR, (MAX_NO_OF_ESTIMATES*MAX_FREQ_COEFFS), (6)) +C_ALLOC_MEM2 (Ram_Sbr_guideVectorDiff, FIXP_DBL, (MAX_NO_OF_ESTIMATES*MAX_FREQ_COEFFS), (6)) +C_ALLOC_MEM2 (Ram_Sbr_guideVectorOrig, FIXP_DBL, (MAX_NO_OF_ESTIMATES*MAX_FREQ_COEFFS), (6)) + +/* + Static Parametric Stereo memory +*/ +C_AALLOC_MEM_L(Ram_PsQmfStatesSynthesis, FIXP_DBL, QMF_FILTER_LENGTH/2, SECT_DATA_L1) + +C_ALLOC_MEM (Ram_PsEnvRBuffer, FIXP_DBL, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2) +C_ALLOC_MEM (Ram_PsEnvIBuffer, FIXP_DBL, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2) +C_ALLOC_MEM2 (Ram_PsChData, PS_CHANNEL_DATA, 1, MAX_PS_CHANNELS) +C_ALLOC_MEM (Ram_PsEncConf, PSENC_CONFIG, 1) +C_ALLOC_MEM_L (Ram_PsEncode, PS_ENCODE, 1, SECT_DATA_L1) +C_ALLOC_MEM (Ram_PsData, PS_DATA, 1) +C_ALLOC_MEM (Ram_ParamStereo, PARAMETRIC_STEREO, 1) +C_ALLOC_MEM2 (Ram_PsOut, PS_OUT, 1, 2) + + +/* QMF data + */ +C_ALLOC_MEM (Ram_PsQmfNewSamples, FIXP_DBL, QMF_CHANNELS) + +C_ALLOC_MEM2 (Ram_PsQmfData, PS_QMF_DATA, 1, MAX_PS_CHANNELS) + +/* HYBRID data + */ +C_AALLOC_MEM (Ram_PsHybFFT, FIXP_DBL, 16) + +C_ALLOC_MEM2(Ram_HybData, PS_HYBRID_DATA, 1, MAX_PS_CHANNELS) +C_ALLOC_MEM2(Ram_PsHybrid, PS_HYBRID, 1, MAX_PS_CHANNELS) +C_ALLOC_MEM (Ram_PsHybConfig, PS_HYBRID_CONFIG, 1) + +C_ALLOC_MEM2(Ram_PsRhyb, FIXP_QMF, ((HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET)*HYBRID_NUM_BANDS), MAX_PS_CHANNELS) +C_ALLOC_MEM2(Ram_PsIhyb, FIXP_QMF, ((HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET)*HYBRID_NUM_BANDS), MAX_PS_CHANNELS) + +C_ALLOC_MEM (Ram_PsHybWkReal, FIXP_QMF, (HYBRID_FRAMESIZE + QMF_BUFFER_MOVE)) +C_ALLOC_MEM (Ram_PsHybWkImag, FIXP_QMF, (HYBRID_FRAMESIZE + QMF_BUFFER_MOVE)) + +C_ALLOC_MEM2(Ram_PsMtmpReal, FIXP_QMF, (MAX_HYBRID_RES), HYBRID_FRAMESIZE) +C_ALLOC_MEM2(Ram_PsMtmpImag, FIXP_QMF, (MAX_HYBRID_RES), HYBRID_FRAMESIZE) + + +/* @} */ + + +/*! + \name DynamicSbrData + + Dynamic memory areas, might be reused in other algorithm sections, + e.g. the core encoder. +*/ +/* @{ */ + + /*! Energy buffer for envelope extraction <br> + Dimension #MAXNRSBRCHANNELS * +#SBR_QMF_SLOTS * #SBR_QMF_CHANNELS + */ + C_ALLOC_MEM2 (Ram_Sbr_envYBuffer, FIXP_DBL, (QMF_MAX_TIME_SLOTS/2 * QMF_CHANNELS), (6)) + + FIXP_DBL* GetRam_Sbr_envYBuffer (int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM!=0); + return ((FIXP_DBL*) (dynamic_RAM + OFFSET_NRG + (n*Y_2_BUF_BYTE) )); + } + + /* + * QMF data + */ + /* The SBR encoder uses a single channel overlapping buffer set (always n=0), but PS does not. */ + FIXP_DBL* GetRam_Sbr_envRBuffer (int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM!=0); + return ((FIXP_DBL*) (dynamic_RAM + OFFSET_QMF + (n*ENV_R_BUFF_BYTE*2) )); + } + FIXP_DBL* GetRam_Sbr_envIBuffer (int n, UCHAR* dynamic_RAM) { + FDK_ASSERT(dynamic_RAM!=0); + //return ((FIXP_DBL*) (dynamic_RAM + OFFSET_QMF + (MAX_NUM_CHANNELS*ENV_R_BUFF_BYTE) + n*ENV_I_BUFF_BYTE)); + return ((FIXP_DBL*) (dynamic_RAM + OFFSET_QMF + (ENV_R_BUFF_BYTE) + (n*ENV_I_BUFF_BYTE*2))); + } + + /* reuse QMF buffer in PS module. We Require space to hold 2 channels. */ + C_ALLOC_MEM2(Ram_PsRqmf, FIXP_QMF, ((PSENC_QMF_BUFFER_LENGTH-QMF_MAX_TIME_SLOTS)*(QMF_CHANNELS)), MAX_PS_CHANNELS) + C_ALLOC_MEM2(Ram_PsIqmf, FIXP_QMF, ((PSENC_QMF_BUFFER_LENGTH-QMF_MAX_TIME_SLOTS)*(QMF_CHANNELS)), MAX_PS_CHANNELS) + + FIXP_QMF* FDKsbrEnc_SliceRam_PsRqmf(FIXP_DBL* rQmfData, UCHAR* dynamic_RAM, int ch, int i, int qmfSlots) + { + FDK_ASSERT(dynamic_RAM!=0); + if (i<HYBRID_READ_OFFSET) + return rQmfData + (i*(QMF_CHANNELS)); + else if ((i<(HYBRID_READ_OFFSET+qmfSlots))) + return GetRam_Sbr_envRBuffer(ch, dynamic_RAM) + ( (i-(HYBRID_READ_OFFSET))*(QMF_CHANNELS) ); + else + return rQmfData + ((i-qmfSlots)*(QMF_CHANNELS)); + } + + FIXP_QMF* FDKsbrEnc_SliceRam_PsIqmf(FIXP_DBL* iQmfData, UCHAR* dynamic_RAM, int ch, int i, int qmfSlots) + { + FDK_ASSERT(dynamic_RAM!=0); + if (i<HYBRID_READ_OFFSET) + return iQmfData + (i*(QMF_CHANNELS)); + else if ((i<(HYBRID_READ_OFFSET+qmfSlots))) + return GetRam_Sbr_envIBuffer(ch, dynamic_RAM) + ( (i-(HYBRID_READ_OFFSET))*(QMF_CHANNELS) ); + else + return iQmfData + ((i-qmfSlots)*(QMF_CHANNELS)); + } + + + + +/* @} */ + + + + + diff --git a/libSBRenc/src/sbr_ram.h b/libSBRenc/src/sbr_ram.h new file mode 100644 index 0000000..23eca20 --- /dev/null +++ b/libSBRenc/src/sbr_ram.h @@ -0,0 +1,171 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! +\file +\brief Memory layout +$Revision: 36847 $ +*/ +#ifndef __SBR_RAM_H +#define __SBR_RAM_H + +#include "sbr_def.h" +#include "env_est.h" +#include "sbr_encoder.h" +#include "sbr.h" + + + +#include "ps_main.h" +#include "ps_encode.h" + + +#define ENV_TRANSIENTS_BYTE ( (sizeof(FIXP_DBL)*(MAX_NUM_CHANNELS*3*QMF_MAX_TIME_SLOTS)) ) + +#define ENV_R_BUFF_BYTE ( (sizeof(FIXP_DBL)*((QMF_MAX_TIME_SLOTS) * QMF_CHANNELS)) ) +#define ENV_I_BUFF_BYTE ( (sizeof(FIXP_DBL)*((QMF_MAX_TIME_SLOTS) * QMF_CHANNELS)) ) + +#define Y_BUF_CH_BYTE ( (sizeof(FIXP_DBL)*QMF_MAX_TIME_SLOTS * QMF_CHANNELS) ) + +#define ENV_R_BUF_PS_BYTE ( (sizeof(FIXP_DBL)*QMF_MAX_TIME_SLOTS * QMF_CHANNELS / 2) ) +#define ENV_I_BUF_PS_BYTE ( (sizeof(FIXP_DBL)*QMF_MAX_TIME_SLOTS * QMF_CHANNELS / 2) ) + +#define TON_BUF_CH_BYTE ( (sizeof(FIXP_DBL)*(MAX_NO_OF_ESTIMATES*MAX_FREQ_COEFFS)) ) + +#define Y_2_BUF_BYTE ( Y_BUF_CH_BYTE>>1 ) + + +/* Workbuffer RAM - Allocation */ +/* + ++++++++++++++++++++++++++++++++++++++++++++++++++++ + | OFFSET_NRG | OFFSET_QMF | + ++++++++++++++++++++++++++++++++++++++++++++++++++++ + -------------------------------------------------- + | 0.5 * | | + | sbr_envYBuffer_size | sbr_envRBuffer | + | | sbr_envIBuffer | + -------------------------------------------------- + +*/ + #define BUF_NRG_SIZE ( (MAX_NUM_CHANNELS * Y_2_BUF_BYTE) ) + + #define OFFSET_NRG ( 0 ) + #define OFFSET_QMF ( OFFSET_NRG + BUF_NRG_SIZE ) + + /* if common dynamic memory used in AAC-core and SBR, find out maximal size of + SCR buffer (see XX in figure above) */ + /* Only PS required holding 2 channel QMF data. AAC_WK_BUF_SIZE_0 must fit into this buffer. */ + #define BUF_QMF_SIZE ( 2*(ENV_R_BUFF_BYTE + ENV_I_BUFF_BYTE) ) + + /* Size of the shareable memory region than can be reused */ + #define SBR_ENC_DYN_RAM_SIZE ( BUF_NRG_SIZE + BUF_QMF_SIZE ) + +/* + ***************************************************************************************************** + */ + + H_ALLOC_MEM(Ram_SbrDynamic_RAM, FIXP_DBL) + + H_ALLOC_MEM(Ram_SbrEncoder, SBR_ENCODER) + H_ALLOC_MEM(Ram_SbrChannel, SBR_CHANNEL) + H_ALLOC_MEM(Ram_SbrElement, SBR_ELEMENT) + + H_ALLOC_MEM(Ram_Sbr_quotaMatrix, FIXP_DBL) + H_ALLOC_MEM(Ram_Sbr_signMatrix, INT) + + H_ALLOC_MEM(Ram_Sbr_QmfStatesAnalysis, FIXP_QAS) + + H_ALLOC_MEM(Ram_Sbr_freqBandTableLO, UCHAR) + H_ALLOC_MEM(Ram_Sbr_freqBandTableHI, UCHAR) + H_ALLOC_MEM(Ram_Sbr_v_k_master, UCHAR) + + H_ALLOC_MEM(Ram_Sbr_detectionVectors, UCHAR) + H_ALLOC_MEM(Ram_Sbr_prevEnvelopeCompensation, UCHAR) + H_ALLOC_MEM(Ram_Sbr_guideScfb, UCHAR) + H_ALLOC_MEM(Ram_Sbr_guideVectorDetected, UCHAR) + + /* Dynamic Memory Allocation */ + + H_ALLOC_MEM(Ram_Sbr_envYBuffer, FIXP_DBL) + FIXP_DBL* GetRam_Sbr_envYBuffer (int n, UCHAR* dynamic_RAM); + FIXP_DBL* GetRam_Sbr_envRBuffer (int n, UCHAR* dynamic_RAM); + FIXP_DBL* GetRam_Sbr_envIBuffer (int n, UCHAR* dynamic_RAM); + + H_ALLOC_MEM(Ram_Sbr_guideVectorDiff, FIXP_DBL) + H_ALLOC_MEM(Ram_Sbr_guideVectorOrig, FIXP_DBL) + + + H_ALLOC_MEM(Ram_PsEnvRBuffer, FIXP_QMF) + H_ALLOC_MEM(Ram_PsEnvIBuffer, FIXP_QMF) + + H_ALLOC_MEM(Ram_PsQmfStatesSynthesis, FIXP_DBL) + H_ALLOC_MEM(Ram_PsQmfNewSamples, FIXP_DBL) + + H_ALLOC_MEM(Ram_PsEncConf, PSENC_CONFIG) + H_ALLOC_MEM(Ram_PsEncode, PS_ENCODE) + H_ALLOC_MEM(Ram_PsData, PS_DATA) + +#define HYBRID_READ_OFFSET ( 10 ) +#define HYBRID_WRITE_OFFSET ( ((32)>>1)-6 ) + +#define HYBRID_DATA_READ_OFFSET ( 0 ) +#define QMF_READ_OFFSET ( 0 ) + + H_ALLOC_MEM(Ram_PsRqmf, FIXP_DBL) + H_ALLOC_MEM(Ram_PsIqmf, FIXP_DBL) + FIXP_DBL* FDKsbrEnc_SliceRam_PsRqmf (FIXP_DBL* rQmfData, UCHAR* dynamic_RAM, int n, int i, int qmfSlots); + FIXP_DBL* FDKsbrEnc_SliceRam_PsIqmf (FIXP_DBL* iQmfData, UCHAR* dynamic_RAM, int n, int i, int qmfSlots); + + H_ALLOC_MEM(Ram_PsQmfData, PS_QMF_DATA) + H_ALLOC_MEM(Ram_PsChData, PS_CHANNEL_DATA) + + H_ALLOC_MEM(Ram_ParamStereo, PARAMETRIC_STEREO) + H_ALLOC_MEM(Ram_PsOut, PS_OUT) + + /* HYBRID */ + H_ALLOC_MEM(Ram_PsHybFFT, FIXP_DBL) + + H_ALLOC_MEM(Ram_HybData, PS_HYBRID_DATA) + H_ALLOC_MEM(Ram_PsRhyb, FIXP_DBL) + H_ALLOC_MEM(Ram_PsIhyb, FIXP_DBL) + + H_ALLOC_MEM(Ram_PsHybConfig, PS_HYBRID_CONFIG) + H_ALLOC_MEM(Ram_PsHybrid, PS_HYBRID) + + FIXP_DBL* psMqmfBufferRealInit (INT ch, INT i); + FIXP_DBL* psMqmfBufferImagInit (INT ch, INT i); + + + /* working buffer */ + H_ALLOC_MEM(Ram_PsHybWkReal, FIXP_DBL) + H_ALLOC_MEM(Ram_PsHybWkImag, FIXP_DBL) + + H_ALLOC_MEM(Ram_PsMtmpReal, FIXP_DBL) + H_ALLOC_MEM(Ram_PsMtmpImag, FIXP_DBL) + + + +#endif + diff --git a/libSBRenc/src/sbr_rom.cpp b/libSBRenc/src/sbr_rom.cpp new file mode 100644 index 0000000..e83a519 --- /dev/null +++ b/libSBRenc/src/sbr_rom.cpp @@ -0,0 +1,681 @@ +/******************************** MPEG Audio Encoder ************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ +******************************************************************************/ +/*! + \file + \brief Definition of constant tables + $Revision: 36914 $ + + This module contains most of the constant data that can be stored in ROM. +*/ + +#include "sbr_rom.h" +#include "genericStds.h" + +//@{ +/******************************************************************************* + + Table Overview: + + o envelope level, 1.5 dB: + 1a) v_Huff_envelopeLevelC10T[121] + 1b) v_Huff_envelopeLevelL10T[121] + 2a) v_Huff_envelopeLevelC10F[121] + 2b) v_Huff_envelopeLevelL10F[121] + + o envelope balance, 1.5 dB: + 3a) bookSbrEnvBalanceC10T[49] + 3b) bookSbrEnvBalanceL10T[49] + 4a) bookSbrEnvBalanceC10F[49] + 4b) bookSbrEnvBalanceL10F[49] + + o envelope level, 3.0 dB: + 5a) v_Huff_envelopeLevelC11T[63] + 5b) v_Huff_envelopeLevelL11T[63] + 6a) v_Huff_envelopeLevelC11F[63] + 6b) v_Huff_envelopeLevelC11F[63] + + o envelope balance, 3.0 dB: + 7a) bookSbrEnvBalanceC11T[25] + 7b) bookSbrEnvBalanceL11T[25] + 8a) bookSbrEnvBalanceC11F[25] + 8b) bookSbrEnvBalanceL11F[25] + + o noise level, 3.0 dB: + 9a) v_Huff_NoiseLevelC11T[63] + 9b) v_Huff_NoiseLevelL11T[63] + - ) (v_Huff_envelopeLevelC11F[63] is used for freq dir) + - ) (v_Huff_envelopeLevelL11F[63] is used for freq dir) + + o noise balance, 3.0 dB: + 10a) bookSbrNoiseBalanceC11T[25] + 10b) bookSbrNoiseBalanceL11T[25] + - ) (bookSbrEnvBalanceC11F[25] is used for freq dir) + - ) (bookSbrEnvBalanceL11F[25] is used for freq dir) + + + (1.5 dB is never used for noise) + +********************************************************************************/ + + +/*******************************************************************************/ +/* table : envelope level, 1.5 dB */ +/* theor range : [-58,58], CODE_BOOK_SCF_LAV = 58 */ +/* implem range: [-60,60], CODE_BOOK_SCF_LAV10 = 60 */ +/* raw stats : envelopeLevel_00 (yes, wrong suffix in name) KK 01-03-09 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C2FIX.m/envelopeLevel_00T_cF.mat/v_nChex_cF + built by : FH 01-07-05 */ + +const INT v_Huff_envelopeLevelC10T[121] = +{ + 0x0003FFD6, 0x0003FFD7, 0x0003FFD8, 0x0003FFD9, 0x0003FFDA, 0x0003FFDB, 0x0007FFB8, 0x0007FFB9, + 0x0007FFBA, 0x0007FFBB, 0x0007FFBC, 0x0007FFBD, 0x0007FFBE, 0x0007FFBF, 0x0007FFC0, 0x0007FFC1, + 0x0007FFC2, 0x0007FFC3, 0x0007FFC4, 0x0007FFC5, 0x0007FFC6, 0x0007FFC7, 0x0007FFC8, 0x0007FFC9, + 0x0007FFCA, 0x0007FFCB, 0x0007FFCC, 0x0007FFCD, 0x0007FFCE, 0x0007FFCF, 0x0007FFD0, 0x0007FFD1, + 0x0007FFD2, 0x0007FFD3, 0x0001FFE6, 0x0003FFD4, 0x0000FFF0, 0x0001FFE9, 0x0003FFD5, 0x0001FFE7, + 0x0000FFF1, 0x0000FFEC, 0x0000FFED, 0x0000FFEE, 0x00007FF4, 0x00003FF9, 0x00003FF7, 0x00001FFA, + 0x00001FF9, 0x00000FFB, 0x000007FC, 0x000003FC, 0x000001FD, 0x000000FD, 0x0000007D, 0x0000003D, + 0x0000001D, 0x0000000D, 0x00000005, 0x00000001, 0x00000000, 0x00000004, 0x0000000C, 0x0000001C, + 0x0000003C, 0x0000007C, 0x000000FC, 0x000001FC, 0x000003FD, 0x00000FFA, 0x00001FF8, 0x00003FF6, + 0x00003FF8, 0x00007FF5, 0x0000FFEF, 0x0001FFE8, 0x0000FFF2, 0x0007FFD4, 0x0007FFD5, 0x0007FFD6, + 0x0007FFD7, 0x0007FFD8, 0x0007FFD9, 0x0007FFDA, 0x0007FFDB, 0x0007FFDC, 0x0007FFDD, 0x0007FFDE, + 0x0007FFDF, 0x0007FFE0, 0x0007FFE1, 0x0007FFE2, 0x0007FFE3, 0x0007FFE4, 0x0007FFE5, 0x0007FFE6, + 0x0007FFE7, 0x0007FFE8, 0x0007FFE9, 0x0007FFEA, 0x0007FFEB, 0x0007FFEC, 0x0007FFED, 0x0007FFEE, + 0x0007FFEF, 0x0007FFF0, 0x0007FFF1, 0x0007FFF2, 0x0007FFF3, 0x0007FFF4, 0x0007FFF5, 0x0007FFF6, + 0x0007FFF7, 0x0007FFF8, 0x0007FFF9, 0x0007FFFA, 0x0007FFFB, 0x0007FFFC, 0x0007FFFD, 0x0007FFFE, + 0x0007FFFF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C2FIX.m/envelopeLevel_00T_cF.mat/v_nLhex_cF + built by : FH 01-07-05 */ + +const UCHAR v_Huff_envelopeLevelL10T[121] = +{ + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x11, 0x12, 0x10, 0x11, 0x12, 0x11, 0x10, 0x10, 0x10, 0x10, 0x0F, 0x0E, 0x0E, 0x0D, + 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0C, 0x0D, 0x0E, 0x0E, 0x0F, 0x10, 0x11, 0x10, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 +}; + + +/* direction: freq + contents : codewords + raw table: HuffCode3C2FIX.m/envelopeLevel_00F_cF.mat/v_nChex_cF + built by : FH 01-07-05 */ + +const INT v_Huff_envelopeLevelC10F[121] = +{ + 0x0007FFE7, 0x0007FFE8, 0x000FFFD2, 0x000FFFD3, 0x000FFFD4, 0x000FFFD5, 0x000FFFD6, 0x000FFFD7, + 0x000FFFD8, 0x0007FFDA, 0x000FFFD9, 0x000FFFDA, 0x000FFFDB, 0x000FFFDC, 0x0007FFDB, 0x000FFFDD, + 0x0007FFDC, 0x0007FFDD, 0x000FFFDE, 0x0003FFE4, 0x000FFFDF, 0x000FFFE0, 0x000FFFE1, 0x0007FFDE, + 0x000FFFE2, 0x000FFFE3, 0x000FFFE4, 0x0007FFDF, 0x000FFFE5, 0x0007FFE0, 0x0003FFE8, 0x0007FFE1, + 0x0003FFE0, 0x0003FFE9, 0x0001FFEF, 0x0003FFE5, 0x0001FFEC, 0x0001FFED, 0x0001FFEE, 0x0000FFF4, + 0x0000FFF3, 0x0000FFF0, 0x00007FF7, 0x00007FF6, 0x00003FFA, 0x00001FFA, 0x00001FF9, 0x00000FFA, + 0x00000FF8, 0x000007F9, 0x000003FB, 0x000001FC, 0x000001FA, 0x000000FB, 0x0000007C, 0x0000003C, + 0x0000001C, 0x0000000C, 0x00000005, 0x00000001, 0x00000000, 0x00000004, 0x0000000D, 0x0000001D, + 0x0000003D, 0x000000FA, 0x000000FC, 0x000001FB, 0x000003FA, 0x000007F8, 0x000007FA, 0x000007FB, + 0x00000FF9, 0x00000FFB, 0x00001FF8, 0x00001FFB, 0x00003FF8, 0x00003FF9, 0x0000FFF1, 0x0000FFF2, + 0x0001FFEA, 0x0001FFEB, 0x0003FFE1, 0x0003FFE2, 0x0003FFEA, 0x0003FFE3, 0x0003FFE6, 0x0003FFE7, + 0x0003FFEB, 0x000FFFE6, 0x0007FFE2, 0x000FFFE7, 0x000FFFE8, 0x000FFFE9, 0x000FFFEA, 0x000FFFEB, + 0x000FFFEC, 0x0007FFE3, 0x000FFFED, 0x000FFFEE, 0x000FFFEF, 0x000FFFF0, 0x0007FFE4, 0x000FFFF1, + 0x0003FFEC, 0x000FFFF2, 0x000FFFF3, 0x0007FFE5, 0x0007FFE6, 0x000FFFF4, 0x000FFFF5, 0x000FFFF6, + 0x000FFFF7, 0x000FFFF8, 0x000FFFF9, 0x000FFFFA, 0x000FFFFB, 0x000FFFFC, 0x000FFFFD, 0x000FFFFE, + 0x000FFFFF +}; + + +/* direction: freq + contents : codeword lengths + raw table: HuffCode3C2FIX.m/envelopeLevel_00F_cF.mat/v_nLhex_cF + built by : FH 01-07-05 */ + +const UCHAR v_Huff_envelopeLevelL10F[121] = +{ + 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x13, 0x14, 0x14, 0x14, 0x14, 0x13, 0x14, + 0x13, 0x13, 0x14, 0x12, 0x14, 0x14, 0x14, 0x13, 0x14, 0x14, 0x14, 0x13, 0x14, 0x13, 0x12, 0x13, + 0x12, 0x12, 0x11, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x10, 0x0F, 0x0F, 0x0E, 0x0D, 0x0D, 0x0C, + 0x0C, 0x0B, 0x0A, 0x09, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x08, 0x08, 0x09, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, 0x0E, 0x0E, 0x10, 0x10, + 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x14, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x13, 0x14, 0x14, 0x14, 0x14, 0x13, 0x14, 0x12, 0x14, 0x14, 0x13, 0x13, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 +}; + + +/*******************************************************************************/ +/* table : envelope balance, 1.5 dB */ +/* theor range : [-48,48], CODE_BOOK_SCF_LAV = 48 */ +/* implem range: same but mapped to [-24,24], CODE_BOOK_SCF_LAV_BALANCE10 = 24 */ +/* raw stats : envelopePan_00 (yes, wrong suffix in name) KK 01-03-09 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C.m/envelopePan_00T.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC10T[49] = +{ + 0x0000FFE4, 0x0000FFE5, 0x0000FFE6, 0x0000FFE7, 0x0000FFE8, 0x0000FFE9, 0x0000FFEA, 0x0000FFEB, + 0x0000FFEC, 0x0000FFED, 0x0000FFEE, 0x0000FFEF, 0x0000FFF0, 0x0000FFF1, 0x0000FFF2, 0x0000FFF3, + 0x0000FFF4, 0x0000FFE2, 0x00000FFC, 0x000007FC, 0x000001FE, 0x0000007E, 0x0000001E, 0x00000006, + 0x00000000, 0x00000002, 0x0000000E, 0x0000003E, 0x000000FE, 0x000007FD, 0x00000FFD, 0x00007FF0, + 0x0000FFE3, 0x0000FFF5, 0x0000FFF6, 0x0000FFF7, 0x0000FFF8, 0x0000FFF9, 0x0000FFFA, 0x0001FFF6, + 0x0001FFF7, 0x0001FFF8, 0x0001FFF9, 0x0001FFFA, 0x0001FFFB, 0x0001FFFC, 0x0001FFFD, 0x0001FFFE, + 0x0001FFFF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C.m/envelopePan_00T.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL10T[49] = +{ + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x0C, 0x0B, 0x09, 0x07, 0x05, 0x03, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0B, 0x0C, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11 +}; + + +/* direction: freq + contents : codewords + raw table: HuffCode3C.m/envelopePan_00F.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC10F[49] = +{ + 0x0003FFE2, 0x0003FFE3, 0x0003FFE4, 0x0003FFE5, 0x0003FFE6, 0x0003FFE7, 0x0003FFE8, 0x0003FFE9, + 0x0003FFEA, 0x0003FFEB, 0x0003FFEC, 0x0003FFED, 0x0003FFEE, 0x0003FFEF, 0x0003FFF0, 0x0000FFF7, + 0x0001FFF0, 0x00003FFC, 0x000007FE, 0x000007FC, 0x000000FE, 0x0000007E, 0x0000000E, 0x00000002, + 0x00000000, 0x00000006, 0x0000001E, 0x0000003E, 0x000001FE, 0x000007FD, 0x00000FFE, 0x00007FFA, + 0x0000FFF6, 0x0003FFF1, 0x0003FFF2, 0x0003FFF3, 0x0003FFF4, 0x0003FFF5, 0x0003FFF6, 0x0003FFF7, + 0x0003FFF8, 0x0003FFF9, 0x0003FFFA, 0x0003FFFB, 0x0003FFFC, 0x0003FFFD, 0x0003FFFE, 0x0007FFFE, + 0x0007FFFF +}; + + +/* direction: freq + contents : codeword lengths + raw table: HuffCode3C.m/envelopePan_00F.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL10F[49] = +{ + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x10, + 0x11, 0x0E, 0x0B, 0x0B, 0x08, 0x07, 0x04, 0x02, 0x01, 0x03, 0x05, 0x06, 0x09, 0x0B, 0x0C, 0x0F, + 0x10, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, + 0x13 +}; + + +/*******************************************************************************/ +/* table : envelope level, 3.0 dB */ +/* theor range : [-29,29], CODE_BOOK_SCF_LAV = 29 */ +/* implem range: [-31,31], CODE_BOOK_SCF_LAV11 = 31 */ +/* raw stats : envelopeLevel_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const INT v_Huff_envelopeLevelC11T[63] = { + 0x0003FFED, 0x0003FFEE, 0x0007FFDE, 0x0007FFDF, 0x0007FFE0, 0x0007FFE1, 0x0007FFE2, 0x0007FFE3, + 0x0007FFE4, 0x0007FFE5, 0x0007FFE6, 0x0007FFE7, 0x0007FFE8, 0x0007FFE9, 0x0007FFEA, 0x0007FFEB, + 0x0007FFEC, 0x0001FFF4, 0x0000FFF7, 0x0000FFF9, 0x0000FFF8, 0x00003FFB, 0x00003FFA, 0x00003FF8, + 0x00001FFA, 0x00000FFC, 0x000007FC, 0x000000FE, 0x0000003E, 0x0000000E, 0x00000002, 0x00000000, + 0x00000006, 0x0000001E, 0x0000007E, 0x000001FE, 0x000007FD, 0x00001FFB, 0x00003FF9, 0x00003FFC, + 0x00007FFA, 0x0000FFF6, 0x0001FFF5, 0x0003FFEC, 0x0007FFED, 0x0007FFEE, 0x0007FFEF, 0x0007FFF0, + 0x0007FFF1, 0x0007FFF2, 0x0007FFF3, 0x0007FFF4, 0x0007FFF5, 0x0007FFF6, 0x0007FFF7, 0x0007FFF8, + 0x0007FFF9, 0x0007FFFA, 0x0007FFFB, 0x0007FFFC, 0x0007FFFD, 0x0007FFFE, 0x0007FFFF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const UCHAR v_Huff_envelopeLevelL11T[63] = { + 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x11, 0x10, 0x10, 0x10, 0x0E, 0x0E, 0x0E, 0x0D, 0x0C, 0x0B, 0x08, 0x06, 0x04, 0x02, 0x01, + 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0E, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 +}; + + +/* direction: freq + contents : codewords + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const INT v_Huff_envelopeLevelC11F[63] = { + 0x000FFFF0, 0x000FFFF1, 0x000FFFF2, 0x000FFFF3, 0x000FFFF4, 0x000FFFF5, 0x000FFFF6, 0x0003FFF3, + 0x0007FFF5, 0x0007FFEE, 0x0007FFEF, 0x0007FFF6, 0x0003FFF4, 0x0003FFF2, 0x000FFFF7, 0x0007FFF0, + 0x0001FFF5, 0x0003FFF0, 0x0001FFF4, 0x0000FFF7, 0x0000FFF6, 0x00007FF8, 0x00003FFB, 0x00000FFD, + 0x000007FD, 0x000003FD, 0x000001FD, 0x000000FD, 0x0000003E, 0x0000000E, 0x00000002, 0x00000000, + 0x00000006, 0x0000001E, 0x000000FC, 0x000001FC, 0x000003FC, 0x000007FC, 0x00000FFC, 0x00001FFC, + 0x00003FFA, 0x00007FF9, 0x00007FFA, 0x0000FFF8, 0x0000FFF9, 0x0001FFF6, 0x0001FFF7, 0x0003FFF5, + 0x0003FFF6, 0x0003FFF1, 0x000FFFF8, 0x0007FFF1, 0x0007FFF2, 0x0007FFF3, 0x000FFFF9, 0x0007FFF7, + 0x0007FFF4, 0x000FFFFA, 0x000FFFFB, 0x000FFFFC, 0x000FFFFD, 0x000FFFFE, 0x000FFFFF +}; + + +/* direction: freq + contents : codeword lengths + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const UCHAR v_Huff_envelopeLevelL11F[63] = { + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x12, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12, 0x14, 0x13, + 0x11, 0x12, 0x11, 0x10, 0x10, 0x0F, 0x0E, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01, + 0x03, 0x05, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x11, 0x11, 0x12, + 0x12, 0x12, 0x14, 0x13, 0x13, 0x13, 0x14, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 +}; + + + +/*******************************************************************************/ +/* table : envelope balance, 3.0 dB */ +/* theor range : [-24,24], CODE_BOOK_SCF_LAV = 24 */ +/* implem range: same but mapped to [-12,12], CODE_BOOK_SCF_LAV_BALANCE11 = 12 */ +/* raw stats : envelopeBalance_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C.m/envelopeBalance_11T.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC11T[25] = +{ + 0x00001FF2, 0x00001FF3, 0x00001FF4, 0x00001FF5, 0x00001FF6, 0x00001FF7, 0x00001FF8, 0x00000FF8, + 0x000000FE, 0x0000007E, 0x0000000E, 0x00000006, 0x00000000, 0x00000002, 0x0000001E, 0x0000003E, + 0x000001FE, 0x00001FF9, 0x00001FFA, 0x00001FFB, 0x00001FFC, 0x00001FFD, 0x00001FFE, 0x00003FFE, + 0x00003FFF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C.m/envelopeBalance_11T.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL11T[25] = +{ + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x08, 0x07, 0x04, 0x03, 0x01, 0x02, 0x05, 0x06, + 0x09, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E +}; + + +/* direction: freq + contents : codewords + raw table: HuffCode3C.m/envelopeBalance_11F.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrEnvBalanceC11F[25] = +{ + 0x00001FF7, 0x00001FF8, 0x00001FF9, 0x00001FFA, 0x00001FFB, 0x00003FF8, 0x00003FF9, 0x000007FC, + 0x000000FE, 0x0000007E, 0x0000000E, 0x00000002, 0x00000000, 0x00000006, 0x0000001E, 0x0000003E, + 0x000001FE, 0x00000FFA, 0x00001FF6, 0x00003FFA, 0x00003FFB, 0x00003FFC, 0x00003FFD, 0x00003FFE, + 0x00003FFF +}; + + +/* direction: freq + contents : codeword lengths + raw table: HuffCode3C.m/envelopeBalance_11F.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrEnvBalanceL11F[25] = +{ + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, 0x0E, 0x0B, 0x08, 0x07, 0x04, 0x02, 0x01, 0x03, 0x05, 0x06, + 0x09, 0x0C, 0x0D, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E +}; + + +/*******************************************************************************/ +/* table : noise level, 3.0 dB */ +/* theor range : [-29,29], CODE_BOOK_SCF_LAV = 29 */ +/* implem range: [-31,31], CODE_BOOK_SCF_LAV11 = 31 */ +/* raw stats : noiseLevel_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const INT v_Huff_NoiseLevelC11T[63] = { + 0x00001FCE, 0x00001FCF, 0x00001FD0, 0x00001FD1, 0x00001FD2, 0x00001FD3, 0x00001FD4, 0x00001FD5, + 0x00001FD6, 0x00001FD7, 0x00001FD8, 0x00001FD9, 0x00001FDA, 0x00001FDB, 0x00001FDC, 0x00001FDD, + 0x00001FDE, 0x00001FDF, 0x00001FE0, 0x00001FE1, 0x00001FE2, 0x00001FE3, 0x00001FE4, 0x00001FE5, + 0x00001FE6, 0x00001FE7, 0x000007F2, 0x000000FD, 0x0000003E, 0x0000000E, 0x00000006, 0x00000000, + 0x00000002, 0x0000001E, 0x000000FC, 0x000003F8, 0x00001FCC, 0x00001FE8, 0x00001FE9, 0x00001FEA, + 0x00001FEB, 0x00001FEC, 0x00001FCD, 0x00001FED, 0x00001FEE, 0x00001FEF, 0x00001FF0, 0x00001FF1, + 0x00001FF2, 0x00001FF3, 0x00001FF4, 0x00001FF5, 0x00001FF6, 0x00001FF7, 0x00001FF8, 0x00001FF9, + 0x00001FFA, 0x00001FFB, 0x00001FFC, 0x00001FFD, 0x00001FFE, 0x00003FFE, 0x00003FFF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode2.m + built by : FH 00-02-04 */ + +const UCHAR v_Huff_NoiseLevelL11T[63] = { + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000B, 0x00000008, 0x00000006, 0x00000004, 0x00000003, 0x00000001, + 0x00000002, 0x00000005, 0x00000008, 0x0000000A, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, + 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000D, 0x0000000E, 0x0000000E +}; + + +/*******************************************************************************/ +/* table : noise balance, 3.0 dB */ +/* theor range : [-24,24], CODE_BOOK_SCF_LAV = 24 */ +/* implem range: same but mapped to [-12,12], CODE_BOOK_SCF_LAV_BALANCE11 = 12 */ +/* raw stats : noiseBalance_11 KK 00-02-03 */ +/*******************************************************************************/ + +/* direction: time + contents : codewords + raw table: HuffCode3C.m/noiseBalance_11.mat/v_nBhex + built by : FH 01-05-15 */ + +const INT bookSbrNoiseBalanceC11T[25] = +{ + 0x000000EC, 0x000000ED, 0x000000EE, 0x000000EF, 0x000000F0, 0x000000F1, 0x000000F2, 0x000000F3, + 0x000000F4, 0x000000F5, 0x0000001C, 0x00000002, 0x00000000, 0x00000006, 0x0000003A, 0x000000F6, + 0x000000F7, 0x000000F8, 0x000000F9, 0x000000FA, 0x000000FB, 0x000000FC, 0x000000FD, 0x000000FE, + 0x000000FF +}; + + +/* direction: time + contents : codeword lengths + raw table: HuffCode3C.m/noiseBalance_11.mat/v_nLhex + built by : FH 01-05-15 */ + +const UCHAR bookSbrNoiseBalanceL11T[25] = +{ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x05, 0x02, 0x01, 0x03, 0x06, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +/* + tuningTable +*/ +const sbrTuningTable_t sbrTuningTable[SBRENC_TUNING_SIZE] = +{ + + /*** AAC ***/ + /* sf,sfsp,sf,sfsp,nnb,nfo,saml,SM,FS*/ + + /*** mono ***/ + + /* 8/16 kHz dual rate */ + { 8000, 10000, 8000, 1, 7, 6, 11,10, 1, 0, 6, SBR_MONO, 3 }, + { 10000, 12000, 8000, 1, 11, 7, 13,12, 1, 0, 6, SBR_MONO, 3 }, + { 12000, 16001, 8000, 1, 14,10, 13,13, 1, 0, 6, SBR_MONO, 3 }, + { 16000, 24000, 8000, 1, 14,10, 14,14, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 24000, 32000, 8000, 1, 14,10, 14,14, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 32000, 48001, 8000, 1, 14,11, 15,15, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ /* bitrates higher than 48000 not supported by AAC core */ + + /* 11/22 kHz dual rate */ + { 8000, 10000, 11025, 1, 5, 4, 6, 6, 1, 0, 6, SBR_MONO, 3 }, + { 10000, 12000, 11025, 1, 8, 5, 12, 9, 1, 0, 6, SBR_MONO, 3 }, + { 12000, 16000, 11025, 1, 12, 8, 13, 8, 1, 0, 6, SBR_MONO, 3 }, + { 16000, 20000, 11025, 1, 12, 8, 13, 8, 1, 0, 6, SBR_MONO, 3 }, /* at such "high" bitrates it's better to upsample the input */ + { 20000, 24001, 11025, 1, 13, 9, 13, 8, 1, 0, 6, SBR_MONO, 3 }, /* signal by a factor of 2 before sending it into the encoder */ + { 24000, 32000, 11025, 1, 14,10, 14, 9, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 32000, 48000, 11025, 1, 15,11, 15,10, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 48000, 64001, 11025, 1, 15,11, 15,10, 2, 0, 3, SBR_MONO, 1 }, /* placebo */ + + /* 12/24 kHz dual rate */ + { 8000, 10000, 12000, 1, 4, 3, 6, 6, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 8 kbit/s */ + { 10000, 12000, 12000, 1, 7, 4, 11, 8, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 10 kbit/s */ + { 12000, 16000, 12000, 1, 11, 7, 12, 8, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 20000, 12000, 1, 11, 7, 12, 8, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ /* at such "high" bitrates it's better to upsample the input */ + { 20000, 24001, 12000, 1, 12, 8, 12, 8, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 20 kbit/s */ /* signal by a factor of 2 before sending it into the encoder */ + { 24000, 32000, 12000, 1, 13, 9, 13, 9, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 32000, 48000, 12000, 1, 14,10, 14,10, 2, 0, 3, SBR_MONO, 2 }, /* placebo */ + { 48000, 64001, 12000, 1, 15,11, 15,11, 2, 0, 3, SBR_MONO, 1 }, /* placebo */ + + /* 16/32 kHz dual rate */ + { 8000, 10000, 16000, 1, 1, 1, 0, 0, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 8 kbit/s */ + { 10000, 12000, 16000, 1, 2, 1, 6, 0, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 10 kbit/s */ + { 12000, 16000, 16000, 1, 4, 2, 6, 0, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 18000, 16000, 1, 4, 2, 8, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 16000, 1, 6, 5,11, 7, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 22000, 28000, 16000, 1, 10, 9,12, 8, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 16000, 1, 12,12,13,13, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 16000, 1, 14,14,13,13, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ + { 44000, 64001, 16000, 1, 15,15,13,13, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + + /* 22.05/44.1 kHz dual rate */ + /* { 8000, 11369, 22050, 1, 1, 1, 1, 1, 1, 0, 6, SBR_MONO, 3 }, */ /* nominal: 8 kbit/s */ /* encoder can not work stable at this extremely low bitrate */ + { 11369, 16000, 22050, 1, 3, 1, 4, 4, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 18000, 22050, 1, 3, 1, 5, 4, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 22050, 1, 4, 4, 8, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 22000, 28000, 22050, 1, 7, 6, 8, 6, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 22050, 1, 10,10, 9, 9, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 22050, 1, 11,11,10,10, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ + { 44000, 64001, 22050, 1, 13,13,12,12, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + + /* 24/48 kHz dual rate */ + /* { 8000, 12000, 24000, 1, 1, 1, 1, 1, 1, 0, 6, SBR_MONO, 3 }, */ /* nominal: 8 kbit/s */ /* encoder can not work stable at this extremely low bitrate */ + { 12000, 16000, 24000, 1, 3, 1, 4, 4, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 18000, 24000, 1, 3, 1, 5, 4, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 24000, 1, 4, 3, 8, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 22000, 28000, 24000, 1, 7, 6, 8, 6, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 24000, 1, 10,10, 9, 9, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 24000, 1, 11,11,10,10, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ + { 44000, 64001, 24000, 1, 13,13,11,11, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + + /* 32/64 kHz dual rate */ /* placebo settings */ + { 24000, 36000, 32000, 1, 4, 4, 4, 4, 2, 0, 3, SBR_MONO, 3 }, /* lowest range */ + { 36000, 60000, 32000, 1, 7, 7, 6, 6, 2, 0, 3, SBR_MONO, 2 }, /* lowest range */ + { 60000, 72000, 32000, 1, 9, 9, 8, 8, 2, 0, 3, SBR_MONO, 1 }, /* low range */ + { 72000,100000, 32000, 1, 11,11,10,10, 2, 0, 3, SBR_MONO, 1 }, /* SBR sweet spot */ + { 100000,160001, 32000, 1, 13,13,11,11, 2, 0, 3, SBR_MONO, 1 }, /* backwards compatible */ + + /* 44.1/88.2 kHz dual rate */ /* placebo settings */ + { 24000, 36000, 44100, 1, 4, 4, 4, 4, 2, 0, 3, SBR_MONO, 3 }, /* lowest range (multichannel rear) */ + { 36000, 60000, 44100, 1, 7, 7, 6, 6, 2, 0, 3, SBR_MONO, 2 }, /* lowest range (multichannel rear) */ + { 60000, 72000, 44100, 1, 9, 9, 8, 8, 2, 0, 3, SBR_MONO, 1 }, /* low range */ + { 72000,100000, 44100, 1, 11,11,10,10, 2, 0, 3, SBR_MONO, 1 }, /* SBR sweet spot */ + { 100000,160001, 44100, 1, 13,13,11,11, 2, 0, 3, SBR_MONO, 1 }, /* backwards compatible */ + + /* 48/96 kHz dual rate */ /* not yet finally tuned */ + { 24000, 36000, 48000, 1, 4, 4, 9, 9, 2, 0, 3, SBR_MONO, 3 }, /* lowest range (multichannel rear) */ + { 36000, 60000, 48000, 1, 7, 7,10,10, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 40 */ + { 60000, 72000, 48000, 1, 9, 9,10,10, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 64 */ + { 72000,100000, 48000, 1, 11,11,11,11, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 80 */ + { 100000,160001, 48000, 1, 13,13,11,11, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 128 */ + + /*** stereo ***/ + /* 08/16 kHz dual rate */ + { 16000, 24000, 8000, 2, 6, 6, 9, 7, 1, 0,-3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ /* placebo */ + { 24000, 28000, 8000, 2, 9, 9, 11, 9, 1, 0,-3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 8000, 2, 11, 9, 11, 9, 2, 0,-3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 8000, 2, 13,11, 13,11, 2, 0,-3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 8000, 2, 14,12, 13,12, 2, 0,-3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 8000, 2, 15,15, 13,13, 3, 0,-3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 8000, 2, 15,15, 13,13, 3, 0,-3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 8000, 2, 15,15, 13,13, 3, 0,-3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 11/22 kHz dual rate */ + { 16000, 24000, 11025, 2, 7, 5, 9, 7, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ /* placebo */ + { 24000, 28000, 11025, 2, 10, 8,10, 8, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 11025, 2, 12, 8,12, 8, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 11025, 2, 13, 9,13, 9, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 11025, 2, 14,11,13,11, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 11025, 2, 15,15,13,13, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 11025, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 11025, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 12/24 kHz dual rate */ + { 16000, 24000, 12000, 2, 6, 4, 9, 7, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ /* placebo */ + { 24000, 28000, 12000, 2, 9, 7,10, 8, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 12000, 2, 11, 7,12, 8, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 12000, 2, 12, 9,12, 9, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 12000, 2, 13,12,13,12, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 12000, 2, 14,14,13,13, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 12000, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 12000, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 16/32 kHz dual rate */ + { 16000, 24000, 16000, 2, 4, 2, 1, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ + { 24000, 28000, 16000, 2, 8, 7,10, 8, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 16000, 2, 10, 9,12,11, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 16000, 2, 13,13,13,13, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 16000, 2, 15,15,13,13, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 16000, 2, 15,15,13,13, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 16000, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 16000, 2, 15,15,13,13, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 22.05/44.1 kHz dual rate */ + { 16000, 24000, 22050, 2, 2, 1, 1, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ + { 24000, 28000, 22050, 2, 5, 4, 6, 5, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 32000, 22050, 2, 5, 4, 8, 7, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 28 kbit/s */ + { 32000, 36000, 22050, 2, 7, 6, 8, 7, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 22050, 2, 10,10, 9, 9, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 22050, 2, 12,12, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 22050, 2, 13,13,10,10, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 22050, 2, 14,14,12,12, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 22050, 2, 14,14,12,12, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 24/48 kHz dual rate */ + { 16000, 24000, 24000, 2, 2, 1, 1, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ + { 24000, 28000, 24000, 2, 5, 5, 6, 6, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 24000, 2, 7, 6, 8, 7, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 24000, 2, 10,10, 9, 9, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 24000, 2, 12,12, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 24000, 2, 13,13,10,10, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 24000, 2, 14,14,12,12, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000,128001, 24000, 2, 15,15,12,12, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 32/64 kHz dual rate */ /* placebo settings */ + { 32000, 60000, 32000, 2, 4, 4, 4, 4, 2, 0, -3, SBR_SWITCH_LRC, 3 }, /* lowest range (multichannel rear) */ + { 60000, 80000, 32000, 2, 7, 7, 6, 6, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* lowest range (multichannel rear) */ + { 80000,112000, 32000, 2, 9, 9, 8, 8, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* low range */ + { 112000,144000, 32000, 2, 11,11,10,10, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* SBR sweet spot */ + { 144000,256001, 32000, 2, 13,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* backwards compatible */ + + /* 44.1/88.2 kHz dual rate */ /* placebo settings */ + { 32000, 60000, 44100, 2, 4, 4, 4, 4, 2, 0, -3, SBR_SWITCH_LRC, 3 }, /* lowest range (multichannel rear) */ + { 60000, 80000, 44100, 2, 7, 7, 6, 6, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* lowest range (multichannel rear) */ + { 80000,112000, 44100, 2, 9, 9, 8, 8, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* low range */ + { 112000,144000, 44100, 2, 11,11,10,10, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* SBR sweet spot */ + { 144000,256001, 44100, 2, 13,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* backwards compatible */ + + /* 48/96 kHz dual rate */ /* not yet finally tuned */ + { 32000, 60000, 48000, 2, 4, 4, 9, 9, 2, 0, -3, SBR_SWITCH_LRC, 3 }, /* lowest range (multichannel rear) */ + { 60000, 80000, 48000, 2, 7, 7, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 64 */ + { 80000,112000, 48000, 2, 9, 9,10,10, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 96 */ + { 112000,144000, 48000, 2, 11,11,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 128 */ + { 144000,256001, 48000, 2, 13,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 192 */ + + /** AAC LOW DELAY SECTION **/ + + /* 22.05/44.1 kHz dual rate */ + { 8000, 11369, 22050, 1, 1, 1, 1, 1, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 8 kbit/s */ /**changed (not changed !!)*/ + { 11369, 16000, 22050, 1, 1, 0, 3, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 18000, 22050, 1, 1, 0, 4, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 22050, 1, 1, 2, 5, 4, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 22000, 28000, 22050, 1, 4, 4, 6, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 22050, 1, 7, 8, 8, 8, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 22050, 1, 9, 9, 9, 9, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 22050, 1, 11,11,11,11, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + { 52000, 64001, 22050, 1, 12,11,11,11, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 56 kbit/s */ + + /* 24/48 kHz dual rate */ + { 8000, 12000, 24000, 1, 1, 1, 1, 1, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 8 kbit/s */ /**changed (not changed !!)*/ + { 12000, 16000, 24000, 1, 1, 0, 3, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ + { 16000, 18000, 24000, 1, 1, 0, 4, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 24000, 1, 1, 1, 4, 4, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 22000, 28000, 24000, 1, 4, 4, 6, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 24000, 1, 6, 8, 8, 8, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 24000, 1, 8, 9, 9, 9, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 24000, 1, 12,11,11,10, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + { 52000, 64001, 24000, 1, 13,11,11,10, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ + + /* 22.05/44.1 kHz dual rate */ + { 16000, 24000, 22050, 2, 0, 0, 0, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ + { 24000, 28000, 22050, 2, 3, 2, 5, 4, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 32000, 22050, 2, 3, 2, 7, 6, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 28 kbit/s */ + { 32000, 36000, 22050, 2, 5, 4, 7, 6, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 22050, 2, 5, 8, 8, 8, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 22050, 2, 7,10, 8, 8, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 22050, 2, 9,11, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 22050, 2, 10,12,10,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000, 82000, 22050, 2, 12,12,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + { 82000,128001, 22050, 2, 13,12,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + + /* 24/48 kHz dual rate */ + { 16000, 24000, 24000, 2, 0, 0, 0, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ + { 24000, 28000, 24000, 2, 3, 3, 5, 5, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ + { 28000, 36000, 24000, 2, 5, 4, 7, 6, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ + { 36000, 44000, 24000, 2, 4, 8, 8, 8, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ + { 44000, 52000, 24000, 2, 6,10, 8, 8, 3, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 48 kbit/s */ + { 52000, 60000, 24000, 2, 9,11, 9, 9, 3, 0, -3, SBR_SWITCH_LRC, 1 }, /* nominal: 56 kbit/s */ + { 60000, 76000, 24000, 2, 11,12,10,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ + { 76000, 88000, 24000, 2, 12,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ + { 88000,128001, 24000, 2, 13,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 92 kbit/s */ +}; + +const psTuningTable_t psTuningTable[4] = +{ + { 8000, 22000, PSENC_STEREO_BANDS_10, PSENC_NENV_1, FL2FXCONST_DBL(3.0f/4.0f) }, + { 22000, 28000, PSENC_STEREO_BANDS_20, PSENC_NENV_1, FL2FXCONST_DBL(2.0f/4.0f) }, + { 28000, 36000, PSENC_STEREO_BANDS_20, PSENC_NENV_2, FL2FXCONST_DBL(1.5f/4.0f) }, + { 36000, 160001, PSENC_STEREO_BANDS_20, PSENC_NENV_4, FL2FXCONST_DBL(1.1f/4.0f) }, +}; + + +//@} + + + diff --git a/libSBRenc/src/sbr_rom.h b/libSBRenc/src/sbr_rom.h new file mode 100644 index 0000000..696a54c --- /dev/null +++ b/libSBRenc/src/sbr_rom.h @@ -0,0 +1,70 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! +\file +\brief Declaration of constant tables +$Revision: 36847 $ +*/ +#ifndef __SBR_ROM_H +#define __SBR_ROM_H + +#include "sbr_def.h" +#include "sbr_encoder.h" + +#include "ps_main.h" + +/* + huffman tables +*/ +extern const INT v_Huff_envelopeLevelC10T[121]; +extern const UCHAR v_Huff_envelopeLevelL10T[121]; +extern const INT v_Huff_envelopeLevelC10F[121]; +extern const UCHAR v_Huff_envelopeLevelL10F[121]; +extern const INT bookSbrEnvBalanceC10T[49]; +extern const UCHAR bookSbrEnvBalanceL10T[49]; +extern const INT bookSbrEnvBalanceC10F[49]; +extern const UCHAR bookSbrEnvBalanceL10F[49]; +extern const INT v_Huff_envelopeLevelC11T[63]; +extern const UCHAR v_Huff_envelopeLevelL11T[63]; +extern const INT v_Huff_envelopeLevelC11F[63]; +extern const UCHAR v_Huff_envelopeLevelL11F[63]; +extern const INT bookSbrEnvBalanceC11T[25]; +extern const UCHAR bookSbrEnvBalanceL11T[25]; +extern const INT bookSbrEnvBalanceC11F[25]; +extern const UCHAR bookSbrEnvBalanceL11F[25]; +extern const INT v_Huff_NoiseLevelC11T[63]; +extern const UCHAR v_Huff_NoiseLevelL11T[63]; +extern const INT bookSbrNoiseBalanceC11T[25]; +extern const UCHAR bookSbrNoiseBalanceL11T[25]; + +#define SBRENC_TUNING_SIZE (126 + 37) + +extern const sbrTuningTable_t sbrTuningTable[SBRENC_TUNING_SIZE]; + +extern const psTuningTable_t psTuningTable[4]; + + +#endif diff --git a/libSBRenc/src/sbrenc_freq_sca.cpp b/libSBRenc/src/sbrenc_freq_sca.cpp new file mode 100644 index 0000000..ce492c9 --- /dev/null +++ b/libSBRenc/src/sbrenc_freq_sca.cpp @@ -0,0 +1,613 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief frequency scale $Revision: 36847 $ +*/ + +#include "sbrenc_freq_sca.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +/* StartFreq */ +static INT getStartFreq(INT fs, const INT start_freq); + +/* StopFreq */ +static INT getStopFreq(INT fs, const INT stop_freq, const INT noChannels); + +static INT numberOfBands(INT b_p_o, INT start, INT stop, FIXP_DBL warp_factor); +static void CalcBands(INT * diff, INT start , INT stop , INT num_bands); +static INT modifyBands(INT max_band, INT * diff, INT length); +static void cumSum(INT start_value, INT* diff, INT length, UCHAR *start_adress); + + + +/******************************************************************************* + Functionname: FDKsbrEnc_getSbrStartFreqRAW + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ + +INT +FDKsbrEnc_getSbrStartFreqRAW (INT startFreq, INT QMFbands, INT fs) +{ + INT result; + + if ( startFreq < 0 || startFreq > 15) { + return -1; + } + /* Update startFreq struct */ + result = getStartFreq(fs, startFreq); + + result = (result*fs/QMFbands+1)>>1; + + return (result); + +} /* End FDKsbrEnc_getSbrStartFreqRAW */ + + +/******************************************************************************* + Functionname: getSbrStopFreq + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +INT FDKsbrEnc_getSbrStopFreqRAW (INT stopFreq, INT QMFbands, INT fs) +{ + INT result; + + if ( stopFreq < 0 || stopFreq > 13) + return -1; + + + /* Uppdate stopFreq struct */ + result = getStopFreq( fs, stopFreq, QMFbands); + result = (result*fs/QMFbands+1)>>1; + + return (result); +} /* End getSbrStopFreq */ + + +/******************************************************************************* + Functionname: getStartFreq + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +static INT +getStartFreq(INT fs, const INT start_freq) +{ + INT k0_min; + + switch(fs){ + case 16000: k0_min = 24; + break; + case 22050: k0_min = 17; + break; + case 24000: k0_min = 16; + break; + case 32000: k0_min = 16; + break; + case 44100: k0_min = 12; + break; + case 48000: k0_min = 11; + break; + case 64000: k0_min = 10; + break; + case 88200: k0_min = 7; + break; + case 96000: k0_min = 7; + break; + default: + k0_min=11; /* illegal fs */ + } + + + switch (fs) { + + case 16000: + { + INT v_offset[]= {-8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}; + return (k0_min + v_offset[start_freq]); + } + case 22050: + { + INT v_offset[]= {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13}; + return (k0_min + v_offset[start_freq]); + } + case 24000: + { + INT v_offset[]= {-5, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16}; + return (k0_min + v_offset[start_freq]); + } + case 32000: + { + INT v_offset[]= {-6, -4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16}; + return (k0_min + v_offset[start_freq]); + } + case 44100: + case 48000: + case 64000: + { + INT v_offset[]= {-4, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20}; + return (k0_min + v_offset[start_freq]); + } + case 88200: + case 96000: + { + INT v_offset[]= {-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24}; + return (k0_min + v_offset[start_freq]); + } + default: + { + INT v_offset[]= {0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 24, 28, 33}; + return (k0_min + v_offset[start_freq]); + } + } +} /* End getStartFreq */ + + +/******************************************************************************* + Functionname: getStopFreq + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ + static INT +getStopFreq(INT fs, const INT stop_freq, const INT noChannels) +{ + INT result,i; + INT k1_min; + INT v_dstop[13]; + + + INT *v_stop_freq = NULL; + INT v_stop_freq_16[14] = {48,49,50,51,52,54,55,56,57,59,60,61,63,64}; + INT v_stop_freq_22[14] = {35,37,38,40,42,44,46,48,51,53,56,58,61,64}; + INT v_stop_freq_24[14] = {32,34,36,38,40,42,44,46,49,52,55,58,61,64}; + INT v_stop_freq_32[14] = {32,34,36,38,40,42,44,46,49,52,55,58,61,64}; + INT v_stop_freq_44[14] = {23,25,27,29,32,34,37,40,43,47,51,55,59,64}; + INT v_stop_freq_48[14] = {21,23,25,27,30,32,35,38,42,45,49,54,59,64}; + INT v_stop_freq_64[14] = {20,22,24,26,29,31,34,37,41,45,49,54,59,64}; + INT v_stop_freq_88[14] = {15,17,19,21,23,26,29,33,37,41,46,51,57,64}; + INT v_stop_freq_96[14] = {13,15,17,19,21,24,27,31,35,39,44,50,57,64}; + + switch(fs){ + case 16000: k1_min = 48; + v_stop_freq =v_stop_freq_16; + break; + case 22050: k1_min = 35; + v_stop_freq =v_stop_freq_22; + break; + case 24000: k1_min = 32; + v_stop_freq =v_stop_freq_24; + break; + case 32000: k1_min = 32; + v_stop_freq =v_stop_freq_32; + break; + case 44100: k1_min = 23; + v_stop_freq =v_stop_freq_44; + break; + case 48000: k1_min = 21; + v_stop_freq =v_stop_freq_48; + break; + case 64000: k1_min = 20; + v_stop_freq =v_stop_freq_64; + break; + case 88200: k1_min = 15; + v_stop_freq =v_stop_freq_88; + break; + case 96000: k1_min = 13; + v_stop_freq =v_stop_freq_96; + break; + default: + k1_min = 21; /* illegal fs */ + } + + + /* Ensure increasing bandwidth */ + for(i = 0; i <= 12; i++) { + v_dstop[i] = v_stop_freq[i+1] - v_stop_freq[i]; + } + + FDKsbrEnc_Shellsort_int(v_dstop, 13); /* Sort bandwidth changes */ + + result = k1_min; + for(i = 0; i < stop_freq; i++) { + result = result + v_dstop[i]; + } + + return(result); + +}/* End getStopFreq */ + + +/******************************************************************************* + Functionname: FDKsbrEnc_FindStartAndStopBand + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +INT +FDKsbrEnc_FindStartAndStopBand(const INT samplingFreq, + const INT noChannels, + const INT startFreq, + const INT stopFreq, + const SR_MODE sampleRateMode, + INT *k0, + INT *k2) +{ + + /* Update startFreq struct */ + *k0 = getStartFreq(samplingFreq, startFreq); + + /* Test if start freq is outside corecoder range */ + if( ( sampleRateMode == 1 ) && + ( samplingFreq*noChannels < + 2**k0 * samplingFreq) ) { + return (1); /* raise the cross-over frequency and/or lower the number + of target bands per octave (or lower the sampling frequency) */ + } + + /*Update stopFreq struct */ + if ( stopFreq < 14 ) { + *k2 = getStopFreq(samplingFreq, stopFreq, noChannels); + } else if( stopFreq == 14 ) { + *k2 = 2 * *k0; + } else { + *k2 = 3 * *k0; + } + + /* limit to Nyqvist */ + if (*k2 > noChannels) { + *k2 = noChannels; + } + + + + /* Test for invalid k0 k2 combinations */ + if ( (samplingFreq == 44100) && ( (*k2 - *k0) > MAX_FREQ_COEFFS_FS44100 ) ) + return (1); /* Number of bands exceeds valid range of MAX_FREQ_COEFFS for fs=44.1kHz */ + + if ( (samplingFreq >= 48000) && ( (*k2 - *k0) > MAX_FREQ_COEFFS_FS48000 ) ) + return (1); /* Number of bands exceeds valid range of MAX_FREQ_COEFFS for fs>=48kHz */ + + if ((*k2 - *k0) > MAX_FREQ_COEFFS) + return (1);/*Number of bands exceeds valid range of MAX_FREQ_COEFFS */ + + if ((*k2 - *k0) < 0) + return (1);/* Number of bands is negative */ + + + return(0); +} + +/******************************************************************************* + Functionname: FDKsbrEnc_UpdateFreqScale + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +INT +FDKsbrEnc_UpdateFreqScale(UCHAR *v_k_master, INT *h_num_bands, + const INT k0, const INT k2, + const INT freqScale, + const INT alterScale) + +{ + + INT b_p_o = 0; /* bands_per_octave */ + FIXP_DBL warp = FL2FXCONST_DBL(0.0f); + INT dk = 0; + + /* Internal variables */ + INT k1 = 0, i; + INT num_bands0; + INT num_bands1; + INT diff_tot[MAX_OCTAVE + MAX_SECOND_REGION]; + INT *diff0 = diff_tot; + INT *diff1 = diff_tot+MAX_OCTAVE; + INT k2_achived; + INT k2_diff; + INT incr = 0; + + /* Init */ + if (freqScale==1) b_p_o = 12; + if (freqScale==2) b_p_o = 10; + if (freqScale==3) b_p_o = 8; + + + if(freqScale > 0) /*Bark*/ + { + if(alterScale==0) + warp = FL2FXCONST_DBL(0.5f); /* 1.0/(1.0*2.0) */ + else + warp = FL2FXCONST_DBL(1.0f/2.6f); /* 1.0/(1.3*2.0); */ + + + if(4*k2 >= 9*k0) /*two or more regions*/ + { + k1=2*k0; + + num_bands0=numberOfBands(b_p_o, k0, k1, FL2FXCONST_DBL(0.5f)); + num_bands1=numberOfBands(b_p_o, k1, k2, warp); + + CalcBands(diff0, k0, k1, num_bands0);/*CalcBands1 => diff0 */ + FDKsbrEnc_Shellsort_int( diff0, num_bands0);/*SortBands sort diff0 */ + + if (diff0[0] == 0) /* too wide FB bands for target tuning */ + { + return (1);/* raise the cross-over frequency and/or lower the number + of target bands per octave (or lower the sampling frequency */ + } + + cumSum(k0, diff0, num_bands0, v_k_master); /* cumsum */ + + CalcBands(diff1, k1, k2, num_bands1); /* CalcBands2 => diff1 */ + FDKsbrEnc_Shellsort_int( diff1, num_bands1); /* SortBands sort diff1 */ + if(diff0[num_bands0-1] > diff1[0]) /* max(1) > min(2) */ + { + if(modifyBands(diff0[num_bands0-1],diff1, num_bands1)) + return(1); + } + + /* Add 2'nd region */ + cumSum(k1, diff1, num_bands1, &v_k_master[num_bands0]); + *h_num_bands=num_bands0+num_bands1; /* Output nr of bands */ + + } + else /* one region */ + { + k1=k2; + + num_bands0=numberOfBands(b_p_o, k0, k1, FL2FXCONST_DBL(0.5f)); + CalcBands(diff0, k0, k1, num_bands0);/* CalcBands1 => diff0 */ + FDKsbrEnc_Shellsort_int( diff0, num_bands0); /* SortBands sort diff0 */ + + if (diff0[0] == 0) /* too wide FB bands for target tuning */ + { + return (1); /* raise the cross-over frequency and/or lower the number + of target bands per octave (or lower the sampling frequency */ + } + + cumSum(k0, diff0, num_bands0, v_k_master);/* cumsum */ + *h_num_bands=num_bands0; /* Output nr of bands */ + + } + } + else /* Linear mode */ + { + if (alterScale==0) { + dk = 1; + num_bands0 = 2 * ((k2 - k0)/2); /* FLOOR to get to few number of bands*/ + } else { + dk = 2; + num_bands0 = 2 * (((k2 - k0)/dk +1)/2); /* ROUND to get closest fit */ + } + + k2_achived = k0 + num_bands0*dk; + k2_diff = k2 - k2_achived; + + for(i=0;i<num_bands0;i++) + diff_tot[i] = dk; + + /* If linear scale wasn't achived */ + /* and we got wide SBR are */ + if (k2_diff < 0) { + incr = 1; + i = 0; + } + + /* If linear scale wasn't achived */ + /* and we got small SBR are */ + if (k2_diff > 0) { + incr = -1; + i = num_bands0-1; + } + + /* Adjust diff vector to get sepc. SBR range */ + while (k2_diff != 0) { + diff_tot[i] = diff_tot[i] - incr; + i = i + incr; + k2_diff = k2_diff + incr; + } + + cumSum(k0, diff_tot, num_bands0, v_k_master);/* cumsum */ + *h_num_bands=num_bands0; /* Output nr of bands */ + + } + + if (*h_num_bands < 1) + return(1); /*To small sbr area */ + + return (0); +}/* End FDKsbrEnc_UpdateFreqScale */ + +static INT +numberOfBands(INT b_p_o, INT start, INT stop, FIXP_DBL warp_factor) +{ + INT result=0; + /* result = 2* (INT) ( (double)b_p_o * (double)(FDKlog((double)stop/(double)start)/FDKlog((double)2)) * (double)FX_DBL2FL(warp_factor) + 0.5); */ + result = ( ( b_p_o * fMult( (CalcLdInt(stop) - CalcLdInt(start)), warp_factor) + (FL2FX_DBL(0.5f)>>LD_DATA_SHIFT) + ) >> ((DFRACT_BITS-1)-LD_DATA_SHIFT) ) << 1; /* do not optimize anymore (rounding!!) */ + + return(result); +} + + +static void +CalcBands(INT * diff, INT start , INT stop , INT num_bands) +{ + INT i, qb, qe, qtmp; + INT previous; + INT current; + FIXP_DBL base, exp, tmp; + + previous=start; + for(i=1; i<= num_bands; i++) + { + base = fDivNorm((FIXP_DBL)stop, (FIXP_DBL)start, &qb); + exp = fDivNorm((FIXP_DBL)i, (FIXP_DBL)num_bands, &qe); + tmp = fPow(base, qb, exp, qe, &qtmp); + tmp = fMult(tmp, (FIXP_DBL)(start<<24)); + current = (INT)scaleValue(tmp, qtmp-23); + current = (current+1) >> 1; /* rounding*/ + diff[i-1] = current-previous; + previous = current; + } + +}/* End CalcBands */ + + +static void +cumSum(INT start_value, INT* diff, INT length, UCHAR *start_adress) +{ + INT i; + start_adress[0]=start_value; + for(i=1;i<=length;i++) + start_adress[i]=start_adress[i-1]+diff[i-1]; +} /* End cumSum */ + + +static INT +modifyBands(INT max_band_previous, INT * diff, INT length) +{ + INT change=max_band_previous-diff[0]; + + /* Limit the change so that the last band cannot get narrower than the first one */ + if ( change > (diff[length-1] - diff[0]) / 2 ) + change = (diff[length-1] - diff[0]) / 2; + + diff[0] += change; + diff[length-1] -= change; + FDKsbrEnc_Shellsort_int(diff, length); + + return(0); +}/* End modifyBands */ + + +/******************************************************************************* + Functionname: FDKsbrEnc_UpdateHiRes + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +INT +FDKsbrEnc_UpdateHiRes(UCHAR *h_hires, INT *num_hires,UCHAR * v_k_master, + INT num_master , INT *xover_band, SR_MODE drOrSr, + INT noQMFChannels) +{ + INT i; + INT divider; + INT max1,max2; + + /* Check if we use a Dual rate => diver=2 else 1 */ + divider = (drOrSr == DUAL_RATE) ? 2 : 1; + + if( (v_k_master[*xover_band] > (noQMFChannels/divider) ) || + ( *xover_band > num_master ) ) { + /* xover_band error, too big for this startFreq. Will be clipped */ + + /* Calculate maximum value for xover_band */ + max1=0; + max2=num_master; + while( (v_k_master[max1+1] < (noQMFChannels/divider)) && + ( (max1+1) < max2) ) + { + max1++; + } + + *xover_band=max1; + } + + *num_hires = num_master - *xover_band; + for(i = *xover_band; i <= num_master; i++) + { + h_hires[i - *xover_band] = v_k_master[i]; + } + + return (0); +}/* End FDKsbrEnc_UpdateHiRes */ + + +/******************************************************************************* + Functionname: FDKsbrEnc_UpdateLoRes + ******************************************************************************* + Description: + + Arguments: + + Return: + *******************************************************************************/ +void +FDKsbrEnc_UpdateLoRes(UCHAR * h_lores, INT *num_lores, UCHAR * h_hires, INT num_hires) +{ + INT i; + + if(num_hires%2 == 0) /* if even number of hires bands */ + { + *num_lores=num_hires/2; + /* Use every second lores=hires[0,2,4...] */ + for(i=0;i<=*num_lores;i++) + h_lores[i]=h_hires[i*2]; + + } + else /* odd number of hires which means xover is odd */ + { + *num_lores=(num_hires+1)/2; + + /* Use lores=hires[0,1,3,5 ...] */ + h_lores[0]=h_hires[0]; + for(i=1;i<=*num_lores;i++) + { + h_lores[i]=h_hires[i*2-1]; + } + } + +}/* End FDKsbrEnc_UpdateLoRes */ diff --git a/libSBRenc/src/sbrenc_freq_sca.h b/libSBRenc/src/sbrenc_freq_sca.h new file mode 100644 index 0000000..a4048e9 --- /dev/null +++ b/libSBRenc/src/sbrenc_freq_sca.h @@ -0,0 +1,71 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief frequency scale prototypes $Revision: 36867 $ +*/ +#ifndef __FREQ_SCA2_H +#define __FREQ_SCA2_H + +#include "sbr_encoder.h" +#include "sbr_def.h" + +#define MAX_OCTAVE 29 +#define MAX_SECOND_REGION 50 + + +INT +FDKsbrEnc_UpdateFreqScale(UCHAR *v_k_master, INT *h_num_bands, + const INT k0, const INT k2, + const INT freq_scale, + const INT alter_scale); + +INT +FDKsbrEnc_UpdateHiRes(UCHAR *h_hires, + INT *num_hires, + UCHAR *v_k_master, + INT num_master , + INT *xover_band, + SR_MODE drOrSr, + INT noQMFChannels); + +void FDKsbrEnc_UpdateLoRes(UCHAR * v_lores, + INT *num_lores, + UCHAR * v_hires, + INT num_hires); + +INT +FDKsbrEnc_FindStartAndStopBand(const INT samplingFreq, + const INT noChannels, + const INT startFreq, + const INT stop_freq, + const SR_MODE sampleRateMode, + INT *k0, + INT *k2); + +INT FDKsbrEnc_getSbrStartFreqRAW (INT startFreq, INT QMFbands, INT fs ); +INT FDKsbrEnc_getSbrStopFreqRAW (INT stopFreq, INT QMFbands, INT fs); +#endif diff --git a/libSBRenc/src/ton_corr.cpp b/libSBRenc/src/ton_corr.cpp new file mode 100644 index 0000000..cc4913c --- /dev/null +++ b/libSBRenc/src/ton_corr.cpp @@ -0,0 +1,829 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Header$ + +*******************************************************************************/ + +#include "ton_corr.h" + +#include "sbr_ram.h" +#include "sbr_misc.h" +#include "genericStds.h" +#include "autocorr2nd.h" + + + +/*************************************************************************** + + Send autoCorrSecondOrder to mlfile + +****************************************************************************/ + +/**************************************************************************/ +/*! + \brief Calculates the tonal to noise ration for different frequency bands + and time segments. + + The ratio between the predicted energy (tonal energy A) and the total + energy (A + B) is calculated. This is converted to the ratio between + the predicted energy (tonal energy A) and the non-predictable energy + (noise energy B). Hence the quota-matrix contains A/B = q/(1-q). + + The samples in nrgVector are scaled by 1.0/16.0 + The samples in pNrgVectorFreq are scaled by 1.0/2.0 + The samples in quotaMatrix are scaled by RELAXATION + + \return none. + +*/ +/**************************************************************************/ + +void +FDKsbrEnc_CalculateTonalityQuotas( HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + FIXP_DBL **RESTRICT sourceBufferReal, /*!< The real part of the QMF-matrix. */ + FIXP_DBL **RESTRICT sourceBufferImag, /*!< The imaginary part of the QMF-matrix. */ + INT usb, /*!< upper side band, highest + 1 QMF band in the SBR range. */ + INT qmfScale /*!< sclefactor of QMF subsamples */ + ) +{ + INT i, k, r, r2, timeIndex, autoCorrScaling; + + INT startIndexMatrix = hTonCorr->startIndexMatrix; + INT totNoEst = hTonCorr->numberOfEstimates; + INT noEstPerFrame = hTonCorr->numberOfEstimatesPerFrame; + INT move = hTonCorr->move; + INT noQmfChannels = hTonCorr->noQmfChannels; /* Numer of Bands */ + INT buffLen = hTonCorr->bufferLength; /* Numer of Slots */ + INT stepSize = hTonCorr->stepSize; + INT *pBlockLength = hTonCorr->lpcLength; + INT** RESTRICT signMatrix = hTonCorr->signMatrix; + FIXP_DBL* RESTRICT nrgVector = hTonCorr->nrgVector; + FIXP_DBL** RESTRICT quotaMatrix = hTonCorr->quotaMatrix; + FIXP_DBL* RESTRICT pNrgVectorFreq = hTonCorr->nrgVectorFreq; + +#define BAND_V_SIZE QMF_MAX_TIME_SLOTS +#define NUM_V_COMBINE 8 /* Must be a divisor of 64 and fulfill the ASSERTs below */ + + FIXP_DBL *realBuf; + FIXP_DBL *imagBuf; + + FIXP_DBL alphar[2],alphai[2],fac; + + C_ALLOC_SCRATCH_START(ac, ACORR_COEFS, 1); + C_ALLOC_SCRATCH_START(realBufRef, FIXP_DBL, 2*BAND_V_SIZE*NUM_V_COMBINE); + + realBuf = realBufRef; + imagBuf = realBuf + BAND_V_SIZE*NUM_V_COMBINE; + + + FDK_ASSERT(buffLen <= BAND_V_SIZE); + FDK_ASSERT(sizeof(FIXP_DBL)*NUM_V_COMBINE*BAND_V_SIZE*2 < (1024*sizeof(FIXP_DBL)-sizeof(ACORR_COEFS)) ); + + /* + * Buffering of the quotaMatrix and the quotaMatrixTransp. + *********************************************************/ + for(i = 0 ; i < move; i++){ + FDKmemcpy(quotaMatrix[i],quotaMatrix[i + noEstPerFrame],noQmfChannels * sizeof(FIXP_DBL)); + FDKmemcpy(signMatrix[i],signMatrix[i + noEstPerFrame],noQmfChannels * sizeof(INT)); + } + + FDKmemmove(nrgVector,nrgVector+noEstPerFrame,move*sizeof(FIXP_DBL)); + FDKmemclear(nrgVector+startIndexMatrix,(totNoEst-startIndexMatrix)*sizeof(FIXP_DBL)); + FDKmemclear(pNrgVectorFreq,noQmfChannels * sizeof(FIXP_DBL)); + + /* + * Calculate the quotas for the current time steps. + **************************************************/ + + for (r = 0; r < usb; r++) + { + int blockLength; + + k = hTonCorr->nextSample; /* startSample */ + timeIndex = startIndexMatrix; + /* Copy as many as possible Band accross all Slots at once */ + if (realBuf != realBufRef) { + realBuf -= BAND_V_SIZE; + imagBuf -= BAND_V_SIZE; + } else { + realBuf += BAND_V_SIZE*(NUM_V_COMBINE-1); + imagBuf += BAND_V_SIZE*(NUM_V_COMBINE-1); + for (i = 0; i < buffLen; i++) { + int v; + FIXP_DBL *ptr; + ptr = realBuf+i; + for (v=0; v<NUM_V_COMBINE; v++) + { + ptr[0] = sourceBufferReal[i][r+v]; + ptr[0+BAND_V_SIZE*NUM_V_COMBINE] = sourceBufferImag[i][r+v]; + ptr -= BAND_V_SIZE; + } + } + } + + blockLength = pBlockLength[0]; + + while(k <= buffLen - blockLength) + { + autoCorrScaling = fixMin(getScalefactor(&realBuf[k-LPC_ORDER], LPC_ORDER+blockLength), getScalefactor(&imagBuf[k-LPC_ORDER], LPC_ORDER+blockLength)); + autoCorrScaling = fixMax(0, autoCorrScaling-1); + + scaleValues(&realBuf[k-LPC_ORDER], LPC_ORDER+blockLength, autoCorrScaling); + scaleValues(&imagBuf[k-LPC_ORDER], LPC_ORDER+blockLength, autoCorrScaling); + + autoCorrScaling <<= 1; /* consider qmf buffer scaling twice */ + autoCorrScaling += autoCorr2nd_cplx ( ac, realBuf+k, imagBuf+k, blockLength ); + + + if(ac->det == FL2FXCONST_DBL(0.0f)){ + alphar[1] = alphai[1] = FL2FXCONST_DBL(0.0f); + + alphar[0] = (ac->r01r)>>2; + alphai[0] = (ac->r01i)>>2; + + fac = fMultDiv2(ac->r00r, ac->r11r)>>1; + } + else{ + alphar[1] = (fMultDiv2(ac->r01r, ac->r12r)>>1) - (fMultDiv2(ac->r01i, ac->r12i)>>1) - (fMultDiv2(ac->r02r, ac->r11r)>>1); + alphai[1] = (fMultDiv2(ac->r01i, ac->r12r)>>1) + (fMultDiv2(ac->r01r, ac->r12i)>>1) - (fMultDiv2(ac->r02i, ac->r11r)>>1); + + alphar[0] = (fMultDiv2(ac->r01r, ac->det)>>(ac->det_scale+1)) + fMult(alphar[1], ac->r12r) + fMult(alphai[1], ac->r12i); + alphai[0] = (fMultDiv2(ac->r01i, ac->det)>>(ac->det_scale+1)) + fMult(alphai[1], ac->r12r) - fMult(alphar[1], ac->r12i); + + fac = fMultDiv2(ac->r00r, fMult(ac->det, ac->r11r))>>(ac->det_scale+1); + } + + if(fac == FL2FXCONST_DBL(0.0f)){ + quotaMatrix[timeIndex][r] = FL2FXCONST_DBL(0.0f); + signMatrix[timeIndex][r] = 0; + } + else { + /* quotaMatrix is scaled with the factor RELAXATION + parse RELAXATION in fractional part and shift factor: 1/(1/0.524288 * 2^RELAXATION_SHIFT) */ + FIXP_DBL tmp,num,denom; + INT numShift,denomShift,commonShift; + INT sign; + + num = fMultDiv2(alphar[0], ac->r01r) + fMultDiv2(alphai[0], ac->r01i) - fMultDiv2(alphar[1], fMult(ac->r02r, ac->r11r)) - fMultDiv2(alphai[1], fMult(ac->r02i, ac->r11r)); + num = fixp_abs(num); + + denom = (fac>>1) + (fMultDiv2(fac,RELAXATION_FRACT)>>RELAXATION_SHIFT) - num; + denom = fixp_abs(denom); + + num = fMult(num,RELAXATION_FRACT); + + numShift = CountLeadingBits(num) - 2; + num = scaleValue(num, numShift); + + denomShift = CountLeadingBits(denom); + denom = (FIXP_DBL)denom << denomShift; + + if ((num > FL2FXCONST_DBL(0.0f)) && (denom != FL2FXCONST_DBL(0.0f))) { + commonShift = fixMin(numShift - denomShift + RELAXATION_SHIFT, DFRACT_BITS-1); + if (commonShift < 0) { + commonShift = -commonShift; + tmp = schur_div(num,denom,16); + commonShift = fixMin(commonShift,CountLeadingBits(tmp)); + quotaMatrix[timeIndex][r] = tmp << commonShift; + } + else { + quotaMatrix[timeIndex][r] = schur_div(num,denom,16) >> commonShift; + } + } + else { + quotaMatrix[timeIndex][r] = FL2FXCONST_DBL(0.0f); + } + + if (ac->r11r != FL2FXCONST_DBL(0.0f)) { + if ( ( (ac->r01r >= FL2FXCONST_DBL(0.0f) ) && ( ac->r11r >= FL2FXCONST_DBL(0.0f) ) ) + ||( (ac->r01r < FL2FXCONST_DBL(0.0f) ) && ( ac->r11r < FL2FXCONST_DBL(0.0f) ) ) ) { + sign = 1; + } + else { + sign = -1; + } + } + else { + sign = 1; + } + + if(sign < 0) { + r2 = r; /* (INT) pow(-1, band); */ + } + else { + r2 = r + 1; /* (INT) pow(-1, band+1); */ + } + signMatrix[timeIndex][r] = 1 - 2*(r2 & 0x1); + } + + nrgVector[timeIndex] += ((ac->r00r) >> fixMin(DFRACT_BITS-1,(2*qmfScale+autoCorrScaling + SCALE_NRGVEC))); + /* pNrgVectorFreq[r] finally has to be divided by noEstPerFrame, replaced division by shifting with one */ + pNrgVectorFreq[r] = pNrgVectorFreq[r] + ((ac->r00r) >> fixMin(DFRACT_BITS-1,(2*qmfScale+autoCorrScaling + SCALE_NRGVEC))); + + blockLength = pBlockLength[1]; + k += stepSize; + timeIndex++; + } + } + + FDK_ASSERT(noEstPerFrame == 2); + + + C_ALLOC_SCRATCH_END(realBuf, FIXP_DBL, 2*BAND_V_SIZE*NUM_V_COMBINE); + C_ALLOC_SCRATCH_END(ac, ACORR_COEFS, 1); +} + +/**************************************************************************/ +/*! + \brief Extracts the parameters required in the decoder to obtain the + correct tonal to noise ratio after SBR. + + Estimates the tonal to noise ratio of the original signal (using LPC). + Predicts the tonal to noise ration of the SBR signal (in the decoder) by + patching the tonal to noise ratio values similar to the patching of the + lowband in the decoder. Given the tonal to noise ratio of the original + and the SBR signal, it estimates the required amount of inverse filtering, + additional noise as well as any additional sines. + + \return none. + +*/ +/**************************************************************************/ +void +FDKsbrEnc_TonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr,/*!< Handle to SBR_TON_CORR struct. */ + INVF_MODE* infVec, /*!< Vector where the inverse filtering levels will be stored. */ + FIXP_DBL * noiseLevels, /*!< Vector where the noise levels will be stored. */ + INT* missingHarmonicFlag, /*!< Flag set to one or zero, dependent on if any strong sines are missing.*/ + UCHAR * missingHarmonicsIndex, /*!< Vector indicating where sines are missing. */ + UCHAR * envelopeCompensation, /*!< Vector to store compensation values for the energies in. */ + const SBR_FRAME_INFO *frameInfo, /*!< Frame info struct, contains the time and frequency grid of the current frame.*/ + UCHAR* transientInfo, /*!< Transient info.*/ + UCHAR* freqBandTable, /*!< Frequency band tables for high-res.*/ + INT nSfb, /*!< Number of scalefactor bands for high-res. */ + XPOS_MODE xposType, /*!< Type of transposer used in the decoder.*/ + UINT sbrSyntaxFlags + ) +{ + INT band; + INT transientFlag = transientInfo[1] ; /*!< Flag indicating if a transient is present in the current frame. */ + INT transientPos = transientInfo[0]; /*!< Position of the transient.*/ + INT transientFrame, transientFrameInvfEst; + INVF_MODE* infVecPtr; + + + /* Determine if this is a frame where a transient starts... + + The detection of noise-floor, missing harmonics and invf_est, is not in sync for the + non-buf-opt decoder such as AAC. Hence we need to keep track on the transient in the + present frame as well as in the next. + */ + transientFrame = 0; + if(hTonCorr->transientNextFrame){ /* The transient was detected in the previous frame, but is actually */ + transientFrame = 1; + hTonCorr->transientNextFrame = 0; + + if(transientFlag){ + if(transientPos + hTonCorr->transientPosOffset >= frameInfo->borders[frameInfo->nEnvelopes]){ + hTonCorr->transientNextFrame = 1; + } + } + } + else{ + if(transientFlag){ + if(transientPos + hTonCorr->transientPosOffset < frameInfo->borders[frameInfo->nEnvelopes]){ + transientFrame = 1; + hTonCorr->transientNextFrame = 0; + } + else{ + hTonCorr->transientNextFrame = 1; + } + } + } + transientFrameInvfEst = transientFrame; + + + /* + Estimate the required invese filtereing level. + */ + if (hTonCorr->switchInverseFilt) + FDKsbrEnc_qmfInverseFilteringDetector(&hTonCorr->sbrInvFilt, + hTonCorr->quotaMatrix, + hTonCorr->nrgVector, + hTonCorr->indexVector, + hTonCorr->frameStartIndexInvfEst, + hTonCorr->numberOfEstimatesPerFrame + hTonCorr->frameStartIndexInvfEst, + transientFrameInvfEst, + infVec); + + /* + Detect what tones will be missing. + */ + if (xposType == XPOS_LC ){ + FDKsbrEnc_SbrMissingHarmonicsDetectorQmf(&hTonCorr->sbrMissingHarmonicsDetector, + hTonCorr->quotaMatrix, + hTonCorr->signMatrix, + hTonCorr->indexVector, + frameInfo, + transientInfo, + missingHarmonicFlag, + missingHarmonicsIndex, + freqBandTable, + nSfb, + envelopeCompensation, + hTonCorr->nrgVectorFreq); + } + else{ + *missingHarmonicFlag = 0; + FDKmemclear(missingHarmonicsIndex,nSfb*sizeof(UCHAR)); + } + + + + /* + Noise floor estimation + */ + + infVecPtr = hTonCorr->sbrInvFilt.prevInvfMode; + + FDKsbrEnc_sbrNoiseFloorEstimateQmf(&hTonCorr->sbrNoiseFloorEstimate, + frameInfo, + noiseLevels, + hTonCorr->quotaMatrix, + hTonCorr->indexVector, + *missingHarmonicFlag, + hTonCorr->frameStartIndex, + hTonCorr->numberOfEstimatesPerFrame, + transientFrame, + infVecPtr, + sbrSyntaxFlags); + + + /* Store the invfVec data for the next frame...*/ + for(band = 0 ; band < hTonCorr->sbrInvFilt.noDetectorBands; band++){ + hTonCorr->sbrInvFilt.prevInvfMode[band] = infVec[band]; + } +} + +/**************************************************************************/ +/*! + \brief Searches for the closest match in the frequency master table. + + + + \return closest entry. + +*/ +/**************************************************************************/ +static INT +findClosestEntry(INT goalSb, + UCHAR *v_k_master, + INT numMaster, + INT direction) +{ + INT index; + + if( goalSb <= v_k_master[0] ) + return v_k_master[0]; + + if( goalSb >= v_k_master[numMaster] ) + return v_k_master[numMaster]; + + if(direction) { + index = 0; + while( v_k_master[index] < goalSb ) { + index++; + } + } else { + index = numMaster; + while( v_k_master[index] > goalSb ) { + index--; + } + } + + return v_k_master[index]; +} + + +/**************************************************************************/ +/*! + \brief resets the patch + + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +static INT +resetPatch(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INT xposctrl, /*!< Different patch modes. */ + INT highBandStartSb, /*!< Start band of the SBR range. */ + UCHAR *v_k_master, /*!< Master frequency table from which all other table are derived.*/ + INT numMaster, /*!< Number of elements in the master table. */ + INT fs, /*!< Sampling frequency. */ + INT noChannels) /*!< Number of QMF-channels. */ +{ + INT patch,k,i; + INT targetStopBand; + + PATCH_PARAM *patchParam = hTonCorr->patchParam; + + INT sbGuard = hTonCorr->guard; + INT sourceStartBand; + INT patchDistance; + INT numBandsInPatch; + + INT lsb = v_k_master[0]; /* Lowest subband related to the synthesis filterbank */ + INT usb = v_k_master[numMaster]; /* Stop subband related to the synthesis filterbank */ + INT xoverOffset = highBandStartSb - v_k_master[0]; /* Calculate distance in subbands between k0 and kx */ + + INT goalSb; + + + /* + * Initialize the patching parameter + */ + + if (xposctrl == 1) { + lsb += xoverOffset; + xoverOffset = 0; + } + + goalSb = (INT)( (2 * noChannels * 16000 + (fs>>1)) / fs ); /* 16 kHz band */ + goalSb = findClosestEntry(goalSb, v_k_master, numMaster, 1); /* Adapt region to master-table */ + + /* First patch */ + sourceStartBand = hTonCorr->shiftStartSb + xoverOffset; + targetStopBand = lsb + xoverOffset; + + /* even (odd) numbered channel must be patched to even (odd) numbered channel */ + patch = 0; + while(targetStopBand < usb) { + + /* To many patches */ + if (patch >= MAX_NUM_PATCHES) + return(1); /*Number of patches to high */ + + patchParam[patch].guardStartBand = targetStopBand; + targetStopBand += sbGuard; + patchParam[patch].targetStartBand = targetStopBand; + + numBandsInPatch = goalSb - targetStopBand; /* get the desired range of the patch */ + + if ( numBandsInPatch >= lsb - sourceStartBand ) { + /* desired number bands are not available -> patch whole source range */ + patchDistance = targetStopBand - sourceStartBand; /* get the targetOffset */ + patchDistance = patchDistance & ~1; /* rounding off odd numbers and make all even */ + numBandsInPatch = lsb - (targetStopBand - patchDistance); + numBandsInPatch = findClosestEntry(targetStopBand + numBandsInPatch, v_k_master, numMaster, 0) - + targetStopBand; /* Adapt region to master-table */ + } + + /* desired number bands are available -> get the minimal even patching distance */ + patchDistance = numBandsInPatch + targetStopBand - lsb; /* get minimal distance */ + patchDistance = (patchDistance + 1) & ~1; /* rounding up odd numbers and make all even */ + + if (numBandsInPatch <= 0) { + patch--; + } else { + patchParam[patch].sourceStartBand = targetStopBand - patchDistance; + patchParam[patch].targetBandOffs = patchDistance; + patchParam[patch].numBandsInPatch = numBandsInPatch; + patchParam[patch].sourceStopBand = patchParam[patch].sourceStartBand + numBandsInPatch; + + targetStopBand += patchParam[patch].numBandsInPatch; + } + + /* All patches but first */ + sourceStartBand = hTonCorr->shiftStartSb; + + /* Check if we are close to goalSb */ + if( fixp_abs(targetStopBand - goalSb) < 3) { + goalSb = usb; + } + + patch++; + + } + + patch--; + + /* if highest patch contains less than three subband: skip it */ + if ( patchParam[patch].numBandsInPatch < 3 && patch > 0 ) { + patch--; + targetStopBand = patchParam[patch].targetStartBand + patchParam[patch].numBandsInPatch; + } + + hTonCorr->noOfPatches = patch + 1; + + + /* Assign the index-vector, so we know where to look for the high-band. + -1 represents a guard-band. */ + for(k = 0; k < hTonCorr->patchParam[0].guardStartBand; k++) + hTonCorr->indexVector[k] = k; + + for(i = 0; i < hTonCorr->noOfPatches; i++) + { + INT sourceStart = hTonCorr->patchParam[i].sourceStartBand; + INT targetStart = hTonCorr->patchParam[i].targetStartBand; + INT numberOfBands = hTonCorr->patchParam[i].numBandsInPatch; + INT startGuardBand = hTonCorr->patchParam[i].guardStartBand; + + for(k = 0; k < (targetStart- startGuardBand); k++) + hTonCorr->indexVector[startGuardBand+k] = -1; + + for(k = 0; k < numberOfBands; k++) + hTonCorr->indexVector[targetStart+k] = sourceStart+k; + } + + return (0); +} + +/**************************************************************************/ +/*! + \brief Creates an instance of the tonality correction parameter module. + + The module includes modules for inverse filtering level estimation, + missing harmonics detection and noise floor level estimation. + + \return errorCode, noError if successful. +*/ +/**************************************************************************/ +INT +FDKsbrEnc_CreateTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + INT chan) /*!< Channel index, needed for mem allocation */ +{ + INT i; + FIXP_DBL* quotaMatrix = GetRam_Sbr_quotaMatrix(chan); + INT* signMatrix = GetRam_Sbr_signMatrix(chan); + + FDKmemclear(hTonCorr, sizeof(SBR_TON_CORR_EST)); + + for (i=0; i<MAX_NO_OF_ESTIMATES; i++) { + hTonCorr->quotaMatrix[i] = quotaMatrix + (i*QMF_CHANNELS); + hTonCorr->signMatrix[i] = signMatrix + (i*QMF_CHANNELS); + } + + FDKsbrEnc_CreateSbrMissingHarmonicsDetector (&hTonCorr->sbrMissingHarmonicsDetector, chan); + + return 0; +} + + + +/**************************************************************************/ +/*! + \brief Initialize an instance of the tonality correction parameter module. + + The module includes modules for inverse filtering level estimation, + missing harmonics detection and noise floor level estimation. + + \return errorCode, noError if successful. +*/ +/**************************************************************************/ +INT +FDKsbrEnc_InitTonCorrParamExtr (INT frameSize, /*!< Current SBR frame size. */ + HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + HANDLE_SBR_CONFIG_DATA sbrCfg, /*!< Pointer to SBR configuration parameters. */ + INT timeSlots, /*!< Number of time-slots per frame */ + INT xposCtrl, /*!< Different patch modes. */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + UINT useSpeechConfig) /*!< Speech or music tuning. */ +{ + INT nCols = sbrCfg->noQmfSlots; + INT fs = sbrCfg->sampleFreq; + INT noQmfChannels = sbrCfg->noQmfBands; + + INT highBandStartSb = sbrCfg->freqBandTable[LOW_RES][0]; + UCHAR *v_k_master = sbrCfg->v_k_master; + INT numMaster = sbrCfg->num_Master; + + UCHAR **freqBandTable = sbrCfg->freqBandTable; + INT *nSfb = sbrCfg->nSfb; + + INT i; + + /* + Reset the patching and allocate memory for the quota matrix. + Assing parameters for the LPC analysis. + */ + if (sbrCfg->sbrSyntaxFlags & SBR_SYNTAX_LOW_DELAY) { + switch (timeSlots) { + case NUMBER_TIME_SLOTS_1920: + hTonCorr->lpcLength[0] = 8 - LPC_ORDER; + hTonCorr->lpcLength[1] = 7 - LPC_ORDER; + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LD; + hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 7; + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + break; + case NUMBER_TIME_SLOTS_2048: + hTonCorr->lpcLength[0] = 8 - LPC_ORDER; + hTonCorr->lpcLength[1] = 8 - LPC_ORDER; + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LD; + hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 8; + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_512LD; + break; + } + } else + switch (timeSlots) { + case NUMBER_TIME_SLOTS_2048: + hTonCorr->lpcLength[0] = 16 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->lpcLength[1] = 16 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LC; + hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 16; + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_2048; + break; + case NUMBER_TIME_SLOTS_1920: + hTonCorr->lpcLength[0] = 15 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->lpcLength[1] = 15 - LPC_ORDER; /* blockLength[0] */ + hTonCorr->numberOfEstimates = NO_OF_ESTIMATES_LC; + hTonCorr->numberOfEstimatesPerFrame = sbrCfg->noQmfSlots / 15; + hTonCorr->frameStartIndexInvfEst = 0; + hTonCorr->transientPosOffset = FRAME_MIDDLE_SLOT_1920; + break; + default: + return -1; + } + + hTonCorr->bufferLength = nCols; + hTonCorr->stepSize = hTonCorr->lpcLength[0] + LPC_ORDER; /* stepSize[0] implicitly 0. */ + + hTonCorr->nextSample = LPC_ORDER; /* firstSample */ + hTonCorr->move = hTonCorr->numberOfEstimates - hTonCorr->numberOfEstimatesPerFrame; /* Number of estimates to move when buffering.*/ + hTonCorr->startIndexMatrix = hTonCorr->numberOfEstimates - hTonCorr->numberOfEstimatesPerFrame; /* Where to store the latest estimations in the tonality Matrix.*/ + hTonCorr->frameStartIndex = 0; /* Where in the tonality matrix the current frame (to be sent to the decoder) starts. */ + hTonCorr->prevTransientFlag = 0; + hTonCorr->transientNextFrame = 0; + + hTonCorr->noQmfChannels = noQmfChannels; + + for (i=0; i<hTonCorr->numberOfEstimates; i++) { + FDKmemclear (hTonCorr->quotaMatrix[i] , sizeof(FIXP_DBL)*noQmfChannels); + FDKmemclear (hTonCorr->signMatrix[i] , sizeof(INT)*noQmfChannels); + } + + /* Reset the patch.*/ + hTonCorr->guard = 0; + hTonCorr->shiftStartSb = 1; + + if(resetPatch(hTonCorr, + xposCtrl, + highBandStartSb, + v_k_master, + numMaster, + fs, + noQmfChannels)) + return(1); + + if(FDKsbrEnc_InitSbrNoiseFloorEstimate (&hTonCorr->sbrNoiseFloorEstimate, + ana_max_level, + freqBandTable[LO], + nSfb[LO], + noiseBands, + noiseFloorOffset, + timeSlots, + useSpeechConfig)) + return(1); + + + if(FDKsbrEnc_initInvFiltDetector(&hTonCorr->sbrInvFilt, + hTonCorr->sbrNoiseFloorEstimate.freqBandTableQmf, + hTonCorr->sbrNoiseFloorEstimate.noNoiseBands, + useSpeechConfig)) + return(1); + + + + if(FDKsbrEnc_InitSbrMissingHarmonicsDetector( + &hTonCorr->sbrMissingHarmonicsDetector, + fs, + frameSize, + nSfb[HI], + noQmfChannels, + hTonCorr->numberOfEstimates, + hTonCorr->move, + hTonCorr->numberOfEstimatesPerFrame, + sbrCfg->sbrSyntaxFlags)) + return(1); + + + + return (0); +} + + + +/**************************************************************************/ +/*! + \brief resets tonality correction parameter module. + + + + \return errorCode, noError if successful. + +*/ +/**************************************************************************/ +INT +FDKsbrEnc_ResetTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INT xposctrl, /*!< Different patch modes. */ + INT highBandStartSb, /*!< Start band of the SBR range. */ + UCHAR *v_k_master, /*!< Master frequency table from which all other table are derived.*/ + INT numMaster, /*!< Number of elements in the master table. */ + INT fs, /*!< Sampling frequency (of the SBR part). */ + UCHAR ** freqBandTable, /*!< Frequency band table for low-res and high-res. */ + INT* nSfb, /*!< Number of frequency bands (hig-res and low-res). */ + INT noQmfChannels /*!< Number of QMF channels. */ + ) +{ + + /* Reset the patch.*/ + hTonCorr->guard = 0; + hTonCorr->shiftStartSb = 1; + + if(resetPatch(hTonCorr, + xposctrl, + highBandStartSb, + v_k_master, + numMaster, + fs, + noQmfChannels)) + return(1); + + + + /* Reset the noise floor estimate.*/ + if(FDKsbrEnc_resetSbrNoiseFloorEstimate (&hTonCorr->sbrNoiseFloorEstimate, + freqBandTable[LO], + nSfb[LO])) + return(1); + + /* + Reset the inveerse filtereing detector. + */ + if(FDKsbrEnc_resetInvFiltDetector(&hTonCorr->sbrInvFilt, + hTonCorr->sbrNoiseFloorEstimate.freqBandTableQmf, + hTonCorr->sbrNoiseFloorEstimate.noNoiseBands)) + return(1); +/* Reset the missing harmonics detector. */ + if(FDKsbrEnc_ResetSbrMissingHarmonicsDetector (&hTonCorr->sbrMissingHarmonicsDetector, + nSfb[HI])) + return(1); + + return (0); +} + + + + + +/**************************************************************************/ +/*! + \brief Deletes the tonality correction paramtere module. + + + + \return none + +*/ +/**************************************************************************/ +void +FDKsbrEnc_DeleteTonCorrParamExtr (HANDLE_SBR_TON_CORR_EST hTonCorr) /*!< Handle to SBR_TON_CORR struct. */ +{ + + if (hTonCorr) { + + FreeRam_Sbr_quotaMatrix(hTonCorr->quotaMatrix); + + FreeRam_Sbr_signMatrix(hTonCorr->signMatrix); + + FDKsbrEnc_DeleteSbrMissingHarmonicsDetector (&hTonCorr->sbrMissingHarmonicsDetector); + + /* deleteInvFiltDetector (&hTonCorr->sbrInvFilt); */ + + } +} diff --git a/libSBRenc/src/ton_corr.h b/libSBRenc/src/ton_corr.h new file mode 100644 index 0000000..c4e9be0 --- /dev/null +++ b/libSBRenc/src/ton_corr.h @@ -0,0 +1,154 @@ +/**************************************************************************** + + (C) copyright Fraunhofer-IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Header$ + +*******************************************************************************/ +/*! + \file + \brief General tonality correction detector module. +*/ +#ifndef _TON_CORR_EST_H +#define _TON_CORR_EST_H + +#include "sbr_encoder.h" +#include "mh_det.h" +#include "nf_est.h" +#include "invf_est.h" + + +#define MAX_NUM_PATCHES 6 +#define SCALE_NRGVEC 4 + +/** parameter set for one single patch */ +typedef struct { + INT sourceStartBand; /*!< first band in lowbands where to take the samples from */ + INT sourceStopBand; /*!< first band in lowbands which is not included in the patch anymore */ + INT guardStartBand; /*!< first band in highbands to be filled with zeros in order to + reduce interferences between patches */ + INT targetStartBand; /*!< first band in highbands to be filled with whitened lowband signal */ + INT targetBandOffs; /*!< difference between 'startTargetBand' and 'startSourceBand' */ + INT numBandsInPatch; /*!< number of consecutive bands in this one patch */ +} PATCH_PARAM; + + + + +typedef struct +{ + INT switchInverseFilt; /*!< Flag to enable dynamic adaption of invf. detection */ + INT noQmfChannels; + INT bufferLength; /*!< Length of the r and i buffers. */ + INT stepSize; /*!< Stride for the lpc estimate. */ + INT numberOfEstimates; /*!< The total number of estiamtes, available in the quotaMatrix.*/ + INT numberOfEstimatesPerFrame; /*!< The number of estimates per frame available in the quotaMatrix.*/ + INT lpcLength[2]; /*!< Segment length used for second order LPC analysis.*/ + INT nextSample; /*!< Where to start the LPC analysis of the current frame.*/ + INT move; /*!< How many estimates to move in the quotaMatrix, when buffering. */ + INT frameStartIndex; /*!< The start index for the current frame in the r and i buffers. */ + INT startIndexMatrix; /*!< The start index for the current frame in the quotaMatrix. */ + INT frameStartIndexInvfEst; /*!< The start index of the inverse filtering, not the same as the others, + dependent on what decoder is used (buffer opt, or no buffer opt). */ + INT prevTransientFlag; /*!< The transisent flag (from the transient detector) for the previous frame. */ + INT transientNextFrame; /*!< Flag to indicate that the transient will show up in the next frame. */ + INT transientPosOffset; /*!< An offset value to match the transient pos as calculated by the transient detector + with the actual position in the frame.*/ + + INT *signMatrix[MAX_NO_OF_ESTIMATES]; /*!< Matrix holding the sign of each channe, i.e. indicating in what + part of a QMF channel a possible sine is. */ + + FIXP_DBL *quotaMatrix[MAX_NO_OF_ESTIMATES];/*!< Matrix holding the quota values for all estimates, all channels. */ + + FIXP_DBL nrgVector[MAX_NO_OF_ESTIMATES]; /*!< Vector holding the averaged energies for every QMF band. */ + FIXP_DBL nrgVectorFreq[QMF_CHANNELS]; /*!< Vector holding the averaged energies for every QMF channel */ + + SCHAR indexVector[QMF_CHANNELS]; /*!< Index vector poINTing to the correct lowband channel, + when indexing a highband channel, -1 represents a guard band */ + PATCH_PARAM patchParam[MAX_NUM_PATCHES]; /*!< new parameter set for patching */ + INT guard; /*!< number of guardbands between every patch */ + INT shiftStartSb; /*!< lowest subband of source range to be included in the patches */ + INT noOfPatches; /*!< number of patches */ + + SBR_MISSING_HARMONICS_DETECTOR sbrMissingHarmonicsDetector; /*!< SBR_MISSING_HARMONICS_DETECTOR struct. */ + SBR_NOISE_FLOOR_ESTIMATE sbrNoiseFloorEstimate; /*!< SBR_NOISE_FLOOR_ESTIMATE struct. */ + SBR_INV_FILT_EST sbrInvFilt; /*!< SBR_INV_FILT_EST struct. */ +} +SBR_TON_CORR_EST; + +typedef SBR_TON_CORR_EST *HANDLE_SBR_TON_CORR_EST; + +void +FDKsbrEnc_TonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INVF_MODE* infVec, /*!< Vector where the inverse filtering levels will be stored. */ + FIXP_DBL * noiseLevels, /*!< Vector where the noise levels will be stored. */ + INT* missingHarmonicFlag, /*!< Flag set to one or zero, dependent on if any strong sines are missing.*/ + UCHAR* missingHarmonicsIndex, /*!< Vector indicating where sines are missing. */ + UCHAR* envelopeCompensation, /*!< Vector to store compensation values for the energies in. */ + const SBR_FRAME_INFO *frameInfo, /*!< Frame info struct, contains the time and frequency grid of the current frame.*/ + UCHAR* transientInfo, /*!< Transient info.*/ + UCHAR * freqBandTable, /*!< Frequency band tables for high-res.*/ + INT nSfb, /*!< Number of scalefactor bands for high-res. */ + XPOS_MODE xposType, /*!< Type of transposer used in the decoder.*/ + UINT sbrSyntaxFlags + ); + +INT +FDKsbrEnc_CreateTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + INT chan); /*!< Channel index, needed for mem allocation */ + +INT +FDKsbrEnc_InitTonCorrParamExtr(INT frameSize, /*!< Current SBR frame size. */ + HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Pointer to handle to SBR_TON_CORR struct. */ + HANDLE_SBR_CONFIG_DATA sbrCfg, /*!< Pointer to SBR configuration parameters. */ + INT timeSlots, /*!< Number of time-slots per frame */ + INT xposCtrl, /*!< Different patch modes. */ + INT ana_max_level, /*!< Maximum level of the adaptive noise. */ + INT noiseBands, /*!< Number of noise bands per octave. */ + INT noiseFloorOffset, /*!< Noise floor offset. */ + UINT useSpeechConfig /*!< Speech or music tuning. */ + ); + +void +FDKsbrEnc_DeleteTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr); /*!< Handle to SBR_TON_CORR struct. */ + + +void +FDKsbrEnc_CalculateTonalityQuotas(HANDLE_SBR_TON_CORR_EST hTonCorr, + FIXP_DBL **sourceBufferReal, + FIXP_DBL **sourceBufferImag, + INT usb, + INT qmfScale /*!< sclefactor of QMF subsamples */ + ); + +INT +FDKsbrEnc_ResetTonCorrParamExtr(HANDLE_SBR_TON_CORR_EST hTonCorr, /*!< Handle to SBR_TON_CORR struct. */ + INT xposctrl, /*!< Different patch modes. */ + INT highBandStartSb, /*!< Start band of the SBR range. */ + UCHAR *v_k_master, /*!< Master frequency table from which all other table are derived.*/ + INT numMaster, /*!< Number of elements in the master table. */ + INT fs, /*!< Sampling frequency (of the SBR part). */ + UCHAR** freqBandTable, /*!< Frequency band table for low-res and high-res. */ + INT* nSfb, /*!< Number of frequency bands (hig-res and low-res). */ + INT noQmfChannels /*!< Number of QMF channels. */ + ); +#endif + diff --git a/libSBRenc/src/tran_det.cpp b/libSBRenc/src/tran_det.cpp new file mode 100644 index 0000000..4011bf3 --- /dev/null +++ b/libSBRenc/src/tran_det.cpp @@ -0,0 +1,645 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ + +#include "tran_det.h" + +#include "fram_gen.h" +#include "sbr_ram.h" +#include "sbr_misc.h" + +#include "genericStds.h" + +#define NORM_QMF_ENERGY 5.684341886080801486968994140625e-14 /* 2^-44 */ + +/* static FIXP_DBL ABS_THRES = fixMax( FL2FXCONST_DBL(1.28e5 * NORM_QMF_ENERGY), (FIXP_DBL)1) Minimum threshold for detecting changes */ +#define ABS_THRES ((FIXP_DBL)16) + +/******************************************************************************* + Functionname: spectralChange + ******************************************************************************* + \brief Calculates a measure for the spectral change within the frame + + The function says how good it would be to split the frame at the given border + position into 2 envelopes. + + The return value delta_sum is scaled with the factor 1/64 + + \return calculated value +*******************************************************************************/ +static FIXP_DBL spectralChange(FIXP_DBL Energies[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS], + INT *scaleEnergies, + FIXP_DBL EnergyTotal, + INT nSfb, + INT start, + INT border, + INT stop) +{ + INT i,j; + INT len1,len2; + FIXP_DBL delta,tmp0,tmp1,tmp2; + FIXP_DBL accu1,accu2,delta_sum,result; + + FDK_ASSERT(scaleEnergies[0] >= 0); + + /* equal for aac (would be not equal for mp3) */ + len1 = border-start; + len2 = stop-border; + + /* prefer borders near the middle of the frame */ + FIXP_DBL pos_weight; + pos_weight = FL2FXCONST_DBL(0.5f) - (len1*GetInvInt(len1+len2)); + pos_weight = /*FL2FXCONST_DBL(1.0)*/ (FIXP_DBL)MAXVAL_DBL - (fMult(pos_weight, pos_weight)<<2); + + delta_sum = FL2FXCONST_DBL(0.0f); + + /* Sum up energies of all QMF-timeslots for both halfs */ + for (j=0; j<nSfb; j++) { + #define NRG_SCALE 3 + /* init with some energy to prevent division by zero + and to prevent splitting for very low levels */ + accu1 = ((FL2FXCONST_DBL((1.0e6*NORM_QMF_ENERGY*8.0/32))) << fixMin(scaleEnergies[0],25))>>NRG_SCALE; /* complex init for compare with original version */ + accu2 = ((FL2FXCONST_DBL((1.0e6*NORM_QMF_ENERGY*8.0/32))) << fixMin(scaleEnergies[0],25))>>NRG_SCALE; /* can be simplified in dsp implementation */ + + /* Sum up energies in first half */ + for (i=start; i<border; i++) { + accu1 += (Energies[i][j]>>NRG_SCALE); + } + + /* Sum up energies in second half */ + for (i=border; i<stop; i++) { + accu2 += (Energies[i][j]>>NRG_SCALE); + } + + /* Energy change in current band */ + tmp0 = CalcLdData(accu2); + tmp1 = CalcLdData(accu1); + tmp2 = (tmp0 - tmp1 + CalcLdData(len1)-CalcLdData(len2)); + delta = fixp_abs(fMult(tmp2, FL2FXCONST_DBL(0.6931471806f))); + + /* Weighting with amplitude ratio of this band */ + result = (EnergyTotal == FL2FXCONST_DBL(0.0f)) + ? FL2FXCONST_DBL(0.f) + : FDKsbrEnc_LSI_divide_scale_fract( (accu1+accu2), + (EnergyTotal>>NRG_SCALE)+(FIXP_DBL)1, + (FIXP_DBL)MAXVAL_DBL >> fixMin(scaleEnergies[0],(DFRACT_BITS-1)) ); + + delta_sum += (FIXP_DBL)(fMult(sqrtFixp(result), delta)); + } + + return fMult(delta_sum, pos_weight); +} + + +/******************************************************************************* + Functionname: addLowbandEnergies + ******************************************************************************* + \brief Calculates total lowband energy + + The return value nrgTotal is scaled by the factor (1/32.0) + + \return total energy in the lowband +*******************************************************************************/ +static FIXP_DBL addLowbandEnergies(FIXP_DBL **Energies, + int *scaleEnergies, + int YBufferWriteOffset, + int nrgSzShift, + int tran_off, + UCHAR *freqBandTable, + int slots) +{ + FIXP_DBL nrgTotal; + FIXP_DBL accu1 = FL2FXCONST_DBL(0.0f); + FIXP_DBL accu2 = FL2FXCONST_DBL(0.0f); + int tran_offdiv2 = tran_off>>nrgSzShift; + int ts,k; + + /* Sum up lowband energy from one frame at offset tran_off */ + for (ts=tran_offdiv2; ts<YBufferWriteOffset; ts++) { + for (k = 0; k < freqBandTable[0]; k++) { + accu1 += Energies[ts][k] >> 6; + } + } + for (; ts<tran_offdiv2+(slots>>nrgSzShift); ts++) { + for (k = 0; k < freqBandTable[0]; k++) { + accu2 += Energies[ts][k] >> 6; + } + } + + nrgTotal = ( (accu1 >> fixMin(scaleEnergies[0],(DFRACT_BITS-1))) + + (accu2 >> fixMin(scaleEnergies[1],(DFRACT_BITS-1))) ) << (2); + + return(nrgTotal); +} + + +/******************************************************************************* + Functionname: addHighbandEnergies + ******************************************************************************* + \brief Add highband energies + + Highband energies are mapped to an array with smaller dimension: + Its time resolution is only 1 SBR-timeslot and its frequency resolution + is 1 SBR-band. Therefore the data to be fed into the spectralChange + function is reduced. + + The values EnergiesM are scaled by the factor (1/32.0) and scaleEnergies[0] + The return value nrgTotal is scaled by the factor (1/32.0) + + \return total energy in the highband +*******************************************************************************/ + +static FIXP_DBL addHighbandEnergies(FIXP_DBL **RESTRICT Energies, /*!< input */ + INT *scaleEnergies, + FIXP_DBL EnergiesM[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS], /*!< Combined output */ + UCHAR *RESTRICT freqBandTable, + INT nSfb, + INT sbrSlots, + INT timeStep) +{ + INT i,j,k,slotIn,slotOut,scale; + INT li,ui; + FIXP_DBL nrgTotal; + FIXP_DBL accu = FL2FXCONST_DBL(0.0f); + + /* Combine QMF-timeslots to SBR-timeslots, + combine QMF-bands to SBR-bands, + combine Left and Right channel */ + for (slotOut=0; slotOut<sbrSlots; slotOut++) { + slotIn = 2*slotOut; + + for (j=0; j<nSfb; j++) { + accu = FL2FXCONST_DBL(0.0f); + + li = freqBandTable[j]; + ui = freqBandTable[j + 1]; + + for (k=li; k<ui; k++) { + for (i=0; i<timeStep; i++) { + accu += (Energies[(slotIn+i)>>1][k] >> 5); + } + } + EnergiesM[slotOut][j] = accu; + } + } + + scale = fixMin(8,scaleEnergies[0]); /* scale energies down before add up */ + + if ((scaleEnergies[0]-1) > (DFRACT_BITS-1) ) + nrgTotal = FL2FXCONST_DBL(0.0f); + else { + /* Now add all energies */ + accu = FL2FXCONST_DBL(0.0f); + for (slotOut=0; slotOut<sbrSlots; slotOut++) { + for (j=0; j<nSfb; j++) { + accu += (EnergiesM[slotOut][j] >> scale); + } + } + nrgTotal = accu >> (scaleEnergies[0]-scale); + } + + return(nrgTotal); +} + + +/******************************************************************************* + Functionname: FDKsbrEnc_frameSplitter + ******************************************************************************* + \brief Decides if a FIXFIX-frame shall be splitted into 2 envelopes + + If no transient has been detected before, the frame can still be splitted + into 2 envelopes. +*******************************************************************************/ +void +FDKsbrEnc_frameSplitter(FIXP_DBL **Energies, + INT *scaleEnergies, + HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + UCHAR *freqBandTable, + UCHAR *tran_vector, + int YBufferWriteOffset, + int YBufferSzShift, + int nSfb, + int timeStep, + int no_cols) +{ + if (tran_vector[1]==0) /* no transient was detected */ + { + FIXP_DBL delta; + FIXP_DBL EnergiesM[NUMBER_TIME_SLOTS_2304][MAX_FREQ_COEFFS]; + FIXP_DBL EnergyTotal,newLowbandEnergy,newHighbandEnergy; + INT border; + INT sbrSlots = fMultI(GetInvInt(timeStep),no_cols); + + FDK_ASSERT( sbrSlots * timeStep == no_cols ); + + /* + Get Lowband-energy over a range of 2 frames (Look half a frame back and ahead). + */ + newLowbandEnergy = addLowbandEnergies(Energies, + scaleEnergies, + YBufferWriteOffset, + YBufferSzShift, + h_sbrTransientDetector->tran_off, + freqBandTable, + no_cols); + + newHighbandEnergy = addHighbandEnergies(Energies, + scaleEnergies, + EnergiesM, + freqBandTable, + nSfb, + sbrSlots, + timeStep); + + if ( h_sbrTransientDetector->frameShift != 0 ) { + if (tran_vector[1]==0) + tran_vector[0] = 0; + } else + { + /* prevLowBandEnergy: Corresponds to 1 frame, starting with half a frame look-behind + newLowbandEnergy: Corresponds to 1 frame, starting in the middle of the current frame */ + EnergyTotal = (newLowbandEnergy + h_sbrTransientDetector->prevLowBandEnergy) >> 1; + EnergyTotal += newHighbandEnergy; + /* The below border should specify the same position as the middle border + of a FIXFIX-frame with 2 envelopes. */ + border = (sbrSlots+1) >> 1; + + delta = spectralChange(EnergiesM, + scaleEnergies, + EnergyTotal, + nSfb, + 0, + border, + sbrSlots); + + if (delta > (h_sbrTransientDetector->split_thr >> LD_DATA_SHIFT)) /* delta scaled by 1/64 */ + tran_vector[0] = 1; /* Set flag for splitting */ + else + tran_vector[0] = 0; + } + + /* Update prevLowBandEnergy */ + h_sbrTransientDetector->prevLowBandEnergy = newLowbandEnergy; + h_sbrTransientDetector->prevHighBandEnergy = newHighbandEnergy; + } +} + +/* + * Calculate transient energy threshold for each QMF band + */ +static void +calculateThresholds(FIXP_DBL **RESTRICT Energies, + INT *RESTRICT scaleEnergies, + FIXP_DBL *RESTRICT thresholds, + int YBufferWriteOffset, + int YBufferSzShift, + int noCols, + int noRows, + int tran_off) +{ + FIXP_DBL mean_val,std_val,temp; + FIXP_DBL i_noCols; + FIXP_DBL i_noCols1; + FIXP_DBL accu,accu0,accu1; + int scaleFactor0,scaleFactor1,commonScale; + int i,j; + + i_noCols = GetInvInt(noCols + tran_off ) << YBufferSzShift; + i_noCols1 = GetInvInt(noCols + tran_off - 1) << YBufferSzShift; + + /* calc minimum scale of energies of previous and current frame */ + commonScale = fixMin(scaleEnergies[0],scaleEnergies[1]); + + /* calc scalefactors to adapt energies to common scale */ + scaleFactor0 = fixMin((scaleEnergies[0]-commonScale), (DFRACT_BITS-1)); + scaleFactor1 = fixMin((scaleEnergies[1]-commonScale), (DFRACT_BITS-1)); + + FDK_ASSERT((scaleFactor0 >= 0) && (scaleFactor1 >= 0)); + + /* calculate standard deviation in every subband */ + for (i=0; i<noRows; i++) + { + int startEnergy = (tran_off>>YBufferSzShift); + int endEnergy = ((noCols>>YBufferSzShift)+tran_off); + int shift; + + /* calculate mean value over decimated energy values (downsampled by 2). */ + accu0 = accu1 = FL2FXCONST_DBL(0.0f); + + for (j=startEnergy; j<YBufferWriteOffset; j++) + accu0 += fMult(Energies[j][i], i_noCols); + for (; j<endEnergy; j++) + accu1 += fMult(Energies[j][i], i_noCols); + + mean_val = (accu0 >> scaleFactor0) + (accu1 >> scaleFactor1); /* average */ + shift = fixMax(0,CountLeadingBits(mean_val)-6); /* -6 to keep room for accumulating upto N = 24 values */ + + /* calculate standard deviation */ + accu = FL2FXCONST_DBL(0.0f); + + /* summe { ((mean_val-nrg)^2) * i_noCols1 } */ + for (j=startEnergy; j<YBufferWriteOffset; j++) { + temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor0))<<shift; + temp = fPow2(temp); + temp = fMult(temp, i_noCols1); + accu += temp; + } + for (; j<endEnergy; j++) { + temp = ((FIXP_DBL)mean_val - ((FIXP_DBL)Energies[j][i] >> scaleFactor1))<<shift; + temp = fPow2(temp); + temp = fMult(temp, i_noCols1); + accu += temp; + } + + std_val = sqrtFixp(accu)>>shift; /* standard deviation */ + + /* + Take new threshold as average of calculated standard deviation ratio + and old threshold if greater than absolute threshold + */ + temp = ( commonScale<=(DFRACT_BITS-1) ) + ? fMult(FL2FXCONST_DBL(0.66f), thresholds[i]) + (fMult(FL2FXCONST_DBL(0.34f), std_val) >> commonScale) + : (FIXP_DBL) 0; + + thresholds[i] = fixMax(ABS_THRES,temp); + + FDK_ASSERT(commonScale >= 0); + } +} + +/* + * Calculate transient levels for each QMF time slot. + */ +static void +extractTransientCandidates(FIXP_DBL **RESTRICT Energies, + INT *RESTRICT scaleEnergies, + FIXP_DBL *RESTRICT thresholds, + FIXP_DBL *RESTRICT transients, + int YBufferWriteOffset, + int YBufferSzShift, + int noCols, + int start_band, + int stop_band, + int tran_off, + int addPrevSamples) +{ + FIXP_DBL i_thres; + C_ALLOC_SCRATCH_START(EnergiesTemp, FIXP_DBL, 2*QMF_MAX_TIME_SLOTS); + FIXP_DBL *RESTRICT pEnergiesTemp = EnergiesTemp; + int tmpScaleEnergies0, tmpScaleEnergies1; + int endCond; + int startEnerg,endEnerg; + int i,j,jIndex,jpBM; + + tmpScaleEnergies0 = scaleEnergies[0]; + tmpScaleEnergies1 = scaleEnergies[1]; + + /* Scale value for first energies, upto YBufferWriteOffset */ + tmpScaleEnergies0 = fixMin(tmpScaleEnergies0, MAX_SHIFT_DBL); + /* Scale value for first energies, from YBufferWriteOffset upwards */ + tmpScaleEnergies1 = fixMin(tmpScaleEnergies1, MAX_SHIFT_DBL); + + FDK_ASSERT((tmpScaleEnergies0 >= 0) && (tmpScaleEnergies1 >= 0)); + + /* Keep addPrevSamples extra previous transient candidates. */ + FDKmemmove(transients, transients + noCols - addPrevSamples, (tran_off+addPrevSamples) * sizeof (FIXP_DBL)); + FDKmemclear(transients + tran_off + addPrevSamples, noCols * sizeof (FIXP_DBL)); + + endCond = noCols; /* Amount of new transient values to be calculated. */ + startEnerg = (tran_off-3)>>YBufferSzShift; /* >>YBufferSzShift because of amount of energy values. -3 because of neighbors being watched. */ + endEnerg = ((noCols+ (YBufferWriteOffset<<YBufferSzShift))-1)>>YBufferSzShift; /* YBufferSzShift shifts because of half energy values. */ + + /* Compute differential values with two different weightings in every subband */ + for (i=start_band; i<stop_band; i++) + { + FIXP_DBL thres = thresholds[i]; + + if((LONG)thresholds[i]>=256) + i_thres = (LONG)( (LONG)MAXVAL_DBL / ((((LONG)thresholds[i]))+1) )<<(32-24); + else + i_thres = (LONG)MAXVAL_DBL; + + /* Copy one timeslot and de-scale and de-squish */ + if (YBufferSzShift == 1) { + for(j=startEnerg; j<YBufferWriteOffset; j++) { + FIXP_DBL tmp = Energies[j][i]; + EnergiesTemp[(j<<1)+1] = EnergiesTemp[j<<1] = tmp>>tmpScaleEnergies0; + } + for(; j<=endEnerg; j++) { + FIXP_DBL tmp = Energies[j][i]; + EnergiesTemp[(j<<1)+1] = EnergiesTemp[j<<1] = tmp>>tmpScaleEnergies1; + } + } else { + for(j=startEnerg; j<YBufferWriteOffset; j++) { + FIXP_DBL tmp = Energies[j][i]; + EnergiesTemp[j] = tmp>>tmpScaleEnergies0; + } + for(; j<=endEnerg; j++) { + FIXP_DBL tmp = Energies[j][i]; + EnergiesTemp[j] = tmp>>tmpScaleEnergies1; + } + } + + /* Detect peaks in energy values. */ + + jIndex = tran_off; + jpBM = jIndex+addPrevSamples; + + for (j=endCond; j--; jIndex++, jpBM++) + { + + FIXP_DBL delta, tran; + int d; + + delta = (FIXP_DBL)0; + tran = (FIXP_DBL)0; + + for (d=1; d<4; d++) { + delta += pEnergiesTemp[jIndex+d]; /* R */ + delta -= pEnergiesTemp[jIndex-d]; /* L */ + delta -= thres; + + if ( delta > (FIXP_DBL)0 ) { + tran += fMult(i_thres, delta); + } + } + transients[jpBM] += tran; + } + } + C_ALLOC_SCRATCH_END(EnergiesTemp, FIXP_DBL, 2*QMF_MAX_TIME_SLOTS); +} + +void +FDKsbrEnc_transientDetect(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTran, + FIXP_DBL **Energies, + INT *scaleEnergies, + UCHAR *transient_info, + int YBufferWriteOffset, + int YBufferSzShift, + int timeStep, + int frameMiddleBorder) +{ + int no_cols = h_sbrTran->no_cols; + int qmfStartSample; + int addPrevSamples; + int timeStepShift=0; + int i, cond; + + /* Where to start looking for transients in the transient candidate buffer */ + qmfStartSample = timeStep * frameMiddleBorder; + /* We need to look one value backwards in the transients, so we might need one more previous value. */ + addPrevSamples = (qmfStartSample > 0) ? 0: 1; + + switch (timeStep) { + case 1: timeStepShift = 0; break; + case 2: timeStepShift = 1; break; + case 4: timeStepShift = 2; break; + } + + calculateThresholds(Energies, + scaleEnergies, + h_sbrTran->thresholds, + YBufferWriteOffset, + YBufferSzShift, + h_sbrTran->no_cols, + h_sbrTran->no_rows, + h_sbrTran->tran_off); + + extractTransientCandidates(Energies, + scaleEnergies, + h_sbrTran->thresholds, + h_sbrTran->transients, + YBufferWriteOffset, + YBufferSzShift, + h_sbrTran->no_cols, + 0, + h_sbrTran->no_rows, + h_sbrTran->tran_off, + addPrevSamples ); + + transient_info[0] = 0; + transient_info[1] = 0; + transient_info[2] = 0; + + /* Offset by the amount of additional previous transient candidates being kept. */ + qmfStartSample += addPrevSamples; + + /* Check for transients in second granule (pick the last value of subsequent values) */ + for (i=qmfStartSample; i<qmfStartSample + no_cols; i++) { + cond = (h_sbrTran->transients[i] < fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1]) ) + && (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr); + + if (cond) { + transient_info[0] = (i - qmfStartSample)>>timeStepShift; + /* FDKprintf("\nSBR Transient at timeSlot %d\n", transient_info[0]); */ + transient_info[1] = 1; + break; + } + } + + if ( h_sbrTran->frameShift != 0) { + /* transient prediction for LDSBR */ + /* Check for transients in first <frameShift> qmf-slots of second frame */ + for (i=qmfStartSample+no_cols; i<qmfStartSample + no_cols+h_sbrTran->frameShift; i++) { + + cond = (h_sbrTran->transients[i] < fMult(FL2FXCONST_DBL(0.9f), h_sbrTran->transients[i - 1]) ) + && (h_sbrTran->transients[i - 1] > h_sbrTran->tran_thr); + + if (cond) { + int pos = (int) ( (i - qmfStartSample-no_cols) >> timeStepShift ); + if ((pos < 3) && (transient_info[1]==0)) { + transient_info[2] = 1; + } + break; + } + } + } +} + +int +FDKsbrEnc_InitSbrTransientDetector(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + INT frameSize, + INT sampleFreq, + sbrConfigurationPtr params, + int tran_fc, + int no_cols, + int no_rows, + int YBufferWriteOffset, + int YBufferSzShift, + int frameShift, + int tran_off) +{ + INT totalBitrate = params->codecSettings.standardBitrate * params->codecSettings.nChannels; + INT codecBitrate = params->codecSettings.bitRate; + FIXP_DBL bitrateFactor_fix, framedur_fix; + INT scale_0, scale_1; + + FDKmemclear(h_sbrTransientDetector,sizeof(SBR_TRANSIENT_DETECTOR)); + + h_sbrTransientDetector->frameShift = frameShift; + h_sbrTransientDetector->tran_off = tran_off; + + if(codecBitrate) { + bitrateFactor_fix = fDivNorm((FIXP_DBL)totalBitrate, (FIXP_DBL)(codecBitrate<<2),&scale_0); + } + else { + bitrateFactor_fix = FL2FXCONST_DBL(1.0/4.0); + scale_0 = 0; + } + + framedur_fix = fDivNorm(frameSize, sampleFreq); + + /* The longer the frames, the more often should the FIXFIX- + case transmit 2 envelopes instead of 1. + Frame durations below 10 ms produce the highest threshold + so that practically always only 1 env is transmitted. */ + FIXP_DBL tmp = framedur_fix - FL2FXCONST_DBL(0.010); + + tmp = fixMax(tmp, FL2FXCONST_DBL(0.0001)); + tmp = fDivNorm(FL2FXCONST_DBL(0.000075), fPow2(tmp), &scale_1); + + scale_1 = -(scale_1 + scale_0 + 2); + + FDK_ASSERT(no_cols <= QMF_MAX_TIME_SLOTS); + FDK_ASSERT(no_rows <= QMF_CHANNELS); + + h_sbrTransientDetector->no_cols = no_cols; + h_sbrTransientDetector->tran_thr = (FIXP_DBL)((params->tran_thr << (32-24-1)) / no_rows); + h_sbrTransientDetector->tran_fc = tran_fc; + + if (scale_1>=0) { + h_sbrTransientDetector->split_thr = fMult(tmp, bitrateFactor_fix) >> scale_1; + } + else { + h_sbrTransientDetector->split_thr = fMult(tmp, bitrateFactor_fix) << (-scale_1); + } + + h_sbrTransientDetector->no_rows = no_rows; + h_sbrTransientDetector->mode = params->tran_det_mode; + h_sbrTransientDetector->prevLowBandEnergy = FL2FXCONST_DBL(0.0f); + + return (0); +} + diff --git a/libSBRenc/src/tran_det.h b/libSBRenc/src/tran_det.h new file mode 100644 index 0000000..3430b44 --- /dev/null +++ b/libSBRenc/src/tran_det.h @@ -0,0 +1,92 @@ +/**************************************************************************** + + (C) Copyright Fraunhofer IIS (2004) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + + $Id$ + +*******************************************************************************/ +/*! + \file + \brief Transient detector prototypes $Revision: 36847 $ +*/ +#ifndef __TRAN_DET_H +#define __TRAN_DET_H + +#include "sbr_encoder.h" +#include "sbr_def.h" + +typedef struct +{ + FIXP_DBL transients[QMF_MAX_TIME_SLOTS+(QMF_MAX_TIME_SLOTS/2)]; + FIXP_DBL thresholds[QMF_CHANNELS]; + FIXP_DBL tran_thr; /* Master threshold for transient signals */ + FIXP_DBL split_thr; /* Threshold for splitting FIXFIX-frames into 2 env */ + FIXP_DBL prevLowBandEnergy; /* Energy of low band */ + FIXP_DBL prevHighBandEnergy; /* Energy of high band */ + INT tran_fc; /* Number of lowband subbands to discard */ + INT no_cols; + INT no_rows; + INT mode; + + int frameShift; + int tran_off; /* Offset for reading energy values. */ +} +SBR_TRANSIENT_DETECTOR; + + +typedef SBR_TRANSIENT_DETECTOR *HANDLE_SBR_TRANSIENT_DETECTOR; + +void +FDKsbrEnc_transientDetect(HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + FIXP_DBL **Energies, + INT *scaleEnergies, + UCHAR *tran_vector, + int YBufferWriteOffset, + int YBufferSzShift, + int timeStep, + int frameMiddleBorder); + +int +FDKsbrEnc_InitSbrTransientDetector (HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + INT frameSize, + INT sampleFreq, + sbrConfigurationPtr params, + int tran_fc, + int no_cols, + int no_rows, + int YBufferWriteOffset, + int YBufferSzShift, + int frameShift, + int tran_off); + +void +FDKsbrEnc_frameSplitter(FIXP_DBL **Energies, + INT *scaleEnergies, + HANDLE_SBR_TRANSIENT_DETECTOR h_sbrTransientDetector, + UCHAR *freqBandTable, + UCHAR *tran_vector, + int YBufferWriteOffset, + int YBufferSzShift, + int nSfb, + int timeStep, + int no_cols); + +#endif |