summaryrefslogtreecommitdiffstats
path: root/libSBRenc
diff options
context:
space:
mode:
authorDave Burke <daveburke@google.com>2012-04-17 09:51:45 -0700
committerDave Burke <daveburke@google.com>2012-04-17 23:04:43 -0700
commit9bf37cc9712506b2483650c82d3c41152337ef7e (patch)
tree77db44e2bae06e3d144b255628be2b7a55c581d3 /libSBRenc
parenta37315fe10ee143d6d0b28c19d41a476a23e63ea (diff)
downloadODR-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')
-rw-r--r--libSBRenc/Android.mk1
-rw-r--r--libSBRenc/include/sbr_encoder.h322
-rw-r--r--libSBRenc/src/Android.mk36
-rw-r--r--libSBRenc/src/bit_sbr.cpp1001
-rw-r--r--libSBRenc/src/bit_sbr.h203
-rw-r--r--libSBRenc/src/cmondata.h52
-rw-r--r--libSBRenc/src/code_env.cpp584
-rw-r--r--libSBRenc/src/code_env.h97
-rw-r--r--libSBRenc/src/env_bit.cpp192
-rw-r--r--libSBRenc/src/env_bit.h68
-rw-r--r--libSBRenc/src/env_est.cpp1834
-rw-r--r--libSBRenc/src/env_est.h167
-rw-r--r--libSBRenc/src/fram_gen.cpp2015
-rw-r--r--libSBRenc/src/fram_gen.h249
-rw-r--r--libSBRenc/src/invf_est.cpp472
-rw-r--r--libSBRenc/src/invf_est.h119
-rw-r--r--libSBRenc/src/mh_det.cpp1381
-rw-r--r--libSBRenc/src/mh_det.h138
-rw-r--r--libSBRenc/src/nf_est.cpp518
-rw-r--r--libSBRenc/src/nf_est.h89
-rw-r--r--libSBRenc/src/ps_bitenc.cpp635
-rw-r--r--libSBRenc/src/ps_bitenc.h115
-rw-r--r--libSBRenc/src/ps_const.h65
-rw-r--r--libSBRenc/src/ps_encode.cpp1068
-rw-r--r--libSBRenc/src/ps_encode.h117
-rw-r--r--libSBRenc/src/ps_main.cpp1079
-rw-r--r--libSBRenc/src/ps_main.h160
-rw-r--r--libSBRenc/src/psenc_hybrid.cpp836
-rw-r--r--libSBRenc/src/psenc_hybrid.h182
-rw-r--r--libSBRenc/src/resampler.cpp450
-rw-r--r--libSBRenc/src/resampler.h109
-rw-r--r--libSBRenc/src/sbr.h107
-rw-r--r--libSBRenc/src/sbr_def.h228
-rw-r--r--libSBRenc/src/sbr_encoder.cpp2109
-rw-r--r--libSBRenc/src/sbr_misc.cpp214
-rw-r--r--libSBRenc/src/sbr_misc.h48
-rw-r--r--libSBRenc/src/sbr_ram.cpp220
-rw-r--r--libSBRenc/src/sbr_ram.h171
-rw-r--r--libSBRenc/src/sbr_rom.cpp681
-rw-r--r--libSBRenc/src/sbr_rom.h70
-rw-r--r--libSBRenc/src/sbrenc_freq_sca.cpp613
-rw-r--r--libSBRenc/src/sbrenc_freq_sca.h71
-rw-r--r--libSBRenc/src/ton_corr.cpp829
-rw-r--r--libSBRenc/src/ton_corr.h154
-rw-r--r--libSBRenc/src/tran_det.cpp645
-rw-r--r--libSBRenc/src/tran_det.h92
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 = &paramsAacLd;
+ } else
+ hs->mhParams = &paramsAac;
+
+ 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[] = {
+ &param_set48,
+ &param_set45,
+ &param_set41,
+ &param_set35,
+ &param_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