summaryrefslogtreecommitdiffstats
path: root/libAACenc/src
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 /libAACenc/src
parenta37315fe10ee143d6d0b28c19d41a476a23e63ea (diff)
downloadfdk-aac-dabplus-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.gz
fdk-aac-dabplus-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.bz2
fdk-aac-dabplus-9bf37cc9712506b2483650c82d3c41152337ef7e.zip
Fraunhofer AAC codec.
License boilerplate update to follow. Change-Id: I2810460c11a58b6d148d84673cc031f3685e79b5
Diffstat (limited to 'libAACenc/src')
-rw-r--r--libAACenc/src/Android.mk53
-rw-r--r--libAACenc/src/aacEnc_ram.cpp132
-rw-r--r--libAACenc/src/aacEnc_ram.h163
-rw-r--r--libAACenc/src/aacEnc_rom.cpp1170
-rw-r--r--libAACenc/src/aacEnc_rom.h141
-rw-r--r--libAACenc/src/aacenc.cpp952
-rw-r--r--libAACenc/src/aacenc.h232
-rw-r--r--libAACenc/src/aacenc_hcr.cpp31
-rw-r--r--libAACenc/src/aacenc_hcr.h33
-rw-r--r--libAACenc/src/aacenc_lib.cpp1696
-rw-r--r--libAACenc/src/aacenc_pns.cpp532
-rw-r--r--libAACenc/src/aacenc_pns.h52
-rw-r--r--libAACenc/src/aacenc_tns.cpp1286
-rw-r--r--libAACenc/src/aacenc_tns.h135
-rw-r--r--libAACenc/src/adj_thr.cpp2262
-rw-r--r--libAACenc/src/adj_thr.h79
-rw-r--r--libAACenc/src/adj_thr_data.h88
-rw-r--r--libAACenc/src/band_nrg.cpp297
-rw-r--r--libAACenc/src/band_nrg.h86
-rw-r--r--libAACenc/src/bandwidth.cpp316
-rw-r--r--libAACenc/src/bandwidth.h44
-rw-r--r--libAACenc/src/bit_cnt.cpp1060
-rw-r--r--libAACenc/src/bit_cnt.h124
-rw-r--r--libAACenc/src/bitenc.cpp1431
-rw-r--r--libAACenc/src/bitenc.h120
-rw-r--r--libAACenc/src/block_switch.cpp500
-rw-r--r--libAACenc/src/block_switch.h85
-rw-r--r--libAACenc/src/channel_map.cpp499
-rw-r--r--libAACenc/src/channel_map.h72
-rw-r--r--libAACenc/src/chaosmeasure.cpp99
-rw-r--r--libAACenc/src/chaosmeasure.h41
-rw-r--r--libAACenc/src/dyn_bits.cpp743
-rw-r--r--libAACenc/src/dyn_bits.h104
-rw-r--r--libAACenc/src/grp_data.cpp206
-rw-r--r--libAACenc/src/grp_data.h53
-rw-r--r--libAACenc/src/intensity.cpp691
-rw-r--r--libAACenc/src/intensity.h61
-rw-r--r--libAACenc/src/interface.h100
-rw-r--r--libAACenc/src/line_pe.cpp145
-rw-r--r--libAACenc/src/line_pe.h77
-rw-r--r--libAACenc/src/metadata_compressor.cpp965
-rw-r--r--libAACenc/src/metadata_compressor.h190
-rw-r--r--libAACenc/src/metadata_main.cpp809
-rw-r--r--libAACenc/src/metadata_main.h161
-rw-r--r--libAACenc/src/ms_stereo.cpp189
-rw-r--r--libAACenc/src/ms_stereo.h44
-rw-r--r--libAACenc/src/noisedet.cpp170
-rw-r--r--libAACenc/src/noisedet.h47
-rw-r--r--libAACenc/src/pns_func.h89
-rw-r--r--libAACenc/src/pnsparam.cpp248
-rw-r--r--libAACenc/src/pnsparam.h78
-rw-r--r--libAACenc/src/pre_echo_control.cpp108
-rw-r--r--libAACenc/src/pre_echo_control.h51
-rw-r--r--libAACenc/src/psy_configuration.cpp594
-rw-r--r--libAACenc/src/psy_configuration.h102
-rw-r--r--libAACenc/src/psy_const.h99
-rw-r--r--libAACenc/src/psy_data.h89
-rw-r--r--libAACenc/src/psy_main.cpp1338
-rw-r--r--libAACenc/src/psy_main.h111
-rw-r--r--libAACenc/src/qc_data.h214
-rw-r--r--libAACenc/src/qc_main.cpp1551
-rw-r--r--libAACenc/src/qc_main.h108
-rw-r--r--libAACenc/src/quantize.cpp323
-rw-r--r--libAACenc/src/quantize.h56
-rw-r--r--libAACenc/src/sf_estim.cpp1243
-rw-r--r--libAACenc/src/sf_estim.h54
-rw-r--r--libAACenc/src/spreading.cpp52
-rw-r--r--libAACenc/src/spreading.h40
-rw-r--r--libAACenc/src/tns_func.h81
-rw-r--r--libAACenc/src/tns_param.cpp31
-rw-r--r--libAACenc/src/tns_param.h33
-rw-r--r--libAACenc/src/tonality.cpp147
-rw-r--r--libAACenc/src/tonality.h46
-rw-r--r--libAACenc/src/transform.cpp203
-rw-r--r--libAACenc/src/transform.h60
75 files changed, 25715 insertions, 0 deletions
diff --git a/libAACenc/src/Android.mk b/libAACenc/src/Android.mk
new file mode 100644
index 0000000..d3bbb9b
--- /dev/null
+++ b/libAACenc/src/Android.mk
@@ -0,0 +1,53 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ aacenc.cpp \
+ aacEnc_ram.cpp \
+ band_nrg.cpp \
+ block_switch.cpp \
+ grp_data.cpp \
+ metadata_main.cpp \
+ pre_echo_control.cpp \
+ quantize.cpp \
+ tonality.cpp \
+ aacenc_hcr.cpp \
+ aacEnc_rom.cpp \
+ bandwidth.cpp \
+ channel_map.cpp \
+ intensity.cpp \
+ ms_stereo.cpp \
+ psy_configuration.cpp \
+ sf_estim.cpp \
+ transform.cpp \
+ aacenc_lib.cpp \
+ aacenc_tns.cpp \
+ bit_cnt.cpp \
+ chaosmeasure.cpp \
+ line_pe.cpp \
+ noisedet.cpp \
+ psy_main.cpp \
+ spreading.cpp \
+ aacenc_pns.cpp \
+ adj_thr.cpp \
+ bitenc.cpp \
+ dyn_bits.cpp \
+ metadata_compressor.cpp \
+ pnsparam.cpp \
+ qc_main.cpp \
+ tns_param.cpp
+
+LOCAL_CFLAGS := -DANDROID
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/../include \
+ $(LOCAL_PATH)/../../libPCMutils/include \
+ $(LOCAL_PATH)/../../libFDK/include \
+ $(LOCAL_PATH)/../../libSYS/include \
+ $(LOCAL_PATH)/../../libMpegTPEnc/include \
+ $(LOCAL_PATH)/../../libSBRenc/include
+
+LOCAL_MODULE:= libAACenc
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libAACenc/src/aacEnc_ram.cpp b/libAACenc/src/aacEnc_ram.cpp
new file mode 100644
index 0000000..3122bb8
--- /dev/null
+++ b/libAACenc/src/aacEnc_ram.cpp
@@ -0,0 +1,132 @@
+/******************************************************************************
+
+ (C) Copyright Fraunhofer IIS (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.
+
+
+ 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:
+ Initial authors: M. Lohwasser, M. Gayer
+ Contents/description:
+
+******************************************************************************/
+/*!
+ \file
+ \brief Memory layout $Revision: 36838 $
+ \author Markus Lohwasser
+*/
+
+#include "aacEnc_ram.h"
+
+ C_ALLOC_MEM (AACdynamic_RAM, FIXP_DBL, AAC_ENC_DYN_RAM_SIZE/sizeof(FIXP_DBL))
+
+/*
+ Static memory areas, must not be overwritten in other sections of the decoder !
+*/
+
+/*
+ The structure AacEncoder contains all Encoder structures.
+*/
+
+C_ALLOC_MEM (Ram_aacEnc_AacEncoder, AAC_ENC, 1)
+
+
+/*
+ The structure PSY_INTERNAl contains all psych configuration and data pointer.
+ * PsyStatic holds last and current Psych data.
+ * PsyInputBuffer contains time input. Signal is needed at the beginning of Psych.
+ Memory can be reused after signal is in time domain.
+ * PsyData contains spectral, nrg and threshold information. Necessary data are
+ copied into PsyOut, so memory is available after leaving psych.
+ * TnsData, ChaosMeasure, PnsData are temporarily necessary, e.g. use memory from
+ PsyInputBuffer.
+*/
+
+C_ALLOC_MEM2 (Ram_aacEnc_PsyElement, PSY_ELEMENT, 1, (6))
+
+C_ALLOC_MEM (Ram_aacEnc_PsyInternal, PSY_INTERNAL, 1)
+C_ALLOC_MEM2 (Ram_aacEnc_PsyStatic, PSY_STATIC, 1, (6))
+
+C_ALLOC_MEM2 (Ram_aacEnc_PsyInputBuffer, INT_PCM, MAX_INPUT_BUFFER_SIZE, (6))
+
+ PSY_DYNAMIC *GetRam_aacEnc_PsyDynamic (int n, UCHAR* dynamic_RAM) {
+ FDK_ASSERT(dynamic_RAM!=0);
+ return ((PSY_DYNAMIC*) (dynamic_RAM + P_BUF_1 + n*sizeof(PSY_DYNAMIC)));
+ }
+
+ C_ALLOC_MEM (Ram_bsOutbuffer, UCHAR, OUTPUTBUFFER_SIZE)
+
+/*
+ The structure PSY_OUT holds all psychoaccoustic data needed
+ in quantization module
+*/
+C_ALLOC_MEM2 (Ram_aacEnc_PsyOut, PSY_OUT, 1, (1))
+
+C_ALLOC_MEM2 (Ram_aacEnc_PsyOutElements, PSY_OUT_ELEMENT, 1, (1)*(6))
+C_ALLOC_MEM2 (Ram_aacEnc_PsyOutChannel, PSY_OUT_CHANNEL, 1, (1)*(6))
+
+
+/*
+ The structure QC_STATE contains preinitialized settings and quantizer structures.
+ * AdjustThreshold structure contains element-wise settings.
+ * ElementBits contains elemnt-wise bit consumption settings.
+ * When CRC is active, lookup table is necessary for fast crc calculation.
+ * Bitcounter contains buffer to find optimal codebooks and minimal bit consumption.
+ Values are temporarily, so dynamic memory can be used.
+*/
+
+C_ALLOC_MEM (Ram_aacEnc_QCstate, QC_STATE, 1)
+C_ALLOC_MEM (Ram_aacEnc_AdjustThreshold, ADJ_THR_STATE, 1)
+
+C_ALLOC_MEM2 (Ram_aacEnc_AdjThrStateElement, ATS_ELEMENT, 1, (6))
+C_ALLOC_MEM2 (Ram_aacEnc_ElementBits, ELEMENT_BITS, 1, (6))
+C_ALLOC_MEM (Ram_aacEnc_BitCntrState, BITCNTR_STATE, 1)
+
+ INT *GetRam_aacEnc_BitLookUp(int n, UCHAR* dynamic_RAM) {
+ FDK_ASSERT(dynamic_RAM!=0);
+ return ((INT*) (dynamic_RAM + P_BUF_1));
+ }
+ INT *GetRam_aacEnc_MergeGainLookUp(int n, UCHAR* dynamic_RAM) {
+ FDK_ASSERT(dynamic_RAM!=0);
+ return ((INT*) (dynamic_RAM + P_BUF_1 + sizeof(INT)*(MAX_SFB_LONG*(CODE_BOOK_ESC_NDX+1))));
+ }
+
+
+/*
+ The structure QC_OUT contains settings and structures holding all necessary information
+ needed in bitstreamwriter.
+*/
+
+C_ALLOC_MEM2 (Ram_aacEnc_QCout, QC_OUT, 1, (1))
+C_ALLOC_MEM2 (Ram_aacEnc_QCelement, QC_OUT_ELEMENT, 1, (1)*(6))
+ QC_OUT_CHANNEL *GetRam_aacEnc_QCchannel (int n, UCHAR* dynamic_RAM) {
+ FDK_ASSERT(dynamic_RAM!=0);
+ return ((QC_OUT_CHANNEL*) (dynamic_RAM + P_BUF_0 + n*sizeof(QC_OUT_CHANNEL)));
+ }
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libAACenc/src/aacEnc_ram.h b/libAACenc/src/aacEnc_ram.h
new file mode 100644
index 0000000..1e87fc4
--- /dev/null
+++ b/libAACenc/src/aacEnc_ram.h
@@ -0,0 +1,163 @@
+/******************************************************************************
+
+ (C) Copyright Fraunhofer IIS (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.
+
+
+ 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:
+ Initial authors: M. Lohwasser, M. Gayer
+ Contents/description:
+
+******************************************************************************/
+/*!
+ \file
+ \brief Memory layout $Revision: 36838 $
+ \author Markus Lohwasser
+*/
+
+#ifndef AAC_ENC_RAM_H
+#define AAC_ENC_RAM_H
+
+#include "common_fix.h"
+
+#include "aacenc.h"
+#include "psy_data.h"
+#include "interface.h"
+#include "psy_main.h"
+#include "bitenc.h"
+#include "bit_cnt.h"
+#include "psy_const.h"
+
+ #define OUTPUTBUFFER_SIZE (8192) /*!< Output buffer size has to be at least 6144 bits per channel (768 bytes). FDK bitbuffer implementation expects buffer of size 2^n. */
+
+
+/*
+ Moved AAC_ENC struct definition from aac_enc.cpp into aacEnc_ram.h to get size and respective
+ static memory in aacEnc_ram.cpp.
+ aac_enc.h is the outward visible header file and putting the struct into would cause necessity
+ of additional visible header files outside library.
+*/
+
+/* define hBitstream size: max AAC framelength is 6144 bits/channel */
+/*#define BUFFER_BITSTR_SIZE ((6400*(6)/bbWordSize) +((bbWordSize - 1) / bbWordSize))*/
+
+struct AAC_ENC {
+
+ AACENC_CONFIG *config;
+
+ INT ancillaryBitsPerFrame; /* ancillary bits per frame calculated from ancillary rate */
+
+ CHANNEL_MAPPING channelMapping;
+
+ QC_STATE *qcKernel;
+ QC_OUT *qcOut[(1)];
+
+ PSY_OUT *psyOut[(1)];
+ PSY_INTERNAL *psyKernel;
+
+ /* lifetime vars */
+
+ CHANNEL_MODE encoderMode;
+ INT bandwidth90dB;
+ AACENC_BITRATE_MODE bitrateMode;
+
+ INT dontWriteAdif; /* use: write ADIF header only before 1st frame */
+
+ FIXP_DBL *dynamic_RAM;
+
+
+ INT maxChannels; /* used while allocation */
+ INT maxElements;
+ INT maxFrames;
+
+ AUDIO_OBJECT_TYPE aot; /* AOT to be used while encoding. */
+
+} ;
+
+#define maxSize(a,b) ( ((a)>(b)) ? (a) : (b) )
+
+#define BIT_LOOK_UP_SIZE ( sizeof(INT)*(MAX_SFB_LONG*(CODE_BOOK_ESC_NDX+1)) )
+#define MERGE_GAIN_LOOK_UP_SIZE ( sizeof(INT)*MAX_SFB_LONG )
+
+
+
+/* Dynamic RAM - Allocation */
+/*
+ ++++++++++++++++++++++++++++++++++++++++++++
+ | P_BUF_0 | P_BUF_1 |
+ ++++++++++++++++++++++++++++++++++++++++++++
+ | QC_OUT_CH | PSY_DYN |
+ ++++++++++++++++++++++++++++++++++++++++++++
+ | | BitLookUp+MergeGainLookUp |
+ ++++++++++++++++++++++++++++++++++++++++++++
+ | | Bitstream output buffer |
+ ++++++++++++++++++++++++++++++++++++++++++++
+*/
+
+#define BUF_SIZE_0 ( ALIGN_SIZE(sizeof(QC_OUT_CHANNEL)*(6)) )
+#define BUF_SIZE_1 ( ALIGN_SIZE(maxSize(sizeof(PSY_DYNAMIC), \
+ (BIT_LOOK_UP_SIZE+MERGE_GAIN_LOOK_UP_SIZE))) )
+
+#define P_BUF_0 ( 0 )
+#define P_BUF_1 ( P_BUF_0 + BUF_SIZE_0 )
+
+#define AAC_ENC_DYN_RAM_SIZE ( BUF_SIZE_0 + BUF_SIZE_1 )
+
+
+ H_ALLOC_MEM (AACdynamic_RAM, FIXP_DBL)
+/*
+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+END - Dynamic RAM - Allocation */
+
+/*
+ See further Memory Allocation details in aacEnc_ram.cpp
+*/
+ H_ALLOC_MEM (Ram_aacEnc_AacEncoder, AAC_ENC)
+
+ H_ALLOC_MEM (Ram_aacEnc_PsyElement, PSY_ELEMENT)
+
+ H_ALLOC_MEM (Ram_aacEnc_PsyInternal, PSY_INTERNAL)
+ H_ALLOC_MEM (Ram_aacEnc_PsyStatic, PSY_STATIC)
+ H_ALLOC_MEM (Ram_aacEnc_PsyInputBuffer, INT_PCM)
+
+ PSY_DYNAMIC *GetRam_aacEnc_PsyDynamic (int n, UCHAR* dynamic_RAM);
+ H_ALLOC_MEM (Ram_bsOutbuffer, UCHAR)
+
+ H_ALLOC_MEM (Ram_aacEnc_PsyOutChannel, PSY_OUT_CHANNEL)
+
+ H_ALLOC_MEM (Ram_aacEnc_PsyOut, PSY_OUT)
+ H_ALLOC_MEM (Ram_aacEnc_PsyOutElements, PSY_OUT_ELEMENT)
+
+ H_ALLOC_MEM (Ram_aacEnc_QCstate, QC_STATE)
+ H_ALLOC_MEM (Ram_aacEnc_AdjustThreshold, ADJ_THR_STATE)
+
+ H_ALLOC_MEM (Ram_aacEnc_AdjThrStateElement, ATS_ELEMENT)
+ H_ALLOC_MEM (Ram_aacEnc_ElementBits, ELEMENT_BITS)
+ H_ALLOC_MEM (Ram_aacEnc_BitCntrState, BITCNTR_STATE)
+
+ INT *GetRam_aacEnc_BitLookUp(int n, UCHAR* dynamic_RAM);
+ INT *GetRam_aacEnc_MergeGainLookUp(int n, UCHAR* dynamic_RAM);
+ QC_OUT_CHANNEL *GetRam_aacEnc_QCchannel (int n, UCHAR* dynamic_RAM);
+
+ H_ALLOC_MEM (Ram_aacEnc_QCout, QC_OUT)
+ H_ALLOC_MEM (Ram_aacEnc_QCelement, QC_OUT_ELEMENT)
+
+
+#endif /* #ifndef AAC_ENC_RAM_H */
+
diff --git a/libAACenc/src/aacEnc_rom.cpp b/libAACenc/src/aacEnc_rom.cpp
new file mode 100644
index 0000000..5349a43
--- /dev/null
+++ b/libAACenc/src/aacEnc_rom.cpp
@@ -0,0 +1,1170 @@
+/******************************************************************************
+
+ (C) copyright Fraunhofer-IIS (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. Lohwasser, M. Gayer
+ Contents/description:
+
+ 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 "aacEnc_rom.h"
+
+/*
+ Huffman Tables
+*/
+const INT FDKaacEnc_huff_ltab1_2[3][3][3][3]=
+{
+ {
+ { {0x000b0009,0x00090007,0x000b0009}, {0x000a0008,0x00070006,0x000a0008}, {0x000b0009,0x00090008,0x000b0009} },
+ { {0x000a0008,0x00070006,0x000a0007}, {0x00070006,0x00050005,0x00070006}, {0x00090007,0x00070006,0x000a0008} },
+ { {0x000b0009,0x00090007,0x000b0008}, {0x00090008,0x00070006,0x00090008}, {0x000b0009,0x00090007,0x000b0009} }
+ },
+ {
+ { {0x00090008,0x00070006,0x00090007}, {0x00070006,0x00050005,0x00070006}, {0x00090007,0x00070006,0x00090008} },
+ { {0x00070006,0x00050005,0x00070006}, {0x00050005,0x00010003,0x00050005}, {0x00070006,0x00050005,0x00070006} },
+ { {0x00090008,0x00070006,0x00090007}, {0x00070006,0x00050005,0x00070006}, {0x00090008,0x00070006,0x00090008} }
+ },
+ {
+ { {0x000b0009,0x00090007,0x000b0009}, {0x00090008,0x00070006,0x00090008}, {0x000b0008,0x00090007,0x000b0009} },
+ { {0x000a0008,0x00070006,0x00090007}, {0x00070006,0x00050004,0x00070006}, {0x00090008,0x00070006,0x000a0007} },
+ { {0x000b0009,0x00090007,0x000b0009}, {0x000a0007,0x00070006,0x00090008}, {0x000b0009,0x00090007,0x000b0009} }
+ }
+};
+
+
+const INT FDKaacEnc_huff_ltab3_4[3][3][3][3]=
+{
+ {
+ { {0x00010004,0x00040005,0x00080008}, {0x00040005,0x00050004,0x00080008}, {0x00090009,0x00090008,0x000a000b} },
+ { {0x00040005,0x00060005,0x00090008}, {0x00060005,0x00060004,0x00090008}, {0x00090008,0x00090007,0x000a000a} },
+ { {0x00090009,0x000a0008,0x000d000b}, {0x00090008,0x00090008,0x000b000a}, {0x000b000b,0x000a000a,0x000c000b} }
+ },
+ {
+ { {0x00040004,0x00060005,0x000a0008}, {0x00060004,0x00070004,0x000a0008}, {0x000a0008,0x000a0008,0x000c000a} },
+ { {0x00050004,0x00070004,0x000b0008}, {0x00060004,0x00070004,0x000a0007}, {0x00090008,0x00090007,0x000b0009} },
+ { {0x00090008,0x000a0008,0x000d000a}, {0x00080007,0x00090007,0x000c0009}, {0x000a000a,0x000b0009,0x000c000a} }
+ },
+ {
+ { {0x00080008,0x000a0008,0x000f000b}, {0x00090008,0x000b0007,0x000f000a}, {0x000d000b,0x000e000a,0x0010000c} },
+ { {0x00080008,0x000a0007,0x000e000a}, {0x00090007,0x000a0007,0x000e0009}, {0x000c000a,0x000c0009,0x000f000b} },
+ { {0x000b000b,0x000c000a,0x0010000c}, {0x000a000a,0x000b0009,0x000f000b}, {0x000c000b,0x000c000a,0x000f000b} }
+ }
+};
+
+const INT FDKaacEnc_huff_ltab5_6[9][9]=
+{
+ {0x000d000b, 0x000c000a, 0x000b0009, 0x000b0009, 0x000a0009, 0x000b0009, 0x000b0009, 0x000c000a, 0x000d000b},
+ {0x000c000a, 0x000b0009, 0x000a0008, 0x00090007, 0x00080007, 0x00090007, 0x000a0008, 0x000b0009, 0x000c000a},
+ {0x000c0009, 0x000a0008, 0x00090006, 0x00080006, 0x00070006, 0x00080006, 0x00090006, 0x000a0008, 0x000b0009},
+ {0x000b0009, 0x00090007, 0x00080006, 0x00050004, 0x00040004, 0x00050004, 0x00080006, 0x00090007, 0x000b0009},
+ {0x000a0009, 0x00080007, 0x00070006, 0x00040004, 0x00010004, 0x00040004, 0x00070006, 0x00080007, 0x000b0009},
+ {0x000b0009, 0x00090007, 0x00080006, 0x00050004, 0x00040004, 0x00050004, 0x00080006, 0x00090007, 0x000b0009},
+ {0x000b0009, 0x000a0008, 0x00090006, 0x00080006, 0x00070006, 0x00080006, 0x00090006, 0x000a0008, 0x000b0009},
+ {0x000c000a, 0x000b0009, 0x000a0008, 0x00090007, 0x00080007, 0x00090007, 0x000a0007, 0x000b0008, 0x000c000a},
+ {0x000d000b, 0x000c000a, 0x000c0009, 0x000b0009, 0x000a0009, 0x000a0009, 0x000b0009, 0x000c000a, 0x000d000b}
+};
+
+const INT FDKaacEnc_huff_ltab7_8[8][8]=
+{
+ {0x00010005, 0x00030004, 0x00060005, 0x00070006, 0x00080007, 0x00090008, 0x000a0009, 0x000b000a},
+ {0x00030004, 0x00040003, 0x00060004, 0x00070005, 0x00080006, 0x00080007, 0x00090007, 0x00090008},
+ {0x00060005, 0x00060004, 0x00070004, 0x00080005, 0x00080006, 0x00090007, 0x00090007, 0x000a0008},
+ {0x00070006, 0x00070005, 0x00080005, 0x00080006, 0x00090006, 0x00090007, 0x000a0008, 0x000a0008},
+ {0x00080007, 0x00080006, 0x00090006, 0x00090006, 0x000a0007, 0x000a0007, 0x000a0008, 0x000b0009},
+ {0x00090008, 0x00080007, 0x00090006, 0x00090007, 0x000a0007, 0x000a0008, 0x000b0008, 0x000b000a},
+ {0x000a0009, 0x00090007, 0x00090007, 0x000a0008, 0x000a0008, 0x000b0008, 0x000c0009, 0x000c0009},
+ {0x000b000a, 0x000a0008, 0x000a0008, 0x000a0008, 0x000b0009, 0x000b0009, 0x000c0009, 0x000c000a}
+};
+
+const INT FDKaacEnc_huff_ltab9_10[13][13]=
+{
+ {0x00010006, 0x00030005, 0x00060006, 0x00080006, 0x00090007, 0x000a0008, 0x000a0009, 0x000b000a, 0x000b000a, 0x000c000a, 0x000c000b, 0x000d000b, 0x000d000c},
+ {0x00030005, 0x00040004, 0x00060004, 0x00070005, 0x00080006, 0x00080007, 0x00090007, 0x000a0008, 0x000a0008, 0x000a0009, 0x000b000a, 0x000c000a, 0x000c000b},
+ {0x00060006, 0x00060004, 0x00070005, 0x00080005, 0x00080006, 0x00090006, 0x000a0007, 0x000a0008, 0x000a0008, 0x000b0009, 0x000c0009, 0x000c000a, 0x000c000a},
+ {0x00080006, 0x00070005, 0x00080005, 0x00090005, 0x00090006, 0x000a0007, 0x000a0007, 0x000b0008, 0x000b0008, 0x000b0009, 0x000c0009, 0x000c000a, 0x000d000a},
+ {0x00090007, 0x00080006, 0x00090006, 0x00090006, 0x000a0006, 0x000a0007, 0x000b0007, 0x000b0008, 0x000b0008, 0x000c0009, 0x000c0009, 0x000c000a, 0x000d000a},
+ {0x000a0008, 0x00090007, 0x00090006, 0x000a0007, 0x000b0007, 0x000b0007, 0x000b0008, 0x000c0008, 0x000b0008, 0x000c0009, 0x000c000a, 0x000d000a, 0x000d000b},
+ {0x000b0009, 0x00090007, 0x000a0007, 0x000b0007, 0x000b0007, 0x000b0008, 0x000c0008, 0x000c0009, 0x000c0009, 0x000c0009, 0x000d000a, 0x000d000a, 0x000d000b},
+ {0x000b0009, 0x000a0008, 0x000a0008, 0x000b0008, 0x000b0008, 0x000c0008, 0x000c0009, 0x000d0009, 0x000d0009, 0x000d000a, 0x000d000a, 0x000d000b, 0x000d000b},
+ {0x000b0009, 0x000a0008, 0x000a0008, 0x000b0008, 0x000b0008, 0x000b0008, 0x000c0009, 0x000c0009, 0x000d000a, 0x000d000a, 0x000e000a, 0x000d000b, 0x000e000b},
+ {0x000b000a, 0x000a0009, 0x000b0009, 0x000b0009, 0x000c0009, 0x000c0009, 0x000c0009, 0x000c000a, 0x000d000a, 0x000d000a, 0x000e000b, 0x000e000b, 0x000e000c},
+ {0x000c000a, 0x000b0009, 0x000b0009, 0x000c0009, 0x000c0009, 0x000c000a, 0x000d000a, 0x000d000a, 0x000d000a, 0x000e000b, 0x000e000b, 0x000e000b, 0x000f000c},
+ {0x000c000b, 0x000b000a, 0x000c0009, 0x000c000a, 0x000c000a, 0x000d000a, 0x000d000a, 0x000d000a, 0x000d000b, 0x000e000b, 0x000e000b, 0x000f000b, 0x000f000c},
+ {0x000d000b, 0x000c000a, 0x000c000a, 0x000c000a, 0x000d000a, 0x000d000a, 0x000d000a, 0x000d000b, 0x000e000b, 0x000e000c, 0x000e000c, 0x000e000c, 0x000f000c}
+};
+
+const UCHAR FDKaacEnc_huff_ltab11[17][17]=
+{
+ {0x04, 0x05, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0b, 0x0c, 0x0c, 0x0a},
+ {0x05, 0x04, 0x05, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x08},
+ {0x06, 0x05, 0x05, 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x08},
+ {0x07, 0x06, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x08},
+ {0x08, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x08},
+ {0x08, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x08},
+ {0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x08},
+ {0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x08},
+ {0x0a, 0x09, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x08},
+ {0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x08},
+ {0x0b, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0a, 0x0b, 0x0b, 0x08},
+ {0x0b, 0x0a, 0x09, 0x09, 0x0a, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x08},
+ {0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x09},
+ {0x0b, 0x0a, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x09},
+ {0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x09},
+ {0x0c, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x09},
+ {0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x05}
+};
+
+const UCHAR FDKaacEnc_huff_ltabscf[121]=
+{
+ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
+ 0x13, 0x13, 0x13, 0x12, 0x13, 0x12, 0x11, 0x11, 0x10, 0x11, 0x10, 0x10, 0x10, 0x10, 0x0f, 0x0f,
+ 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0c, 0x0b, 0x0a, 0x0a,
+ 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x01, 0x04, 0x04, 0x05,
+ 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c,
+ 0x0c, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x10, 0x0f, 0x10, 0x0f, 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, 0x13, 0x13
+};
+
+
+const USHORT FDKaacEnc_huff_ctab1[3][3][3][3]=
+{
+ {
+ { {0x07f8,0x01f1,0x07fd}, {0x03f5,0x0068,0x03f0}, {0x07f7,0x01ec,0x07f5} },
+ { {0x03f1,0x0072,0x03f4}, {0x0074,0x0011,0x0076}, {0x01eb,0x006c,0x03f6} },
+ { {0x07fc,0x01e1,0x07f1}, {0x01f0,0x0061,0x01f6}, {0x07f2,0x01ea,0x07fb} }
+ },
+ {
+ { {0x01f2,0x0069,0x01ed}, {0x0077,0x0017,0x006f}, {0x01e6,0x0064,0x01e5} },
+ { {0x0067,0x0015,0x0062}, {0x0012,0x0000,0x0014}, {0x0065,0x0016,0x006d} },
+ { {0x01e9,0x0063,0x01e4}, {0x006b,0x0013,0x0071}, {0x01e3,0x0070,0x01f3} }
+ },
+ {
+ { {0x07fe,0x01e7,0x07f3}, {0x01ef,0x0060,0x01ee}, {0x07f0,0x01e2,0x07fa} },
+ { {0x03f3,0x006a,0x01e8}, {0x0075,0x0010,0x0073}, {0x01f4,0x006e,0x03f7} },
+ { {0x07f6,0x01e0,0x07f9}, {0x03f2,0x0066,0x01f5}, {0x07ff,0x01f7,0x07f4} }
+ }
+};
+
+const USHORT FDKaacEnc_huff_ctab2[3][3][3][3]=
+{
+ {
+ { {0x01f3,0x006f,0x01fd}, {0x00eb,0x0023,0x00ea}, {0x01f7,0x00e8,0x01fa} },
+ { {0x00f2,0x002d,0x0070}, {0x0020,0x0006,0x002b}, {0x006e,0x0028,0x00e9} },
+ { {0x01f9,0x0066,0x00f8}, {0x00e7,0x001b,0x00f1}, {0x01f4,0x006b,0x01f5} }
+ },
+ {
+ { {0x00ec,0x002a,0x006c}, {0x002c,0x000a,0x0027}, {0x0067,0x001a,0x00f5} },
+ { {0x0024,0x0008,0x001f}, {0x0009,0x0000,0x0007}, {0x001d,0x000b,0x0030} },
+ { {0x00ef,0x001c,0x0064}, {0x001e,0x000c,0x0029}, {0x00f3,0x002f,0x00f0} }
+ },
+ {
+ { {0x01fc,0x0071,0x01f2}, {0x00f4,0x0021,0x00e6}, {0x00f7,0x0068,0x01f8} },
+ { {0x00ee,0x0022,0x0065}, {0x0031,0x0002,0x0026}, {0x00ed,0x0025,0x006a} },
+ { {0x01fb,0x0072,0x01fe}, {0x0069,0x002e,0x00f6}, {0x01ff,0x006d,0x01f6} }
+ }
+};
+
+const USHORT FDKaacEnc_huff_ctab3[3][3][3][3]=
+{
+ {
+ { {0x0000,0x0009,0x00ef}, {0x000b,0x0019,0x00f0}, {0x01eb,0x01e6,0x03f2} },
+ { {0x000a,0x0035,0x01ef}, {0x0034,0x0037,0x01e9}, {0x01ed,0x01e7,0x03f3} },
+ { {0x01ee,0x03ed,0x1ffa}, {0x01ec,0x01f2,0x07f9}, {0x07f8,0x03f8,0x0ff8} }
+ },
+ {
+ { {0x0008,0x0038,0x03f6}, {0x0036,0x0075,0x03f1}, {0x03eb,0x03ec,0x0ff4} },
+ { {0x0018,0x0076,0x07f4}, {0x0039,0x0074,0x03ef}, {0x01f3,0x01f4,0x07f6} },
+ { {0x01e8,0x03ea,0x1ffc}, {0x00f2,0x01f1,0x0ffb}, {0x03f5,0x07f3,0x0ffc} }
+ },
+ {
+ { {0x00ee,0x03f7,0x7ffe}, {0x01f0,0x07f5,0x7ffd}, {0x1ffb,0x3ffa,0xffff} },
+ { {0x00f1,0x03f0,0x3ffc}, {0x01ea,0x03ee,0x3ffb}, {0x0ff6,0x0ffa,0x7ffc} },
+ { {0x07f2,0x0ff5,0xfffe}, {0x03f4,0x07f7,0x7ffb}, {0x0ff7,0x0ff9,0x7ffa} }
+ }
+};
+
+const USHORT FDKaacEnc_huff_ctab4[3][3][3][3]=
+{
+ {
+ { {0x0007,0x0016,0x00f6}, {0x0018,0x0008,0x00ef}, {0x01ef,0x00f3,0x07f8} },
+ { {0x0019,0x0017,0x00ed}, {0x0015,0x0001,0x00e2}, {0x00f0,0x0070,0x03f0} },
+ { {0x01ee,0x00f1,0x07fa}, {0x00ee,0x00e4,0x03f2}, {0x07f6,0x03ef,0x07fd} }
+ },
+ {
+ { {0x0005,0x0014,0x00f2}, {0x0009,0x0004,0x00e5}, {0x00f4,0x00e8,0x03f4} },
+ { {0x0006,0x0002,0x00e7}, {0x0003,0x0000,0x006b}, {0x00e3,0x0069,0x01f3} },
+ { {0x00eb,0x00e6,0x03f6}, {0x006e,0x006a,0x01f4}, {0x03ec,0x01f0,0x03f9} }
+ },
+ {
+ { {0x00f5,0x00ec,0x07fb}, {0x00ea,0x006f,0x03f7}, {0x07f9,0x03f3,0x0fff} },
+ { {0x00e9,0x006d,0x03f8}, {0x006c,0x0068,0x01f5}, {0x03ee,0x01f2,0x07f4} },
+ { {0x07f7,0x03f1,0x0ffe}, {0x03ed,0x01f1,0x07f5}, {0x07fe,0x03f5,0x07fc} }
+ }
+};
+const USHORT FDKaacEnc_huff_ctab5[9][9]=
+{
+ {0x1fff, 0x0ff7, 0x07f4, 0x07e8, 0x03f1, 0x07ee, 0x07f9, 0x0ff8, 0x1ffd},
+ {0x0ffd, 0x07f1, 0x03e8, 0x01e8, 0x00f0, 0x01ec, 0x03ee, 0x07f2, 0x0ffa},
+ {0x0ff4, 0x03ef, 0x01f2, 0x00e8, 0x0070, 0x00ec, 0x01f0, 0x03ea, 0x07f3},
+ {0x07eb, 0x01eb, 0x00ea, 0x001a, 0x0008, 0x0019, 0x00ee, 0x01ef, 0x07ed},
+ {0x03f0, 0x00f2, 0x0073, 0x000b, 0x0000, 0x000a, 0x0071, 0x00f3, 0x07e9},
+ {0x07ef, 0x01ee, 0x00ef, 0x0018, 0x0009, 0x001b, 0x00eb, 0x01e9, 0x07ec},
+ {0x07f6, 0x03eb, 0x01f3, 0x00ed, 0x0072, 0x00e9, 0x01f1, 0x03ed, 0x07f7},
+ {0x0ff6, 0x07f0, 0x03e9, 0x01ed, 0x00f1, 0x01ea, 0x03ec, 0x07f8, 0x0ff9},
+ {0x1ffc, 0x0ffc, 0x0ff5, 0x07ea, 0x03f3, 0x03f2, 0x07f5, 0x0ffb, 0x1ffe}
+};
+
+const USHORT FDKaacEnc_huff_ctab6[9][9]=
+{
+ {0x07fe, 0x03fd, 0x01f1, 0x01eb, 0x01f4, 0x01ea, 0x01f0, 0x03fc, 0x07fd},
+ {0x03f6, 0x01e5, 0x00ea, 0x006c, 0x0071, 0x0068, 0x00f0, 0x01e6, 0x03f7},
+ {0x01f3, 0x00ef, 0x0032, 0x0027, 0x0028, 0x0026, 0x0031, 0x00eb, 0x01f7},
+ {0x01e8, 0x006f, 0x002e, 0x0008, 0x0004, 0x0006, 0x0029, 0x006b, 0x01ee},
+ {0x01ef, 0x0072, 0x002d, 0x0002, 0x0000, 0x0003, 0x002f, 0x0073, 0x01fa},
+ {0x01e7, 0x006e, 0x002b, 0x0007, 0x0001, 0x0005, 0x002c, 0x006d, 0x01ec},
+ {0x01f9, 0x00ee, 0x0030, 0x0024, 0x002a, 0x0025, 0x0033, 0x00ec, 0x01f2},
+ {0x03f8, 0x01e4, 0x00ed, 0x006a, 0x0070, 0x0069, 0x0074, 0x00f1, 0x03fa},
+ {0x07ff, 0x03f9, 0x01f6, 0x01ed, 0x01f8, 0x01e9, 0x01f5, 0x03fb, 0x07fc}
+};
+
+const USHORT FDKaacEnc_huff_ctab7[8][8]=
+{
+ {0x0000, 0x0005, 0x0037, 0x0074, 0x00f2, 0x01eb, 0x03ed, 0x07f7},
+ {0x0004, 0x000c, 0x0035, 0x0071, 0x00ec, 0x00ee, 0x01ee, 0x01f5},
+ {0x0036, 0x0034, 0x0072, 0x00ea, 0x00f1, 0x01e9, 0x01f3, 0x03f5},
+ {0x0073, 0x0070, 0x00eb, 0x00f0, 0x01f1, 0x01f0, 0x03ec, 0x03fa},
+ {0x00f3, 0x00ed, 0x01e8, 0x01ef, 0x03ef, 0x03f1, 0x03f9, 0x07fb},
+ {0x01ed, 0x00ef, 0x01ea, 0x01f2, 0x03f3, 0x03f8, 0x07f9, 0x07fc},
+ {0x03ee, 0x01ec, 0x01f4, 0x03f4, 0x03f7, 0x07f8, 0x0ffd, 0x0ffe},
+ {0x07f6, 0x03f0, 0x03f2, 0x03f6, 0x07fa, 0x07fd, 0x0ffc, 0x0fff}
+};
+
+const USHORT FDKaacEnc_huff_ctab8[8][8]=
+{
+ {0x000e, 0x0005, 0x0010, 0x0030, 0x006f, 0x00f1, 0x01fa, 0x03fe},
+ {0x0003, 0x0000, 0x0004, 0x0012, 0x002c, 0x006a, 0x0075, 0x00f8},
+ {0x000f, 0x0002, 0x0006, 0x0014, 0x002e, 0x0069, 0x0072, 0x00f5},
+ {0x002f, 0x0011, 0x0013, 0x002a, 0x0032, 0x006c, 0x00ec, 0x00fa},
+ {0x0071, 0x002b, 0x002d, 0x0031, 0x006d, 0x0070, 0x00f2, 0x01f9},
+ {0x00ef, 0x0068, 0x0033, 0x006b, 0x006e, 0x00ee, 0x00f9, 0x03fc},
+ {0x01f8, 0x0074, 0x0073, 0x00ed, 0x00f0, 0x00f6, 0x01f6, 0x01fd},
+ {0x03fd, 0x00f3, 0x00f4, 0x00f7, 0x01f7, 0x01fb, 0x01fc, 0x03ff}
+};
+
+const USHORT FDKaacEnc_huff_ctab9[13][13]=
+{
+ {0x0000, 0x0005, 0x0037, 0x00e7, 0x01de, 0x03ce, 0x03d9, 0x07c8, 0x07cd, 0x0fc8, 0x0fdd, 0x1fe4, 0x1fec},
+ {0x0004, 0x000c, 0x0035, 0x0072, 0x00ea, 0x00ed, 0x01e2, 0x03d1, 0x03d3, 0x03e0, 0x07d8, 0x0fcf, 0x0fd5},
+ {0x0036, 0x0034, 0x0071, 0x00e8, 0x00ec, 0x01e1, 0x03cf, 0x03dd, 0x03db, 0x07d0, 0x0fc7, 0x0fd4, 0x0fe4},
+ {0x00e6, 0x0070, 0x00e9, 0x01dd, 0x01e3, 0x03d2, 0x03dc, 0x07cc, 0x07ca, 0x07de, 0x0fd8, 0x0fea, 0x1fdb},
+ {0x01df, 0x00eb, 0x01dc, 0x01e6, 0x03d5, 0x03de, 0x07cb, 0x07dd, 0x07dc, 0x0fcd, 0x0fe2, 0x0fe7, 0x1fe1},
+ {0x03d0, 0x01e0, 0x01e4, 0x03d6, 0x07c5, 0x07d1, 0x07db, 0x0fd2, 0x07e0, 0x0fd9, 0x0feb, 0x1fe3, 0x1fe9},
+ {0x07c4, 0x01e5, 0x03d7, 0x07c6, 0x07cf, 0x07da, 0x0fcb, 0x0fda, 0x0fe3, 0x0fe9, 0x1fe6, 0x1ff3, 0x1ff7},
+ {0x07d3, 0x03d8, 0x03e1, 0x07d4, 0x07d9, 0x0fd3, 0x0fde, 0x1fdd, 0x1fd9, 0x1fe2, 0x1fea, 0x1ff1, 0x1ff6},
+ {0x07d2, 0x03d4, 0x03da, 0x07c7, 0x07d7, 0x07e2, 0x0fce, 0x0fdb, 0x1fd8, 0x1fee, 0x3ff0, 0x1ff4, 0x3ff2},
+ {0x07e1, 0x03df, 0x07c9, 0x07d6, 0x0fca, 0x0fd0, 0x0fe5, 0x0fe6, 0x1feb, 0x1fef, 0x3ff3, 0x3ff4, 0x3ff5},
+ {0x0fe0, 0x07ce, 0x07d5, 0x0fc6, 0x0fd1, 0x0fe1, 0x1fe0, 0x1fe8, 0x1ff0, 0x3ff1, 0x3ff8, 0x3ff6, 0x7ffc},
+ {0x0fe8, 0x07df, 0x0fc9, 0x0fd7, 0x0fdc, 0x1fdc, 0x1fdf, 0x1fed, 0x1ff5, 0x3ff9, 0x3ffb, 0x7ffd, 0x7ffe},
+ {0x1fe7, 0x0fcc, 0x0fd6, 0x0fdf, 0x1fde, 0x1fda, 0x1fe5, 0x1ff2, 0x3ffa, 0x3ff7, 0x3ffc, 0x3ffd, 0x7fff}
+};
+
+const USHORT FDKaacEnc_huff_ctab10[13][13]=
+{
+ {0x0022, 0x0008, 0x001d, 0x0026, 0x005f, 0x00d3, 0x01cf, 0x03d0, 0x03d7, 0x03ed, 0x07f0, 0x07f6, 0x0ffd},
+ {0x0007, 0x0000, 0x0001, 0x0009, 0x0020, 0x0054, 0x0060, 0x00d5, 0x00dc, 0x01d4, 0x03cd, 0x03de, 0x07e7},
+ {0x001c, 0x0002, 0x0006, 0x000c, 0x001e, 0x0028, 0x005b, 0x00cd, 0x00d9, 0x01ce, 0x01dc, 0x03d9, 0x03f1},
+ {0x0025, 0x000b, 0x000a, 0x000d, 0x0024, 0x0057, 0x0061, 0x00cc, 0x00dd, 0x01cc, 0x01de, 0x03d3, 0x03e7},
+ {0x005d, 0x0021, 0x001f, 0x0023, 0x0027, 0x0059, 0x0064, 0x00d8, 0x00df, 0x01d2, 0x01e2, 0x03dd, 0x03ee},
+ {0x00d1, 0x0055, 0x0029, 0x0056, 0x0058, 0x0062, 0x00ce, 0x00e0, 0x00e2, 0x01da, 0x03d4, 0x03e3, 0x07eb},
+ {0x01c9, 0x005e, 0x005a, 0x005c, 0x0063, 0x00ca, 0x00da, 0x01c7, 0x01ca, 0x01e0, 0x03db, 0x03e8, 0x07ec},
+ {0x01e3, 0x00d2, 0x00cb, 0x00d0, 0x00d7, 0x00db, 0x01c6, 0x01d5, 0x01d8, 0x03ca, 0x03da, 0x07ea, 0x07f1},
+ {0x01e1, 0x00d4, 0x00cf, 0x00d6, 0x00de, 0x00e1, 0x01d0, 0x01d6, 0x03d1, 0x03d5, 0x03f2, 0x07ee, 0x07fb},
+ {0x03e9, 0x01cd, 0x01c8, 0x01cb, 0x01d1, 0x01d7, 0x01df, 0x03cf, 0x03e0, 0x03ef, 0x07e6, 0x07f8, 0x0ffa},
+ {0x03eb, 0x01dd, 0x01d3, 0x01d9, 0x01db, 0x03d2, 0x03cc, 0x03dc, 0x03ea, 0x07ed, 0x07f3, 0x07f9, 0x0ff9},
+ {0x07f2, 0x03ce, 0x01e4, 0x03cb, 0x03d8, 0x03d6, 0x03e2, 0x03e5, 0x07e8, 0x07f4, 0x07f5, 0x07f7, 0x0ffb},
+ {0x07fa, 0x03ec, 0x03df, 0x03e1, 0x03e4, 0x03e6, 0x03f0, 0x07e9, 0x07ef, 0x0ff8, 0x0ffe, 0x0ffc, 0x0fff}
+};
+
+const USHORT FDKaacEnc_huff_ctab11[21][17]=
+{
+ {0x0000, 0x0006, 0x0019, 0x003d, 0x009c, 0x00c6, 0x01a7, 0x0390, 0x03c2, 0x03df, 0x07e6, 0x07f3, 0x0ffb, 0x07ec, 0x0ffa, 0x0ffe, 0x038e},
+ {0x0005, 0x0001, 0x0008, 0x0014, 0x0037, 0x0042, 0x0092, 0x00af, 0x0191, 0x01a5, 0x01b5, 0x039e, 0x03c0, 0x03a2, 0x03cd, 0x07d6, 0x00ae},
+ {0x0017, 0x0007, 0x0009, 0x0018, 0x0039, 0x0040, 0x008e, 0x00a3, 0x00b8, 0x0199, 0x01ac, 0x01c1, 0x03b1, 0x0396, 0x03be, 0x03ca, 0x009d},
+ {0x003c, 0x0015, 0x0016, 0x001a, 0x003b, 0x0044, 0x0091, 0x00a5, 0x00be, 0x0196, 0x01ae, 0x01b9, 0x03a1, 0x0391, 0x03a5, 0x03d5, 0x0094},
+ {0x009a, 0x0036, 0x0038, 0x003a, 0x0041, 0x008c, 0x009b, 0x00b0, 0x00c3, 0x019e, 0x01ab, 0x01bc, 0x039f, 0x038f, 0x03a9, 0x03cf, 0x0093},
+ {0x00bf, 0x003e, 0x003f, 0x0043, 0x0045, 0x009e, 0x00a7, 0x00b9, 0x0194, 0x01a2, 0x01ba, 0x01c3, 0x03a6, 0x03a7, 0x03bb, 0x03d4, 0x009f},
+ {0x01a0, 0x008f, 0x008d, 0x0090, 0x0098, 0x00a6, 0x00b6, 0x00c4, 0x019f, 0x01af, 0x01bf, 0x0399, 0x03bf, 0x03b4, 0x03c9, 0x03e7, 0x00a8},
+ {0x01b6, 0x00ab, 0x00a4, 0x00aa, 0x00b2, 0x00c2, 0x00c5, 0x0198, 0x01a4, 0x01b8, 0x038c, 0x03a4, 0x03c4, 0x03c6, 0x03dd, 0x03e8, 0x00ad},
+ {0x03af, 0x0192, 0x00bd, 0x00bc, 0x018e, 0x0197, 0x019a, 0x01a3, 0x01b1, 0x038d, 0x0398, 0x03b7, 0x03d3, 0x03d1, 0x03db, 0x07dd, 0x00b4},
+ {0x03de, 0x01a9, 0x019b, 0x019c, 0x01a1, 0x01aa, 0x01ad, 0x01b3, 0x038b, 0x03b2, 0x03b8, 0x03ce, 0x03e1, 0x03e0, 0x07d2, 0x07e5, 0x00b7},
+ {0x07e3, 0x01bb, 0x01a8, 0x01a6, 0x01b0, 0x01b2, 0x01b7, 0x039b, 0x039a, 0x03ba, 0x03b5, 0x03d6, 0x07d7, 0x03e4, 0x07d8, 0x07ea, 0x00ba},
+ {0x07e8, 0x03a0, 0x01bd, 0x01b4, 0x038a, 0x01c4, 0x0392, 0x03aa, 0x03b0, 0x03bc, 0x03d7, 0x07d4, 0x07dc, 0x07db, 0x07d5, 0x07f0, 0x00c1},
+ {0x07fb, 0x03c8, 0x03a3, 0x0395, 0x039d, 0x03ac, 0x03ae, 0x03c5, 0x03d8, 0x03e2, 0x03e6, 0x07e4, 0x07e7, 0x07e0, 0x07e9, 0x07f7, 0x0190},
+ {0x07f2, 0x0393, 0x01be, 0x01c0, 0x0394, 0x0397, 0x03ad, 0x03c3, 0x03c1, 0x03d2, 0x07da, 0x07d9, 0x07df, 0x07eb, 0x07f4, 0x07fa, 0x0195},
+ {0x07f8, 0x03bd, 0x039c, 0x03ab, 0x03a8, 0x03b3, 0x03b9, 0x03d0, 0x03e3, 0x03e5, 0x07e2, 0x07de, 0x07ed, 0x07f1, 0x07f9, 0x07fc, 0x0193},
+ {0x0ffd, 0x03dc, 0x03b6, 0x03c7, 0x03cc, 0x03cb, 0x03d9, 0x03da, 0x07d3, 0x07e1, 0x07ee, 0x07ef, 0x07f5, 0x07f6, 0x0ffc, 0x0fff, 0x019d},
+ {0x01c2, 0x00b5, 0x00a1, 0x0096, 0x0097, 0x0095, 0x0099, 0x00a0, 0x00a2, 0x00ac, 0x00a9, 0x00b1, 0x00b3, 0x00bb, 0x00c0, 0x018f, 0x0004},
+ {0x0018, 0x002e, 0x0000, 0x005a, 0x00a5, 0x00f8, 0x00b7, 0x0094, 0x00f9, 0x004d, 0x0021, 0x002b, 0x004f, 0x007b, 0x00bc, 0x0046, 0x0015},
+ {0x0042, 0x0037, 0x0078, 0x000d, 0x0068, 0x005f, 0x000d, 0x005e, 0x005a, 0x00be, 0x0063, 0x007e, 0x001f, 0x0092, 0x001a, 0x00ab, 0x0032},
+ {0x00e6, 0x0037, 0x0000, 0x0058, 0x000b, 0x005a, 0x00e1, 0x005d, 0x0029, 0x0017, 0x007e, 0x0069, 0x00aa, 0x0054, 0x0029, 0x0032, 0x0041},
+ {0x0046, 0x00ea, 0x0034, 0x00ea, 0x0011, 0x001b, 0x00a9, 0x0094, 0x00e2, 0x0031, 0x00d0, 0x00e5, 0x0007, 0x0070, 0x0069, 0x003e, 0x0021}
+};
+
+const INT FDKaacEnc_huff_ctabscf[121]=
+{
+ 0x0003ffe8, 0x0003ffe6, 0x0003ffe7, 0x0003ffe5, 0x0007fff5, 0x0007fff1, 0x0007ffed, 0x0007fff6,
+ 0x0007ffee, 0x0007ffef, 0x0007fff0, 0x0007fffc, 0x0007fffd, 0x0007ffff, 0x0007fffe, 0x0007fff7,
+ 0x0007fff8, 0x0007fffb, 0x0007fff9, 0x0003ffe4, 0x0007fffa, 0x0003ffe3, 0x0001ffef, 0x0001fff0,
+ 0x0000fff5, 0x0001ffee, 0x0000fff2, 0x0000fff3, 0x0000fff4, 0x0000fff1, 0x00007ff6, 0x00007ff7,
+ 0x00003ff9, 0x00003ff5, 0x00003ff7, 0x00003ff3, 0x00003ff6, 0x00003ff2, 0x00001ff7, 0x00001ff5,
+ 0x00000ff9, 0x00000ff7, 0x00000ff6, 0x000007f9, 0x00000ff4, 0x000007f8, 0x000003f9, 0x000003f7,
+ 0x000003f5, 0x000001f8, 0x000001f7, 0x000000fa, 0x000000f8, 0x000000f6, 0x00000079, 0x0000003a,
+ 0x00000038, 0x0000001a, 0x0000000b, 0x00000004, 0x00000000, 0x0000000a, 0x0000000c, 0x0000001b,
+ 0x00000039, 0x0000003b, 0x00000078, 0x0000007a, 0x000000f7, 0x000000f9, 0x000001f6, 0x000001f9,
+ 0x000003f4, 0x000003f6, 0x000003f8, 0x000007f5, 0x000007f4, 0x000007f6, 0x000007f7, 0x00000ff5,
+ 0x00000ff8, 0x00001ff4, 0x00001ff6, 0x00001ff8, 0x00003ff8, 0x00003ff4, 0x0000fff0, 0x00007ff4,
+ 0x0000fff6, 0x00007ff5, 0x0003ffe2, 0x0007ffd9, 0x0007ffda, 0x0007ffdb, 0x0007ffdc, 0x0007ffdd,
+ 0x0007ffde, 0x0007ffd8, 0x0007ffd2, 0x0007ffd3, 0x0007ffd4, 0x0007ffd5, 0x0007ffd6, 0x0007fff2,
+ 0x0007ffdf, 0x0007ffe7, 0x0007ffe8, 0x0007ffe9, 0x0007ffea, 0x0007ffeb, 0x0007ffe6, 0x0007ffe0,
+ 0x0007ffe1, 0x0007ffe2, 0x0007ffe3, 0x0007ffe4, 0x0007ffe5, 0x0007ffd7, 0x0007ffec, 0x0007fff4,
+ 0x0007fff3
+};
+
+/*
+ table of (0.50000...1.00000) ^0.75
+*/
+const FIXP_QTD FDKaacEnc_mTab_3_4[MANT_SIZE] =
+{
+ QTC(0x4c1bf829), QTC(0x4c3880de), QTC(0x4c550603), QTC(0x4c71879c), QTC(0x4c8e05aa), QTC(0x4caa8030), QTC(0x4cc6f72f), QTC(0x4ce36aab),
+ QTC(0x4cffdaa4), QTC(0x4d1c471d), QTC(0x4d38b019), QTC(0x4d55159a), QTC(0x4d7177a1), QTC(0x4d8dd631), QTC(0x4daa314b), QTC(0x4dc688f3),
+ QTC(0x4de2dd2a), QTC(0x4dff2df2), QTC(0x4e1b7b4d), QTC(0x4e37c53d), QTC(0x4e540bc5), QTC(0x4e704ee6), QTC(0x4e8c8ea3), QTC(0x4ea8cafd),
+ QTC(0x4ec503f7), QTC(0x4ee13992), QTC(0x4efd6bd0), QTC(0x4f199ab4), QTC(0x4f35c640), QTC(0x4f51ee75), QTC(0x4f6e1356), QTC(0x4f8a34e4),
+ QTC(0x4fa65321), QTC(0x4fc26e10), QTC(0x4fde85b2), QTC(0x4ffa9a0a), QTC(0x5016ab18), QTC(0x5032b8e0), QTC(0x504ec362), QTC(0x506acaa1),
+ QTC(0x5086cea0), QTC(0x50a2cf5e), QTC(0x50becce0), QTC(0x50dac725), QTC(0x50f6be31), QTC(0x5112b205), QTC(0x512ea2a3), QTC(0x514a900d),
+ QTC(0x51667a45), QTC(0x5182614c), QTC(0x519e4524), QTC(0x51ba25cf), QTC(0x51d60350), QTC(0x51f1dda7), QTC(0x520db4d6), QTC(0x522988e0),
+ QTC(0x524559c6), QTC(0x52612789), QTC(0x527cf22d), QTC(0x5298b9b1), QTC(0x52b47e19), QTC(0x52d03f65), QTC(0x52ebfd98), QTC(0x5307b8b4),
+ QTC(0x532370b9), QTC(0x533f25aa), QTC(0x535ad789), QTC(0x53768656), QTC(0x53923215), QTC(0x53addac6), QTC(0x53c9806b), QTC(0x53e52306),
+ QTC(0x5400c298), QTC(0x541c5f24), QTC(0x5437f8ab), QTC(0x54538f2e), QTC(0x546f22af), QTC(0x548ab330), QTC(0x54a640b3), QTC(0x54c1cb38),
+ QTC(0x54dd52c2), QTC(0x54f8d753), QTC(0x551458eb), QTC(0x552fd78d), QTC(0x554b5339), QTC(0x5566cbf3), QTC(0x558241bb), QTC(0x559db492),
+ QTC(0x55b9247b), QTC(0x55d49177), QTC(0x55effb87), QTC(0x560b62ad), QTC(0x5626c6eb), QTC(0x56422842), QTC(0x565d86b4), QTC(0x5678e242),
+ QTC(0x56943aee), QTC(0x56af90b9), QTC(0x56cae3a4), QTC(0x56e633b2), QTC(0x570180e4), QTC(0x571ccb3b), QTC(0x573812b8), QTC(0x5753575e),
+ QTC(0x576e992e), QTC(0x5789d829), QTC(0x57a51450), QTC(0x57c04da6), QTC(0x57db842b), QTC(0x57f6b7e1), QTC(0x5811e8c9), QTC(0x582d16e6),
+ QTC(0x58484238), QTC(0x58636ac0), QTC(0x587e9081), QTC(0x5899b37c), QTC(0x58b4d3b1), QTC(0x58cff123), QTC(0x58eb0bd3), QTC(0x590623c2),
+ QTC(0x592138f2), QTC(0x593c4b63), QTC(0x59575b19), QTC(0x59726812), QTC(0x598d7253), QTC(0x59a879da), QTC(0x59c37eab), QTC(0x59de80c6),
+ QTC(0x59f9802d), QTC(0x5a147ce0), QTC(0x5a2f76e2), QTC(0x5a4a6e34), QTC(0x5a6562d6), QTC(0x5a8054cb), QTC(0x5a9b4414), QTC(0x5ab630b2),
+ QTC(0x5ad11aa6), QTC(0x5aec01f1), QTC(0x5b06e696), QTC(0x5b21c895), QTC(0x5b3ca7ef), QTC(0x5b5784a6), QTC(0x5b725ebc), QTC(0x5b8d3631),
+ QTC(0x5ba80b06), QTC(0x5bc2dd3e), QTC(0x5bddacd9), QTC(0x5bf879d8), QTC(0x5c13443d), QTC(0x5c2e0c09), QTC(0x5c48d13e), QTC(0x5c6393dc),
+ QTC(0x5c7e53e5), QTC(0x5c99115a), QTC(0x5cb3cc3c), QTC(0x5cce848d), QTC(0x5ce93a4e), QTC(0x5d03ed80), QTC(0x5d1e9e24), QTC(0x5d394c3b),
+ QTC(0x5d53f7c7), QTC(0x5d6ea0c9), QTC(0x5d894742), QTC(0x5da3eb33), QTC(0x5dbe8c9e), QTC(0x5dd92b84), QTC(0x5df3c7e5), QTC(0x5e0e61c3),
+ QTC(0x5e28f920), QTC(0x5e438dfc), QTC(0x5e5e2059), QTC(0x5e78b037), QTC(0x5e933d99), QTC(0x5eadc87e), QTC(0x5ec850e9), QTC(0x5ee2d6da),
+ QTC(0x5efd5a53), QTC(0x5f17db54), QTC(0x5f3259e0), QTC(0x5f4cd5f6), QTC(0x5f674f99), QTC(0x5f81c6c8), QTC(0x5f9c3b87), QTC(0x5fb6add4),
+ QTC(0x5fd11db3), QTC(0x5feb8b23), QTC(0x6005f626), QTC(0x60205ebd), QTC(0x603ac4e9), QTC(0x605528ac), QTC(0x606f8a05), QTC(0x6089e8f7),
+ QTC(0x60a44583), QTC(0x60be9fa9), QTC(0x60d8f76b), QTC(0x60f34cca), QTC(0x610d9fc7), QTC(0x6127f062), QTC(0x61423e9e), QTC(0x615c8a7a),
+ QTC(0x6176d3f9), QTC(0x61911b1b), QTC(0x61ab5fe1), QTC(0x61c5a24d), QTC(0x61dfe25f), QTC(0x61fa2018), QTC(0x62145b7a), QTC(0x622e9485),
+ QTC(0x6248cb3b), QTC(0x6262ff9d), QTC(0x627d31ab), QTC(0x62976167), QTC(0x62b18ed1), QTC(0x62cbb9eb), QTC(0x62e5e2b6), QTC(0x63000933),
+ QTC(0x631a2d62), QTC(0x63344f45), QTC(0x634e6edd), QTC(0x63688c2b), QTC(0x6382a730), QTC(0x639cbfec), QTC(0x63b6d661), QTC(0x63d0ea90),
+ QTC(0x63eafc7a), QTC(0x64050c1f), QTC(0x641f1982), QTC(0x643924a2), QTC(0x64532d80), QTC(0x646d341f), QTC(0x6487387e), QTC(0x64a13a9e),
+ QTC(0x64bb3a81), QTC(0x64d53828), QTC(0x64ef3393), QTC(0x65092cc4), QTC(0x652323bb), QTC(0x653d1879), QTC(0x65570b00), QTC(0x6570fb50),
+ QTC(0x658ae96b), QTC(0x65a4d550), QTC(0x65bebf01), QTC(0x65d8a680), QTC(0x65f28bcc), QTC(0x660c6ee8), QTC(0x66264fd3), QTC(0x66402e8f),
+ QTC(0x665a0b1c), QTC(0x6673e57d), QTC(0x668dbdb0), QTC(0x66a793b8), QTC(0x66c16795), QTC(0x66db3949), QTC(0x66f508d4), QTC(0x670ed636),
+ QTC(0x6728a172), QTC(0x67426a87), QTC(0x675c3177), QTC(0x6775f643), QTC(0x678fb8eb), QTC(0x67a97971), QTC(0x67c337d5), QTC(0x67dcf418),
+ QTC(0x67f6ae3b), QTC(0x6810663f), QTC(0x682a1c25), QTC(0x6843cfed), QTC(0x685d8199), QTC(0x68773129), QTC(0x6890de9f), QTC(0x68aa89fa),
+ QTC(0x68c4333d), QTC(0x68ddda67), QTC(0x68f77f7a), QTC(0x69112277), QTC(0x692ac35e), QTC(0x69446230), QTC(0x695dfeee), QTC(0x6977999a),
+ QTC(0x69913232), QTC(0x69aac8ba), QTC(0x69c45d31), QTC(0x69ddef98), QTC(0x69f77ff0), QTC(0x6a110e3a), QTC(0x6a2a9a77), QTC(0x6a4424a8),
+ QTC(0x6a5daccc), QTC(0x6a7732e6), QTC(0x6a90b6f6), QTC(0x6aaa38fd), QTC(0x6ac3b8fb), QTC(0x6add36f2), QTC(0x6af6b2e2), QTC(0x6b102ccd),
+ QTC(0x6b29a4b2), QTC(0x6b431a92), QTC(0x6b5c8e6f), QTC(0x6b76004a), QTC(0x6b8f7022), QTC(0x6ba8ddf9), QTC(0x6bc249d0), QTC(0x6bdbb3a7),
+ QTC(0x6bf51b80), QTC(0x6c0e815a), QTC(0x6c27e537), QTC(0x6c414718), QTC(0x6c5aa6fd), QTC(0x6c7404e7), QTC(0x6c8d60d7), QTC(0x6ca6bace),
+ QTC(0x6cc012cc), QTC(0x6cd968d2), QTC(0x6cf2bce1), QTC(0x6d0c0ef9), QTC(0x6d255f1d), QTC(0x6d3ead4b), QTC(0x6d57f985), QTC(0x6d7143cc),
+ QTC(0x6d8a8c21), QTC(0x6da3d283), QTC(0x6dbd16f5), QTC(0x6dd65976), QTC(0x6def9a08), QTC(0x6e08d8ab), QTC(0x6e221560), QTC(0x6e3b5027),
+ QTC(0x6e548902), QTC(0x6e6dbff1), QTC(0x6e86f4f5), QTC(0x6ea0280e), QTC(0x6eb9593e), QTC(0x6ed28885), QTC(0x6eebb5e3), QTC(0x6f04e15a),
+ QTC(0x6f1e0aea), QTC(0x6f373294), QTC(0x6f505859), QTC(0x6f697c39), QTC(0x6f829e35), QTC(0x6f9bbe4e), QTC(0x6fb4dc85), QTC(0x6fcdf8d9),
+ QTC(0x6fe7134d), QTC(0x70002be0), QTC(0x70194293), QTC(0x70325767), QTC(0x704b6a5d), QTC(0x70647b76), QTC(0x707d8ab1), QTC(0x70969811),
+ QTC(0x70afa394), QTC(0x70c8ad3d), QTC(0x70e1b50c), QTC(0x70fabb01), QTC(0x7113bf1d), QTC(0x712cc161), QTC(0x7145c1ce), QTC(0x715ec064),
+ QTC(0x7177bd24), QTC(0x7190b80f), QTC(0x71a9b124), QTC(0x71c2a866), QTC(0x71db9dd4), QTC(0x71f49170), QTC(0x720d8339), QTC(0x72267331),
+ QTC(0x723f6159), QTC(0x72584db0), QTC(0x72713838), QTC(0x728a20f1), QTC(0x72a307db), QTC(0x72bbecf9), QTC(0x72d4d049), QTC(0x72edb1ce),
+ QTC(0x73069187), QTC(0x731f6f75), QTC(0x73384b98), QTC(0x735125f3), QTC(0x7369fe84), QTC(0x7382d54d), QTC(0x739baa4e), QTC(0x73b47d89),
+ QTC(0x73cd4efd), QTC(0x73e61eab), QTC(0x73feec94), QTC(0x7417b8b8), QTC(0x74308319), QTC(0x74494bb6), QTC(0x74621291), QTC(0x747ad7aa),
+ QTC(0x74939b02), QTC(0x74ac5c98), QTC(0x74c51c6f), QTC(0x74ddda86), QTC(0x74f696de), QTC(0x750f5178), QTC(0x75280a54), QTC(0x7540c174),
+ QTC(0x755976d7), QTC(0x75722a7e), QTC(0x758adc69), QTC(0x75a38c9b), QTC(0x75bc3b12), QTC(0x75d4e7cf), QTC(0x75ed92d4), QTC(0x76063c21),
+ QTC(0x761ee3b6), QTC(0x76378994), QTC(0x76502dbc), QTC(0x7668d02e), QTC(0x768170eb), QTC(0x769a0ff3), QTC(0x76b2ad47), QTC(0x76cb48e7),
+ QTC(0x76e3e2d5), QTC(0x76fc7b10), QTC(0x7715119a), QTC(0x772da673), QTC(0x7746399b), QTC(0x775ecb13), QTC(0x77775adc), QTC(0x778fe8f6),
+ QTC(0x77a87561), QTC(0x77c1001f), QTC(0x77d98930), QTC(0x77f21095), QTC(0x780a964d), QTC(0x78231a5b), QTC(0x783b9cbd), QTC(0x78541d75),
+ QTC(0x786c9c84), QTC(0x788519e9), QTC(0x789d95a6), QTC(0x78b60fbb), QTC(0x78ce8828), QTC(0x78e6feef), QTC(0x78ff740f), QTC(0x7917e78a),
+ QTC(0x7930595f), QTC(0x7948c990), QTC(0x7961381d), QTC(0x7979a506), QTC(0x7992104c), QTC(0x79aa79f0), QTC(0x79c2e1f1), QTC(0x79db4852),
+ QTC(0x79f3ad11), QTC(0x7a0c1031), QTC(0x7a2471b0), QTC(0x7a3cd191), QTC(0x7a552fd3), QTC(0x7a6d8c76), QTC(0x7a85e77d), QTC(0x7a9e40e6),
+ QTC(0x7ab698b2), QTC(0x7aceeee3), QTC(0x7ae74378), QTC(0x7aff9673), QTC(0x7b17e7d2), QTC(0x7b303799), QTC(0x7b4885c5), QTC(0x7b60d259),
+ QTC(0x7b791d55), QTC(0x7b9166b9), QTC(0x7ba9ae86), QTC(0x7bc1f4bc), QTC(0x7bda395c), QTC(0x7bf27c66), QTC(0x7c0abddb), QTC(0x7c22fdbb),
+ QTC(0x7c3b3c07), QTC(0x7c5378c0), QTC(0x7c6bb3e5), QTC(0x7c83ed78), QTC(0x7c9c2579), QTC(0x7cb45be9), QTC(0x7ccc90c7), QTC(0x7ce4c414),
+ QTC(0x7cfcf5d2), QTC(0x7d152600), QTC(0x7d2d549f), QTC(0x7d4581b0), QTC(0x7d5dad32), QTC(0x7d75d727), QTC(0x7d8dff8f), QTC(0x7da6266a),
+ QTC(0x7dbe4bba), QTC(0x7dd66f7d), QTC(0x7dee91b6), QTC(0x7e06b264), QTC(0x7e1ed188), QTC(0x7e36ef22), QTC(0x7e4f0b34), QTC(0x7e6725bd),
+ QTC(0x7e7f3ebd), QTC(0x7e975636), QTC(0x7eaf6c28), QTC(0x7ec78093), QTC(0x7edf9378), QTC(0x7ef7a4d7), QTC(0x7f0fb4b1), QTC(0x7f27c307),
+ QTC(0x7f3fcfd8), QTC(0x7f57db25), QTC(0x7f6fe4ef), QTC(0x7f87ed36), QTC(0x7f9ff3fb), QTC(0x7fb7f93e), QTC(0x7fcffcff), QTC(0x7fe7ff40)
+};
+
+/*
+ table of pow(2.0,0.25*q)/2.0, q[0..4)
+*/
+const FIXP_QTD FDKaacEnc_quantTableQ[4] = { QTC(0x40000000), QTC(0x4c1bf7ff), QTC(0x5a82797f), QTC(0x6ba27e7f) };
+
+/*
+ table of pow(2.0,0.75*e)/8.0, e[0..4)
+*/
+const FIXP_QTD FDKaacEnc_quantTableE[4] = { QTC(0x10000000), QTC(0x1ae89f99), QTC(0x2d413ccd), QTC(0x4c1bf828) };
+
+
+/*
+ table to count used number of bits
+*/
+const SHORT FDKaacEnc_sideInfoTabLong[MAX_SFB_LONG + 1] =
+{
+ 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
+ 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
+ 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
+ 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000e,
+ 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e,
+ 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e,
+ 0x000e, 0x000e, 0x000e, 0x000e
+};
+
+
+const SHORT FDKaacEnc_sideInfoTabShort[MAX_SFB_SHORT + 1] =
+{
+ 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x000a,
+ 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000d, 0x000d
+};
+
+
+
+
+
+
+/*
+ Psy Configuration constants
+*/
+
+const SFB_PARAM_LONG p_FDKaacEnc_8000_long_1024 = {
+ 40,
+ { 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 16, 16, 16, 16, 16, 16, 16,
+ 20, 20, 20, 20, 24, 24, 24, 28, 28, 32, 36, 36, 40, 44, 48, 52, 56, 60, 64, 80 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_8000_short_128 = {
+ 15,
+ { 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 12, 16, 20, 20 }
+};
+
+const SFB_PARAM_LONG p_FDKaacEnc_11025_long_1024 = {
+ 43,
+ { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 16, 16, 16, 16, 20, 20, 20, 24, 24, 28, 28, 32, 36, 40, 40, 44, 48, 52, 56, 60,
+ 64, 64, 64 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_11025_short_128 = {
+ 15,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 12, 12, 16, 20, 20 }
+};
+
+const SFB_PARAM_LONG p_FDKaacEnc_12000_long_1024 = {
+ 43,
+ { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 16, 16, 16, 16, 20, 20, 20, 24, 24, 28, 28, 32, 36, 40, 40, 44, 48, 52, 56, 60,
+ 64, 64, 64 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_12000_short_128 = {
+ 15,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 12, 12, 16, 20, 20 }
+};
+
+const SFB_PARAM_LONG p_FDKaacEnc_16000_long_1024 = {
+ 43,
+ { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 16, 16, 16, 16, 20, 20, 20, 24, 24, 28, 28, 32, 36, 40, 40, 44, 48, 52, 56, 60,
+ 64, 64, 64 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_16000_short_128 = {
+ 15,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 12, 12, 16, 20, 20 }
+};
+const SFB_PARAM_LONG p_FDKaacEnc_22050_long_1024 = {
+ 47,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 12, 12, 12, 12, 16, 16, 16, 20, 20, 24, 24, 28, 28, 32, 36, 36, 40, 44, 48,
+ 52, 52, 64, 64, 64, 64, 64 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_22050_short_128 = {
+ 15,
+ { 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 16, 16, 20 }
+};
+const SFB_PARAM_LONG p_FDKaacEnc_24000_long_1024 = {
+ 47,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 12, 12, 12, 12, 16, 16, 16, 20, 20, 24, 24, 28, 28, 32, 36, 36, 40, 44, 48,
+ 52, 52, 64, 64, 64, 64, 64 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_24000_short_128 = {
+ 15,
+ { 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 16, 16, 20 }
+};
+const SFB_PARAM_LONG p_FDKaacEnc_32000_long_1024 = {
+ 51,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12,
+ 12, 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_32000_short_128 = {
+ 14,
+ { 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16 }
+};
+const SFB_PARAM_LONG p_FDKaacEnc_44100_long_1024 = {
+ 49,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12,
+ 12, 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 96 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_44100_short_128 = {
+ 14,
+ { 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16 }
+};
+const SFB_PARAM_LONG p_FDKaacEnc_48000_long_1024 = {
+ 49,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 12, 12, 12,
+ 12, 16, 16, 20, 20, 24, 24, 28, 28, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 96 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_48000_short_128 = {
+ 14,
+ { 4, 4, 4, 4, 4, 8, 8, 8, 12, 12, 12, 16, 16, 16 }
+};
+const SFB_PARAM_LONG p_FDKaacEnc_64000_long_1024 = {
+ 47,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12,
+ 12, 16, 16, 16, 20, 24, 24, 28, 36, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_64000_short_128 = {
+ 12,
+ { 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 }
+};
+const SFB_PARAM_LONG p_FDKaacEnc_88200_long_1024 = {
+ 41,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 12,
+ 12, 12, 12, 12, 16, 16, 24, 28, 36, 44, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_88200_short_128 = {
+ 12,
+ { 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 }
+};
+const SFB_PARAM_LONG p_FDKaacEnc_96000_long_1024 = {
+ 41,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 12,
+ 12, 12, 12, 12, 16, 16, 24, 28, 36, 44, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64 }
+};
+const SFB_PARAM_SHORT p_FDKaacEnc_96000_short_128 = {
+ 12,
+ { 4, 4, 4, 4, 4, 4, 8, 8, 8, 16, 28, 36 }
+};
+
+
+/*
+ TNS filter coefficients
+*/
+
+/*
+ 3 bit resolution
+*/
+const FIXP_DBL FDKaacEnc_tnsEncCoeff3[8]=
+{
+ 0x81f1d201, 0x91261481, 0xadb92301, 0xd438af00, 0x00000000, 0x37898080, 0x64130dff, 0x7cca6fff
+};
+const FIXP_DBL FDKaacEnc_tnsCoeff3Borders[8]={
+ 0x80000001 /*-4*/, 0x87b826df /*-3*/, 0x9df24154 /*-2*/, 0xbfffffe5 /*-1*/,
+ 0xe9c5e578 /* 0*/, 0x1c7b90f0 /* 1*/, 0x4fce83a9 /* 2*/, 0x7352f2c3 /* 3*/
+};
+
+/*
+ 4 bit resolution
+*/
+const FIXP_DBL FDKaacEnc_tnsEncCoeff4[16]=
+{
+ 0x808bc881, 0x84e2e581, 0x8d6b4a01, 0x99da9201, 0xa9c45701, 0xbc9dde81, 0xd1c2d500, 0xe87ae540,
+ 0x00000000, 0x1a9cd9c0, 0x340ff240, 0x4b3c8bff, 0x5f1f5e7f, 0x6ed9eb7f, 0x79bc387f, 0x7f4c7e7f
+};
+const FIXP_DBL FDKaacEnc_tnsCoeff4Borders[16]=
+{
+ 0x80000001 /*-8*/, 0x822deff0 /*-7*/, 0x88a4bfe6 /*-6*/, 0x932c159d /*-5*/,
+ 0xa16827c2 /*-4*/, 0xb2dcde27 /*-3*/, 0xc6f20b91 /*-2*/, 0xdcf89c64 /*-1*/,
+ 0xf4308ce1 /* 0*/, 0x0d613054 /* 1*/, 0x278dde80 /* 2*/, 0x4000001b /* 3*/,
+ 0x55a6127b /* 4*/, 0x678dde8f /* 5*/, 0x74ef0ed7 /* 6*/, 0x7d33f0da /* 7*/
+};
+const FIXP_DBL FDKaacEnc_mTab_4_3Elc[512]={
+ FL2FXCONST_DBL(0.3968502629920499),FL2FXCONST_DBL(0.3978840634868335),FL2FXCONST_DBL(0.3989185359354711),FL2FXCONST_DBL(0.3999536794661432),
+ FL2FXCONST_DBL(0.4009894932098531),FL2FXCONST_DBL(0.4020259763004115),FL2FXCONST_DBL(0.4030631278744227),FL2FXCONST_DBL(0.4041009470712695),
+ FL2FXCONST_DBL(0.4051394330330996),FL2FXCONST_DBL(0.4061785849048110),FL2FXCONST_DBL(0.4072184018340380),FL2FXCONST_DBL(0.4082588829711372),
+ FL2FXCONST_DBL(0.4093000274691739),FL2FXCONST_DBL(0.4103418344839078),FL2FXCONST_DBL(0.4113843031737798),FL2FXCONST_DBL(0.4124274326998980),
+ FL2FXCONST_DBL(0.4134712222260245),FL2FXCONST_DBL(0.4145156709185620),FL2FXCONST_DBL(0.4155607779465400),FL2FXCONST_DBL(0.4166065424816022),
+ FL2FXCONST_DBL(0.4176529636979932),FL2FXCONST_DBL(0.4187000407725452),FL2FXCONST_DBL(0.4197477728846652),FL2FXCONST_DBL(0.4207961592163222),
+ FL2FXCONST_DBL(0.4218451989520345),FL2FXCONST_DBL(0.4228948912788567),FL2FXCONST_DBL(0.4239452353863673),FL2FXCONST_DBL(0.4249962304666564),
+ FL2FXCONST_DBL(0.4260478757143130),FL2FXCONST_DBL(0.4271001703264124),FL2FXCONST_DBL(0.4281531135025046),FL2FXCONST_DBL(0.4292067044446017),
+ FL2FXCONST_DBL(0.4302609423571658),FL2FXCONST_DBL(0.4313158264470970),FL2FXCONST_DBL(0.4323713559237216),FL2FXCONST_DBL(0.4334275299987803),
+ FL2FXCONST_DBL(0.4344843478864161),FL2FXCONST_DBL(0.4355418088031630),FL2FXCONST_DBL(0.4365999119679339),FL2FXCONST_DBL(0.4376586566020096),
+ FL2FXCONST_DBL(0.4387180419290272),FL2FXCONST_DBL(0.4397780671749683),FL2FXCONST_DBL(0.4408387315681480),FL2FXCONST_DBL(0.4419000343392039),
+ FL2FXCONST_DBL(0.4429619747210847),FL2FXCONST_DBL(0.4440245519490388),FL2FXCONST_DBL(0.4450877652606038),FL2FXCONST_DBL(0.4461516138955953),
+ FL2FXCONST_DBL(0.4472160970960963),FL2FXCONST_DBL(0.4482812141064458),FL2FXCONST_DBL(0.4493469641732286),FL2FXCONST_DBL(0.4504133465452648),
+ FL2FXCONST_DBL(0.4514803604735984),FL2FXCONST_DBL(0.4525480052114875),FL2FXCONST_DBL(0.4536162800143939),FL2FXCONST_DBL(0.4546851841399719),
+ FL2FXCONST_DBL(0.4557547168480591),FL2FXCONST_DBL(0.4568248774006652),FL2FXCONST_DBL(0.4578956650619623),FL2FXCONST_DBL(0.4589670790982746),
+ FL2FXCONST_DBL(0.4600391187780688),FL2FXCONST_DBL(0.4611117833719430),FL2FXCONST_DBL(0.4621850721526184),FL2FXCONST_DBL(0.4632589843949278),
+ FL2FXCONST_DBL(0.4643335193758069),FL2FXCONST_DBL(0.4654086763742842),FL2FXCONST_DBL(0.4664844546714713),FL2FXCONST_DBL(0.4675608535505532),
+ FL2FXCONST_DBL(0.4686378722967790),FL2FXCONST_DBL(0.4697155101974522),FL2FXCONST_DBL(0.4707937665419216),FL2FXCONST_DBL(0.4718726406215713),
+ FL2FXCONST_DBL(0.4729521317298118),FL2FXCONST_DBL(0.4740322391620711),FL2FXCONST_DBL(0.4751129622157845),FL2FXCONST_DBL(0.4761943001903867),
+ FL2FXCONST_DBL(0.4772762523873015),FL2FXCONST_DBL(0.4783588181099338),FL2FXCONST_DBL(0.4794419966636599),FL2FXCONST_DBL(0.4805257873558190),
+ FL2FXCONST_DBL(0.4816101894957042),FL2FXCONST_DBL(0.4826952023945537),FL2FXCONST_DBL(0.4837808253655421),FL2FXCONST_DBL(0.4848670577237714),
+ FL2FXCONST_DBL(0.4859538987862632),FL2FXCONST_DBL(0.4870413478719488),FL2FXCONST_DBL(0.4881294043016621),FL2FXCONST_DBL(0.4892180673981298),
+ FL2FXCONST_DBL(0.4903073364859640),FL2FXCONST_DBL(0.4913972108916533),FL2FXCONST_DBL(0.4924876899435545),FL2FXCONST_DBL(0.4935787729718844),
+ FL2FXCONST_DBL(0.4946704593087116),FL2FXCONST_DBL(0.4957627482879484),FL2FXCONST_DBL(0.4968556392453423),FL2FXCONST_DBL(0.4979491315184684),
+ FL2FXCONST_DBL(0.4990432244467211),FL2FXCONST_DBL(0.5001379173713062),FL2FXCONST_DBL(0.5012332096352328),FL2FXCONST_DBL(0.5023291005833056),
+ FL2FXCONST_DBL(0.5034255895621171),FL2FXCONST_DBL(0.5045226759200399),FL2FXCONST_DBL(0.5056203590072181),FL2FXCONST_DBL(0.5067186381755611),
+ FL2FXCONST_DBL(0.5078175127787346),FL2FXCONST_DBL(0.5089169821721536),FL2FXCONST_DBL(0.5100170457129749),FL2FXCONST_DBL(0.5111177027600893),
+ FL2FXCONST_DBL(0.5122189526741143),FL2FXCONST_DBL(0.5133207948173868),FL2FXCONST_DBL(0.5144232285539552),FL2FXCONST_DBL(0.5155262532495726),
+ FL2FXCONST_DBL(0.5166298682716894),FL2FXCONST_DBL(0.5177340729894460),FL2FXCONST_DBL(0.5188388667736652),FL2FXCONST_DBL(0.5199442489968457),
+ FL2FXCONST_DBL(0.5210502190331544),FL2FXCONST_DBL(0.5221567762584198),FL2FXCONST_DBL(0.5232639200501247),FL2FXCONST_DBL(0.5243716497873989),
+ FL2FXCONST_DBL(0.5254799648510130),FL2FXCONST_DBL(0.5265888646233705),FL2FXCONST_DBL(0.5276983484885021),FL2FXCONST_DBL(0.5288084158320574),
+ FL2FXCONST_DBL(0.5299190660412995),FL2FXCONST_DBL(0.5310302985050975),FL2FXCONST_DBL(0.5321421126139198),FL2FXCONST_DBL(0.5332545077598274),
+ FL2FXCONST_DBL(0.5343674833364678),FL2FXCONST_DBL(0.5354810387390675),FL2FXCONST_DBL(0.5365951733644262),FL2FXCONST_DBL(0.5377098866109097),
+ FL2FXCONST_DBL(0.5388251778784438),FL2FXCONST_DBL(0.5399410465685075),FL2FXCONST_DBL(0.5410574920841272),FL2FXCONST_DBL(0.5421745138298695),
+ FL2FXCONST_DBL(0.5432921112118353),FL2FXCONST_DBL(0.5444102836376534),FL2FXCONST_DBL(0.5455290305164744),FL2FXCONST_DBL(0.5466483512589642),
+ FL2FXCONST_DBL(0.5477682452772976),FL2FXCONST_DBL(0.5488887119851529),FL2FXCONST_DBL(0.5500097507977050),FL2FXCONST_DBL(0.5511313611316194),
+ FL2FXCONST_DBL(0.5522535424050467),FL2FXCONST_DBL(0.5533762940376158),FL2FXCONST_DBL(0.5544996154504284),FL2FXCONST_DBL(0.5556235060660528),
+ FL2FXCONST_DBL(0.5567479653085183),FL2FXCONST_DBL(0.5578729926033087),FL2FXCONST_DBL(0.5589985873773569),FL2FXCONST_DBL(0.5601247490590389),
+ FL2FXCONST_DBL(0.5612514770781683),FL2FXCONST_DBL(0.5623787708659898),FL2FXCONST_DBL(0.5635066298551742),FL2FXCONST_DBL(0.5646350534798125),
+ FL2FXCONST_DBL(0.5657640411754097),FL2FXCONST_DBL(0.5668935923788799),FL2FXCONST_DBL(0.5680237065285404),FL2FXCONST_DBL(0.5691543830641059),
+ FL2FXCONST_DBL(0.5702856214266832),FL2FXCONST_DBL(0.5714174210587655),FL2FXCONST_DBL(0.5725497814042271),FL2FXCONST_DBL(0.5736827019083177),
+ FL2FXCONST_DBL(0.5748161820176573),FL2FXCONST_DBL(0.5759502211802304),FL2FXCONST_DBL(0.5770848188453810),FL2FXCONST_DBL(0.5782199744638067),
+ FL2FXCONST_DBL(0.5793556874875542),FL2FXCONST_DBL(0.5804919573700131),FL2FXCONST_DBL(0.5816287835659116),FL2FXCONST_DBL(0.5827661655313104),
+ FL2FXCONST_DBL(0.5839041027235979),FL2FXCONST_DBL(0.5850425946014850),FL2FXCONST_DBL(0.5861816406250000),FL2FXCONST_DBL(0.5873212402554834),
+ FL2FXCONST_DBL(0.5884613929555826),FL2FXCONST_DBL(0.5896020981892474),FL2FXCONST_DBL(0.5907433554217242),FL2FXCONST_DBL(0.5918851641195517),
+ FL2FXCONST_DBL(0.5930275237505556),FL2FXCONST_DBL(0.5941704337838434),FL2FXCONST_DBL(0.5953138936897999),FL2FXCONST_DBL(0.5964579029400819),
+ FL2FXCONST_DBL(0.5976024610076139),FL2FXCONST_DBL(0.5987475673665825),FL2FXCONST_DBL(0.5998932214924321),FL2FXCONST_DBL(0.6010394228618597),
+ FL2FXCONST_DBL(0.6021861709528106),FL2FXCONST_DBL(0.6033334652444733),FL2FXCONST_DBL(0.6044813052172748),FL2FXCONST_DBL(0.6056296903528761),
+ FL2FXCONST_DBL(0.6067786201341671),FL2FXCONST_DBL(0.6079280940452625),FL2FXCONST_DBL(0.6090781115714966),FL2FXCONST_DBL(0.6102286721994192),
+ FL2FXCONST_DBL(0.6113797754167908),FL2FXCONST_DBL(0.6125314207125777),FL2FXCONST_DBL(0.6136836075769482),FL2FXCONST_DBL(0.6148363355012674),
+ FL2FXCONST_DBL(0.6159896039780929),FL2FXCONST_DBL(0.6171434125011708),FL2FXCONST_DBL(0.6182977605654305),FL2FXCONST_DBL(0.6194526476669808),
+ FL2FXCONST_DBL(0.6206080733031054),FL2FXCONST_DBL(0.6217640369722584),FL2FXCONST_DBL(0.6229205381740598),FL2FXCONST_DBL(0.6240775764092919),
+ FL2FXCONST_DBL(0.6252351511798939),FL2FXCONST_DBL(0.6263932619889586),FL2FXCONST_DBL(0.6275519083407275),FL2FXCONST_DBL(0.6287110897405869),
+ FL2FXCONST_DBL(0.6298708056950635),FL2FXCONST_DBL(0.6310310557118203),FL2FXCONST_DBL(0.6321918392996523),FL2FXCONST_DBL(0.6333531559684823),
+ FL2FXCONST_DBL(0.6345150052293571),FL2FXCONST_DBL(0.6356773865944432),FL2FXCONST_DBL(0.6368402995770224),FL2FXCONST_DBL(0.6380037436914881),
+ FL2FXCONST_DBL(0.6391677184533411),FL2FXCONST_DBL(0.6403322233791856),FL2FXCONST_DBL(0.6414972579867254),FL2FXCONST_DBL(0.6426628217947594),
+ FL2FXCONST_DBL(0.6438289143231779),FL2FXCONST_DBL(0.6449955350929588),FL2FXCONST_DBL(0.6461626836261636),FL2FXCONST_DBL(0.6473303594459330),
+ FL2FXCONST_DBL(0.6484985620764839),FL2FXCONST_DBL(0.6496672910431047),FL2FXCONST_DBL(0.6508365458721518),FL2FXCONST_DBL(0.6520063260910459),
+ FL2FXCONST_DBL(0.6531766312282679),FL2FXCONST_DBL(0.6543474608133552),FL2FXCONST_DBL(0.6555188143768979),FL2FXCONST_DBL(0.6566906914505349),
+ FL2FXCONST_DBL(0.6578630915669509),FL2FXCONST_DBL(0.6590360142598715),FL2FXCONST_DBL(0.6602094590640603),FL2FXCONST_DBL(0.6613834255153149),
+ FL2FXCONST_DBL(0.6625579131504635),FL2FXCONST_DBL(0.6637329215073610),FL2FXCONST_DBL(0.6649084501248851),FL2FXCONST_DBL(0.6660844985429335),
+ FL2FXCONST_DBL(0.6672610663024197),FL2FXCONST_DBL(0.6684381529452691),FL2FXCONST_DBL(0.6696157580144163),FL2FXCONST_DBL(0.6707938810538011),
+ FL2FXCONST_DBL(0.6719725216083646),FL2FXCONST_DBL(0.6731516792240465),FL2FXCONST_DBL(0.6743313534477807),FL2FXCONST_DBL(0.6755115438274927),
+ FL2FXCONST_DBL(0.6766922499120955),FL2FXCONST_DBL(0.6778734712514865),FL2FXCONST_DBL(0.6790552073965435),FL2FXCONST_DBL(0.6802374578991223),
+ FL2FXCONST_DBL(0.6814202223120524),FL2FXCONST_DBL(0.6826035001891340),FL2FXCONST_DBL(0.6837872910851345),FL2FXCONST_DBL(0.6849715945557853),
+ FL2FXCONST_DBL(0.6861564101577784),FL2FXCONST_DBL(0.6873417374487629),FL2FXCONST_DBL(0.6885275759873420),FL2FXCONST_DBL(0.6897139253330697),
+ FL2FXCONST_DBL(0.6909007850464473),FL2FXCONST_DBL(0.6920881546889198),FL2FXCONST_DBL(0.6932760338228737),FL2FXCONST_DBL(0.6944644220116332),
+ FL2FXCONST_DBL(0.6956533188194565),FL2FXCONST_DBL(0.6968427238115332),FL2FXCONST_DBL(0.6980326365539813),FL2FXCONST_DBL(0.6992230566138435),
+ FL2FXCONST_DBL(0.7004139835590845),FL2FXCONST_DBL(0.7016054169585869),FL2FXCONST_DBL(0.7027973563821499),FL2FXCONST_DBL(0.7039898014004843),
+ FL2FXCONST_DBL(0.7051827515852106),FL2FXCONST_DBL(0.7063762065088554),FL2FXCONST_DBL(0.7075701657448483),FL2FXCONST_DBL(0.7087646288675196),
+ FL2FXCONST_DBL(0.7099595954520960),FL2FXCONST_DBL(0.7111550650746988),FL2FXCONST_DBL(0.7123510373123402),FL2FXCONST_DBL(0.7135475117429202),
+ FL2FXCONST_DBL(0.7147444879452244),FL2FXCONST_DBL(0.7159419654989200),FL2FXCONST_DBL(0.7171399439845538),FL2FXCONST_DBL(0.7183384229835486),
+ FL2FXCONST_DBL(0.7195374020782005),FL2FXCONST_DBL(0.7207368808516762),FL2FXCONST_DBL(0.7219368588880097),FL2FXCONST_DBL(0.7231373357720997),
+ FL2FXCONST_DBL(0.7243383110897066),FL2FXCONST_DBL(0.7255397844274496),FL2FXCONST_DBL(0.7267417553728043),FL2FXCONST_DBL(0.7279442235140992),
+ FL2FXCONST_DBL(0.7291471884405130),FL2FXCONST_DBL(0.7303506497420724),FL2FXCONST_DBL(0.7315546070096487),FL2FXCONST_DBL(0.7327590598349553),
+ FL2FXCONST_DBL(0.7339640078105445),FL2FXCONST_DBL(0.7351694505298055),FL2FXCONST_DBL(0.7363753875869610),FL2FXCONST_DBL(0.7375818185770647),
+ FL2FXCONST_DBL(0.7387887430959987),FL2FXCONST_DBL(0.7399961607404706),FL2FXCONST_DBL(0.7412040711080108),FL2FXCONST_DBL(0.7424124737969701),
+ FL2FXCONST_DBL(0.7436213684065166),FL2FXCONST_DBL(0.7448307545366334),FL2FXCONST_DBL(0.7460406317881158),FL2FXCONST_DBL(0.7472509997625686),
+ FL2FXCONST_DBL(0.7484618580624036),FL2FXCONST_DBL(0.7496732062908372),FL2FXCONST_DBL(0.7508850440518872),FL2FXCONST_DBL(0.7520973709503704),
+ FL2FXCONST_DBL(0.7533101865919009),FL2FXCONST_DBL(0.7545234905828862),FL2FXCONST_DBL(0.7557372825305252),FL2FXCONST_DBL(0.7569515620428062),
+ FL2FXCONST_DBL(0.7581663287285035),FL2FXCONST_DBL(0.7593815821971756),FL2FXCONST_DBL(0.7605973220591619),FL2FXCONST_DBL(0.7618135479255810),
+ FL2FXCONST_DBL(0.7630302594083277),FL2FXCONST_DBL(0.7642474561200708),FL2FXCONST_DBL(0.7654651376742505),FL2FXCONST_DBL(0.7666833036850760),
+ FL2FXCONST_DBL(0.7679019537675227),FL2FXCONST_DBL(0.7691210875373307),FL2FXCONST_DBL(0.7703407046110011),FL2FXCONST_DBL(0.7715608046057948),
+ FL2FXCONST_DBL(0.7727813871397293),FL2FXCONST_DBL(0.7740024518315765),FL2FXCONST_DBL(0.7752239983008605),FL2FXCONST_DBL(0.7764460261678551),
+ FL2FXCONST_DBL(0.7776685350535814),FL2FXCONST_DBL(0.7788915245798054),FL2FXCONST_DBL(0.7801149943690360),FL2FXCONST_DBL(0.7813389440445223),
+ FL2FXCONST_DBL(0.7825633732302513),FL2FXCONST_DBL(0.7837882815509458),FL2FXCONST_DBL(0.7850136686320621),FL2FXCONST_DBL(0.7862395340997874),
+ FL2FXCONST_DBL(0.7874658775810378),FL2FXCONST_DBL(0.7886926987034559),FL2FXCONST_DBL(0.7899199970954088),FL2FXCONST_DBL(0.7911477723859853),
+ FL2FXCONST_DBL(0.7923760242049944),FL2FXCONST_DBL(0.7936047521829623),FL2FXCONST_DBL(0.7948339559511308),FL2FXCONST_DBL(0.7960636351414546),
+ FL2FXCONST_DBL(0.7972937893865995),FL2FXCONST_DBL(0.7985244183199399),FL2FXCONST_DBL(0.7997555215755570),FL2FXCONST_DBL(0.8009870987882359),
+ FL2FXCONST_DBL(0.8022191495934644),FL2FXCONST_DBL(0.8034516736274301),FL2FXCONST_DBL(0.8046846705270185),FL2FXCONST_DBL(0.8059181399298110),
+ FL2FXCONST_DBL(0.8071520814740822),FL2FXCONST_DBL(0.8083864947987989),FL2FXCONST_DBL(0.8096213795436166),FL2FXCONST_DBL(0.8108567353488784),
+ FL2FXCONST_DBL(0.8120925618556127),FL2FXCONST_DBL(0.8133288587055308),FL2FXCONST_DBL(0.8145656255410253),FL2FXCONST_DBL(0.8158028620051674),
+ FL2FXCONST_DBL(0.8170405677417053),FL2FXCONST_DBL(0.8182787423950622),FL2FXCONST_DBL(0.8195173856103341),FL2FXCONST_DBL(0.8207564970332875),
+ FL2FXCONST_DBL(0.8219960763103580),FL2FXCONST_DBL(0.8232361230886477),FL2FXCONST_DBL(0.8244766370159234),FL2FXCONST_DBL(0.8257176177406150),
+ FL2FXCONST_DBL(0.8269590649118125),FL2FXCONST_DBL(0.8282009781792650),FL2FXCONST_DBL(0.8294433571933784),FL2FXCONST_DBL(0.8306862016052132),
+ FL2FXCONST_DBL(0.8319295110664831),FL2FXCONST_DBL(0.8331732852295520),FL2FXCONST_DBL(0.8344175237474336),FL2FXCONST_DBL(0.8356622262737878),
+ FL2FXCONST_DBL(0.8369073924629202),FL2FXCONST_DBL(0.8381530219697793),FL2FXCONST_DBL(0.8393991144499545),FL2FXCONST_DBL(0.8406456695596752),
+ FL2FXCONST_DBL(0.8418926869558079),FL2FXCONST_DBL(0.8431401662958544),FL2FXCONST_DBL(0.8443881072379507),FL2FXCONST_DBL(0.8456365094408642),
+ FL2FXCONST_DBL(0.8468853725639923),FL2FXCONST_DBL(0.8481346962673606),FL2FXCONST_DBL(0.8493844802116208),FL2FXCONST_DBL(0.8506347240580492),
+ FL2FXCONST_DBL(0.8518854274685442),FL2FXCONST_DBL(0.8531365901056253),FL2FXCONST_DBL(0.8543882116324307),FL2FXCONST_DBL(0.8556402917127157),
+ FL2FXCONST_DBL(0.8568928300108512),FL2FXCONST_DBL(0.8581458261918209),FL2FXCONST_DBL(0.8593992799212207),FL2FXCONST_DBL(0.8606531908652563),
+ FL2FXCONST_DBL(0.8619075586907414),FL2FXCONST_DBL(0.8631623830650962),FL2FXCONST_DBL(0.8644176636563452),FL2FXCONST_DBL(0.8656734001331161),
+ FL2FXCONST_DBL(0.8669295921646375),FL2FXCONST_DBL(0.8681862394207371),FL2FXCONST_DBL(0.8694433415718407),FL2FXCONST_DBL(0.8707008982889695),
+ FL2FXCONST_DBL(0.8719589092437391),FL2FXCONST_DBL(0.8732173741083574),FL2FXCONST_DBL(0.8744762925556232),FL2FXCONST_DBL(0.8757356642589241),
+ FL2FXCONST_DBL(0.8769954888922352),FL2FXCONST_DBL(0.8782557661301171),FL2FXCONST_DBL(0.8795164956477146),FL2FXCONST_DBL(0.8807776771207545),
+ FL2FXCONST_DBL(0.8820393102255443),FL2FXCONST_DBL(0.8833013946389704),FL2FXCONST_DBL(0.8845639300384969),FL2FXCONST_DBL(0.8858269161021629),
+ FL2FXCONST_DBL(0.8870903525085819),FL2FXCONST_DBL(0.8883542389369399),FL2FXCONST_DBL(0.8896185750669933),FL2FXCONST_DBL(0.8908833605790678),
+ FL2FXCONST_DBL(0.8921485951540565),FL2FXCONST_DBL(0.8934142784734187),FL2FXCONST_DBL(0.8946804102191776),FL2FXCONST_DBL(0.8959469900739191),
+ FL2FXCONST_DBL(0.8972140177207906),FL2FXCONST_DBL(0.8984814928434985),FL2FXCONST_DBL(0.8997494151263077),FL2FXCONST_DBL(0.9010177842540390),
+ FL2FXCONST_DBL(0.9022865999120682),FL2FXCONST_DBL(0.9035558617863242),FL2FXCONST_DBL(0.9048255695632878),FL2FXCONST_DBL(0.9060957229299895),
+ FL2FXCONST_DBL(0.9073663215740092),FL2FXCONST_DBL(0.9086373651834729),FL2FXCONST_DBL(0.9099088534470528),FL2FXCONST_DBL(0.9111807860539647),
+ FL2FXCONST_DBL(0.9124531626939672),FL2FXCONST_DBL(0.9137259830573594),FL2FXCONST_DBL(0.9149992468349805),FL2FXCONST_DBL(0.9162729537182071),
+ FL2FXCONST_DBL(0.9175471033989524),FL2FXCONST_DBL(0.9188216955696648),FL2FXCONST_DBL(0.9200967299233258),FL2FXCONST_DBL(0.9213722061534494),
+ FL2FXCONST_DBL(0.9226481239540795),FL2FXCONST_DBL(0.9239244830197896),FL2FXCONST_DBL(0.9252012830456805),FL2FXCONST_DBL(0.9264785237273793),
+ FL2FXCONST_DBL(0.9277562047610376),FL2FXCONST_DBL(0.9290343258433305),FL2FXCONST_DBL(0.9303128866714547),FL2FXCONST_DBL(0.9315918869431275),
+ FL2FXCONST_DBL(0.9328713263565848),FL2FXCONST_DBL(0.9341512046105802),FL2FXCONST_DBL(0.9354315214043836),FL2FXCONST_DBL(0.9367122764377792),
+ FL2FXCONST_DBL(0.9379934694110648),FL2FXCONST_DBL(0.9392751000250497),FL2FXCONST_DBL(0.9405571679810542),FL2FXCONST_DBL(0.9418396729809072),
+ FL2FXCONST_DBL(0.9431226147269456),FL2FXCONST_DBL(0.9444059929220124),FL2FXCONST_DBL(0.9456898072694558),FL2FXCONST_DBL(0.9469740574731275),
+ FL2FXCONST_DBL(0.9482587432373810),FL2FXCONST_DBL(0.9495438642670713),FL2FXCONST_DBL(0.9508294202675522),FL2FXCONST_DBL(0.9521154109446763),
+ FL2FXCONST_DBL(0.9534018360047926),FL2FXCONST_DBL(0.9546886951547455),FL2FXCONST_DBL(0.9559759881018738),FL2FXCONST_DBL(0.9572637145540087),
+ FL2FXCONST_DBL(0.9585518742194732),FL2FXCONST_DBL(0.9598404668070802),FL2FXCONST_DBL(0.9611294920261317),FL2FXCONST_DBL(0.9624189495864168),
+ FL2FXCONST_DBL(0.9637088391982110),FL2FXCONST_DBL(0.9649991605722750),FL2FXCONST_DBL(0.9662899134198524),FL2FXCONST_DBL(0.9675810974526697),
+ FL2FXCONST_DBL(0.9688727123829343),FL2FXCONST_DBL(0.9701647579233330),FL2FXCONST_DBL(0.9714572337870316),FL2FXCONST_DBL(0.9727501396876727),
+ FL2FXCONST_DBL(0.9740434753393749),FL2FXCONST_DBL(0.9753372404567313),FL2FXCONST_DBL(0.9766314347548087),FL2FXCONST_DBL(0.9779260579491460),
+ FL2FXCONST_DBL(0.9792211097557527),FL2FXCONST_DBL(0.9805165898911081),FL2FXCONST_DBL(0.9818124980721600),FL2FXCONST_DBL(0.9831088340163232),
+ FL2FXCONST_DBL(0.9844055974414786),FL2FXCONST_DBL(0.9857027880659716),FL2FXCONST_DBL(0.9870004056086111),FL2FXCONST_DBL(0.9882984497886684),
+ FL2FXCONST_DBL(0.9895969203258759),FL2FXCONST_DBL(0.9908958169404255),FL2FXCONST_DBL(0.9921951393529680),FL2FXCONST_DBL(0.9934948872846116),
+ FL2FXCONST_DBL(0.9947950604569206),FL2FXCONST_DBL(0.9960956585919144),FL2FXCONST_DBL(0.9973966814120665),FL2FXCONST_DBL(0.9986981286403025)
+};
+
+const FIXP_DBL FDKaacEnc_specExpMantTableCombElc[4][14] =
+{
+ {FL2FXCONST_DBL(0.5000000000000000), FL2FXCONST_DBL(0.6299605249474366), FL2FXCONST_DBL(0.7937005259840998), FL2FXCONST_DBL(0.5000000000000000),
+ FL2FXCONST_DBL(0.6299605249474366), FL2FXCONST_DBL(0.7937005259840998), FL2FXCONST_DBL(0.5000000000000000), FL2FXCONST_DBL(0.6299605249474366),
+ FL2FXCONST_DBL(0.7937005259840998), FL2FXCONST_DBL(0.5000000000000000), FL2FXCONST_DBL(0.6299605249474366), FL2FXCONST_DBL(0.7937005259840998),
+ FL2FXCONST_DBL(0.5000000000000000), FL2FXCONST_DBL(0.6299605249474366)},
+
+ {FL2FXCONST_DBL(0.5946035575013605), FL2FXCONST_DBL(0.7491535384383408), FL2FXCONST_DBL(0.9438743126816935), FL2FXCONST_DBL(0.5946035575013605),
+ FL2FXCONST_DBL(0.7491535384383408), FL2FXCONST_DBL(0.9438743126816935), FL2FXCONST_DBL(0.5946035575013605), FL2FXCONST_DBL(0.7491535384383408),
+ FL2FXCONST_DBL(0.9438743126816935), FL2FXCONST_DBL(0.5946035575013605), FL2FXCONST_DBL(0.7491535384383408), FL2FXCONST_DBL(0.9438743126816935),
+ FL2FXCONST_DBL(0.5946035575013605), FL2FXCONST_DBL(0.7491535384383408)},
+
+ {FL2FXCONST_DBL(0.7071067811865476), FL2FXCONST_DBL(0.8908987181403393), FL2FXCONST_DBL(0.5612310241546865), FL2FXCONST_DBL(0.7071067811865476),
+ FL2FXCONST_DBL(0.8908987181403393), FL2FXCONST_DBL(0.5612310241546865), FL2FXCONST_DBL(0.7071067811865476), FL2FXCONST_DBL(0.8908987181403393),
+ FL2FXCONST_DBL(0.5612310241546865), FL2FXCONST_DBL(0.7071067811865476), FL2FXCONST_DBL(0.8908987181403393), FL2FXCONST_DBL(0.5612310241546865),
+ FL2FXCONST_DBL(0.7071067811865476), FL2FXCONST_DBL(0.8908987181403393)},
+
+ {FL2FXCONST_DBL(0.8408964152537145), FL2FXCONST_DBL(0.5297315471796477), FL2FXCONST_DBL(0.6674199270850172), FL2FXCONST_DBL(0.8408964152537145),
+ FL2FXCONST_DBL(0.5297315471796477), FL2FXCONST_DBL(0.6674199270850172), FL2FXCONST_DBL(0.8408964152537145), FL2FXCONST_DBL(0.5297315471796477),
+ FL2FXCONST_DBL(0.6674199270850172), FL2FXCONST_DBL(0.8408964152537145), FL2FXCONST_DBL(0.5297315471796477), FL2FXCONST_DBL(0.6674199270850172),
+ FL2FXCONST_DBL(0.8408964152537145), FL2FXCONST_DBL(0.5297315471796477)}
+};
+
+const UCHAR FDKaacEnc_specExpTableComb[4][14] =
+{
+ {1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18},
+ {1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18},
+ {1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 16, 17, 18},
+ {1, 3, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19}
+};
+
+
+#define WTS0 1
+#define WTS1 0
+#define WTS2 -2
+
+const FIXP_WTB ELDAnalysis512[1536] = {
+ /* part 0 */
+ WTC0(0xfac5a770), WTC0(0xfaafbab8), WTC0(0xfa996a40), WTC0(0xfa82bbd0), WTC0(0xfa6bb538), WTC0(0xfa545c38), WTC0(0xfa3cb698), WTC0(0xfa24ca28),
+ WTC0(0xfa0c9ca8), WTC0(0xf9f433e8), WTC0(0xf9db9580), WTC0(0xf9c2c298), WTC0(0xf9a9b800), WTC0(0xf9907250), WTC0(0xf976ee38), WTC0(0xf95d2b88),
+ WTC0(0xf9432d10), WTC0(0xf928f5c0), WTC0(0xf90e8868), WTC0(0xf8f3e400), WTC0(0xf8d903a0), WTC0(0xf8bde238), WTC0(0xf8a27af0), WTC0(0xf886cde8),
+ WTC0(0xf86ae020), WTC0(0xf84eb6c0), WTC0(0xf83256f8), WTC0(0xf815c4b8), WTC0(0xf7f902c0), WTC0(0xf7dc13b0), WTC0(0xf7befa60), WTC0(0xf7a1ba40),
+ WTC0(0xf78457c0), WTC0(0xf766d780), WTC0(0xf7493d90), WTC0(0xf72b8990), WTC0(0xf70db5f0), WTC0(0xf6efbd30), WTC0(0xf6d19a20), WTC0(0xf6b352e0),
+ WTC0(0xf694f8c0), WTC0(0xf6769da0), WTC0(0xf6585310), WTC0(0xf63a28d0), WTC0(0xf61c2c60), WTC0(0xf5fe6b10), WTC0(0xf5e0f250), WTC0(0xf5c3ceb0),
+ WTC0(0xf5a70be0), WTC0(0xf58ab5a0), WTC0(0xf56ed7b0), WTC0(0xf5537e40), WTC0(0xf538b610), WTC0(0xf51e8bf0), WTC0(0xf5050c90), WTC0(0xf4ec4330),
+ WTC0(0xf4d439b0), WTC0(0xf4bcf9b0), WTC0(0xf4a68ce0), WTC0(0xf490fa80), WTC0(0xf47c4760), WTC0(0xf4687830), WTC0(0xf4558f00), WTC0(0xf4434fc0),
+ WTC0(0xf4314070), WTC0(0xf41ee450), WTC0(0xf40bc130), WTC0(0xf3f799c0), WTC0(0xf3e26d30), WTC0(0xf3cc3d70), WTC0(0xf3b50c80), WTC0(0xf39cdd60),
+ WTC0(0xf383b440), WTC0(0xf3699550), WTC0(0xf34e84c0), WTC0(0xf33286b0), WTC0(0xf3159f10), WTC0(0xf2f7d1b0), WTC0(0xf2d92290), WTC0(0xf2b994d0),
+ WTC0(0xf2992ad0), WTC0(0xf277e6d0), WTC0(0xf255cb60), WTC0(0xf232dd00), WTC0(0xf20f2240), WTC0(0xf1eaa1d0), WTC0(0xf1c56240), WTC0(0xf19f63d0),
+ WTC0(0xf178a0f0), WTC0(0xf15113a0), WTC0(0xf128b5c0), WTC0(0xf0ff7fd0), WTC0(0xf0d56860), WTC0(0xf0aa6610), WTC0(0xf07e6fd0), WTC0(0xf0518190),
+ WTC0(0xf0239cd0), WTC0(0xeff4c320), WTC0(0xefc4f720), WTC0(0xef945080), WTC0(0xef62fce0), WTC0(0xef312a40), WTC0(0xeeff05c0), WTC0(0xeecca2c0),
+ WTC0(0xee99faa0), WTC0(0xee6705a0), WTC0(0xee33bb60), WTC0(0xee000060), WTC0(0xedcba660), WTC0(0xed967e80), WTC0(0xed605b80), WTC0(0xed293b40),
+ WTC0(0xecf146a0), WTC0(0xecb8a8a0), WTC0(0xec7f8bc0), WTC0(0xec461260), WTC0(0xec0c5720), WTC0(0xebd27440), WTC0(0xeb988220), WTC0(0xeb5e7040),
+ WTC0(0xeb2404c0), WTC0(0xeae90440), WTC0(0xeaad33c0), WTC0(0xea7066c0), WTC0(0xea327f60), WTC0(0xe9f36000), WTC0(0xe9b2ed60), WTC0(0xe9713920),
+ WTC0(0xe92e81e0), WTC0(0xe8eb08c0), WTC0(0xe8a70e60), WTC0(0xe862d8e0), WTC0(0xe81eb340), WTC0(0xe7dae8a0), WTC0(0xe797c1a0), WTC0(0xe7554ca0),
+ WTC0(0xe7135dc0), WTC0(0xe6d1c6a0), WTC0(0xe6905720), WTC0(0xe64eb9c0), WTC0(0xe60c7300), WTC0(0xe5c90600), WTC0(0xe583f920), WTC0(0xe53d1ce0),
+ WTC0(0xe4f48c80), WTC0(0xe4aa6640), WTC0(0xe45ecaa0), WTC0(0xe4120be0), WTC0(0xe3c4ae60), WTC0(0xe3773860), WTC0(0xe32a2ea0), WTC0(0xe2ddeea0),
+ WTC0(0xe292af00), WTC0(0xe248a4a0), WTC0(0xe2000140), WTC0(0xe1b8b640), WTC0(0xe1727440), WTC0(0xe12ce900), WTC0(0xe0e7c280), WTC0(0xe0a2b420),
+ WTC0(0xe05d76c0), WTC0(0xe017c360), WTC0(0xdfd15440), WTC0(0xdf8a0540), WTC0(0xdf41d300), WTC0(0xdef8bb40), WTC0(0xdeaebd40), WTC0(0xde63e7c0),
+ WTC0(0xde185940), WTC0(0xddcc3180), WTC0(0xdd7f9000), WTC0(0xdd329e80), WTC0(0xdce58e80), WTC0(0xdc989300), WTC0(0xdc4bde40), WTC0(0xdbff96c0),
+ WTC0(0xdbb3d780), WTC0(0xdb68bb80), WTC0(0xdb1e5c80), WTC0(0xdad4c380), WTC0(0xda8be840), WTC0(0xda43c1c0), WTC0(0xd9fc4740), WTC0(0xd9b56640),
+ WTC0(0xd96f0440), WTC0(0xd9290600), WTC0(0xd8e35080), WTC0(0xd89dcd40), WTC0(0xd8586b40), WTC0(0xd8131940), WTC0(0xd7cdc640), WTC0(0xd7886180),
+ WTC0(0xd742dc80), WTC0(0xd6fd2780), WTC0(0xd6b73400), WTC0(0xd670fd80), WTC0(0xd62a8a40), WTC0(0xd5e3e080), WTC0(0xd59d0840), WTC0(0xd5562b80),
+ WTC0(0xd50f9540), WTC0(0xd4c992c0), WTC0(0xd4846f80), WTC0(0xd4405a80), WTC0(0xd3fd6580), WTC0(0xd3bba140), WTC0(0xd37b1c80), WTC0(0xd33bb780),
+ WTC0(0xd2fd2400), WTC0(0xd2bf1240), WTC0(0xd2813300), WTC0(0xd2435ac0), WTC0(0xd2057fc0), WTC0(0xd1c79a00), WTC0(0xd189a240), WTC0(0xd14b9dc0),
+ WTC0(0xd10d9e00), WTC0(0xd0cfb580), WTC0(0xd091f6c0), WTC0(0xd0548100), WTC0(0xd0177f40), WTC0(0xcfdb1cc0), WTC0(0xcf9f84c0), WTC0(0xcf64d780),
+ WTC0(0xcf2b2b00), WTC0(0xcef29440), WTC0(0xcebb2640), WTC0(0xce84c000), WTC0(0xce4f0bc0), WTC0(0xce19b200), WTC0(0xcde45d40), WTC0(0xcdaeedc0),
+ WTC0(0xcd7979c0), WTC0(0xcd4419c0), WTC0(0xcd0ee6c0), WTC0(0xccda0540), WTC0(0xcca5a500), WTC0(0xcc71f640), WTC0(0xcc3f2800), WTC0(0xcc0d4300),
+ WTC0(0xcbdc2a00), WTC0(0xcbabbe80), WTC0(0xcb7be200), WTC0(0xcb4c8200), WTC0(0xcb1d9800), WTC0(0xcaef1d40), WTC0(0xcac10bc0), WTC0(0xca936440),
+ WTC0(0xca662d00), WTC0(0xca396d40), WTC0(0xca0d2b80), WTC0(0xc9e16f80), WTC0(0xc9b63f80), WTC0(0xc98ba2c0), WTC0(0xc961a000), WTC0(0xc9383ec0),
+ WTC0(0xc90a0440), WTC0(0xc8e0d280), WTC0(0xc8b73b80), WTC0(0xc88d4900), WTC0(0xc86304c0), WTC0(0xc83878c0), WTC0(0xc80dae80), WTC0(0xc7e2afc0),
+ WTC0(0xc7b78640), WTC0(0xc78c3c40), WTC0(0xc760da80), WTC0(0xc7356640), WTC0(0xc709de40), WTC0(0xc6de41c0), WTC0(0xc6b28fc0), WTC0(0xc686bd40),
+ WTC0(0xc65ab600), WTC0(0xc62e6580), WTC0(0xc601b880), WTC0(0xc5d4bac0), WTC0(0xc5a79640), WTC0(0xc57a76c0), WTC0(0xc54d8780), WTC0(0xc520e840),
+ WTC0(0xc4f4acc0), WTC0(0xc4c8e880), WTC0(0xc49dad80), WTC0(0xc472e640), WTC0(0xc44856c0), WTC0(0xc41dc140), WTC0(0xc3f2e940), WTC0(0xc3c7bc00),
+ WTC0(0xc39c4f00), WTC0(0xc370b9c0), WTC0(0xc34513c0), WTC0(0xc3197940), WTC0(0xc2ee0a00), WTC0(0xc2c2e640), WTC0(0xc2982d80), WTC0(0xc26df5c0),
+ WTC0(0xc2444b00), WTC0(0xc21b3940), WTC0(0xc1f2cbc0), WTC0(0xc1cb05c0), WTC0(0xc1a3e340), WTC0(0xc17d5f00), WTC0(0xc15773c0), WTC0(0xc1320940),
+ WTC0(0xc10cf480), WTC0(0xc0e80a00), WTC0(0xc0c31f00), WTC0(0xc09e2640), WTC0(0xc0792ec0), WTC0(0xc0544940), WTC0(0xc02f86c0), WTC0(0xc00b04c0),
+ WTC0(0xbfe6ed01), WTC0(0xbfc36a01), WTC0(0xbfa0a581), WTC0(0xbf7eb581), WTC0(0xbf5d9a81), WTC0(0xbf3d5501), WTC0(0xbf1de601), WTC0(0xbeff4801),
+ WTC0(0xbee17201), WTC0(0xbec45881), WTC0(0xbea7f301), WTC0(0xbe8c3781), WTC0(0xbe712001), WTC0(0xbe56a381), WTC0(0xbe3cbc01), WTC0(0xbe236001),
+ WTC0(0xbe0a8581), WTC0(0xbdf22181), WTC0(0xbdda2a01), WTC0(0xbdc29a81), WTC0(0xbdab7181), WTC0(0xbd94b001), WTC0(0xbd7e5581), WTC0(0xbd686681),
+ WTC0(0xbd52eb01), WTC0(0xbd3deb81), WTC0(0xbd297181), WTC0(0xbd158801), WTC0(0xbd023f01), WTC0(0xbcefa601), WTC0(0xbcddcc81), WTC0(0xbcccbd01),
+ WTC0(0xbcbc7e01), WTC0(0xbcad1501), WTC0(0xbc9e8801), WTC0(0xbc90d481), WTC0(0xbc83f201), WTC0(0xbc77d601), WTC0(0xbc6c7781), WTC0(0xbc61c401),
+ WTC0(0xbc57a301), WTC0(0xbc4dfb81), WTC0(0xbc44b481), WTC0(0xbc3bbc01), WTC0(0xbc330781), WTC0(0xbc2a8c81), WTC0(0xbc224181), WTC0(0xbc1a2401),
+ WTC0(0xbc123b81), WTC0(0xbc0a8f01), WTC0(0xbc032601), WTC0(0xbbfc0f81), WTC0(0xbbf56181), WTC0(0xbbef3301), WTC0(0xbbe99981), WTC0(0xbbe49d01),
+ WTC0(0xbbe03801), WTC0(0xbbdc6481), WTC0(0xbbd91b81), WTC0(0xbbd64d01), WTC0(0xbbd3e101), WTC0(0xbbd1bd81), WTC0(0xbbcfca81), WTC0(0xbbce0601),
+ WTC0(0xbbcc8201), WTC0(0xbbcb5301), WTC0(0xbbca8d01), WTC0(0xbbca5081), WTC0(0xbbcaca01), WTC0(0xbbcc2681), WTC0(0xbbce9181), WTC0(0xbbd21281),
+ WTC0(0xbbd68c81), WTC0(0xbbdbe201), WTC0(0xbbe1f401), WTC0(0xbbe89901), WTC0(0xbbef9b81), WTC0(0xbbf6c601), WTC0(0xbbfde481), WTC0(0xbc04e381),
+ WTC0(0xbc0bcf81), WTC0(0xbc12b801), WTC0(0xbc19ab01), WTC0(0xbc20ae01), WTC0(0xbc27bd81), WTC0(0xbc2ed681), WTC0(0xbc35f501), WTC0(0xbc3d1801),
+ WTC0(0xbc444081), WTC0(0xbc4b6e81), WTC0(0xbc52a381), WTC0(0xbc59df81), WTC0(0xbc612301), WTC0(0xbc686e01), WTC0(0xbc6fc101), WTC0(0xbc771c01),
+ WTC0(0xbc7e7e01), WTC0(0xbc85e801), WTC0(0xbc8d5901), WTC0(0xbc94d201), WTC0(0xbc9c5281), WTC0(0xbca3db01), WTC0(0xbcab6c01), WTC0(0xbcb30601),
+ WTC0(0xbcbaa801), WTC0(0xbcc25181), WTC0(0xbcca0301), WTC0(0xbcd1bb81), WTC0(0xbcd97c81), WTC0(0xbce14601), WTC0(0xbce91801), WTC0(0xbcf0f381),
+ WTC0(0xbcf8d781), WTC0(0xbd00c381), WTC0(0xbd08b781), WTC0(0xbd10b381), WTC0(0xbd18b781), WTC0(0xbd20c401), WTC0(0xbd28d981), WTC0(0xbd30f881),
+ WTC0(0xbd391f81), WTC0(0xbd414f01), WTC0(0xbd498601), WTC0(0xbd51c481), WTC0(0xbd5a0b01), WTC0(0xbd625981), WTC0(0xbd6ab101), WTC0(0xbd731081),
+ WTC0(0xbd7b7781), WTC0(0xbd83e681), WTC0(0xbd8c5c01), WTC0(0xbd94d801), WTC0(0xbd9d5b81), WTC0(0xbda5e601), WTC0(0xbdae7881), WTC0(0xbdb71201),
+ WTC0(0xbdbfb281), WTC0(0xbdc85981), WTC0(0xbdd10681), WTC0(0xbdd9b981), WTC0(0xbde27201), WTC0(0xbdeb3101), WTC0(0xbdf3f701), WTC0(0xbdfcc301),
+ WTC0(0xbe059481), WTC0(0xbe0e6c01), WTC0(0xbe174781), WTC0(0xbe202801), WTC0(0xbe290d01), WTC0(0xbe31f701), WTC0(0xbe3ae601), WTC0(0xbe43da81),
+ WTC0(0xbe4cd381), WTC0(0xbe55d001), WTC0(0xbe5ed081), WTC0(0xbe67d381), WTC0(0xbe70da01), WTC0(0xbe79e481), WTC0(0xbe82f301), WTC0(0xbe8c0501),
+ WTC0(0xbe951a81), WTC0(0xbe9e3281), WTC0(0xbea74c81), WTC0(0xbeb06881), WTC0(0xbeb98681), WTC0(0xbec2a781), WTC0(0xbecbca81), WTC0(0xbed4f081),
+ WTC0(0xbede1901), WTC0(0xbee74281), WTC0(0xbef06d01), WTC0(0xbef99901), WTC0(0xbf02c581), WTC0(0xbf0bf381), WTC0(0xbf152381), WTC0(0xbf1e5501),
+ WTC0(0xbf278801), WTC0(0xbf30bb01), WTC0(0xbf39ee81), WTC0(0xbf432281), WTC0(0xbf4c5681), WTC0(0xbf558b01), WTC0(0xbf5ec101), WTC0(0xbf67f801),
+ WTC0(0xbf712f01), WTC0(0xbf7a6681), WTC0(0xbf839d81), WTC0(0xbf8cd481), WTC0(0xbf960b01), WTC0(0xbf9f4181), WTC0(0xbfa87901), WTC0(0xbfb1b101),
+ WTC0(0xbfbae981), WTC0(0xbfc42201), WTC0(0xbfcd5a01), WTC0(0xbfd69101), WTC0(0xbfdfc781), WTC0(0xbfe8fc01), WTC0(0xbff22f81), WTC0(0xbffb6081),
+ /* part 1 */
+ WTC1(0x80093e01), WTC1(0x801b9b01), WTC1(0x802df701), WTC1(0x80405101), WTC1(0x8052a881), WTC1(0x8064fc81), WTC1(0x80774c81), WTC1(0x80899881),
+ WTC1(0x809bdf01), WTC1(0x80ae1f81), WTC1(0x80c05a01), WTC1(0x80d28d81), WTC1(0x80e4bb81), WTC1(0x80f6e481), WTC1(0x81090981), WTC1(0x811b2981),
+ WTC1(0x812d4481), WTC1(0x813f5981), WTC1(0x81516701), WTC1(0x81636d81), WTC1(0x81756d81), WTC1(0x81876781), WTC1(0x81995c01), WTC1(0x81ab4b01),
+ WTC1(0x81bd3401), WTC1(0x81cf1581), WTC1(0x81e0ee81), WTC1(0x81f2bf81), WTC1(0x82048881), WTC1(0x82164a81), WTC1(0x82280581), WTC1(0x8239b981),
+ WTC1(0x824b6601), WTC1(0x825d0901), WTC1(0x826ea201), WTC1(0x82803101), WTC1(0x8291b601), WTC1(0x82a33281), WTC1(0x82b4a601), WTC1(0x82c61101),
+ WTC1(0x82d77201), WTC1(0x82e8c801), WTC1(0x82fa1181), WTC1(0x830b4f81), WTC1(0x831c8101), WTC1(0x832da781), WTC1(0x833ec381), WTC1(0x834fd481),
+ WTC1(0x8360d901), WTC1(0x8371d081), WTC1(0x8382ba01), WTC1(0x83939501), WTC1(0x83a46181), WTC1(0x83b52101), WTC1(0x83c5d381), WTC1(0x83d67881),
+ WTC1(0x83e70f01), WTC1(0x83f79681), WTC1(0x84080d81), WTC1(0x84187401), WTC1(0x8428ca01), WTC1(0x84391081), WTC1(0x84494881), WTC1(0x84597081),
+ WTC1(0x84698881), WTC1(0x84798f81), WTC1(0x84898481), WTC1(0x84996701), WTC1(0x84a93801), WTC1(0x84b8f801), WTC1(0x84c8a701), WTC1(0x84d84601),
+ WTC1(0x84e7d381), WTC1(0x84f74e01), WTC1(0x8506b581), WTC1(0x85160981), WTC1(0x85254a81), WTC1(0x85347901), WTC1(0x85439601), WTC1(0x8552a181),
+ WTC1(0x85619a01), WTC1(0x85707f81), WTC1(0x857f5101), WTC1(0x858e0e01), WTC1(0x859cb781), WTC1(0x85ab4f01), WTC1(0x85b9d481), WTC1(0x85c84801),
+ WTC1(0x85d6a981), WTC1(0x85e4f801), WTC1(0x85f33281), WTC1(0x86015981), WTC1(0x860f6e01), WTC1(0x861d7081), WTC1(0x862b6201), WTC1(0x86394301),
+ WTC1(0x86471281), WTC1(0x8654d001), WTC1(0x86627b01), WTC1(0x86701381), WTC1(0x867d9a81), WTC1(0x868b1001), WTC1(0x86987581), WTC1(0x86a5ca81),
+ WTC1(0x86b30f01), WTC1(0x86c04381), WTC1(0x86cd6681), WTC1(0x86da7901), WTC1(0x86e77b81), WTC1(0x86f46d81), WTC1(0x87014f81), WTC1(0x870e2301),
+ WTC1(0x871ae981), WTC1(0x8727a381), WTC1(0x87345381), WTC1(0x8740f681), WTC1(0x874d8681), WTC1(0x8759fd01), WTC1(0x87665481), WTC1(0x87729701),
+ WTC1(0x877ede01), WTC1(0x878b4301), WTC1(0x8797dd81), WTC1(0x87a48b01), WTC1(0x87b0ef01), WTC1(0x87bcab81), WTC1(0x87c76201), WTC1(0x87d0ca81),
+ WTC1(0x87fdd781), WTC1(0x881dd301), WTC1(0x88423301), WTC1(0x886a8a81), WTC1(0x88962981), WTC1(0x88c45e81), WTC1(0x88f47901), WTC1(0x8925f101),
+ WTC1(0x89586901), WTC1(0x898b8301), WTC1(0x89bee581), WTC1(0x89f26101), WTC1(0x8a25f301), WTC1(0x8a599a81), WTC1(0x8a8d5801), WTC1(0x8ac13381),
+ WTC1(0x8af53e81), WTC1(0x8b298b81), WTC1(0x8b5e2c81), WTC1(0x8b933001), WTC1(0x8bc8a401), WTC1(0x8bfe9401), WTC1(0x8c350d01), WTC1(0x8c6c1b01),
+ WTC1(0x8ca3cb01), WTC1(0x8cdc2901), WTC1(0x8d154081), WTC1(0x8d4f1b01), WTC1(0x8d89be81), WTC1(0x8dc53001), WTC1(0x8e017581), WTC1(0x8e3e9481),
+ WTC1(0x8e7c9301), WTC1(0x8ebb7581), WTC1(0x8efb4181), WTC1(0x8f3bfb01), WTC1(0x8f7da401), WTC1(0x8fc03f01), WTC1(0x9003ce81), WTC1(0x90485401),
+ WTC1(0x908dd101), WTC1(0x90d44781), WTC1(0x911bb981), WTC1(0x91642781), WTC1(0x91ad9281), WTC1(0x91f7f981), WTC1(0x92435d01), WTC1(0x928fbe01),
+ WTC1(0x92dd1b01), WTC1(0x932b7501), WTC1(0x937acb01), WTC1(0x93cb1c81), WTC1(0x941c6901), WTC1(0x946eaf81), WTC1(0x94c1ee01), WTC1(0x95162381),
+ WTC1(0x956b4f81), WTC1(0x95c17081), WTC1(0x96188501), WTC1(0x96708b81), WTC1(0x96c98381), WTC1(0x97236b01), WTC1(0x977e4181), WTC1(0x97da0481),
+ WTC1(0x9836b201), WTC1(0x98944901), WTC1(0x98f2c601), WTC1(0x99522801), WTC1(0x99b26c81), WTC1(0x9a139101), WTC1(0x9a759301), WTC1(0x9ad87081),
+ WTC1(0x9b3c2801), WTC1(0x9ba0b701), WTC1(0x9c061b81), WTC1(0x9c6c5481), WTC1(0x9cd35f81), WTC1(0x9d3b3b81), WTC1(0x9da3e601), WTC1(0x9e0d5e01),
+ WTC1(0x9e779f81), WTC1(0x9ee2a901), WTC1(0x9f4e7801), WTC1(0x9fbb0981), WTC1(0xa0285d81), WTC1(0xa0967201), WTC1(0xa1054701), WTC1(0xa174da81),
+ WTC1(0xa1e52a81), WTC1(0xa2563501), WTC1(0xa2c7f801), WTC1(0xa33a7201), WTC1(0xa3ada281), WTC1(0xa4218801), WTC1(0xa4962181), WTC1(0xa50b6e81),
+ WTC1(0xa5816e81), WTC1(0xa5f81f81), WTC1(0xa66f8201), WTC1(0xa6e79401), WTC1(0xa7605601), WTC1(0xa7d9c681), WTC1(0xa853e501), WTC1(0xa8ceb201),
+ WTC1(0xa94a2c01), WTC1(0xa9c65401), WTC1(0xaa432981), WTC1(0xaac0ad01), WTC1(0xab3edf01), WTC1(0xabbdc001), WTC1(0xac3d5001), WTC1(0xacbd9081),
+ WTC1(0xad3e8101), WTC1(0xadc02281), WTC1(0xae427481), WTC1(0xaec57801), WTC1(0xaf492f01), WTC1(0xafcd9a81), WTC1(0xb052bc01), WTC1(0xb0d89401),
+ WTC1(0xb15f2381), WTC1(0xb1e66a01), WTC1(0xb26e6881), WTC1(0xb2f71f01), WTC1(0xb3808d81), WTC1(0xb40ab501), WTC1(0xb4959501), WTC1(0xb5212e81),
+ WTC1(0x4a6cf67f), WTC1(0x49dffeff), WTC1(0x495265ff), WTC1(0x48c4277f), WTC1(0x4835407f), WTC1(0x47a5aeff), WTC1(0x471570ff), WTC1(0x468484ff),
+ WTC1(0x45f2eaff), WTC1(0x4560a2ff), WTC1(0x44cdad7f), WTC1(0x443a0c7f), WTC1(0x43a5c07f), WTC1(0x4310caff), WTC1(0x427b2bff), WTC1(0x41e4e3ff),
+ WTC1(0x414df2ff), WTC1(0x40b6557f), WTC1(0x401e06ff), WTC1(0x3f8503c0), WTC1(0x3eeb4e00), WTC1(0x3e50ebc0), WTC1(0x3db5e680), WTC1(0x3d1a4680),
+ WTC1(0x3c7e10c0), WTC1(0x3be14cc0), WTC1(0x3b4402c0), WTC1(0x3aa63800), WTC1(0x3a07e840), WTC1(0x39690880), WTC1(0x38c98700), WTC1(0x38295b40),
+ WTC1(0x37888a80), WTC1(0x36e71d40), WTC1(0x36451d80), WTC1(0x35a29400), WTC1(0x34ff8800), WTC1(0x345c04c0), WTC1(0x33b81940), WTC1(0x3313d200),
+ WTC1(0x326f3800), WTC1(0x31ca5600), WTC1(0x31253840), WTC1(0x307fe8c0), WTC1(0x2fda6e40), WTC1(0x2f34ce40), WTC1(0x2e8f0e40), WTC1(0x2de92ec0),
+ WTC1(0x2d432780), WTC1(0x2c9cea40), WTC1(0x2bf66300), WTC1(0x2b4f88c0), WTC1(0x2aa864c0), WTC1(0x2a010240), WTC1(0x29596e40), WTC1(0x28b1ba80),
+ WTC1(0x2809ff40), WTC1(0x27625b80), WTC1(0x26baf580), WTC1(0x2613e7c0), WTC1(0x256d3dc0), WTC1(0x24c70300), WTC1(0x24214380), WTC1(0x237c0800),
+ WTC1(0x22d75400), WTC1(0x22332a80), WTC1(0x218f8cc0), WTC1(0x20ec7e40), WTC1(0x204a04c0), WTC1(0x1fa82540), WTC1(0x1f06e300), WTC1(0x1e664000),
+ WTC1(0x1dc63bc0), WTC1(0x1d26d3c0), WTC1(0x1c8803a0), WTC1(0x1be9cc40), WTC1(0x1b4c34c0), WTC1(0x1aaf4480), WTC1(0x1a130260), WTC1(0x197774a0),
+ WTC1(0x18dca260), WTC1(0x184294e0), WTC1(0x17a95840), WTC1(0x1710fd80), WTC1(0x16799ce0), WTC1(0x15e35340), WTC1(0x154e41a0), WTC1(0x14ba8360),
+ WTC1(0x14282be0), WTC1(0x13975100), WTC1(0x13080aa0), WTC1(0x127a6240), WTC1(0x11ee50a0), WTC1(0x1163cc80), WTC1(0x10dacb20), WTC1(0x105333a0),
+ WTC1(0x0fccdb30), WTC1(0x0f478f40), WTC1(0x0ec31700), WTC1(0x0e3f4e80), WTC1(0x0dbc27f0), WTC1(0x0d399000), WTC1(0x0cb76d00), WTC1(0x0c359d50),
+ WTC1(0x0bb3fd50), WTC1(0x0b326bd0), WTC1(0x0ab0ca80), WTC1(0x0a2f0dc0), WTC1(0x09ad40c0), WTC1(0x092b7a90), WTC1(0x08a9db80), WTC1(0x08285c80),
+ WTC1(0x07a6c7b8), WTC1(0x0724e4e0), WTC1(0x06a27b80), WTC1(0x061f52f8), WTC1(0x059b2ad0), WTC1(0x0515b568), WTC1(0x048ea058), WTC1(0x04066408),
+ WTC1(0x037e52d8), WTC1(0x02f7d3c8), WTC1(0x0274614c), WTC1(0x01f63008), WTC1(0x0180403a), WTC1(0x0115c442), WTC1(0x00ba09e2), WTC1(0x006f077c),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ /* part 2 */
+ WTC2(0xfff36be1), WTC2(0xffdafbc1), WTC2(0xffc28035), WTC2(0xffa9fe8a), WTC2(0xff917c08), WTC2(0xff78fdfc), WTC2(0xff6089af), WTC2(0xff48246c),
+ WTC2(0xff2fd37f), WTC2(0xff179c31), WTC2(0xfeff83b6), WTC2(0xfee78d18), WTC2(0xfecfb93e), WTC2(0xfeb808f2), WTC2(0xfea07d06), WTC2(0xfe8916b4),
+ WTC2(0xfe71d7a0), WTC2(0xfe5ac174), WTC2(0xfe43d5d6), WTC2(0xfe2d167e), WTC2(0xfe16852e), WTC2(0xfe0023a6), WTC2(0xfde9f3f8), WTC2(0xfdd3ff7c),
+ WTC2(0xfdbe56c0), WTC2(0xfda90aa8), WTC2(0xfd942b78), WTC2(0xfd7fbb20), WTC2(0xfd6bad50), WTC2(0xfd57f510), WTC2(0xfd44857c), WTC2(0xfd3153fc),
+ WTC2(0xfd1e5840), WTC2(0xfd0b8a0c), WTC2(0xfcf8e180), WTC2(0xfce65eec), WTC2(0xfcd40ad0), WTC2(0xfcc1ee0c), WTC2(0xfcb011e8), WTC2(0xfc9e896c),
+ WTC2(0xfc8d716c), WTC2(0xfc7ce720), WTC2(0xfc6d072c), WTC2(0xfc5de09c), WTC2(0xfc4f74e8), WTC2(0xfc41c4e8), WTC2(0xfc34d0dc), WTC2(0xfc288a68),
+ WTC2(0xfc1cd49c), WTC2(0xfc1191e0), WTC2(0xfc06a4d0), WTC2(0xfbfbf3e8), WTC2(0xfbf16990), WTC2(0xfbe6f068), WTC2(0xfbdc7428), WTC2(0xfbd1fc68),
+ WTC2(0xfbc7ac50), WTC2(0xfbbda868), WTC2(0xfbb41500), WTC2(0xfbab1438), WTC2(0xfba2c5f8), WTC2(0xfb9b4a00), WTC2(0xfb94bfa8), WTC2(0xfb8f3b48),
+ WTC2(0xfb8ac638), WTC2(0xfb876970), WTC2(0xfb852d20), WTC2(0xfb840ae0), WTC2(0xfb83ed60), WTC2(0xfb84bec0), WTC2(0xfb866918), WTC2(0xfb88d4a8),
+ WTC2(0xfb8be810), WTC2(0xfb8f89d0), WTC2(0xfb93a080), WTC2(0xfb981418), WTC2(0xfb9ccdf0), WTC2(0xfba1b770), WTC2(0xfba6bae0), WTC2(0xfbabd5c0),
+ WTC2(0xfbb118d8), WTC2(0xfbb695c0), WTC2(0xfbbc5e90), WTC2(0xfbc29030), WTC2(0xfbc95268), WTC2(0xfbd0cd78), WTC2(0xfbd929c8), WTC2(0xfbe294d0),
+ WTC2(0xfbed4108), WTC2(0xfbf96118), WTC2(0xfc0726c8), WTC2(0xfc16b064), WTC2(0xfc280890), WTC2(0xfc3b3920), WTC2(0xfc504a98), WTC2(0xfc67271c),
+ WTC2(0xfc7f9a74), WTC2(0xfc996f18), WTC2(0xfcb46eb8), WTC2(0xfcd050b0), WTC2(0xfcecba24), WTC2(0xfd094f64), WTC2(0xfd25b720), WTC2(0xfd41ce40),
+ WTC2(0xfd5da7f8), WTC2(0xfd7959d8), WTC2(0xfd94fb74), WTC2(0xfdb0d3fc), WTC2(0xfdcd5a34), WTC2(0xfdeb06e4), WTC2(0xfe0a5184), WTC2(0xfe2b92c4),
+ WTC2(0xfe4f0486), WTC2(0xfe74df54), WTC2(0xfe9d5886), WTC2(0xfec85b92), WTC2(0xfef58a16), WTC2(0xff248275), WTC2(0xff54e401), WTC2(0xff866330),
+ WTC2(0xffb8c99b), WTC2(0xffebe1c9), WTC2(0x001f786a), WTC2(0x00538bf9), WTC2(0x00884cbc), WTC2(0x00bded23), WTC2(0x00f49f54), WTC2(0x012c8ee4),
+ WTC2(0x0165e0d2), WTC2(0x01a0b9d6), WTC2(0x01dd3d80), WTC2(0x021b74d4), WTC2(0x025b4e48), WTC2(0x029cb730), WTC2(0x02df9d0c), WTC2(0x0323f1a4),
+ WTC2(0x0369ab00), WTC2(0x03b0bf5c), WTC2(0x03f925a0), WTC2(0x0442e3d8), WTC2(0x048e0f40), WTC2(0x04dabdb0), WTC2(0x05290430), WTC2(0x0578e428),
+ WTC2(0x05ca4b60), WTC2(0x061d26c0), WTC2(0x067163d8), WTC2(0x06c6ff10), WTC2(0x071e03b0), WTC2(0x07767da0), WTC2(0x07d07918), WTC2(0x082c08e0),
+ WTC2(0x08894660), WTC2(0x08e84b70), WTC2(0x094930b0), WTC2(0x09abf8d0), WTC2(0x0a109020), WTC2(0x0a76e210), WTC2(0x0adeda50), WTC2(0x0b486b80),
+ WTC2(0x0bb38f00), WTC2(0x0c203e80), WTC2(0x0c8e73e0), WTC2(0x0cfe2c30), WTC2(0x0d6f6820), WTC2(0x0de22850), WTC2(0x0e566d90), WTC2(0x0ecc3dd0),
+ WTC2(0x0f43a3a0), WTC2(0x0fbca9f0), WTC2(0x10375b80), WTC2(0x10b3be20), WTC2(0x1131d280), WTC2(0x11b19960), WTC2(0x123313a0), WTC2(0x12b64380),
+ WTC2(0x133b2d00), WTC2(0x13c1d440), WTC2(0x144a3d60), WTC2(0x14d46900), WTC2(0x15605480), WTC2(0x15edfd20), WTC2(0x167d6040), WTC2(0x170e7e80),
+ WTC2(0x17a15b80), WTC2(0x1835fb00), WTC2(0x18cc60a0), WTC2(0x19648dc0), WTC2(0x19fe80e0), WTC2(0x1a9a38a0), WTC2(0x1b37b3e0), WTC2(0x1bd6f400),
+ WTC2(0x1c77fd20), WTC2(0x1d1ad400), WTC2(0x1dbf7c80), WTC2(0x1e65f820), WTC2(0x1f0e4540), WTC2(0x1fb861e0), WTC2(0x20644cc0), WTC2(0x21120640),
+ WTC2(0x21c19240), WTC2(0x2272f480), WTC2(0x23263000), WTC2(0x23db4580), WTC2(0x24923340), WTC2(0x254af700), WTC2(0x26058e80), WTC2(0x26c1fa00),
+ WTC2(0x27803d00), WTC2(0x28405a40), WTC2(0x29025500), WTC2(0x29c62d40), WTC2(0x2a8be0c0), WTC2(0x2b536cc0), WTC2(0x2c1ccf80), WTC2(0x2ce80840),
+ WTC2(0x2db519c0), WTC2(0x2e840600), WTC2(0x2f54cf80), WTC2(0x302775c0), WTC2(0x30fbf640), WTC2(0x31d24e00), WTC2(0x32aa7a00), WTC2(0x338479c0),
+ WTC2(0x34604e40), WTC2(0x353df900), WTC2(0x361d7ac0), WTC2(0x36fed200), WTC2(0x37e1fb40), WTC2(0x38c6f240), WTC2(0x39adb2c0), WTC2(0x3a963a00),
+ WTC2(0x3b808740), WTC2(0x3c6c9880), WTC2(0x3d5a6cc0), WTC2(0x3e4a0040), WTC2(0x3f3b4bc0), WTC2(0x402e48ff), WTC2(0x4122f17f), WTC2(0x42193f7f),
+ WTC2(0x43112eff), WTC2(0x440abbff), WTC2(0x4505e2ff), WTC2(0x46029e7f), WTC2(0x4700e9ff), WTC2(0x4800bfff), WTC2(0x49021bff), WTC2(0x4a050eff),
+ WTC2(0x4b09bc7f), WTC2(0x4c104aff), WTC2(0x4d18df7f), WTC2(0x4e23a07f), WTC2(0x4f30b2ff), WTC2(0x50403c7f), WTC2(0x515262ff), WTC2(0x52674b7f),
+ WTC2(0x001678b2), WTC2(0x00061a3b), WTC2(0xfffb4622), WTC2(0xfff5ea94), WTC2(0xfff5f5b9), WTC2(0xfffb55bd), WTC2(0x0005f8cb), WTC2(0x0015cd0c),
+ WTC2(0x002ac0ac), WTC2(0x0044c1d5), WTC2(0x0063beb2), WTC2(0x0087a56d), WTC2(0x00b06431), WTC2(0x00dde929), WTC2(0x01102280), WTC2(0x0146fe5e),
+ WTC2(0x01826af2), WTC2(0x01c25662), WTC2(0x0206aedc), WTC2(0x024f6288), WTC2(0x029c5f94), WTC2(0x02ed9424), WTC2(0x0342ee6c), WTC2(0x039c5c90),
+ WTC2(0x03f9ccbc), WTC2(0x045b2d18), WTC2(0x04c06bd8), WTC2(0x05297718), WTC2(0x05963d10), WTC2(0x0606abe8), WTC2(0x067ab1c0), WTC2(0x06f23cd0),
+ WTC2(0x076d3b40), WTC2(0x07eb9b38), WTC2(0x086d4ae0), WTC2(0x08f23860), WTC2(0x097a51f0), WTC2(0x0a0585b0), WTC2(0x0a93c1d0), WTC2(0x0b24f470),
+ WTC2(0x0bb90bc0), WTC2(0x0c4ff5f0), WTC2(0x0ce9a130), WTC2(0x0d85fb90), WTC2(0x0e24f360), WTC2(0x0ec676b0), WTC2(0x0f6a73b0), WTC2(0x1010d880),
+ WTC2(0x10b99360), WTC2(0x11649280), WTC2(0x1211c400), WTC2(0x12c115e0), WTC2(0x137276a0), WTC2(0x1425d420), WTC2(0x14db1ca0), WTC2(0x15923e60),
+ WTC2(0x164b2780), WTC2(0x1705c620), WTC2(0x17c20860), WTC2(0x187fdca0), WTC2(0x193f30e0), WTC2(0x19fff340), WTC2(0x1ac21200), WTC2(0x1b857b40),
+ WTC2(0x1c4a1d40), WTC2(0x1d0fe600), WTC2(0x1dd6c3e0), WTC2(0x1e9ea4e0), WTC2(0x1f677740), WTC2(0x20312940), WTC2(0x20fba8c0), WTC2(0x21c6e440),
+ WTC2(0x2292c9c0), WTC2(0x235f4780), WTC2(0x242c4b80), WTC2(0x24f9c400), WTC2(0x25c79f40), WTC2(0x2695cb40), WTC2(0x27643680), WTC2(0x2832cec0),
+ WTC2(0x29018240), WTC2(0x29d03f80), WTC2(0x2a9ef480), WTC2(0x2b6d8f00), WTC2(0x2c3bfdc0), WTC2(0x2d0a2ec0), WTC2(0x2dd81000), WTC2(0x2ea58fc0),
+ WTC2(0x2f729c40), WTC2(0x303f2380), WTC2(0x310b1400), WTC2(0x31d65b80), WTC2(0x32a0e840), WTC2(0x336aa8c0), WTC2(0x34338ac0), WTC2(0x34fb7cc0),
+ WTC2(0x35c26cc0), WTC2(0x36884900), WTC2(0x374cff80), WTC2(0x38107e80), WTC2(0x38d2b440), WTC2(0x39938ec0), WTC2(0x3a52fc40), WTC2(0x3b10eb00),
+ WTC2(0x3bcd4900), WTC2(0x3c880480), WTC2(0x3d410bc0), WTC2(0x3df84d00), WTC2(0x3eadb600), WTC2(0x3f613540), WTC2(0x4012b8ff), WTC2(0x40c22eff),
+ WTC2(0x416f85ff), WTC2(0x421aab7f), WTC2(0x42c38e7f), WTC2(0x436a1c7f), WTC2(0x440e437f), WTC2(0x44aff27f), WTC2(0x454f167f), WTC2(0x45eb9eff),
+ WTC2(0x468578ff), WTC2(0x471c937f), WTC2(0x47b0dc7f), WTC2(0x484241ff), WTC2(0x48d0b1ff), WTC2(0x495c1a7f), WTC2(0x49e46a7f), WTC2(0x4a698f7f),
+ WTC2(0x4aeb77ff), WTC2(0x4b6a11ff), WTC2(0x4be54b7f), WTC2(0x4c5d12ff), WTC2(0x4cd155ff), WTC2(0x4d4203ff), WTC2(0x4daf09ff), WTC2(0x4e18567f),
+ WTC2(0x4e7dd77f), WTC2(0x4edf7b7f), WTC2(0x4f3d307f), WTC2(0x4f96e47f), WTC2(0x4fec85ff), WTC2(0x503e02ff), WTC2(0x508b497f), WTC2(0x50d447ff),
+ WTC2(0x5118ec7f), WTC2(0x515924ff), WTC2(0x5194dfff), WTC2(0x51cc0b7f), WTC2(0x51fe95ff), WTC2(0x522c6cff), WTC2(0x52557eff), WTC2(0x5279b9ff),
+ WTC2(0x52990c7f), WTC2(0x52b364ff), WTC2(0x52c8b07f), WTC2(0x52d8ddff), WTC2(0x52e3db7f), WTC2(0x52e996ff), WTC2(0x52e9ff7f), WTC2(0x52e501ff),
+ WTC2(0x52da8cff), WTC2(0x52ca8f7f), WTC2(0x52b4f67f), WTC2(0x5299b07f), WTC2(0x5278ac7f), WTC2(0x5251d77f), WTC2(0x52251fff), WTC2(0x51f274ff),
+ WTC2(0x51b9c37f), WTC2(0x517af9ff), WTC2(0x5136077f), WTC2(0x50ead8ff), WTC2(0x50995cff), WTC2(0x504181ff), WTC2(0x4fe335ff), WTC2(0x4f7e677f),
+ WTC2(0x4f1303ff), WTC2(0x4ea0f9ff), WTC2(0x4e2837ff), WTC2(0x4da8ab7f), WTC2(0x4d2242ff), WTC2(0x4c94ecff), WTC2(0x4c0096ff), WTC2(0x4b652f7f),
+ WTC2(0x4ac2a4ff), WTC2(0x4a18e4ff), WTC2(0x4967ddff), WTC2(0x48af7e7f), WTC2(0x47efb3ff), WTC2(0x47286cff), WTC2(0x4659ad7f), WTC2(0x45856f7f),
+ WTC2(0x44afa3ff), WTC2(0x43dc507f), WTC2(0x430f657f), WTC2(0x424ad47f), WTC2(0x418e927f), WTC2(0x40da7bff), WTC2(0x402e6f7f), WTC2(0x3f8a3100),
+ WTC2(0x3eed6f40), WTC2(0x3e57d700), WTC2(0x3dc914c0), WTC2(0x3d40cc40), WTC2(0x3cbe98c0), WTC2(0x3c421540), WTC2(0x3bcadbc0), WTC2(0x3b588880),
+ WTC2(0x3aeab780), WTC2(0x3a810540), WTC2(0x3a1b0e00), WTC2(0x39b86d00), WTC2(0x3958bcc0), WTC2(0x38fb9700), WTC2(0x38a095c0), WTC2(0x38473d80),
+ WTC2(0x37eeff40), WTC2(0x37974b40), WTC2(0x373f9500), WTC2(0x36e7ae00), WTC2(0x368fc4c0), WTC2(0x36380b80), WTC2(0x35e0b300), WTC2(0x3589c140),
+ WTC2(0x35331180), WTC2(0x34dc7c80), WTC2(0x3485dc80), WTC2(0x342f1600), WTC2(0x33d81780), WTC2(0x3380d0c0), WTC2(0x33293100), WTC2(0x32d11800),
+ WTC2(0x32785780), WTC2(0x321ec0c0), WTC2(0x31c42680), WTC2(0x316885c0), WTC2(0x310c0580), WTC2(0x30aecec0), WTC2(0x30510940), WTC2(0x2ff2b8c0),
+ WTC2(0x2f93bf40), WTC2(0x2f33fc00), WTC2(0x2ed350c0), WTC2(0x2e71ba80), WTC2(0x2e0f5340), WTC2(0x2dac35c0), WTC2(0x2d487c80), WTC2(0x2ce431c0),
+ WTC2(0x2c7f4fc0), WTC2(0x2c19d080), WTC2(0x2bb3ad80), WTC2(0x2b4ce080), WTC2(0x2ae56340), WTC2(0x2a7d2f80), WTC2(0x2a143f00), WTC2(0x29aa8b40)
+};
+
+const FIXP_WTB ELDAnalysis480[1440] = {
+ WTC0(0xfacfbef0), WTC0(0xfab88c18), WTC0(0xfaa0e520), WTC0(0xfa88d110), WTC0(0xfa7056e8), WTC0(0xfa577db0), WTC0(0xfa3e4c70), WTC0(0xfa24ca28),
+ WTC0(0xfa0afde0), WTC0(0xf9f0eea0), WTC0(0xf9d6a2c8), WTC0(0xf9bc1ab8), WTC0(0xf9a15230), WTC0(0xf9864510), WTC0(0xf96af058), WTC0(0xf94f55c0),
+ WTC0(0xf93378e0), WTC0(0xf9175d80), WTC0(0xf8fb0468), WTC0(0xf8de68b8), WTC0(0xf8c18438), WTC0(0xf8a450d8), WTC0(0xf886cde8), WTC0(0xf8690148),
+ WTC0(0xf84af148), WTC0(0xf82ca410), WTC0(0xf80e1e18), WTC0(0xf7ef62a0), WTC0(0xf7d074e0), WTC0(0xf7b15870), WTC0(0xf7921240), WTC0(0xf772a7a0),
+ WTC0(0xf7531e50), WTC0(0xf7337820), WTC0(0xf713afd0), WTC0(0xf6f3bea0), WTC0(0xf6d39dc0), WTC0(0xf6b352e0), WTC0(0xf692f280), WTC0(0xf6729250),
+ WTC0(0xf65247a0), WTC0(0xf63224c0), WTC0(0xf6123a00), WTC0(0xf5f297c0), WTC0(0xf5d34dd0), WTC0(0xf5b46b10), WTC0(0xf595fd90), WTC0(0xf5781390),
+ WTC0(0xf55abba0), WTC0(0xf53e0510), WTC0(0xf521ff70), WTC0(0xf506ba30), WTC0(0xf4ec4330), WTC0(0xf4d2a680), WTC0(0xf4b9efe0), WTC0(0xf4a22ac0),
+ WTC0(0xf48b5f70), WTC0(0xf4759310), WTC0(0xf460cde0), WTC0(0xf44cfcc0), WTC0(0xf439aff0), WTC0(0xf4264e00), WTC0(0xf4123d90), WTC0(0xf3fd1370),
+ WTC0(0xf3e6be00), WTC0(0xf3cf41a0), WTC0(0xf3b6a030), WTC0(0xf39cdd60), WTC0(0xf381fe00), WTC0(0xf3660760), WTC0(0xf348fe70), WTC0(0xf32ae820),
+ WTC0(0xf30bc940), WTC0(0xf2eba690), WTC0(0xf2ca8480), WTC0(0xf2a86670), WTC0(0xf2854f40), WTC0(0xf2614190), WTC0(0xf23c41e0), WTC0(0xf21657a0),
+ WTC0(0xf1ef8ae0), WTC0(0xf1c7e3e0), WTC0(0xf19f63d0), WTC0(0xf1760450), WTC0(0xf14bbdf0), WTC0(0xf1208960), WTC0(0xf0f45cd0), WTC0(0xf0c72ce0),
+ WTC0(0xf098ee00), WTC0(0xf06996f0), WTC0(0xf0392620), WTC0(0xf0079e10), WTC0(0xefd4ffc0), WTC0(0xefa15ca0), WTC0(0xef6ce600), WTC0(0xef37d460),
+ WTC0(0xef025f80), WTC0(0xeecca2c0), WTC0(0xee969760), WTC0(0xee603440), WTC0(0xee296d20), WTC0(0xedf21c00), WTC0(0xedba07e0), WTC0(0xed80f640),
+ WTC0(0xed46bf40), WTC0(0xed0b7b00), WTC0(0xeccf5fc0), WTC0(0xec92a120), WTC0(0xec556d60), WTC0(0xec17e700), WTC0(0xebda2d40), WTC0(0xeb9c5fa0),
+ WTC0(0xeb5e7040), WTC0(0xeb201b20), WTC0(0xeae117c0), WTC0(0xeaa12000), WTC0(0xea600180), WTC0(0xea1d9940), WTC0(0xe9d9c160), WTC0(0xe99468a0),
+ WTC0(0xe94dc040), WTC0(0xe9061940), WTC0(0xe8bdc140), WTC0(0xe8750ae0), WTC0(0xe82c4fa0), WTC0(0xe7e3ea40), WTC0(0xe79c35e0), WTC0(0xe7554ca0),
+ WTC0(0xe70efc00), WTC0(0xe6c90c20), WTC0(0xe6833f00), WTC0(0xe63d2300), WTC0(0xe5f620a0), WTC0(0xe5ad9dc0), WTC0(0xe5632080), WTC0(0xe5169da0),
+ WTC0(0xe4c83e60), WTC0(0xe4782400), WTC0(0xe4269840), WTC0(0xe3d42dc0), WTC0(0xe38188c0), WTC0(0xe32f4be0), WTC0(0xe2ddeea0), WTC0(0xe28db520),
+ WTC0(0xe23ee000), WTC0(0xe1f1a580), WTC0(0xe1a5e3a0), WTC0(0xe15b35a0), WTC0(0xe1113860), WTC0(0xe0c78a00), WTC0(0xe07dd0e0), WTC0(0xe033b7c0),
+ WTC0(0xdfe8e680), WTC0(0xdf9d1fc0), WTC0(0xdf5055c0), WTC0(0xdf0287c0), WTC0(0xdeb3b340), WTC0(0xde63e7c0), WTC0(0xde134a00), WTC0(0xddc20000),
+ WTC0(0xdd703180), WTC0(0xdd1e1280), WTC0(0xdccbe080), WTC0(0xdc79d980), WTC0(0xdc283600), WTC0(0xdbd71e00), WTC0(0xdb86b140), WTC0(0xdb3710c0),
+ WTC0(0xdae850c0), WTC0(0xda9a6bc0), WTC0(0xda4d5640), WTC0(0xda010640), WTC0(0xd9b56640), WTC0(0xd96a5700), WTC0(0xd91fb700), WTC0(0xd8d56600),
+ WTC0(0xd88b4a40), WTC0(0xd8414f00), WTC0(0xd7f75f80), WTC0(0xd7ad6740), WTC0(0xd76352c0), WTC0(0xd7191040), WTC0(0xd6ce8c80), WTC0(0xd683bd00),
+ WTC0(0xd638a5c0), WTC0(0xd5ed4f80), WTC0(0xd5a1c240), WTC0(0xd5562b80), WTC0(0xd50ae500), WTC0(0xd4c04c80), WTC0(0xd476bb40), WTC0(0xd42e62c0),
+ WTC0(0xd3e75680), WTC0(0xd3a1ad00), WTC0(0xd35d6780), WTC0(0xd31a4300), WTC0(0xd2d7dc00), WTC0(0xd295d080), WTC0(0xd253d8c0), WTC0(0xd211df40),
+ WTC0(0xd1cfdbc0), WTC0(0xd18dc480), WTC0(0xd14b9dc0), WTC0(0xd1097c80), WTC0(0xd0c77700), WTC0(0xd085a500), WTC0(0xd0442f40), WTC0(0xd0034a80),
+ WTC0(0xcfc32c00), WTC0(0xcf840400), WTC0(0xcf45f400), WTC0(0xcf0913c0), WTC0(0xcecd8000), WTC0(0xce932c80), WTC0(0xce59bf40), WTC0(0xce20cd40),
+ WTC0(0xcde7ec40), WTC0(0xcdaeedc0), WTC0(0xcd75ea00), WTC0(0xcd3cfec0), WTC0(0xcd044b40), WTC0(0xcccbff00), WTC0(0xcc945480), WTC0(0xcc5d8780),
+ WTC0(0xcc27c3c0), WTC0(0xcbf2fc40), WTC0(0xcbbf0a00), WTC0(0xcb8bc7c0), WTC0(0xcb591880), WTC0(0xcb26f0c0), WTC0(0xcaf54980), WTC0(0xcac41ac0),
+ WTC0(0xca936440), WTC0(0xca632d80), WTC0(0xca337f00), WTC0(0xca046180), WTC0(0xc9d5dd40), WTC0(0xc9a7fa80), WTC0(0xc97ac200), WTC0(0xc94e3c00),
+ WTC0(0xc91d1840), WTC0(0xc8f15980), WTC0(0xc8c52340), WTC0(0xc8988100), WTC0(0xc86b7f00), WTC0(0xc83e28c0), WTC0(0xc8108a80), WTC0(0xc7e2afc0),
+ WTC0(0xc7b4a480), WTC0(0xc7867480), WTC0(0xc7582b40), WTC0(0xc729cc80), WTC0(0xc6fb5700), WTC0(0xc6ccca40), WTC0(0xc69e2180), WTC0(0xc66f49c0),
+ WTC0(0xc64029c0), WTC0(0xc610a740), WTC0(0xc5e0bfc0), WTC0(0xc5b09e80), WTC0(0xc5807900), WTC0(0xc5508440), WTC0(0xc520e840), WTC0(0xc4f1bdc0),
+ WTC0(0xc4c31d00), WTC0(0xc4951780), WTC0(0xc4678a00), WTC0(0xc43a28c0), WTC0(0xc40ca800), WTC0(0xc3deccc0), WTC0(0xc3b09940), WTC0(0xc3822c00),
+ WTC0(0xc353a0c0), WTC0(0xc3251740), WTC0(0xc2f6b500), WTC0(0xc2c8a140), WTC0(0xc29b02c0), WTC0(0xc26df5c0), WTC0(0xc2418940), WTC0(0xc215cbc0),
+ WTC0(0xc1eaca00), WTC0(0xc1c08680), WTC0(0xc196fb00), WTC0(0xc16e22c0), WTC0(0xc145f040), WTC0(0xc11e3a80), WTC0(0xc0f6cc00), WTC0(0xc0cf6ec0),
+ WTC0(0xc0a802c0), WTC0(0xc0809280), WTC0(0xc0593340), WTC0(0xc031f880), WTC0(0xc00b04c0), WTC0(0xbfe48981), WTC0(0xbfbebb81), WTC0(0xbf99cb01),
+ WTC0(0xbf75cc81), WTC0(0xbf52c101), WTC0(0xbf30a901), WTC0(0xbf0f8301), WTC0(0xbeef4601), WTC0(0xbecfe601), WTC0(0xbeb15701), WTC0(0xbe938c81),
+ WTC0(0xbe767e81), WTC0(0xbe5a2301), WTC0(0xbe3e7201), WTC0(0xbe236001), WTC0(0xbe08e181), WTC0(0xbdeee981), WTC0(0xbdd56b81), WTC0(0xbdbc6381),
+ WTC0(0xbda3d081), WTC0(0xbd8bb281), WTC0(0xbd740b81), WTC0(0xbd5ce281), WTC0(0xbd464281), WTC0(0xbd303581), WTC0(0xbd1ac801), WTC0(0xbd060c81),
+ WTC0(0xbcf21601), WTC0(0xbcdef701), WTC0(0xbcccbd01), WTC0(0xbcbb7001), WTC0(0xbcab1781), WTC0(0xbc9bb901), WTC0(0xbc8d5101), WTC0(0xbc7fd301),
+ WTC0(0xbc733401), WTC0(0xbc676501), WTC0(0xbc5c4c81), WTC0(0xbc51cb01), WTC0(0xbc47c281), WTC0(0xbc3e1981), WTC0(0xbc34c081), WTC0(0xbc2bab01),
+ WTC0(0xbc22cd81), WTC0(0xbc1a2401), WTC0(0xbc11b681), WTC0(0xbc098d81), WTC0(0xbc01b381), WTC0(0xbbfa3c01), WTC0(0xbbf34281), WTC0(0xbbece281),
+ WTC0(0xbbe73201), WTC0(0xbbe23281), WTC0(0xbbdddb01), WTC0(0xbbda2501), WTC0(0xbbd70201), WTC0(0xbbd45601), WTC0(0xbbd20301), WTC0(0xbbcfea81),
+ WTC0(0xbbce0601), WTC0(0xbbcc6b01), WTC0(0xbbcb3201), WTC0(0xbbca7481), WTC0(0xbbca5d01), WTC0(0xbbcb2281), WTC0(0xbbccfc81), WTC0(0xbbd01301),
+ WTC0(0xbbd45881), WTC0(0xbbd9a781), WTC0(0xbbdfdb81), WTC0(0xbbe6c801), WTC0(0xbbee2f81), WTC0(0xbbf5d181), WTC0(0xbbfd6c01), WTC0(0xbc04e381),
+ WTC0(0xbc0c4581), WTC0(0xbc13a481), WTC0(0xbc1b1081), WTC0(0xbc228f01), WTC0(0xbc2a1a81), WTC0(0xbc31af01), WTC0(0xbc394901), WTC0(0xbc40e881),
+ WTC0(0xbc488e81), WTC0(0xbc503b81), WTC0(0xbc57f101), WTC0(0xbc5fae81), WTC0(0xbc677501), WTC0(0xbc6f4401), WTC0(0xbc771c01), WTC0(0xbc7efc81),
+ WTC0(0xbc86e581), WTC0(0xbc8ed701), WTC0(0xbc96d101), WTC0(0xbc9ed481), WTC0(0xbca6e101), WTC0(0xbcaef701), WTC0(0xbcb71701), WTC0(0xbcbf4001),
+ WTC0(0xbcc77181), WTC0(0xbccfac01), WTC0(0xbcd7ef01), WTC0(0xbce03b81), WTC0(0xbce89281), WTC0(0xbcf0f381), WTC0(0xbcf95e81), WTC0(0xbd01d281),
+ WTC0(0xbd0a4f81), WTC0(0xbd12d581), WTC0(0xbd1b6501), WTC0(0xbd23ff01), WTC0(0xbd2ca281), WTC0(0xbd355081), WTC0(0xbd3e0801), WTC0(0xbd46c801),
+ WTC0(0xbd4f9101), WTC0(0xbd586281), WTC0(0xbd613d81), WTC0(0xbd6a2201), WTC0(0xbd731081), WTC0(0xbd7c0781), WTC0(0xbd850701), WTC0(0xbd8e0e01),
+ WTC0(0xbd971c81), WTC0(0xbda03381), WTC0(0xbda95301), WTC0(0xbdb27b01), WTC0(0xbdbbab01), WTC0(0xbdc4e301), WTC0(0xbdce2181), WTC0(0xbdd76701),
+ WTC0(0xbde0b301), WTC0(0xbdea0681), WTC0(0xbdf36101), WTC0(0xbdfcc301), WTC0(0xbe062b81), WTC0(0xbe0f9a01), WTC0(0xbe190d81), WTC0(0xbe228681),
+ WTC0(0xbe2c0501), WTC0(0xbe358901), WTC0(0xbe3f1381), WTC0(0xbe48a301), WTC0(0xbe523781), WTC0(0xbe5bd001), WTC0(0xbe656c01), WTC0(0xbe6f0c01),
+ WTC0(0xbe78b001), WTC0(0xbe825801), WTC0(0xbe8c0501), WTC0(0xbe95b581), WTC0(0xbe9f6901), WTC0(0xbea91f01), WTC0(0xbeb2d681), WTC0(0xbebc9181),
+ WTC0(0xbec64e81), WTC0(0xbed00f81), WTC0(0xbed9d281), WTC0(0xbee39801), WTC0(0xbeed5f01), WTC0(0xbef72681), WTC0(0xbf00ef81), WTC0(0xbf0aba01),
+ WTC0(0xbf148681), WTC0(0xbf1e5501), WTC0(0xbf282501), WTC0(0xbf31f501), WTC0(0xbf3bc601), WTC0(0xbf459681), WTC0(0xbf4f6801), WTC0(0xbf593a01),
+ WTC0(0xbf630d81), WTC0(0xbf6ce201), WTC0(0xbf76b701), WTC0(0xbf808b81), WTC0(0xbf8a5f81), WTC0(0xbf943301), WTC0(0xbf9e0701), WTC0(0xbfa7dc01),
+ WTC0(0xbfb1b101), WTC0(0xbfbb8701), WTC0(0xbfc55c81), WTC0(0xbfcf3181), WTC0(0xbfd90601), WTC0(0xbfe2d901), WTC0(0xbfecaa81), WTC0(0xbff67a01),
+ /* part 1 */
+ WTC1(0x80130981), WTC1(0x80269f81), WTC1(0x803a3381), WTC1(0x804dc481), WTC1(0x80615281), WTC1(0x8074dc01), WTC1(0x80886081), WTC1(0x809bdf01),
+ WTC1(0x80af5701), WTC1(0x80c2c781), WTC1(0x80d63101), WTC1(0x80e99401), WTC1(0x80fcf181), WTC1(0x81104a01), WTC1(0x81239d81), WTC1(0x8136ea01),
+ WTC1(0x814a2f81), WTC1(0x815d6c01), WTC1(0x8170a181), WTC1(0x8183cf81), WTC1(0x8196f781), WTC1(0x81aa1981), WTC1(0x81bd3401), WTC1(0x81d04681),
+ WTC1(0x81e34f81), WTC1(0x81f64f01), WTC1(0x82094581), WTC1(0x821c3401), WTC1(0x822f1b01), WTC1(0x8241fa01), WTC1(0x8254cf01), WTC1(0x82679901),
+ WTC1(0x827a5801), WTC1(0x828d0b01), WTC1(0x829fb401), WTC1(0x82b25301), WTC1(0x82c4e801), WTC1(0x82d77201), WTC1(0x82e9ef01), WTC1(0x82fc5f01),
+ WTC1(0x830ec081), WTC1(0x83211501), WTC1(0x83335c81), WTC1(0x83459881), WTC1(0x8357c701), WTC1(0x8369e781), WTC1(0x837bf801), WTC1(0x838df801),
+ WTC1(0x839fe801), WTC1(0x83b1c881), WTC1(0x83c39a81), WTC1(0x83d55d01), WTC1(0x83e70f01), WTC1(0x83f8b001), WTC1(0x840a3e81), WTC1(0x841bb981),
+ WTC1(0x842d2281), WTC1(0x843e7a81), WTC1(0x844fc081), WTC1(0x8460f581), WTC1(0x84721701), WTC1(0x84832481), WTC1(0x84941d81), WTC1(0x84a50201),
+ WTC1(0x84b5d301), WTC1(0x84c69101), WTC1(0x84d73c01), WTC1(0x84e7d381), WTC1(0x84f85581), WTC1(0x8508c181), WTC1(0x85191801), WTC1(0x85295881),
+ WTC1(0x85398481), WTC1(0x85499d01), WTC1(0x8559a081), WTC1(0x85698e81), WTC1(0x85796601), WTC1(0x85892681), WTC1(0x8598d081), WTC1(0x85a86581),
+ WTC1(0x85b7e601), WTC1(0x85c75201), WTC1(0x85d6a981), WTC1(0x85e5eb81), WTC1(0x85f51681), WTC1(0x86042c01), WTC1(0x86132c01), WTC1(0x86221801),
+ WTC1(0x8630f181), WTC1(0x863fb701), WTC1(0x864e6901), WTC1(0x865d0581), WTC1(0x866b8d81), WTC1(0x867a0081), WTC1(0x86886001), WTC1(0x8696ad01),
+ WTC1(0x86a4e781), WTC1(0x86b30f01), WTC1(0x86c12401), WTC1(0x86cf2601), WTC1(0x86dd1481), WTC1(0x86eaf081), WTC1(0x86f8ba81), WTC1(0x87067281),
+ WTC1(0x87141b01), WTC1(0x8721b481), WTC1(0x872f4201), WTC1(0x873cc201), WTC1(0x874a2f01), WTC1(0x87578181), WTC1(0x8764b101), WTC1(0x8771c601),
+ WTC1(0x877ede01), WTC1(0x878c1881), WTC1(0x87998f01), WTC1(0x87a70e81), WTC1(0x87b42481), WTC1(0x87c05e81), WTC1(0x87cb5101), WTC1(0x87d4ac81),
+ WTC1(0x87e73d81), WTC1(0x88124281), WTC1(0x88353501), WTC1(0x885f8481), WTC1(0x888d3181), WTC1(0x88be1681), WTC1(0x88f13801), WTC1(0x8925f101),
+ WTC1(0x895bcd01), WTC1(0x89925a81), WTC1(0x89c92f81), WTC1(0x8a001f01), WTC1(0x8a372881), WTC1(0x8a6e4a01), WTC1(0x8aa58681), WTC1(0x8adcee01),
+ WTC1(0x8b149701), WTC1(0x8b4c9701), WTC1(0x8b850281), WTC1(0x8bbde981), WTC1(0x8bf75b01), WTC1(0x8c316681), WTC1(0x8c6c1b01), WTC1(0x8ca78781),
+ WTC1(0x8ce3ba81), WTC1(0x8d20c301), WTC1(0x8d5eaa01), WTC1(0x8d9d7781), WTC1(0x8ddd3201), WTC1(0x8e1de001), WTC1(0x8e5f8881), WTC1(0x8ea23201),
+ WTC1(0x8ee5e301), WTC1(0x8f2aa101), WTC1(0x8f706f01), WTC1(0x8fb74f81), WTC1(0x8fff4601), WTC1(0x90485401), WTC1(0x90927b81), WTC1(0x90ddc001),
+ WTC1(0x912a2201), WTC1(0x9177a301), WTC1(0x91c64301), WTC1(0x92160301), WTC1(0x9266e281), WTC1(0x92b8e101), WTC1(0x930bff81), WTC1(0x93603d01),
+ WTC1(0x93b59901), WTC1(0x940c1281), WTC1(0x9463a881), WTC1(0x94bc5981), WTC1(0x95162381), WTC1(0x95710601), WTC1(0x95ccff01), WTC1(0x962a0c81),
+ WTC1(0x96882e01), WTC1(0x96e76101), WTC1(0x9747a481), WTC1(0x97a8f681), WTC1(0x980b5501), WTC1(0x986ebd81), WTC1(0x98d32d81), WTC1(0x9938a281),
+ WTC1(0x999f1981), WTC1(0x9a069001), WTC1(0x9a6f0381), WTC1(0x9ad87081), WTC1(0x9b42d581), WTC1(0x9bae2f81), WTC1(0x9c1a7c81), WTC1(0x9c87ba81),
+ WTC1(0x9cf5e701), WTC1(0x9d650081), WTC1(0x9dd50481), WTC1(0x9e45f081), WTC1(0x9eb7c101), WTC1(0x9f2a7281), WTC1(0x9f9e0301), WTC1(0xa0127081),
+ WTC1(0xa087b981), WTC1(0xa0fddd81), WTC1(0xa174da81), WTC1(0xa1ecae01), WTC1(0xa2655581), WTC1(0xa2dece81), WTC1(0xa3591801), WTC1(0xa3d43001),
+ WTC1(0xa4501601), WTC1(0xa4ccc901), WTC1(0xa54a4701), WTC1(0xa5c89001), WTC1(0xa647a301), WTC1(0xa6c77e01), WTC1(0xa7482101), WTC1(0xa7c98b01),
+ WTC1(0xa84bbb81), WTC1(0xa8ceb201), WTC1(0xa9526d81), WTC1(0xa9d6ef01), WTC1(0xaa5c3601), WTC1(0xaae24301), WTC1(0xab691681), WTC1(0xabf0b181),
+ WTC1(0xac791401), WTC1(0xad023f01), WTC1(0xad8c3301), WTC1(0xae16f001), WTC1(0xaea27681), WTC1(0xaf2ec901), WTC1(0xafbbe801), WTC1(0xb049d601),
+ WTC1(0xb0d89401), WTC1(0xb1682281), WTC1(0xb1f88181), WTC1(0xb289b181), WTC1(0xb31bb301), WTC1(0xb3ae8601), WTC1(0xb4422b81), WTC1(0xb4d6a381),
+ WTC1(0x4a5a327f), WTC1(0x49c4adff), WTC1(0x492e637f), WTC1(0x48974f7f), WTC1(0x47ff6d7f), WTC1(0x4766baff), WTC1(0x46cd35ff), WTC1(0x4632dd7f),
+ WTC1(0x4597b0ff), WTC1(0x44fbb1ff), WTC1(0x445eeaff), WTC1(0x43c165ff), WTC1(0x4323227f), WTC1(0x4284277f), WTC1(0x41e48aff), WTC1(0x4144557f),
+ WTC1(0x40a3867f), WTC1(0x4001f5ff), WTC1(0x3f5f5d80), WTC1(0x3ebbad00), WTC1(0x3e16ee40), WTC1(0x3d713d00), WTC1(0x3ccab700), WTC1(0x3c236500),
+ WTC1(0x3b7b5800), WTC1(0x3ad2ecc0), WTC1(0x3a2a6540), WTC1(0x3981b7c0), WTC1(0x38d8ba00), WTC1(0x382f01c0), WTC1(0x37846240), WTC1(0x36d8eb00),
+ WTC1(0x362c9ec0), WTC1(0x357f7a00), WTC1(0x34d18340), WTC1(0x3422c900), WTC1(0x33736c40), WTC1(0x32c39040), WTC1(0x32134280), WTC1(0x31629280),
+ WTC1(0x30b1a000), WTC1(0x30008380), WTC1(0x2f4f4240), WTC1(0x2e9df180), WTC1(0x2decc780), WTC1(0x2d3bd640), WTC1(0x2c8b0cc0), WTC1(0x2bda3080),
+ WTC1(0x2b28ec80), WTC1(0x2a773500), WTC1(0x29c51b40), WTC1(0x291293c0), WTC1(0x285f9280), WTC1(0x27ac35c0), WTC1(0x26f8ab40), WTC1(0x26454c00),
+ WTC1(0x25925600), WTC1(0x24dfd580), WTC1(0x242ddd40), WTC1(0x237c87c0), WTC1(0x22cbe240), WTC1(0x221bef40), WTC1(0x216cb040), WTC1(0x20be2800),
+ WTC1(0x20105c80), WTC1(0x1f6352a0), WTC1(0x1eb71240), WTC1(0x1e0ba140), WTC1(0x1d60fe40), WTC1(0x1cb723e0), WTC1(0x1c0e0300), WTC1(0x1b6596c0),
+ WTC1(0x1abde8a0), WTC1(0x1a16fbe0), WTC1(0x1970c680), WTC1(0x18cb4840), WTC1(0x18268e20), WTC1(0x1782a0c0), WTC1(0x16df8960), WTC1(0x163d6300),
+ WTC1(0x159c52c0), WTC1(0x14fc87e0), WTC1(0x145e2c80), WTC1(0x13c15b60), WTC1(0x13263240), WTC1(0x128cd9a0), WTC1(0x11f562a0), WTC1(0x115fc1c0),
+ WTC1(0x10cbf160), WTC1(0x1039f200), WTC1(0x0fa9a080), WTC1(0x0f1abd90), WTC1(0x0e8d01d0), WTC1(0x0e003330), WTC1(0x0d743590), WTC1(0x0ce8ef40),
+ WTC1(0x0c5e1900), WTC1(0x0bd35d70), WTC1(0x0b488eb0), WTC1(0x0abd8410), WTC1(0x0a320a00), WTC1(0x09a60e70), WTC1(0x0919ab00), WTC1(0x088d0de0),
+ WTC1(0x080065e0), WTC1(0x07739710), WTC1(0x06e65808), WTC1(0x06588348), WTC1(0x05ca0ae0), WTC1(0x053aaaf8), WTC1(0x04a9faf0), WTC1(0x0417f698),
+ WTC1(0x03859ff4), WTC1(0x02f49be4), WTC1(0x0266b668), WTC1(0x01de554e), WTC1(0x015f50ca), WTC1(0x00eb7e5d), WTC1(0x00904f24), WTC1(0x00212889),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000), WTC1(0x00000000),
+ /* part 2 */
+ WTC2(0xfffece02), WTC2(0xffe4c3df), WTC2(0xffcaaa55), WTC2(0xffb087d1), WTC2(0xff9662bf), WTC2(0xff7c418b), WTC2(0xff622aa0), WTC2(0xff48246c),
+ WTC2(0xff2e355a), WTC2(0xff1463db), WTC2(0xfefab608), WTC2(0xfee12f0a), WTC2(0xfec7cfd2), WTC2(0xfeae995a), WTC2(0xfe958cc4), WTC2(0xfe7cabce),
+ WTC2(0xfe63f882), WTC2(0xfe4b74e0), WTC2(0xfe3322f6), WTC2(0xfe1b04dc), WTC2(0xfe031ccc), WTC2(0xfdeb6cf0), WTC2(0xfdd3ff7c), WTC2(0xfdbce834),
+ WTC2(0xfda63bb8), WTC2(0xfd900c68), WTC2(0xfd7a590c), WTC2(0xfd6511b4), WTC2(0xfd5026c0), WTC2(0xfd3b8954), WTC2(0xfd272df0), WTC2(0xfd130adc),
+ WTC2(0xfcff15ac), WTC2(0xfceb4a68), WTC2(0xfcd7b110), WTC2(0xfcc454d0), WTC2(0xfcb14064), WTC2(0xfc9e896c), WTC2(0xfc8c5264), WTC2(0xfc7abef0),
+ WTC2(0xfc69f078), WTC2(0xfc59f5e8), WTC2(0xfc4acfec), WTC2(0xfc3c8060), WTC2(0xfc2f0264), WTC2(0xfc223b7c), WTC2(0xfc160714), WTC2(0xfc0a4150),
+ WTC2(0xfbfec920), WTC2(0xfbf38320), WTC2(0xfbe855d0), WTC2(0xfbdd2740), WTC2(0xfbd1fc68), WTC2(0xfbc6fea0), WTC2(0xfbbc5a48), WTC2(0xfbb23b48),
+ WTC2(0xfba8ca78), WTC2(0xfba02e50), WTC2(0xfb988de0), WTC2(0xfb920b40), WTC2(0xfb8cb870), WTC2(0xfb889f68), WTC2(0xfb85cbe8), WTC2(0xfb843dd0),
+ WTC2(0xfb83df78), WTC2(0xfb8495d0), WTC2(0xfb864660), WTC2(0xfb88d4a8), WTC2(0xfb8c21e8), WTC2(0xfb900f28), WTC2(0xfb947dc0), WTC2(0xfb9950c0),
+ WTC2(0xfb9e6d08), WTC2(0xfba3b658), WTC2(0xfba91908), WTC2(0xfbae9e08), WTC2(0xfbb45bd0), WTC2(0xfbba66f8), WTC2(0xfbc0dcf0), WTC2(0xfbc7ead8),
+ WTC2(0xfbcfc200), WTC2(0xfbd89330), WTC2(0xfbe294d0), WTC2(0xfbee03d0), WTC2(0xfbfb1de8), WTC2(0xfc0a1da4), WTC2(0xfc1b22e0), WTC2(0xfc2e38f0),
+ WTC2(0xfc436d48), WTC2(0xfc5abf7c), WTC2(0xfc74024c), WTC2(0xfc8ef2e8), WTC2(0xfcab51ac), WTC2(0xfcc8d024), WTC2(0xfce704f0), WTC2(0xfd0580cc),
+ WTC2(0xfd23d4d0), WTC2(0xfd41ce40), WTC2(0xfd5f81b0), WTC2(0xfd7d08f0), WTC2(0xfd9a8560), WTC2(0xfdb85938), WTC2(0xfdd71798), WTC2(0xfdf753b8),
+ WTC2(0xfe1993ee), WTC2(0xfe3e30f8), WTC2(0xfe656cba), WTC2(0xfe8f8fdc), WTC2(0xfebca8a4), WTC2(0xfeec590e), WTC2(0xff1e285c), WTC2(0xff51a0b7),
+ WTC2(0xff866330), WTC2(0xffbc2cbb), WTC2(0xfff2bbff), WTC2(0x0029d79d), WTC2(0x00618a22), WTC2(0x009a1185), WTC2(0x00d3aa8c), WTC2(0x010e8ff6),
+ WTC2(0x014af29e), WTC2(0x0188fe56), WTC2(0x01c8e108), WTC2(0x020ab3c4), WTC2(0x024e68a8), WTC2(0x0293e824), WTC2(0x02db1bc8), WTC2(0x0323f1a4),
+ WTC2(0x036e5d6c), WTC2(0x03ba5320), WTC2(0x0407c938), WTC2(0x0456cad0), WTC2(0x04a77288), WTC2(0x04f9db88), WTC2(0x054e1888), WTC2(0x05a41ef0),
+ WTC2(0x05fbd6e0), WTC2(0x065528c0), WTC2(0x06b00838), WTC2(0x070c7ee0), WTC2(0x076a9bb0), WTC2(0x07ca6d10), WTC2(0x082c08e0), WTC2(0x088f8da0),
+ WTC2(0x08f51ac0), WTC2(0x095ccc20), WTC2(0x09c69f70), WTC2(0x0a327b40), WTC2(0x0aa046d0), WTC2(0x0b0febb0), WTC2(0x0b815dd0), WTC2(0x0bf49600),
+ WTC2(0x0c698c50), WTC2(0x0ce03ba0), WTC2(0x0d58a380), WTC2(0x0dd2c510), WTC2(0x0e4ea110), WTC2(0x0ecc3dd0), WTC2(0x0f4ba800), WTC2(0x0fcced10),
+ WTC2(0x10501960), WTC2(0x10d532a0), WTC2(0x115c39c0), WTC2(0x11e52fa0), WTC2(0x12701560), WTC2(0x12fcef20), WTC2(0x138bc200), WTC2(0x141c9300),
+ WTC2(0x14af64a0), WTC2(0x154434e0), WTC2(0x15db0020), WTC2(0x1673c360), WTC2(0x170e7e80), WTC2(0x17ab35e0), WTC2(0x1849ee40), WTC2(0x18eaaba0),
+ WTC2(0x198d6f00), WTC2(0x1a3236a0), WTC2(0x1ad90080), WTC2(0x1b81cc60), WTC2(0x1c2c9da0), WTC2(0x1cd97980), WTC2(0x1d8865c0), WTC2(0x1e396540),
+ WTC2(0x1eec7700), WTC2(0x1fa198c0), WTC2(0x2058c840), WTC2(0x21120640), WTC2(0x21cd5700), WTC2(0x228abec0), WTC2(0x234a4180), WTC2(0x240bdf80),
+ WTC2(0x24cf95c0), WTC2(0x259561c0), WTC2(0x265d4200), WTC2(0x27273840), WTC2(0x27f348c0), WTC2(0x28c17700), WTC2(0x2991c500), WTC2(0x2a643080),
+ WTC2(0x2b38b680), WTC2(0x2c0f53c0), WTC2(0x2ce80840), WTC2(0x2dc2d680), WTC2(0x2e9fc100), WTC2(0x2f7ecac0), WTC2(0x305ff280), WTC2(0x314334c0),
+ WTC2(0x32288e00), WTC2(0x330ffb80), WTC2(0x33f97d80), WTC2(0x34e515c0), WTC2(0x35d2c5c0), WTC2(0x36c28d00), WTC2(0x37b467c0), WTC2(0x38a85080),
+ WTC2(0x399e4240), WTC2(0x3a963a00), WTC2(0x3b903600), WTC2(0x3c8c3480), WTC2(0x3d8a3380), WTC2(0x3e8a2dc0), WTC2(0x3f8c1b40), WTC2(0x408ff2ff),
+ WTC2(0x4195ae7f), WTC2(0x429d477f), WTC2(0x43a6b87f), WTC2(0x44b1fdff), WTC2(0x45bf11ff), WTC2(0x46cdee7f), WTC2(0x47de8cff), WTC2(0x48f0e77f),
+ WTC2(0x4a050eff), WTC2(0x4b1b2dff), WTC2(0x4c3372ff), WTC2(0x4d4e0bff), WTC2(0x4e6b257f), WTC2(0x4f8aedff), WTC2(0x50ad92ff), WTC2(0x51d341ff),
+ WTC2(0x002006a9), WTC2(0x000bfb36), WTC2(0xfffe45ac), WTC2(0xfff6d064), WTC2(0xfff585bc), WTC2(0xfffa500d), WTC2(0x000519b4), WTC2(0x0015cd0c),
+ WTC2(0x002c5470), WTC2(0x00489a3b), WTC2(0x006a88c8), WTC2(0x00920a74), WTC2(0x00bf0999), WTC2(0x00f17092), WTC2(0x012929bc), WTC2(0x01661f70),
+ WTC2(0x01a83c0c), WTC2(0x01ef69e8), WTC2(0x023b9364), WTC2(0x028ca2d4), WTC2(0x02e2829c), WTC2(0x033d1d10), WTC2(0x039c5c90), WTC2(0x04002b78),
+ WTC2(0x04687418), WTC2(0x04d520e0), WTC2(0x05461c18), WTC2(0x05bb5020), WTC2(0x0634a758), WTC2(0x06b20c20), WTC2(0x073368c8), WTC2(0x07b8a7b0),
+ WTC2(0x0841b340), WTC2(0x08ce75b0), WTC2(0x095ed980), WTC2(0x09f2c900), WTC2(0x0a8a2e80), WTC2(0x0b24f470), WTC2(0x0bc30510), WTC2(0x0c644ad0),
+ WTC2(0x0d08b010), WTC2(0x0db01f10), WTC2(0x0e5a8250), WTC2(0x0f07c400), WTC2(0x0fb7cea0), WTC2(0x106a8c80), WTC2(0x111fe800), WTC2(0x11d7cb60),
+ WTC2(0x12922120), WTC2(0x134ed3a0), WTC2(0x140dcd00), WTC2(0x14cef7e0), WTC2(0x15923e60), WTC2(0x16578b00), WTC2(0x171ec820), WTC2(0x17e7e020),
+ WTC2(0x18b2bd20), WTC2(0x197f49c0), WTC2(0x1a4d7040), WTC2(0x1b1d1b00), WTC2(0x1bee3460), WTC2(0x1cc0a6a0), WTC2(0x1d945c40), WTC2(0x1e693f80),
+ WTC2(0x1f3f3ac0), WTC2(0x20163880), WTC2(0x20ee22c0), WTC2(0x21c6e440), WTC2(0x22a06740), WTC2(0x237a9600), WTC2(0x24555ac0), WTC2(0x2530a040),
+ WTC2(0x260c5080), WTC2(0x26e85600), WTC2(0x27c49b00), WTC2(0x28a10a00), WTC2(0x297d8d80), WTC2(0x2a5a0f80), WTC2(0x2b367a80), WTC2(0x2c12b8c0),
+ WTC2(0x2ceeb500), WTC2(0x2dca5940), WTC2(0x2ea58fc0), WTC2(0x2f804340), WTC2(0x305a5dc0), WTC2(0x3133ca00), WTC2(0x320c7200), WTC2(0x32e44000),
+ WTC2(0x33bb1ec0), WTC2(0x3490f880), WTC2(0x3565b7c0), WTC2(0x36394640), WTC2(0x370b8f00), WTC2(0x37dc7c00), WTC2(0x38abf7c0), WTC2(0x3979ecc0),
+ WTC2(0x3a464500), WTC2(0x3b10eb00), WTC2(0x3bd9c940), WTC2(0x3ca0c9c0), WTC2(0x3d65d740), WTC2(0x3e28dc00), WTC2(0x3ee9c240), WTC2(0x3fa87480),
+ WTC2(0x4064dcff), WTC2(0x411ee67f), WTC2(0x41d67a7f), WTC2(0x428b847f), WTC2(0x433ded7f), WTC2(0x43eda0ff), WTC2(0x449a887f), WTC2(0x45448f7f),
+ WTC2(0x45eb9eff), WTC2(0x468fa1ff), WTC2(0x473082ff), WTC2(0x47ce2c7f), WTC2(0x4868887f), WTC2(0x48ff80ff), WTC2(0x499300ff), WTC2(0x4a22f2ff),
+ WTC2(0x4aaf407f), WTC2(0x4b37d47f), WTC2(0x4bbc997f), WTC2(0x4c3d78ff), WTC2(0x4cba5e7f), WTC2(0x4d33337f), WTC2(0x4da7e27f), WTC2(0x4e18567f),
+ WTC2(0x4e8478ff), WTC2(0x4eec347f), WTC2(0x4f4f737f), WTC2(0x4fae20ff), WTC2(0x500825ff), WTC2(0x505d6dff), WTC2(0x50ade37f), WTC2(0x50f96f7f),
+ WTC2(0x513ffdff), WTC2(0x518177ff), WTC2(0x51bdc87f), WTC2(0x51f4d9ff), WTC2(0x5226967f), WTC2(0x5252e87f), WTC2(0x5279b9ff), WTC2(0x529af5ff),
+ WTC2(0x52b6867f), WTC2(0x52cc55ff), WTC2(0x52dc4eff), WTC2(0x52e65aff), WTC2(0x52ea657f), WTC2(0x52e857ff), WTC2(0x52e01d7f), WTC2(0x52d19fff),
+ WTC2(0x52bcc9ff), WTC2(0x52a1857f), WTC2(0x527fbd7f), WTC2(0x52575b7f), WTC2(0x52284a7f), WTC2(0x51f274ff), WTC2(0x51b5c47f), WTC2(0x5172247f),
+ WTC2(0x51277dff), WTC2(0x50d5bc7f), WTC2(0x507cc9ff), WTC2(0x501c90ff), WTC2(0x4fb4fb7f), WTC2(0x4f45f3ff), WTC2(0x4ecf64ff), WTC2(0x4e5138ff),
+ WTC2(0x4dcb597f), WTC2(0x4d3db1ff), WTC2(0x4ca82bff), WTC2(0x4c0ab27f), WTC2(0x4b652f7f), WTC2(0x4ab78d7f), WTC2(0x4a01b67f), WTC2(0x4943957f),
+ WTC2(0x487d12ff), WTC2(0x47ae1f7f), WTC2(0x46d68f7f), WTC2(0x45f7187f), WTC2(0x4513597f), WTC2(0x4430467f), WTC2(0x4352d2ff), WTC2(0x427e6bff),
+ WTC2(0x41b390ff), WTC2(0x40f2077f), WTC2(0x4039a87f), WTC2(0x3f8a3100), WTC2(0x3ee33e00), WTC2(0x3e446ac0), WTC2(0x3dad5180), WTC2(0x3d1d7fc0),
+ WTC2(0x3c947b00), WTC2(0x3c11c7c0), WTC2(0x3b94ebc0), WTC2(0x3b1d6dc0), WTC2(0x3aaad480), WTC2(0x3a3ca740), WTC2(0x39d26c40), WTC2(0x396ba8c0),
+ WTC2(0x3907e080), WTC2(0x38a69800), WTC2(0x38473d80), WTC2(0x37e923c0), WTC2(0x378b9b80), WTC2(0x372e0380), WTC2(0x36d03a80), WTC2(0x36727f00),
+ WTC2(0x36150e40), WTC2(0x35b81540), WTC2(0x355b8000), WTC2(0x34ff1dc0), WTC2(0x34a2bfc0), WTC2(0x34463e80), WTC2(0x33e982c0), WTC2(0x338c7880),
+ WTC2(0x332f0bc0), WTC2(0x32d11800), WTC2(0x327265c0), WTC2(0x3212bbc0), WTC2(0x31b1e740), WTC2(0x314fef00), WTC2(0x30ed0540), WTC2(0x30895c80),
+ WTC2(0x30251880), WTC2(0x2fc02880), WTC2(0x2f5a6480), WTC2(0x2ef3a480), WTC2(0x2e8bd640), WTC2(0x2e231100), WTC2(0x2db97680), WTC2(0x2d4f2700),
+ WTC2(0x2ce431c0), WTC2(0x2c789080), WTC2(0x2c0c3bc0), WTC2(0x2b9f2bc0), WTC2(0x2b315940), WTC2(0x2ac2bc00), WTC2(0x2a534cc0), WTC2(0x29e303c0)
+};
+
+
diff --git a/libAACenc/src/aacEnc_rom.h b/libAACenc/src/aacEnc_rom.h
new file mode 100644
index 0000000..e96e0e7
--- /dev/null
+++ b/libAACenc/src/aacEnc_rom.h
@@ -0,0 +1,141 @@
+/******************************************************************************
+
+ (C) Copyright Fraunhofer IIS (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.
+
+
+ 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:
+ Initial authors: M. Lohwasser, M. Gayer
+ Contents/description:
+
+******************************************************************************/
+/*!
+ \file
+ \brief Memory layout $Revision: 36838 $
+ \author Markus Lohwasser
+*/
+
+#ifndef AAC_ENC_ROM_H
+#define AAC_ENC_ROM_H
+
+#include "common_fix.h"
+
+#include "psy_const.h"
+#include "psy_configuration.h"
+#include "FDK_tools_rom.h"
+
+/*
+ Huffman Tables
+*/
+extern const INT FDKaacEnc_huff_ltab1_2[3][3][3][3];
+extern const INT FDKaacEnc_huff_ltab3_4[3][3][3][3];
+extern const INT FDKaacEnc_huff_ltab5_6[9][9];
+extern const INT FDKaacEnc_huff_ltab7_8[8][8];
+extern const INT FDKaacEnc_huff_ltab9_10[13][13];
+extern const UCHAR FDKaacEnc_huff_ltab11[17][17];
+extern const UCHAR FDKaacEnc_huff_ltabscf[121];
+extern const USHORT FDKaacEnc_huff_ctab1[3][3][3][3];
+extern const USHORT FDKaacEnc_huff_ctab2[3][3][3][3];
+extern const USHORT FDKaacEnc_huff_ctab3[3][3][3][3];
+extern const USHORT FDKaacEnc_huff_ctab4[3][3][3][3];
+extern const USHORT FDKaacEnc_huff_ctab5[9][9];
+extern const USHORT FDKaacEnc_huff_ctab6[9][9];
+extern const USHORT FDKaacEnc_huff_ctab7[8][8];
+extern const USHORT FDKaacEnc_huff_ctab8[8][8];
+extern const USHORT FDKaacEnc_huff_ctab9[13][13];
+extern const USHORT FDKaacEnc_huff_ctab10[13][13];
+extern const USHORT FDKaacEnc_huff_ctab11[21][17];
+extern const INT FDKaacEnc_huff_ctabscf[121];
+
+/*
+ quantizer
+*/
+#define MANT_DIGITS 9
+#define MANT_SIZE (1<<MANT_DIGITS)
+
+#if defined(ARCH_PREFER_MULT_32x16)
+#define FIXP_QTD FIXP_SGL
+#define QTC FX_DBL2FXCONST_SGL
+#else
+#define FIXP_QTD FIXP_DBL
+#define QTC
+#endif
+
+extern const FIXP_QTD FDKaacEnc_mTab_3_4[MANT_SIZE];
+extern const FIXP_QTD FDKaacEnc_quantTableQ[4];
+extern const FIXP_QTD FDKaacEnc_quantTableE[4];
+
+extern const FIXP_DBL FDKaacEnc_mTab_4_3Elc[512];
+extern const FIXP_DBL FDKaacEnc_specExpMantTableCombElc[4][14];
+extern const UCHAR FDKaacEnc_specExpTableComb[4][14];
+
+
+/*
+ table to count used number of bits
+*/
+extern const SHORT FDKaacEnc_sideInfoTabLong[MAX_SFB_LONG + 1];
+extern const SHORT FDKaacEnc_sideInfoTabShort[MAX_SFB_SHORT + 1];
+
+
+/*
+ Psy Configuration constants
+*/
+extern const SFB_PARAM_LONG p_FDKaacEnc_8000_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_8000_short_128;
+extern const SFB_PARAM_LONG p_FDKaacEnc_11025_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_11025_short_128;
+extern const SFB_PARAM_LONG p_FDKaacEnc_12000_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_12000_short_128;
+extern const SFB_PARAM_LONG p_FDKaacEnc_16000_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_16000_short_128;
+extern const SFB_PARAM_LONG p_FDKaacEnc_22050_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_22050_short_128;
+extern const SFB_PARAM_LONG p_FDKaacEnc_24000_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_24000_short_128;
+extern const SFB_PARAM_LONG p_FDKaacEnc_32000_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_32000_short_128;
+extern const SFB_PARAM_LONG p_FDKaacEnc_44100_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_44100_short_128;
+extern const SFB_PARAM_LONG p_FDKaacEnc_48000_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_48000_short_128;
+extern const SFB_PARAM_LONG p_FDKaacEnc_64000_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_64000_short_128;
+extern const SFB_PARAM_LONG p_FDKaacEnc_88200_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_88200_short_128;
+extern const SFB_PARAM_LONG p_FDKaacEnc_96000_long_1024;
+extern const SFB_PARAM_SHORT p_FDKaacEnc_96000_short_128;
+
+
+/*
+ TNS filter coefficients
+*/
+extern const FIXP_DBL FDKaacEnc_tnsEncCoeff3[8];
+extern const FIXP_DBL FDKaacEnc_tnsCoeff3Borders[8];
+extern const FIXP_DBL FDKaacEnc_tnsEncCoeff4[16];
+extern const FIXP_DBL FDKaacEnc_tnsCoeff4Borders[16];
+
+#define WTC0 WTC
+#define WTC1 WTC
+#define WTC2 WTC
+
+extern const FIXP_WTB ELDAnalysis512[1536];
+extern const FIXP_WTB ELDAnalysis480[1440];
+
+
+#endif /* #ifndef AAC_ENC_ROM_H */
diff --git a/libAACenc/src/aacenc.cpp b/libAACenc/src/aacenc.cpp
new file mode 100644
index 0000000..5ab7192
--- /dev/null
+++ b/libAACenc/src/aacenc.cpp
@@ -0,0 +1,952 @@
+/*************************** Fast MPEG AAC Audio Encoder **********************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Schug / A. Groeschel
+ contents/description: fast aac coder functions
+
+******************************************************************************/
+
+#include "aacenc.h"
+
+#include "bitenc.h"
+#include "interface.h"
+#include "psy_configuration.h"
+#include "psy_main.h"
+#include "qc_main.h"
+#include "bandwidth.h"
+#include "channel_map.h"
+#include "tns_func.h"
+#include "aacEnc_ram.h"
+
+#include "genericStds.h"
+
+
+
+
+static AAC_ENCODER_ERROR FDKaacEnc_InitCheckAncillary(INT bitRate,
+ INT framelength,
+ INT ancillaryRate,
+ INT *ancillaryBitsPerFrame,
+ INT sampleRate);
+
+/**
+ * For calculating average bitrate of an access unit 32 bit data width is not sufficient
+ * in worst case. Therefore use scaling of the samplingrate parameter to keep complete information.
+ */
+typedef struct {
+ INT samplingRate;
+ UCHAR scalingFactor;
+} SR_SCALING_TAB;
+
+static const SR_SCALING_TAB samplingRateScalingTable[] =
+{
+ { 8000, 5 }, { 11025, 0 }, { 12000, 5 }, { 16000, 5 },
+ { 22050, 1 }, { 24000, 5 }, { 32000, 5 }, { 44100, 2 },
+ { 48000, 5 }, { 64000, 5 }, { 88200, 3 }, { 96000, 5 }
+};
+
+/**
+ * Get maximal scaling factor without losing samplingrate accuracy.
+ *
+ * \param samplingRate Samplingrate to be used.
+ * \return scaling value.
+ */
+static int GetSrSf(const INT samplingRate)
+{
+ int i, result = 0;
+
+ for (i=0; i<(int)(sizeof(samplingRateScalingTable)/sizeof(SR_SCALING_TAB)); i++) {
+ if ( samplingRateScalingTable[i].samplingRate == samplingRate ) {
+ result = samplingRateScalingTable[i].scalingFactor;
+ break;
+ }
+ }
+ return result;
+}
+
+#define MIN_BUFSIZE_PER_EFF_CHAN 6144
+
+typedef struct
+{
+ AACENC_BITRATE_MODE bitrateMode;
+ int chanBitrate[2]; /* mono/stereo settings */
+} CONFIG_TAB_ENTRY_VBR;
+
+static const CONFIG_TAB_ENTRY_VBR configTabVBR[] = {
+ {AACENC_BR_MODE_CBR, { 0, 0}} ,
+ {AACENC_BR_MODE_VBR_1, { 32000, 20000}} ,
+ {AACENC_BR_MODE_VBR_2, { 40000, 32000}} ,
+ {AACENC_BR_MODE_VBR_3, { 56000, 48000}} ,
+ {AACENC_BR_MODE_VBR_4, { 72000, 64000}} ,
+ {AACENC_BR_MODE_VBR_5, {112000, 96000}}
+};
+
+/*-----------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_GetVBRBitrate
+ description: Get VBR bitrate from vbr quality
+ input params: int vbrQuality (VBR0, VBR1, VBR2)
+ channelMode
+ returns: vbr bitrate
+
+ ------------------------------------------------------------------------------*/
+INT FDKaacEnc_GetVBRBitrate(INT bitrateMode, CHANNEL_MODE channelMode)
+{
+ INT bitrate = 0;
+ INT monoStereoMode = 0; /* default mono */
+
+ if (FDKaacEnc_GetMonoStereoMode(channelMode)==EL_MODE_STEREO) {
+ monoStereoMode = 1;
+ }
+
+ switch((AACENC_BITRATE_MODE)bitrateMode){
+ case AACENC_BR_MODE_VBR_1:
+ case AACENC_BR_MODE_VBR_2:
+ case AACENC_BR_MODE_VBR_3:
+ case AACENC_BR_MODE_VBR_4:
+ case AACENC_BR_MODE_VBR_5:
+ bitrate = configTabVBR[bitrateMode].chanBitrate[monoStereoMode];
+ break;
+ case AACENC_BR_MODE_INVALID:
+ case AACENC_BR_MODE_CBR:
+ case AACENC_BR_MODE_SFR:
+ case AACENC_BR_MODE_FF:
+ default:
+ bitrate = 0;
+ break;
+ }
+
+ /* convert channel bitrate to overall bitrate*/
+ bitrate *= FDKaacEnc_GetChannelModeConfiguration(channelMode)->nChannelsEff;
+
+ return bitrate;
+}
+
+/**
+ * \brief Convert encoder bitreservoir value for transport library.
+ *
+ * \param bitrateMode Bitratemode used in current encoder instance. Se ::AACENC_BITRATE_MODE
+ * \param bitresTotal Encoder bitreservoir level in bits.
+ *
+ * \return Corrected bitreservoir level used in transport library.
+ */
+static INT FDKaacEnc_EncBitresToTpBitres(
+ const AACENC_BITRATE_MODE bitrateMode,
+ const INT bitresTotal
+ )
+{
+ INT transporBitreservoir = 0;
+
+ switch (bitrateMode) {
+ case AACENC_BR_MODE_CBR:
+ transporBitreservoir = bitresTotal; /* encoder bitreservoir level */
+ break;
+ case AACENC_BR_MODE_VBR_1:
+ case AACENC_BR_MODE_VBR_2:
+ case AACENC_BR_MODE_VBR_3:
+ case AACENC_BR_MODE_VBR_4:
+ case AACENC_BR_MODE_VBR_5:
+ transporBitreservoir = FDK_INT_MAX; /* signal variable bitrate */
+ break;
+ case AACENC_BR_MODE_FF:
+ case AACENC_BR_MODE_SFR:
+ transporBitreservoir = 0; /* super framing and fixed framing */
+ break; /* without bitreservoir signaling */
+ default:
+ case AACENC_BR_MODE_INVALID:
+ transporBitreservoir = 0; /* invalid configuration*/
+ FDK_ASSERT(0);
+ }
+
+ return transporBitreservoir;
+}
+
+/*-----------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_AacInitDefaultConfig
+ description: gives reasonable default configuration
+ returns: ---
+
+ ------------------------------------------------------------------------------*/
+void FDKaacEnc_AacInitDefaultConfig(AACENC_CONFIG *config)
+{
+ /* make thepre initialization of the structs flexible */
+ FDKmemclear(config, sizeof(AACENC_CONFIG));
+
+ /* default ancillary */
+ config->anc_Rate = 0; /* no ancillary data */
+ config->ancDataBitRate = 0; /* no additional consumed bitrate */
+
+ /* default configurations */
+ config->bitRate = -1; /* bitrate must be set*/
+ config->averageBits = -1; /* instead of bitrate/s we can configure bits/superframe */
+ config->bitrateMode = 0;
+ config->bandWidth = 0; /* get bandwidth from table */
+ config->useTns = TNS_ENABLE_MASK; /* tns enabled completly */
+ config->usePns = 1; /* depending on channelBitrate this might be set to 0 later */
+ config->useIS = 1; /* Intensity Stereo Configuration */
+ config->framelength = DEFAULT_FRAMELENGTH; /* used frame size */
+ config->syntaxFlags = 0; /* default syntax with no specialities */
+ config->epConfig = -1; /* no ER syntax -> no additional error protection */
+ config->nSubFrames = 1; /* default, no sub frames */
+ config->channelOrder = CH_ORDER_MPEG; /* Use MPEG channel ordering. */
+ config->channelMode = MODE_UNKNOWN;
+ config->minBitsPerFrame = -1; /* minum number of bits in each AU */
+ config->maxBitsPerFrame = -1; /* minum number of bits in each AU */
+ config->bitreservoir = -1; /* default, uninitialized value */
+
+ /* init tabs in fixpoint_math */
+ InitLdInt();
+ InitInvSqrtTab();
+}
+
+
+/*---------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_Open
+ description: allocate and initialize a new encoder instance
+ returns: error code
+
+ ---------------------------------------------------------------------------*/
+AAC_ENCODER_ERROR FDKaacEnc_Open(HANDLE_AAC_ENC *phAacEnc,
+ const INT nElements,
+ const INT nChannels,
+ const INT nSubFrames)
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ AAC_ENC *hAacEnc = NULL;
+ UCHAR *dynamicRAM = NULL;
+
+ if (phAacEnc==NULL) {
+ return AAC_ENC_INVALID_HANDLE;
+ }
+
+ /* allocate encoder structure */
+ hAacEnc = GetRam_aacEnc_AacEncoder();
+ if (hAacEnc == NULL) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto bail;
+ }
+ FDKmemclear(hAacEnc, sizeof(AAC_ENC));
+
+ hAacEnc->dynamic_RAM = GetAACdynamic_RAM();
+ dynamicRAM = (UCHAR*)hAacEnc->dynamic_RAM;
+
+ /* allocate the Psy aud Psy Out structure */
+ ErrorStatus = FDKaacEnc_PsyNew(&hAacEnc->psyKernel,
+ nElements,
+ nChannels
+ ,dynamicRAM
+ );
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ ErrorStatus = FDKaacEnc_PsyOutNew(hAacEnc->psyOut,
+ nElements,
+ nChannels,
+ nSubFrames
+ ,dynamicRAM
+ );
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ /* allocate the Q&C Out structure */
+ ErrorStatus = FDKaacEnc_QCOutNew(hAacEnc->qcOut,
+ nElements,
+ nChannels,
+ nSubFrames
+ ,dynamicRAM
+ );
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ /* allocate the Q&C kernel */
+ ErrorStatus = FDKaacEnc_QCNew(&hAacEnc->qcKernel,
+ nElements
+ ,dynamicRAM
+ );
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ hAacEnc->maxChannels = nChannels;
+ hAacEnc->maxElements = nElements;
+ hAacEnc->maxFrames = nSubFrames;
+
+bail:
+ *phAacEnc = hAacEnc;
+ return ErrorStatus;
+}
+
+
+AAC_ENCODER_ERROR FDKaacEnc_Initialize(HANDLE_AAC_ENC hAacEnc,
+ AACENC_CONFIG *config, /* pre-initialized config struct */
+ HANDLE_TRANSPORTENC hTpEnc,
+ ULONG initFlags)
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ INT psyBitrate, tnsMask; //INT profile = 1;
+ CHANNEL_MAPPING *cm = NULL;
+
+ INT qmbfac, qbw;
+ FIXP_DBL mbfac, bw_ratio;
+ QC_INIT qcInit;
+ INT averageBitsPerFrame = 0;
+
+ if (config==NULL)
+ return AAC_ENC_INVALID_HANDLE;
+
+ /******************* sanity checks *******************/
+
+ /* check config structure */
+ if (config->nChannels < 1 || config->nChannels > (6)) {
+ return AAC_ENC_UNSUPPORTED_CHANNELCONFIG;
+ }
+
+ /* check sample rate */
+ switch (config->sampleRate)
+ {
+ case 8000:
+ case 11025:
+ case 12000:
+ case 16000:
+ case 22050:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ case 64000:
+ case 88200:
+ case 96000:
+ break;
+ default:
+ return AAC_ENC_UNSUPPORTED_SAMPLINGRATE;
+ }
+
+ /* bitrate has to be set */
+ if (config->bitRate==-1) {
+ return AAC_ENC_UNSUPPORTED_BITRATE;
+ }
+
+ /* check bit rate */
+
+ /* check if bitRate is not too low or high */
+ averageBitsPerFrame = (config->bitRate*(config->framelength>>GetSrSf(config->sampleRate))) / (config->sampleRate>>GetSrSf(config->sampleRate)) / config->nSubFrames;
+
+ /* assume minimum static bits of 40 in each channel. */
+ if ( (averageBitsPerFrame <= ((40*config->nChannels) + transportEnc_GetStaticBits(hTpEnc, averageBitsPerFrame))) ||
+ ( ((config->bitRate*(config->framelength>>GetSrSf(config->sampleRate)))) >
+ ((FDKaacEnc_GetChannelModeConfiguration(config->channelMode)->nChannelsEff * MIN_BUFSIZE_PER_EFF_CHAN))*(config->sampleRate>>GetSrSf(config->sampleRate)) )
+ )
+ {
+ return AAC_ENC_UNSUPPORTED_BITRATE;
+ }
+
+ if (config->syntaxFlags & AC_ER_VCB11) {
+ return AAC_ENC_UNSUPPORTED_ER_FORMAT;
+ }
+ if (config->syntaxFlags & AC_ER_HCR) {
+ return AAC_ENC_UNSUPPORTED_ER_FORMAT;
+ }
+
+ /* check frame length */
+ switch (config->framelength)
+ {
+ case 1024:
+ if ( config->audioObjectType != AOT_AAC_LC
+ && config->audioObjectType != AOT_SBR
+ && config->audioObjectType != AOT_PS
+ && config->audioObjectType != AOT_ER_AAC_LC
+ && config->audioObjectType != AOT_AAC_SCAL )
+ {
+ return AAC_ENC_INVALID_FRAME_LENGTH;
+ }
+ break;
+ case 512:
+ case 480:
+ if ( config->audioObjectType != AOT_ER_AAC_LD
+ && config->audioObjectType != AOT_ER_AAC_ELD )
+ {
+ return AAC_ENC_INVALID_FRAME_LENGTH;
+ }
+ break;
+ default:
+ return AAC_ENC_INVALID_FRAME_LENGTH;
+ }
+
+ if (config->anc_Rate != 0) {
+
+ ErrorStatus = FDKaacEnc_InitCheckAncillary(config->bitRate,
+ config->framelength,
+ config->anc_Rate,
+ &hAacEnc->ancillaryBitsPerFrame,
+ config->sampleRate);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+
+ /* update estimated consumed bitrate */
+ config->ancDataBitRate += ( (hAacEnc->ancillaryBitsPerFrame * config->sampleRate) / config->framelength );
+
+ }
+
+ /* maximal allowed DSE bytes in frame */
+ {
+ /* fixpoint calculation*/
+ INT q_res, encBitrate, sc;
+ FIXP_DBL tmp = fDivNorm(config->framelength, config->sampleRate, &q_res);
+ encBitrate = (config->bitRate/*-config->ancDataBitRate*/)- (INT)(config->nChannels*8000);
+ sc = CountLeadingBits(encBitrate);
+ config->maxAncBytesPerAU = FDKmin( (256), FDKmax(0,(INT)(fMultDiv2(tmp, (FIXP_DBL)(encBitrate<<sc))>>(-q_res+sc-1+3))) );
+ }
+
+ /* bind config to hAacEnc->config */
+ hAacEnc->config = config;
+
+ /* set hAacEnc->bitrateMode */
+ hAacEnc->bitrateMode = (AACENC_BITRATE_MODE)config->bitrateMode;
+
+ hAacEnc->encoderMode = config->channelMode;
+
+ ErrorStatus = FDKaacEnc_InitChannelMapping(hAacEnc->encoderMode, config->channelOrder, &hAacEnc->channelMapping);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ cm = &hAacEnc->channelMapping;
+
+ ErrorStatus = FDKaacEnc_DetermineBandWidth(&hAacEnc->config->bandWidth,
+ config->bandWidth,
+ config->bitRate - config->ancDataBitRate,
+ hAacEnc->bitrateMode,
+ config->sampleRate,
+ config->framelength,
+ cm,
+ hAacEnc->encoderMode);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ hAacEnc->bandwidth90dB = (INT)hAacEnc->config->bandWidth;
+
+ tnsMask = config->useTns ? TNS_ENABLE_MASK : 0x0;
+ psyBitrate = config->bitRate - config->ancDataBitRate;
+
+ ErrorStatus = FDKaacEnc_psyInit(hAacEnc->psyKernel,
+ hAacEnc->psyOut,
+ hAacEnc->maxFrames,
+ hAacEnc->maxChannels,
+ config->audioObjectType,
+ cm);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ ErrorStatus = FDKaacEnc_psyMainInit(hAacEnc->psyKernel,
+ config->audioObjectType,
+ cm,
+ config->sampleRate,
+ config->framelength,
+ psyBitrate,
+ tnsMask,
+ hAacEnc->bandwidth90dB,
+ config->usePns,
+ config->useIS,
+ config->syntaxFlags,
+ initFlags);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ ErrorStatus = FDKaacEnc_QCOutInit(hAacEnc->qcOut, hAacEnc->maxFrames, cm);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+
+
+ qcInit.channelMapping = &hAacEnc->channelMapping;
+ qcInit.sceCpe = 0;
+
+ {
+ int maxBitres;
+ qcInit.averageBits = (averageBitsPerFrame+7)&~7;
+ maxBitres = (MIN_BUFSIZE_PER_EFF_CHAN*cm->nChannelsEff) - qcInit.averageBits;
+ qcInit.bitRes = (config->bitreservoir!=-1) ? FDKmin(config->bitreservoir, maxBitres) : maxBitres;
+
+ qcInit.maxBits = fixMin(MIN_BUFSIZE_PER_EFF_CHAN*cm->nChannelsEff, ((averageBitsPerFrame+7)&~7)+qcInit.bitRes);
+ qcInit.maxBits = (config->maxBitsPerFrame!=-1) ? fixMin(qcInit.maxBits, config->maxBitsPerFrame) : qcInit.maxBits;
+
+ qcInit.minBits = fixMax(0, ((averageBitsPerFrame-1)&~7)-qcInit.bitRes-transportEnc_GetStaticBits(hTpEnc, ((averageBitsPerFrame+7)&~7)+qcInit.bitRes));
+ qcInit.minBits = (config->minBitsPerFrame!=-1) ? fixMax(qcInit.minBits, config->minBitsPerFrame) : qcInit.minBits;
+ }
+
+ qcInit.nSubFrames = config->nSubFrames;
+ qcInit.padding.paddingRest = config->sampleRate;
+
+ /* Calc meanPe */
+ bw_ratio = fDivNorm((FIXP_DBL)hAacEnc->bandwidth90dB, (FIXP_DBL)(config->sampleRate>>1), &qbw);
+ qbw = DFRACT_BITS-1-qbw;
+ /* qcInit.meanPe = 10.0f * FRAME_LEN_LONG * hAacEnc->bandwidth90dB/(config->sampleRate/2.0f); */
+ qcInit.meanPe = fMult(bw_ratio, (FIXP_DBL)((10*config->framelength)<<16)) >> (qbw-15);
+
+ /* Calc maxBitFac */
+ mbfac = fDivNorm((MIN_BUFSIZE_PER_EFF_CHAN-744)*cm->nChannelsEff, qcInit.averageBits/qcInit.nSubFrames, &qmbfac);
+ qmbfac = DFRACT_BITS-1-qmbfac;
+ qcInit.maxBitFac = (qmbfac > 24) ? (mbfac >> (qmbfac - 24)):(mbfac << (24 - qmbfac));
+
+ switch(config->bitrateMode){
+ case AACENC_BR_MODE_CBR:
+ qcInit.bitrateMode = QCDATA_BR_MODE_CBR;
+ break;
+ case AACENC_BR_MODE_VBR_1:
+ qcInit.bitrateMode = QCDATA_BR_MODE_VBR_1;
+ break;
+ case AACENC_BR_MODE_VBR_2:
+ qcInit.bitrateMode = QCDATA_BR_MODE_VBR_2;
+ break;
+ case AACENC_BR_MODE_VBR_3:
+ qcInit.bitrateMode = QCDATA_BR_MODE_VBR_3;
+ break;
+ case AACENC_BR_MODE_VBR_4:
+ qcInit.bitrateMode = QCDATA_BR_MODE_VBR_4;
+ break;
+ case AACENC_BR_MODE_VBR_5:
+ qcInit.bitrateMode = QCDATA_BR_MODE_VBR_5;
+ break;
+ case AACENC_BR_MODE_SFR:
+ qcInit.bitrateMode = QCDATA_BR_MODE_SFR;
+ break;
+ case AACENC_BR_MODE_FF:
+ qcInit.bitrateMode = QCDATA_BR_MODE_FF;
+ break;
+ default:
+ ErrorStatus = AAC_ENC_UNSUPPORTED_BITRATE_MODE;
+ goto bail;
+ }
+
+ qcInit.invQuant = (config->useRequant)?2:0;
+
+ /* maxIterations should be set to the maximum number of requantization iterations that are
+ * allowed before the crash recovery functionality is activated. This setting should be adjusted
+ * to the processing power available, i.e. to the processing power headroom in one frame that is
+ * still left after normal encoding without requantization. Please note that if activated this
+ * functionality is used most likely only in cases where the encoder is operating beyond
+ * recommended settings, i.e. the audio quality is suboptimal anyway. Activating the crash
+ * recovery does not further reduce audio quality significantly in these cases. */
+ if ( (config->audioObjectType == AOT_ER_AAC_LD) || (config->audioObjectType == AOT_ER_AAC_ELD) ) {
+ qcInit.maxIterations = 2;
+ }
+ else
+ {
+ qcInit.maxIterations = 5;
+ }
+
+ qcInit.bitrate = config->bitRate - config->ancDataBitRate;
+
+ qcInit.staticBits = transportEnc_GetStaticBits(hTpEnc, qcInit.averageBits/qcInit.nSubFrames);
+
+ ErrorStatus = FDKaacEnc_QCInit(hAacEnc->qcKernel, &qcInit);
+ if (ErrorStatus != AAC_ENC_OK)
+ goto bail;
+
+ /* Map virtual aot's to intern aot used in bitstream writer. */
+ switch (hAacEnc->config->audioObjectType) {
+ case AOT_MP2_AAC_LC:
+ case AOT_DABPLUS_AAC_LC:
+ hAacEnc->aot = AOT_AAC_LC;
+ break;
+ case AOT_MP2_SBR:
+ case AOT_DABPLUS_SBR:
+ hAacEnc->aot = AOT_SBR;
+ break;
+ case AOT_MP2_PS:
+ case AOT_DABPLUS_PS:
+ hAacEnc->aot = AOT_PS;
+ break;
+ default:
+ hAacEnc->aot = hAacEnc->config->audioObjectType;
+ }
+
+ /* common things */
+
+ return AAC_ENC_OK;
+
+bail:
+
+ return ErrorStatus;
+}
+
+
+/*---------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_EncodeFrame
+ description: encodes one frame
+ returns: error code
+
+ ---------------------------------------------------------------------------*/
+AAC_ENCODER_ERROR FDKaacEnc_EncodeFrame( HANDLE_AAC_ENC hAacEnc, /* encoder handle */
+ HANDLE_TRANSPORTENC hTpEnc,
+ INT_PCM* RESTRICT inputBuffer,
+ INT* nOutBytes,
+ AACENC_EXT_PAYLOAD extPayload[MAX_TOTAL_EXT_PAYLOADS]
+ )
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ int el, n, c=0;
+ UCHAR extPayloadUsed[MAX_TOTAL_EXT_PAYLOADS];
+
+ CHANNEL_MAPPING *cm = &hAacEnc->channelMapping;
+
+
+
+ PSY_OUT *psyOut = hAacEnc->psyOut[c];
+ QC_OUT *qcOut = hAacEnc->qcOut[c];
+
+ FDKmemclear(extPayloadUsed, MAX_TOTAL_EXT_PAYLOADS * sizeof(UCHAR));
+
+ qcOut->elementExtBits = 0; /* sum up all extended bit of each element */
+ qcOut->staticBits = 0; /* sum up side info bits of each element */
+ qcOut->totalNoRedPe = 0; /* sum up PE */
+
+ /* advance psychoacoustics */
+ for (el=0; el<cm->nElements; el++) {
+ ELEMENT_INFO elInfo = cm->elInfo[el];
+
+ if ( (elInfo.elType == ID_SCE)
+ || (elInfo.elType == ID_CPE)
+ || (elInfo.elType == ID_LFE) )
+ {
+ int ch;
+
+ /* update pointer!*/
+ for(ch=0;ch<elInfo.nChannelsInEl;ch++) {
+ PSY_OUT_CHANNEL *psyOutChan = psyOut->psyOutElement[el]->psyOutChannel[ch];
+ QC_OUT_CHANNEL *qcOutChan = qcOut->qcElement[el]->qcOutChannel[ch];
+
+ psyOutChan->mdctSpectrum = qcOutChan->mdctSpectrum;
+ psyOutChan->sfbSpreadEnergy = qcOutChan->sfbSpreadEnergy;
+ psyOutChan->sfbEnergy = qcOutChan->sfbEnergy;
+ psyOutChan->sfbEnergyLdData = qcOutChan->sfbEnergyLdData;
+ psyOutChan->sfbMinSnrLdData = qcOutChan->sfbMinSnrLdData;
+ psyOutChan->sfbThresholdLdData = qcOutChan->sfbThresholdLdData;
+
+ }
+
+ FDKaacEnc_psyMain(elInfo.nChannelsInEl,
+ hAacEnc->psyKernel->psyElement[el],
+ hAacEnc->psyKernel->psyDynamic,
+ hAacEnc->psyKernel->psyConf,
+ psyOut->psyOutElement[el],
+ inputBuffer,
+ cm->elInfo[el].ChannelIndex,
+ cm->nChannels
+
+ );
+
+ /* FormFactor, Pe and staticBitDemand calculation */
+ ErrorStatus = FDKaacEnc_QCMainPrepare(&elInfo,
+ hAacEnc->qcKernel->hAdjThr->adjThrStateElem[el],
+ psyOut->psyOutElement[el],
+ qcOut->qcElement[el],
+ hAacEnc->aot,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->config->epConfig);
+
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ /*-------------------------------------------- */
+
+ qcOut->qcElement[el]->extBitsUsed = 0;
+ qcOut->qcElement[el]->nExtensions = 0;
+ /* reset extension payload */
+ FDKmemclear(&qcOut->qcElement[el]->extension, (1)*sizeof(QC_OUT_EXTENSION));
+
+ for ( n = 0; n < MAX_TOTAL_EXT_PAYLOADS; n++ ) {
+ if ( !extPayloadUsed[n]
+ && (extPayload[n].associatedChElement == el)
+ && (extPayload[n].dataSize > 0)
+ && (extPayload[n].pData != NULL) )
+ {
+ int idx = qcOut->qcElement[el]->nExtensions++;
+
+ qcOut->qcElement[el]->extension[idx].type = extPayload[n].dataType; /* Perform a sanity check on the type? */
+ qcOut->qcElement[el]->extension[idx].nPayloadBits = extPayload[n].dataSize;
+ qcOut->qcElement[el]->extension[idx].pPayload = extPayload[n].pData;
+ /* Now ask the bitstream encoder how many bits we need to encode the data with the current bitstream syntax: */
+ qcOut->qcElement[el]->extBitsUsed +=
+ FDKaacEnc_writeExtensionData( NULL,
+ &qcOut->qcElement[el]->extension[idx],
+ 0, 0,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->aot,
+ hAacEnc->config->epConfig );
+ extPayloadUsed[n] = 1;
+ }
+ }
+
+ /* sum up extension and static bits for all channel elements */
+ qcOut->elementExtBits += qcOut->qcElement[el]->extBitsUsed;
+ qcOut->staticBits += qcOut->qcElement[el]->staticBitsUsed;
+
+ /* sum up pe */
+ qcOut->totalNoRedPe += qcOut->qcElement[el]->peData.pe;
+ }
+ }
+
+ qcOut->nExtensions = 0;
+ qcOut->globalExtBits = 0;
+
+ /* reset extension payload */
+ FDKmemclear(&qcOut->extension, (2+2)*sizeof(QC_OUT_EXTENSION));
+
+ /* Add extension payload not assigned to an channel element
+ (Ancillary data is the only supported type up to now) */
+ for ( n = 0; n < MAX_TOTAL_EXT_PAYLOADS; n++ ) {
+ if ( !extPayloadUsed[n]
+ && (extPayload[n].associatedChElement == -1)
+ && (extPayload[n].pData != NULL) )
+ {
+ UINT payloadBits = 0;
+
+ if (extPayload[n].dataType == EXT_DATA_ELEMENT) {
+ if (hAacEnc->ancillaryBitsPerFrame) {
+ /* granted frame dse bitrate */
+ payloadBits = hAacEnc->ancillaryBitsPerFrame;
+ }
+ else {
+ /* write anc data if bitrate constraint fulfilled */
+ if ((extPayload[n].dataSize>>3) <= hAacEnc->config->maxAncBytesPerAU) {
+ payloadBits = extPayload[n].dataSize;
+ }
+ }
+ payloadBits = fixMin( extPayload[n].dataSize, payloadBits );
+ } else {
+ payloadBits = extPayload[n].dataSize;
+ }
+
+ if (payloadBits > 0)
+ {
+ int idx = qcOut->nExtensions++;
+
+ qcOut->extension[idx].type = extPayload[n].dataType; /* Perform a sanity check on the type? */
+ qcOut->extension[idx].nPayloadBits = payloadBits;
+ qcOut->extension[idx].pPayload = extPayload[n].pData;
+ /* Now ask the bitstream encoder how many bits we need to encode the data with the current bitstream syntax: */
+ qcOut->globalExtBits += FDKaacEnc_writeExtensionData( NULL,
+ &qcOut->extension[idx],
+ 0, 0,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->aot,
+ hAacEnc->config->epConfig );
+ if (extPayload[n].dataType == EXT_DATA_ELEMENT) {
+ /* substract the processed bits */
+ extPayload[n].dataSize -= payloadBits;
+ }
+ extPayloadUsed[n] = 1;
+ }
+ }
+ }
+
+ if (!(hAacEnc->config->syntaxFlags & (AC_SCALABLE|AC_ER))) {
+ qcOut->globalExtBits += EL_ID_BITS; /* add bits for ID_END */
+ }
+
+ /* build bitstream all nSubFrames */
+ {
+ INT totalBits = 0; /* Total AU bits */;
+ INT avgTotalBits = 0;
+
+ /*-------------------------------------------- */
+ /* Get average total bits */
+ /*-------------------------------------------- */
+ {
+ /* frame wise bitrate adaption */
+ FDKaacEnc_AdjustBitrate(hAacEnc->qcKernel,
+ cm,
+ &avgTotalBits,
+ hAacEnc->config->bitRate,
+ hAacEnc->config->sampleRate,
+ hAacEnc->config->framelength);
+
+ /* adjust super frame bitrate */
+ avgTotalBits *= hAacEnc->config->nSubFrames;
+ }
+
+ /* Make first estimate of transport header overhead.
+ Take maximum possible frame size into account to prevent bitreservoir underrun. */
+ hAacEnc->qcKernel->globHdrBits = transportEnc_GetStaticBits(hTpEnc, avgTotalBits + hAacEnc->qcKernel->bitResTot);
+
+
+ /*-------------------------------------------- */
+ /*-------------------------------------------- */
+ /*-------------------------------------------- */
+
+ ErrorStatus = FDKaacEnc_QCMain(hAacEnc->qcKernel,
+ hAacEnc->psyOut,
+ hAacEnc->qcOut,
+ avgTotalBits,
+ cm
+ ,hAacEnc->aot,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->config->epConfig);
+
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+ /*-------------------------------------------- */
+
+ /*-------------------------------------------- */
+ ErrorStatus = FDKaacEnc_updateFillBits(cm,
+ hAacEnc->qcKernel,
+ hAacEnc->qcKernel->elementBits,
+ hAacEnc->qcOut);
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ /*-------------------------------------------- */
+ ErrorStatus = FDKaacEnc_FinalizeBitConsumption(cm,
+ hAacEnc->qcKernel,
+ qcOut,
+ qcOut->qcElement,
+ hTpEnc,
+ hAacEnc->aot,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->config->epConfig);
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+ /*-------------------------------------------- */
+ totalBits += qcOut->totalBits;
+
+
+ /*-------------------------------------------- */
+ FDKaacEnc_updateBitres(cm,
+ hAacEnc->qcKernel,
+ hAacEnc->qcOut);
+
+ /*-------------------------------------------- */
+
+ /* for ( all sub frames ) ... */
+ /* write bitstream header */
+ transportEnc_WriteAccessUnit(
+ hTpEnc,
+ totalBits,
+ FDKaacEnc_EncBitresToTpBitres(hAacEnc->bitrateMode, hAacEnc->qcKernel->bitResTot),
+ cm->nChannelsEff);
+
+ /* write bitstream */
+ ErrorStatus = FDKaacEnc_WriteBitstream(
+ hTpEnc,
+ cm,
+ qcOut,
+ psyOut,
+ hAacEnc->qcKernel,
+ hAacEnc->aot,
+ hAacEnc->config->syntaxFlags,
+ hAacEnc->config->epConfig);
+
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ /* transportEnc_EndAccessUnit() is being called inside FDKaacEnc_WriteBitstream() */
+ transportEnc_GetFrame(hTpEnc, nOutBytes);
+
+ } /* -end- if (curFrame==hAacEnc->qcKernel->nSubFrames) */
+
+
+ /*-------------------------------------------- */
+ return AAC_ENC_OK;
+}
+
+/*---------------------------------------------------------------------------
+
+ functionname:FDKaacEnc_Close
+ description: delete encoder instance
+ returns:
+
+ ---------------------------------------------------------------------------*/
+
+void FDKaacEnc_Close( HANDLE_AAC_ENC* phAacEnc) /* encoder handle */
+{
+ if (*phAacEnc == NULL) {
+ return;
+ }
+ AAC_ENC *hAacEnc = (AAC_ENC*)*phAacEnc;
+
+ if (hAacEnc->dynamic_RAM != NULL)
+ FreeAACdynamic_RAM(&hAacEnc->dynamic_RAM);
+
+ FDKaacEnc_PsyClose(&hAacEnc->psyKernel,hAacEnc->psyOut);
+
+ FDKaacEnc_QCClose(&hAacEnc->qcKernel, hAacEnc->qcOut);
+
+ FreeRam_aacEnc_AacEncoder(phAacEnc);
+}
+
+
+/* The following functions are in this source file only for convenience and */
+/* need not be visible outside of a possible encoder library. */
+
+/* basic defines for ancillary data */
+#define MAX_ANCRATE 19200 /* ancillary rate >= 19200 isn't valid */
+
+/*---------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_InitCheckAncillary
+ description: initialize and check ancillary data struct
+ return: if success or NULL if error
+
+ ---------------------------------------------------------------------------*/
+static AAC_ENCODER_ERROR FDKaacEnc_InitCheckAncillary(INT bitRate,
+ INT framelength,
+ INT ancillaryRate,
+ INT *ancillaryBitsPerFrame,
+ INT sampleRate)
+{
+ INT diffToByteAlign;
+
+ /* don't use negative ancillary rates */
+ if ( ancillaryRate < -1 )
+ return AAC_ENC_UNSUPPORTED_ANC_BITRATE;
+
+ /* check if ancillary rate is ok */
+ if ( (ancillaryRate != (-1)) && (ancillaryRate != 0) ) {
+ /* ancRate <= 15% of bitrate && ancRate < 19200 */
+ if ( ( ancillaryRate >= MAX_ANCRATE ) ||
+ ( (ancillaryRate * 20) > (bitRate * 3) ) ) {
+ return AAC_ENC_UNSUPPORTED_ANC_BITRATE;
+ }
+ }
+ else if (ancillaryRate == -1) {
+ /* if no special ancRate is requested but a ancillary file is
+ stated, then generate a ancillary rate matching to the bitrate */
+ if (bitRate >= (MAX_ANCRATE * 10)) {
+ /* ancillary rate is 19199 */
+ ancillaryRate = (MAX_ANCRATE - 1);
+ }
+ else { /* 10% of bitrate */
+ ancillaryRate = bitRate / 10;
+ }
+ }
+
+ /* make ancillaryBitsPerFrame byte align */
+ *ancillaryBitsPerFrame = (ancillaryRate * framelength ) / sampleRate;
+ diffToByteAlign = *ancillaryBitsPerFrame % 8;
+ *ancillaryBitsPerFrame = *ancillaryBitsPerFrame - diffToByteAlign;
+
+ return AAC_ENC_OK;
+}
diff --git a/libAACenc/src/aacenc.h b/libAACenc/src/aacenc.h
new file mode 100644
index 0000000..66ef2b9
--- /dev/null
+++ b/libAACenc/src/aacenc.h
@@ -0,0 +1,232 @@
+/************************* Fast MPEG AAC Audio Encoder **********************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Schug / A. Groeschel
+ contents/description: fast aac coder interface library functions
+
+******************************************************************************/
+
+#ifndef _aacenc_h_
+#define _aacenc_h_
+
+#include "common_fix.h"
+#include "FDK_audio.h"
+
+#include "tpenc_lib.h"
+
+#include "sbr_encoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * AAC-LC error codes.
+ */
+typedef enum {
+ AAC_ENC_OK = 0x0000, /*!< All fine. */
+
+ AAC_ENC_UNKNOWN = 0x0002, /*!< Error condition is of unknown reason, or from another module. */
+
+ /* initialization errors */
+ aac_enc_init_error_start = 0x2000,
+ AAC_ENC_INVALID_HANDLE = 0x2020, /*!< The handle passed to the function call was invalid (probably NULL). */
+ AAC_ENC_INVALID_FRAME_LENGTH = 0x2080, /*!< Invalid frame length (must be 1024 or 960). */
+ AAC_ENC_INVALID_N_CHANNELS = 0x20e0, /*!< Invalid amount of audio input channels. */
+ AAC_ENC_INVALID_SFB_TABLE = 0x2140, /*!< Internal encoder error. */
+
+ AAC_ENC_UNSUPPORTED_AOT = 0x3000, /*!< The Audio Object Type (AOT) is not supported. */
+ AAC_ENC_UNSUPPORTED_BITRATE = 0x3020, /*!< The chosen bitrate is not supported. */
+ AAC_ENC_UNSUPPORTED_BITRATE_MODE = 0x3028, /*!< Unsupported bit rate mode (CBR or VBR). */
+ AAC_ENC_UNSUPPORTED_ANC_BITRATE = 0x3040, /*!< Unsupported ancillay bitrate. */
+ AAC_ENC_UNSUPPORTED_ANC_MODE = 0x3060,
+ AAC_ENC_UNSUPPORTED_TRANSPORT_TYPE = 0x3080, /*!< The bitstream format is not supported. */
+ AAC_ENC_UNSUPPORTED_ER_FORMAT = 0x30a0, /*!< The error resilience tool format is not supported. */
+ AAC_ENC_UNSUPPORTED_EPCONFIG = 0x30c0, /*!< The error protection format is not supported. */
+ AAC_ENC_UNSUPPORTED_CHANNELCONFIG = 0x30e0, /*!< The channel configuration (either number or arrangement) is not supported. */
+ AAC_ENC_UNSUPPORTED_SAMPLINGRATE = 0x3100, /*!< Sample rate of audio input is not supported. */
+ AAC_ENC_NO_MEMORY = 0x3120, /*!< Could not allocate memory. */
+ AAC_ENC_PE_INIT_TABLE_NOT_FOUND = 0x3140, /*!< Internal encoder error. */
+
+ aac_enc_init_error_end,
+
+ /* encode errors */
+ aac_enc_error_start = 0x4000,
+ AAC_ENC_QUANT_ERROR = 0x4020, /*!< Too many bits used in quantization. */
+ AAC_ENC_WRITTEN_BITS_ERROR = 0x4040, /*!< Unexpected number of written bits, differs to
+ calculated number of bits. */
+ AAC_ENC_PNS_TABLE_ERROR = 0x4060, /*!< PNS level out of range. */
+ AAC_ENC_GLOBAL_GAIN_TOO_HIGH = 0x4080, /*!< Internal quantizer error. */
+ AAC_ENC_BITRES_TOO_LOW = 0x40a0, /*!< Too few bits in bit reservoir. */
+ AAC_ENC_BITRES_TOO_HIGH = 0x40a1, /*!< Too many bits in bit reservoir. */
+ AAC_ENC_INVALID_CHANNEL_BITRATE = 0x4100,
+ AAC_ENC_INVALID_ELEMENTINFO_TYPE = 0x4120, /*!< Internal encoder error. */
+
+ AAC_ENC_WRITE_SCAL_ERROR = 0x41e0, /*!< Error writing scalefacData. */
+ AAC_ENC_WRITE_SEC_ERROR = 0x4200, /*!< Error writing sectionData. */
+ AAC_ENC_WRITE_SPEC_ERROR = 0x4220, /*!< Error writing spectralData. */
+ aac_enc_error_end
+
+} AAC_ENCODER_ERROR;
+/*-------------------------- defines --------------------------------------*/
+
+#define ANC_DATA_BUFFERSIZE 1024 /* ancBuffer size */
+#define DEFAULT_FRAMELENGTH 1024 /* size of AAC core frame in (new) PCM samples */
+
+#define MAX_TOTAL_EXT_PAYLOADS (((6) * (1)) + (2+2))
+
+
+typedef enum {
+ AACENC_BR_MODE_INVALID = -1, /*!< Invalid bitrate mode. */
+ AACENC_BR_MODE_CBR = 0, /*!< Constant bitrate mode. */
+ AACENC_BR_MODE_VBR_1 = 1, /*!< Variable bitrate mode, about 32 kbps/channel. */
+ AACENC_BR_MODE_VBR_2 = 2, /*!< Variable bitrate mode, about 40 kbps/channel. */
+ AACENC_BR_MODE_VBR_3 = 3, /*!< Variable bitrate mode, about 48-56 kbps/channel. */
+ AACENC_BR_MODE_VBR_4 = 4, /*!< Variable bitrate mode, about 64 kbps/channel. */
+ AACENC_BR_MODE_VBR_5 = 5, /*!< Variable bitrate mode, about 80-96 kbps/channel. */
+ AACENC_BR_MODE_FF = 6, /*!< Fixed frame mode. */
+ AACENC_BR_MODE_SFR = 7 /*!< Superframe mode. */
+
+} AACENC_BITRATE_MODE;
+
+typedef enum {
+
+ CH_ORDER_MPEG = 0, /*!< MPEG channel ordering (e. g. 5.1: C, L, R, SL, SR, LFE) */
+ CH_ORDER_WAV /*!< WAV fileformat channel ordering (e. g. 5.1: L, R, C, LFE, SL, SR) */
+
+} CHANNEL_ORDER;
+
+/*-------------------- structure definitions ------------------------------*/
+
+struct AACENC_CONFIG {
+ INT sampleRate; /* encoder sample rate */
+ INT bitRate; /* encoder bit rate in bits/sec */
+ INT ancDataBitRate; /* additional bits consumed by anc data or sbr have to be consiedered while configuration */
+
+ INT nSubFrames; /* number of frames in super frame (not ADTS/LATM subframes !) */
+ AUDIO_OBJECT_TYPE audioObjectType; /* Audio Object Type */
+
+ INT averageBits; /* encoder bit rate in bits/superframe */
+ INT bitrateMode; /* encoder bitrate mode (CBR/VBR) */
+ INT nChannels; /* number of channels to process */
+ CHANNEL_ORDER channelOrder; /* Input Channel ordering scheme. */
+ INT bandWidth; /* targeted audio bandwidth in Hz */
+ CHANNEL_MODE channelMode; /* encoder channel mode configuration */
+ INT framelength; /* used frame size */
+
+ UINT syntaxFlags; /* bitstreams syntax configuration */
+ SCHAR epConfig; /* error protection configuration */
+
+ INT anc_Rate; /* ancillary rate, 0 (disabled), -1 (default) else desired rate */
+ UINT maxAncBytesPerAU;
+ INT minBitsPerFrame; /* minimum number of bits in AU */
+ INT maxBitsPerFrame; /* maximum number of bits in AU */
+ INT bitreservoir; /* size of bitreservoir */
+
+ UCHAR useTns; /* flag: use temporal noise shaping */
+ UCHAR usePns; /* flag: use perceptual noise substitution */
+ UCHAR useIS; /* flag: use intensity coding */
+
+ UCHAR useRequant; /* flag: use afterburner */
+};
+
+typedef struct {
+ UCHAR *pData; /* pointer to extension payload data */
+ UINT dataSize; /* extension payload data size in bits */
+ EXT_PAYLOAD_TYPE dataType; /* extension payload data type */
+ INT associatedChElement; /* number of the channel element the data is assigned to */
+} AACENC_EXT_PAYLOAD;
+
+typedef struct AAC_ENC *HANDLE_AAC_ENC;
+
+ /*-----------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_GetVBRBitrate
+ description: Get VBR bitrate from vbr quality
+ input params: int vbrQuality (VBR0, VBR1, VBR2)
+ channelMode
+ returns: vbr bitrate
+
+ ------------------------------------------------------------------------------*/
+ INT FDKaacEnc_GetVBRBitrate(INT bitrateMode, CHANNEL_MODE channelMode);
+
+
+/*-----------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_AacInitDefaultConfig
+ description: gives reasonable default configuration
+ returns: ---
+
+ ------------------------------------------------------------------------------*/
+void FDKaacEnc_AacInitDefaultConfig(AACENC_CONFIG *config);
+
+/*---------------------------------------------------------------------------
+
+ functionname:FDKaacEnc_Open
+ description: allocate and initialize a new encoder instance
+ returns: 0 if success
+
+ ---------------------------------------------------------------------------*/
+AAC_ENCODER_ERROR FDKaacEnc_Open(HANDLE_AAC_ENC *phAacEnc, /* pointer to an encoder handle, initialized on return */
+ const INT nElements, /* number of maximal elements in instance to support */
+ const INT nChannels, /* number of maximal channels in instance to support */
+ const INT nSubFrames); /* support superframing in instance */
+
+
+AAC_ENCODER_ERROR FDKaacEnc_Initialize(HANDLE_AAC_ENC hAacEncoder, /* pointer to an encoder handle, initialized on return */
+ AACENC_CONFIG *config, /* pre-initialized config struct */
+ HANDLE_TRANSPORTENC hTpEnc,
+ ULONG initFlags);
+
+
+/*---------------------------------------------------------------------------
+
+ functionname: FDKaacEnc_EncodeFrame
+ description: encode one frame
+ returns: 0 if success
+
+ ---------------------------------------------------------------------------*/
+
+AAC_ENCODER_ERROR FDKaacEnc_EncodeFrame( HANDLE_AAC_ENC hAacEnc, /* encoder handle */
+ HANDLE_TRANSPORTENC hTpEnc,
+ INT_PCM* inputBuffer,
+ INT* numOutBytes,
+ AACENC_EXT_PAYLOAD extPayload[MAX_TOTAL_EXT_PAYLOADS]
+ );
+
+/*---------------------------------------------------------------------------
+
+ functionname:FDKaacEnc_Close
+ description: delete encoder instance
+ returns:
+
+ ---------------------------------------------------------------------------*/
+
+void FDKaacEnc_Close( HANDLE_AAC_ENC* phAacEnc); /* encoder handle */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _aacenc_h_ */
+
diff --git a/libAACenc/src/aacenc_hcr.cpp b/libAACenc/src/aacenc_hcr.cpp
new file mode 100644
index 0000000..d648847
--- /dev/null
+++ b/libAACenc/src/aacenc_hcr.cpp
@@ -0,0 +1,31 @@
+/*************************** MPEG AAC Audio Encoder *************************
+
+ (C) Copyright Fraunhofer IIS (2000-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: R. Boehm
+ contents/description: huffman codeword reordering
+ based on source from aacErrRobTrans
+
+ 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 "aacenc_hcr.h"
+
diff --git a/libAACenc/src/aacenc_hcr.h b/libAACenc/src/aacenc_hcr.h
new file mode 100644
index 0000000..b6bd5b8
--- /dev/null
+++ b/libAACenc/src/aacenc_hcr.h
@@ -0,0 +1,33 @@
+/*************************** MPEG AAC Audio Encoder *************************
+
+ (C) Copyright Fraunhofer IIS (2000-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: R. Boehm
+ contents/description: huffman codeword reordering
+ based on source from aacErrRobTrans
+
+ 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 _AACENC_HCR
+#define _AACENC_HCR_H
+
+
+#endif /* ifndef _AACENC_HCR */
diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp
new file mode 100644
index 0000000..65a9bfc
--- /dev/null
+++ b/libAACenc/src/aacenc_lib.cpp
@@ -0,0 +1,1696 @@
+/**************************** MPEG-4 HE-AAC Encoder *************************
+
+ (C) Copyright Fraunhofer IIS (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.
+
+
+ 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$
+ Initial author: M. Lohwasser
+ contents/description: FDK HE-AAC Encoder interface library functions
+
+****************************************************************************/
+
+#include "aacenc_lib.h"
+#include "FDK_audio.h"
+#include "aacenc.h"
+
+#include "aacEnc_ram.h"
+#include "FDK_core.h" /* FDK_tools versioning info */
+
+/* Encoder library info */
+#define AACENCODER_LIB_VL0 3
+#define AACENCODER_LIB_VL1 3
+#define AACENCODER_LIB_VL2 0
+#define AACENCODER_LIB_TITLE "AAC Encoder"
+#define AACENCODER_LIB_BUILD_DATE __DATE__
+#define AACENCODER_LIB_BUILD_TIME __TIME__
+
+
+#include "sbr_encoder.h"
+#include "../src/sbr_ram.h"
+#include "channel_map.h"
+
+#include "psy_const.h"
+#include "bitenc.h"
+
+#include "tpenc_lib.h"
+
+#include "metadata_main.h"
+
+#define SBL(fl) (fl/8) /*!< Short block length (hardcoded to 8 short blocks per long block) */
+#define BSLA(fl) (4*SBL(fl)+SBL(fl)/2) /*!< AAC block switching look-ahead */
+#define DELAY_AAC(fl) (fl+BSLA(fl)) /*!< MDCT + blockswitching */
+#define DELAY_AACELD(fl) ( (fl) + ((fl)/2) ) /*!< ELD FB delay */
+
+#define INPUTBUFFER_SIZE (1537+100+2048)
+
+////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Flags to characterize encoder modules to be supported in present instance.
+ */
+enum {
+ ENC_MODE_FLAG_AAC = 0x0001,
+ ENC_MODE_FLAG_SBR = 0x0002,
+ ENC_MODE_FLAG_PS = 0x0004,
+ ENC_MODE_FLAG_SAC = 0x0008,
+ ENC_MODE_FLAG_META = 0x0010
+};
+
+////////////////////////////////////////////////////////////////////////////////////
+typedef struct {
+ AUDIO_OBJECT_TYPE userAOT; /*!< Audio Object Type. */
+ UINT userSamplerate; /*!< Sampling frequency. */
+ UINT nChannels; /*!< will be set via channelMode. */
+ CHANNEL_MODE userChannelMode;
+ UINT userBitrate;
+ UINT userBitrateMode;
+ UINT userBandwidth;
+ UINT userAfterburner;
+ UINT userFramelength;
+ UINT userAncDataRate;
+
+ UCHAR userTns; /*!< Use TNS coding. */
+ UCHAR userPns; /*!< Use PNS coding. */
+ UCHAR userIntensity; /*!< Use Intensity coding. */
+
+ TRANSPORT_TYPE userTpType; /*!< Transport type */
+ UCHAR userTpSignaling; /*!< Extension AOT signaling mode. */
+ UCHAR userTpNsubFrames; /*!< Number of sub frames in a transport frame for LOAS/LATM or ADTS (default 1). */
+ UCHAR userTpAmxv; /*!< AudioMuxVersion to be used for LATM (default 0). */
+ UCHAR userTpProtection;
+ UCHAR userTpHeaderPeriod; /*!< Parameter used to configure LATM/LOAS SMC rate. Moreover this parameters is
+ used to configure repetition rate of PCE in raw_data_block. */
+
+ UCHAR userErTools; /*!< Use VCB11, HCR and/or RVLC ER tool. */
+ UINT userPceAdditions; /*!< Configure additional bits in PCE. */
+
+ UCHAR userMetaDataMode; /*!< Meta data library configuration. */
+
+ UCHAR userSbrEnabled;
+
+} USER_PARAM;
+
+////////////////////////////////////////////////////////////////////////////////////
+
+/****************************************************************************
+ Structure Definitions
+****************************************************************************/
+
+typedef struct AACENC_CONFIG *HANDLE_AACENC_CONFIG;
+
+
+struct AACENCODER
+{
+ USER_PARAM extParam;
+ CODER_CONFIG coderConfig;
+
+ /* AAC */
+ AACENC_CONFIG aacConfig;
+ HANDLE_AAC_ENC hAacEnc;
+
+ /* SBR */
+ HANDLE_SBR_ENCODER hEnvEnc;
+
+ /* Meta Data */
+ HANDLE_FDK_METADATA_ENCODER hMetadataEnc;
+ INT metaDataAllowed; /* Signal whether chosen configuration allows metadata. Necessary for delay
+ compensation. Metadata mode is a separate parameter. */
+
+ /* Transport */
+ HANDLE_TRANSPORTENC hTpEnc;
+
+ /* Output */
+ UCHAR *outBuffer; /* Internal bitstream buffer */
+ INT outBufferInBytes; /* Size of internal bitstream buffer*/
+
+ /* Input */
+ INT_PCM *inputBuffer; /* Internal input buffer. Input source for AAC encoder */
+ INT inputBufferOffset; /* Where to write new input samples. */
+
+ INT nSamplesToRead; /* number of input samples neeeded for encoding one frame */
+ INT nSamplesRead; /* number of input samples already in input buffer */
+ INT nZerosAppended; /* appended zeros at end of file*/
+ INT nDelay; /* encoder delay */
+
+ AACENC_EXT_PAYLOAD extPayload [MAX_TOTAL_EXT_PAYLOADS];
+ /* Extension payload */
+ UCHAR extPayloadData [(1)][(6)][MAX_PAYLOAD_SIZE];
+ UINT extPayloadSize [(1)][(6)]; /* payload sizes in bits */
+
+ ULONG InitFlags; /* internal status to treggier re-initialization */
+
+
+ /* Memory allocation info. */
+ INT nMaxAacElements;
+ INT nMaxAacChannels;
+ INT nMaxSbrElements;
+ INT nMaxSbrChannels;
+ UINT nMaxSubFrames;
+
+ UINT encoder_modis;
+
+ /* Capabity flags */
+ UINT CAPF_tpEnc;
+
+} ;
+
+////////////////////////////////////////////////////////////////////////////////////
+
+static inline INT isSbrActive(const HANDLE_AACENC_CONFIG hAacConfig)
+{
+ INT sbrUsed = 0;
+
+ if ( (hAacConfig->audioObjectType==AOT_SBR) || (hAacConfig->audioObjectType==AOT_PS)
+ || (hAacConfig->audioObjectType==AOT_MP2_SBR) || (hAacConfig->audioObjectType==AOT_MP2_PS)
+ || (hAacConfig->audioObjectType==AOT_DABPLUS_SBR) || (hAacConfig->audioObjectType==AOT_DABPLUS_PS)
+ || (hAacConfig->audioObjectType==AOT_DRM_SBR) || (hAacConfig->audioObjectType==AOT_DRM_MPEG_PS) )
+ {
+ sbrUsed = 1;
+ }
+ if (hAacConfig->audioObjectType == AOT_ER_AAC_ELD && (hAacConfig->syntaxFlags & AC_SBR_PRESENT))
+ {
+ sbrUsed = 1;
+ }
+
+ return ( sbrUsed );
+}
+
+/****************************************************************************
+ Allocate Encoder
+****************************************************************************/
+
+H_ALLOC_MEM (_AacEncoder, AACENCODER)
+C_ALLOC_MEM (_AacEncoder, AACENCODER, 1)
+
+
+
+
+/*
+ * Map Encoder specific config structures to CODER_CONFIG.
+ */
+static
+void FDKaacEnc_MapConfig(CODER_CONFIG *cc, USER_PARAM *extCfg, HANDLE_AACENC_CONFIG hAacConfig)
+{
+ AUDIO_OBJECT_TYPE transport_AOT = AOT_NULL_OBJECT;
+ FDKmemclear(cc, sizeof(CODER_CONFIG));
+
+ cc->flags = 0;
+
+ /* Map virtual aot to transport aot. */
+ switch (hAacConfig->audioObjectType) {
+ case AOT_MP2_AAC_LC:
+ transport_AOT = AOT_AAC_LC;
+ break;
+ case AOT_MP2_SBR:
+ transport_AOT = AOT_SBR;
+ cc->flags |= CC_SBR;
+ break;
+ case AOT_MP2_PS:
+ transport_AOT = AOT_PS;
+ cc->flags |= CC_SBR;
+ break;
+ default:
+ transport_AOT = hAacConfig->audioObjectType;
+ }
+
+ if (hAacConfig->audioObjectType == AOT_ER_AAC_ELD) {
+ cc->flags |= (hAacConfig->syntaxFlags & AC_SBR_PRESENT) ? CC_SBR : 0;
+ }
+
+ /* transport type is usually AAC-LC. */
+ if ( (transport_AOT == AOT_SBR) || (transport_AOT == AOT_PS) ) {
+ cc->aot = AOT_AAC_LC;
+ }
+ else {
+ cc->aot = transport_AOT;
+ }
+
+ /* Configure extension aot. */
+ if (extCfg->userTpSignaling==0) {
+ cc->extAOT = AOT_NULL_OBJECT; /* implicit */
+ }
+ else {
+ if ( (extCfg->userTpSignaling==1) && ( (transport_AOT==AOT_SBR) || (transport_AOT==AOT_PS) ) ) {
+ cc->extAOT = AOT_SBR; /* explicit backward compatible */
+ }
+ else {
+ cc->extAOT = transport_AOT; /* explicit hierarchical */
+ }
+ }
+ cc->extSamplingRate = extCfg->userSamplerate;
+ cc->bitRate = hAacConfig->bitRate;
+ cc->noChannels = hAacConfig->nChannels;
+ cc->flags |= CC_IS_BASELAYER;
+ cc->channelMode = hAacConfig->channelMode;
+
+ cc->nSubFrames = (hAacConfig->nSubFrames > 1 && extCfg->userTpNsubFrames == 1)
+ ? hAacConfig->nSubFrames
+ : extCfg->userTpNsubFrames;
+
+ cc->flags |= (extCfg->userTpProtection) ? CC_PROTECTION : 0;
+
+ if (extCfg->userTpHeaderPeriod!=0xFF) {
+ cc->headerPeriod = extCfg->userTpHeaderPeriod;
+ }
+ else { /* auto-mode */
+ switch (extCfg->userTpType) {
+ case TT_MP4_ADTS:
+ case TT_MP4_LOAS:
+ case TT_MP4_LATM_MCP1:
+ cc->headerPeriod = 10;
+ break;
+ default:
+ cc->headerPeriod = 0;
+ }
+ }
+
+ cc->samplesPerFrame = hAacConfig->framelength;
+ cc->samplingRate = hAacConfig->sampleRate;
+
+ /* Mpeg-4 signaling for transport library. */
+ switch ( hAacConfig->audioObjectType ) {
+ case AOT_MP2_AAC_LC:
+ case AOT_MP2_SBR:
+ case AOT_MP2_PS:
+ cc->flags &= ~CC_MPEG_ID; /* Required for ADTS. */
+ //config->userTpSignaling=0;
+ cc->extAOT = AOT_NULL_OBJECT;
+ break;
+ default:
+ cc->flags |= CC_MPEG_ID;
+ }
+
+ /* ER-tools signaling. */
+ cc->flags |= (hAacConfig->syntaxFlags & AC_ER_VCB11) ? CC_VCB11 : 0;
+ cc->flags |= (hAacConfig->syntaxFlags & AC_ER_HCR) ? CC_HCR : 0;
+ cc->flags |= (hAacConfig->syntaxFlags & AC_ER_RVLC) ? CC_RVLC : 0;
+
+ /* Matrix mixdown coefficient configuration. */
+ if ( (extCfg->userPceAdditions&0x1) && (hAacConfig->epConfig==-1)
+ && ((cc->channelMode==MODE_1_2_2)||(cc->channelMode==MODE_1_2_2_1)) )
+ {
+ cc->matrixMixdownA = ((extCfg->userPceAdditions>>1)&0x3)+1;
+ cc->flags |= (extCfg->userPceAdditions>>3)&0x1 ? CC_PSEUDO_SURROUND : 0;
+ }
+ else {
+ cc->matrixMixdownA = 0;
+ }
+}
+
+/*
+ * Examine buffer descriptor regarding choosen identifier.
+ *
+ * \param pBufDesc Pointer to buffer descriptor
+ * \param identifier Buffer identifier to look for.
+
+ * \return - Buffer descriptor index.
+ * -1, if there is no entry available.
+ */
+static INT getBufDescIdx(
+ const AACENC_BufDesc *pBufDesc,
+ const AACENC_BufferIdentifier identifier
+)
+{
+ INT i, idx = -1;
+
+ for (i=0; i<pBufDesc->numBufs; i++) {
+ if ( (AACENC_BufferIdentifier)pBufDesc->bufferIdentifiers[i] == identifier ) {
+ idx = i;
+ break;
+ }
+ }
+ return idx;
+}
+
+
+/****************************************************************************
+ Function Declarations
+****************************************************************************/
+
+AAC_ENCODER_ERROR aacEncDefaultConfig(HANDLE_AACENC_CONFIG hAacConfig,
+ USER_PARAM *config)
+{
+ /* make reasonable default settings */
+ FDKaacEnc_AacInitDefaultConfig (hAacConfig);
+
+ /* clear confure structure and copy default settings */
+ FDKmemclear(config, sizeof(USER_PARAM));
+
+ /* copy encoder configuration settings */
+ config->nChannels = hAacConfig->nChannels;
+ config->userAOT = hAacConfig->audioObjectType = AOT_AAC_LC;
+ config->userSamplerate = hAacConfig->sampleRate;
+ config->userChannelMode = hAacConfig->channelMode;
+ config->userBitrate = hAacConfig->bitRate;
+ config->userBitrateMode = hAacConfig->bitrateMode;
+ config->userBandwidth = hAacConfig->bandWidth;
+ config->userTns = hAacConfig->useTns;
+ config->userPns = hAacConfig->usePns;
+ config->userIntensity = hAacConfig->useIS;
+ config->userAfterburner = hAacConfig->useRequant;
+ config->userFramelength = (UINT)-1;
+
+ if (hAacConfig->syntaxFlags & AC_ER_VCB11) {
+ config->userErTools |= 0x01;
+ }
+ if (hAacConfig->syntaxFlags & AC_ER_HCR) {
+ config->userErTools |= 0x02;
+ }
+
+ /* initialize transport parameters */
+ config->userTpType = TT_UNKNOWN;
+ config->userTpAmxv = 0;
+ config->userTpSignaling = 0; /* default, implicit signaling */
+ config->userTpNsubFrames = 1;
+ config->userTpProtection = 0; /* not crc protected*/
+ config->userTpHeaderPeriod = 0xFF; /* header period in auto mode */
+ config->userPceAdditions = 0; /* no matrix mixdown coefficient */
+ config->userMetaDataMode = 0; /* do not embed any meta data info */
+
+ config->userAncDataRate = 0;
+
+ return AAC_ENC_OK;
+}
+
+/*
+ * \brief Consistency check of given USER_PARAM struct and
+ * copy back configuration from public struct into internal
+ * encoder configuration struct.
+ *
+ * \hAacEncoder Internal encoder config which is to be updated
+ * \param config User provided config (public struct)
+ * \return ´returns always AAC_ENC_OK
+ */
+static
+AACENC_ERROR FDKaacEnc_AdjustEncSettings(HANDLE_AACENCODER hAacEncoder,
+ USER_PARAM *config)
+{
+ AACENC_ERROR err = AACENC_OK;
+
+ /* Get struct pointers. */
+ HANDLE_AACENC_CONFIG hAacConfig = &hAacEncoder->aacConfig;
+
+ hAacConfig->nChannels = config->nChannels;
+
+ /* Encoder settings update. */
+ hAacConfig->sampleRate = config->userSamplerate;
+ hAacConfig->useTns = config->userTns;
+ hAacConfig->usePns = config->userPns;
+ hAacConfig->useIS = config->userIntensity;
+ hAacConfig->bitRate = config->userBitrate;
+ hAacConfig->channelMode = config->userChannelMode;
+ hAacConfig->bitrateMode = config->userBitrateMode;
+ hAacConfig->bandWidth = config->userBandwidth;
+ hAacConfig->useRequant = config->userAfterburner;
+
+ hAacConfig->audioObjectType = config->userAOT;
+ hAacConfig->anc_Rate = config->userAncDataRate;
+ hAacConfig->syntaxFlags = 0;
+ hAacConfig->epConfig = -1;
+
+ /* Adapt internal AOT when necessary. */
+ switch ( hAacConfig->audioObjectType ) {
+ case AOT_MP2_AAC_LC:
+ case AOT_MP2_SBR:
+ case AOT_MP2_PS:
+ hAacConfig->usePns = 0;
+ if (config->userTpSignaling!=0) {
+ return AACENC_INVALID_CONFIG; /* only implicit signaling allowed */
+ }
+ case AOT_AAC_LC:
+ case AOT_SBR:
+ case AOT_PS:
+ config->userTpType = (config->userTpType!=TT_UNKNOWN) ? config->userTpType : TT_MP4_ADTS;
+ hAacConfig->framelength = (config->userFramelength!=(UINT)-1) ? config->userFramelength : 1024;
+ if (hAacConfig->framelength != 1024 && hAacConfig->framelength != 960) {
+ return AACENC_INVALID_CONFIG;
+ }
+ break;
+ case AOT_ER_AAC_LC:
+ hAacConfig->epConfig = 0;
+ hAacConfig->syntaxFlags |= AC_ER;
+ hAacConfig->syntaxFlags |= ((config->userErTools & 0x1) ? AC_ER_VCB11 : 0);
+ hAacConfig->syntaxFlags |= ((config->userErTools & 0x2) ? AC_ER_HCR : 0);
+ config->userTpType = (config->userTpType!=TT_UNKNOWN) ? config->userTpType : TT_MP4_LOAS;
+ hAacConfig->framelength = (config->userFramelength!=(UINT)-1) ? config->userFramelength : 1024;
+ if (hAacConfig->framelength != 1024 && hAacConfig->framelength != 960) {
+ return AACENC_INVALID_CONFIG;
+ }
+ break;
+ case AOT_ER_AAC_LD:
+ hAacConfig->epConfig = 0;
+ hAacConfig->syntaxFlags |= AC_ER|AC_LD;
+ hAacConfig->syntaxFlags |= ((config->userErTools & 0x1) ? AC_ER_VCB11 : 0);
+ hAacConfig->syntaxFlags |= ((config->userErTools & 0x2) ? AC_ER_HCR : 0);
+ hAacConfig->syntaxFlags |= ((config->userErTools & 0x4) ? AC_ER_RVLC : 0);
+ config->userTpType = (config->userTpType!=TT_UNKNOWN) ? config->userTpType : TT_MP4_LOAS;
+ hAacConfig->framelength = (config->userFramelength!=(UINT)-1) ? config->userFramelength : 512;
+ if (hAacConfig->framelength != 512 && hAacConfig->framelength != 480) {
+ return AACENC_INVALID_CONFIG;
+ }
+ break;
+ case AOT_ER_AAC_ELD:
+ hAacConfig->epConfig = 0;
+ hAacConfig->syntaxFlags |= AC_ER|AC_ELD;
+ hAacConfig->syntaxFlags |= ((config->userErTools & 0x1) ? AC_ER_VCB11 : 0);
+ hAacConfig->syntaxFlags |= ((config->userErTools & 0x2) ? AC_ER_HCR : 0);
+ hAacConfig->syntaxFlags |= ((config->userErTools & 0x4) ? AC_ER_RVLC : 0);
+ hAacConfig->syntaxFlags |= ((config->userSbrEnabled) ? AC_SBR_PRESENT : 0);
+ config->userTpType = (config->userTpType!=TT_UNKNOWN) ? config->userTpType : TT_MP4_LOAS;
+ hAacConfig->framelength = (config->userFramelength!=(UINT)-1) ? config->userFramelength : 512;
+ if (hAacConfig->framelength != 512 && hAacConfig->framelength != 480) {
+ return AACENC_INVALID_CONFIG;
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch ( hAacConfig->audioObjectType ) {
+ case AOT_ER_AAC_LD:
+ case AOT_ER_AAC_ELD:
+ if (config->userBitrateMode==8) {
+ hAacConfig->bitrateMode = 0;
+ }
+ if (config->userBitrateMode==0) {
+ hAacConfig->bitreservoir = 50*config->nChannels; /* default, reduced bitreservoir */
+ }
+ if (hAacConfig->bitrateMode!=0) {
+ return AACENC_INVALID_CONFIG;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (hAacConfig->epConfig >= 0) {
+ hAacConfig->syntaxFlags |= AC_ER;
+ if (((INT)hAacConfig->channelMode < 1) || ((INT)hAacConfig->channelMode > 7)) {
+ return AACENC_INVALID_CONFIG; /* Cannel config 0 not supported. */
+ }
+ }
+
+ if ( FDKaacEnc_DetermineEncoderMode(&hAacConfig->channelMode, hAacConfig->nChannels) != AAC_ENC_OK) {
+ return AACENC_INVALID_CONFIG; /* nChannels doesn't match chMode, this is just a check-up */
+ }
+
+ if ( (hAacConfig->nChannels > hAacEncoder->nMaxAacChannels)
+ || ( (FDKaacEnc_GetChannelModeConfiguration(hAacConfig->channelMode)->nChannelsEff > hAacEncoder->nMaxSbrChannels) &&
+ isSbrActive(hAacConfig) )
+ )
+ {
+ return AACENC_INVALID_CONFIG; /* not enough channels allocated */
+ }
+
+ /* get bitrate in VBR configuration */
+ if ( (hAacConfig->bitrateMode>=1) && (hAacConfig->bitrateMode<=5) ) {
+ /* In VBR mode; SBR-modul depends on bitrate, core encoder on bitrateMode. */
+ hAacConfig->bitRate = FDKaacEnc_GetVBRBitrate(hAacConfig->bitrateMode, hAacConfig->channelMode);
+ }
+
+
+
+ /* Set default bitrate if no external bitrate declared. */
+ if (hAacConfig->bitRate==-1) {
+ INT bitrate = FDKaacEnc_GetChannelModeConfiguration(hAacConfig->channelMode)->nChannelsEff * hAacConfig->sampleRate;
+ switch (hAacConfig->audioObjectType)
+ {
+ case AOT_AAC_LC:
+ hAacConfig->bitRate = bitrate + (bitrate>>1); /* 1.5 bits per sample */
+ break;
+ case AOT_SBR:
+ hAacConfig->bitRate = (bitrate + (bitrate>>2))>>1; /* 0.625 bits per sample */
+ break;
+ case AOT_PS:
+ hAacConfig->bitRate = (bitrate>>1); /* 0.5 bit per sample */
+ break;
+ default:
+ hAacConfig->bitRate = bitrate;
+ break;
+ }
+ }
+
+ /* Configure PNS */
+ if ( ((hAacConfig->bitrateMode>=1) && (hAacConfig->bitrateMode<=5)) /* VBR without PNS. */
+ || (hAacConfig->useTns == 0) ) /* TNS required. */
+ {
+ hAacConfig->usePns = 0;
+ }
+
+ /* Meta data restriction. */
+ switch (hAacConfig->audioObjectType)
+ {
+ /* Allow metadata support */
+ case AOT_AAC_LC:
+ case AOT_SBR:
+ hAacEncoder->metaDataAllowed = 1;
+ if (((INT)hAacConfig->channelMode < 1) || ((INT)hAacConfig->channelMode > 7)) {
+ config->userMetaDataMode = 0;
+ }
+ break;
+ /* Prohibit metadata support */
+ default:
+ hAacEncoder->metaDataAllowed = 0;
+ }
+
+ return err;
+}
+
+static
+INT aacenc_SbrCallback(
+ void * self,
+ HANDLE_FDK_BITSTREAM hBs,
+ const INT sampleRateIn,
+ const INT sampleRateOut,
+ const INT samplesPerFrame,
+ const AUDIO_OBJECT_TYPE coreCodec,
+ const MP4_ELEMENT_ID elementID,
+ const INT elementIndex
+ )
+{
+ HANDLE_AACENCODER hAacEncoder = (HANDLE_AACENCODER)self;
+
+ sbrEncoder_GetHeader(hAacEncoder->hEnvEnc, hBs, elementIndex, 0);
+
+ return 0;
+}
+
+static AACENC_ERROR aacEncInit(HANDLE_AACENCODER hAacEncoder,
+ ULONG InitFlags,
+ USER_PARAM *config)
+{
+ AACENC_ERROR err = AACENC_OK;
+
+ INT aacBufferOffset = 0;
+ HANDLE_SBR_ENCODER *hSbrEncoder = &hAacEncoder->hEnvEnc;
+ HANDLE_AACENC_CONFIG hAacConfig = &hAacEncoder->aacConfig;
+
+ hAacEncoder->nZerosAppended = 0; /* count appended zeros */
+
+ INT frameLength = hAacConfig->framelength;
+
+
+ if ( (InitFlags & AACENC_INIT_CONFIG) )
+ {
+ CHANNEL_MODE prevChMode = hAacConfig->channelMode;
+
+ /* Verify settings and update: config -> heAacEncoder */
+ if ( (err=FDKaacEnc_AdjustEncSettings(hAacEncoder, config)) != AACENC_OK ) {
+ return err;
+ }
+ frameLength = hAacConfig->framelength; /* adapt temporal framelength */
+
+ /* Seamless channel reconfiguration in sbr not fully implemented */
+ if ( (prevChMode!=hAacConfig->channelMode) && isSbrActive(hAacConfig) ) {
+ InitFlags |= AACENC_INIT_STATES;
+ }
+ }
+
+ /* Clear input buffer */
+ if ( (InitFlags == AACENC_INIT_ALL) ) {
+ FDKmemclear(hAacEncoder->inputBuffer, sizeof(INT_PCM)*hAacEncoder->nMaxAacChannels*INPUTBUFFER_SIZE);
+ }
+
+ if ( (InitFlags & AACENC_INIT_CONFIG) )
+ {
+ aacBufferOffset = 0;
+ if (hAacConfig->audioObjectType == AOT_ER_AAC_ELD) {
+ hAacEncoder->nDelay = DELAY_AACELD(hAacConfig->framelength);
+ } else
+ {
+ hAacEncoder->nDelay = DELAY_AAC(hAacConfig->framelength); /* AAC encoder delay */
+ }
+ hAacConfig->ancDataBitRate = 0;
+ }
+
+ if ( isSbrActive(hAacConfig) &&
+ ((InitFlags & AACENC_INIT_CONFIG) || (InitFlags & AACENC_INIT_STATES)) )
+ {
+ INT sbrError;
+ SBR_ELEMENT_INFO sbrElInfo[(6)];
+ CHANNEL_MAPPING channelMapping;
+ int el;
+ INT codebits = hAacConfig->bitRate;
+ INT bitrateSc = CountLeadingBits(codebits);
+ AUDIO_OBJECT_TYPE aot = hAacConfig->audioObjectType;
+
+ if ( FDKaacEnc_InitChannelMapping(hAacConfig->channelMode,
+ hAacConfig->channelOrder,
+ &channelMapping) != AAC_ENC_OK )
+ {
+ return AACENC_INIT_ERROR;
+ }
+
+ /* Check return value and if the SBR encoder can handle enough elements */
+ if (channelMapping.nElements > (6)) {
+ return AACENC_INIT_ERROR;
+ }
+
+ /* Copy Element info */
+ for (el=0; el<channelMapping.nElements; el++) {
+ sbrElInfo[el].ChannelIndex[0] = channelMapping.elInfo[el].ChannelIndex[0];
+ sbrElInfo[el].ChannelIndex[1] = channelMapping.elInfo[el].ChannelIndex[1];
+ sbrElInfo[el].elType = channelMapping.elInfo[el].elType;
+ sbrElInfo[el].bitRate = (INT)(fMult(channelMapping.elInfo[el].relativeBits, (FIXP_DBL)(hAacConfig->bitRate<<bitrateSc))>>(bitrateSc));
+ sbrElInfo[el].instanceTag = channelMapping.elInfo[el].instanceTag;
+ sbrElInfo[el].nChannelsInEl = channelMapping.elInfo[el].nChannelsInEl;
+
+ sbrElInfo[el].bitRate = fMult(channelMapping.elInfo[el].relativeBits, (FIXP_DBL)hAacConfig->bitRate);
+ codebits -= sbrElInfo[el].bitRate;
+ }
+ sbrElInfo[0].bitRate += codebits;
+
+ UINT initFlag = 0;
+ initFlag += (InitFlags & AACENC_INIT_STATES) ? 1 : 0;
+
+ /* Let the SBR encoder take a look at the configuration and change if required. */
+ sbrError = sbrEncoder_Init(
+ *hSbrEncoder,
+ sbrElInfo,
+ channelMapping.nElements,
+ hAacEncoder->inputBuffer,
+ &hAacConfig->bandWidth,
+ &aacBufferOffset,
+ &hAacConfig->nChannels,
+ &hAacConfig->sampleRate,
+ &frameLength,
+ &hAacConfig->audioObjectType,
+ &hAacEncoder->nDelay,
+ (hAacConfig->audioObjectType == AOT_ER_AAC_ELD) ? 1 : TRANS_FAC,
+ initFlag
+ );
+
+ /* Suppress AOT reconfiguration and check error status. */
+ if ( sbrError || (hAacConfig->audioObjectType!=aot) ) {
+ return AACENC_INIT_SBR_ERROR;
+ }
+
+ if (hAacConfig->nChannels == 1) {
+ hAacConfig->channelMode = MODE_1;
+ }
+
+ /* Never use PNS if SBR is active */
+ if ( hAacConfig->usePns ) {
+ hAacConfig->usePns = 0;
+ }
+
+ /* estimated bitrate consumed by SBR or PS */
+ hAacConfig->ancDataBitRate = sbrEncoder_GetEstimateBitrate(*hSbrEncoder) ;
+
+ } /* sbr initialization */
+
+
+ /*
+ * Initialize Transport - Module.
+ */
+ if ( (InitFlags & AACENC_INIT_TRANSPORT) )
+ {
+ UINT flags = 0;
+
+ FDKaacEnc_MapConfig(&hAacEncoder->coderConfig, config, hAacConfig);
+
+ /* create flags for transport encoder */
+ if (config->userTpAmxv == 1) {
+ flags |= TP_FLAG_LATM_AMV;
+ }
+ /* Clear output buffer */
+ FDKmemclear(hAacEncoder->outBuffer, hAacEncoder->outBufferInBytes*sizeof(UCHAR));
+
+ /* Initialize Bitstream encoder */
+ if ( transportEnc_Init(hAacEncoder->hTpEnc, hAacEncoder->outBuffer, hAacEncoder->outBufferInBytes, config->userTpType, &hAacEncoder->coderConfig, flags) != 0) {
+ return AACENC_INIT_TP_ERROR;
+ }
+
+ } /* transport initialization */
+
+ /*
+ * Initialize AAC - Core.
+ */
+ if ( (InitFlags & AACENC_INIT_CONFIG) ||
+ (InitFlags & AACENC_INIT_STATES) )
+ {
+ AAC_ENCODER_ERROR err;
+ err = FDKaacEnc_Initialize(hAacEncoder->hAacEnc,
+ hAacConfig,
+ hAacEncoder->hTpEnc,
+ (InitFlags & AACENC_INIT_STATES) ? 1 : 0);
+
+ if (err != AAC_ENC_OK) {
+ return AACENC_INIT_AAC_ERROR;
+ }
+
+ } /* aac initialization */
+
+ /*
+ * Initialize Meta Data - Encoder.
+ */
+ if ( hAacEncoder->hMetadataEnc && (hAacEncoder->metaDataAllowed!=0) &&
+ ((InitFlags & AACENC_INIT_CONFIG) ||(InitFlags & AACENC_INIT_STATES)) )
+ {
+ INT inputDataDelay = DELAY_AAC(hAacConfig->framelength);
+
+ if ( isSbrActive(hAacConfig) && hSbrEncoder!=NULL) {
+ inputDataDelay = 2*inputDataDelay + sbrEncoder_GetInputDataDelay(*hSbrEncoder);
+ }
+
+ if ( FDK_MetadataEnc_Init(hAacEncoder->hMetadataEnc,
+ ((InitFlags&AACENC_INIT_STATES) ? 1 : 0),
+ config->userMetaDataMode,
+ inputDataDelay,
+ frameLength,
+ config->userSamplerate,
+ config->nChannels,
+ config->userChannelMode,
+ hAacConfig->channelOrder) != 0)
+ {
+ return AACENC_INIT_META_ERROR;
+ }
+
+ hAacEncoder->nDelay += FDK_MetadataEnc_GetDelay(hAacEncoder->hMetadataEnc);
+ }
+
+ /*
+ * Update pointer to working buffer.
+ */
+ if ( (InitFlags & AACENC_INIT_CONFIG) )
+ {
+ hAacEncoder->inputBufferOffset = aacBufferOffset;
+
+ hAacEncoder->nSamplesToRead = frameLength * config->nChannels;
+
+ /* Make nDelay comparison compatible with config->nSamplesRead */
+ hAacEncoder->nDelay *= config->nChannels;
+
+ } /* parameter changed */
+
+ return AACENC_OK;
+}
+
+
+AACENC_ERROR aacEncOpen(
+ HANDLE_AACENCODER *phAacEncoder,
+ const UINT encModules,
+ const UINT maxChannels
+ )
+{
+ AACENC_ERROR err = AACENC_OK;
+ HANDLE_AACENCODER hAacEncoder = NULL;
+
+ if (phAacEncoder == NULL) {
+ err = AACENC_INVALID_HANDLE;
+ goto bail;
+ }
+
+ /* allocate memory */
+ hAacEncoder = Get_AacEncoder();
+
+ if (hAacEncoder == NULL) {
+ err = AACENC_MEMORY_ERROR;
+ goto bail;
+ }
+
+ FDKmemclear(hAacEncoder, sizeof(AACENCODER));
+
+ /* Specify encoder modules to be allocated. */
+ if (encModules==0) {
+ hAacEncoder->encoder_modis = ENC_MODE_FLAG_AAC;
+ hAacEncoder->encoder_modis |= ENC_MODE_FLAG_SBR;
+ hAacEncoder->encoder_modis |= ENC_MODE_FLAG_PS;
+ hAacEncoder->encoder_modis |= ENC_MODE_FLAG_META;
+ }
+ else {
+ /* consider SAC and PS module */
+ hAacEncoder->encoder_modis = encModules;
+ }
+
+ /* Determine max channel configuration. */
+ if (maxChannels==0) {
+ hAacEncoder->nMaxAacChannels = (6);
+ hAacEncoder->nMaxSbrChannels = (6);
+ }
+ else {
+ hAacEncoder->nMaxAacChannels = (maxChannels&0x00FF);
+ if ( (hAacEncoder->encoder_modis&ENC_MODE_FLAG_SBR) ) {
+ hAacEncoder->nMaxSbrChannels = (maxChannels&0xFF00) ? (maxChannels>>8) : hAacEncoder->nMaxAacChannels;
+ }
+
+ if ( (hAacEncoder->nMaxAacChannels>(6)) || (hAacEncoder->nMaxSbrChannels>(6)) ) {
+ err = AACENC_INVALID_CONFIG;
+ goto bail;
+ }
+ } /* maxChannels==0 */
+
+ /* Max number of elements could be tuned any more. */
+ hAacEncoder->nMaxAacElements = fixMin((6), hAacEncoder->nMaxAacChannels);
+ hAacEncoder->nMaxSbrElements = fixMin((6), hAacEncoder->nMaxSbrChannels);
+ hAacEncoder->nMaxSubFrames = (1);
+
+
+ /* In case of memory overlay, allocate memory out of libraries */
+
+ hAacEncoder->inputBuffer = (INT_PCM*)FDKcalloc(hAacEncoder->nMaxAacChannels*INPUTBUFFER_SIZE, sizeof(INT_PCM));
+
+ /* Open SBR Encoder */
+ if (hAacEncoder->encoder_modis&ENC_MODE_FLAG_SBR) {
+ if ( sbrEncoder_Open(&hAacEncoder->hEnvEnc,
+ hAacEncoder->nMaxSbrElements,
+ hAacEncoder->nMaxSbrChannels,
+ (hAacEncoder->encoder_modis&ENC_MODE_FLAG_PS) ? 1 : 0 ) )
+ {
+ err = AACENC_MEMORY_ERROR;
+ goto bail;
+ }
+ } /* (encoder_modis&ENC_MODE_FLAG_SBR) */
+
+
+ /* Open Aac Encoder */
+ if ( FDKaacEnc_Open(&hAacEncoder->hAacEnc,
+ hAacEncoder->nMaxAacElements,
+ hAacEncoder->nMaxAacChannels,
+ (1)) != AAC_ENC_OK )
+ {
+ err = AACENC_MEMORY_ERROR;
+ goto bail;
+ }
+
+ { /* Get bitstream outputbuffer size */
+ UINT ld_M;
+ for (ld_M=1; (UINT)(1<<ld_M) < (hAacEncoder->nMaxSubFrames*hAacEncoder->nMaxAacChannels*6144)>>3; ld_M++) ;
+ hAacEncoder->outBufferInBytes = (1<<ld_M); /* buffer has to be 2^n */
+ }
+ hAacEncoder->outBuffer = GetRam_bsOutbuffer();
+ if (OUTPUTBUFFER_SIZE < hAacEncoder->outBufferInBytes ) {
+ err = AACENC_MEMORY_ERROR;
+ goto bail;
+ }
+
+ /* Open Meta Data Encoder */
+ if (hAacEncoder->encoder_modis&ENC_MODE_FLAG_META) {
+ if ( FDK_MetadataEnc_Open(&hAacEncoder->hMetadataEnc) )
+ {
+ err = AACENC_MEMORY_ERROR;
+ goto bail;
+ }
+ } /* (encoder_modis&ENC_MODE_FLAG_META) */
+
+ /* Open Transport Encoder */
+ if ( transportEnc_Open(&hAacEncoder->hTpEnc) != 0 )
+ {
+ err = AACENC_MEMORY_ERROR;
+ goto bail;
+ }
+ else {
+ C_ALLOC_SCRATCH_START(pLibInfo, LIB_INFO, FDK_MODULE_LAST);
+
+ FDKinitLibInfo( pLibInfo);
+ transportEnc_GetLibInfo( pLibInfo );
+
+ /* Get capabilty flag for transport encoder. */
+ hAacEncoder->CAPF_tpEnc = FDKlibInfo_getCapabilities( pLibInfo, FDK_TPENC);
+
+ C_ALLOC_SCRATCH_END(pLibInfo, LIB_INFO, FDK_MODULE_LAST);
+ }
+ if ( transportEnc_RegisterSbrCallback(hAacEncoder->hTpEnc, aacenc_SbrCallback, hAacEncoder) != 0 ) {
+ err = AACENC_INIT_TP_ERROR;
+ goto bail;
+ }
+
+ /* Initialize encoder instance with default parameters. */
+ aacEncDefaultConfig(&hAacEncoder->aacConfig, &hAacEncoder->extParam);
+
+ /* Initialize headerPeriod in coderConfig for aacEncoder_GetParam(). */
+ hAacEncoder->coderConfig.headerPeriod = hAacEncoder->extParam.userTpHeaderPeriod;
+
+ /* All encoder modules have to be initialized */
+ hAacEncoder->InitFlags = AACENC_INIT_ALL;
+
+ /* Return encoder instance */
+ *phAacEncoder = hAacEncoder;
+
+ return err;
+
+bail:
+ aacEncClose(&hAacEncoder);
+
+ return err;
+}
+
+
+
+AACENC_ERROR aacEncClose(HANDLE_AACENCODER *phAacEncoder)
+{
+ AACENC_ERROR err = AACENC_OK;
+
+ if (phAacEncoder == NULL) {
+ err = AACENC_INVALID_HANDLE;
+ goto bail;
+ }
+
+ if (*phAacEncoder != NULL) {
+ HANDLE_AACENCODER hAacEncoder = *phAacEncoder;
+
+
+ if (hAacEncoder->inputBuffer!=NULL) {
+ FDKfree(hAacEncoder->inputBuffer);
+ hAacEncoder->inputBuffer = NULL;
+ }
+
+ if (hAacEncoder->outBuffer) {
+ FreeRam_bsOutbuffer(&hAacEncoder->outBuffer);
+ }
+
+ if (hAacEncoder->hEnvEnc) {
+ sbrEncoder_Close (&hAacEncoder->hEnvEnc);
+ }
+ if (hAacEncoder->hAacEnc) {
+ FDKaacEnc_Close (&hAacEncoder->hAacEnc);
+ }
+
+ transportEnc_Close(&hAacEncoder->hTpEnc);
+
+ if (hAacEncoder->hMetadataEnc) {
+ FDK_MetadataEnc_Close (&hAacEncoder->hMetadataEnc);
+ }
+
+ Free_AacEncoder(phAacEncoder);
+ }
+
+bail:
+ return err;
+}
+
+AACENC_ERROR aacEncEncode(
+ const HANDLE_AACENCODER hAacEncoder,
+ const AACENC_BufDesc *inBufDesc,
+ const AACENC_BufDesc *outBufDesc,
+ const AACENC_InArgs *inargs,
+ AACENC_OutArgs *outargs
+ )
+{
+ AACENC_ERROR err = AACENC_OK;
+ INT i, nBsBytes = 0;
+ INT outBytes[(1)];
+ int nExtensions = 0;
+ int ancDataExtIdx = -1;
+
+ /* deal with valid encoder handle */
+ if (hAacEncoder==NULL) {
+ err = AACENC_INVALID_HANDLE;
+ goto bail;
+ }
+
+
+ /*
+ * Adjust user settings and trigger reinitialization.
+ */
+ if (hAacEncoder->InitFlags!=0) {
+
+ err = aacEncInit(hAacEncoder,
+ hAacEncoder->InitFlags,
+ &hAacEncoder->extParam);
+
+ if (err!=AACENC_OK) {
+ /* keep init flags alive! */
+ goto bail;
+ }
+ hAacEncoder->InitFlags = AACENC_INIT_NONE;
+ }
+
+ if (outargs!=NULL) {
+ FDKmemclear(outargs, sizeof(AACENC_OutArgs));
+ }
+
+ if (outBufDesc!=NULL) {
+ for (i=0; i<outBufDesc->numBufs; i++) {
+ if (outBufDesc->bufs[i]!=NULL) {
+ FDKmemclear(outBufDesc->bufs[i], outBufDesc->bufSizes[i]);
+ }
+ }
+ }
+
+ /*
+ * If only encoder handle given, independent (re)initialization can be triggered.
+ */
+ if ( (hAacEncoder!=NULL) & (inBufDesc==NULL) && (outBufDesc==NULL) && (inargs==NULL) && (outargs==NULL) ) {
+ goto bail;
+ }
+
+ /* reset buffer wich signals number of valid bytes in output bitstream buffer */
+ FDKmemclear(outBytes, hAacEncoder->aacConfig.nSubFrames*sizeof(INT));
+
+ /*
+ * Manage incoming audio samples.
+ */
+ if ( (inargs->numInSamples > 0) && (getBufDescIdx(inBufDesc,IN_AUDIO_DATA) != -1) )
+ {
+ /* Fetch data until nSamplesToRead reached */
+ INT idx = getBufDescIdx(inBufDesc,IN_AUDIO_DATA);
+ INT newSamples = fixMax(0,fixMin(inargs->numInSamples, hAacEncoder->nSamplesToRead-hAacEncoder->nSamplesRead));
+ INT_PCM *pIn = hAacEncoder->inputBuffer+hAacEncoder->inputBufferOffset+hAacEncoder->nSamplesRead;
+
+ /* Copy new input samples to internal buffer */
+ if (inBufDesc->bufElSizes[idx]==(INT)sizeof(INT_PCM)) {
+ FDKmemcpy(pIn, (INT_PCM*)inBufDesc->bufs[idx], newSamples*sizeof(INT_PCM)); /* Fast copy. */
+ }
+ else if (inBufDesc->bufElSizes[idx]>(INT)sizeof(INT_PCM)) {
+ for (i=0; i<newSamples; i++) {
+ pIn[i] = (INT_PCM)(((LONG*)inBufDesc->bufs[idx])[i]>>16); /* Convert 32 to 16 bit. */
+ }
+ }
+ else {
+ for (i=0; i<newSamples; i++) {
+ pIn[i] = ((INT_PCM)(((SHORT*)inBufDesc->bufs[idx])[i]))<<16; /* Convert 16 to 32 bit. */
+ }
+ }
+ hAacEncoder->nSamplesRead += newSamples;
+
+ /* Number of fetched input buffer samples. */
+ outargs->numInSamples = newSamples;
+ }
+
+ /* input buffer completely filled ? */
+ if (hAacEncoder->nSamplesRead < hAacEncoder->nSamplesToRead)
+ {
+ /* - eof reached and flushing enabled, or
+ - return to main and wait for further incoming audio samples */
+ if (inargs->numInSamples==-1)
+ {
+ if ( (hAacEncoder->nZerosAppended < hAacEncoder->nDelay)
+ )
+ {
+ int nZeros = hAacEncoder->nSamplesToRead - hAacEncoder->nSamplesRead;
+
+ FDK_ASSERT(nZeros >= 0);
+
+ /* clear out until end-of-buffer */
+ if (nZeros) {
+ FDKmemclear(hAacEncoder->inputBuffer+hAacEncoder->inputBufferOffset+hAacEncoder->nSamplesRead, sizeof(INT_PCM)*nZeros );
+ hAacEncoder->nZerosAppended += nZeros;
+ hAacEncoder->nSamplesRead = hAacEncoder->nSamplesToRead;
+ }
+ }
+ else { /* flushing completed */
+ err = AACENC_ENCODE_EOF; /* eof reached */
+ goto bail;
+ }
+ }
+ else { /* inargs->numInSamples!= -1 */
+ goto bail; /* not enough samples in input buffer and no flushing enabled */
+ }
+ }
+
+ /* init payload */
+ FDKmemclear(hAacEncoder->extPayload, sizeof(AACENC_EXT_PAYLOAD) * MAX_TOTAL_EXT_PAYLOADS);
+ for (i = 0; i < MAX_TOTAL_EXT_PAYLOADS; i++) {
+ hAacEncoder->extPayload[i].associatedChElement = -1;
+ }
+ FDKmemclear(hAacEncoder->extPayloadData, sizeof(hAacEncoder->extPayloadData));
+ FDKmemclear(hAacEncoder->extPayloadSize, sizeof(hAacEncoder->extPayloadSize));
+
+
+ /*
+ * Calculate Meta Data info.
+ */
+ if ( (hAacEncoder->hMetadataEnc!=NULL) && (hAacEncoder->metaDataAllowed!=0) ) {
+
+ const AACENC_MetaData *pMetaData = NULL;
+ AACENC_EXT_PAYLOAD *pMetaDataExtPayload = NULL;
+ UINT nMetaDataExtensions = 0;
+ INT matrix_mixdown_idx = 0;
+
+ /* New meta data info available ? */
+ if ( getBufDescIdx(inBufDesc,IN_METADATA_SETUP) != -1 ) {
+ pMetaData = (AACENC_MetaData*)inBufDesc->bufs[getBufDescIdx(inBufDesc,IN_METADATA_SETUP)];
+ }
+
+ FDK_MetadataEnc_Process(hAacEncoder->hMetadataEnc,
+ hAacEncoder->inputBuffer+hAacEncoder->inputBufferOffset,
+ hAacEncoder->nSamplesRead,
+ pMetaData,
+ &pMetaDataExtPayload,
+ &nMetaDataExtensions,
+ &matrix_mixdown_idx
+ );
+
+ for (i=0; i<(INT)nMetaDataExtensions; i++) { /* Get meta data extension payload. */
+ hAacEncoder->extPayload[nExtensions++] = pMetaDataExtPayload[i];
+ }
+ if (matrix_mixdown_idx!=-1) { /* Set matrix mixdown coefficient. */
+ UINT pceValue = (UINT)( (1<<3) | ((matrix_mixdown_idx&0x2)<<1) | 1 );
+ if (hAacEncoder->extParam.userPceAdditions != pceValue) {
+ hAacEncoder->extParam.userPceAdditions = pceValue;
+ hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT;
+ }
+ }
+ }
+
+
+ if ( isSbrActive(&hAacEncoder->aacConfig) ) {
+
+ INT nPayload = 0;
+
+ /*
+ * Encode SBR data.
+ */
+ if (sbrEncoder_EncodeFrame(hAacEncoder->hEnvEnc,
+ hAacEncoder->inputBuffer,
+ hAacEncoder->extParam.nChannels,
+ hAacEncoder->extPayloadSize[nPayload],
+ hAacEncoder->extPayloadData[nPayload]
+#if defined(EVAL_PACKAGE_SILENCE) || defined(EVAL_PACKAGE_SBR_SILENCE)
+ ,hAacEncoder->hAacEnc->clearOutput
+#endif
+ ))
+ {
+ err = AACENC_ENCODE_ERROR;
+ goto bail;
+ }
+ else {
+ /* Add SBR extension payload */
+ for (i = 0; i < (6); i++) {
+ if (hAacEncoder->extPayloadSize[nPayload][i] > 0) {
+ hAacEncoder->extPayload[nExtensions].pData = hAacEncoder->extPayloadData[nPayload][i];
+ {
+ hAacEncoder->extPayload[nExtensions].dataSize = hAacEncoder->extPayloadSize[nPayload][i];
+ hAacEncoder->extPayload[nExtensions].associatedChElement = i;
+ }
+ hAacEncoder->extPayload[nExtensions].dataType = EXT_SBR_DATA; /* Once SBR Encoder supports SBR CRC set EXT_SBR_DATA_CRC */
+ nExtensions++; /* or EXT_SBR_DATA according to configuration. */
+ FDK_ASSERT(nExtensions<=MAX_TOTAL_EXT_PAYLOADS);
+ }
+ }
+ nPayload++;
+ }
+ } /* sbrEnabled */
+
+ if ( (inargs->numAncBytes > 0) && ( getBufDescIdx(inBufDesc,IN_ANCILLRY_DATA)!=-1 ) ) {
+ INT idx = getBufDescIdx(inBufDesc,IN_ANCILLRY_DATA);
+ hAacEncoder->extPayload[nExtensions].dataSize = inargs->numAncBytes * 8;
+ hAacEncoder->extPayload[nExtensions].pData = (UCHAR*)inBufDesc->bufs[idx];
+ hAacEncoder->extPayload[nExtensions].dataType = EXT_DATA_ELEMENT;
+ hAacEncoder->extPayload[nExtensions].associatedChElement = -1;
+ ancDataExtIdx = nExtensions; /* store index */
+ nExtensions++;
+ }
+
+ /*
+ * Encode AAC - Core.
+ */
+ if ( FDKaacEnc_EncodeFrame( hAacEncoder->hAacEnc,
+ hAacEncoder->hTpEnc,
+ hAacEncoder->inputBuffer,
+ outBytes,
+ hAacEncoder->extPayload
+ ) != AAC_ENC_OK )
+ {
+ err = AACENC_ENCODE_ERROR;
+ goto bail;
+ }
+
+ if (ancDataExtIdx >= 0) {
+ outargs->numAncBytes = inargs->numAncBytes - (hAacEncoder->extPayload[ancDataExtIdx].dataSize>>3);
+ }
+
+ /* samples exhausted */
+ hAacEncoder->nSamplesRead -= hAacEncoder->nSamplesToRead;
+
+ /*
+ * Delay balancing buffer handling
+ */
+ if (isSbrActive(&hAacEncoder->aacConfig)) {
+ sbrEncoder_UpdateBuffers(hAacEncoder->hEnvEnc, hAacEncoder->inputBuffer);
+ }
+
+ /*
+ * Make bitstream public
+ */
+ if (outBufDesc->numBufs>=1) {
+
+ INT bsIdx = getBufDescIdx(outBufDesc,OUT_BITSTREAM_DATA);
+ INT auIdx = getBufDescIdx(outBufDesc,OUT_AU_SIZES);
+
+ for (i=0,nBsBytes=0; i<hAacEncoder->aacConfig.nSubFrames; i++) {
+ nBsBytes += outBytes[i];
+
+ if (auIdx!=-1) {
+ ((INT*)outBufDesc->bufs[auIdx])[i] = outBytes[i];
+ }
+ }
+
+ if ( (bsIdx!=-1) && (outBufDesc->bufSizes[bsIdx]>=nBsBytes) ) {
+ FDKmemcpy(outBufDesc->bufs[bsIdx], hAacEncoder->outBuffer, sizeof(UCHAR)*nBsBytes);
+ outargs->numOutBytes = nBsBytes;
+ }
+ else {
+ /* output buffer too small, can't write valid bitstream */
+ err = AACENC_ENCODE_ERROR;
+ goto bail;
+ }
+ }
+
+bail:
+ if (err == AACENC_ENCODE_ERROR) {
+ /* All encoder modules have to be initialized */
+ hAacEncoder->InitFlags = AACENC_INIT_ALL;
+ }
+
+ return err;
+}
+
+static
+AAC_ENCODER_ERROR aacEncGetConf(HANDLE_AACENCODER hAacEncoder,
+ UINT *size,
+ UCHAR *confBuffer)
+{
+ FDK_BITSTREAM tmpConf;
+ UINT confType;
+ UCHAR buf[64];
+ int err;
+
+ /* Init bit buffer */
+ FDKinitBitStream(&tmpConf, buf, 64, 0, BS_WRITER);
+
+ /* write conf in tmp buffer */
+ err = transportEnc_GetConf(hAacEncoder->hTpEnc, &hAacEncoder->coderConfig, &tmpConf, &confType);
+
+ /* copy data to outbuffer: length in bytes */
+ FDKbyteAlign(&tmpConf, 0);
+
+ /* Check buffer size */
+ if (FDKgetValidBits(&tmpConf) > ((*size)<<3))
+ return AAC_ENC_UNKNOWN;
+
+ FDKfetchBuffer(&tmpConf, confBuffer, size);
+
+ if (err != 0)
+ return AAC_ENC_UNKNOWN;
+ else
+ return AAC_ENC_OK;
+}
+
+
+AACENC_ERROR aacEncGetLibInfo(LIB_INFO *info)
+{
+ int i = 0;
+
+ if (info == NULL) {
+ return AACENC_INVALID_HANDLE;
+ }
+
+ FDK_toolsGetLibInfo( info );
+ transportEnc_GetLibInfo( info );
+
+ sbrEncoder_GetLibInfo( info );
+
+ /* 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 AACENC_INIT_ERROR;
+ }
+
+ info[i].module_id = FDK_AACENC;
+ info[i].build_date = (char*)AACENCODER_LIB_BUILD_DATE;
+ info[i].build_time = (char*)AACENCODER_LIB_BUILD_TIME;
+ info[i].title = (char*)AACENCODER_LIB_TITLE;
+ info[i].version = LIB_VERSION(AACENCODER_LIB_VL0, AACENCODER_LIB_VL1, AACENCODER_LIB_VL2);;
+ LIB_VERSION_STRING(&info[i]);
+
+ /* Capability flags */
+ info[i].flags = 0
+ | CAPF_AAC_1024 | CAPF_AAC_LC
+ | CAPF_AAC_512
+ | CAPF_AAC_480
+ | CAPF_AAC_DRC
+ ;
+ /* End of flags */
+
+ return AACENC_OK;
+}
+
+AACENC_ERROR aacEncoder_SetParam(
+ const HANDLE_AACENCODER hAacEncoder,
+ const AACENC_PARAM param,
+ const UINT value
+ )
+{
+ AACENC_ERROR err = AACENC_OK;
+ USER_PARAM *settings = &hAacEncoder->extParam;
+
+ /* check encoder handle */
+ if (hAacEncoder == NULL) {
+ err = AACENC_INVALID_HANDLE;
+ goto bail;
+ }
+
+ /* apply param value */
+ switch (param)
+ {
+ case AACENC_AOT:
+ if (settings->userAOT != (AUDIO_OBJECT_TYPE)value) {
+ /* check if AOT matches the allocated modules */
+ switch ( value ) {
+ case AOT_PS:
+ case AOT_MP2_PS:
+ if (!(hAacEncoder->encoder_modis & (ENC_MODE_FLAG_PS))) {
+ err = AACENC_INVALID_CONFIG;
+ goto bail;
+ }
+ case AOT_SBR:
+ case AOT_MP2_SBR:
+ if (!(hAacEncoder->encoder_modis & (ENC_MODE_FLAG_SBR))) {
+ err = AACENC_INVALID_CONFIG;
+ goto bail;
+ }
+ case AOT_AAC_LC:
+ case AOT_MP2_AAC_LC:
+ case AOT_ER_AAC_LC:
+ case AOT_ER_AAC_LD:
+ case AOT_ER_AAC_ELD:
+ if (!(hAacEncoder->encoder_modis & (ENC_MODE_FLAG_AAC))) {
+ err = AACENC_INVALID_CONFIG;
+ goto bail;
+ }
+ break;
+ default:
+ err = AACENC_INVALID_CONFIG;
+ goto bail;
+ }/* switch value */
+ settings->userAOT = (AUDIO_OBJECT_TYPE)value;
+ hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_STATES | AACENC_INIT_TRANSPORT;
+ }
+ break;
+ case AACENC_BITRATE:
+ if (settings->userBitrate != value) {
+ settings->userBitrate = value;
+ hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_TRANSPORT;
+ }
+ break;
+ case AACENC_BITRATEMODE:
+ if (settings->userBitrateMode != value) {
+ switch ( value ) {
+ case 0:
+ case 8:
+ settings->userBitrateMode = value;
+ hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_TRANSPORT;
+ break;
+ default:
+ err = AACENC_INVALID_CONFIG;
+ break;
+ } /* switch value */
+ }
+ break;
+ case AACENC_SAMPLERATE:
+ if (settings->userSamplerate != value) {
+ if ( !( (value==8000) || (value==11025) || (value==12000) || (value==16000) || (value==22050) || (value==24000) ||
+ (value==32000) || (value==44100) || (value==48000) || (value==64000) || (value==88200) || (value==96000) ) )
+ {
+ err = AACENC_INVALID_CONFIG;
+ break;
+ }
+ settings->userSamplerate = value;
+ hAacEncoder->nSamplesRead = 0; /* reset internal inputbuffer */
+ hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_STATES | AACENC_INIT_TRANSPORT;
+ }
+ break;
+ case AACENC_CHANNELMODE:
+ if (settings->userChannelMode != (CHANNEL_MODE)value) {
+ const CHANNEL_MODE_CONFIG_TAB* pConfig = FDKaacEnc_GetChannelModeConfiguration((CHANNEL_MODE)value);
+ if (pConfig==NULL) {
+ err = AACENC_INVALID_CONFIG;
+ break;
+ }
+ if ( (pConfig->nElements > hAacEncoder->nMaxAacElements)
+ || (pConfig->nChannelsEff > hAacEncoder->nMaxAacChannels)
+ || !((value>=1) && (value<=6))
+ )
+ {
+ err = AACENC_INVALID_CONFIG;
+ break;
+ }
+
+ settings->userChannelMode = (CHANNEL_MODE)value;
+ settings->nChannels = pConfig->nChannels;
+ hAacEncoder->nSamplesRead = 0; /* reset internal inputbuffer */
+ hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_TRANSPORT;
+ }
+ break;
+ case AACENC_BANDWIDTH:
+ if (settings->userBandwidth != value) {
+ settings->userBandwidth = value;
+ hAacEncoder->InitFlags |= AACENC_INIT_CONFIG;
+ }
+ break;
+ case AACENC_CHANNELORDER:
+ if (hAacEncoder->aacConfig.channelOrder != (CHANNEL_ORDER)value) {
+ if (! ((value==0) || (value==1)) ) {
+ err = AACENC_INVALID_CONFIG;
+ break;
+ }
+ hAacEncoder->aacConfig.channelOrder = (CHANNEL_ORDER)value;
+ hAacEncoder->nSamplesRead = 0; /* reset internal inputbuffer */
+ hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_STATES | AACENC_INIT_TRANSPORT;
+ }
+ break;
+ case AACENC_AFTERBURNER:
+ if (settings->userAfterburner != value) {
+ if (! ((value==0) || (value==1)) ) {
+ err = AACENC_INVALID_CONFIG;
+ break;
+ }
+ settings->userAfterburner = value;
+ hAacEncoder->InitFlags |= AACENC_INIT_CONFIG;
+ }
+ break;
+ case AACENC_GRANULE_LENGTH:
+ if (settings->userFramelength != value) {
+ switch (value) {
+ case 1024:
+ case 512:
+ case 480:
+ settings->userFramelength = value;
+ hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_TRANSPORT;
+ break;
+ default:
+ err = AACENC_INVALID_CONFIG;
+ break;
+ }
+ }
+ break;
+ case AACENC_SBR_MODE:
+ if (settings->userSbrEnabled != value) {
+ settings->userSbrEnabled = value;
+ hAacEncoder->InitFlags |= AACENC_INIT_CONFIG | AACENC_INIT_STATES | AACENC_INIT_TRANSPORT;
+ }
+ break;
+ case AACENC_TRANSMUX:
+ if (settings->userTpType != (TRANSPORT_TYPE)value) {
+
+ TRANSPORT_TYPE type = (TRANSPORT_TYPE)value;
+ UINT flags = hAacEncoder->CAPF_tpEnc;
+
+ if ( !( ((type==TT_MP4_ADIF) && (flags&CAPF_ADIF))
+ || ((type==TT_MP4_ADTS) && (flags&CAPF_ADTS))
+ || ((type==TT_MP4_LATM_MCP0) && ((flags&CAPF_LATM) && (flags&CAPF_RAWPACKETS)))
+ || ((type==TT_MP4_LATM_MCP1) && ((flags&CAPF_LATM) && (flags&CAPF_RAWPACKETS)))
+ || ((type==TT_MP4_LOAS) && (flags&CAPF_LOAS))
+ || ((type==TT_MP4_RAW) && (flags&CAPF_RAWPACKETS))
+ ) )
+ {
+ err = AACENC_INVALID_CONFIG;
+ break;
+ }
+ settings->userTpType = (TRANSPORT_TYPE)value;
+ hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT;
+ }
+ break;
+ case AACENC_SIGNALING_MODE:
+ if (settings->userTpSignaling != value) {
+ if ( !((value==0) || (value==1) || (value==2)) ) {
+ err = AACENC_INVALID_CONFIG;
+ break;
+ }
+ settings->userTpSignaling = value;
+ hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT;
+ }
+ break;
+ case AACENC_PROTECTION:
+ if (settings->userTpProtection != value) {
+ if ( !((value==0) || (value==1)) ) {
+ err = AACENC_INVALID_CONFIG;
+ break;
+ }
+ settings->userTpProtection = value;
+ hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT;
+ }
+ break;
+ case AACENC_HEADER_PERIOD:
+ if (settings->userTpHeaderPeriod != value) {
+ settings->userTpHeaderPeriod = value;
+ hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT;
+ }
+ break;
+ case AACENC_TPSUBFRAMES:
+ if (settings->userTpNsubFrames != value) {
+ if (! ( (value>=1) && (value<=4) ) ) {
+ err = AACENC_INVALID_CONFIG;
+ break;
+ }
+ settings->userTpNsubFrames = value;
+ hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT;
+ }
+ break;
+ case AACENC_ANCILLARY_BITRATE:
+ if (settings->userAncDataRate != value) {
+ settings->userAncDataRate = value;
+ }
+ break;
+ case AACENC_CONTROL_STATE:
+ if (hAacEncoder->InitFlags != value) {
+ if (value&AACENC_RESET_INBUFFER) {
+ hAacEncoder->nSamplesRead = 0;
+ }
+ hAacEncoder->InitFlags = value;
+ }
+ break;
+ case AACENC_METADATA_MODE:
+ if ((UINT)settings->userMetaDataMode != value) {
+ if ( !((value>=0) && (value<=2)) ) {
+ err = AACENC_INVALID_CONFIG;
+ break;
+ }
+ settings->userMetaDataMode = value;
+ hAacEncoder->InitFlags |= AACENC_INIT_CONFIG;
+ }
+ break;
+ default:
+ err = AACENC_UNSUPPORTED_PARAMETER;
+ break;
+ } /* switch(param) */
+
+bail:
+ return err;
+}
+
+UINT aacEncoder_GetParam(
+ const HANDLE_AACENCODER hAacEncoder,
+ const AACENC_PARAM param
+ )
+{
+ UINT value = 0;
+ USER_PARAM *settings = &hAacEncoder->extParam;
+
+ /* check encoder handle */
+ if (hAacEncoder == NULL) {
+ goto bail;
+ }
+
+ /* apply param value */
+ switch (param)
+ {
+ case AACENC_AOT:
+ value = (UINT)hAacEncoder->aacConfig.audioObjectType;
+ break;
+ case AACENC_BITRATE:
+ value = (UINT)((hAacEncoder->aacConfig.bitrateMode==AACENC_BR_MODE_CBR) ? hAacEncoder->aacConfig.bitRate : -1);
+ break;
+ case AACENC_BITRATEMODE:
+ value = (UINT)hAacEncoder->aacConfig.bitrateMode;
+ break;
+ case AACENC_SAMPLERATE:
+ value = (UINT)settings->userSamplerate;
+ break;
+ case AACENC_CHANNELMODE:
+ value = (UINT)hAacEncoder->aacConfig.channelMode;
+ break;
+ case AACENC_BANDWIDTH:
+ value = (UINT)hAacEncoder->aacConfig.bandWidth;
+ break;
+ case AACENC_CHANNELORDER:
+ value = (UINT)hAacEncoder->aacConfig.channelOrder;
+ break;
+ case AACENC_AFTERBURNER:
+ value = (UINT)hAacEncoder->aacConfig.useRequant;
+ break;
+ case AACENC_GRANULE_LENGTH:
+ value = (UINT)hAacEncoder->aacConfig.framelength;
+ break;
+ case AACENC_SBR_MODE:
+ value = (UINT) (hAacEncoder->aacConfig.syntaxFlags & AC_SBR_PRESENT) ? 1 : 0;
+ break;
+ case AACENC_TRANSMUX:
+ value = (UINT)settings->userTpType;
+ break;
+ case AACENC_SIGNALING_MODE:
+ value = (UINT)settings->userTpSignaling;
+ break;
+ case AACENC_PROTECTION:
+ value = (UINT)settings->userTpProtection;
+ break;
+ case AACENC_HEADER_PERIOD:
+ value = (UINT)hAacEncoder->coderConfig.headerPeriod;
+ break;
+ case AACENC_TPSUBFRAMES:
+ value = (UINT)settings->userTpNsubFrames;
+ break;
+ case AACENC_ANCILLARY_BITRATE:
+ value = (UINT)hAacEncoder->aacConfig.anc_Rate;
+ break;
+ case AACENC_CONTROL_STATE:
+ value = (UINT)hAacEncoder->InitFlags;
+ break;
+ case AACENC_METADATA_MODE:
+ value = (hAacEncoder->metaDataAllowed==0) ? 0 : (UINT)settings->userMetaDataMode;
+ break;
+ default:
+ //err = MPS_INVALID_PARAMETER;
+ break;
+ } /* switch(param) */
+
+bail:
+ return value;
+}
+
+AACENC_ERROR aacEncInfo(
+ const HANDLE_AACENCODER hAacEncoder,
+ AACENC_InfoStruct *pInfo
+ )
+{
+ AACENC_ERROR err = AACENC_OK;
+
+ FDKmemclear(pInfo, sizeof(AACENC_InfoStruct));
+ pInfo->confSize = 64; /* pre-initialize */
+
+ pInfo->maxOutBufBytes = ((hAacEncoder->nMaxAacChannels*6144)+7)>>3;
+ pInfo->maxAncBytes = hAacEncoder->aacConfig.maxAncBytesPerAU;
+ pInfo->inBufFillLevel = hAacEncoder->nSamplesRead/hAacEncoder->extParam.nChannels;
+ pInfo->inputChannels = hAacEncoder->extParam.nChannels;
+ pInfo->frameLength = hAacEncoder->nSamplesToRead/hAacEncoder->extParam.nChannels;
+ pInfo->encoderDelay = hAacEncoder->nDelay/hAacEncoder->extParam.nChannels;
+
+ /* Get encoder configuration */
+ if ( aacEncGetConf(hAacEncoder, &pInfo->confSize, &pInfo->confBuf[0]) != AAC_ENC_OK) {
+ err = AACENC_INIT_ERROR;
+ goto bail;
+ }
+bail:
+ return err;
+}
+
diff --git a/libAACenc/src/aacenc_pns.cpp b/libAACenc/src/aacenc_pns.cpp
new file mode 100644
index 0000000..8437132
--- /dev/null
+++ b/libAACenc/src/aacenc_pns.cpp
@@ -0,0 +1,532 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (2001)
+ 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$
+
+ Initial author: M. Lohwasser
+ contents/description: pns.c
+
+******************************************************************************/
+
+#define PNS_CONFORMANCE_TEST 0
+
+#include "aacenc_pns.h"
+#include "psy_data.h"
+#include "pnsparam.h"
+#include "noisedet.h"
+#include "bit_cnt.h"
+#include "interface.h"
+
+
+/* minCorrelationEnergy = (1.0e-10f)^2 ~ 2^-67 = 2^-47 * 2^-20 */
+static const FIXP_DBL minCorrelationEnergy = FL2FXCONST_DBL(0.0); /* FL2FXCONST_DBL((float)FDKpow(2.0,-47)); */
+/* noiseCorrelationThresh = 0.6^2 */
+static const FIXP_DBL noiseCorrelationThresh = FL2FXCONST_DBL(0.36);
+
+static void FDKaacEnc_FDKaacEnc_noiseDetection( PNS_CONFIG *pnsConf,
+ PNS_DATA *pnsData,
+ const INT sfbActive,
+ const INT *sfbOffset,
+ INT tnsOrder,
+ INT tnsPredictionGain,
+ INT tnsActive,
+ FIXP_DBL *mdctSpectrum,
+ INT *sfbMaxScaleSpec,
+ FIXP_SGL *sfbtonality );
+
+static void FDKaacEnc_CalcNoiseNrgs( const INT sfbActive,
+ INT *pnsFlag,
+ FIXP_DBL *sfbEnergyLdData,
+ INT *noiseNrg );
+
+/*****************************************************************************
+
+ functionname: initPnsConfiguration
+ description: fill pnsConf with pns parameters
+ returns: error status
+ input: PNS Config struct (modified)
+ bitrate, samplerate, usePns,
+ number of sfb's, pointer to sfb offset
+ output: error code
+
+*****************************************************************************/
+
+AAC_ENCODER_ERROR FDKaacEnc_InitPnsConfiguration(PNS_CONFIG *pnsConf,
+ INT bitRate,
+ INT sampleRate,
+ INT usePns,
+ INT sfbCnt,
+ const INT *sfbOffset,
+ const INT numChan,
+ const INT isLC)
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+
+ /* init noise detection */
+ ErrorStatus = FDKaacEnc_GetPnsParam(&pnsConf->np,
+ bitRate,
+ sampleRate,
+ sfbCnt,
+ sfbOffset,
+ &usePns,
+ numChan,
+ isLC);
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ pnsConf->minCorrelationEnergy = minCorrelationEnergy;
+ pnsConf->noiseCorrelationThresh = noiseCorrelationThresh;
+
+ pnsConf->usePns = usePns;
+
+ return AAC_ENC_OK;
+}
+
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_PnsDetect
+ description: do decision, if PNS shall used or not
+ returns:
+ input: pns config structure
+ pns data structure (modified),
+ lastWindowSequence (long or short blocks)
+ sfbActive
+ pointer to Sfb Energy, Threshold, Offset
+ pointer to mdct Spectrum
+ length of each group
+ pointer to tonality calculated in chaosmeasure
+ tns order and prediction gain
+ calculated noiseNrg at active PNS
+ output: pnsFlag in pns data structure
+
+*****************************************************************************/
+void FDKaacEnc_PnsDetect(PNS_CONFIG *pnsConf,
+ PNS_DATA *pnsData,
+ const INT lastWindowSequence,
+ const INT sfbActive,
+ const INT maxSfbPerGroup,
+ FIXP_DBL *sfbThresholdLdData,
+ const INT *sfbOffset,
+ FIXP_DBL *mdctSpectrum,
+ INT *sfbMaxScaleSpec,
+ FIXP_SGL *sfbtonality,
+ INT tnsOrder,
+ INT tnsPredictionGain,
+ INT tnsActive,
+ FIXP_DBL *sfbEnergyLdData,
+ INT *noiseNrg )
+
+{
+ int sfb;
+ int startNoiseSfb;
+
+ if (pnsConf->np.detectionAlgorithmFlags & IS_LOW_COMLEXITY) {
+ if ( (!pnsConf->usePns) || /* pns enabled? */
+ (lastWindowSequence == SHORT_WINDOW) ) /* currently only long blocks */
+ {
+ FDKmemclear(pnsData->pnsFlag, MAX_GROUPED_SFB*sizeof(INT)); /* clear all pnsFlags */
+ for (sfb=0; sfb<MAX_GROUPED_SFB; sfb++) {
+ noiseNrg[sfb] = NO_NOISE_PNS; /* clear nrg's of previous frame */
+ }
+ return;
+ }
+ }
+ else {
+ if(!pnsConf->usePns)
+ return;
+
+ /* PNS only for long Windows */
+ if (pnsConf->np.detectionAlgorithmFlags & JUST_LONG_WINDOW) {
+ if(lastWindowSequence != LONG_WINDOW) {
+ for (sfb = 0; sfb < sfbActive; sfb++) {
+ pnsData->pnsFlag[sfb] = 0; /* clear all pnsFlags */
+ }
+ return;
+ }
+ }
+ }
+ /*
+ call noise detection
+ */
+ FDKaacEnc_FDKaacEnc_noiseDetection( pnsConf,
+ pnsData,
+ sfbActive,
+ sfbOffset,
+ tnsOrder,
+ tnsPredictionGain,
+ tnsActive,
+ mdctSpectrum,
+ sfbMaxScaleSpec,
+ sfbtonality );
+
+ /* set startNoiseSfb (long) */
+ startNoiseSfb = pnsConf->np.startSfb;
+
+ /* Set noise substitution status */
+ for(sfb = 0; sfb < sfbActive; sfb++) {
+
+ /* No PNS below startNoiseSfb */
+ if(sfb < startNoiseSfb){
+ pnsData->pnsFlag[sfb] = 0;
+ continue;
+ }
+
+ /*
+ do noise substitution if
+ fuzzy measure is high enough
+ sfb freq > minimum sfb freq
+ signal in coder band is not masked
+ */
+
+ if((pnsData->noiseFuzzyMeasure[sfb] > FL2FXCONST_SGL(0.5)) &&
+ ( (sfbThresholdLdData[sfb] + FL2FXCONST_DBL(0.5849625f/64.0f)) /* thr * 1.5 = thrLd +ld(1.5)/64 */
+ < sfbEnergyLdData[sfb] ) )
+ {
+ /*
+ mark in psyout flag array that we will code
+ this band with PNS
+ */
+ pnsData->pnsFlag[sfb] = 1; /* PNS_ON */
+ }
+ else{
+ pnsData->pnsFlag[sfb] = 0; /* PNS_OFF */
+ }
+
+ /* no PNS if LTP is active */
+ }
+
+ /* avoid PNS holes */
+ if((pnsData->noiseFuzzyMeasure[0]>FL2FXCONST_SGL(0.5f)) && (pnsData->pnsFlag[1])) {
+ pnsData->pnsFlag[0] = 1;
+ }
+
+ for(sfb=1; sfb<maxSfbPerGroup-1; sfb++) {
+ if((pnsData->noiseFuzzyMeasure[sfb]>pnsConf->np.gapFillThr) &&
+ (pnsData->pnsFlag[sfb-1]) && (pnsData->pnsFlag[sfb+1])) {
+ pnsData->pnsFlag[sfb] = 1;
+ }
+ }
+
+ if(maxSfbPerGroup>0) {
+ /* avoid PNS hole */
+ if((pnsData->noiseFuzzyMeasure[maxSfbPerGroup-1]>pnsConf->np.gapFillThr) && (pnsData->pnsFlag[maxSfbPerGroup-2])) {
+ pnsData->pnsFlag[maxSfbPerGroup-1] = 1;
+ }
+ /* avoid single PNS band */
+ if(pnsData->pnsFlag[maxSfbPerGroup-2]==0) {
+ pnsData->pnsFlag[maxSfbPerGroup-1] = 0;
+ }
+ }
+
+ /* avoid single PNS bands */
+ if(pnsData->pnsFlag[1]==0) {
+ pnsData->pnsFlag[0] = 0;
+ }
+
+ for(sfb=1; sfb<maxSfbPerGroup-1; sfb++) {
+ if((pnsData->pnsFlag[sfb-1]==0)&&(pnsData->pnsFlag[sfb+1]==0)) {
+ pnsData->pnsFlag[sfb] = 0;
+ }
+ }
+
+
+ /*
+ calculate noiseNrg's
+ */
+ FDKaacEnc_CalcNoiseNrgs( sfbActive,
+ pnsData->pnsFlag,
+ sfbEnergyLdData,
+ noiseNrg );
+}
+
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_FDKaacEnc_noiseDetection
+ description: wrapper for noisedet.c
+ returns:
+ input: pns config structure
+ pns data structure (modified),
+ sfbActive
+ tns order and prediction gain
+ pointer to mdct Spectrumand Sfb Energy
+ pointer to Sfb tonality
+ output: noiseFuzzyMeasure in structure pnsData
+ flags tonal / nontonal
+
+*****************************************************************************/
+static void FDKaacEnc_FDKaacEnc_noiseDetection( PNS_CONFIG *pnsConf,
+ PNS_DATA *pnsData,
+ const INT sfbActive,
+ const INT *sfbOffset,
+ int tnsOrder,
+ INT tnsPredictionGain,
+ INT tnsActive,
+ FIXP_DBL *mdctSpectrum,
+ INT *sfbMaxScaleSpec,
+ FIXP_SGL *sfbtonality )
+{
+ INT condition = TRUE;
+ if ( !(pnsConf->np.detectionAlgorithmFlags & IS_LOW_COMLEXITY) ) {
+ condition = (tnsOrder > 3);
+ }
+ /*
+ no PNS if heavy TNS activity
+ clear pnsData->noiseFuzzyMeasure
+ */
+ if((pnsConf->np.detectionAlgorithmFlags & USE_TNS_GAIN_THR) &&
+ (tnsPredictionGain >= pnsConf->np.tnsGainThreshold) && condition &&
+ !((pnsConf->np.detectionAlgorithmFlags & USE_TNS_PNS) && (tnsPredictionGain >= pnsConf->np.tnsPNSGainThreshold) && (tnsActive)) )
+ {
+ /* clear all noiseFuzzyMeasure */
+ FDKmemclear(pnsData->noiseFuzzyMeasure, sfbActive*sizeof(FIXP_SGL));
+ }
+ else
+ {
+ /*
+ call noise detection, output in pnsData->noiseFuzzyMeasure,
+ use real mdct spectral data
+ */
+ FDKaacEnc_noiseDetect( mdctSpectrum,
+ sfbMaxScaleSpec,
+ sfbActive,
+ sfbOffset,
+ pnsData->noiseFuzzyMeasure,
+ &pnsConf->np,
+ sfbtonality);
+ }
+}
+
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_CalcNoiseNrgs
+ description: Calculate the NoiseNrg's
+ returns:
+ input: sfbActive
+ if pnsFlag calculate NoiseNrg
+ pointer to sfbEnergy and groupLen
+ pointer to noiseNrg (modified)
+ output: noiseNrg's in pnsFlaged sfb's
+
+*****************************************************************************/
+
+static void FDKaacEnc_CalcNoiseNrgs( const INT sfbActive,
+ INT *RESTRICT pnsFlag,
+ FIXP_DBL *RESTRICT sfbEnergyLdData,
+ INT *RESTRICT noiseNrg )
+{
+ int sfb;
+ INT tmp = (-LOG_NORM_PCM)<<2;
+
+ for(sfb = 0; sfb < sfbActive; sfb++) {
+ if(pnsFlag[sfb]) {
+ INT nrg = (-sfbEnergyLdData[sfb]+FL2FXCONST_DBL(0.5f/64.0f))>>(DFRACT_BITS-1-7);
+ noiseNrg[sfb] = tmp - nrg;
+ }
+ }
+}
+
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_CodePnsChannel
+ description: Execute pns decission
+ returns:
+ input: sfbActive
+ pns config structure
+ use PNS if pnsFlag
+ pointer to Sfb Energy, noiseNrg, Threshold
+ output: set sfbThreshold high to code pe with 0,
+ noiseNrg marks flag for pns coding
+
+*****************************************************************************/
+
+void FDKaacEnc_CodePnsChannel(const INT sfbActive,
+ PNS_CONFIG *pnsConf,
+ INT *RESTRICT pnsFlag,
+ FIXP_DBL *RESTRICT sfbEnergyLdData,
+ INT *RESTRICT noiseNrg,
+ FIXP_DBL *RESTRICT sfbThresholdLdData)
+{
+ INT sfb;
+ INT lastiNoiseEnergy = 0;
+ INT firstPNSband = 1; /* TRUE for first PNS-coded band */
+
+ /* no PNS */
+ if(!pnsConf->usePns) {
+ for(sfb = 0; sfb < sfbActive; sfb++) {
+ /* no PNS coding */
+ noiseNrg[sfb] = NO_NOISE_PNS;
+ }
+ return;
+ }
+
+ /* code PNS */
+ for(sfb = 0; sfb < sfbActive; sfb++) {
+ if(pnsFlag[sfb]) {
+ /* high sfbThreshold causes pe = 0 */
+ if(noiseNrg[sfb] != NO_NOISE_PNS)
+ sfbThresholdLdData[sfb] = sfbEnergyLdData[sfb] + FL2FXCONST_DBL(1.0f/LD_DATA_SCALING);
+
+ /* set noiseNrg in valid region */
+ if(!firstPNSband) {
+ INT deltaiNoiseEnergy = noiseNrg[sfb] - lastiNoiseEnergy;
+
+ if(deltaiNoiseEnergy > CODE_BOOK_PNS_LAV)
+ noiseNrg[sfb] -= deltaiNoiseEnergy - CODE_BOOK_PNS_LAV;
+ else if(deltaiNoiseEnergy < -CODE_BOOK_PNS_LAV)
+ noiseNrg[sfb] -= deltaiNoiseEnergy + CODE_BOOK_PNS_LAV;
+ }
+ else {
+ firstPNSband = 0;
+ }
+ lastiNoiseEnergy = noiseNrg[sfb];
+ }
+ else {
+ /* no PNS coding */
+ noiseNrg[sfb] = NO_NOISE_PNS;
+ }
+ }
+}
+
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_PreProcessPnsChannelPair
+ description: Calculate the correlation of noise in a channel pair
+
+ returns:
+ input: sfbActive
+ pointer to sfb energies left, right and mid channel
+ pns config structure
+ pns data structure left and right (modified)
+
+ output: noiseEnergyCorrelation in pns data structure
+
+*****************************************************************************/
+
+void FDKaacEnc_PreProcessPnsChannelPair(const INT sfbActive,
+ FIXP_DBL *RESTRICT sfbEnergyLeft,
+ FIXP_DBL *RESTRICT sfbEnergyRight,
+ FIXP_DBL *RESTRICT sfbEnergyLeftLD,
+ FIXP_DBL *RESTRICT sfbEnergyRightLD,
+ FIXP_DBL *RESTRICT sfbEnergyMid,
+ PNS_CONFIG *RESTRICT pnsConf,
+ PNS_DATA *pnsDataLeft,
+ PNS_DATA *pnsDataRight)
+{
+ INT sfb;
+ FIXP_DBL ccf;
+
+ if(!pnsConf->usePns)
+ return;
+
+ FIXP_DBL *RESTRICT pNoiseEnergyCorrelationL = pnsDataLeft->noiseEnergyCorrelation;
+ FIXP_DBL *RESTRICT pNoiseEnergyCorrelationR = pnsDataRight->noiseEnergyCorrelation;
+
+ for(sfb=0;sfb< sfbActive;sfb++) {
+ FIXP_DBL quot = (sfbEnergyLeftLD[sfb]>>1) + (sfbEnergyRightLD[sfb]>>1);
+
+ if(quot < FL2FXCONST_DBL(-32.0f/(float)LD_DATA_SCALING))
+ ccf = FL2FXCONST_DBL(0.0f);
+ else {
+ FIXP_DBL accu = sfbEnergyMid[sfb]- (((sfbEnergyLeft[sfb]>>1)+(sfbEnergyRight[sfb]>>1))>>1);
+ INT sign = (accu < FL2FXCONST_DBL(0.0f)) ? 1 : 0 ;
+ accu = fixp_abs(accu);
+
+ ccf = CalcLdData(accu) + FL2FXCONST_DBL((float)1.0f/(float)LD_DATA_SCALING) - quot; /* ld(accu*2) = ld(accu) + 1 */
+ ccf = (ccf>=FL2FXCONST_DBL(0.0)) ? ((FIXP_DBL)MAXVAL_DBL) : (sign) ? -CalcInvLdData(ccf) : CalcInvLdData(ccf);
+ }
+
+ pNoiseEnergyCorrelationL[sfb] = ccf;
+ pNoiseEnergyCorrelationR[sfb] = ccf;
+ }
+}
+
+
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_PostProcessPnsChannelPair
+ description: if PNS used at left and right channel,
+ use msMask to flag correlation
+ returns:
+ input: sfbActive
+ pns config structure
+ pns data structure left and right (modified)
+ pointer to msMask, flags correlation by pns coding (modified)
+ Digest of MS coding
+ output: pnsFlag in pns data structure,
+ msFlag in msMask (flags correlation)
+
+*****************************************************************************/
+
+void FDKaacEnc_PostProcessPnsChannelPair(const INT sfbActive,
+ PNS_CONFIG *pnsConf,
+ PNS_DATA *pnsDataLeft,
+ PNS_DATA *pnsDataRight,
+ INT *RESTRICT msMask,
+ INT *msDigest )
+{
+ INT sfb;
+
+ if(!pnsConf->usePns)
+ return;
+
+ for(sfb=0;sfb<sfbActive;sfb++) {
+ /*
+ MS post processing
+ */
+ if( msMask[sfb] ) {
+ if( (pnsDataLeft->pnsFlag[sfb]) &&
+ (pnsDataRight->pnsFlag[sfb]) ) {
+ /* AAC only: Standard */
+ /* do this to avoid ms flags in layers that should not have it */
+ if(pnsDataLeft->noiseEnergyCorrelation[sfb] <= pnsConf->noiseCorrelationThresh){
+ msMask[sfb] = 0;
+ *msDigest = MS_SOME;
+ }
+ }
+ else {
+ /*
+ No PNS coding
+ */
+ pnsDataLeft->pnsFlag[sfb] = 0;
+ pnsDataRight->pnsFlag[sfb] = 0;
+ }
+ }
+
+ /*
+ Use MS flag to signal noise correlation if
+ pns is active in both channels
+ */
+ if( (pnsDataLeft->pnsFlag[sfb]) && (pnsDataRight->pnsFlag[sfb]) ) {
+ if(pnsDataLeft->noiseEnergyCorrelation[sfb] > pnsConf->noiseCorrelationThresh) {
+ msMask[sfb] = 1;
+ *msDigest = MS_SOME;
+ }
+ }
+ }
+}
diff --git a/libAACenc/src/aacenc_pns.h b/libAACenc/src/aacenc_pns.h
new file mode 100644
index 0000000..f0b29d0
--- /dev/null
+++ b/libAACenc/src/aacenc_pns.h
@@ -0,0 +1,52 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (2001)
+ 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$
+
+ Initial author: M. Lohwasser
+ contents/description: pns.h
+
+******************************************************************************/
+
+#ifndef __PNS_H
+#define __PNS_H
+
+#include "common_fix.h"
+
+#include "pnsparam.h"
+
+#define NO_NOISE_PNS FDK_INT_MIN
+
+typedef struct{
+ NOISEPARAMS np;
+ FIXP_DBL minCorrelationEnergy;
+ FIXP_DBL noiseCorrelationThresh;
+ INT usePns;
+} PNS_CONFIG;
+
+typedef struct{
+ FIXP_SGL noiseFuzzyMeasure[MAX_GROUPED_SFB];
+ FIXP_DBL noiseEnergyCorrelation[MAX_GROUPED_SFB];
+ INT pnsFlag[MAX_GROUPED_SFB];
+} PNS_DATA;
+
+#endif
diff --git a/libAACenc/src/aacenc_tns.cpp b/libAACenc/src/aacenc_tns.cpp
new file mode 100644
index 0000000..f795e24
--- /dev/null
+++ b/libAACenc/src/aacenc_tns.cpp
@@ -0,0 +1,1286 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: Alex Groeschel
+ contents/description: Temporal noise shaping
+
+******************************************************************************/
+
+#include "aacenc_tns.h"
+#include "psy_const.h"
+#include "psy_configuration.h"
+#include "tns_func.h"
+#include "aacEnc_rom.h"
+#include "aacenc_tns.h"
+
+enum {
+ HIFILT = 0, /* index of higher filter */
+ LOFILT = 1 /* index of lower filter */
+};
+
+
+#define FILTER_DIRECTION 0
+
+static const FIXP_DBL acfWindowLong[12+3+1] = {
+ 0x7fffffff,0x7fb80000,0x7ee00000,0x7d780000,0x7b800000,0x78f80000,0x75e00000,0x72380000,
+ 0x6e000000,0x69380000,0x63e00000,0x5df80000,0x57800000,0x50780000,0x48e00000,0x40b80000
+};
+
+static const FIXP_DBL acfWindowShort[4+3+1] = {
+ 0x7fffffff,0x7e000000,0x78000000,0x6e000000,0x60000000,0x4e000000,0x38000000,0x1e000000
+};
+
+
+typedef struct {
+ INT filterEnabled[MAX_NUM_OF_FILTERS];
+ INT threshOn[MAX_NUM_OF_FILTERS]; /* min. prediction gain for using tns TABUL*/
+ INT filterStartFreq[MAX_NUM_OF_FILTERS]; /* lowest freq for lpc TABUL*/
+ INT tnsLimitOrder[MAX_NUM_OF_FILTERS]; /* Limit for TNS order TABUL*/
+ INT tnsFilterDirection[MAX_NUM_OF_FILTERS]; /* Filtering direction, 0=up, 1=down TABUL */
+ INT acfSplit[MAX_NUM_OF_FILTERS];
+ FIXP_DBL tnsTimeResolution[MAX_NUM_OF_FILTERS]; /* TNS max. time resolution TABUL. Should be fract but MSVC won't compile then */
+ INT seperateFiltersAllowed;
+
+} TNS_PARAMETER_TABULATED;
+
+
+typedef struct{
+ INT bitRateFrom[2]; /* noneSbr=0, useSbr=1 */
+ INT bitRateTo[2]; /* noneSbr=0, useSbr=1 */
+ TNS_PARAMETER_TABULATED paramTab[2]; /* mono=0, stereo=1 */
+
+} TNS_INFO_TAB;
+
+#define TNS_TIMERES_SCALE (1)
+#define FL2_TIMERES_FIX(a) ( FL2FXCONST_DBL(a/(float)(1<<TNS_TIMERES_SCALE)) )
+
+static const TNS_INFO_TAB tnsInfoTab[] =
+{
+ {
+ { 16000, 13500},
+ { 32000, 28000},
+ {
+ { {1, 1}, {1437, 1500}, {1400, 600}, {12, 12}, {FILTER_DIRECTION, FILTER_DIRECTION}, {3, 1}, {FL2_TIMERES_FIX(0.4f), FL2_TIMERES_FIX(1.2f)}, 1 },
+ { {1, 1}, {1437, 1500}, {1400, 600}, {12, 12}, {FILTER_DIRECTION, FILTER_DIRECTION}, {3, 1}, {FL2_TIMERES_FIX(0.4f), FL2_TIMERES_FIX(1.2f)}, 1 }
+ }
+ },
+ {
+ { 32001, 28001},
+ { 60000, 52000},
+ {
+ { {1, 1}, {1437, 1500}, {1400, 600}, {12, 10}, {FILTER_DIRECTION, FILTER_DIRECTION}, {3, 1}, {FL2_TIMERES_FIX(0.4f), FL2_TIMERES_FIX(1.0f)}, 1 },
+ { {1, 1}, {1437, 1500}, {1400, 600}, {12, 10}, {FILTER_DIRECTION, FILTER_DIRECTION}, {3, 1}, {FL2_TIMERES_FIX(0.4f), FL2_TIMERES_FIX(1.0f)}, 1 }
+ }
+ },
+ {
+ { 60001, 52001},
+ { 384000, 384000},
+ {
+ { {1, 1}, {1437, 1500}, {1400, 600}, {12, 8}, {FILTER_DIRECTION, FILTER_DIRECTION}, {3, 1}, {FL2_TIMERES_FIX(0.4f), FL2_TIMERES_FIX(1.0f)}, 1 },
+ { {1, 1}, {1437, 1500}, {1400, 600}, {12, 8}, {FILTER_DIRECTION, FILTER_DIRECTION}, {3, 1}, {FL2_TIMERES_FIX(0.4f), FL2_TIMERES_FIX(1.0f)}, 1 }
+ }
+ }
+};
+
+typedef struct {
+ INT samplingRate;
+ SCHAR maxBands[2]; /* long=0; short=1 */
+
+} TNS_MAX_TAB_ENTRY;
+
+static const TNS_MAX_TAB_ENTRY tnsMaxBandsTab1024[] =
+{
+ { 96000, { 31, 9}},
+ { 88200, { 31, 9}},
+ { 64000, { 34, 10}},
+ { 48000, { 40, 14}},
+ { 44100, { 42, 14}},
+ { 32000, { 51, 14}},
+ { 24000, { 46, 14}},
+ { 22050, { 46, 14}},
+ { 16000, { 42, 14}},
+ { 12000, { 42, 14}},
+ { 11025, { 42, 14}},
+ { 8000, { 39, 14}}
+};
+
+static const TNS_MAX_TAB_ENTRY tnsMaxBandsTab480[] =
+{
+ { 48000, { 31, -1}},
+ { 44100, { 32, -1}},
+ { 32000, { 37, -1}},
+ { 24000, { 30, -1}},
+ { 22050, { 30, -1}}
+};
+
+static const TNS_MAX_TAB_ENTRY tnsMaxBandsTab512[] =
+{
+ { 48000, { 31, -1}},
+ { 44100, { 32, -1}},
+ { 32000, { 37, -1}},
+ { 24000, { 31, -1}},
+ { 22050, { 31, -1}}
+};
+
+static INT FDKaacEnc_AutoToParcor(
+ FIXP_DBL *RESTRICT input,
+ FIXP_DBL *RESTRICT reflCoeff,
+ const INT numOfCoeff
+ );
+
+static void FDKaacEnc_Parcor2Index(
+ const FIXP_DBL *parcor,
+ INT *RESTRICT index,
+ const INT order,
+ const INT bitsPerCoeff
+ );
+
+static void FDKaacEnc_Index2Parcor(
+ const INT *index,
+ FIXP_DBL *RESTRICT parcor,
+ const INT order,
+ const INT bitsPerCoeff
+ );
+
+static INT FDKaacEnc_ParcorToLpc(
+ const FIXP_DBL *reflCoeff,
+ FIXP_DBL *RESTRICT LpcCoeff,
+ const INT numOfCoeff,
+ FIXP_DBL *RESTRICT workBuffer
+ );
+
+static void FDKaacEnc_AnalysisFilter(
+ FIXP_DBL *RESTRICT signal,
+ const INT numOfLines,
+ const FIXP_DBL *predictorCoeff,
+ const INT order,
+ const INT lpcGainFactor
+ );
+
+static void FDKaacEnc_CalcGaussWindow(
+ FIXP_DBL *win,
+ const int winSize,
+ const INT samplingRate,
+ const INT transformResolution,
+ const FIXP_DBL timeResolution,
+ const INT timeResolution_e
+ );
+
+static const TNS_PARAMETER_TABULATED* FDKaacEnc_GetTnsParam(
+ const INT bitRate,
+ const INT channels,
+ const INT sbrLd
+ )
+{
+ int i;
+ const TNS_PARAMETER_TABULATED *tnsConfigTab = NULL;
+
+ for (i = 0; i < (int) (sizeof(tnsInfoTab)/sizeof(TNS_INFO_TAB)); i++) {
+ if ((bitRate >= tnsInfoTab[i].bitRateFrom[sbrLd?1:0]) &&
+ bitRate <= tnsInfoTab[i].bitRateTo[sbrLd?1:0])
+ {
+ tnsConfigTab = &tnsInfoTab[i].paramTab[(channels==1)?0:1];
+ }
+ }
+
+ return tnsConfigTab;
+}
+
+
+static INT getTnsMaxBands(
+ const INT sampleRate,
+ const INT granuleLength,
+ const INT isShortBlock
+ )
+{
+ int i;
+ INT numBands = -1;
+ const TNS_MAX_TAB_ENTRY *pMaxBandsTab = NULL;
+ int maxBandsTabSize = 0;
+
+ switch (granuleLength) {
+ case 960:
+ case 1024:
+ pMaxBandsTab = tnsMaxBandsTab1024;
+ maxBandsTabSize = sizeof(tnsMaxBandsTab1024)/sizeof(TNS_MAX_TAB_ENTRY);
+ break;
+ case 480:
+ pMaxBandsTab = tnsMaxBandsTab480;
+ maxBandsTabSize = sizeof(tnsMaxBandsTab480)/sizeof(TNS_MAX_TAB_ENTRY);
+ break;
+ case 512:
+ pMaxBandsTab = tnsMaxBandsTab512;
+ maxBandsTabSize = sizeof(tnsMaxBandsTab512)/sizeof(TNS_MAX_TAB_ENTRY);
+ break;
+ default:
+ numBands = -1;
+ }
+
+ if (pMaxBandsTab!=NULL) {
+ for (i=0; i<maxBandsTabSize; i++) {
+ numBands = pMaxBandsTab[i].maxBands[(!isShortBlock)?0:1];
+ if (sampleRate >= pMaxBandsTab[i].samplingRate) {
+ break;
+ }
+ }
+ }
+
+ return numBands;
+}
+
+/***************************************************************************/
+/*!
+ \brief FDKaacEnc_FreqToBandWithRounding
+
+ Returns index of nearest band border
+
+ \param frequency
+ \param sampling frequency
+ \param total number of bands
+ \param pointer to table of band borders
+
+ \return band border
+****************************************************************************/
+
+INT FDKaacEnc_FreqToBandWithRounding(
+ const INT freq,
+ const INT fs,
+ const INT numOfBands,
+ const INT *bandStartOffset
+ )
+{
+ INT lineNumber, band;
+
+ /* assert(freq >= 0); */
+ lineNumber = (freq*bandStartOffset[numOfBands]*4/fs+1)/2;
+
+ /* freq > fs/2 */
+ if (lineNumber >= bandStartOffset[numOfBands])
+ return numOfBands;
+
+ /* find band the line number lies in */
+ for (band=0; band<numOfBands; band++) {
+ if (bandStartOffset[band+1]>lineNumber) break;
+ }
+
+ /* round to nearest band border */
+ if (lineNumber - bandStartOffset[band] >
+ bandStartOffset[band+1] - lineNumber )
+ {
+ band++;
+ }
+
+ return(band);
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_InitTnsConfiguration
+ description: fill TNS_CONFIG structure with sensible content
+ returns:
+ input: bitrate, samplerate, number of channels,
+ blocktype (long or short),
+ TNS Config struct (modified),
+ psy config struct,
+ tns active flag
+ output:
+
+*****************************************************************************/
+AAC_ENCODER_ERROR FDKaacEnc_InitTnsConfiguration(INT bitRate,
+ INT sampleRate,
+ INT channels,
+ INT blockType,
+ INT granuleLength,
+ INT ldSbrPresent,
+ TNS_CONFIG *tC,
+ PSY_CONFIGURATION *pC,
+ INT active,
+ INT useTnsPeak)
+{
+ int i;
+ //float acfTimeRes = (blockType == SHORT_WINDOW) ? 0.125f : 0.046875f;
+
+ if (channels <= 0)
+ return (AAC_ENCODER_ERROR)1;
+
+ /* initialize TNS filter flag, order, and coefficient resolution (in bits per coeff) */
+ tC->tnsActive = (active) ? TRUE : FALSE;
+ tC->maxOrder = (blockType == SHORT_WINDOW) ? 5 : 12; /* maximum: 7, 20 */
+ if (bitRate < 16000)
+ tC->maxOrder -= 2;
+ tC->coefRes = (blockType == SHORT_WINDOW) ? 3 : 4;
+
+ /* LPC stop line: highest MDCT line to be coded, but do not go beyond TNS_MAX_BANDS! */
+ tC->lpcStopBand = getTnsMaxBands(sampleRate, granuleLength, (blockType == SHORT_WINDOW) ? 1 : 0);
+
+ if (tC->lpcStopBand < 0) {
+ return (AAC_ENCODER_ERROR)1;
+ }
+
+ tC->lpcStopBand = FDKmin(tC->lpcStopBand, pC->sfbActive);
+ tC->lpcStopLine = pC->sfbOffset[tC->lpcStopBand];
+
+ switch (granuleLength) {
+ case 960:
+ case 1024:
+ /* TNS start line: skip lower MDCT lines to prevent artifacts due to filter mismatch */
+ tC->lpcStartBand[LOFILT] = (blockType == SHORT_WINDOW) ? 0 : ((sampleRate < 18783) ? 4 : 8);
+ tC->lpcStartLine[LOFILT] = pC->sfbOffset[tC->lpcStartBand[LOFILT]];
+
+ i = tC->lpcStopBand;
+ while (pC->sfbOffset[i] > (tC->lpcStartLine[LOFILT] + (tC->lpcStopLine - tC->lpcStartLine[LOFILT]) / 4)) i--;
+ tC->lpcStartBand[HIFILT] = i;
+ tC->lpcStartLine[HIFILT] = pC->sfbOffset[i];
+
+ tC->confTab.threshOn[HIFILT] = 1437;
+ tC->confTab.threshOn[LOFILT] = 1500;
+
+ tC->confTab.tnsLimitOrder[HIFILT] = tC->maxOrder;
+ tC->confTab.tnsLimitOrder[LOFILT] = tC->maxOrder - 7;
+
+ tC->confTab.tnsFilterDirection[HIFILT] = FILTER_DIRECTION;
+ tC->confTab.tnsFilterDirection[LOFILT] = FILTER_DIRECTION;
+
+ tC->confTab.acfSplit[HIFILT] = -1; /* signal Merged4to2QuartersAutoCorrelation in FDKaacEnc_MergedAutoCorrelation*/
+ tC->confTab.acfSplit[LOFILT] = -1; /* signal Merged4to2QuartersAutoCorrelation in FDKaacEnc_MergedAutoCorrelation */
+
+ tC->confTab.filterEnabled[HIFILT] = 1;
+ tC->confTab.filterEnabled[LOFILT] = 1;
+ tC->confTab.seperateFiltersAllowed = 1;
+
+ /* compute autocorrelation window based on maximum filter order for given block type */
+ /* for (i = 0; i <= tC->maxOrder + 3; i++) {
+ float acfWinTemp = acfTimeRes * i;
+ acfWindow[i] = FL2FXCONST_DBL(1.0f - acfWinTemp * acfWinTemp);
+ }
+ */
+ if (blockType == SHORT_WINDOW) {
+ FDKmemcpy(tC->acfWindow[HIFILT], acfWindowShort, FDKmin(sizeof(acfWindowShort), sizeof(tC->acfWindow[HIFILT])));
+ FDKmemcpy(tC->acfWindow[LOFILT], acfWindowShort, FDKmin(sizeof(acfWindowShort), sizeof(tC->acfWindow[HIFILT])));
+ }
+ else {
+ FDKmemcpy(tC->acfWindow[HIFILT], acfWindowLong, FDKmin(sizeof(acfWindowLong), sizeof(tC->acfWindow[HIFILT])));
+ FDKmemcpy(tC->acfWindow[LOFILT], acfWindowLong, FDKmin(sizeof(acfWindowLong), sizeof(tC->acfWindow[HIFILT])));
+ }
+ break;
+ case 480:
+ case 512:
+ {
+ const TNS_PARAMETER_TABULATED* pCfg = FDKaacEnc_GetTnsParam(bitRate, channels, ldSbrPresent);
+
+ if ( pCfg != NULL ) {
+ tC->lpcStartBand[HIFILT] = FDKaacEnc_FreqToBandWithRounding(pCfg->filterStartFreq[HIFILT], sampleRate, pC->sfbCnt, pC->sfbOffset);
+ tC->lpcStartLine[HIFILT] = pC->sfbOffset[tC->lpcStartBand[HIFILT]];
+ tC->lpcStartBand[LOFILT] = FDKaacEnc_FreqToBandWithRounding(pCfg->filterStartFreq[LOFILT], sampleRate, pC->sfbCnt, pC->sfbOffset);
+ tC->lpcStartLine[LOFILT] = pC->sfbOffset[tC->lpcStartBand[LOFILT]];
+
+ tC->confTab.threshOn[HIFILT] = pCfg->threshOn[HIFILT];
+ tC->confTab.threshOn[LOFILT] = pCfg->threshOn[LOFILT];
+
+ tC->confTab.tnsLimitOrder[HIFILT] = pCfg->tnsLimitOrder[HIFILT];
+ tC->confTab.tnsLimitOrder[LOFILT] = pCfg->tnsLimitOrder[LOFILT];
+
+ tC->confTab.tnsFilterDirection[HIFILT] = pCfg->tnsFilterDirection[HIFILT];
+ tC->confTab.tnsFilterDirection[LOFILT] = pCfg->tnsFilterDirection[LOFILT];
+
+ tC->confTab.acfSplit[HIFILT] = pCfg->acfSplit[HIFILT];
+ tC->confTab.acfSplit[LOFILT] = pCfg->acfSplit[LOFILT];
+
+ tC->confTab.filterEnabled[HIFILT] = pCfg->filterEnabled[HIFILT];
+ tC->confTab.filterEnabled[LOFILT] = pCfg->filterEnabled[LOFILT];
+ tC->confTab.seperateFiltersAllowed = pCfg->seperateFiltersAllowed;
+
+ FDKaacEnc_CalcGaussWindow(tC->acfWindow[HIFILT], tC->maxOrder+1, sampleRate, granuleLength, pCfg->tnsTimeResolution[HIFILT], TNS_TIMERES_SCALE);
+ FDKaacEnc_CalcGaussWindow(tC->acfWindow[LOFILT], tC->maxOrder+1, sampleRate, granuleLength, pCfg->tnsTimeResolution[LOFILT], TNS_TIMERES_SCALE);
+ }
+ else {
+ tC->tnsActive = FALSE; /* no configuration available, disable tns tool */
+ }
+ }
+ break;
+ default:
+ tC->tnsActive = FALSE; /* no configuration available, disable tns tool */
+ }
+
+ return AAC_ENC_OK;
+
+}
+
+/***************************************************************************/
+/*!
+ \brief FDKaacEnc_ScaleUpSpectrum
+
+ Scales up spectrum lines in a given frequency section
+
+ \param scaled spectrum
+ \param original spectrum
+ \param frequency line to start scaling
+ \param frequency line to enc scaling
+
+ \return scale factor
+
+****************************************************************************/
+static inline INT FDKaacEnc_ScaleUpSpectrum(
+ FIXP_DBL *dest,
+ const FIXP_DBL *src,
+ const INT startLine,
+ const INT stopLine
+ )
+{
+ INT i, scale;
+
+ FIXP_DBL maxVal = FL2FXCONST_DBL(0.f);
+
+ /* Get highest value in given spectrum */
+ for (i=startLine; i<stopLine; i++) {
+ maxVal = fixMax(maxVal,fixp_abs(src[i]));
+ }
+ scale = CountLeadingBits(maxVal);
+
+ /* Scale spectrum according to highest value */
+ for (i=startLine; i<stopLine; i++) {
+ dest[i] = src[i]<<scale;
+ }
+
+ return scale;
+}
+
+/***************************************************************************/
+/*!
+ \brief FDKaacEnc_CalcAutoCorrValue
+
+ Calculate autocorellation value for one lag
+
+ \param pointer to spectrum
+ \param start line
+ \param stop line
+ \param lag to be calculated
+ \param scaling of the lag
+
+****************************************************************************/
+static inline FIXP_DBL FDKaacEnc_CalcAutoCorrValue(
+ const FIXP_DBL *spectrum,
+ const INT startLine,
+ const INT stopLine,
+ const INT lag,
+ const INT scale
+ )
+{
+ int i;
+ FIXP_DBL result = FL2FXCONST_DBL(0.f);
+
+ if (lag==0) {
+ for (i=startLine; i<stopLine; i++) {
+ result += (fPow2(spectrum[i])>>scale);
+ }
+ }
+ else {
+ for (i=startLine; i<(stopLine-lag); i++) {
+ result += (fMult(spectrum[i], spectrum[i+lag])>>scale);
+ }
+ }
+
+ return result;
+}
+
+/***************************************************************************/
+/*!
+ \brief FDKaacEnc_AutoCorrNormFac
+
+ Autocorrelation function for 1st and 2nd half of the spectrum
+
+ \param pointer to spectrum
+ \param pointer to autocorrelation window
+ \param filter start line
+
+****************************************************************************/
+static inline FIXP_DBL FDKaacEnc_AutoCorrNormFac(
+ const FIXP_DBL value,
+ const INT scale,
+ INT *sc
+ )
+{
+ #define HLM_MIN_NRG 0.0000000037252902984619140625f /* 2^-28 */
+ #define MAX_INV_NRGFAC (1.f/HLM_MIN_NRG)
+
+ FIXP_DBL retValue;
+ FIXP_DBL A, B;
+
+ if (scale>=0) {
+ A = value;
+ B = FL2FXCONST_DBL(HLM_MIN_NRG)>>fixMin(DFRACT_BITS-1,scale);
+ }
+ else {
+ A = value>>fixMin(DFRACT_BITS-1,(-scale));
+ B = FL2FXCONST_DBL(HLM_MIN_NRG);
+ }
+
+ if (A > B) {
+ int shift = 0;
+ FIXP_DBL tmp = invSqrtNorm2(value,&shift);
+
+ retValue = fMult(tmp,tmp);
+ *sc += (2*shift);
+ }
+ else {
+ /* MAX_INV_NRGFAC*FDKpow(2,-28) = 1/2^-28 * 2^-28 = 1.0 */
+ retValue = /*FL2FXCONST_DBL(MAX_INV_NRGFAC*FDKpow(2,-28))*/ (FIXP_DBL)MAXVAL_DBL;
+ *sc += scale+28;
+ }
+
+ return retValue;
+}
+
+static void FDKaacEnc_MergedAutoCorrelation(
+ const FIXP_DBL *spectrum,
+ const FIXP_DBL acfWindow[MAX_NUM_OF_FILTERS][TNS_MAX_ORDER+3+1],
+ const INT lpcStartLine[MAX_NUM_OF_FILTERS],
+ const INT lpcStopLine,
+ const INT maxOrder,
+ const INT acfSplit[MAX_NUM_OF_FILTERS],
+ FIXP_DBL *_rxx1,
+ FIXP_DBL *_rxx2
+ )
+{
+ int i, idx0, idx1, idx2, idx3, idx4, lag;
+ FIXP_DBL rxx1_0, rxx2_0, rxx3_0, rxx4_0;
+
+ /* buffer for temporal spectrum */
+ C_ALLOC_SCRATCH_START(pSpectrum, FIXP_DBL, (1024));
+
+ /* pre-initialization output */
+ FDKmemclear(&_rxx1[0], sizeof(FIXP_DBL)*(maxOrder+1));
+ FDKmemclear(&_rxx2[0], sizeof(FIXP_DBL)*(maxOrder+1));
+
+ /* MDCT line indices separating the 1st, 2nd, 3rd, and 4th analysis quarters */
+ if ( (acfSplit[LOFILT]==-1) || (acfSplit[HIFILT]==-1) ) {
+ /* autocorrelation function for 1st, 2nd, 3rd, and 4th quarter of the spectrum */
+ idx0 = lpcStartLine[LOFILT];
+ i = lpcStopLine - lpcStartLine[LOFILT];
+ idx1 = idx0 + i / 4;
+ idx2 = idx0 + i / 2;
+ idx3 = idx0 + i * 3 / 4;
+ idx4 = lpcStopLine;
+ }
+ else {
+ FDK_ASSERT(acfSplit[LOFILT]==1);
+ FDK_ASSERT(acfSplit[HIFILT]==3);
+ i = (lpcStopLine - lpcStartLine[HIFILT]) / 3;
+ idx0 = lpcStartLine[LOFILT];
+ idx1 = lpcStartLine[HIFILT];
+ idx2 = idx1 + i;
+ idx3 = idx2 + i;
+ idx4 = lpcStopLine;
+ }
+
+ /* copy spectrum to temporal buffer and scale up as much as possible */
+ INT sc1 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx0, idx1);
+ INT sc2 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx1, idx2);
+ INT sc3 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx2, idx3);
+ INT sc4 = FDKaacEnc_ScaleUpSpectrum(pSpectrum, spectrum, idx3, idx4);
+
+ /* get scaling values for summation */
+ INT nsc1, nsc2, nsc3, nsc4;
+ for (nsc1=1; (1<<nsc1)<(idx1-idx0); nsc1++);
+ for (nsc2=1; (1<<nsc2)<(idx2-idx1); nsc2++);
+ for (nsc3=1; (1<<nsc3)<(idx3-idx2); nsc3++);
+ for (nsc4=1; (1<<nsc4)<(idx4-idx3); nsc4++);
+
+ /* compute autocorrelation value at lag zero, i. e. energy, for each quarter */
+ rxx1_0 = FDKaacEnc_CalcAutoCorrValue(pSpectrum, idx0, idx1, 0, nsc1);
+ rxx2_0 = FDKaacEnc_CalcAutoCorrValue(pSpectrum, idx1, idx2, 0, nsc2);
+ rxx3_0 = FDKaacEnc_CalcAutoCorrValue(pSpectrum, idx2, idx3, 0, nsc3);
+ rxx4_0 = FDKaacEnc_CalcAutoCorrValue(pSpectrum, idx3, idx4, 0, nsc4);
+
+ /* compute energy normalization factors, i. e. 1/energy (saves some divisions) */
+ if (rxx1_0 != FL2FXCONST_DBL(0.f))
+ {
+ INT sc_fac1 = -1;
+ FIXP_DBL fac1 = FDKaacEnc_AutoCorrNormFac(rxx1_0, ((-2*sc1)+nsc1), &sc_fac1);
+ _rxx1[0] = scaleValue(fMult(rxx1_0,fac1),sc_fac1);
+
+ for (lag = 1; lag <= maxOrder; lag++) {
+ /* compute energy-normalized and windowed autocorrelation values at this lag */
+ if ((3 * lag) <= maxOrder + 3) {
+ FIXP_DBL x1 = FDKaacEnc_CalcAutoCorrValue(pSpectrum, idx0, idx1, lag, nsc1);
+ _rxx1[lag] = fMult(scaleValue(fMult(x1,fac1),sc_fac1), acfWindow[LOFILT][3*lag]);
+ }
+ }
+ }
+
+ /* auto corr over upper 3/4 of spectrum */
+ if ( !((rxx2_0 == FL2FXCONST_DBL(0.f)) && (rxx3_0 == FL2FXCONST_DBL(0.f)) && (rxx4_0 == FL2FXCONST_DBL(0.f))) )
+ {
+ FIXP_DBL fac2, fac3, fac4;
+ fac2 = fac3 = fac4 = FL2FXCONST_DBL(0.f);
+ INT sc_fac2, sc_fac3, sc_fac4;
+ sc_fac2 = sc_fac3 = sc_fac4 = 0;
+
+ if (rxx2_0!=FL2FXCONST_DBL(0.f)) {
+ fac2 = FDKaacEnc_AutoCorrNormFac(rxx2_0, ((-2*sc2)+nsc2), &sc_fac2);
+ sc_fac2 -= 2;
+ }
+ if (rxx3_0!=FL2FXCONST_DBL(0.f)) {
+ fac3 = FDKaacEnc_AutoCorrNormFac(rxx3_0, ((-2*sc3)+nsc3), &sc_fac3);
+ sc_fac3 -= 2;
+ }
+ if (rxx4_0!=FL2FXCONST_DBL(0.f)) {
+ fac4 = FDKaacEnc_AutoCorrNormFac(rxx4_0, ((-2*sc4)+nsc4), &sc_fac4);
+ sc_fac4 -= 2;
+ }
+
+ _rxx2[0] = scaleValue(fMult(rxx2_0,fac2),sc_fac2) +
+ scaleValue(fMult(rxx3_0,fac3),sc_fac3) +
+ scaleValue(fMult(rxx4_0,fac4),sc_fac4);
+
+ for (lag = 1; lag <= maxOrder; lag++) {
+ /* merge quarters 2, 3, 4 into one autocorrelation; quarter 1 stays separate */
+ FIXP_DBL x2 = scaleValue(fMult(FDKaacEnc_CalcAutoCorrValue(pSpectrum, idx1, idx2, lag, nsc2), fac2),sc_fac2) +
+ scaleValue(fMult(FDKaacEnc_CalcAutoCorrValue(pSpectrum, idx2, idx3, lag, nsc3), fac3),sc_fac3) +
+ scaleValue(fMult(FDKaacEnc_CalcAutoCorrValue(pSpectrum, idx3, idx4, lag, nsc4), fac4),sc_fac4);
+
+ _rxx2[lag] = fMult(x2, acfWindow[HIFILT][lag]);
+ }
+ }
+
+ C_ALLOC_SCRATCH_END(pSpectrum, FIXP_DBL, (1024));
+}
+
+
+/*****************************************************************************
+ functionname: FDKaacEnc_TnsDetect
+ description: do decision, if TNS shall be used or not
+ returns:
+ input: tns data structure (modified),
+ tns config structure,
+ scalefactor size and table,
+ spectrum,
+ subblock num, blocktype,
+ sfb-wise energy.
+
+*****************************************************************************/
+INT FDKaacEnc_TnsDetect(
+ TNS_DATA *tnsData,
+ const TNS_CONFIG *tC,
+ TNS_INFO* tnsInfo,
+ INT sfbCnt,
+ FIXP_DBL *spectrum,
+ INT subBlockNumber,
+ INT blockType
+ )
+{
+ /* autocorrelation function for 1st, 2nd, 3rd, and 4th quarter of the spectrum. */
+ FIXP_DBL rxx1[TNS_MAX_ORDER+1]; /* higher part */
+ FIXP_DBL rxx2[TNS_MAX_ORDER+1]; /* lower part */
+ FIXP_DBL parcor_tmp[TNS_MAX_ORDER];
+
+ int i;
+
+ TNS_SUBBLOCK_INFO *tsbi = (blockType == SHORT_WINDOW)
+ ? &tnsData->dataRaw.Short.subBlockInfo[subBlockNumber]
+ : &tnsData->dataRaw.Long.subBlockInfo;
+
+ tnsData->filtersMerged = FALSE;
+ tsbi->tnsActive = FALSE;
+ tsbi->predictionGain = 1000;
+ tnsInfo->numOfFilters[subBlockNumber] = 0;
+ tnsInfo->coefRes[subBlockNumber] = tC->coefRes;
+ for (i = 0; i < tC->maxOrder; i++) {
+ tnsInfo->coef[subBlockNumber][HIFILT][i] = tnsInfo->coef[subBlockNumber][LOFILT][i] = 0;
+ }
+
+ tnsInfo->length[subBlockNumber][HIFILT] = tnsInfo->length[subBlockNumber][LOFILT] = 0;
+ tnsInfo->order [subBlockNumber][HIFILT] = tnsInfo->order [subBlockNumber][LOFILT] = 0;
+
+ if ( (tC->tnsActive) && (tC->maxOrder>0) )
+ {
+ int sumSqrCoef;
+
+ FDKaacEnc_MergedAutoCorrelation(
+ spectrum,
+ tC->acfWindow,
+ tC->lpcStartLine,
+ tC->lpcStopLine,
+ tC->maxOrder,
+ tC->confTab.acfSplit,
+ rxx1,
+ rxx2);
+
+ /* compute higher TNS filter in lattice (ParCor) form with LeRoux-Gueguen algorithm */
+ tsbi->predictionGain = FDKaacEnc_AutoToParcor(rxx2, parcor_tmp, tC->confTab.tnsLimitOrder[HIFILT]);
+
+ /* non-linear quantization of TNS lattice coefficients with given resolution */
+ FDKaacEnc_Parcor2Index(
+ parcor_tmp,
+ tnsInfo->coef[subBlockNumber][HIFILT],
+ tC->confTab.tnsLimitOrder[HIFILT],
+ tC->coefRes);
+
+ /* reduce filter order by truncating trailing zeros, compute sum(abs(coefs)) */
+ for (i = tC->confTab.tnsLimitOrder[HIFILT] - 1; i >= 0; i--) {
+ if (tnsInfo->coef[subBlockNumber][HIFILT][i] != 0) {
+ break;
+ }
+ }
+
+ tnsInfo->order[subBlockNumber][HIFILT] = i + 1;
+
+ sumSqrCoef = 0;
+ for (; i >= 0; i--) {
+ sumSqrCoef += tnsInfo->coef[subBlockNumber][HIFILT][i] * tnsInfo->coef[subBlockNumber][HIFILT][i];
+ }
+
+ tnsInfo->direction[subBlockNumber][HIFILT] = tC->confTab.tnsFilterDirection[HIFILT];
+ tnsInfo->length[subBlockNumber][HIFILT] = sfbCnt - tC->lpcStartBand[HIFILT];
+
+ /* disable TNS if predictionGain is less than 3dB or sumSqrCoef is too small */
+ if ((tsbi->predictionGain > tC->confTab.threshOn[HIFILT]) || (sumSqrCoef > (tC->confTab.tnsLimitOrder[HIFILT]/2 + 2)))
+ {
+ tsbi->tnsActive = TRUE;
+ tnsInfo->numOfFilters[subBlockNumber]++;
+
+ /* compute second filter for lower quarter; only allowed for long windows! */
+ if ( (blockType != SHORT_WINDOW) &&
+ (tC->confTab.filterEnabled[LOFILT]) && (tC->confTab.seperateFiltersAllowed) )
+ {
+ /* compute second filter for lower frequencies */
+
+ /* compute TNS filter in lattice (ParCor) form with LeRoux-Gueguen algorithm */
+ INT predGain = FDKaacEnc_AutoToParcor(rxx1, parcor_tmp, tC->confTab.tnsLimitOrder[LOFILT]);
+
+ /* non-linear quantization of TNS lattice coefficients with given resolution */
+ FDKaacEnc_Parcor2Index(
+ parcor_tmp,
+ tnsInfo->coef[subBlockNumber][LOFILT],
+ tC->confTab.tnsLimitOrder[LOFILT],
+ tC->coefRes);
+
+ /* reduce filter order by truncating trailing zeros, compute sum(abs(coefs)) */
+ for (i = tC->confTab.tnsLimitOrder[LOFILT] - 1; i >= 0; i--) {
+ if (tnsInfo->coef[subBlockNumber][LOFILT][i] != 0) {
+ break;
+ }
+ }
+ tnsInfo->order[subBlockNumber][LOFILT] = i + 1;
+
+ sumSqrCoef = 0;
+ for (; i >= 0; i--) {
+ sumSqrCoef += tnsInfo->coef[subBlockNumber][LOFILT][i] * tnsInfo->coef[subBlockNumber][LOFILT][i];
+ }
+
+ tnsInfo->direction[subBlockNumber][LOFILT] = tC->confTab.tnsFilterDirection[LOFILT];
+ tnsInfo->length[subBlockNumber][LOFILT] = tC->lpcStartBand[HIFILT] - tC->lpcStartBand[LOFILT];
+
+ /* filter lower quarter if gain is high enough, but not if it's too high */
+ if ( ( (predGain > tC->confTab.threshOn[LOFILT]) && (predGain < (16000 * tC->confTab.tnsLimitOrder[LOFILT])) )
+ || ( (sumSqrCoef > 9) && (sumSqrCoef < 22 * tC->confTab.tnsLimitOrder[LOFILT]) ) )
+ {
+ /* compare lower to upper filter; if they are very similar, merge them */
+ sumSqrCoef = 0;
+ for (i = 0; i < tC->confTab.tnsLimitOrder[LOFILT]; i++) {
+ sumSqrCoef += FDKabs(tnsInfo->coef[subBlockNumber][HIFILT][i] - tnsInfo->coef[subBlockNumber][LOFILT][i]);
+ }
+ if ( (sumSqrCoef < 2) &&
+ (tnsInfo->direction[subBlockNumber][LOFILT] == tnsInfo->direction[subBlockNumber][HIFILT]) )
+ {
+ tnsData->filtersMerged = TRUE;
+ tnsInfo->length[subBlockNumber][HIFILT] = sfbCnt - tC->lpcStartBand[LOFILT];
+ for (; i < tnsInfo->order[subBlockNumber][HIFILT]; i++) {
+ if (FDKabs(tnsInfo->coef[subBlockNumber][HIFILT][i]) > 1) {
+ break;
+ }
+ }
+ for (i--; i >= 0; i--) {
+ if (tnsInfo->coef[subBlockNumber][HIFILT][i] != 0) {
+ break;
+ }
+ }
+ if (i < tnsInfo->order[subBlockNumber][HIFILT]) {
+ tnsInfo->order[subBlockNumber][HIFILT] = i + 1;
+ }
+ }
+ else {
+ tnsInfo->numOfFilters[subBlockNumber]++;
+ }
+ } /* filter lower part */
+ } /* second filter allowed */
+ } /* if predictionGain > 1437 ... */
+ } /* maxOrder > 0 && tnsActive */
+
+ return 0;
+
+}
+
+
+/***************************************************************************/
+/*!
+ \brief FDKaacLdEnc_TnsSync
+
+ synchronize TNS parameters when TNS gain difference small (relative)
+
+ \param pointer to TNS data structure (destination)
+ \param pointer to TNS data structure (source)
+ \param pointer to TNS config structure
+ \param number of sub-block
+ \param block type
+
+ \return void
+****************************************************************************/
+void FDKaacEnc_TnsSync(
+ TNS_DATA *tnsDataDest,
+ const TNS_DATA *tnsDataSrc,
+ TNS_INFO *tnsInfoDest,
+ TNS_INFO *tnsInfoSrc,
+ const INT blockTypeDest,
+ const INT blockTypeSrc,
+ const TNS_CONFIG *tC
+ )
+{
+ int i, w, absDiff, nWindows;
+ TNS_SUBBLOCK_INFO *sbInfoDest;
+ const TNS_SUBBLOCK_INFO *sbInfoSrc;
+
+ /* if one channel contains short blocks and the other not, do not synchronize */
+ if ( (blockTypeSrc == SHORT_WINDOW && blockTypeDest != SHORT_WINDOW) ||
+ (blockTypeDest == SHORT_WINDOW && blockTypeSrc != SHORT_WINDOW) )
+ {
+ return;
+ }
+
+ if (blockTypeDest != SHORT_WINDOW) {
+ sbInfoDest = &tnsDataDest->dataRaw.Long.subBlockInfo;
+ sbInfoSrc = &tnsDataSrc->dataRaw.Long.subBlockInfo;
+ nWindows = 1;
+ } else {
+ sbInfoDest = &tnsDataDest->dataRaw.Short.subBlockInfo[0];
+ sbInfoSrc = &tnsDataSrc->dataRaw.Short.subBlockInfo[0];
+ nWindows = 8;
+ }
+
+ for (w=0; w<nWindows; w++) {
+ const TNS_SUBBLOCK_INFO *pSbInfoSrcW = sbInfoSrc + w;
+ TNS_SUBBLOCK_INFO *pSbInfoDestW = sbInfoDest + w;
+ INT doSync = 1, absDiffSum = 0;
+
+ /* if TNS is active in at least one channel, check if ParCor coefficients of higher filter are similar */
+ if (pSbInfoDestW->tnsActive || pSbInfoSrcW->tnsActive) {
+ for (i = 0; i < tC->maxOrder; i++) {
+ absDiff = FDKabs(tnsInfoDest->coef[w][HIFILT][i] - tnsInfoSrc->coef[w][HIFILT][i]);
+ absDiffSum += absDiff;
+ /* if coefficients diverge too much between channels, do not synchronize */
+ if ((absDiff > 1) || (absDiffSum > 2)) {
+ doSync = 0;
+ break;
+ }
+ }
+
+ if (doSync) {
+ /* if no significant difference was detected, synchronize coefficient sets */
+ if (pSbInfoSrcW->tnsActive) {
+ /* no dest filter, or more dest than source filters: use one dest filter */
+ if ((!pSbInfoDestW->tnsActive) ||
+ ((pSbInfoDestW->tnsActive) && (tnsInfoDest->numOfFilters[w] > tnsInfoSrc->numOfFilters[w])))
+ {
+ pSbInfoDestW->tnsActive = tnsInfoDest->numOfFilters[w] = 1;
+ }
+ tnsDataDest->filtersMerged = tnsDataSrc->filtersMerged;
+ tnsInfoDest->order [w][HIFILT] = tnsInfoSrc->order [w][HIFILT];
+ tnsInfoDest->length [w][HIFILT] = tnsInfoSrc->length [w][HIFILT];
+ tnsInfoDest->direction [w][HIFILT] = tnsInfoSrc->direction [w][HIFILT];
+ tnsInfoDest->coefCompress[w][HIFILT] = tnsInfoSrc->coefCompress[w][HIFILT];
+
+ for (i = 0; i < tC->maxOrder; i++) {
+ tnsInfoDest->coef[w][HIFILT][i] = tnsInfoSrc->coef[w][HIFILT][i];
+ }
+ }
+ else
+ pSbInfoDestW->tnsActive = tnsInfoDest->numOfFilters[w] = 0;
+ }
+ }
+
+ }
+}
+
+/***************************************************************************/
+/*!
+ \brief FDKaacEnc_TnsEncode
+
+ perform TNS encoding
+
+ \param pointer to TNS info structure
+ \param pointer to TNS data structure
+ \param number of sfbs
+ \param pointer to TNS config structure
+ \param low-pass line
+ \param pointer to spectrum
+ \param number of sub-block
+ \param block type
+
+ \return ERROR STATUS
+****************************************************************************/
+INT FDKaacEnc_TnsEncode(
+ TNS_INFO* tnsInfo,
+ TNS_DATA* tnsData,
+ const INT numOfSfb,
+ const TNS_CONFIG *tC,
+ const INT lowPassLine,
+ FIXP_DBL* spectrum,
+ const INT subBlockNumber,
+ const INT blockType
+ )
+{
+ INT i, startLine, stopLine;
+
+ if ( ( (blockType == SHORT_WINDOW) && (!tnsData->dataRaw.Short.subBlockInfo[subBlockNumber].tnsActive) )
+ || ( (blockType != SHORT_WINDOW) && (!tnsData->dataRaw.Long.subBlockInfo.tnsActive) ) )
+ {
+ return 1;
+ }
+
+ startLine = (tnsData->filtersMerged) ? tC->lpcStartLine[LOFILT] : tC->lpcStartLine[HIFILT];
+ stopLine = tC->lpcStopLine;
+
+ for (i=0; i<tnsInfo->numOfFilters[subBlockNumber]; i++) {
+
+ INT lpcGainFactor;
+ FIXP_DBL LpcCoeff[TNS_MAX_ORDER];
+ FIXP_DBL workBuffer[TNS_MAX_ORDER];
+ FIXP_DBL parcor_tmp[TNS_MAX_ORDER];
+
+ FDKaacEnc_Index2Parcor(
+ tnsInfo->coef[subBlockNumber][i],
+ parcor_tmp,
+ tnsInfo->order[subBlockNumber][i],
+ tC->coefRes);
+
+ lpcGainFactor = FDKaacEnc_ParcorToLpc(
+ parcor_tmp,
+ LpcCoeff,
+ tnsInfo->order[subBlockNumber][i],
+ workBuffer);
+
+ FDKaacEnc_AnalysisFilter(
+ &spectrum[startLine],
+ stopLine - startLine,
+ LpcCoeff,
+ tnsInfo->order[subBlockNumber][i],
+ lpcGainFactor);
+
+ /* update for second filter */
+ startLine = tC->lpcStartLine[LOFILT];
+ stopLine = tC->lpcStartLine[HIFILT];
+ }
+
+ return(0);
+
+}
+
+static void FDKaacEnc_CalcGaussWindow(
+ FIXP_DBL *win,
+ const int winSize,
+ const INT samplingRate,
+ const INT transformResolution,
+ const FIXP_DBL timeResolution,
+ const INT timeResolution_e
+ )
+{
+ #define PI_SCALE (2)
+ #define PI_FIX FL2FXCONST_DBL(3.1416f/(float)(1<<PI_SCALE))
+
+ #define EULER_SCALE (2)
+ #define EULER_FIX FL2FXCONST_DBL(2.7183/(float)(1<<EULER_SCALE))
+
+ #define COEFF_LOOP_SCALE (4)
+
+ INT i, e1, e2, gaussExp_e;
+ FIXP_DBL gaussExp_m;
+
+ /* calc. window exponent from time resolution:
+ *
+ * gaussExp = PI * samplingRate * 0.001f * timeResolution / transformResolution;
+ * gaussExp = -0.5f * gaussExp * gaussExp;
+ */
+ gaussExp_m = fMultNorm(timeResolution, fMult(PI_FIX, fDivNorm( (FIXP_DBL)(samplingRate), (FIXP_DBL)(LONG)(transformResolution*1000.f), &e1)), &e2);
+ gaussExp_m = -fPow2Div2(gaussExp_m);
+ gaussExp_e = 2*(e1+e2+timeResolution_e+PI_SCALE);
+
+ FDK_ASSERT( winSize < (1<<COEFF_LOOP_SCALE) );
+
+ /* calc. window coefficients
+ * win[i] = (float)exp( gaussExp * (i+0.5) * (i+0.5) );
+ */
+ for( i=0; i<winSize; i++) {
+
+ win[i] = fPow(
+ EULER_FIX,
+ EULER_SCALE,
+ fMult(gaussExp_m, fPow2((i*FL2FXCONST_DBL(1.f/(float)(1<<COEFF_LOOP_SCALE)) + FL2FXCONST_DBL(.5f/(float)(1<<COEFF_LOOP_SCALE))))),
+ gaussExp_e + 2*COEFF_LOOP_SCALE,
+ &e1);
+
+ win[i] = scaleValue(win[i], e1);
+ }
+}
+
+
+/***************************************************************************/
+/*!
+ \brief FDKaacEnc_AutoToParcor
+
+ conversion autocorrelation to reflection coefficients
+
+ \param pointer to input (acf)
+ \param pointer to output (reflection coefficients)
+ \param number of coefficients
+
+ \return prediction gain
+****************************************************************************/
+static INT FDKaacEnc_AutoToParcor(
+ FIXP_DBL *RESTRICT input,
+ FIXP_DBL *RESTRICT reflCoeff,
+ const INT numOfCoeff
+ )
+{
+ INT i, j, scale=0;
+ FIXP_DBL tmp, parcorWorkBuffer[TNS_MAX_ORDER];
+ INT predictionGain = (INT)(TNS_PREDGAIN_SCALE);
+
+ FIXP_DBL *RESTRICT workBuffer = parcorWorkBuffer;
+ const FIXP_DBL autoCorr_0 = input[0];
+
+ if((FIXP_DBL)input[0] == FL2FXCONST_DBL(0.0)) {
+ FDKmemclear(reflCoeff,numOfCoeff*sizeof(FIXP_DBL));
+ return(predictionGain);
+ }
+
+ FDKmemcpy(workBuffer,&input[1],numOfCoeff*sizeof(FIXP_DBL));
+ for(i=0; i<numOfCoeff; i++) {
+ LONG sign = ((LONG)workBuffer[0] >> (DFRACT_BITS-1));
+ tmp = (FIXP_DBL)((LONG)workBuffer[0]^sign);
+
+ if(input[0]<tmp)
+ break;
+
+ tmp = (FIXP_DBL)((LONG)schur_div(tmp, input[0], FRACT_BITS)^(~sign));
+ reflCoeff[i] = tmp;
+
+ for(j=numOfCoeff-i-1; j>=0; j--) {
+ FIXP_DBL accu1 = fMult(tmp, input[j]);
+ FIXP_DBL accu2 = fMult(tmp, workBuffer[j]);
+ workBuffer[j] += accu1;
+ input[j] += accu2;
+ }
+
+ workBuffer++;
+ }
+
+ tmp = fMult((FIXP_DBL)((LONG)TNS_PREDGAIN_SCALE<<21), fDivNorm(autoCorr_0, input[0], &scale));
+ predictionGain = (LONG)scaleValue(tmp,scale-21);
+
+ return (predictionGain);
+}
+
+
+static INT FDKaacEnc_Search3(FIXP_DBL parcor)
+{
+ INT i, index=0;
+
+ for(i=0;i<8;i++){
+ if(parcor > FDKaacEnc_tnsCoeff3Borders[i])
+ index=i;
+ }
+ return(index-4);
+}
+
+static INT FDKaacEnc_Search4(FIXP_DBL parcor)
+{
+ INT i, index=0;
+
+ for(i=0;i<16;i++){
+ if(parcor > FDKaacEnc_tnsCoeff4Borders[i])
+ index=i;
+ }
+ return(index-8);
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_Parcor2Index
+
+*****************************************************************************/
+static void FDKaacEnc_Parcor2Index(
+ const FIXP_DBL *parcor,
+ INT *RESTRICT index,
+ const INT order,
+ const INT bitsPerCoeff
+ )
+{
+ INT i;
+ for(i=0; i<order; i++) {
+ if(bitsPerCoeff == 3)
+ index[i] = FDKaacEnc_Search3(parcor[i]);
+ else
+ index[i] = FDKaacEnc_Search4(parcor[i]);
+ }
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_Index2Parcor
+ description: inverse quantization for reflection coefficients
+ returns: -
+ input: quantized values, ptr. to reflection coefficients,
+ no. of coefficients, resolution
+ output: reflection coefficients
+
+*****************************************************************************/
+static void FDKaacEnc_Index2Parcor(
+ const INT *index,
+ FIXP_DBL *RESTRICT parcor,
+ const INT order,
+ const INT bitsPerCoeff
+ )
+{
+ INT i;
+ for(i=0; i<order; i++)
+ parcor[i] = bitsPerCoeff == 4 ? FDKaacEnc_tnsEncCoeff4[index[i]+8] : FDKaacEnc_tnsEncCoeff3[index[i]+4];
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_ParcorToLpc
+ description: conversion reflection coefficients to LPC coefficients
+ returns: Gain factor
+ input: reflection coefficients, no. of reflection coefficients <order>,
+ ptr. to work buffer (required size: order)
+ output: <order> LPC coefficients
+
+*****************************************************************************/
+static INT FDKaacEnc_ParcorToLpc(
+ const FIXP_DBL *reflCoeff,
+ FIXP_DBL *RESTRICT LpcCoeff,
+ const INT numOfCoeff,
+ FIXP_DBL *RESTRICT workBuffer
+ )
+{
+ INT i, j;
+ INT shiftval, par2LpcShiftVal = 6; /* 6 should be enough, bec. max(numOfCoeff) = 20 */
+ FIXP_DBL maxVal = FL2FXCONST_DBL(0.0f);
+
+ LpcCoeff[0] = reflCoeff[0] >> par2LpcShiftVal;
+ for(i=1; i<numOfCoeff; i++) {
+ for(j=0; j<i; j++) {
+ workBuffer[j] = LpcCoeff[i-1-j];
+ }
+
+ for(j=0; j<i; j++) {
+ LpcCoeff[j] += fMult(reflCoeff[i],workBuffer[j]);
+ }
+
+ LpcCoeff[i] = reflCoeff[i] >> par2LpcShiftVal;
+ }
+
+ /* normalize LpcCoeff and calc shiftfactor */
+ for(i=0; i<numOfCoeff; i++) {
+ maxVal = fixMax(maxVal,(FIXP_DBL)fixp_abs(LpcCoeff[i]));
+ }
+
+ shiftval = CountLeadingBits(maxVal);
+ shiftval = (shiftval>=par2LpcShiftVal) ? par2LpcShiftVal : shiftval;
+
+ for(i=0; i<numOfCoeff; i++)
+ LpcCoeff[i] = LpcCoeff[i]<<shiftval;
+
+ return (par2LpcShiftVal - shiftval);
+}
+
+/***************************************************************************/
+/*!
+ \brief FDKaacEnc_AnalysisFilter
+
+ TNS analysis filter (all-zero filter)
+
+ \param pointer to signal spectrum
+ \param number of lines
+ \param pointer to lpc coefficients
+ \param filter order
+ \param lpc gain factor
+
+ \return void
+****************************************************************************/
+/* Note: in-place computation possible */
+static void FDKaacEnc_AnalysisFilter(
+ FIXP_DBL *RESTRICT signal,
+ const INT numOfLines,
+ const FIXP_DBL *predictorCoeff,
+ const INT order,
+ const INT lpcGainFactor
+ )
+{
+ FIXP_DBL statusVar[TNS_MAX_ORDER];
+ INT i, j;
+ const INT shift = lpcGainFactor + 1; /* +1, because fMultDiv2 */
+ FIXP_DBL tmp;
+
+ if (order>0) {
+
+ INT idx = 0;
+
+ /* keep filter coefficients twice and save memory copy operation in
+ modulo state buffer */
+#if defined(ARCH_PREFER_MULT_32x16)
+ FIXP_SGL coeff[2*TNS_MAX_ORDER];
+ const FIXP_SGL *pCoeff;
+ for(i=0;i<order;i++) {
+ coeff[i] = FX_DBL2FX_SGL(predictorCoeff[i]);
+ }
+ FDKmemcpy(&coeff[order], coeff, order*sizeof(FIXP_SGL));
+#else
+ FIXP_DBL coeff[2*TNS_MAX_ORDER];
+ const FIXP_DBL *pCoeff;
+ FDKmemcpy(&coeff[0], predictorCoeff, order*sizeof(FIXP_DBL));
+ FDKmemcpy(&coeff[order], predictorCoeff, order*sizeof(FIXP_DBL));
+#endif
+ FDKmemclear(statusVar, order*sizeof(FIXP_DBL));
+
+ for(j=0; j<numOfLines; j++) {
+ pCoeff = &coeff[(order-idx)];
+ tmp = FL2FXCONST_DBL(0);
+ for(i=0; i<order; i++) {
+ tmp = fMultAddDiv2(tmp, pCoeff[i], statusVar[i]) ;
+ }
+
+ if(--idx<0) { idx = order-1; }
+ statusVar[idx] = signal[j];
+
+ FDK_ASSERT(lpcGainFactor>=0);
+ signal[j] = (tmp<<shift) + signal[j];
+ }
+ }
+}
+
+
diff --git a/libAACenc/src/aacenc_tns.h b/libAACenc/src/aacenc_tns.h
new file mode 100644
index 0000000..4ddfdbb
--- /dev/null
+++ b/libAACenc/src/aacenc_tns.h
@@ -0,0 +1,135 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: Alex Groeschel
+ contents/description: Temporal noise shaping
+
+******************************************************************************/
+#ifndef _TNS_H
+#define _TNS_H
+
+#include "common_fix.h"
+
+#include "psy_const.h"
+
+
+#ifndef PI
+#define PI 3.1415926535897931f
+#endif
+
+/**
+ * TNS_ENABLE_MASK
+ * This bitfield defines which TNS features are enabled
+ * The TNS mask is composed of 4 bits.
+ * tnsMask |= 0x1; activate TNS short blocks
+ * tnsMask |= 0x2; activate TNS for long blocks
+ * tnsMask |= 0x4; activate TNS PEAK tool for short blocks
+ * tnsMask |= 0x8; activate TNS PEAK tool for long blocks
+ */
+#define TNS_ENABLE_MASK 0xf
+
+/* TNS max filter order for Low Complexity MPEG4 profile */
+#define TNS_MAX_ORDER 12
+
+
+#define MAX_NUM_OF_FILTERS 2
+
+
+typedef struct{ /*stuff that is tabulated dependent on bitrate etc. */
+ INT filterEnabled[MAX_NUM_OF_FILTERS];
+ INT threshOn[MAX_NUM_OF_FILTERS]; /* min. prediction gain for using tns TABUL*/
+ INT tnsLimitOrder[MAX_NUM_OF_FILTERS]; /* Limit for TNS order TABUL*/
+ INT tnsFilterDirection[MAX_NUM_OF_FILTERS]; /* Filtering direction, 0=up, 1=down TABUL */
+ INT acfSplit[MAX_NUM_OF_FILTERS];
+ INT seperateFiltersAllowed;
+
+}TNS_CONFIG_TABULATED;
+
+
+
+typedef struct { /*assigned at InitTime*/
+ TNS_CONFIG_TABULATED confTab;
+ INT tnsActive;
+ INT maxOrder; /* max. order of tns filter */
+ INT coefRes;
+ FIXP_DBL acfWindow[MAX_NUM_OF_FILTERS][TNS_MAX_ORDER+3+1];
+ /* now some things that only probably can be done at Init time;
+ could be they have to be split up for each individual (short) window or
+ even filter. */
+ INT lpcStartBand[MAX_NUM_OF_FILTERS];
+ INT lpcStartLine[MAX_NUM_OF_FILTERS];
+ INT lpcStopBand;
+ INT lpcStopLine;
+
+}TNS_CONFIG;
+
+
+typedef struct {
+ INT tnsActive;
+ INT predictionGain;
+} TNS_SUBBLOCK_INFO;
+
+typedef struct{ /*changed at runTime*/
+ TNS_SUBBLOCK_INFO subBlockInfo[TRANS_FAC];
+ FIXP_DBL ratioMultTable[TRANS_FAC][MAX_SFB_SHORT];
+} TNS_DATA_SHORT;
+
+typedef struct{ /*changed at runTime*/
+ TNS_SUBBLOCK_INFO subBlockInfo;
+ FIXP_DBL ratioMultTable[MAX_SFB_LONG];
+} TNS_DATA_LONG;
+
+/* can be implemented as union */
+typedef shouldBeUnion{
+ TNS_DATA_LONG Long;
+ TNS_DATA_SHORT Short;
+}TNS_DATA_RAW;
+
+typedef struct{
+ INT numOfSubblocks;
+ TNS_DATA_RAW dataRaw;
+ INT tnsMaxScaleSpec;
+ INT filtersMerged;
+}TNS_DATA;
+
+typedef struct{
+ INT numOfFilters[TRANS_FAC];
+ INT coefRes[TRANS_FAC];
+ INT length[TRANS_FAC][MAX_NUM_OF_FILTERS];
+ INT order[TRANS_FAC][MAX_NUM_OF_FILTERS];
+ INT direction[TRANS_FAC][MAX_NUM_OF_FILTERS];
+ INT coefCompress[TRANS_FAC][MAX_NUM_OF_FILTERS];
+ /* for Long: length TNS_MAX_ORDER (12 for LC) is required -> 12 */
+ /* for Short: length TRANS_FAC*TNS_MAX_ORDER (only 5 for short LC) is required -> 8*5=40 */
+ /* Currently TRANS_FAC*TNS_MAX_ORDER = 8*12 = 96 (for LC) is used (per channel)! Memory could be saved here! */
+ INT coef[TRANS_FAC][MAX_NUM_OF_FILTERS][TNS_MAX_ORDER];
+}TNS_INFO;
+
+INT FDKaacEnc_FreqToBandWithRounding(
+ const INT freq,
+ const INT fs,
+ const INT numOfBands,
+ const INT *bandStartOffset
+ );
+
+#endif /* _TNS_H */
diff --git a/libAACenc/src/adj_thr.cpp b/libAACenc/src/adj_thr.cpp
new file mode 100644
index 0000000..d9d89f2
--- /dev/null
+++ b/libAACenc/src/adj_thr.cpp
@@ -0,0 +1,2262 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: Threshold compensation
+
+******************************************************************************/
+
+#include "common_fix.h"
+
+#include "adj_thr_data.h"
+#include "adj_thr.h"
+#include "qc_data.h"
+#include "sf_estim.h"
+#include "aacEnc_ram.h"
+
+
+
+
+#define INV_INT_TAB_SIZE (8)
+static const FIXP_DBL invInt[INV_INT_TAB_SIZE] =
+{
+ 0x7fffffff, 0x7fffffff, 0x40000000, 0x2aaaaaaa, 0x20000000, 0x19999999, 0x15555555, 0x12492492
+};
+
+
+#define INV_SQRT4_TAB_SIZE (8)
+static const FIXP_DBL invSqrt4[INV_SQRT4_TAB_SIZE] =
+{
+ 0x7fffffff, 0x7fffffff, 0x6ba27e65, 0x61424bb5, 0x5a827999, 0x55994845, 0x51c8e33c, 0x4eb160d1
+};
+
+
+/*static const INT invRedExp = 4;*/
+static const FIXP_DBL SnrLdMin1 = (FIXP_DBL)0xfcad0ddf; /*FL2FXCONST_DBL(FDKlog(0.316)/FDKlog(2.0)/LD_DATA_SCALING);*/
+static const FIXP_DBL SnrLdMin2 = (FIXP_DBL)0x0351e1a2; /*FL2FXCONST_DBL(FDKlog(3.16) /FDKlog(2.0)/LD_DATA_SCALING);*/
+static const FIXP_DBL SnrLdFac = (FIXP_DBL)0xff5b2c3e; /*FL2FXCONST_DBL(FDKlog(0.8) /FDKlog(2.0)/LD_DATA_SCALING);*/
+
+static const FIXP_DBL SnrLdMin3 = (FIXP_DBL)0xfe000000; /*FL2FXCONST_DBL(FDKlog(0.5) /FDKlog(2.0)/LD_DATA_SCALING);*/
+static const FIXP_DBL SnrLdMin4 = (FIXP_DBL)0x02000000; /*FL2FXCONST_DBL(FDKlog(2.0) /FDKlog(2.0)/LD_DATA_SCALING);*/
+static const FIXP_DBL SnrLdMin5 = (FIXP_DBL)0xfc000000; /*FL2FXCONST_DBL(FDKlog(0.25) /FDKlog(2.0)/LD_DATA_SCALING);*/
+
+
+/* values for avoid hole flag */
+enum _avoid_hole_state {
+ NO_AH =0,
+ AH_INACTIVE =1,
+ AH_ACTIVE =2
+};
+
+
+/* Q format definitions */
+#define Q_BITFAC (24) /* Q scaling used in FDKaacEnc_bitresCalcBitFac() calculation */
+#define Q_AVGBITS (17) /* scale bit values */
+
+static INT FDKaacEnc_bits2pe2(
+ const INT bits,
+ const FIXP_DBL factor_m,
+ const INT factor_e
+ )
+{
+ return (INT)(fMult(factor_m, (FIXP_DBL)(bits<<Q_AVGBITS)) >> (Q_AVGBITS-factor_e));
+}
+
+/*****************************************************************************
+functionname: FDKaacEnc_calcThreshExp
+description: loudness calculation (threshold to the power of redExp)
+*****************************************************************************/
+static void FDKaacEnc_calcThreshExp(FIXP_DBL thrExp[(2)][MAX_GROUPED_SFB],
+ QC_OUT_CHANNEL* qcOutChannel[(2)],
+ PSY_OUT_CHANNEL* psyOutChannel[(2)],
+ const INT nChannels)
+{
+ INT ch, sfb, sfbGrp;
+ FIXP_DBL thrExpLdData;
+
+ for (ch=0; ch<nChannels; ch++) {
+ for(sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup) {
+ for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+ thrExpLdData = psyOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb]>>2 ;
+ thrExp[ch][sfbGrp+sfb] = CalcInvLdData(thrExpLdData);
+ }
+ }
+ }
+}
+
+
+/*****************************************************************************
+ functionname: FDKaacEnc_adaptMinSnr
+ description: reduce minSnr requirements for bands with relative low energies
+*****************************************************************************/
+static void FDKaacEnc_adaptMinSnr(QC_OUT_CHANNEL *qcOutChannel[(2)],
+ PSY_OUT_CHANNEL *psyOutChannel[(2)],
+ MINSNR_ADAPT_PARAM *msaParam,
+ const INT nChannels)
+{
+ INT ch, sfb, sfbGrp, nSfb;
+ FIXP_DBL avgEnLD64, dbRatio, minSnrRed;
+ FIXP_DBL minSnrLimitLD64 = FL2FXCONST_DBL(-0.00503012648262f); /* ld64(0.8f) */
+ FIXP_DBL nSfbLD64;
+ FIXP_DBL accu;
+
+ for (ch=0; ch<nChannels; ch++) {
+ /* calc average energy per scalefactor band */
+ nSfb = 0;
+ accu = FL2FXCONST_DBL(0.0f);
+
+ for (sfbGrp=0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) {
+ for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+ accu += psyOutChannel[ch]->sfbEnergy[sfbGrp+sfb]>>6;
+ nSfb++;
+ }
+ }
+
+ if ((accu == FL2FXCONST_DBL(0.0f)) || (nSfb == 0)) {
+ avgEnLD64 = FL2FXCONST_DBL(-1.0f);
+ }
+ else {
+ nSfbLD64 = CalcLdInt(nSfb);
+ avgEnLD64 = CalcLdData(accu);
+ avgEnLD64 = avgEnLD64 + FL2FXCONST_DBL(0.09375f) - nSfbLD64; /* 0.09375f: compensate shift with 6 */
+ }
+
+ /* reduce minSnr requirement by minSnr^minSnrRed dependent on avgEn/sfbEn */
+ for (sfbGrp=0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) {
+ for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+ if ( (msaParam->startRatio + qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb]) < avgEnLD64 ) {
+ dbRatio = fMult((avgEnLD64 - qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb]),FL2FXCONST_DBL(0.3010299956f)); /* scaled by (1.0f/(10.0f*64.0f)) */
+ minSnrRed = msaParam->redOffs + fMult(msaParam->redRatioFac,dbRatio); /* scaled by 1.0f/64.0f*/
+ minSnrRed = fixMax(minSnrRed, msaParam->maxRed); /* scaled by 1.0f/64.0f*/
+ qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb] = (fMult(qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb],minSnrRed)) << 6;
+ qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(minSnrLimitLD64, qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb]);
+ }
+ }
+ }
+ }
+}
+
+
+/*****************************************************************************
+functionname: FDKaacEnc_initAvoidHoleFlag
+description: determine bands where avoid hole is not necessary resp. possible
+*****************************************************************************/
+static void FDKaacEnc_initAvoidHoleFlag(QC_OUT_CHANNEL *qcOutChannel[(2)],
+ PSY_OUT_CHANNEL *psyOutChannel[(2)],
+ UCHAR ahFlag[(2)][MAX_GROUPED_SFB],
+ struct TOOLSINFO *toolsInfo,
+ const INT nChannels,
+ const PE_DATA *peData,
+ AH_PARAM *ahParam)
+{
+ INT ch, sfb, sfbGrp;
+ FIXP_DBL sfbEn, sfbEnm1;
+ FIXP_DBL sfbEnLdData;
+ FIXP_DBL avgEnLdData;
+
+ /* decrease spread energy by 3dB for long blocks, resp. 2dB for shorts
+ (avoid more holes in long blocks) */
+ for (ch=0; ch<nChannels; ch++) {
+ INT sfbGrp, sfb;
+ QC_OUT_CHANNEL* qcOutChan = qcOutChannel[ch];
+
+ if (psyOutChannel[ch]->lastWindowSequence != SHORT_WINDOW) {
+ for (sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup)
+ for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++)
+ qcOutChan->sfbSpreadEnergy[sfbGrp+sfb] >>= 1 ;
+ }
+ else {
+ for (sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup)
+ for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++)
+ qcOutChan->sfbSpreadEnergy[sfbGrp+sfb] =
+ fMult(FL2FXCONST_DBL(0.63f),
+ qcOutChan->sfbSpreadEnergy[sfbGrp+sfb]) ;
+ }
+ }
+
+ /* increase minSnr for local peaks, decrease it for valleys */
+ if (ahParam->modifyMinSnr) {
+ for(ch=0; ch<nChannels; ch++) {
+ QC_OUT_CHANNEL* qcOutChan = qcOutChannel[ch];
+ for(sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup){
+ for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+ FIXP_DBL sfbEnp1, avgEn;
+ if (sfb > 0)
+ sfbEnm1 = qcOutChan->sfbEnergy[sfbGrp+sfb-1];
+ else
+ sfbEnm1 = qcOutChan->sfbEnergy[sfbGrp+sfb];
+
+ if (sfb < psyOutChannel[ch]->maxSfbPerGroup-1)
+ sfbEnp1 = qcOutChan->sfbEnergy[sfbGrp+sfb+1];
+ else
+ sfbEnp1 = qcOutChan->sfbEnergy[sfbGrp+sfb];
+
+ avgEn = (sfbEnm1>>1) + (sfbEnp1>>1);
+ avgEnLdData = CalcLdData(avgEn);
+ sfbEn = qcOutChan->sfbEnergy[sfbGrp+sfb];
+ sfbEnLdData = qcOutChan->sfbEnergyLdData[sfbGrp+sfb];
+ /* peak ? */
+ if (sfbEn > avgEn) {
+ FIXP_DBL tmpMinSnrLdData;
+ if (psyOutChannel[ch]->lastWindowSequence==LONG_WINDOW)
+ tmpMinSnrLdData = fixMax( SnrLdFac + (FIXP_DBL)(avgEnLdData - sfbEnLdData), (FIXP_DBL)SnrLdMin1 ) ;
+ else
+ tmpMinSnrLdData = fixMax( SnrLdFac + (FIXP_DBL)(avgEnLdData - sfbEnLdData), (FIXP_DBL)SnrLdMin3 ) ;
+
+ qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] =
+ fixMin(qcOutChan->sfbMinSnrLdData[sfbGrp+sfb], tmpMinSnrLdData);
+ }
+ /* valley ? */
+ if ( ((sfbEnLdData+(FIXP_DBL)SnrLdMin4) < (FIXP_DBL)avgEnLdData) && (sfbEn > FL2FXCONST_DBL(0.0)) ) {
+ FIXP_DBL tmpMinSnrLdData = avgEnLdData - sfbEnLdData -(FIXP_DBL)SnrLdMin4 + qcOutChan->sfbMinSnrLdData[sfbGrp+sfb];
+ tmpMinSnrLdData = fixMin((FIXP_DBL)SnrLdFac, tmpMinSnrLdData);
+ qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(tmpMinSnrLdData,
+ (FIXP_DBL)(qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + SnrLdMin2 ));
+ }
+ }
+ }
+ }
+ }
+
+ /* stereo: adapt the minimum requirements sfbMinSnr of mid and
+ side channels to avoid spending unnoticable bits */
+ if (nChannels == 2) {
+ QC_OUT_CHANNEL* qcOutChanM = qcOutChannel[0];
+ QC_OUT_CHANNEL* qcOutChanS = qcOutChannel[1];
+ PSY_OUT_CHANNEL* psyOutChanM = psyOutChannel[0];
+ for(sfbGrp = 0;sfbGrp < psyOutChanM->sfbCnt;sfbGrp+= psyOutChanM->sfbPerGroup){
+ for (sfb=0; sfb<psyOutChanM->maxSfbPerGroup; sfb++) {
+ if (toolsInfo->msMask[sfbGrp+sfb]) {
+ FIXP_DBL maxSfbEnLd = fixMax(qcOutChanM->sfbEnergyLdData[sfbGrp+sfb],qcOutChanS->sfbEnergyLdData[sfbGrp+sfb]);
+ FIXP_DBL maxThrLd, sfbMinSnrTmpLd;
+
+ if ( ((SnrLdMin5>>1) + (maxSfbEnLd>>1) + (qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb]>>1)) <= FL2FXCONST_DBL(-0.5f))
+ maxThrLd = FL2FXCONST_DBL(-1.0f) ;
+ else
+ maxThrLd = SnrLdMin5 + maxSfbEnLd + qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb];
+
+ if (qcOutChanM->sfbEnergy[sfbGrp+sfb] > FL2FXCONST_DBL(0.0f))
+ sfbMinSnrTmpLd = maxThrLd - qcOutChanM->sfbEnergyLdData[sfbGrp+sfb];
+ else
+ sfbMinSnrTmpLd = FL2FXCONST_DBL(0.0f);
+
+ qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb] = fixMax(qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb],sfbMinSnrTmpLd);
+
+ if (qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb] <= FL2FXCONST_DBL(0.0f))
+ qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb], (FIXP_DBL)SnrLdFac);
+
+ if (qcOutChanS->sfbEnergy[sfbGrp+sfb] > FL2FXCONST_DBL(0.0f))
+ sfbMinSnrTmpLd = maxThrLd - qcOutChanS->sfbEnergyLdData[sfbGrp+sfb];
+ else
+ sfbMinSnrTmpLd = FL2FXCONST_DBL(0.0f);
+
+ qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb] = fixMax(qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb],sfbMinSnrTmpLd);
+
+ if (qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb] <= FL2FXCONST_DBL(0.0f))
+ qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb],(FIXP_DBL)SnrLdFac);
+
+ if (qcOutChanM->sfbEnergy[sfbGrp+sfb]>qcOutChanM->sfbSpreadEnergy[sfbGrp+sfb])
+ qcOutChanS->sfbSpreadEnergy[sfbGrp+sfb] =
+ fMult(qcOutChanS->sfbEnergy[sfbGrp+sfb], FL2FXCONST_DBL(0.9f));
+
+ if (qcOutChanS->sfbEnergy[sfbGrp+sfb]>qcOutChanS->sfbSpreadEnergy[sfbGrp+sfb])
+ qcOutChanM->sfbSpreadEnergy[sfbGrp+sfb] =
+ fMult(qcOutChanM->sfbEnergy[sfbGrp+sfb], FL2FXCONST_DBL(0.9f));
+ }
+ }
+ }
+ }
+
+ /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
+ for(ch=0; ch<nChannels; ch++) {
+ QC_OUT_CHANNEL *qcOutChan = qcOutChannel[ch];
+ PSY_OUT_CHANNEL *psyOutChan = psyOutChannel[ch];
+ for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
+ for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
+ if ((qcOutChan->sfbSpreadEnergy[sfbGrp+sfb] > qcOutChan->sfbEnergy[sfbGrp+sfb])
+ || (qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] > FL2FXCONST_DBL(0.0f))) {
+ ahFlag[ch][sfbGrp+sfb] = NO_AH;
+ }
+ else {
+ ahFlag[ch][sfbGrp+sfb] = AH_INACTIVE;
+ }
+ }
+ }
+ }
+}
+
+
+
+/**
+ * \brief Calculate constants that do not change during successive pe calculations.
+ *
+ * \param peData Pointer to structure containing PE data of current element.
+ * \param psyOutChannel Pointer to PSY_OUT_CHANNEL struct holding nChannels elements.
+ * \param qcOutChannel Pointer to QC_OUT_CHANNEL struct holding nChannels elements.
+ * \param nChannels Number of channels in element.
+ * \param peOffset Fixed PE offset defined while FDKaacEnc_AdjThrInit() depending on bitrate.
+ *
+ * \return void
+ */
+static
+void FDKaacEnc_preparePe(PE_DATA *peData,
+ PSY_OUT_CHANNEL* psyOutChannel[(2)],
+ QC_OUT_CHANNEL* qcOutChannel[(2)],
+ const INT nChannels,
+ const INT peOffset)
+{
+ INT ch;
+
+ for(ch=0; ch<nChannels; ch++) {
+ PSY_OUT_CHANNEL *psyOutChan = psyOutChannel[ch];
+ FDKaacEnc_prepareSfbPe(&peData->peChannelData[ch],
+ psyOutChan->sfbEnergyLdData,
+ psyOutChan->sfbThresholdLdData,
+ qcOutChannel[ch]->sfbFormFactorLdData,
+ psyOutChan->sfbOffsets,
+ psyOutChan->sfbCnt,
+ psyOutChan->sfbPerGroup,
+ psyOutChan->maxSfbPerGroup);
+ }
+ peData->offset = peOffset;
+}
+
+/**
+ * \brief Calculate weighting factor for threshold adjustment.
+ *
+ * Calculate weighting factor to be applied at energies and thresholds in ld64 format.
+ *
+ * \param peData, Pointer to PE data in current element.
+ * \param psyOutChannel Pointer to PSY_OUT_CHANNEL struct holding nChannels elements.
+ * \param qcOutChannel Pointer to QC_OUT_CHANNEL struct holding nChannels elements.
+ * \param toolsInfo Pointer to tools info struct of current element.
+ * \param adjThrStateElement Pointer to ATS_ELEMENT holding enFacPatch states.
+ * \param nChannels Number of channels in element.
+ * \param usePatchTool Apply the weighting tool 0 (no) else (yes).
+ *
+ * \return void
+ */
+static
+void FDKaacEnc_calcWeighting(PE_DATA *peData,
+ PSY_OUT_CHANNEL* psyOutChannel[(2)],
+ QC_OUT_CHANNEL* qcOutChannel[(2)],
+ struct TOOLSINFO *toolsInfo,
+ ATS_ELEMENT* adjThrStateElement,
+ const INT nChannels,
+ const INT usePatchTool)
+{
+ int ch, noShortWindowInFrame = TRUE;
+ INT exePatchM = 0;
+
+ for (ch=0; ch<nChannels; ch++) {
+ if (psyOutChannel[ch]->lastWindowSequence == SHORT_WINDOW) {
+ noShortWindowInFrame = FALSE;
+ }
+ FDKmemclear(qcOutChannel[ch]->sfbEnFacLd, MAX_GROUPED_SFB*sizeof(FIXP_DBL));
+ }
+
+ if (usePatchTool==0) {
+ return; /* tool is disabled */
+ }
+
+ for (ch=0; ch<nChannels; ch++) {
+
+ PSY_OUT_CHANNEL *psyOutChan = psyOutChannel[ch];
+
+ if (noShortWindowInFrame) { /* retain energy ratio between blocks of different length */
+
+ FIXP_DBL nrgSum14, nrgSum12, nrgSum34, nrgTotal;
+ FIXP_DBL nrgFacLd_14, nrgFacLd_12, nrgFacLd_34;
+ INT usePatch, exePatch;
+ int sfb, nLinesSum = 0;
+
+ nrgSum14 = nrgSum12 = nrgSum34 = nrgTotal = FL2FXCONST_DBL(0.f);
+
+ /* calculate flatness of audible spectrum, i.e. spectrum above masking threshold. */
+ for (sfb = 0; sfb < psyOutChan->sfbCnt; sfb++) {
+
+ FIXP_DBL nrgFac12 = CalcInvLdData(psyOutChan->sfbEnergyLdData[sfb]>>1); /* nrg^(1/2) */
+ FIXP_DBL nrgFac14 = CalcInvLdData(psyOutChan->sfbEnergyLdData[sfb]>>2); /* nrg^(1/4) */
+
+ /* maximal number of bands is 64, results scaling factor 6 */
+ nLinesSum += peData->peChannelData[ch].sfbNLines[sfb]; /* relevant lines */
+ nrgTotal += ( psyOutChan->sfbEnergy[sfb] >> 6 ); /* sum up nrg */
+ nrgSum12 += ( nrgFac12 >> 6 ); /* sum up nrg^(2/4) */
+ nrgSum14 += ( nrgFac14 >> 6 ); /* sum up nrg^(1/4) */
+ nrgSum34 += ( fMult(nrgFac14, nrgFac12) >> 6 ); /* sum up nrg^(3/4) */
+ }
+
+ nrgTotal = CalcLdData(nrgTotal); /* get ld64 of total nrg */
+
+ nrgFacLd_14 = CalcLdData(nrgSum14) - nrgTotal; /* ld64(nrgSum14/nrgTotal) */
+ nrgFacLd_12 = CalcLdData(nrgSum12) - nrgTotal; /* ld64(nrgSum12/nrgTotal) */
+ nrgFacLd_34 = CalcLdData(nrgSum34) - nrgTotal; /* ld64(nrgSum34/nrgTotal) */
+
+ adjThrStateElement->chaosMeasureEnFac[ch] = FDKmax( FL2FXCONST_DBL(0.1875f), fDivNorm(nLinesSum,psyOutChan->sfbOffsets[psyOutChan->sfbCnt]) );
+
+ usePatch = (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.78125f));
+ exePatch = ((usePatch) && (adjThrStateElement->lastEnFacPatch[ch]));
+
+ for (sfb = 0; sfb < psyOutChan->sfbCnt; sfb++) {
+ INT sfbExePatch;
+
+ /* for MS coupled SFBs, also execute patch in side channel if done in mid channel */
+ if ((ch == 1) && (toolsInfo->msMask[sfb])) {
+ sfbExePatch = exePatchM;
+ }
+ else {
+ sfbExePatch = exePatch;
+ }
+
+ if ( (sfbExePatch) && (psyOutChan->sfbEnergy[sfb]>FL2FXCONST_DBL(0.f)) )
+ {
+ /* execute patch based on spectral flatness calculated above */
+ if (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.8125f)) {
+ qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_14 + (psyOutChan->sfbEnergyLdData[sfb]+(psyOutChan->sfbEnergyLdData[sfb]>>1)))>>1 ); /* sfbEnergy^(3/4) */
+ }
+ else if (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.796875f)) {
+ qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_12 + psyOutChan->sfbEnergyLdData[sfb])>>1 ); /* sfbEnergy^(2/4) */
+ }
+ else {
+ qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_34 + (psyOutChan->sfbEnergyLdData[sfb]>>1))>>1 ); /* sfbEnergy^(1/4) */
+ }
+ qcOutChannel[ch]->sfbEnFacLd[sfb] = fixMin(qcOutChannel[ch]->sfbEnFacLd[sfb],(FIXP_DBL)0);
+
+ }
+ } /* sfb loop */
+
+ adjThrStateElement->lastEnFacPatch[ch] = usePatch;
+ exePatchM = exePatch;
+ }
+ else {
+ /* !noShortWindowInFrame */
+ adjThrStateElement->chaosMeasureEnFac[ch] = FL2FXCONST_DBL(0.75f);
+ adjThrStateElement->lastEnFacPatch[ch] = TRUE; /* allow use of sfbEnFac patch in upcoming frame */
+ }
+
+ } /* ch loop */
+
+}
+
+
+
+
+/*****************************************************************************
+functionname: FDKaacEnc_calcPe
+description: calculate pe for both channels
+*****************************************************************************/
+static
+void FDKaacEnc_calcPe(PSY_OUT_CHANNEL* psyOutChannel[(2)],
+ QC_OUT_CHANNEL* qcOutChannel[(2)],
+ PE_DATA *peData,
+ const INT nChannels)
+{
+ INT ch;
+
+ peData->pe = peData->offset;
+ peData->constPart = 0;
+ peData->nActiveLines = 0;
+ for(ch=0; ch<nChannels; ch++) {
+ PE_CHANNEL_DATA *peChanData = &peData->peChannelData[ch];
+ FDKaacEnc_calcSfbPe(&peData->peChannelData[ch],
+ qcOutChannel[ch]->sfbWeightedEnergyLdData,
+ qcOutChannel[ch]->sfbThresholdLdData,
+ psyOutChannel[ch]->sfbCnt,
+ psyOutChannel[ch]->sfbPerGroup,
+ psyOutChannel[ch]->maxSfbPerGroup,
+ psyOutChannel[ch]->isBook,
+ psyOutChannel[ch]->isScale);
+
+ peData->pe += peChanData->pe;
+ peData->constPart += peChanData->constPart;
+ peData->nActiveLines += peChanData->nActiveLines;
+ }
+}
+
+void FDKaacEnc_peCalculation(PE_DATA *peData,
+ PSY_OUT_CHANNEL* psyOutChannel[(2)],
+ QC_OUT_CHANNEL* qcOutChannel[(2)],
+ struct TOOLSINFO *toolsInfo,
+ ATS_ELEMENT* adjThrStateElement,
+ const INT nChannels)
+{
+ /* constants that will not change during successive pe calculations */
+ FDKaacEnc_preparePe(peData, psyOutChannel, qcOutChannel, nChannels, adjThrStateElement->peOffset);
+
+ /* calculate weighting factor for threshold adjustment */
+ FDKaacEnc_calcWeighting(peData, psyOutChannel, qcOutChannel, toolsInfo, adjThrStateElement, nChannels, 1);
+{
+ /* no weighting of threholds and energies for mlout */
+ /* weight energies and thresholds */
+ int ch;
+ for (ch=0; ch<nChannels; ch++) {
+
+ int sfb, sfbGrp;
+ QC_OUT_CHANNEL* pQcOutCh = qcOutChannel[ch];
+
+ for (sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) {
+ for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+ pQcOutCh->sfbWeightedEnergyLdData[sfb+sfbGrp] = pQcOutCh->sfbEnergyLdData[sfb+sfbGrp] - pQcOutCh->sfbEnFacLd[sfb+sfbGrp];
+ pQcOutCh->sfbThresholdLdData[sfb+sfbGrp] -= pQcOutCh->sfbEnFacLd[sfb+sfbGrp];
+ }
+ }
+ }
+}
+
+ /* pe without reduction */
+ FDKaacEnc_calcPe(psyOutChannel, qcOutChannel, peData, nChannels);
+}
+
+
+
+/*****************************************************************************
+functionname: FDKaacEnc_FDKaacEnc_calcPeNoAH
+description: sum the pe data only for bands where avoid hole is inactive
+*****************************************************************************/
+static void FDKaacEnc_FDKaacEnc_calcPeNoAH(INT *pe,
+ INT *constPart,
+ INT *nActiveLines,
+ PE_DATA *peData,
+ UCHAR ahFlag[(2)][MAX_GROUPED_SFB],
+ PSY_OUT_CHANNEL* psyOutChannel[(2)],
+ const INT nChannels)
+{
+ INT ch, sfb,sfbGrp;
+
+ INT pe_tmp = peData->offset;
+ INT constPart_tmp = 0;
+ INT nActiveLines_tmp = 0;
+ for(ch=0; ch<nChannels; ch++) {
+ PE_CHANNEL_DATA *peChanData = &peData->peChannelData[ch];
+ for(sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup){
+ for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+ if(ahFlag[ch][sfbGrp+sfb] < AH_ACTIVE) {
+ pe_tmp += peChanData->sfbPe[sfbGrp+sfb];
+ constPart_tmp += peChanData->sfbConstPart[sfbGrp+sfb];
+ nActiveLines_tmp += peChanData->sfbNActiveLines[sfbGrp+sfb];
+ }
+ }
+ }
+ }
+ /* correct scaled pe and constPart values */
+ *pe = pe_tmp >> PE_CONSTPART_SHIFT;
+ *constPart = constPart_tmp >> PE_CONSTPART_SHIFT;
+
+ *nActiveLines = nActiveLines_tmp;
+}
+
+
+/*****************************************************************************
+functionname: FDKaacEnc_reduceThresholdsCBR
+description: apply reduction formula
+*****************************************************************************/
+static const FIXP_DBL limitThrReducedLdData = (FIXP_DBL)0x00008000; /*FL2FXCONST_DBL(FDKpow(2.0,-LD_DATA_SCALING/4.0));*/
+
+static void FDKaacEnc_reduceThresholdsCBR(QC_OUT_CHANNEL* qcOutChannel[(2)],
+ PSY_OUT_CHANNEL* psyOutChannel[(2)],
+ UCHAR ahFlag[(2)][MAX_GROUPED_SFB],
+ FIXP_DBL thrExp[(2)][MAX_GROUPED_SFB],
+ const INT nChannels,
+ const FIXP_DBL redVal,
+ const SCHAR redValScaling)
+{
+ INT ch, sfb, sfbGrp;
+ FIXP_DBL sfbEnLdData, sfbThrLdData, sfbThrReducedLdData;
+ FIXP_DBL sfbThrExp;
+
+ for(ch=0; ch<nChannels; ch++) {
+ QC_OUT_CHANNEL *qcOutChan = qcOutChannel[ch];
+ for(sfbGrp = 0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+= psyOutChannel[ch]->sfbPerGroup){
+ for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+ sfbEnLdData = qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb];
+ sfbThrLdData = qcOutChan->sfbThresholdLdData[sfbGrp+sfb];
+ sfbThrExp = thrExp[ch][sfbGrp+sfb];
+ if ((sfbEnLdData > sfbThrLdData) && (ahFlag[ch][sfbGrp+sfb] != AH_ACTIVE)) {
+
+ /* threshold reduction formula:
+ float tmp = thrExp[ch][sfb]+redVal;
+ tmp *= tmp;
+ sfbThrReduced = tmp*tmp;
+ */
+ int minScale = fixMin(CountLeadingBits(sfbThrExp), CountLeadingBits(redVal) - (DFRACT_BITS-1-redValScaling) )-1;
+
+ /* 4*log( sfbThrExp + redVal ) */
+ sfbThrReducedLdData = CalcLdData(fAbs(scaleValue(sfbThrExp, minScale) + scaleValue(redVal,(DFRACT_BITS-1-redValScaling)+minScale)))
+ - (FIXP_DBL)(minScale<<(DFRACT_BITS-1-LD_DATA_SHIFT));
+ sfbThrReducedLdData <<= 2;
+
+ /* avoid holes */
+ if ( ((sfbThrReducedLdData - sfbEnLdData) > qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] )
+ && (ahFlag[ch][sfbGrp+sfb] != NO_AH) )
+ {
+ if (qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] > (FL2FXCONST_DBL(-1.0f) - sfbEnLdData) ){
+ sfbThrReducedLdData = fixMax((qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + sfbEnLdData), sfbThrLdData);
+ }
+ else sfbThrReducedLdData = sfbThrLdData;
+ ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE;
+ }
+
+ /* minimum of 29 dB Ratio for Thresholds */
+ if ((sfbEnLdData+(FIXP_DBL)MAXVAL_DBL) > FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING)){
+ sfbThrReducedLdData = fixMax(sfbThrReducedLdData, (sfbEnLdData - FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING)));
+ }
+
+ qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = sfbThrReducedLdData;
+ }
+ }
+ }
+ }
+}
+
+/* similar to prepareSfbPe1() */
+static FIXP_DBL FDKaacEnc_calcChaosMeasure(PSY_OUT_CHANNEL *psyOutChannel,
+ const FIXP_DBL *sfbFormFactorLdData)
+{
+ #define SCALE_FORM_FAC (4) /* (SCALE_FORM_FAC+FORM_FAC_SHIFT) >= ld(FRAME_LENGTH)*/
+ #define SCALE_NRGS (8)
+ #define SCALE_NLINES (16)
+ #define SCALE_NRGS_SQRT4 (2) /* 0.25 * SCALE_NRGS */
+ #define SCALE_NLINES_P34 (12) /* 0.75 * SCALE_NLINES */
+
+ INT sfbGrp, sfb;
+ FIXP_DBL chaosMeasure;
+ INT frameNLines = 0;
+ FIXP_DBL frameFormFactor = FL2FXCONST_DBL(0.f);
+ FIXP_DBL frameEnergy = FL2FXCONST_DBL(0.f);
+
+ for (sfbGrp=0; sfbGrp<psyOutChannel->sfbCnt; sfbGrp+=psyOutChannel->sfbPerGroup) {
+ for (sfb=0; sfb<psyOutChannel->maxSfbPerGroup; sfb++){
+ if (psyOutChannel->sfbEnergyLdData[sfbGrp+sfb] > psyOutChannel->sfbThresholdLdData[sfbGrp+sfb]) {
+ frameFormFactor += (CalcInvLdData(sfbFormFactorLdData[sfbGrp+sfb])>>SCALE_FORM_FAC);
+ frameNLines += (psyOutChannel->sfbOffsets[sfbGrp+sfb+1] - psyOutChannel->sfbOffsets[sfbGrp+sfb]);
+ frameEnergy += (psyOutChannel->sfbEnergy[sfbGrp+sfb]>>SCALE_NRGS);
+ }
+ }
+ }
+
+ if(frameNLines > 0){
+
+ /* frameNActiveLines = frameFormFactor*2^FORM_FAC_SHIFT * ((frameEnergy *2^SCALE_NRGS)/frameNLines)^-0.25
+ chaosMeasure = frameNActiveLines / frameNLines */
+ chaosMeasure =
+ CalcInvLdData( (((CalcLdData(frameFormFactor)>>1) -
+ (CalcLdData(frameEnergy)>>(2+1))) -
+ (fMultDiv2(FL2FXCONST_DBL(0.75f),CalcLdData((FIXP_DBL)frameNLines<<(DFRACT_BITS-1-SCALE_NLINES))) -
+ (((FIXP_DBL)(SCALE_FORM_FAC-SCALE_NRGS_SQRT4+FORM_FAC_SHIFT-(SCALE_NLINES_P34))<<(DFRACT_BITS-1-LD_DATA_SHIFT))>>1))
+ )<<1 );
+ } else {
+
+ /* assuming total chaos, if no sfb is above thresholds */
+ chaosMeasure = FL2FXCONST_DBL(1.f);
+ }
+
+ return chaosMeasure;
+}
+
+
+/* apply reduction formula for VBR-mode */
+static void FDKaacEnc_reduceThresholdsVBR(QC_OUT_CHANNEL* qcOutChannel[(2)],
+ PSY_OUT_CHANNEL* psyOutChannel[(2)],
+ UCHAR ahFlag[(2)][MAX_GROUPED_SFB],
+ FIXP_DBL thrExp[(2)][MAX_GROUPED_SFB],
+ const INT nChannels,
+ const FIXP_DBL vbrQualFactor,
+ FIXP_DBL* chaosMeasureOld)
+{
+ INT ch, sfbGrp, sfb;
+ FIXP_DBL chGroupEnergy[TRANS_FAC][2];/*energy for each group and channel*/
+ FIXP_DBL chChaosMeasure[2];
+ FIXP_DBL frameEnergy = FL2FXCONST_DBL(1e-10f);
+ FIXP_DBL chaosMeasure = FL2FXCONST_DBL(0.f);
+ FIXP_DBL sfbEnLdData, sfbThrLdData, sfbThrExp;
+ FIXP_DBL sfbThrReducedLdData;
+ FIXP_DBL chaosMeasureAvg;
+ INT groupCnt; /* loop counter */
+ FIXP_DBL redVal[TRANS_FAC]; /* reduction values; in short-block case one redVal for each group */
+ QC_OUT_CHANNEL *qcOutChan = NULL;
+ PSY_OUT_CHANNEL *psyOutChan = NULL;
+
+#define SCALE_GROUP_ENERGY (8)
+
+#define CONST_CHAOS_MEAS_AVG_FAC_0 (FL2FXCONST_DBL(0.25f))
+#define CONST_CHAOS_MEAS_AVG_FAC_1 (FL2FXCONST_DBL(1.f-0.25f))
+
+#define MIN_LDTHRESH (FL2FXCONST_DBL(-0.515625f))
+
+
+ for(ch=0; ch<nChannels; ch++){
+ qcOutChan = qcOutChannel[ch];
+ psyOutChan = psyOutChannel[ch];
+
+ /* adding up energy for each channel and each group separately */
+ FIXP_DBL chEnergy = FL2FXCONST_DBL(0.f);
+ groupCnt=0;
+
+ for (sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup, groupCnt++) {
+ chGroupEnergy[groupCnt][ch] = FL2FXCONST_DBL(0.f);
+ for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++){
+ chGroupEnergy[groupCnt][ch] += (psyOutChan->sfbEnergy[sfbGrp+sfb]>>SCALE_GROUP_ENERGY);
+ }
+ chEnergy += chGroupEnergy[groupCnt][ch];
+ }
+ frameEnergy += chEnergy;
+
+ /* chaosMeasure */
+ if (psyOutChannel[0]->lastWindowSequence == SHORT_WINDOW) {
+ chChaosMeasure[ch] = FL2FXCONST_DBL(0.5f); /* assume a constant chaos measure of 0.5f for short blocks */
+ } else {
+ chChaosMeasure[ch] = FDKaacEnc_calcChaosMeasure(psyOutChannel[ch], qcOutChannel[ch]->sfbFormFactorLdData);
+ }
+ chaosMeasure += fMult(chChaosMeasure[ch], chEnergy);
+ }
+
+ if(frameEnergy > chaosMeasure) {
+ INT scale = CntLeadingZeros(frameEnergy) - 1;
+ FIXP_DBL num = chaosMeasure<<scale;
+ FIXP_DBL denum = frameEnergy<<scale;
+ chaosMeasure = schur_div(num,denum,16);
+ }
+ else {
+ chaosMeasure = FL2FXCONST_DBL(1.f);
+ }
+
+ chaosMeasureAvg = fMult(CONST_CHAOS_MEAS_AVG_FAC_0, chaosMeasure) +
+ fMult(CONST_CHAOS_MEAS_AVG_FAC_1, *chaosMeasureOld); /* averaging chaos measure */
+ *chaosMeasureOld = chaosMeasure = (fixMin(chaosMeasure, chaosMeasureAvg)); /* use min-value, safe for next frame */
+
+ /* characteristic curve
+ chaosMeasure = 0.2f + 0.7f/0.3f * (chaosMeasure - 0.2f);
+ chaosMeasure = fixMin(1.0f, fixMax(0.1f, chaosMeasure));
+ constants scaled by 4.f
+ */
+ chaosMeasure = ((FL2FXCONST_DBL(0.2f)>>2) + fMult(FL2FXCONST_DBL(0.7f/(4.f*0.3f)), (chaosMeasure - FL2FXCONST_DBL(0.2f))));
+ chaosMeasure = (fixMin((FIXP_DBL)(FL2FXCONST_DBL(1.0f)>>2), fixMax((FIXP_DBL)(FL2FXCONST_DBL(0.1f)>>2), chaosMeasure)))<<2;
+
+ /* calculation of reduction value */
+ if (psyOutChannel[0]->lastWindowSequence == SHORT_WINDOW){ /* short-blocks */
+ FDK_ASSERT(TRANS_FAC==8);
+ #define WIN_TYPE_SCALE (3)
+
+ INT sfbGrp, groupCnt=0;
+ for (sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup,groupCnt++) {
+
+ FIXP_DBL groupEnergy = FL2FXCONST_DBL(0.f);
+
+ for(ch=0;ch<nChannels;ch++){
+ groupEnergy += chGroupEnergy[groupCnt][ch]; /* adding up the channels groupEnergy */
+ }
+
+ FDK_ASSERT(psyOutChannel[0]->groupLen[groupCnt]<=INV_INT_TAB_SIZE);
+ groupEnergy = fMult(groupEnergy,invInt[psyOutChannel[0]->groupLen[groupCnt]]); /* correction of group energy */
+ groupEnergy = fixMin(groupEnergy, frameEnergy>>WIN_TYPE_SCALE); /* do not allow an higher redVal as calculated framewise */
+
+ groupEnergy>>=2; /* 2*WIN_TYPE_SCALE = 6 => 6+2 = 8 ==> 8/4 = int number */
+
+ redVal[groupCnt] = fMult(fMult(vbrQualFactor,chaosMeasure),
+ CalcInvLdData(CalcLdData(groupEnergy)>>2) )
+ << (int)( ( 2 + (2*WIN_TYPE_SCALE) + SCALE_GROUP_ENERGY )>>2 ) ;
+
+ }
+ } else { /* long-block */
+
+ redVal[0] = fMult( fMult(vbrQualFactor,chaosMeasure),
+ CalcInvLdData(CalcLdData(frameEnergy)>>2) )
+ << (int)( SCALE_GROUP_ENERGY>>2 ) ;
+ }
+
+ for(ch=0; ch<nChannels; ch++) {
+ qcOutChan = qcOutChannel[ch];
+ psyOutChan = psyOutChannel[ch];
+
+ for (sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup) {
+ for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++){
+
+ sfbEnLdData = (qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb]);
+ sfbThrLdData = (qcOutChan->sfbThresholdLdData[sfbGrp+sfb]);
+ sfbThrExp = thrExp[ch][sfbGrp+sfb];
+
+ if ( (sfbThrLdData>=MIN_LDTHRESH) && (sfbEnLdData > sfbThrLdData) && (ahFlag[ch][sfbGrp+sfb] != AH_ACTIVE)) {
+
+ /* Short-Window */
+ if (psyOutChannel[ch]->lastWindowSequence == SHORT_WINDOW) {
+ const int groupNumber = (int) sfb/psyOutChan->sfbPerGroup;
+
+ FDK_ASSERT(INV_SQRT4_TAB_SIZE>psyOutChan->groupLen[groupNumber]);
+
+ sfbThrExp = fMult(sfbThrExp, fMult( FL2FXCONST_DBL(2.82f/4.f), invSqrt4[psyOutChan->groupLen[groupNumber]]))<<2 ;
+
+ if ( sfbThrExp <= (limitThrReducedLdData-redVal[groupNumber]) ) {
+ sfbThrReducedLdData = FL2FXCONST_DBL(-1.0f);
+ }
+ else {
+ if ((FIXP_DBL)redVal[groupNumber] >= FL2FXCONST_DBL(1.0f)-sfbThrExp)
+ sfbThrReducedLdData = FL2FXCONST_DBL(0.0f);
+ else {
+ /* threshold reduction formula */
+ sfbThrReducedLdData = CalcLdData(sfbThrExp + redVal[groupNumber]);
+ sfbThrReducedLdData <<= 2;
+ }
+ }
+ sfbThrReducedLdData += ( CalcLdInt(psyOutChan->groupLen[groupNumber]) -
+ ((FIXP_DBL)6<<(DFRACT_BITS-1-LD_DATA_SHIFT)) );
+ }
+
+ /* Long-Window */
+ else {
+ if ((FIXP_DBL)redVal[0] >= FL2FXCONST_DBL(1.0f)-sfbThrExp) {
+ sfbThrReducedLdData = FL2FXCONST_DBL(0.0f);
+ }
+ else {
+ /* threshold reduction formula */
+ sfbThrReducedLdData = CalcLdData(sfbThrExp + redVal[0]);
+ sfbThrReducedLdData <<= 2;
+ }
+ }
+
+ /* avoid holes */
+ if ( ((sfbThrReducedLdData - sfbEnLdData) > qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] )
+ && (ahFlag[ch][sfbGrp+sfb] != NO_AH) )
+ {
+ if (qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] > (FL2FXCONST_DBL(-1.0f) - sfbEnLdData) ){
+ sfbThrReducedLdData = fixMax((qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + sfbEnLdData), sfbThrLdData);
+ }
+ else sfbThrReducedLdData = sfbThrLdData;
+ ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE;
+ }
+
+ if (sfbThrReducedLdData<FL2FXCONST_DBL(-0.5f))
+ sfbThrReducedLdData = FL2FXCONST_DBL(-1.f);
+
+ /* minimum of 29 dB Ratio for Thresholds */
+ if ((sfbEnLdData+FL2FXCONST_DBL(1.0f)) > FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING)){
+ sfbThrReducedLdData = fixMax(sfbThrReducedLdData, sfbEnLdData - FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING));
+ }
+
+ sfbThrReducedLdData = fixMax(MIN_LDTHRESH,sfbThrReducedLdData);
+
+ qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = sfbThrReducedLdData;
+ }
+ }
+ }
+ }
+}
+
+
+/*****************************************************************************
+functionname: FDKaacEnc_correctThresh
+description: if pe difference deltaPe between desired pe and real pe is small enough,
+the difference can be distributed among the scale factor bands.
+New thresholds can be derived from this pe-difference
+*****************************************************************************/
+static void FDKaacEnc_correctThresh(CHANNEL_MAPPING* cm,
+ QC_OUT_ELEMENT* qcElement[(6)],
+ PSY_OUT_ELEMENT* psyOutElement[(6)],
+ UCHAR ahFlag[(6)][(2)][MAX_GROUPED_SFB],
+ FIXP_DBL thrExp[(6)][(2)][MAX_GROUPED_SFB],
+ const FIXP_DBL redVal[(6)],
+ const SCHAR redValScaling[(6)],
+ const INT deltaPe,
+ const INT processElements,
+ const INT elementOffset)
+{
+ INT ch, sfb, sfbGrp;
+ QC_OUT_CHANNEL *qcOutChan;
+ PSY_OUT_CHANNEL *psyOutChan;
+ PE_CHANNEL_DATA *peChanData;
+ FIXP_DBL thrFactorLdData;
+ FIXP_DBL sfbEnLdData, sfbThrLdData, sfbThrReducedLdData;
+ FIXP_DBL *sfbPeFactorsLdData[(6)][(2)];
+ FIXP_DBL sfbNActiveLinesLdData[(2)][MAX_GROUPED_SFB];
+ INT normFactorInt;
+ FIXP_DBL normFactorLdData;
+
+ INT nElements = elementOffset+processElements;
+ INT elementId;
+
+ /* scratch is empty; use temporal memory from quantSpec in QC_OUT_CHANNEL */
+ for(elementId=elementOffset;elementId<nElements;elementId++) {
+ for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
+ SHORT* ptr = qcElement[elementId]->qcOutChannel[ch]->quantSpec;
+ sfbPeFactorsLdData[elementId][ch] = (FIXP_DBL*)ptr;
+ }
+ }
+
+ /* for each sfb calc relative factors for pe changes */
+ normFactorInt = 0;
+
+ for(elementId=elementOffset;elementId<nElements;elementId++) {
+ if (cm->elInfo[elementId].elType != ID_DSE) {
+
+ for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
+
+ qcOutChan = qcElement[elementId]->qcOutChannel[ch];
+ psyOutChan = psyOutElement[elementId]->psyOutChannel[ch];
+ peChanData = &qcElement[elementId]->peData.peChannelData[ch];
+
+ for(sfbGrp = 0; sfbGrp < psyOutChan->sfbCnt; sfbGrp+= psyOutChan->sfbPerGroup){
+ for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
+
+ if ( peChanData->sfbNActiveLines[sfbGrp+sfb] == 0 ) {
+ sfbNActiveLinesLdData[ch][sfbGrp+sfb] = FL2FXCONST_DBL(-1.0f);
+ }
+ else {
+ /* Both CalcLdInt and CalcLdData can be used!
+ * No offset has to be subtracted, because sfbNActiveLinesLdData
+ * is shorted while thrFactor calculation */
+ sfbNActiveLinesLdData[ch][sfbGrp+sfb] = CalcLdInt(peChanData->sfbNActiveLines[sfbGrp+sfb]);
+ }
+ if ( ((ahFlag[elementId][ch][sfbGrp+sfb] < AH_ACTIVE) || (deltaPe > 0)) &&
+ peChanData->sfbNActiveLines[sfbGrp+sfb] != 0 )
+ {
+ if (thrExp[elementId][ch][sfbGrp+sfb] > -redVal[elementId]) {
+
+ /* sfbPeFactors[ch][sfbGrp+sfb] = peChanData->sfbNActiveLines[sfbGrp+sfb] /
+ (thrExp[elementId][ch][sfbGrp+sfb] + redVal[elementId]); */
+
+ int minScale = fixMin(CountLeadingBits(thrExp[elementId][ch][sfbGrp+sfb]), CountLeadingBits(redVal[elementId]) - (DFRACT_BITS-1-redValScaling[elementId]) ) - 1;
+
+ /* sumld = ld64( sfbThrExp + redVal ) */
+ FIXP_DBL sumLd = CalcLdData(scaleValue(thrExp[elementId][ch][sfbGrp+sfb], minScale) + scaleValue(redVal[elementId], (DFRACT_BITS-1-redValScaling[elementId])+minScale))
+ - (FIXP_DBL)(minScale<<(DFRACT_BITS-1-LD_DATA_SHIFT));
+
+ if (sumLd < FL2FXCONST_DBL(0.f)) {
+ sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb] - sumLd;
+ }
+ else {
+ if ( sfbNActiveLinesLdData[ch][sfbGrp+sfb] > (FL2FXCONST_DBL(-1.f) + sumLd) ) {
+ sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb] - sumLd;
+ }
+ else {
+ sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb];
+ }
+ }
+
+ normFactorInt += (INT)CalcInvLdData(sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb]);
+ }
+ else sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = FL2FXCONST_DBL(1.0f);
+ }
+ else sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = FL2FXCONST_DBL(-1.0f);
+ }
+ }
+ }
+ }
+ }
+
+ /* normFactorLdData = ld64(deltaPe/normFactorInt) */
+ normFactorLdData = CalcLdData((FIXP_DBL)((deltaPe<0) ? (-deltaPe) : (deltaPe))) - CalcLdData((FIXP_DBL)normFactorInt);
+
+ /* distribute the pe difference to the scalefactors
+ and calculate the according thresholds */
+ for(elementId=elementOffset;elementId<nElements;elementId++) {
+ if (cm->elInfo[elementId].elType != ID_DSE) {
+
+ for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
+ qcOutChan = qcElement[elementId]->qcOutChannel[ch];
+ psyOutChan = psyOutElement[elementId]->psyOutChannel[ch];
+ peChanData = &qcElement[elementId]->peData.peChannelData[ch];
+
+ for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
+ for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
+
+ if (peChanData->sfbNActiveLines[sfbGrp+sfb] > 0) {
+
+ /* pe difference for this sfb */
+ if ( (sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb]==FL2FXCONST_DBL(-1.0f)) ||
+ (deltaPe==0) )
+ {
+ thrFactorLdData = FL2FXCONST_DBL(0.f);
+ }
+ else {
+ /* new threshold */
+ FIXP_DBL tmp = CalcInvLdData(sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] + normFactorLdData - sfbNActiveLinesLdData[ch][sfbGrp+sfb] - FL2FXCONST_DBL((float)LD_DATA_SHIFT/LD_DATA_SCALING));
+
+ /* limit thrFactor to 60dB */
+ tmp = (deltaPe<0) ? tmp : (-tmp);
+ thrFactorLdData = FDKmin(tmp, FL2FXCONST_DBL(20.f/LD_DATA_SCALING));
+ }
+
+ /* new threshold */
+ sfbThrLdData = qcOutChan->sfbThresholdLdData[sfbGrp+sfb];
+ sfbEnLdData = qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb];
+
+ if (thrFactorLdData < FL2FXCONST_DBL(0.f)) {
+ if( sfbThrLdData > (FL2FXCONST_DBL(-1.f)-thrFactorLdData) ) {
+ sfbThrReducedLdData = sfbThrLdData + thrFactorLdData;
+ }
+ else {
+ sfbThrReducedLdData = FL2FXCONST_DBL(-1.f);
+ }
+ }
+ else{
+ sfbThrReducedLdData = sfbThrLdData + thrFactorLdData;
+ }
+
+ /* avoid hole */
+ if ( (sfbThrReducedLdData - sfbEnLdData > qcOutChan->sfbMinSnrLdData[sfbGrp+sfb]) &&
+ (ahFlag[elementId][ch][sfbGrp+sfb] == AH_INACTIVE) )
+ {
+ /* sfbThrReduced = max(psyOutChan[ch]->sfbMinSnr[i] * sfbEn, sfbThr); */
+ if ( sfbEnLdData > (sfbThrLdData-qcOutChan->sfbMinSnrLdData[sfbGrp+sfb]) ) {
+ sfbThrReducedLdData = qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + sfbEnLdData;
+ }
+ else {
+ sfbThrReducedLdData = sfbThrLdData;
+ }
+ ahFlag[elementId][ch][sfbGrp+sfb] = AH_ACTIVE;
+ }
+
+ qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = sfbThrReducedLdData;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/*****************************************************************************
+ functionname: FDKaacEnc_reduceMinSnr
+ description: if the desired pe can not be reached, reduce pe by
+ reducing minSnr
+*****************************************************************************/
+void FDKaacEnc_reduceMinSnr(CHANNEL_MAPPING* cm,
+ QC_OUT_ELEMENT* qcElement[(6)],
+ PSY_OUT_ELEMENT* psyOutElement[(6)],
+ UCHAR ahFlag[(6)][(2)][MAX_GROUPED_SFB],
+ const INT desiredPe,
+ INT* redPeGlobal,
+ const INT processElements,
+ const INT elementOffset)
+
+{
+ INT elementId;
+ INT nElements = elementOffset+processElements;
+
+ INT newGlobalPe = *redPeGlobal;
+
+ for(elementId=elementOffset;elementId<nElements;elementId++) {
+ if (cm->elInfo[elementId].elType != ID_DSE) {
+ INT ch;
+ INT maxSfbPerGroup[2];
+ INT sfbCnt[2];
+ INT sfbPerGroup[2];
+
+ for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
+ maxSfbPerGroup[ch] = psyOutElement[elementId]->psyOutChannel[ch]->maxSfbPerGroup-1;
+ sfbCnt[ch] = psyOutElement[elementId]->psyOutChannel[ch]->sfbCnt;
+ sfbPerGroup[ch] = psyOutElement[elementId]->psyOutChannel[ch]->sfbPerGroup;
+ }
+
+ PE_DATA *peData = &qcElement[elementId]->peData;
+
+ do
+ {
+ for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
+
+ INT sfb, sfbGrp;
+ QC_OUT_CHANNEL *qcOutChan = qcElement[elementId]->qcOutChannel[ch];
+ INT noReduction = 1;
+
+ if (maxSfbPerGroup[ch]>=0) { /* sfb in next channel */
+ INT deltaPe = 0;
+ sfb = maxSfbPerGroup[ch]--;
+ noReduction = 0;
+
+ for (sfbGrp = 0; sfbGrp < sfbCnt[ch]; sfbGrp += sfbPerGroup[ch]) {
+
+ if (ahFlag[elementId][ch][sfbGrp+sfb] != NO_AH &&
+ qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] < SnrLdFac)
+ {
+ /* increase threshold to new minSnr of 1dB */
+ qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] = SnrLdFac;
+
+ /* sfbThrReduced = max(psyOutChan[ch]->sfbMinSnr[i] * sfbEn, sfbThr); */
+ if ( qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb] >= qcOutChan->sfbThresholdLdData[sfbGrp+sfb] - qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] ) {
+
+ qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb] + qcOutChan->sfbMinSnrLdData[sfbGrp+sfb];
+
+ /* calc new pe */
+ /* C2 + C3*ld(1/0.8) = 1.5 */
+ deltaPe -= (peData->peChannelData[ch].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT);
+
+ /* sfbPe = 1.5 * sfbNLines */
+ peData->peChannelData[ch].sfbPe[sfbGrp+sfb] = (3*peData->peChannelData[ch].sfbNLines[sfbGrp+sfb]) << (PE_CONSTPART_SHIFT-1);
+ deltaPe += (peData->peChannelData[ch].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT);
+ }
+ }
+
+ } /* sfbGrp loop */
+
+ peData->pe += deltaPe;
+ peData->peChannelData[ch].pe += deltaPe;
+ newGlobalPe += deltaPe;
+
+ /* stop if enough has been saved */
+ if (peData->pe <= desiredPe) {
+ goto bail;
+ }
+
+ } /* sfb > 0 */
+
+ if ( (ch==(cm->elInfo[elementId].nChannelsInEl-1)) && noReduction ) {
+ goto bail;
+ }
+
+ } /* ch loop */
+
+ } while ( peData->pe > desiredPe);
+
+ } /* != ID_DSE */
+ } /* element loop */
+
+
+bail:
+ /* update global PE */
+ *redPeGlobal = newGlobalPe;
+}
+
+
+/*****************************************************************************
+ functionname: FDKaacEnc_allowMoreHoles
+ description: if the desired pe can not be reached, some more scalefactor
+ bands have to be quantized to zero
+*****************************************************************************/
+static void FDKaacEnc_allowMoreHoles(CHANNEL_MAPPING* cm,
+ QC_OUT_ELEMENT* qcElement[(6)],
+ PSY_OUT_ELEMENT* psyOutElement[(6)],
+ ATS_ELEMENT* AdjThrStateElement[(6)],
+ UCHAR ahFlag[(6)][(2)][MAX_GROUPED_SFB],
+ const INT desiredPe,
+ const INT currentPe,
+ const int processElements,
+ const int elementOffset)
+{
+ INT elementId;
+ INT nElements = elementOffset+processElements;
+ INT actPe = currentPe;
+
+ if (actPe <= desiredPe) {
+ return; /* nothing to do */
+ }
+
+ for (elementId = elementOffset;elementId<nElements;elementId++) {
+ if (cm->elInfo[elementId].elType != ID_DSE) {
+
+ INT ch, sfb, sfbGrp;
+
+ PE_DATA *peData = &qcElement[elementId]->peData;
+ const INT nChannels = cm->elInfo[elementId].nChannelsInEl;
+
+ QC_OUT_CHANNEL* qcOutChannel[(2)] = {NULL};
+ PSY_OUT_CHANNEL* psyOutChannel[(2)] = {NULL};
+
+ for (ch=0; ch<nChannels; ch++) {
+
+ /* init pointers */
+ qcOutChannel[ch] = qcElement[elementId]->qcOutChannel[ch];
+ psyOutChannel[ch] = psyOutElement[elementId]->psyOutChannel[ch];
+
+ for(sfbGrp=0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+= psyOutChannel[ch]->sfbPerGroup) {
+ for (sfb=psyOutChannel[ch]->maxSfbPerGroup; sfb<psyOutChannel[ch]->sfbPerGroup; sfb++) {
+ peData->peChannelData[ch].sfbPe[sfbGrp+sfb] = 0;
+ }
+ }
+ }
+
+ /* for MS allow hole in the channel with less energy */
+ if ( nChannels==2 && psyOutChannel[0]->lastWindowSequence==psyOutChannel[1]->lastWindowSequence ) {
+
+ for (sfb=0; sfb<psyOutChannel[0]->maxSfbPerGroup; sfb++) {
+ for(sfbGrp=0; sfbGrp < psyOutChannel[0]->sfbCnt; sfbGrp+=psyOutChannel[0]->sfbPerGroup) {
+ if (psyOutElement[elementId]->toolsInfo.msMask[sfbGrp+sfb]) {
+ FIXP_DBL EnergyLd_L = qcOutChannel[0]->sfbWeightedEnergyLdData[sfbGrp+sfb];
+ FIXP_DBL EnergyLd_R = qcOutChannel[1]->sfbWeightedEnergyLdData[sfbGrp+sfb];
+
+ /* allow hole in side channel ? */
+ if ( (ahFlag[elementId][1][sfbGrp+sfb] != NO_AH) &&
+ (((FL2FXCONST_DBL(-0.02065512648f)>>1) + (qcOutChannel[0]->sfbMinSnrLdData[sfbGrp+sfb]>>1))
+ > ((EnergyLd_R>>1) - (EnergyLd_L>>1))) )
+ {
+ ahFlag[elementId][1][sfbGrp+sfb] = NO_AH;
+ qcOutChannel[1]->sfbThresholdLdData[sfbGrp+sfb] = FL2FXCONST_DBL(0.015625f) + EnergyLd_R;
+ actPe -= peData->peChannelData[1].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT;
+ }
+ /* allow hole in mid channel ? */
+ else if ( (ahFlag[elementId][0][sfbGrp+sfb] != NO_AH) &&
+ (((FL2FXCONST_DBL(-0.02065512648f)>>1) + (qcOutChannel[1]->sfbMinSnrLdData[sfbGrp+sfb]>>1))
+ > ((EnergyLd_L>>1) - (EnergyLd_R>>1))) )
+ {
+ ahFlag[elementId][0][sfbGrp+sfb] = NO_AH;
+ qcOutChannel[0]->sfbThresholdLdData[sfbGrp+sfb] = FL2FXCONST_DBL(0.015625f) + EnergyLd_L;
+ actPe -= peData->peChannelData[0].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT;
+ } /* if (ahFlag) */
+ } /* if MS */
+ } /* sfbGrp */
+ if (actPe <= desiredPe) {
+ return; /* stop if enough has been saved */
+ }
+ } /* sfb */
+ } /* MS possible ? */
+
+ /* more holes necessary? subsequently erase bands
+ starting with low energies */
+ INT startSfb[2];
+ FIXP_DBL avgEnLD64,minEnLD64;
+ INT ahCnt;
+ FIXP_DBL ahCntLD64;
+ INT enIdx;
+ FIXP_DBL enLD64[4];
+ FIXP_DBL avgEn;
+
+ /* do not go below startSfb */
+ for (ch=0; ch<nChannels; ch++) {
+ if (psyOutChannel[ch]->lastWindowSequence != SHORT_WINDOW)
+ startSfb[ch] = AdjThrStateElement[elementId]->ahParam.startSfbL;
+ else
+ startSfb[ch] = AdjThrStateElement[elementId]->ahParam.startSfbS;
+ }
+
+ /* calc avg and min energies of bands that avoid holes */
+ avgEn = FL2FXCONST_DBL(0.0f);
+ minEnLD64 = FL2FXCONST_DBL(0.0f);
+ ahCnt = 0;
+
+ for (ch=0; ch<nChannels; ch++) {
+
+ sfbGrp=0;
+ sfb=startSfb[ch];
+
+ do {
+ for (; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+ if ((ahFlag[elementId][ch][sfbGrp+sfb]!=NO_AH) &&
+ (qcOutChannel[ch]->sfbWeightedEnergyLdData[sfbGrp+sfb] > qcOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb])){
+ minEnLD64 = fixMin(minEnLD64,qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb]);
+ avgEn += qcOutChannel[ch]->sfbEnergy[sfbGrp+sfb] >> 6;
+ ahCnt++;
+ }
+ }
+
+ sfbGrp += psyOutChannel[ch]->sfbPerGroup;
+ sfb=0;
+
+ } while (sfbGrp < psyOutChannel[ch]->sfbCnt);
+ }
+
+ if ( (avgEn == FL2FXCONST_DBL(0.0f)) || (ahCnt == 0) ) {
+ avgEnLD64 = FL2FXCONST_DBL(0.0f);
+ }
+ else {
+ avgEnLD64 = CalcLdData(avgEn);
+ ahCntLD64 = CalcLdInt(ahCnt);
+ avgEnLD64 = avgEnLD64 + FL2FXCONST_DBL(0.09375f) - ahCntLD64; /* compensate shift with 6 */
+ }
+
+ /* calc some energy borders between minEn and avgEn */
+ /* for (enIdx=0; enIdx<4; enIdx++) */
+ /* en[enIdx] = minEn * (float)FDKpow(avgEn/(minEn+FLT_MIN), (2*enIdx+1)/7.0f); */
+ enLD64[0] = minEnLD64 + fMult((avgEnLD64-minEnLD64),FL2FXCONST_DBL(0.14285714285f));
+ enLD64[1] = minEnLD64 + fMult((avgEnLD64-minEnLD64),FL2FXCONST_DBL(0.42857142857f));
+ enLD64[2] = minEnLD64 + fMult((avgEnLD64-minEnLD64),FL2FXCONST_DBL(0.71428571428f));
+ enLD64[3] = minEnLD64 + (avgEnLD64-minEnLD64);
+
+ for (enIdx=0; enIdx<4; enIdx++) {
+ INT noReduction = 1;
+
+ INT maxSfbPerGroup[2];
+ INT sfbCnt[2];
+ INT sfbPerGroup[2];
+
+ for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
+ maxSfbPerGroup[ch] = psyOutElement[elementId]->psyOutChannel[ch]->maxSfbPerGroup-1;
+ sfbCnt[ch] = psyOutElement[elementId]->psyOutChannel[ch]->sfbCnt;
+ sfbPerGroup[ch] = psyOutElement[elementId]->psyOutChannel[ch]->sfbPerGroup;
+ }
+
+ do {
+
+ noReduction = 1;
+
+ for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
+
+ INT sfb, sfbGrp;
+
+ /* start with lowest energy border at highest sfb */
+ if (maxSfbPerGroup[ch]>=startSfb[ch]) { /* sfb in next channel */
+ sfb = maxSfbPerGroup[ch]--;
+ noReduction = 0;
+
+ for (sfbGrp = 0; sfbGrp < sfbCnt[ch]; sfbGrp += sfbPerGroup[ch]) {
+ /* sfb energy below border ? */
+ if (ahFlag[elementId][ch][sfbGrp+sfb] != NO_AH && qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb] < enLD64[enIdx]) {
+ /* allow hole */
+ ahFlag[elementId][ch][sfbGrp+sfb] = NO_AH;
+ qcOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb] = FL2FXCONST_DBL(0.015625f) + qcOutChannel[ch]->sfbWeightedEnergyLdData[sfbGrp+sfb];
+ actPe -= peData->peChannelData[ch].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT;
+ }
+ } /* sfbGrp */
+
+ if (actPe <= desiredPe) {
+ return; /* stop if enough has been saved */
+ }
+ } /* sfb > 0 */
+ } /* ch loop */
+
+ } while( (noReduction == 0) && (actPe > desiredPe) );
+
+ if (actPe <= desiredPe) {
+ return; /* stop if enough has been saved */
+ }
+
+ } /* enIdx loop */
+
+ } /* EOF DSE-suppression */
+ } /* EOF for all elements... */
+
+}
+
+/* reset avoid hole flags from AH_ACTIVE to AH_INACTIVE */
+static void FDKaacEnc_resetAHFlags( UCHAR ahFlag[(2)][MAX_GROUPED_SFB],
+ const int nChannels,
+ PSY_OUT_CHANNEL *psyOutChannel[(2)])
+{
+ int ch, sfb, sfbGrp;
+
+ for(ch=0; ch<nChannels; ch++) {
+ for (sfbGrp=0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) {
+ for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+ if ( ahFlag[ch][sfbGrp+sfb] == AH_ACTIVE) {
+ ahFlag[ch][sfbGrp+sfb] = AH_INACTIVE;
+ }
+ }
+ }
+ }
+}
+
+
+static FIXP_DBL CalcRedValPower(FIXP_DBL num,
+ FIXP_DBL denum,
+ INT* scaling )
+{
+ FIXP_DBL value = FL2FXCONST_DBL(0.f);
+
+ if (num>=FL2FXCONST_DBL(0.f)) {
+ value = fDivNorm( num, denum, scaling);
+ }
+ else {
+ value = -fDivNorm( -num, denum, scaling);
+ }
+ value = f2Pow(value, *scaling, scaling);
+ *scaling = DFRACT_BITS-1-*scaling;
+
+ return value;
+}
+
+
+/*****************************************************************************
+functionname: FDKaacEnc_adaptThresholdsToPe
+description: two guesses for the reduction value and one final correction of the thresholds
+*****************************************************************************/
+static void FDKaacEnc_adaptThresholdsToPe(CHANNEL_MAPPING* cm,
+ ATS_ELEMENT* AdjThrStateElement[(6)],
+ QC_OUT_ELEMENT* qcElement[(6)],
+ PSY_OUT_ELEMENT* psyOutElement[(6)],
+ const INT desiredPe,
+ const INT processElements,
+ const INT elementOffset)
+{
+ FIXP_DBL redValue[(6)];
+ SCHAR redValScaling[(6)];
+ UCHAR pAhFlag[(6)][(2)][MAX_GROUPED_SFB];
+ FIXP_DBL pThrExp[(6)][(2)][MAX_GROUPED_SFB];
+ int iter;
+
+ INT constPartGlobal, noRedPeGlobal, nActiveLinesGlobal, redPeGlobal;
+ constPartGlobal = noRedPeGlobal = nActiveLinesGlobal = redPeGlobal = 0;
+
+ int elementId;
+
+ int nElements = elementOffset+processElements;
+ if(nElements > cm->nElements) {
+ nElements = cm->nElements;
+ }
+
+ /* ------------------------------------------------------- */
+ /* Part I: Initialize data structures and variables... */
+ /* ------------------------------------------------------- */
+ for (elementId = elementOffset;elementId<nElements;elementId++) {
+ if (cm->elInfo[elementId].elType != ID_DSE) {
+
+ INT nChannels = cm->elInfo[elementId].nChannelsInEl;
+ PE_DATA *peData = &qcElement[elementId]->peData;
+
+ /* thresholds to the power of redExp */
+ FDKaacEnc_calcThreshExp(pThrExp[elementId], qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, nChannels);
+
+ /* lower the minSnr requirements for low energies compared to the average
+ energy in this frame */
+ FDKaacEnc_adaptMinSnr(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, &AdjThrStateElement[elementId]->minSnrAdaptParam, nChannels);
+
+ /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
+ FDKaacEnc_initAvoidHoleFlag(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, pAhFlag[elementId], &psyOutElement[elementId]->toolsInfo, nChannels, peData, &AdjThrStateElement[elementId]->ahParam);
+
+ /* sum up */
+ constPartGlobal += peData->constPart;
+ noRedPeGlobal += peData->pe;
+ nActiveLinesGlobal += fixMax((INT)peData->nActiveLines, 1);
+
+ } /* EOF DSE-suppression */
+ } /* EOF for all elements... */
+
+ /* ----------------------------------------------------------------------- */
+ /* Part II: Calculate bit consumption of initial bit constraints setup */
+ /* ----------------------------------------------------------------------- */
+ for (elementId = elementOffset;elementId<nElements;elementId++) {
+ if (cm->elInfo[elementId].elType != ID_DSE) {
+ /*
+ redVal = ( 2 ^ ( (constPartGlobal-desiredPe) / (invRedExp*nActiveLinesGlobal) )
+ - 2 ^ ( (constPartGlobal-noRedPeGlobal) / (invRedExp*nActiveLinesGlobal) ) )
+ */
+
+
+ INT nChannels = cm->elInfo[elementId].nChannelsInEl;
+ PE_DATA *peData = &qcElement[elementId]->peData;
+
+ /* first guess of reduction value */
+ int scale0=0, scale1=0;
+ FIXP_DBL tmp0 = CalcRedValPower( constPartGlobal-desiredPe, 4*nActiveLinesGlobal, &scale0 );
+ FIXP_DBL tmp1 = CalcRedValPower( constPartGlobal-noRedPeGlobal, 4*nActiveLinesGlobal, &scale1 );
+
+ int scalMin = FDKmin(scale0, scale1)-1;
+
+ redValue[elementId] = scaleValue(tmp0,(scalMin-scale0)) - scaleValue(tmp1,(scalMin-scale1));
+ redValScaling[elementId] = scalMin;
+
+ /* reduce thresholds */
+ FDKaacEnc_reduceThresholdsCBR(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, pAhFlag[elementId], pThrExp[elementId], nChannels, redValue[elementId], redValScaling[elementId]);
+
+ /* pe after first guess */
+ FDKaacEnc_calcPe(psyOutElement[elementId]->psyOutChannel, qcElement[elementId]->qcOutChannel, peData, nChannels);
+
+ redPeGlobal += peData->pe;
+ } /* EOF DSE-suppression */
+ } /* EOF for all elements... */
+
+ /* -------------------------------------------------- */
+ /* Part III: Iterate until bit constraints are met */
+ /* -------------------------------------------------- */
+ iter = 0;
+ while ((fixp_abs(redPeGlobal - desiredPe) > fMultI(FL2FXCONST_DBL(0.05f),desiredPe)) && (iter < 1)) {
+
+ INT desiredPeNoAHGlobal;
+ INT redPeNoAHGlobal = 0;
+ INT constPartNoAHGlobal = 0;
+ INT nActiveLinesNoAHGlobal = 0;
+
+ for (elementId = elementOffset;elementId<nElements;elementId++) {
+ if (cm->elInfo[elementId].elType != ID_DSE) {
+
+ INT redPeNoAH, constPartNoAH, nActiveLinesNoAH;
+ INT nChannels = cm->elInfo[elementId].nChannelsInEl;
+ PE_DATA *peData = &qcElement[elementId]->peData;
+
+ /* pe for bands where avoid hole is inactive */
+ FDKaacEnc_FDKaacEnc_calcPeNoAH(&redPeNoAH, &constPartNoAH, &nActiveLinesNoAH,
+ peData, pAhFlag[elementId], psyOutElement[elementId]->psyOutChannel, nChannels);
+
+ redPeNoAHGlobal += redPeNoAH;
+ constPartNoAHGlobal += constPartNoAH;
+ nActiveLinesNoAHGlobal += nActiveLinesNoAH;
+ } /* EOF DSE-suppression */
+ } /* EOF for all elements... */
+
+ /* Calculate new redVal ... */
+ if(desiredPe < redPeGlobal) {
+
+ /* new desired pe without bands where avoid hole is active */
+ desiredPeNoAHGlobal = desiredPe - (redPeGlobal - redPeNoAHGlobal);
+
+ /* limit desiredPeNoAH to positive values, as the PE can not become negative */
+ desiredPeNoAHGlobal = FDKmax(0,desiredPeNoAHGlobal);
+
+ /* second guess (only if there are bands left where avoid hole is inactive)*/
+ if (nActiveLinesNoAHGlobal > 0) {
+ for (elementId = elementOffset;elementId<nElements;elementId++) {
+ if (cm->elInfo[elementId].elType != ID_DSE) {
+ /*
+ redVal += ( 2 ^ ( (constPartNoAHGlobal-desiredPeNoAHGlobal) / (invRedExp*nActiveLinesNoAHGlobal) )
+ - 2 ^ ( (constPartNoAHGlobal-redPeNoAHGlobal) / (invRedExp*nActiveLinesNoAHGlobal) ) )
+ */
+ int scale0 = 0;
+ int scale1 = 0;
+
+ FIXP_DBL tmp0 = CalcRedValPower( constPartNoAHGlobal-desiredPeNoAHGlobal, 4*nActiveLinesNoAHGlobal, &scale0 );
+ FIXP_DBL tmp1 = CalcRedValPower( constPartNoAHGlobal-redPeNoAHGlobal, 4*nActiveLinesNoAHGlobal, &scale1 );
+
+ int scalMin = FDKmin(scale0, scale1)-1;
+
+ tmp0 = scaleValue(tmp0,(scalMin-scale0)) - scaleValue(tmp1,(scalMin-scale1));
+ scale0 = scalMin;
+
+ /* old reduction value */
+ tmp1 = redValue[elementId];
+ scale1 = redValScaling[elementId];
+
+ scalMin = fixMin(scale0,scale1)-1;
+
+ /* sum up old and new reduction value */
+ redValue[elementId] = scaleValue(tmp0,(scalMin-scale0)) + scaleValue(tmp1,(scalMin-scale1));
+ redValScaling[elementId] = scalMin;
+
+ } /* EOF DSE-suppression */
+ } /* EOF for all elements... */
+ } /* nActiveLinesNoAHGlobal > 0 */
+ }
+ else {
+ /* desiredPe >= redPeGlobal */
+ for (elementId = elementOffset;elementId<nElements;elementId++) {
+ if (cm->elInfo[elementId].elType != ID_DSE) {
+
+ INT redVal_scale = 0;
+ FIXP_DBL tmp = fDivNorm((FIXP_DBL)redPeGlobal, (FIXP_DBL)desiredPe, &redVal_scale);
+
+ /* redVal *= redPeGlobal/desiredPe; */
+ redValue[elementId] = fMult(redValue[elementId], tmp);
+ redValScaling[elementId] -= redVal_scale;
+
+ FDKaacEnc_resetAHFlags(pAhFlag[elementId], cm->elInfo[elementId].nChannelsInEl, psyOutElement[elementId]->psyOutChannel);
+ } /* EOF DSE-suppression */
+ } /* EOF for all elements... */
+ }
+
+ redPeGlobal = 0;
+ /* Calculate new redVal's PE... */
+ for (elementId = elementOffset;elementId<nElements;elementId++) {
+ if (cm->elInfo[elementId].elType != ID_DSE) {
+
+ INT nChannels = cm->elInfo[elementId].nChannelsInEl;
+ PE_DATA *peData = &qcElement[elementId]->peData;
+
+ /* reduce thresholds */
+ FDKaacEnc_reduceThresholdsCBR(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, pAhFlag[elementId], pThrExp[elementId], nChannels, redValue[elementId], redValScaling[elementId]);
+
+ /* pe after second guess */
+ FDKaacEnc_calcPe(psyOutElement[elementId]->psyOutChannel, qcElement[elementId]->qcOutChannel, peData, nChannels);
+ redPeGlobal += peData->pe;
+
+ } /* EOF DSE-suppression */
+ } /* EOF for all elements... */
+
+ iter++;
+ } /* EOF while */
+
+
+ /* ------------------------------------------------------- */
+ /* Part IV: if still required, further reduce constraints */
+ /* ------------------------------------------------------- */
+ /* 1.0* 1.15* 1.20*
+ * desiredPe desiredPe desiredPe
+ * | | |
+ * ...XXXXXXXXXXXXXXXXXXXXXXXXXXX| |
+ * | | |XXXXXXXXXXX...
+ * | |XXXXXXXXXXX|
+ * --- A --- | --- B --- | --- C ---
+ *
+ * (X): redPeGlobal
+ * (A): FDKaacEnc_correctThresh()
+ * (B): FDKaacEnc_allowMoreHoles()
+ * (C): FDKaacEnc_reduceMinSnr()
+ */
+
+ /* correct thresholds to get closer to the desired pe */
+ if ( redPeGlobal > desiredPe ) {
+ FDKaacEnc_correctThresh(cm, qcElement, psyOutElement, pAhFlag, pThrExp, redValue, redValScaling,
+ desiredPe - redPeGlobal, processElements, elementOffset);
+
+ /* update PE */
+ redPeGlobal = 0;
+ for(elementId=elementOffset;elementId<nElements;elementId++) {
+ if (cm->elInfo[elementId].elType != ID_DSE) {
+
+ INT nChannels = cm->elInfo[elementId].nChannelsInEl;
+ PE_DATA *peData = &qcElement[elementId]->peData;
+
+ /* pe after correctThresh */
+ FDKaacEnc_calcPe(psyOutElement[elementId]->psyOutChannel, qcElement[elementId]->qcOutChannel, peData, nChannels);
+ redPeGlobal += peData->pe;
+
+ } /* EOF DSE-suppression */
+ } /* EOF for all elements... */
+ }
+
+ if ( redPeGlobal > desiredPe ) {
+ /* reduce pe by reducing minSnr requirements */
+ FDKaacEnc_reduceMinSnr(cm, qcElement, psyOutElement, pAhFlag,
+ (fMultI(FL2FXCONST_DBL(0.15f),desiredPe) + desiredPe),
+ &redPeGlobal, processElements, elementOffset);
+
+ /* reduce pe by allowing additional spectral holes */
+ FDKaacEnc_allowMoreHoles(cm, qcElement, psyOutElement, AdjThrStateElement, pAhFlag,
+ desiredPe, redPeGlobal, processElements, elementOffset);
+ }
+
+}
+
+
+/* similar to FDKaacEnc_adaptThresholdsToPe(), for VBR-mode */
+void FDKaacEnc_AdaptThresholdsVBR(QC_OUT_CHANNEL* qcOutChannel[(2)],
+ PSY_OUT_CHANNEL* psyOutChannel[(2)],
+ ATS_ELEMENT* AdjThrStateElement,
+ struct TOOLSINFO *toolsInfo,
+ PE_DATA *peData,
+ const INT nChannels)
+{
+ UCHAR pAhFlag[(2)][MAX_GROUPED_SFB];
+ FIXP_DBL pThrExp[(2)][MAX_GROUPED_SFB];
+
+ /* thresholds to the power of redExp */
+ FDKaacEnc_calcThreshExp(pThrExp, qcOutChannel, psyOutChannel, nChannels);
+
+ /* lower the minSnr requirements for low energies compared to the average
+ energy in this frame */
+ FDKaacEnc_adaptMinSnr(qcOutChannel, psyOutChannel, &AdjThrStateElement->minSnrAdaptParam, nChannels);
+
+ /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
+ FDKaacEnc_initAvoidHoleFlag(qcOutChannel, psyOutChannel, pAhFlag, toolsInfo,
+ nChannels, peData, &AdjThrStateElement->ahParam);
+
+ /* reduce thresholds */
+ FDKaacEnc_reduceThresholdsVBR(qcOutChannel, psyOutChannel, pAhFlag, pThrExp, nChannels,
+ AdjThrStateElement->vbrQualFactor,
+ &AdjThrStateElement->chaosMeasureOld);
+
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_calcBitSave
+ description: Calculates percentage of bit save, see figure below
+ returns:
+ input: parameters and bitres-fullness
+ output: percentage of bit save
+
+*****************************************************************************/
+/*
+ bitsave
+ maxBitSave(%)| clipLow
+ |---\
+ | \
+ | \
+ | \
+ | \
+ |--------\--------------> bitres
+ | \
+ minBitSave(%)| \------------
+ clipHigh maxBitres
+*/
+static FIXP_DBL FDKaacEnc_calcBitSave(FIXP_DBL fillLevel,
+ const FIXP_DBL clipLow,
+ const FIXP_DBL clipHigh,
+ const FIXP_DBL minBitSave,
+ const FIXP_DBL maxBitSave,
+ const FIXP_DBL bitsave_slope)
+{
+ FIXP_DBL bitsave;
+
+ fillLevel = fixMax(fillLevel, clipLow);
+ fillLevel = fixMin(fillLevel, clipHigh);
+
+ bitsave = maxBitSave - fMult((fillLevel-clipLow), bitsave_slope);
+
+ return (bitsave);
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_calcBitSpend
+ description: Calculates percentage of bit spend, see figure below
+ returns:
+ input: parameters and bitres-fullness
+ output: percentage of bit spend
+
+*****************************************************************************/
+/*
+ bitspend clipHigh
+ maxBitSpend(%)| /-----------maxBitres
+ | /
+ | /
+ | /
+ | /
+ | /
+ |----/-----------------> bitres
+ | /
+ minBitSpend(%)|--/
+ clipLow
+*/
+static FIXP_DBL FDKaacEnc_calcBitSpend(FIXP_DBL fillLevel,
+ const FIXP_DBL clipLow,
+ const FIXP_DBL clipHigh,
+ const FIXP_DBL minBitSpend,
+ const FIXP_DBL maxBitSpend,
+ const FIXP_DBL bitspend_slope)
+{
+ FIXP_DBL bitspend;
+
+ fillLevel = fixMax(fillLevel, clipLow);
+ fillLevel = fixMin(fillLevel, clipHigh);
+
+ bitspend = minBitSpend + fMult(fillLevel-clipLow, bitspend_slope);
+
+ return (bitspend);
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_adjustPeMinMax()
+ description: adjusts peMin and peMax parameters over time
+ returns:
+ input: current pe, peMin, peMax, bitres size
+ output: adjusted peMin/peMax
+
+*****************************************************************************/
+static void FDKaacEnc_adjustPeMinMax(const INT currPe,
+ INT *peMin,
+ INT *peMax)
+{
+ FIXP_DBL minFacHi = FL2FXCONST_DBL(0.3f), maxFacHi = (FIXP_DBL)MAXVAL_DBL, minFacLo = FL2FXCONST_DBL(0.14f), maxFacLo = FL2FXCONST_DBL(0.07f);
+ INT diff;
+
+ INT minDiff_fix = fMultI(FL2FXCONST_DBL(0.1666666667f), currPe);
+
+ if (currPe > *peMax)
+ {
+ diff = (currPe-*peMax) ;
+ *peMin += fMultI(minFacHi,diff);
+ *peMax += fMultI(maxFacHi,diff);
+ }
+ else if (currPe < *peMin)
+ {
+ diff = (*peMin-currPe) ;
+ *peMin -= fMultI(minFacLo,diff);
+ *peMax -= fMultI(maxFacLo,diff);
+ }
+ else
+ {
+ *peMin += fMultI(minFacHi, (currPe - *peMin));
+ *peMax -= fMultI(maxFacLo, (*peMax - currPe));
+ }
+
+ if ((*peMax - *peMin) < minDiff_fix)
+ {
+ INT peMax_fix = *peMax, peMin_fix = *peMin;
+ FIXP_DBL partLo_fix, partHi_fix;
+
+ partLo_fix = (FIXP_DBL)fixMax(0, currPe - peMin_fix);
+ partHi_fix = (FIXP_DBL)fixMax(0, peMax_fix - currPe);
+
+ peMax_fix = (INT)(currPe + fMultI(fDivNorm(partHi_fix, (partLo_fix+partHi_fix)), minDiff_fix));
+ peMin_fix = (INT)(currPe - fMultI(fDivNorm(partLo_fix, (partLo_fix+partHi_fix)), minDiff_fix));
+ peMin_fix = fixMax(0, peMin_fix);
+
+ *peMax = peMax_fix;
+ *peMin = peMin_fix;
+ }
+}
+
+
+
+/*****************************************************************************
+
+ functionname: BitresCalcBitFac
+ description: calculates factor of spending bits for one frame
+ 1.0 : take all frame dynpart bits
+ >1.0 : take all frame dynpart bits + bitres
+ <1.0 : put bits in bitreservoir
+ returns: BitFac
+ input: bitres-fullness, pe, blockType, parameter-settings
+ output:
+
+*****************************************************************************/
+/*
+ bitfac(%) pemax
+ bitspend(%) | /-----------maxBitres
+ | /
+ | /
+ | /
+ | /
+ | /
+ |----/-----------------> pe
+ | /
+ bitsave(%) |--/
+ pemin
+*/
+
+static FIXP_DBL FDKaacEnc_bitresCalcBitFac(const INT bitresBits,
+ const INT maxBitresBits,
+ const INT pe,
+ const INT lastWindowSequence,
+ const INT avgBits,
+ const FIXP_DBL maxBitFac,
+ ADJ_THR_STATE *AdjThr,
+ ATS_ELEMENT *adjThrChan)
+{
+ BRES_PARAM *bresParam;
+ INT pex;
+
+ INT qmin, qbr, qbres, qmbr;
+ FIXP_DBL bitSave, bitSpend;
+
+ FIXP_DBL bitresFac_fix, tmp_cst, tmp_fix;
+ FIXP_DBL pe_pers, bits_ratio, maxBrVal;
+ FIXP_DBL bitsave_slope, bitspend_slope, maxBitFac_tmp;
+ FIXP_DBL fillLevel_fix = (FIXP_DBL)0x7fffffff;
+ FIXP_DBL UNITY = (FIXP_DBL)0x7fffffff;
+ FIXP_DBL POINT7 = (FIXP_DBL)0x5999999A;
+
+ if (maxBitresBits > bitresBits) {
+ fillLevel_fix = fDivNorm(bitresBits, maxBitresBits);
+ }
+
+ if (lastWindowSequence != SHORT_WINDOW)
+ {
+ bresParam = &(AdjThr->bresParamLong);
+ bitsave_slope = (FIXP_DBL)0x3BBBBBBC;
+ bitspend_slope = (FIXP_DBL)0x55555555;
+ }
+ else
+ {
+ bresParam = &(AdjThr->bresParamShort);
+ bitsave_slope = (FIXP_DBL)0x2E8BA2E9;
+ bitspend_slope = (FIXP_DBL)0x7fffffff;
+ }
+
+ pex = fixMax(pe, adjThrChan->peMin);
+ pex = fixMin(pex, adjThrChan->peMax);
+
+ bitSave = FDKaacEnc_calcBitSave(fillLevel_fix,
+ bresParam->clipSaveLow, bresParam->clipSaveHigh,
+ bresParam->minBitSave, bresParam->maxBitSave, bitsave_slope);
+
+ bitSpend = FDKaacEnc_calcBitSpend(fillLevel_fix,
+ bresParam->clipSpendLow, bresParam->clipSpendHigh,
+ bresParam->minBitSpend, bresParam->maxBitSpend, bitspend_slope);
+
+ pe_pers = fDivNorm(pex - adjThrChan->peMin, adjThrChan->peMax - adjThrChan->peMin);
+ tmp_fix = fMult(((FIXP_DBL)bitSpend + (FIXP_DBL)bitSave), pe_pers);
+ bitresFac_fix = (UNITY>>1) - ((FIXP_DBL)bitSave>>1) + (tmp_fix>>1); qbres = (DFRACT_BITS-2);
+
+ /* (float)bitresBits/(float)avgBits */
+ bits_ratio = fDivNorm(bitresBits, avgBits, &qbr);
+ qbr = DFRACT_BITS-1-qbr;
+
+ /* Add 0.7 in q31 to bits_ratio in qbr */
+ /* 0.7f + (float)bitresBits/(float)avgBits */
+ qmin = fixMin(qbr, (DFRACT_BITS-1));
+ bits_ratio = bits_ratio >> (qbr - qmin);
+ tmp_cst = POINT7 >> ((DFRACT_BITS-1) - qmin);
+ maxBrVal = (bits_ratio>>1) + (tmp_cst>>1); qmbr = qmin - 1;
+
+ /* bitresFac_fix = fixMin(bitresFac_fix, 0.7 + bitresBits/avgBits); */
+ bitresFac_fix = bitresFac_fix >> (qbres - qmbr); qbres = qmbr;
+ bitresFac_fix = fixMin(bitresFac_fix, maxBrVal);
+
+ /* Compare with maxBitFac */
+ qmin = fixMin(Q_BITFAC, qbres);
+ bitresFac_fix = bitresFac_fix >> (qbres - qmin);
+ maxBitFac_tmp = maxBitFac >> (Q_BITFAC - qmin);
+ if(maxBitFac_tmp < bitresFac_fix)
+ {
+ bitresFac_fix = maxBitFac;
+ }
+ else
+ {
+ if(qmin < Q_BITFAC)
+ {
+ bitresFac_fix = bitresFac_fix << (Q_BITFAC-qmin);
+ }
+ else
+ {
+ bitresFac_fix = bitresFac_fix >> (qmin-Q_BITFAC);
+ }
+ }
+
+ FDKaacEnc_adjustPeMinMax(pe, &adjThrChan->peMin, &adjThrChan->peMax);
+
+ return bitresFac_fix;
+}
+
+
+/*****************************************************************************
+functionname: FDKaacEnc_AdjThrNew
+description: allocate ADJ_THR_STATE
+*****************************************************************************/
+INT FDKaacEnc_AdjThrNew(ADJ_THR_STATE** phAdjThr,
+ INT nElements)
+{
+ INT err = 0;
+ INT i;
+ ADJ_THR_STATE* hAdjThr = GetRam_aacEnc_AdjustThreshold();
+ if (hAdjThr==NULL) {
+ err = 1;
+ goto bail;
+ }
+
+ for (i=0; i<nElements; i++) {
+ hAdjThr->adjThrStateElem[i] = GetRam_aacEnc_AdjThrStateElement(i);
+ if (hAdjThr->adjThrStateElem[i]==NULL) {
+ err = 1;
+ goto bail;
+ }
+ }
+
+bail:
+ *phAdjThr = hAdjThr;
+ return err;
+}
+
+
+/*****************************************************************************
+functionname: FDKaacEnc_AdjThrInit
+description: initialize ADJ_THR_STATE
+*****************************************************************************/
+void FDKaacEnc_AdjThrInit(ADJ_THR_STATE *hAdjThr,
+ const INT meanPe,
+ ELEMENT_BITS *elBits[(6)],
+ INT nElements,
+ FIXP_DBL vbrQualFactor)
+{
+ INT i;
+
+ FIXP_DBL POINT8 = FL2FXCONST_DBL(0.8f);
+ FIXP_DBL POINT6 = FL2FXCONST_DBL(0.6f);
+
+ /* common for all elements: */
+ /* parameters for bitres control */
+ hAdjThr->bresParamLong.clipSaveLow = (FIXP_DBL)0x1999999a; /* FL2FXCONST_DBL(0.2f); */
+ hAdjThr->bresParamLong.clipSaveHigh = (FIXP_DBL)0x7999999a; /* FL2FXCONST_DBL(0.95f); */
+ hAdjThr->bresParamLong.minBitSave = (FIXP_DBL)0xf999999a; /* FL2FXCONST_DBL(-0.05f); */
+ hAdjThr->bresParamLong.maxBitSave = (FIXP_DBL)0x26666666; /* FL2FXCONST_DBL(0.3f); */
+ hAdjThr->bresParamLong.clipSpendLow = (FIXP_DBL)0x1999999a; /* FL2FXCONST_DBL(0.2f); */
+ hAdjThr->bresParamLong.clipSpendHigh = (FIXP_DBL)0x7999999a; /* FL2FXCONST_DBL(0.95f); */
+ hAdjThr->bresParamLong.minBitSpend = (FIXP_DBL)0xf3333333; /* FL2FXCONST_DBL(-0.10f); */
+ hAdjThr->bresParamLong.maxBitSpend = (FIXP_DBL)0x33333333; /* FL2FXCONST_DBL(0.4f); */
+
+ hAdjThr->bresParamShort.clipSaveLow = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
+ hAdjThr->bresParamShort.clipSaveHigh = (FIXP_DBL)0x5fffffff; /* FL2FXCONST_DBL(0.75f); */
+ hAdjThr->bresParamShort.minBitSave = (FIXP_DBL)0x00000000; /* FL2FXCONST_DBL(0.0f); */
+ hAdjThr->bresParamShort.maxBitSave = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
+ hAdjThr->bresParamShort.clipSpendLow = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
+ hAdjThr->bresParamShort.clipSpendHigh = (FIXP_DBL)0x5fffffff; /* FL2FXCONST_DBL(0.75f); */
+ hAdjThr->bresParamShort.minBitSpend = (FIXP_DBL)0xf9999998; /* FL2FXCONST_DBL(-0.05f); */
+ hAdjThr->bresParamShort.maxBitSpend = (FIXP_DBL)0x40000000; /* FL2FXCONST_DBL(0.5f); */
+
+ /* specific for each element: */
+ for (i=0; i<nElements; i++) {
+ ATS_ELEMENT* atsElem = hAdjThr->adjThrStateElem[i];
+ MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam;
+ INT chBitrate = elBits[i]->chBitrateEl;
+
+ /* parameters for bitres control */
+ atsElem->peMin = fMultI(POINT8, meanPe) >> 1;
+ atsElem->peMax = fMultI(POINT6, meanPe);
+
+ /* for use in FDKaacEnc_reduceThresholdsVBR */
+ atsElem->chaosMeasureOld = FL2FXCONST_DBL(0.3f);
+
+ /* additional pe offset to correct pe2bits for low bitrates */
+ atsElem->peOffset = 0;
+
+ /* vbr initialisation */
+ atsElem->vbrQualFactor = vbrQualFactor;
+ if (chBitrate < 32000)
+ {
+ atsElem->peOffset = fixMax(50, 100-fMultI((FIXP_DBL)0x666667, chBitrate));
+ }
+
+ /* avoid hole parameters */
+ if (chBitrate > 20000) {
+ atsElem->ahParam.modifyMinSnr = TRUE;
+ atsElem->ahParam.startSfbL = 15;
+ atsElem->ahParam.startSfbS = 3;
+ }
+ else {
+ atsElem->ahParam.modifyMinSnr = FALSE;
+ atsElem->ahParam.startSfbL = 0;
+ atsElem->ahParam.startSfbS = 0;
+ }
+
+ /* minSnr adaptation */
+ msaParam->maxRed = FL2FXCONST_DBL(0.00390625f); /* 0.25f/64.0f */
+ /* start adaptation of minSnr for avgEn/sfbEn > startRatio */
+ msaParam->startRatio = FL2FXCONST_DBL(0.05190512648f); /* ld64(10.0f) */
+ /* maximum minSnr reduction to minSnr^maxRed is reached for
+ avgEn/sfbEn >= maxRatio */
+ /* msaParam->maxRatio = 1000.0f; */
+ /*msaParam->redRatioFac = ((float)1.0f - msaParam->maxRed) / ((float)10.0f*log10(msaParam->startRatio/msaParam->maxRatio)/log10(2.0f)*(float)0.3010299956f);*/
+ msaParam->redRatioFac = FL2FXCONST_DBL(-0.375f); /* -0.0375f * 10.0f */
+ /*msaParam->redOffs = (float)1.0f - msaParam->redRatioFac * (float)10.0f * log10(msaParam->startRatio)/log10(2.0f) * (float)0.3010299956f;*/
+ msaParam->redOffs = FL2FXCONST_DBL(0.021484375); /* 1.375f/64.0f */
+
+ /* init pe correction */
+ atsElem->peCorrectionFactor_m = FL2FXCONST_DBL(0.5f); /* 1.0 */
+ atsElem->peCorrectionFactor_e = 1;
+
+ atsElem->dynBitsLast = -1;
+ atsElem->peLast = 0;
+
+ /* init bits to pe factor */
+ atsElem->bits2PeFactor_m = FL2FXCONST_DBL(1.18f/(1<<(1)));
+ atsElem->bits2PeFactor_e = 1;
+ }
+}
+
+
+/*****************************************************************************
+ functionname: FDKaacEnc_FDKaacEnc_calcPeCorrection
+ description: calc desired pe
+*****************************************************************************/
+static void FDKaacEnc_FDKaacEnc_calcPeCorrection(
+ FIXP_DBL *const correctionFac_m,
+ INT *const correctionFac_e,
+ const INT peAct,
+ const INT peLast,
+ const INT bitsLast,
+ const FIXP_DBL bits2PeFactor_m,
+ const INT bits2PeFactor_e
+ )
+{
+ if ( (bitsLast > 0) && (peAct < 1.5f*peLast) && (peAct > 0.7f*peLast) &&
+ (FDKaacEnc_bits2pe2(bitsLast, fMult(FL2FXCONST_DBL(1.2f/2.f), bits2PeFactor_m), bits2PeFactor_e+1) > peLast) &&
+ (FDKaacEnc_bits2pe2(bitsLast, fMult(FL2FXCONST_DBL(0.65f), bits2PeFactor_m), bits2PeFactor_e ) < peLast) )
+ {
+ FIXP_DBL corrFac = *correctionFac_m;
+
+ int scaling = 0;
+ FIXP_DBL denum = (FIXP_DBL)FDKaacEnc_bits2pe2(bitsLast, bits2PeFactor_m, bits2PeFactor_e);
+ FIXP_DBL newFac = fDivNorm((FIXP_DBL)peLast, denum, &scaling);
+
+ /* dead zone, newFac and corrFac are scaled by 0.5 */
+ if ((FIXP_DBL)peLast <= denum) { /* ratio <= 1.f */
+ newFac = fixMax(scaleValue(fixMin( fMult(FL2FXCONST_DBL(1.1f/2.f), newFac), scaleValue(FL2FXCONST_DBL( 1.f/2.f), -scaling)), scaling), FL2FXCONST_DBL(0.85f/2.f) );
+ }
+ else { /* ratio < 1.f */
+ newFac = fixMax( fixMin( scaleValue(fMult(FL2FXCONST_DBL(0.9f/2.f), newFac), scaling), FL2FXCONST_DBL(1.15f/2.f) ), FL2FXCONST_DBL( 1.f/2.f) );
+ }
+
+ if ( ((newFac > FL2FXCONST_DBL(1.f/2.f)) && (corrFac < FL2FXCONST_DBL(1.f/2.f)))
+ || ((newFac < FL2FXCONST_DBL(1.f/2.f)) && (corrFac > FL2FXCONST_DBL(1.f/2.f))))
+ {
+ corrFac = FL2FXCONST_DBL(1.f/2.f);
+ }
+
+ /* faster adaptation towards 1.0, slower in the other direction */
+ if ( (corrFac < FL2FXCONST_DBL(1.f/2.f) && newFac < corrFac)
+ || (corrFac > FL2FXCONST_DBL(1.f/2.f) && newFac > corrFac) )
+ {
+ corrFac = fMult(FL2FXCONST_DBL(0.85f), corrFac) + fMult(FL2FXCONST_DBL(0.15f), newFac);
+ }
+ else {
+ corrFac = fMult(FL2FXCONST_DBL(0.7f), corrFac) + fMult(FL2FXCONST_DBL(0.3f), newFac);
+ }
+
+ corrFac = fixMax( fixMin( corrFac, FL2FXCONST_DBL(1.15f/2.f) ), FL2FXCONST_DBL(0.85/2.f) );
+
+ *correctionFac_m = corrFac;
+ *correctionFac_e = 1;
+ }
+ else {
+ *correctionFac_m = FL2FXCONST_DBL(1.f/2.f);
+ *correctionFac_e = 1;
+ }
+}
+
+
+void FDKaacEnc_DistributeBits(ADJ_THR_STATE *adjThrState,
+ ATS_ELEMENT *AdjThrStateElement,
+ PSY_OUT_CHANNEL *psyOutChannel[(2)],
+ PE_DATA *peData,
+ INT *grantedPe,
+ INT *grantedPeCorr,
+ const INT nChannels,
+ const INT commonWindow,
+ const INT grantedDynBits,
+ const INT bitresBits,
+ const INT maxBitresBits,
+ const FIXP_DBL maxBitFac,
+ const INT bitDistributenMode)
+{
+ FIXP_DBL bitFactor;
+ INT noRedPe = peData->pe;
+
+ /* prefer short windows for calculation of bitFactor */
+ INT curWindowSequence = LONG_WINDOW;
+ if (nChannels==2) {
+ if ((psyOutChannel[0]->lastWindowSequence == SHORT_WINDOW) ||
+ (psyOutChannel[1]->lastWindowSequence == SHORT_WINDOW)) {
+ curWindowSequence = SHORT_WINDOW;
+ }
+ }
+ else {
+ curWindowSequence = psyOutChannel[0]->lastWindowSequence;
+ }
+
+ if (grantedDynBits >= 1) {
+ if (bitDistributenMode!=0) {
+ *grantedPe = FDKaacEnc_bits2pe2(grantedDynBits, AdjThrStateElement->bits2PeFactor_m, AdjThrStateElement->bits2PeFactor_e);
+ }
+ else
+ {
+ /* factor dependend on current fill level and pe */
+ bitFactor = FDKaacEnc_bitresCalcBitFac(bitresBits, maxBitresBits, noRedPe,
+ curWindowSequence, grantedDynBits, maxBitFac,
+ adjThrState,
+ AdjThrStateElement
+ );
+
+ /* desired pe for actual frame */
+ /* Worst case max of grantedDynBits is = 1024 * 5.27 * 2 */
+ *grantedPe = FDKaacEnc_bits2pe2(grantedDynBits,
+ fMult(bitFactor, AdjThrStateElement->bits2PeFactor_m), AdjThrStateElement->bits2PeFactor_e+(DFRACT_BITS-1-Q_BITFAC)
+ );
+ }
+ }
+ else {
+ *grantedPe = 0; /* prevent divsion by 0 */
+ }
+
+ /* correction of pe value */
+ {
+ FDKaacEnc_FDKaacEnc_calcPeCorrection(
+ &AdjThrStateElement->peCorrectionFactor_m,
+ &AdjThrStateElement->peCorrectionFactor_e,
+ fixMin(*grantedPe, noRedPe),
+ AdjThrStateElement->peLast,
+ AdjThrStateElement->dynBitsLast,
+ AdjThrStateElement->bits2PeFactor_m,
+ AdjThrStateElement->bits2PeFactor_e
+ );
+ }
+
+ *grantedPeCorr = (INT)(fMult((FIXP_DBL)(*grantedPe<<Q_AVGBITS), AdjThrStateElement->peCorrectionFactor_m) >> (Q_AVGBITS-AdjThrStateElement->peCorrectionFactor_e));
+
+ /* update last pe */
+ AdjThrStateElement->peLast = *grantedPe;
+ AdjThrStateElement->dynBitsLast = -1;
+
+}
+
+/*****************************************************************************
+functionname: FDKaacEnc_AdjustThresholds
+description: adjust thresholds
+*****************************************************************************/
+void FDKaacEnc_AdjustThresholds(ATS_ELEMENT* AdjThrStateElement[(6)],
+ QC_OUT_ELEMENT* qcElement[(6)],
+ QC_OUT* qcOut,
+ PSY_OUT_ELEMENT* psyOutElement[(6)],
+ INT CBRbitrateMode,
+ CHANNEL_MAPPING* cm)
+{
+ int i;
+ if (CBRbitrateMode)
+ {
+ /* In case, no bits must be shifted between different elements, */
+ /* an element-wise execution of the pe-dependent threshold- */
+ /* adaption becomes necessary... */
+ for (i=0; i<cm->nElements; i++)
+ {
+ ELEMENT_INFO elInfo = cm->elInfo[i];
+
+ if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) ||
+ (elInfo.elType == ID_LFE))
+ {
+ /* qcElement[i]->grantedPe = 2000; */ /* Use this only for debugging */
+ //if (totalGrantedPeCorr < totalNoRedPe) {
+ if (qcElement[i]->grantedPe < qcElement[i]->peData.pe)
+ {
+ /* calc threshold necessary for desired pe */
+ FDKaacEnc_adaptThresholdsToPe(cm,
+ AdjThrStateElement,
+ qcElement,
+ psyOutElement,
+ qcElement[i]->grantedPeCorr,
+ 1, /* Process only 1 element */
+ i); /* Process exactly THIS element */
+
+ }
+
+ } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */
+
+ } /* -end- element loop */
+ }
+ else {
+ for (i=0; i<cm->nElements; i++)
+ {
+ ELEMENT_INFO elInfo = cm->elInfo[i];
+
+ if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) ||
+ (elInfo.elType == ID_LFE))
+ {
+ /* for VBR-mode */
+ FDKaacEnc_AdaptThresholdsVBR(qcElement[i]->qcOutChannel,
+ psyOutElement[i]->psyOutChannel,
+ AdjThrStateElement[i],
+ &psyOutElement[i]->toolsInfo,
+ &qcElement[i]->peData,
+ cm->elInfo[i].nChannelsInEl);
+ } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */
+
+ } /* -end- element loop */
+
+ }
+ for (i=0; i<cm->nElements; i++) {
+ int ch,sfb,sfbGrp;
+ /* no weighting of threholds and energies for mlout */
+ /* weight energies and thresholds */
+ for (ch=0; ch<cm->elInfo[i].nChannelsInEl; ch++) {
+ QC_OUT_CHANNEL* pQcOutCh = qcElement[i]->qcOutChannel[ch];
+ for (sfbGrp = 0;sfbGrp < psyOutElement[i]->psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutElement[i]->psyOutChannel[ch]->sfbPerGroup) {
+ for (sfb=0; sfb<psyOutElement[i]->psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
+ pQcOutCh->sfbThresholdLdData[sfb+sfbGrp] += pQcOutCh->sfbEnFacLd[sfb+sfbGrp];
+ }
+ }
+ }
+ }
+
+}
+
+void FDKaacEnc_AdjThrClose(ADJ_THR_STATE** phAdjThr)
+{
+ INT i;
+ ADJ_THR_STATE* hAdjThr = *phAdjThr;
+
+ if (hAdjThr!=NULL) {
+ for (i=0; i<(6); i++) {
+ if (hAdjThr->adjThrStateElem[i]!=NULL) {
+ FreeRam_aacEnc_AdjThrStateElement(&hAdjThr->adjThrStateElem[i]);
+ }
+ }
+ FreeRam_aacEnc_AdjustThreshold(phAdjThr);
+ }
+}
+
diff --git a/libAACenc/src/adj_thr.h b/libAACenc/src/adj_thr.h
new file mode 100644
index 0000000..44db688
--- /dev/null
+++ b/libAACenc/src/adj_thr.h
@@ -0,0 +1,79 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: Threshold compensation
+
+******************************************************************************/
+#ifndef __ADJ_THR_H
+#define __ADJ_THR_H
+
+
+#include "adj_thr_data.h"
+#include "qc_data.h"
+#include "line_pe.h"
+#include "interface.h"
+
+
+
+void FDKaacEnc_peCalculation(PE_DATA *peData,
+ PSY_OUT_CHANNEL* psyOutChannel[(2)],
+ QC_OUT_CHANNEL* qcOutChannel[(2)],
+ struct TOOLSINFO *toolsInfo,
+ ATS_ELEMENT* adjThrStateElement,
+ const INT nChannels);
+
+INT FDKaacEnc_AdjThrNew(ADJ_THR_STATE** phAdjThr,
+ INT nElements);
+
+void FDKaacEnc_AdjThrInit(ADJ_THR_STATE *hAdjThr,
+ const INT peMean,
+ ELEMENT_BITS* elBits[(6)],
+ INT nElements,
+ FIXP_DBL vbrQualFactor);
+
+
+void FDKaacEnc_DistributeBits(ADJ_THR_STATE *adjThrState,
+ ATS_ELEMENT *AdjThrStateElement,
+ PSY_OUT_CHANNEL *psyOutChannel[(2)],
+ PE_DATA *peData,
+ INT *grantedPe,
+ INT *grantedPeCorr,
+ const INT nChannels,
+ const INT commonWindow,
+ const INT avgBits,
+ const INT bitresBits,
+ const INT maxBitresBits,
+ const FIXP_DBL maxBitFac,
+ const INT bitDistributenMode);
+
+void FDKaacEnc_AdjustThresholds(ATS_ELEMENT* AdjThrStateElement[(6)],
+ QC_OUT_ELEMENT* qcElement[(6)],
+ QC_OUT* qcOut,
+ PSY_OUT_ELEMENT* psyOutElement[(6)],
+ INT CBRbitrateMode,
+ CHANNEL_MAPPING* cm);
+
+void FDKaacEnc_AdjThrClose(ADJ_THR_STATE** hAdjThr);
+
+#endif
diff --git a/libAACenc/src/adj_thr_data.h b/libAACenc/src/adj_thr_data.h
new file mode 100644
index 0000000..6cb28cf
--- /dev/null
+++ b/libAACenc/src/adj_thr_data.h
@@ -0,0 +1,88 @@
+/************************* Fast MPEG AAC Audio Encoder **********************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Schug / A. Groeschel
+ contents/description: threshold calculations
+
+******************************************************************************/
+
+#ifndef __ADJ_THR_DATA_H
+#define __ADJ_THR_DATA_H
+
+
+#include "psy_const.h"
+
+typedef struct {
+ FIXP_DBL clipSaveLow, clipSaveHigh;
+ FIXP_DBL minBitSave, maxBitSave;
+ FIXP_DBL clipSpendLow, clipSpendHigh;
+ FIXP_DBL minBitSpend, maxBitSpend;
+} BRES_PARAM;
+
+typedef struct {
+ INT modifyMinSnr;
+ INT startSfbL, startSfbS;
+} AH_PARAM;
+
+typedef struct {
+ FIXP_DBL maxRed;
+ FIXP_DBL startRatio;
+ FIXP_DBL maxRatio;
+ FIXP_DBL redRatioFac;
+ FIXP_DBL redOffs;
+} MINSNR_ADAPT_PARAM;
+
+typedef struct {
+ /* parameters for bitreservoir control */
+ INT peMin, peMax;
+ /* constant offset to pe */
+ INT peOffset;
+ /* constant PeFactor */
+ FIXP_DBL bits2PeFactor_m;
+ INT bits2PeFactor_e;
+ /* avoid hole parameters */
+ AH_PARAM ahParam;
+ /* values for correction of pe */
+ /* paramters for adaptation of minSnr */
+ MINSNR_ADAPT_PARAM minSnrAdaptParam;
+ INT peLast;
+ INT dynBitsLast;
+ FIXP_DBL peCorrectionFactor_m;
+ INT peCorrectionFactor_e;
+
+ /* vbr encoding */
+ FIXP_DBL vbrQualFactor;
+ FIXP_DBL chaosMeasureOld;
+
+ /* threshold weighting */
+ FIXP_DBL chaosMeasureEnFac[(2)];
+ INT lastEnFacPatch[(2)];
+
+} ATS_ELEMENT;
+
+typedef struct {
+ BRES_PARAM bresParamLong, bresParamShort;
+ ATS_ELEMENT* adjThrStateElem[(6)];
+} ADJ_THR_STATE;
+
+#endif
diff --git a/libAACenc/src/band_nrg.cpp b/libAACenc/src/band_nrg.cpp
new file mode 100644
index 0000000..8ae271b
--- /dev/null
+++ b/libAACenc/src/band_nrg.cpp
@@ -0,0 +1,297 @@
+/***************************** MPEG-4 AAC Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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. Werner
+ contents/description: Band/Line energy calculations
+
+ 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 "band_nrg.h"
+
+
+/*****************************************************************************
+ functionname: FDKaacEnc_CalcSfbMaxScaleSpec
+ description:
+ input:
+ output:
+*****************************************************************************/
+void
+FDKaacEnc_CalcSfbMaxScaleSpec(const FIXP_DBL *RESTRICT mdctSpectrum,
+ const INT *RESTRICT bandOffset,
+ INT *RESTRICT sfbMaxScaleSpec,
+ const INT numBands)
+{
+ INT i,j;
+ FIXP_DBL maxSpc, tmp;
+
+ for(i=0; i<numBands; i++) {
+ maxSpc = (FIXP_DBL)0;
+ for (j=bandOffset[i]; j<bandOffset[i+1]; j++) {
+ tmp = fixp_abs(mdctSpectrum[j]);
+ maxSpc = fixMax(maxSpc, tmp);
+ }
+ sfbMaxScaleSpec[i] = (maxSpc==(FIXP_DBL)0) ? (DFRACT_BITS-2) : CntLeadingZeros(maxSpc)-1;
+ /* CountLeadingBits() is not necessary here since test value is always > 0 */
+ }
+}
+
+/*****************************************************************************
+ functionname: FDKaacEnc_CheckBandEnergyOptim
+ description:
+ input:
+ output:
+*****************************************************************************/
+FIXP_DBL
+FDKaacEnc_CheckBandEnergyOptim(const FIXP_DBL *RESTRICT mdctSpectrum,
+ INT *RESTRICT sfbMaxScaleSpec,
+ const INT *RESTRICT bandOffset,
+ const INT numBands,
+ FIXP_DBL *RESTRICT bandEnergy,
+ FIXP_DBL *RESTRICT bandEnergyLdData,
+ INT minSpecShift)
+{
+ INT i, j, scale, nr = 0;
+ FIXP_DBL maxNrgLd = FL2FXCONST_DBL(-1.0f);
+ FIXP_DBL maxNrg = 0;
+ FIXP_DBL spec;
+
+ for(i=0; i<numBands; i++) {
+ scale = fixMax(0, sfbMaxScaleSpec[i]-4);
+ FIXP_DBL tmp = 0;
+ for (j=bandOffset[i]; j<bandOffset[i+1]; j++){
+ spec = mdctSpectrum[j]<<scale;
+ tmp = fPow2AddDiv2(tmp, spec);
+ }
+ bandEnergy[i] = tmp<<1;
+
+ /* calculate ld of bandNrg, subtract scaling */
+ bandEnergyLdData[i] = CalcLdData(bandEnergy[i]);
+ if (bandEnergyLdData[i] != FL2FXCONST_DBL(-1.0f)) {
+ bandEnergyLdData[i] -= scale*FL2FXCONST_DBL(2.0/64);
+ }
+ /* find index of maxNrg */
+ if (bandEnergyLdData[i] > maxNrgLd) {
+ maxNrgLd = bandEnergyLdData[i];
+ nr = i;
+ }
+ }
+
+ /* return unscaled maxNrg*/
+ scale = fixMax(0,sfbMaxScaleSpec[nr]-4);
+ scale = fixMax(2*(minSpecShift-scale),-(DFRACT_BITS-1));
+
+ maxNrg = scaleValue(bandEnergy[nr], scale);
+
+ return maxNrg;
+}
+
+/*****************************************************************************
+ functionname: FDKaacEnc_CalcBandEnergyOptimLong
+ description:
+ input:
+ output:
+*****************************************************************************/
+INT
+FDKaacEnc_CalcBandEnergyOptimLong(const FIXP_DBL *RESTRICT mdctSpectrum,
+ INT *RESTRICT sfbMaxScaleSpec,
+ const INT *RESTRICT bandOffset,
+ const INT numBands,
+ FIXP_DBL *RESTRICT bandEnergy,
+ FIXP_DBL *RESTRICT bandEnergyLdData)
+{
+ INT i, j, shiftBits = 0;
+ FIXP_DBL maxNrgLd = FL2FXCONST_DBL(0.0f);
+
+ FIXP_DBL spec;
+
+ for(i=0; i<numBands; i++) {
+ INT leadingBits = sfbMaxScaleSpec[i]-4; /* max sfbWidth = 96 ; 2^7=128 => 7/2 = 4 (spc*spc) */
+ FIXP_DBL tmp = FL2FXCONST_DBL(0.0);
+ /* don't use scaleValue() here, it increases workload quite sufficiently... */
+ if (leadingBits>=0) {
+ for (j=bandOffset[i];j<bandOffset[i+1];j++) {
+ spec = mdctSpectrum[j]<<leadingBits;
+ tmp = fPow2AddDiv2(tmp, spec);
+ }
+ } else {
+ INT shift = -leadingBits;
+ for (j=bandOffset[i];j<bandOffset[i+1];j++){
+ spec = mdctSpectrum[j]>>shift;
+ tmp = fPow2AddDiv2(tmp, spec);
+ }
+ }
+ bandEnergy[i] = tmp<<1;
+ }
+
+ /* calculate ld of bandNrg, subtract scaling */
+ LdDataVector(bandEnergy, bandEnergyLdData, numBands);
+ for(i=numBands; i--!=0; ) {
+ FIXP_DBL scaleDiff = (sfbMaxScaleSpec[i]-4)*FL2FXCONST_DBL(2.0/64);
+
+ bandEnergyLdData[i] = (bandEnergyLdData[i] >= ((FL2FXCONST_DBL(-1.f)>>1) + (scaleDiff>>1)))
+ ? bandEnergyLdData[i]-scaleDiff : FL2FXCONST_DBL(-1.f);
+ /* find maxNrgLd */
+ maxNrgLd = fixMax(maxNrgLd, bandEnergyLdData[i]);
+ }
+
+ if (maxNrgLd<=(FIXP_DBL)0)
+ {
+ for(i=numBands; i--!=0; )
+ {
+ INT scale = fixMin((sfbMaxScaleSpec[i]-4)<<1,(DFRACT_BITS-1));
+ bandEnergy[i] = scaleValue(bandEnergy[i], -scale);
+ }
+ return 0;
+ }
+ else
+ { /* scale down NRGs */
+ while (maxNrgLd>FL2FXCONST_DBL(0.0f))
+ {
+ maxNrgLd -= FL2FXCONST_DBL(2.0/64);
+ shiftBits++;
+ }
+ for(i=numBands; i--!=0; )
+ {
+ INT scale = fixMin( ((sfbMaxScaleSpec[i]-4)+shiftBits)<<1, (DFRACT_BITS-1));
+ bandEnergyLdData[i] -= shiftBits*FL2FXCONST_DBL(2.0/64);
+ bandEnergy[i] = scaleValue(bandEnergy[i], -scale);
+ }
+ return shiftBits;
+ }
+}
+
+
+/*****************************************************************************
+ functionname: FDKaacEnc_CalcBandEnergyOptimShort
+ description:
+ input:
+ output:
+*****************************************************************************/
+void
+FDKaacEnc_CalcBandEnergyOptimShort(const FIXP_DBL *RESTRICT mdctSpectrum,
+ INT *RESTRICT sfbMaxScaleSpec,
+ const INT *RESTRICT bandOffset,
+ const INT numBands,
+ FIXP_DBL *RESTRICT bandEnergy)
+{
+ INT i, j;
+
+ for(i=0; i<numBands; i++)
+ {
+ int leadingBits = fixMax(0,sfbMaxScaleSpec[i]-4); /* max sfbWidth = 96 ; 2^7=128 => 7/2 = 4 (spc*spc) */
+ FIXP_DBL tmp = FL2FXCONST_DBL(0.0);
+ for (j=bandOffset[i];j<bandOffset[i+1];j++)
+ {
+ FIXP_DBL spec = mdctSpectrum[j]<<leadingBits;
+ tmp = fPow2AddDiv2(tmp, spec);
+ }
+ bandEnergy[i] = tmp<<1;
+ }
+
+ for(i=0; i<numBands; i++)
+ {
+ INT scale = 2*fixMax(0,sfbMaxScaleSpec[i]-4); /* max sfbWidth = 96 ; 2^7=128 => 7/2 = 4 (spc*spc) */
+ scale = fixMin(scale,(DFRACT_BITS-1));
+ bandEnergy[i] >>= scale;
+ }
+}
+
+
+/*****************************************************************************
+ functionname: FDKaacEnc_CalcBandNrgMSOpt
+ description:
+ input:
+ output:
+*****************************************************************************/
+void FDKaacEnc_CalcBandNrgMSOpt(const FIXP_DBL *RESTRICT mdctSpectrumLeft,
+ const FIXP_DBL *RESTRICT mdctSpectrumRight,
+ INT *RESTRICT sfbMaxScaleSpecLeft,
+ INT *RESTRICT sfbMaxScaleSpecRight,
+ const INT *RESTRICT bandOffset,
+ const INT numBands,
+ FIXP_DBL *RESTRICT bandEnergyMid,
+ FIXP_DBL *RESTRICT bandEnergySide,
+ INT calcLdData,
+ FIXP_DBL *RESTRICT bandEnergyMidLdData,
+ FIXP_DBL *RESTRICT bandEnergySideLdData)
+{
+ INT i, j, minScale;
+ FIXP_DBL NrgMid, NrgSide, specm, specs;
+
+ for (i=0; i<numBands; i++) {
+
+ NrgMid = NrgSide = FL2FXCONST_DBL(0.0);
+ minScale = fixMin(sfbMaxScaleSpecLeft[i], sfbMaxScaleSpecRight[i])-4;
+ minScale = fixMax(0, minScale);
+
+ if (minScale > 0) {
+ for (j=bandOffset[i];j<bandOffset[i+1];j++) {
+ FIXP_DBL specL = mdctSpectrumLeft[j]<<(minScale-1);
+ FIXP_DBL specR = mdctSpectrumRight[j]<<(minScale-1);
+ specm = specL + specR;
+ specs = specL - specR;
+ NrgMid = fPow2AddDiv2(NrgMid, specm);
+ NrgSide = fPow2AddDiv2(NrgSide, specs);
+ }
+ } else {
+ for (j=bandOffset[i];j<bandOffset[i+1];j++) {
+ FIXP_DBL specL = mdctSpectrumLeft[j]>>1;
+ FIXP_DBL specR = mdctSpectrumRight[j]>>1;
+ specm = specL + specR;
+ specs = specL - specR;
+ NrgMid = fPow2AddDiv2(NrgMid, specm);
+ NrgSide = fPow2AddDiv2(NrgSide, specs);
+ }
+ }
+ bandEnergyMid[i] = NrgMid<<1;
+ bandEnergySide[i] = NrgSide<<1;
+ }
+
+ if(calcLdData) {
+ LdDataVector(bandEnergyMid, bandEnergyMidLdData, numBands);
+ LdDataVector(bandEnergySide, bandEnergySideLdData, numBands);
+ }
+
+ for (i=0; i<numBands; i++)
+ {
+ INT minScale = fixMin(sfbMaxScaleSpecLeft[i], sfbMaxScaleSpecRight[i]);
+ INT scale = fixMax(0, 2*(minScale-4));
+
+ if (calcLdData)
+ {
+ /* using the minimal scaling of left and right channel can cause very small energies;
+ check ldNrg before subtract scaling multiplication: fract*INT we don't need fMult */
+
+ int minus = scale*FL2FXCONST_DBL(1.0/64);
+
+ if (bandEnergyMidLdData[i] != FL2FXCONST_DBL(-1.0f))
+ bandEnergyMidLdData[i] -= minus;
+
+ if (bandEnergySideLdData[i] != FL2FXCONST_DBL(-1.0f))
+ bandEnergySideLdData[i] -= minus;
+ }
+ scale = fixMin(scale, (DFRACT_BITS-1));
+ bandEnergyMid[i] >>= scale;
+ bandEnergySide[i] >>= scale;
+ }
+}
diff --git a/libAACenc/src/band_nrg.h b/libAACenc/src/band_nrg.h
new file mode 100644
index 0000000..23a207b
--- /dev/null
+++ b/libAACenc/src/band_nrg.h
@@ -0,0 +1,86 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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): M. Werner
+ Description: Band/Line energy calculation
+
+ 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 _BAND_NRG_H
+#define _BAND_NRG_H
+
+#include "common_fix.h"
+
+
+void
+FDKaacEnc_CalcSfbMaxScaleSpec(
+ const FIXP_DBL *mdctSpectrum,
+ const INT *bandOffset,
+ INT *sfbMaxScaleSpec,
+ const INT numBands
+ );
+
+FIXP_DBL
+FDKaacEnc_CheckBandEnergyOptim(
+ const FIXP_DBL *mdctSpectrum,
+ INT *sfbMaxScaleSpec,
+ const INT *bandOffset,
+ const INT numBands,
+ FIXP_DBL *bandEnergy,
+ FIXP_DBL *bandEnergyLdData,
+ INT minSpecShift
+ );
+
+INT
+FDKaacEnc_CalcBandEnergyOptimLong(
+ const FIXP_DBL *mdctSpectrum,
+ INT *sfbMaxScaleSpec,
+ const INT *bandOffset,
+ const INT numBands,
+ FIXP_DBL *bandEnergy,
+ FIXP_DBL *bandEnergyLdData
+ );
+
+void
+FDKaacEnc_CalcBandEnergyOptimShort(
+ const FIXP_DBL *mdctSpectrum,
+ INT *sfbMaxScaleSpec,
+ const INT *bandOffset,
+ const INT numBands,
+ FIXP_DBL *bandEnergy
+ );
+
+
+void FDKaacEnc_CalcBandNrgMSOpt(
+ const FIXP_DBL *RESTRICT mdctSpectrumLeft,
+ const FIXP_DBL *RESTRICT mdctSpectrumRight,
+ INT *RESTRICT sfbMaxScaleSpecLeft,
+ INT *RESTRICT sfbMaxScaleSpecRight,
+ const INT *RESTRICT bandOffset,
+ const INT numBands,
+ FIXP_DBL *RESTRICT bandEnergyMid,
+ FIXP_DBL *RESTRICT bandEnergySide,
+ INT calcLdData,
+ FIXP_DBL *RESTRICT bandEnergyMidLdData,
+ FIXP_DBL *RESTRICT bandEnergySideLdData);
+
+#endif
diff --git a/libAACenc/src/bandwidth.cpp b/libAACenc/src/bandwidth.cpp
new file mode 100644
index 0000000..51c3a33
--- /dev/null
+++ b/libAACenc/src/bandwidth.cpp
@@ -0,0 +1,316 @@
+/************************* Fast MPEG AAC Audio Encoder **********************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Schug / A. Groeschel
+ contents/description: bandwidth expert
+
+******************************************************************************/
+
+#include "channel_map.h"
+#include "bandwidth.h"
+#include "aacEnc_ram.h"
+
+typedef struct{
+ INT chanBitRate;
+ INT bandWidthMono;
+ INT bandWidth2AndMoreChan;
+
+} BANDWIDTH_TAB;
+
+static const BANDWIDTH_TAB bandWidthTable[] = {
+ {0, 3700, 5000},
+ {12000, 5000, 6400},
+ {20000, 6900, 9640},
+ {28000, 9600, 13050},
+ {40000, 12060, 14260},
+ {56000, 13950, 15500},
+ {72000, 14200, 16120},
+ {96000, 17000, 17000},
+ {576001,17000, 17000}
+};
+
+
+static const BANDWIDTH_TAB bandWidthTable_LD_22050[] = {
+ { 8000, 2000, 2400},
+ {12000, 2500, 2700},
+ {16000, 3300, 3100},
+ {24000, 6250, 7200},
+ {32000, 9200, 10500},
+ {40000, 16000, 16000},
+ {48000, 16000, 16000},
+ {360001, 16000, 16000}
+};
+
+static const BANDWIDTH_TAB bandWidthTable_LD_24000[] = {
+ { 8000, 2000, 2000},
+ {12000, 2000, 2300},
+ {16000, 2200, 2500},
+ {24000, 5650, 6400},
+ {32000, 11600, 12000},
+ {40000, 12000, 16000},
+ {48000, 16000, 16000},
+ {64000, 16000, 16000},
+ {360001, 16000, 16000}
+};
+
+static const BANDWIDTH_TAB bandWidthTable_LD_32000[] = {
+ { 8000, 2000, 2000},
+ {12000, 2000, 2000},
+ {24000, 4250, 5200},
+ {32000, 8400, 9000},
+ {40000, 9400, 11300},
+ {48000, 11900, 13700},
+ {64000, 14800, 16000},
+ {76000, 16000, 16000},
+ {360001, 16000, 16000}
+};
+
+static const BANDWIDTH_TAB bandWidthTable_LD_44100[] = {
+ { 8000, 2000, 2000},
+ {24000, 2000, 2000},
+ {32000, 4400, 5700},
+ {40000, 7400, 8800},
+ {48000, 9000, 10700},
+ {56000, 11000, 12900},
+ {64000, 14400, 15500},
+ {80000, 16000, 16200},
+ {96000, 16500, 16000},
+ {128000, 16000, 16000},
+ {360001, 16000, 16000}
+};
+
+static const BANDWIDTH_TAB bandWidthTable_LD_48000[] = {
+ { 8000, 2000, 2000},
+ {24000, 2000, 2000},
+ {32000, 4400, 5700},
+ {40000, 7400, 8800},
+ {48000, 9000, 10700},
+ {56000, 11000, 12800},
+ {64000, 14300, 15400},
+ {80000, 16000, 16200},
+ {96000, 16500, 16000},
+ {128000, 16000, 16000},
+ {360001, 16000, 16000}
+};
+
+typedef struct{
+ AACENC_BITRATE_MODE bitrateMode;
+ int bandWidthMono;
+ int bandWidth2AndMoreChan;
+} BANDWIDTH_TAB_VBR;
+
+static const BANDWIDTH_TAB_VBR bandWidthTableVBR[]= {
+ {AACENC_BR_MODE_CBR, 0, 0},
+ {AACENC_BR_MODE_VBR_1, 13050, 13050},
+ {AACENC_BR_MODE_VBR_2, 13050, 13050},
+ {AACENC_BR_MODE_VBR_3, 14260, 14260},
+ {AACENC_BR_MODE_VBR_4, 15500, 15500},
+ {AACENC_BR_MODE_VBR_5, 48000, 48000},
+ {AACENC_BR_MODE_SFR, 0, 0},
+ {AACENC_BR_MODE_FF, 0, 0}
+
+};
+
+static INT GetBandwidthEntry(
+ const INT frameLength,
+ const INT sampleRate,
+ const INT chanBitRate,
+ const INT entryNo)
+{
+ INT bandwidth = -1;
+ const BANDWIDTH_TAB *pBwTab = NULL;
+ INT bwTabSize = 0;
+
+ switch (frameLength) {
+ case 960:
+ case 1024:
+ pBwTab = bandWidthTable;
+ bwTabSize = sizeof(bandWidthTable)/sizeof(BANDWIDTH_TAB);
+ break;
+ case 480:
+ case 512:
+ switch (sampleRate) {
+ case 8000:
+ case 11025:
+ case 12000:
+ case 16000:
+ case 22050:
+ pBwTab = bandWidthTable_LD_22050;
+ bwTabSize = sizeof(bandWidthTable_LD_22050)/sizeof(BANDWIDTH_TAB);
+ break;
+ case 24000:
+ pBwTab = bandWidthTable_LD_24000;
+ bwTabSize = sizeof(bandWidthTable_LD_24000)/sizeof(BANDWIDTH_TAB);
+ break;
+ case 32000:
+ pBwTab = bandWidthTable_LD_32000;
+ bwTabSize = sizeof(bandWidthTable_LD_32000)/sizeof(BANDWIDTH_TAB);
+ break;
+ case (44100):
+ pBwTab = bandWidthTable_LD_44100;
+ bwTabSize = sizeof(bandWidthTable_LD_44100)/sizeof(BANDWIDTH_TAB);
+ break;
+ case 48000:
+ case 64000:
+ case 88200:
+ case 96000:
+ pBwTab = bandWidthTable_LD_48000;
+ bwTabSize = sizeof(bandWidthTable_LD_48000)/sizeof(BANDWIDTH_TAB);
+ break;
+ }
+ break;
+ default:
+ pBwTab = NULL;
+ bwTabSize = 0;
+ }
+
+ if (pBwTab!=NULL) {
+ int i;
+ for (i=0; i<bwTabSize-1; i++) {
+ if (chanBitRate >= pBwTab[i].chanBitRate &&
+ chanBitRate < pBwTab[i+1].chanBitRate)
+ {
+ switch (frameLength) {
+ case 960:
+ case 1024:
+ bandwidth = (entryNo==0)
+ ? pBwTab[i].bandWidthMono
+ : pBwTab[i].bandWidth2AndMoreChan;
+ break;
+ case 480:
+ case 512:
+ {
+ INT q_res = 0;
+ INT startBw = (entryNo==0) ? pBwTab[i ].bandWidthMono : pBwTab[i ].bandWidth2AndMoreChan;
+ INT endBw = (entryNo==0) ? pBwTab[i+1].bandWidthMono : pBwTab[i+1].bandWidth2AndMoreChan;
+ INT startBr = pBwTab[i].chanBitRate;
+ INT endBr = pBwTab[i+1].chanBitRate;
+
+ FIXP_DBL bwFac_fix = fDivNorm(chanBitRate-startBr, endBr-startBr, &q_res);
+ bandwidth = (INT)scaleValue(fMult(bwFac_fix, (FIXP_DBL)(endBw-startBw)),q_res) + startBw;
+ }
+ break;
+ default:
+ bandwidth = -1;
+ }
+ break;
+ } /* within bitrate range */
+ }
+ } /* pBwTab!=NULL */
+
+ return bandwidth;
+}
+
+
+AAC_ENCODER_ERROR FDKaacEnc_DetermineBandWidth(INT* bandWidth,
+ INT proposedBandWidth,
+ INT bitrate,
+ AACENC_BITRATE_MODE bitrateMode,
+ INT sampleRate,
+ INT frameLength,
+ CHANNEL_MAPPING* cm,
+ CHANNEL_MODE encoderMode)
+{
+ AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK;
+ //FIXP_DBL invBandWidthGain=FL2FXCONST_DBL(1.f);
+ INT chanBitRate = bitrate/cm->nChannels;
+
+ /* vbr */
+ switch(bitrateMode){
+ case AACENC_BR_MODE_VBR_1:
+ case AACENC_BR_MODE_VBR_2:
+ case AACENC_BR_MODE_VBR_3:
+ case AACENC_BR_MODE_VBR_4:
+ case AACENC_BR_MODE_VBR_5:
+ if (proposedBandWidth != 0){
+ /* use given bw */
+ *bandWidth = proposedBandWidth;
+ } else {
+ /* take bw from table */
+ switch(encoderMode){
+ case MODE_1:
+ *bandWidth = bandWidthTableVBR[bitrateMode].bandWidthMono;
+ break;
+ case MODE_2:
+ case MODE_1_2:
+ case MODE_1_2_1:
+ case MODE_1_2_2:
+ case MODE_1_2_2_1:
+ case MODE_1_2_2_2_1:
+ *bandWidth = bandWidthTableVBR[bitrateMode].bandWidth2AndMoreChan;
+ break;
+ default:
+ return AAC_ENC_UNSUPPORTED_CHANNELCONFIG;
+ }
+ }
+ break;
+ case AACENC_BR_MODE_CBR:
+ case AACENC_BR_MODE_SFR:
+ case AACENC_BR_MODE_FF:
+
+ /* bandwidth limiting */
+ if (proposedBandWidth != 0) {
+ *bandWidth = FDKmin(proposedBandWidth, FDKmin(20000, sampleRate>>1));
+ }
+ else { /* search reasonable bandwidth */
+
+ int entryNo = 0;
+
+ switch(encoderMode){
+ case MODE_1: /* mono */
+ entryNo = 0; /* use mono bandwith settings */
+ break;
+
+ case MODE_2: /* stereo */
+ case MODE_1_2: /* sce + cpe */
+ case MODE_1_2_1: /* sce + cpe + sce */
+ case MODE_1_2_2: /* sce + cpe + cpe */
+ case MODE_1_2_2_1: /* (5.1) sce + cpe + cpe + lfe */
+ case MODE_1_2_2_2_1: /* (7.1) sce + cpe + cpe + cpe + lfe */
+ entryNo = 1; /* use stereo bandwith settings */
+ break;
+
+ default:
+ return AAC_ENC_UNSUPPORTED_CHANNELCONFIG;
+ }
+
+ *bandWidth = GetBandwidthEntry(
+ frameLength,
+ sampleRate,
+ chanBitRate,
+ entryNo);
+
+ if (*bandWidth==-1) {
+ ErrorStatus = AAC_ENC_INVALID_CHANNEL_BITRATE;
+ }
+ }
+ break;
+ default:
+ *bandWidth = 0;
+ return AAC_ENC_UNSUPPORTED_BITRATE_MODE;
+ }
+
+ *bandWidth = FDKmin(*bandWidth, sampleRate/2);
+
+ return ErrorStatus;;
+}
diff --git a/libAACenc/src/bandwidth.h b/libAACenc/src/bandwidth.h
new file mode 100644
index 0000000..e58ab94
--- /dev/null
+++ b/libAACenc/src/bandwidth.h
@@ -0,0 +1,44 @@
+/************************* Fast MPEG AAC Audio Encoder **********************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Schug / A. Groeschel
+ contents/description: bandwidth expert
+
+******************************************************************************/
+
+#ifndef _BANDWIDTH_H
+#define _BANDWIDTH_H
+
+
+#include "qc_data.h"
+
+AAC_ENCODER_ERROR FDKaacEnc_DetermineBandWidth(INT* bandWidth,
+ INT proposedBandwidth,
+ INT bitrate,
+ AACENC_BITRATE_MODE bitrateMode,
+ INT sampleRate,
+ INT frameLength,
+ CHANNEL_MAPPING* cm,
+ CHANNEL_MODE encoderMode);
+
+#endif /* BANDWIDTH_H */
diff --git a/libAACenc/src/bit_cnt.cpp b/libAACenc/src/bit_cnt.cpp
new file mode 100644
index 0000000..f1a9b73
--- /dev/null
+++ b/libAACenc/src/bit_cnt.cpp
@@ -0,0 +1,1060 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Huffman Bitcounter & coder
+
+******************************************************************************/
+
+#include "bit_cnt.h"
+
+#include "aacEnc_ram.h"
+
+#define HI_LTAB(a) (a>>16)
+#define LO_LTAB(a) (a & 0xffff)
+
+/*****************************************************************************
+
+
+ functionname: FDKaacEnc_count1_2_3_4_5_6_7_8_9_10_11
+ description: counts tables 1-11
+ returns:
+ input: quantized spectrum
+ output: bitCount for tables 1-11
+
+*****************************************************************************/
+
+static void FDKaacEnc_count1_2_3_4_5_6_7_8_9_10_11(const SHORT *RESTRICT values,
+ const INT width,
+ INT *bitCount)
+{
+
+ INT i;
+ INT bc1_2,bc3_4,bc5_6,bc7_8,bc9_10,bc11,sc;
+ INT t0,t1,t2,t3;
+ bc1_2=0;
+ bc3_4=0;
+ bc5_6=0;
+ bc7_8=0;
+ bc9_10=0;
+ bc11=0;
+ sc=0;
+
+ for(i=0;i<width;i+=4){
+
+ t0= values[i+0];
+ t1= values[i+1];
+ t2= values[i+2];
+ t3= values[i+3];
+
+ /* 1,2 */
+
+ bc1_2+=FDKaacEnc_huff_ltab1_2[t0+1][t1+1][t2+1][t3+1];
+
+ /* 5,6 */
+ bc5_6+=FDKaacEnc_huff_ltab5_6[t0+4][t1+4];
+ bc5_6+=FDKaacEnc_huff_ltab5_6[t2+4][t3+4];
+
+ t0=fixp_abs(t0);
+ t1=fixp_abs(t1);
+ t2=fixp_abs(t2);
+ t3=fixp_abs(t3);
+
+
+ bc3_4+= FDKaacEnc_huff_ltab3_4[t0][t1][t2][t3];
+
+ bc7_8+=FDKaacEnc_huff_ltab7_8[t0][t1];
+ bc7_8+=FDKaacEnc_huff_ltab7_8[t2][t3];
+
+ bc9_10+=FDKaacEnc_huff_ltab9_10[t0][t1];
+ bc9_10+=FDKaacEnc_huff_ltab9_10[t2][t3];
+
+ bc11+= (INT) FDKaacEnc_huff_ltab11[t0][t1];
+ bc11+= (INT) FDKaacEnc_huff_ltab11[t2][t3];
+
+ sc+=(t0>0)+(t1>0)+(t2>0)+(t3>0);
+ }
+
+ bitCount[1]=HI_LTAB(bc1_2);
+ bitCount[2]=LO_LTAB(bc1_2);
+ bitCount[3]=HI_LTAB(bc3_4)+sc;
+ bitCount[4]=LO_LTAB(bc3_4)+sc;
+ bitCount[5]=HI_LTAB(bc5_6);
+ bitCount[6]=LO_LTAB(bc5_6);
+ bitCount[7]=HI_LTAB(bc7_8)+sc;
+ bitCount[8]=LO_LTAB(bc7_8)+sc;
+ bitCount[9]=HI_LTAB(bc9_10)+sc;
+ bitCount[10]=LO_LTAB(bc9_10)+sc;
+ bitCount[11]=bc11+sc;
+
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_count3_4_5_6_7_8_9_10_11
+ description: counts tables 3-11
+ returns:
+ input: quantized spectrum
+ output: bitCount for tables 3-11
+
+*****************************************************************************/
+
+static void FDKaacEnc_count3_4_5_6_7_8_9_10_11(const SHORT *RESTRICT values,
+ const INT width,
+ INT *bitCount)
+{
+
+ INT i;
+ INT bc3_4,bc5_6,bc7_8,bc9_10,bc11,sc;
+ INT t0,t1,t2,t3;
+
+ bc3_4=0;
+ bc5_6=0;
+ bc7_8=0;
+ bc9_10=0;
+ bc11=0;
+ sc=0;
+
+ for(i=0;i<width;i+=4){
+
+ t0= values[i+0];
+ t1= values[i+1];
+ t2= values[i+2];
+ t3= values[i+3];
+
+ bc5_6+=FDKaacEnc_huff_ltab5_6[t0+4][t1+4];
+ bc5_6+=FDKaacEnc_huff_ltab5_6[t2+4][t3+4];
+
+ t0=fixp_abs(t0);
+ t1=fixp_abs(t1);
+ t2=fixp_abs(t2);
+ t3=fixp_abs(t3);
+
+ bc3_4+= FDKaacEnc_huff_ltab3_4[t0][t1][t2][t3];
+
+ bc7_8+=FDKaacEnc_huff_ltab7_8[t0][t1];
+ bc7_8+=FDKaacEnc_huff_ltab7_8[t2][t3];
+
+ bc9_10+=FDKaacEnc_huff_ltab9_10[t0][t1];
+ bc9_10+=FDKaacEnc_huff_ltab9_10[t2][t3];
+
+ bc11+= (INT) FDKaacEnc_huff_ltab11[t0][t1];
+ bc11+= (INT) FDKaacEnc_huff_ltab11[t2][t3];
+
+ sc+=(t0>0)+(t1>0)+(t2>0)+(t3>0);
+ }
+
+ bitCount[1]=INVALID_BITCOUNT;
+ bitCount[2]=INVALID_BITCOUNT;
+ bitCount[3]=HI_LTAB(bc3_4)+sc;
+ bitCount[4]=LO_LTAB(bc3_4)+sc;
+ bitCount[5]=HI_LTAB(bc5_6);
+ bitCount[6]=LO_LTAB(bc5_6);
+ bitCount[7]=HI_LTAB(bc7_8)+sc;
+ bitCount[8]=LO_LTAB(bc7_8)+sc;
+ bitCount[9]=HI_LTAB(bc9_10)+sc;
+ bitCount[10]=LO_LTAB(bc9_10)+sc;
+ bitCount[11]=bc11+sc;
+}
+
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_count5_6_7_8_9_10_11
+ description: counts tables 5-11
+ returns:
+ input: quantized spectrum
+ output: bitCount for tables 5-11
+
+*****************************************************************************/
+
+
+static void FDKaacEnc_count5_6_7_8_9_10_11(const SHORT *RESTRICT values,
+ const INT width,
+ INT *bitCount)
+{
+
+ INT i;
+ INT bc5_6,bc7_8,bc9_10,bc11,sc;
+ INT t0,t1;
+ bc5_6=0;
+ bc7_8=0;
+ bc9_10=0;
+ bc11=0;
+ sc=0;
+
+ for(i=0;i<width;i+=2){
+
+ t0 = values[i+0];
+ t1 = values[i+1];
+
+ bc5_6+=FDKaacEnc_huff_ltab5_6[t0+4][t1+4];
+
+ t0=fixp_abs(t0);
+ t1=fixp_abs(t1);
+
+ bc7_8+=FDKaacEnc_huff_ltab7_8[t0][t1];
+ bc9_10+=FDKaacEnc_huff_ltab9_10[t0][t1];
+ bc11+= (INT) FDKaacEnc_huff_ltab11[t0][t1];
+
+ sc+=(t0>0)+(t1>0);
+ }
+ bitCount[1]=INVALID_BITCOUNT;
+ bitCount[2]=INVALID_BITCOUNT;
+ bitCount[3]=INVALID_BITCOUNT;
+ bitCount[4]=INVALID_BITCOUNT;
+ bitCount[5]=HI_LTAB(bc5_6);
+ bitCount[6]=LO_LTAB(bc5_6);
+ bitCount[7]=HI_LTAB(bc7_8)+sc;
+ bitCount[8]=LO_LTAB(bc7_8)+sc;
+ bitCount[9]=HI_LTAB(bc9_10)+sc;
+ bitCount[10]=LO_LTAB(bc9_10)+sc;
+ bitCount[11]=bc11+sc;
+
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_count7_8_9_10_11
+ description: counts tables 7-11
+ returns:
+ input: quantized spectrum
+ output: bitCount for tables 7-11
+
+*****************************************************************************/
+
+static void FDKaacEnc_count7_8_9_10_11(const SHORT *RESTRICT values,
+ const INT width,
+ INT *bitCount)
+{
+
+ INT i;
+ INT bc7_8,bc9_10,bc11,sc;
+ INT t0,t1;
+
+ bc7_8=0;
+ bc9_10=0;
+ bc11=0;
+ sc=0;
+
+ for(i=0;i<width;i+=2){
+ t0=fixp_abs(values[i+0]);
+ t1=fixp_abs(values[i+1]);
+
+ bc7_8+=FDKaacEnc_huff_ltab7_8[t0][t1];
+ bc9_10+=FDKaacEnc_huff_ltab9_10[t0][t1];
+ bc11+= (INT) FDKaacEnc_huff_ltab11[t0][t1];
+ sc+=(t0>0)+(t1>0);
+ }
+
+ bitCount[1]=INVALID_BITCOUNT;
+ bitCount[2]=INVALID_BITCOUNT;
+ bitCount[3]=INVALID_BITCOUNT;
+ bitCount[4]=INVALID_BITCOUNT;
+ bitCount[5]=INVALID_BITCOUNT;
+ bitCount[6]=INVALID_BITCOUNT;
+ bitCount[7]=HI_LTAB(bc7_8)+sc;
+ bitCount[8]=LO_LTAB(bc7_8)+sc;
+ bitCount[9]=HI_LTAB(bc9_10)+sc;
+ bitCount[10]=LO_LTAB(bc9_10)+sc;
+ bitCount[11]=bc11+sc;
+
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_count9_10_11
+ description: counts tables 9-11
+ returns:
+ input: quantized spectrum
+ output: bitCount for tables 9-11
+
+*****************************************************************************/
+
+
+
+static void FDKaacEnc_count9_10_11(const SHORT *RESTRICT values,
+ const INT width,
+ INT *bitCount)
+{
+
+ INT i;
+ INT bc9_10,bc11,sc;
+ INT t0,t1;
+
+ bc9_10=0;
+ bc11=0;
+ sc=0;
+
+ for(i=0;i<width;i+=2){
+ t0=fixp_abs(values[i+0]);
+ t1=fixp_abs(values[i+1]);
+
+ bc9_10+=FDKaacEnc_huff_ltab9_10[t0][t1];
+ bc11+= (INT) FDKaacEnc_huff_ltab11[t0][t1];
+
+ sc+=(t0>0)+(t1>0);
+ }
+
+ bitCount[1]=INVALID_BITCOUNT;
+ bitCount[2]=INVALID_BITCOUNT;
+ bitCount[3]=INVALID_BITCOUNT;
+ bitCount[4]=INVALID_BITCOUNT;
+ bitCount[5]=INVALID_BITCOUNT;
+ bitCount[6]=INVALID_BITCOUNT;
+ bitCount[7]=INVALID_BITCOUNT;
+ bitCount[8]=INVALID_BITCOUNT;
+ bitCount[9]=HI_LTAB(bc9_10)+sc;
+ bitCount[10]=LO_LTAB(bc9_10)+sc;
+ bitCount[11]=bc11+sc;
+
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_count11
+ description: counts table 11
+ returns:
+ input: quantized spectrum
+ output: bitCount for table 11
+
+*****************************************************************************/
+
+static void FDKaacEnc_count11(const SHORT *RESTRICT values,
+ const INT width,
+ INT *bitCount)
+{
+
+ INT i;
+ INT bc11,sc;
+ INT t0,t1;
+
+ bc11=0;
+ sc=0;
+ for(i=0;i<width;i+=2){
+ t0=fixp_abs(values[i+0]);
+ t1=fixp_abs(values[i+1]);
+ bc11+= (INT) FDKaacEnc_huff_ltab11[t0][t1];
+ sc+=(t0>0)+(t1>0);
+ }
+
+ bitCount[1]=INVALID_BITCOUNT;
+ bitCount[2]=INVALID_BITCOUNT;
+ bitCount[3]=INVALID_BITCOUNT;
+ bitCount[4]=INVALID_BITCOUNT;
+ bitCount[5]=INVALID_BITCOUNT;
+ bitCount[6]=INVALID_BITCOUNT;
+ bitCount[7]=INVALID_BITCOUNT;
+ bitCount[8]=INVALID_BITCOUNT;
+ bitCount[9]=INVALID_BITCOUNT;
+ bitCount[10]=INVALID_BITCOUNT;
+ bitCount[11]=bc11+sc;
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_countEsc
+ description: counts table 11 (with Esc)
+ returns:
+ input: quantized spectrum
+ output: bitCount for tables 11 (with Esc)
+
+*****************************************************************************/
+
+static void FDKaacEnc_countEsc(const SHORT *RESTRICT values,
+ const INT width,
+ INT *RESTRICT bitCount)
+{
+
+ INT i;
+ INT bc11,ec,sc;
+ INT t0,t1,t00,t01;
+
+ bc11=0;
+ sc=0;
+ ec=0;
+ for(i=0;i<width;i+=2){
+ t0=fixp_abs(values[i+0]);
+ t1=fixp_abs(values[i+1]);
+
+ sc+=(t0>0)+(t1>0);
+
+ t00 = fixMin(t0,16);
+ t01 = fixMin(t1,16);
+ bc11+= (INT) FDKaacEnc_huff_ltab11[t00][t01];
+
+ if(t0>=16){
+ ec+=5;
+ while((t0>>=1) >= 16)
+ ec+=2;
+ }
+
+ if(t1>=16){
+ ec+=5;
+ while((t1>>=1) >= 16)
+ ec+=2;
+ }
+ }
+
+ for (i=0; i<11; i++)
+ bitCount[i]=INVALID_BITCOUNT;
+
+ bitCount[11]=bc11+sc+ec;
+}
+
+
+typedef void (*COUNT_FUNCTION)(const SHORT *RESTRICT values,
+ const INT width,
+ INT *RESTRICT bitCount);
+
+static const COUNT_FUNCTION countFuncTable[CODE_BOOK_ESC_LAV+1] =
+{
+
+ FDKaacEnc_count1_2_3_4_5_6_7_8_9_10_11, /* 0 */
+ FDKaacEnc_count1_2_3_4_5_6_7_8_9_10_11, /* 1 */
+ FDKaacEnc_count3_4_5_6_7_8_9_10_11, /* 2 */
+ FDKaacEnc_count5_6_7_8_9_10_11, /* 3 */
+ FDKaacEnc_count5_6_7_8_9_10_11, /* 4 */
+ FDKaacEnc_count7_8_9_10_11, /* 5 */
+ FDKaacEnc_count7_8_9_10_11, /* 6 */
+ FDKaacEnc_count7_8_9_10_11, /* 7 */
+ FDKaacEnc_count9_10_11, /* 8 */
+ FDKaacEnc_count9_10_11, /* 9 */
+ FDKaacEnc_count9_10_11, /* 10 */
+ FDKaacEnc_count9_10_11, /* 11 */
+ FDKaacEnc_count9_10_11, /* 12 */
+ FDKaacEnc_count11, /* 13 */
+ FDKaacEnc_count11, /* 14 */
+ FDKaacEnc_count11, /* 15 */
+ FDKaacEnc_countEsc /* 16 */
+};
+
+
+
+INT FDKaacEnc_bitCount(const SHORT *values,
+ const INT width,
+ INT maxVal,
+ INT *bitCount)
+{
+
+ /*
+ check if we can use codebook 0
+ */
+
+ if(maxVal == 0)
+ bitCount[0] = 0;
+ else
+ bitCount[0] = INVALID_BITCOUNT;
+
+ maxVal = fixMin(maxVal,(INT)CODE_BOOK_ESC_LAV);
+ countFuncTable[maxVal](values,width,bitCount);
+ return(0);
+}
+
+
+
+
+/*
+ count difference between actual and zeroed lines
+*/
+INT FDKaacEnc_countValues(SHORT *RESTRICT values, INT width, INT codeBook)
+{
+
+ INT i,t0,t1,t2,t3,t00,t01;
+ INT codeLength;
+ INT signLength;
+ INT bitCnt=0;
+
+ switch(codeBook){
+ case CODE_BOOK_ZERO_NO:
+ break;
+
+ case CODE_BOOK_1_NO:
+ for(i=0; i<width; i+=4) {
+ t0 = values[i+0];
+ t1 = values[i+1];
+ t2 = values[i+2];
+ t3 = values[i+3];
+ codeLength = HI_LTAB(FDKaacEnc_huff_ltab1_2[t0+1][t1+1][t2+1][t3+1]);
+ bitCnt+= codeLength;
+ }
+ break;
+
+ case CODE_BOOK_2_NO:
+ for(i=0; i<width; i+=4) {
+ t0 = values[i+0];
+ t1 = values[i+1];
+ t2 = values[i+2];
+ t3 = values[i+3];
+ codeLength = LO_LTAB(FDKaacEnc_huff_ltab1_2[t0+1][t1+1][t2+1][t3+1]);
+ bitCnt+= codeLength;
+ }
+ break;
+
+ case CODE_BOOK_3_NO:
+ for(i=0; i<width; i+=4) {
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ t0=fixp_abs(t0);
+ }
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ t1=fixp_abs(t1);
+ }
+ t2 = values[i+2];
+ if(t2 != 0){
+ signLength++;
+ t2=fixp_abs(t2);
+ }
+ t3 = values[i+3];
+ if(t3 != 0){
+ signLength++;
+ t3=fixp_abs(t3);
+ }
+
+ codeLength = HI_LTAB(FDKaacEnc_huff_ltab3_4[t0][t1][t2][t3]);
+ bitCnt+=codeLength+signLength;
+ }
+ break;
+
+ case CODE_BOOK_4_NO:
+ for(i=0; i<width; i+=4) {
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ t0=fixp_abs(t0);
+ }
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ t1=fixp_abs(t1);
+ }
+ t2 = values[i+2];
+ if(t2 != 0){
+ signLength++;
+ t2=fixp_abs(t2);
+ }
+ t3 = values[i+3];
+ if(t3 != 0){
+ signLength++;
+ t3=fixp_abs(t3);
+ }
+ codeLength = LO_LTAB(FDKaacEnc_huff_ltab3_4[t0][t1][t2][t3]);
+ bitCnt+=codeLength+signLength;
+ }
+ break;
+
+ case CODE_BOOK_5_NO:
+ for(i=0; i<width; i+=2) {
+ t0 = values[i+0];
+ t1 = values[i+1];
+ codeLength = HI_LTAB(FDKaacEnc_huff_ltab5_6[t0+4][t1+4]);
+ bitCnt+=codeLength;
+ }
+ break;
+
+ case CODE_BOOK_6_NO:
+ for(i=0; i<width; i+=2) {
+ t0 = values[i+0];
+ t1 = values[i+1];
+ codeLength = LO_LTAB(FDKaacEnc_huff_ltab5_6[t0+4][t1+4]);
+ bitCnt+=codeLength;
+ }
+ break;
+
+ case CODE_BOOK_7_NO:
+ for(i=0; i<width; i+=2){
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ t0=fixp_abs(t0);
+ }
+
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ t1=fixp_abs(t1);
+ }
+ codeLength = HI_LTAB(FDKaacEnc_huff_ltab7_8[t0][t1]);
+ bitCnt+=codeLength +signLength;
+ }
+ break;
+
+ case CODE_BOOK_8_NO:
+ for(i=0; i<width; i+=2) {
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ t0=fixp_abs(t0);
+ }
+
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ t1=fixp_abs(t1);
+ }
+ codeLength = LO_LTAB(FDKaacEnc_huff_ltab7_8[t0][t1]);
+ bitCnt+=codeLength +signLength;
+ }
+ break;
+
+ case CODE_BOOK_9_NO:
+ for(i=0; i<width; i+=2) {
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ t0=fixp_abs(t0);
+ }
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ t1=fixp_abs(t1);
+ }
+ codeLength = HI_LTAB(FDKaacEnc_huff_ltab9_10[t0][t1]);
+ bitCnt+=codeLength +signLength;
+ }
+ break;
+
+ case CODE_BOOK_10_NO:
+ for(i=0; i<width; i+=2) {
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ t0=fixp_abs(t0);
+ }
+
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ t1=fixp_abs(t1);
+ }
+ codeLength = LO_LTAB(FDKaacEnc_huff_ltab9_10[t0][t1]);
+ bitCnt+=codeLength +signLength;
+ }
+ break;
+
+ case CODE_BOOK_ESC_NO:
+ for(i=0; i<width; i+=2) {
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ t0=fixp_abs(t0);
+ }
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ t1=fixp_abs(t1);
+ }
+ t00 = fixMin(t0,16);
+ t01 = fixMin(t1,16);
+
+ codeLength = (INT) FDKaacEnc_huff_ltab11[t00][t01];
+ bitCnt+=codeLength +signLength;
+ if(t0 >=16){
+ INT n,p;
+ n=0;
+ p=t0;
+ while((p>>=1) >=16){
+ bitCnt++;
+ n++;
+ }
+ bitCnt+=(n+5);
+ }
+ if(t1 >=16){
+ INT n,p;
+ n=0;
+ p=t1;
+ while((p>>=1) >=16){
+ bitCnt++;
+ n++;
+ }
+ bitCnt+=(n+5);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return(bitCnt);
+}
+
+
+
+INT FDKaacEnc_codeValues(SHORT *RESTRICT values, INT width, INT codeBook, HANDLE_FDK_BITSTREAM hBitstream)
+{
+
+ INT i,t0,t1,t2,t3,t00,t01;
+ INT codeWord,codeLength;
+ INT sign,signLength;
+
+ switch(codeBook){
+ case CODE_BOOK_ZERO_NO:
+ break;
+
+ case CODE_BOOK_1_NO:
+ for(i=0; i<width; i+=4) {
+ t0 = values[i+0]+1;
+ t1 = values[i+1]+1;
+ t2 = values[i+2]+1;
+ t3 = values[i+3]+1;
+ codeWord = FDKaacEnc_huff_ctab1[t0][t1][t2][t3];
+ codeLength = HI_LTAB(FDKaacEnc_huff_ltab1_2[t0][t1][t2][t3]);
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ }
+ break;
+
+ case CODE_BOOK_2_NO:
+ for(i=0; i<width; i+=4) {
+ t0 = values[i+0]+1;
+ t1 = values[i+1]+1;
+ t2 = values[i+2]+1;
+ t3 = values[i+3]+1;
+ codeWord = FDKaacEnc_huff_ctab2[t0][t1][t2][t3];
+ codeLength = LO_LTAB(FDKaacEnc_huff_ltab1_2[t0][t1][t2][t3]);
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ }
+ break;
+
+ case CODE_BOOK_3_NO:
+ for(i=0; i<width; i+=4) {
+ sign=0;
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ sign<<=1;
+ if(t0 < 0){
+ sign|=1;
+ t0=fixp_abs(t0);
+ }
+ }
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ sign<<=1;
+ if(t1 < 0){
+ sign|=1;
+ t1=fixp_abs(t1);
+ }
+ }
+ t2 = values[i+2];
+ if(t2 != 0){
+ signLength++;
+ sign<<=1;
+ if(t2 < 0){
+ sign|=1;
+ t2=fixp_abs(t2);
+ }
+ }
+ t3 = values[i+3];
+ if(t3 != 0){
+ signLength++;
+ sign<<=1;
+ if(t3 < 0){
+ sign|=1;
+ t3=fixp_abs(t3);
+ }
+ }
+
+ codeWord = FDKaacEnc_huff_ctab3[t0][t1][t2][t3];
+ codeLength = HI_LTAB(FDKaacEnc_huff_ltab3_4[t0][t1][t2][t3]);
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ FDKwriteBits(hBitstream,sign,signLength);
+ }
+ break;
+
+ case CODE_BOOK_4_NO:
+ for(i=0; i<width; i+=4) {
+ sign=0;
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ sign<<=1;
+ if(t0 < 0){
+ sign|=1;
+ t0=fixp_abs(t0);
+ }
+ }
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ sign<<=1;
+ if(t1 < 0){
+ sign|=1;
+ t1=fixp_abs(t1);
+ }
+ }
+ t2 = values[i+2];
+ if(t2 != 0){
+ signLength++;
+ sign<<=1;
+ if(t2 < 0){
+ sign|=1;
+ t2=fixp_abs(t2);
+ }
+ }
+ t3 = values[i+3];
+ if(t3 != 0){
+ signLength++;
+ sign<<=1;
+ if(t3 < 0){
+ sign|=1;
+ t3=fixp_abs(t3);
+ }
+ }
+ codeWord = FDKaacEnc_huff_ctab4[t0][t1][t2][t3];
+ codeLength = LO_LTAB(FDKaacEnc_huff_ltab3_4[t0][t1][t2][t3]);
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ FDKwriteBits(hBitstream,sign,signLength);
+ }
+ break;
+
+ case CODE_BOOK_5_NO:
+ for(i=0; i<width; i+=2) {
+ t0 = values[i+0]+4;
+ t1 = values[i+1]+4;
+ codeWord = FDKaacEnc_huff_ctab5[t0][t1];
+ codeLength = HI_LTAB(FDKaacEnc_huff_ltab5_6[t0][t1]);
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ }
+ break;
+
+ case CODE_BOOK_6_NO:
+ for(i=0; i<width; i+=2) {
+ t0 = values[i+0]+4;
+ t1 = values[i+1]+4;
+ codeWord = FDKaacEnc_huff_ctab6[t0][t1];
+ codeLength = LO_LTAB(FDKaacEnc_huff_ltab5_6[t0][t1]);
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ }
+ break;
+
+ case CODE_BOOK_7_NO:
+ for(i=0; i<width; i+=2){
+ sign=0;
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ sign<<=1;
+ if(t0 < 0){
+ sign|=1;
+ t0=fixp_abs(t0);
+ }
+ }
+
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ sign<<=1;
+ if(t1 < 0){
+ sign|=1;
+ t1=fixp_abs(t1);
+ }
+ }
+ codeWord = FDKaacEnc_huff_ctab7[t0][t1];
+ codeLength = HI_LTAB(FDKaacEnc_huff_ltab7_8[t0][t1]);
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ FDKwriteBits(hBitstream,sign,signLength);
+ }
+ break;
+
+ case CODE_BOOK_8_NO:
+ for(i=0; i<width; i+=2) {
+ sign=0;
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ sign<<=1;
+ if(t0 < 0){
+ sign|=1;
+ t0=fixp_abs(t0);
+ }
+ }
+
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ sign<<=1;
+ if(t1 < 0){
+ sign|=1;
+ t1=fixp_abs(t1);
+ }
+ }
+ codeWord = FDKaacEnc_huff_ctab8[t0][t1];
+ codeLength = LO_LTAB(FDKaacEnc_huff_ltab7_8[t0][t1]);
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ FDKwriteBits(hBitstream,sign,signLength);
+ }
+ break;
+
+ case CODE_BOOK_9_NO:
+ for(i=0; i<width; i+=2) {
+ sign=0;
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ sign<<=1;
+ if(t0 < 0){
+ sign|=1;
+ t0=fixp_abs(t0);
+ }
+ }
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ sign<<=1;
+ if(t1 < 0){
+ sign|=1;
+ t1=fixp_abs(t1);
+ }
+ }
+ codeWord = FDKaacEnc_huff_ctab9[t0][t1];
+ codeLength = HI_LTAB(FDKaacEnc_huff_ltab9_10[t0][t1]);
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ FDKwriteBits(hBitstream,sign,signLength);
+ }
+ break;
+
+ case CODE_BOOK_10_NO:
+ for(i=0; i<width; i+=2) {
+ sign=0;
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ sign<<=1;
+ if(t0 < 0){
+ sign|=1;
+ t0=fixp_abs(t0);
+ }
+ }
+
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ sign<<=1;
+ if(t1 < 0){
+ sign|=1;
+ t1=fixp_abs(t1);
+ }
+ }
+ codeWord = FDKaacEnc_huff_ctab10[t0][t1];
+ codeLength = LO_LTAB(FDKaacEnc_huff_ltab9_10[t0][t1]);
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ FDKwriteBits(hBitstream,sign,signLength);
+ }
+ break;
+
+ case CODE_BOOK_ESC_NO:
+ for(i=0; i<width; i+=2) {
+ sign=0;
+ signLength=0;
+ t0 = values[i+0];
+ if(t0 != 0){
+ signLength++;
+ sign<<=1;
+ if(t0 < 0){
+ sign|=1;
+ t0=fixp_abs(t0);
+ }
+ }
+ t1 = values[i+1];
+ if(t1 != 0){
+ signLength++;
+ sign<<=1;
+ if(t1 < 0){
+ sign|=1;
+ t1=fixp_abs(t1);
+ }
+ }
+ t00 = fixMin(t0,16);
+ t01 = fixMin(t1,16);
+
+ codeWord = FDKaacEnc_huff_ctab11[t00][t01];
+ codeLength = (INT) FDKaacEnc_huff_ltab11[t00][t01];
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ FDKwriteBits(hBitstream,sign,signLength);
+ if(t0 >=16){
+ INT n,p;
+ n=0;
+ p=t0;
+ while((p>>=1) >=16){
+ FDKwriteBits(hBitstream,1,1);
+ n++;
+ }
+ FDKwriteBits(hBitstream,0,1);
+ FDKwriteBits(hBitstream,t0-(1<<(n+4)),n+4);
+ }
+ if(t1 >=16){
+ INT n,p;
+ n=0;
+ p=t1;
+ while((p>>=1) >=16){
+ FDKwriteBits(hBitstream,1,1);
+ n++;
+ }
+ FDKwriteBits(hBitstream,0,1);
+ FDKwriteBits(hBitstream,t1-(1<<(n+4)),n+4);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return(0);
+}
+
+INT FDKaacEnc_codeScalefactorDelta(INT delta, HANDLE_FDK_BITSTREAM hBitstream)
+{
+ INT codeWord,codeLength;
+
+ if(fixp_abs(delta) >CODE_BOOK_SCF_LAV)
+ return(1);
+
+ codeWord = FDKaacEnc_huff_ctabscf[delta+CODE_BOOK_SCF_LAV];
+ codeLength = (INT)FDKaacEnc_huff_ltabscf[delta+CODE_BOOK_SCF_LAV];
+ FDKwriteBits(hBitstream,codeWord,codeLength);
+ return(0);
+}
+
+
+
diff --git a/libAACenc/src/bit_cnt.h b/libAACenc/src/bit_cnt.h
new file mode 100644
index 0000000..6baf7df
--- /dev/null
+++ b/libAACenc/src/bit_cnt.h
@@ -0,0 +1,124 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Huffman Bitcounter & coder
+
+******************************************************************************/
+#ifndef __BITCOUNT_H
+#define __BITCOUNT_H
+
+
+#include "common_fix.h"
+#include "FDK_bitstream.h"
+#include "aacEnc_rom.h"
+
+#define INVALID_BITCOUNT (FDK_INT_MAX/4)
+
+/*
+ code book number table
+*/
+
+enum codeBookNo{
+ CODE_BOOK_ZERO_NO= 0,
+ CODE_BOOK_1_NO= 1,
+ CODE_BOOK_2_NO= 2,
+ CODE_BOOK_3_NO= 3,
+ CODE_BOOK_4_NO= 4,
+ CODE_BOOK_5_NO= 5,
+ CODE_BOOK_6_NO= 6,
+ CODE_BOOK_7_NO= 7,
+ CODE_BOOK_8_NO= 8,
+ CODE_BOOK_9_NO= 9,
+ CODE_BOOK_10_NO= 10,
+ CODE_BOOK_ESC_NO= 11,
+ CODE_BOOK_RES_NO= 12,
+ CODE_BOOK_PNS_NO= 13,
+ CODE_BOOK_IS_OUT_OF_PHASE_NO= 14,
+ CODE_BOOK_IS_IN_PHASE_NO= 15
+
+};
+
+/*
+ code book index table
+*/
+
+enum codeBookNdx{
+ CODE_BOOK_ZERO_NDX,
+ CODE_BOOK_1_NDX,
+ CODE_BOOK_2_NDX,
+ CODE_BOOK_3_NDX,
+ CODE_BOOK_4_NDX,
+ CODE_BOOK_5_NDX,
+ CODE_BOOK_6_NDX,
+ CODE_BOOK_7_NDX,
+ CODE_BOOK_8_NDX,
+ CODE_BOOK_9_NDX,
+ CODE_BOOK_10_NDX,
+ CODE_BOOK_ESC_NDX,
+ CODE_BOOK_RES_NDX,
+ CODE_BOOK_PNS_NDX,
+ CODE_BOOK_IS_OUT_OF_PHASE_NDX,
+ CODE_BOOK_IS_IN_PHASE_NDX,
+ NUMBER_OF_CODE_BOOKS
+};
+
+/*
+ code book lav table
+*/
+
+enum codeBookLav{
+ CODE_BOOK_ZERO_LAV=0,
+ CODE_BOOK_1_LAV=1,
+ CODE_BOOK_2_LAV=1,
+ CODE_BOOK_3_LAV=2,
+ CODE_BOOK_4_LAV=2,
+ CODE_BOOK_5_LAV=4,
+ CODE_BOOK_6_LAV=4,
+ CODE_BOOK_7_LAV=7,
+ CODE_BOOK_8_LAV=7,
+ CODE_BOOK_9_LAV=12,
+ CODE_BOOK_10_LAV=12,
+ CODE_BOOK_ESC_LAV=16,
+ CODE_BOOK_SCF_LAV=60,
+ CODE_BOOK_PNS_LAV=60
+ };
+
+INT FDKaacEnc_bitCount(const SHORT *aQuantSpectrum,
+ const INT noOfSpecLines,
+ INT maxVal,
+ INT *bitCountLut);
+
+INT FDKaacEnc_countValues(SHORT *values, INT width, INT codeBook);
+
+INT FDKaacEnc_codeValues(SHORT *values, INT width, INT codeBook, HANDLE_FDK_BITSTREAM hBitstream);
+
+INT FDKaacEnc_codeScalefactorDelta(INT scalefactor, HANDLE_FDK_BITSTREAM hBitstream);
+
+inline INT FDKaacEnc_bitCountScalefactorDelta(const INT delta)
+{
+ FDK_ASSERT( (0 <= (delta+CODE_BOOK_SCF_LAV)) && ((delta+CODE_BOOK_SCF_LAV)<(int)(sizeof(FDKaacEnc_huff_ltabscf)/sizeof((FDKaacEnc_huff_ltabscf[0])))) );
+ return((INT)FDKaacEnc_huff_ltabscf[delta+CODE_BOOK_SCF_LAV]);
+}
+
+#endif
diff --git a/libAACenc/src/bitenc.cpp b/libAACenc/src/bitenc.cpp
new file mode 100644
index 0000000..d70f872
--- /dev/null
+++ b/libAACenc/src/bitenc.cpp
@@ -0,0 +1,1431 @@
+ /******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: Bitstream encoder
+
+******************************************************************************/
+
+#include "bitenc.h"
+#include "bit_cnt.h"
+#include "dyn_bits.h"
+#include "qc_data.h"
+#include "interface.h"
+#include "aacEnc_ram.h"
+
+
+#include "tpenc_lib.h"
+
+#include "FDK_tools_rom.h" /* needed for the bitstream syntax tables */
+
+static const int globalGainOffset = 100;
+static const int icsReservedBit = 0;
+static const int noiseOffset = 90;
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_encodeSpectralData
+ description: encode spectral data
+ returns: the number of written bits
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_encodeSpectralData(INT *sfbOffset,
+ SECTION_DATA *sectionData,
+ SHORT *quantSpectrum,
+ HANDLE_FDK_BITSTREAM hBitStream)
+{
+ INT i,sfb;
+ INT dbgVal = FDKgetValidBits(hBitStream);
+
+ for(i=0;i<sectionData->noOfSections;i++)
+ {
+ if(sectionData->huffsection[i].codeBook != CODE_BOOK_PNS_NO)
+ {
+ /* huffencode spectral data for this huffsection */
+ INT tmp = sectionData->huffsection[i].sfbStart+sectionData->huffsection[i].sfbCnt;
+ for(sfb=sectionData->huffsection[i].sfbStart; sfb<tmp; sfb++)
+ {
+ FDKaacEnc_codeValues(quantSpectrum+sfbOffset[sfb],
+ sfbOffset[sfb+1]-sfbOffset[sfb],
+ sectionData->huffsection[i].codeBook,
+ hBitStream);
+ }
+ }
+ }
+ return(FDKgetValidBits(hBitStream)-dbgVal);
+}
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_encodeGlobalGain
+ description: encodes Global Gain (common scale factor)
+ returns: the number of static bits
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_encodeGlobalGain(INT globalGain,
+ INT scalefac,
+ HANDLE_FDK_BITSTREAM hBitStream,
+ INT mdctScale)
+{
+ if (hBitStream != NULL) {
+ FDKwriteBits(hBitStream,globalGain - scalefac + globalGainOffset-4*(LOG_NORM_PCM-mdctScale),8);
+ }
+ return (8);
+}
+
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_encodeIcsInfo
+ description: encodes Ics Info
+ returns: the number of static bits
+ input:
+ output:
+
+*****************************************************************************/
+
+static INT FDKaacEnc_encodeIcsInfo(INT blockType,
+ INT windowShape,
+ INT groupingMask,
+ INT maxSfbPerGroup,
+ HANDLE_FDK_BITSTREAM hBitStream,
+ UINT syntaxFlags)
+{
+ INT statBits;
+
+ if (blockType == SHORT_WINDOW) {
+ statBits = 8 + TRANS_FAC - 1;
+ } else {
+ if (syntaxFlags & AC_ELD) {
+ statBits = 6;
+ } else
+ {
+ statBits = (!(syntaxFlags & AC_SCALABLE)) ? 11 : 10;
+ }
+ }
+
+ if (hBitStream != NULL) {
+
+ if (!(syntaxFlags & AC_ELD)){
+ FDKwriteBits(hBitStream,icsReservedBit,1);
+ FDKwriteBits(hBitStream,blockType,2);
+ FDKwriteBits(hBitStream, (windowShape == LOL_WINDOW) ? KBD_WINDOW : windowShape,1);
+ }
+
+ switch(blockType){
+ case LONG_WINDOW:
+ case START_WINDOW:
+ case STOP_WINDOW:
+ FDKwriteBits(hBitStream,maxSfbPerGroup,6);
+
+ if (!(syntaxFlags & (AC_SCALABLE|AC_ELD)) ) { /* If not scalable syntax then ... */
+ /* No predictor data present */
+ FDKwriteBits(hBitStream, 0, 1);
+ }
+ break;
+
+ case SHORT_WINDOW:
+ FDKwriteBits(hBitStream,maxSfbPerGroup,4);
+
+ /* Write grouping bits */
+ FDKwriteBits(hBitStream,groupingMask,TRANS_FAC-1);
+ break;
+ }
+ }
+
+ return (statBits);
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_encodeSectionData
+ description: encode section data (common Huffman codebooks for adjacent
+ SFB's)
+ returns: none
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_encodeSectionData(SECTION_DATA *sectionData,
+ HANDLE_FDK_BITSTREAM hBitStream,
+ UINT useVCB11)
+{
+ if (hBitStream != NULL) {
+ INT sectEscapeVal=0,sectLenBits=0;
+ INT sectLen;
+ INT i;
+ INT dbgVal=FDKgetValidBits(hBitStream);
+ INT sectCbBits = 4;
+
+ switch(sectionData->blockType)
+ {
+ case LONG_WINDOW:
+ case START_WINDOW:
+ case STOP_WINDOW:
+ sectEscapeVal = SECT_ESC_VAL_LONG;
+ sectLenBits = SECT_BITS_LONG;
+ break;
+
+ case SHORT_WINDOW:
+ sectEscapeVal = SECT_ESC_VAL_SHORT;
+ sectLenBits = SECT_BITS_SHORT;
+ break;
+ }
+
+ for(i=0;i<sectionData->noOfSections;i++)
+ {
+ INT codeBook = sectionData->huffsection[i].codeBook;
+
+ FDKwriteBits(hBitStream,codeBook,sectCbBits);
+
+ {
+ sectLen = sectionData->huffsection[i].sfbCnt;
+
+ while(sectLen >= sectEscapeVal)
+ {
+ FDKwriteBits(hBitStream,sectEscapeVal,sectLenBits);
+ sectLen-=sectEscapeVal;
+ }
+ FDKwriteBits(hBitStream,sectLen,sectLenBits);
+ }
+ }
+ return(FDKgetValidBits(hBitStream)-dbgVal);
+ }
+ return (0);
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_encodeScaleFactorData
+ description: encode DPCM coded scale factors
+ returns: none
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_encodeScaleFactorData(UINT *maxValueInSfb,
+ SECTION_DATA *sectionData,
+ INT *scalefac,
+ HANDLE_FDK_BITSTREAM hBitStream,
+ INT *RESTRICT noiseNrg,
+ const INT *isScale,
+ INT globalGain)
+{
+ if (hBitStream != NULL) {
+ INT i,j,lastValScf,deltaScf;
+ INT deltaPns;
+ INT lastValPns = 0;
+ INT noisePCMFlag = TRUE;
+ INT lastValIs;
+
+ INT dbgVal = FDKgetValidBits(hBitStream);
+
+ lastValScf=scalefac[sectionData->firstScf];
+ lastValPns = globalGain-scalefac[sectionData->firstScf]+globalGainOffset-4*LOG_NORM_PCM-noiseOffset;
+ lastValIs = 0;
+
+ for(i=0; i<sectionData->noOfSections; i++){
+ if (sectionData->huffsection[i].codeBook != CODE_BOOK_ZERO_NO) {
+
+ if ((sectionData->huffsection[i].codeBook == CODE_BOOK_IS_OUT_OF_PHASE_NO) ||
+ (sectionData->huffsection[i].codeBook == CODE_BOOK_IS_IN_PHASE_NO))
+ {
+ INT sfbStart = sectionData->huffsection[i].sfbStart;
+ INT tmp = sfbStart + sectionData->huffsection[i].sfbCnt;
+ for(j=sfbStart; j<tmp; j++) {
+ INT deltaIs = isScale[j]-lastValIs;
+ lastValIs = isScale[j];
+ if(FDKaacEnc_codeScalefactorDelta(deltaIs,hBitStream)) {
+ return(1);
+ }
+ } /* sfb */
+ }
+ else if(sectionData->huffsection[i].codeBook == CODE_BOOK_PNS_NO) {
+ INT sfbStart = sectionData->huffsection[i].sfbStart;
+ INT tmp = sfbStart + sectionData->huffsection[i].sfbCnt;
+ for(j=sfbStart; j<tmp; j++) {
+ deltaPns = noiseNrg[j]-lastValPns;
+ lastValPns = noiseNrg[j];
+
+ if(noisePCMFlag){
+ FDKwriteBits(hBitStream,deltaPns+(1<<(PNS_PCM_BITS-1)),PNS_PCM_BITS);
+ noisePCMFlag = FALSE;
+ }
+ else {
+ if(FDKaacEnc_codeScalefactorDelta(deltaPns,hBitStream)) {
+ return(1);
+ }
+ }
+ } /* sfb */
+ }
+ else {
+ INT tmp = sectionData->huffsection[i].sfbStart+sectionData->huffsection[i].sfbCnt;
+ for(j=sectionData->huffsection[i].sfbStart; j<tmp; j++){
+ /*
+ check if we can repeat the last value to save bits
+ */
+ if(maxValueInSfb[j] == 0)
+ deltaScf = 0;
+ else{
+ deltaScf = -(scalefac[j]-lastValScf);
+ lastValScf = scalefac[j];
+ }
+ if(FDKaacEnc_codeScalefactorDelta(deltaScf,hBitStream)){
+ return(1);
+ }
+ } /* sfb */
+ } /* code scalefactor */
+ } /* sectionData->huffsection[i].codeBook != CODE_BOOK_ZERO_NO */
+ } /* section loop */
+
+ return(FDKgetValidBits(hBitStream)-dbgVal);
+ } /* if (hBitStream != NULL) */
+
+ return (0);
+}
+
+/*****************************************************************************
+
+ functionname:encodeMsInfo
+ description: encodes MS-Stereo Info
+ returns: the number of static bits
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_encodeMSInfo(INT sfbCnt,
+ INT grpSfb,
+ INT maxSfb,
+ INT msDigest,
+ INT *jsFlags,
+ HANDLE_FDK_BITSTREAM hBitStream)
+{
+ INT sfb, sfbOff, msBits = 0;
+
+ if (hBitStream != NULL)
+ {
+ switch(msDigest)
+ {
+ case MS_NONE:
+ FDKwriteBits(hBitStream,SI_MS_MASK_NONE,2);
+ msBits += 2;
+ break;
+
+ case MS_ALL:
+ FDKwriteBits(hBitStream,SI_MS_MASK_ALL,2);
+ msBits += 2;
+ break;
+
+ case MS_SOME:
+ FDKwriteBits(hBitStream,SI_MS_MASK_SOME,2);
+ msBits += 2;
+ for(sfbOff = 0; sfbOff < sfbCnt; sfbOff+=grpSfb)
+ {
+ for(sfb=0; sfb<maxSfb; sfb++)
+ {
+ if(jsFlags[sfbOff+sfb] & MS_ON){
+ FDKwriteBits(hBitStream,1,1);
+ }
+ else{
+ FDKwriteBits(hBitStream,0,1);
+ }
+ msBits += 1;
+ }
+ }
+ break;
+ }
+ }
+ else {
+ msBits += 2;
+ if (msDigest == MS_SOME) {
+ for(sfbOff = 0; sfbOff < sfbCnt; sfbOff+=grpSfb) {
+ for(sfb=0; sfb<maxSfb; sfb++) {
+ msBits += 1;
+ }
+ }
+ }
+ }
+ return (msBits);
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_encodeTnsDataPresent
+ description: encode TNS data (filter order, coeffs, ..)
+ returns: the number of static bits
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_encodeTnsDataPresent(TNS_INFO *tnsInfo,
+ INT blockType,
+ HANDLE_FDK_BITSTREAM hBitStream)
+{
+ if ( (hBitStream!=NULL) && (tnsInfo!=NULL) )
+ {
+ INT i, tnsPresent = 0;
+ INT numOfWindows = (blockType==SHORT_WINDOW?TRANS_FAC:1);
+
+ for (i=0; i<numOfWindows; i++) {
+ if (tnsInfo->numOfFilters[i]!=0) {
+ tnsPresent=1;
+ break;
+ }
+ }
+
+ if (tnsPresent==0) {
+ FDKwriteBits(hBitStream,0,1);
+ } else {
+ FDKwriteBits(hBitStream,1,1);
+ }
+ }
+ return (1);
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_encodeTnsData
+ description: encode TNS data (filter order, coeffs, ..)
+ returns: the number of static bits
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_encodeTnsData(TNS_INFO *tnsInfo,
+ INT blockType,
+ HANDLE_FDK_BITSTREAM hBitStream)
+{
+ INT tnsBits = 0;
+
+ if (tnsInfo!=NULL) {
+
+ INT i,j,k;
+ INT tnsPresent = 0;
+ INT coefBits;
+ INT numOfWindows=(blockType==SHORT_WINDOW?TRANS_FAC:1);
+
+ for (i=0; i<numOfWindows; i++) {
+ if (tnsInfo->numOfFilters[i]!=0) {
+ tnsPresent=1;
+ }
+ }
+
+ if (hBitStream != NULL)
+ {
+ if (tnsPresent==1) { /* there is data to be written*/
+ for (i=0; i<numOfWindows; i++) {
+ FDKwriteBits(hBitStream,tnsInfo->numOfFilters[i],(blockType==SHORT_WINDOW?1:2));
+ tnsBits += (blockType==SHORT_WINDOW?1:2);
+ if (tnsInfo->numOfFilters[i]) {
+ FDKwriteBits(hBitStream,(tnsInfo->coefRes[i]==4?1:0),1);
+ tnsBits += 1;
+ }
+ for (j=0; j<tnsInfo->numOfFilters[i]; j++) {
+ FDKwriteBits(hBitStream,tnsInfo->length[i][j],(blockType==SHORT_WINDOW?4:6));
+ tnsBits += (blockType==SHORT_WINDOW?4:6);
+ FDK_ASSERT(tnsInfo->order[i][j] <= 12);
+ FDKwriteBits(hBitStream,tnsInfo->order[i][j],(blockType==SHORT_WINDOW?3:5));
+ tnsBits += (blockType==SHORT_WINDOW?3:5);
+ if (tnsInfo->order[i][j]){
+ FDKwriteBits(hBitStream,tnsInfo->direction[i][j],1);
+ tnsBits +=1; /*direction*/
+ if(tnsInfo->coefRes[i] == 4) {
+ coefBits = 3;
+ for(k=0; k<tnsInfo->order[i][j]; k++) {
+ if (tnsInfo->coef[i][j][k]> 3 ||
+ tnsInfo->coef[i][j][k]< -4) {
+ coefBits = 4;
+ break;
+ }
+ }
+ } else {
+ coefBits = 2;
+ for(k=0; k<tnsInfo->order[i][j]; k++) {
+ if ( tnsInfo->coef[i][j][k]> 1
+ || tnsInfo->coef[i][j][k]< -2) {
+ coefBits = 3;
+ break;
+ }
+ }
+ }
+ FDKwriteBits(hBitStream,-(coefBits - tnsInfo->coefRes[i]),1); /*coef_compres*/
+ tnsBits +=1; /*coef_compression */
+ for (k=0; k<tnsInfo->order[i][j]; k++ ) {
+ static const INT rmask[] = {0,1,3,7,15};
+ FDKwriteBits(hBitStream,tnsInfo->coef[i][j][k] & rmask[coefBits],coefBits);
+ tnsBits += coefBits;
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ if (tnsPresent != 0) {
+ for (i=0; i<numOfWindows; i++) {
+ tnsBits += (blockType==SHORT_WINDOW?1:2);
+ if (tnsInfo->numOfFilters[i]) {
+ tnsBits += 1;
+ for (j=0; j<tnsInfo->numOfFilters[i]; j++) {
+ tnsBits += (blockType==SHORT_WINDOW?4:6);
+ tnsBits += (blockType==SHORT_WINDOW?3:5);
+ if (tnsInfo->order[i][j]) {
+ tnsBits +=1; /*direction*/
+ tnsBits +=1; /*coef_compression */
+ if (tnsInfo->coefRes[i] == 4) {
+ coefBits=3;
+ for (k=0; k<tnsInfo->order[i][j]; k++) {
+ if (tnsInfo->coef[i][j][k]> 3 || tnsInfo->coef[i][j][k]< -4) {
+ coefBits = 4;
+ break;
+ }
+ }
+ }
+ else {
+ coefBits = 2;
+ for (k=0; k<tnsInfo->order[i][j]; k++) {
+ if (tnsInfo->coef[i][j][k]> 1 || tnsInfo->coef[i][j][k]< -2) {
+ coefBits = 3;
+ break;
+ }
+ }
+ }
+ for (k=0; k<tnsInfo->order[i][j]; k++) {
+ tnsBits += coefBits;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } /* (tnsInfo!=NULL) */
+
+ return (tnsBits);
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_encodeGainControlData
+ description: unsupported
+ returns: none
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_encodeGainControlData(HANDLE_FDK_BITSTREAM hBitStream)
+{
+ if (hBitStream != NULL) {
+ FDKwriteBits(hBitStream,0,1);
+ }
+ return (1);
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_encodePulseData
+ description: not supported yet (dummy)
+ returns: none
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_encodePulseData(HANDLE_FDK_BITSTREAM hBitStream)
+{
+ if (hBitStream != NULL) {
+ FDKwriteBits(hBitStream,0,1);
+ }
+ return (1);
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_writeExtensionPayload
+ description: write extension payload to bitstream
+ returns: number of written bits
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_writeExtensionPayload( HANDLE_FDK_BITSTREAM hBitStream,
+ EXT_PAYLOAD_TYPE extPayloadType,
+ const UCHAR *extPayloadData,
+ INT extPayloadBits
+ )
+{
+ #define EXT_TYPE_BITS ( 4 )
+ #define DATA_EL_VERSION_BITS ( 4 )
+ #define FILL_NIBBLE_BITS ( 4 )
+
+ INT extBitsUsed = 0;
+
+ if (extPayloadBits >= EXT_TYPE_BITS)
+ {
+ UCHAR fillByte = 0x00; /* for EXT_FIL and EXT_FILL_DATA */
+
+ if (hBitStream != NULL) {
+ FDKwriteBits(hBitStream, extPayloadType, EXT_TYPE_BITS);
+ }
+ extBitsUsed += EXT_TYPE_BITS;
+
+ switch (extPayloadType) {
+ case EXT_DYNAMIC_RANGE:
+ /* case EXT_SAC_DATA: */
+ case EXT_SBR_DATA:
+ case EXT_SBR_DATA_CRC:
+ if (hBitStream != NULL) {
+ int i, writeBits = extPayloadBits;
+ for (i=0; writeBits >= 8; i++) {
+ FDKwriteBits(hBitStream, extPayloadData[i], 8);
+ writeBits -= 8;
+ }
+ if (writeBits > 0) {
+ FDKwriteBits(hBitStream, extPayloadData[i]>>(8-writeBits), writeBits);
+ }
+ }
+ extBitsUsed += extPayloadBits;
+ break;
+
+ case EXT_DATA_ELEMENT:
+ {
+ INT dataElementLength = (extPayloadBits+7)>>3;
+ INT cnt = dataElementLength;
+ int loopCounter = 1;
+
+ while (dataElementLength >= 255) {
+ loopCounter++;
+ dataElementLength -= 255;
+ }
+
+ if (hBitStream != NULL) {
+ int i;
+ FDKwriteBits(hBitStream, 0x00, DATA_EL_VERSION_BITS); /* data_element_version = ANC_DATA */
+
+ for (i=1; i<loopCounter; i++) {
+ FDKwriteBits(hBitStream, 255, 8);
+ }
+ FDKwriteBits(hBitStream, dataElementLength, 8);
+
+ for (i=0; i<cnt; i++) {
+ FDKwriteBits(hBitStream, extPayloadData[i], 8);
+ }
+ }
+ extBitsUsed += DATA_EL_VERSION_BITS + (loopCounter*8) + (cnt*8);
+ }
+ break;
+
+ case EXT_FILL_DATA:
+ fillByte = 0xA5;
+ case EXT_FIL:
+ default:
+ if (hBitStream != NULL) {
+ int writeBits = extPayloadBits;
+ FDKwriteBits(hBitStream, 0x00, FILL_NIBBLE_BITS);
+ writeBits -= 8; /* acount for the extension type and the fill nibble */
+ while (writeBits >= 8) {
+ FDKwriteBits(hBitStream, fillByte, 8);
+ writeBits -= 8;
+ }
+ }
+ extBitsUsed += FILL_NIBBLE_BITS + (extPayloadBits & ~0x7) - 8;
+ break;
+ }
+ }
+
+ return (extBitsUsed);
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_writeDataStreamElement
+ description: write data stream elements like ancillary data ...
+ returns: the amount of used bits
+ input:
+ output:
+
+******************************************************************************/
+static INT FDKaacEnc_writeDataStreamElement( HANDLE_TRANSPORTENC hTpEnc,
+ INT elementInstanceTag,
+ INT dataPayloadBytes,
+ UCHAR *dataBuffer,
+ UINT alignAnchor )
+{
+ #define DATA_BYTE_ALIGN_FLAG ( 0 )
+
+ #define EL_INSTANCE_TAG_BITS ( 4 )
+ #define DATA_BYTE_ALIGN_FLAG_BITS ( 1 )
+ #define DATA_LEN_COUNT_BITS ( 8 )
+ #define DATA_LEN_ESC_COUNT_BITS ( 8 )
+
+ #define MAX_DATA_ALIGN_BITS ( 7 )
+ #define MAX_DSE_DATA_BYTES ( 510 )
+
+ INT dseBitsUsed = 0;
+
+ while (dataPayloadBytes > 0)
+ {
+ int esc_count = -1;
+ int cnt = 0;
+ INT crcReg = -1;
+
+ dseBitsUsed += EL_ID_BITS + EL_INSTANCE_TAG_BITS
+ + DATA_BYTE_ALIGN_FLAG_BITS + DATA_LEN_COUNT_BITS;
+
+ if (DATA_BYTE_ALIGN_FLAG) {
+ dseBitsUsed += MAX_DATA_ALIGN_BITS;
+ }
+
+ cnt = fixMin(MAX_DSE_DATA_BYTES, dataPayloadBytes);
+ if ( cnt >= 255 ) {
+ esc_count = cnt - 255;
+ dseBitsUsed += DATA_LEN_ESC_COUNT_BITS;
+ }
+
+ dataPayloadBytes -= cnt;
+ dseBitsUsed += cnt * 8;
+
+ if (hTpEnc != NULL) {
+ HANDLE_FDK_BITSTREAM hBitStream = transportEnc_GetBitstream(hTpEnc);
+ int i;
+
+ FDKwriteBits(hBitStream, ID_DSE, EL_ID_BITS);
+
+ crcReg = transportEnc_CrcStartReg(hTpEnc, 0);
+
+ FDKwriteBits(hBitStream, elementInstanceTag, EL_INSTANCE_TAG_BITS);
+ FDKwriteBits(hBitStream, DATA_BYTE_ALIGN_FLAG, DATA_BYTE_ALIGN_FLAG_BITS);
+
+ /* write length field(s) */
+ if ( esc_count >= 0 ) {
+ FDKwriteBits(hBitStream, 255, DATA_LEN_COUNT_BITS);
+ FDKwriteBits(hBitStream, esc_count, DATA_LEN_ESC_COUNT_BITS);
+ } else {
+ FDKwriteBits(hBitStream, cnt, DATA_LEN_COUNT_BITS);
+ }
+
+ if (DATA_BYTE_ALIGN_FLAG) {
+ INT tmp = (INT)FDKgetValidBits(hBitStream);
+ FDKbyteAlign(hBitStream, alignAnchor);
+ /* count actual bits */
+ dseBitsUsed += (INT)FDKgetValidBits(hBitStream) - tmp - MAX_DATA_ALIGN_BITS;
+ }
+
+ /* write payload */
+ for (i=0; i<cnt; i++) {
+ FDKwriteBits(hBitStream, dataBuffer[i], 8);
+ }
+ transportEnc_CrcEndReg(hTpEnc, crcReg);
+ }
+ }
+
+ return (dseBitsUsed);
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_writeExtensionData
+ description: write extension payload to bitstream
+ returns: number of written bits
+ input:
+ output:
+
+*****************************************************************************/
+INT FDKaacEnc_writeExtensionData( HANDLE_TRANSPORTENC hTpEnc,
+ QC_OUT_EXTENSION *pExtension,
+ INT elInstanceTag, /* for DSE only */
+ UINT alignAnchor, /* for DSE only */
+ UINT syntaxFlags,
+ AUDIO_OBJECT_TYPE aot,
+ SCHAR epConfig
+ )
+{
+ #define FILL_EL_COUNT_BITS ( 4 )
+ #define FILL_EL_ESC_COUNT_BITS ( 8 )
+ #define MAX_FILL_DATA_BYTES ( 269 )
+
+ HANDLE_FDK_BITSTREAM hBitStream = NULL;
+ INT payloadBits = pExtension->nPayloadBits;
+ INT extBitsUsed = 0;
+
+ if (hTpEnc != NULL) {
+ hBitStream = transportEnc_GetBitstream(hTpEnc);
+ }
+
+ if (syntaxFlags & (AC_SCALABLE|AC_ER))
+ {
+ if ( syntaxFlags & AC_DRM )
+ { /* CAUTION: The caller has to assure that fill
+ data is written before the SBR payload. */
+ UCHAR *extPayloadData = pExtension->pPayload;
+
+ switch (pExtension->type)
+ {
+ case EXT_SBR_DATA:
+ case EXT_SBR_DATA_CRC:
+ /* SBR payload is written in reverse */
+ if (hBitStream != NULL) {
+ int i, writeBits = payloadBits;
+
+ FDKpushFor(hBitStream, payloadBits-1); /* Does a cache sync internally */
+
+ for (i=0; writeBits >= 8; i++) {
+ FDKwriteBitsBwd(hBitStream, extPayloadData[i], 8);
+ writeBits -= 8;
+ }
+ if (writeBits > 0) {
+ FDKwriteBitsBwd(hBitStream, extPayloadData[i]>>(8-writeBits), writeBits);
+ }
+
+ FDKsyncCacheBwd (hBitStream);
+ FDKpushFor (hBitStream, payloadBits+1);
+ }
+ extBitsUsed += payloadBits;
+ break;
+
+ case EXT_FILL_DATA:
+ case EXT_FIL:
+ default:
+ if (hBitStream != NULL) {
+ int writeBits = payloadBits;
+ while (writeBits >= 8) {
+ FDKwriteBits(hBitStream, 0x00, 8);
+ writeBits -= 8;
+ }
+ FDKwriteBits(hBitStream, 0x00, writeBits);
+ }
+ extBitsUsed += payloadBits;
+ break;
+ }
+ }
+ else {
+ if ( (syntaxFlags & AC_ELD) && ((pExtension->type==EXT_SBR_DATA) || (pExtension->type==EXT_SBR_DATA_CRC)) ) {
+
+ if (hBitStream != NULL) {
+ int i, writeBits = payloadBits;
+ UCHAR *extPayloadData = pExtension->pPayload;
+
+ for (i=0; writeBits >= 8; i++) {
+ FDKwriteBits(hBitStream, extPayloadData[i], 8);
+ writeBits -= 8;
+ }
+ if (writeBits > 0) {
+ FDKwriteBits(hBitStream, extPayloadData[i]>>(8-writeBits), writeBits);
+ }
+ }
+ extBitsUsed += payloadBits;
+ }
+ else
+ {
+ /* ER or scalable syntax -> write extension en bloc */
+ extBitsUsed += FDKaacEnc_writeExtensionPayload( hBitStream,
+ pExtension->type,
+ pExtension->pPayload,
+ payloadBits );
+ }
+ }
+ }
+ else {
+ /* We have normal GA bitstream payload (AOT 2,5,29) so pack
+ the data into a fill elements or DSEs */
+
+ if ( pExtension->type == EXT_DATA_ELEMENT )
+ {
+ extBitsUsed += FDKaacEnc_writeDataStreamElement( hTpEnc,
+ elInstanceTag,
+ pExtension->nPayloadBits>>3,
+ pExtension->pPayload,
+ alignAnchor );
+ }
+ else {
+ while (payloadBits >= (EL_ID_BITS + FILL_EL_COUNT_BITS)) {
+ INT cnt, esc_count=-1, alignBits=7;
+
+ if ( (pExtension->type == EXT_FILL_DATA) || (pExtension->type == EXT_FIL) )
+ {
+ payloadBits -= EL_ID_BITS + FILL_EL_COUNT_BITS;
+ if (payloadBits >= 15*8) {
+ payloadBits -= FILL_EL_ESC_COUNT_BITS;
+ esc_count = 0; /* write esc_count even if cnt becomes smaller 15 */
+ }
+ alignBits = 0;
+ }
+
+ cnt = fixMin(MAX_FILL_DATA_BYTES, (payloadBits+alignBits)>>3);
+
+ if (cnt >= 15) {
+ esc_count = cnt - 15 + 1;
+ }
+
+ if (hBitStream != NULL) {
+ /* write bitstream */
+ FDKwriteBits(hBitStream, ID_FIL, EL_ID_BITS);
+ if (esc_count >= 0) {
+ FDKwriteBits(hBitStream, 15, FILL_EL_COUNT_BITS);
+ FDKwriteBits(hBitStream, esc_count, FILL_EL_ESC_COUNT_BITS);
+ } else {
+ FDKwriteBits(hBitStream, cnt, FILL_EL_COUNT_BITS);
+ }
+ }
+
+ extBitsUsed += EL_ID_BITS + FILL_EL_COUNT_BITS + ((esc_count>=0) ? FILL_EL_ESC_COUNT_BITS : 0);
+
+ cnt = fixMin(cnt*8, payloadBits); /* convert back to bits */
+ extBitsUsed += FDKaacEnc_writeExtensionPayload( hBitStream,
+ pExtension->type,
+ pExtension->pPayload,
+ cnt );
+ payloadBits -= cnt;
+ }
+ }
+ }
+
+ return (extBitsUsed);
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_ByteAlignment
+ description:
+ returns:
+ input:
+ output:
+
+*****************************************************************************/
+static void FDKaacEnc_ByteAlignment(HANDLE_FDK_BITSTREAM hBitStream, int alignBits)
+{
+ FDKwriteBits(hBitStream, 0, alignBits);
+}
+
+AAC_ENCODER_ERROR FDKaacEnc_ChannelElementWrite( HANDLE_TRANSPORTENC hTpEnc,
+ ELEMENT_INFO *pElInfo,
+ QC_OUT_CHANNEL *qcOutChannel[(2)],
+ PSY_OUT_ELEMENT *psyOutElement,
+ PSY_OUT_CHANNEL *psyOutChannel[(2)],
+ UINT syntaxFlags,
+ AUDIO_OBJECT_TYPE aot,
+ SCHAR epConfig,
+ INT *pBitDemand,
+ UCHAR minCnt
+ )
+{
+ AAC_ENCODER_ERROR error = AAC_ENC_OK;
+ HANDLE_FDK_BITSTREAM hBitStream = NULL;
+ INT bitDemand = 0;
+ const element_list_t *list;
+ int i, ch, decision_bit;
+ INT crcReg1 = -1, crcReg2 = -1;
+ UCHAR numberOfChannels;
+
+ if (hTpEnc != NULL) {
+ /* Get bitstream handle */
+ hBitStream = transportEnc_GetBitstream(hTpEnc);
+ }
+
+ if ( (pElInfo->elType==ID_SCE) || (pElInfo->elType==ID_LFE) ) {
+ numberOfChannels = 1;
+ } else {
+ numberOfChannels = 2;
+ }
+
+ /* Get channel element sequence table */
+ list = getBitstreamElementList(aot, epConfig, numberOfChannels, 0);
+ if (list == NULL) {
+ error = AAC_ENC_UNSUPPORTED_AOT;
+ goto bail;
+ }
+
+ if (!(syntaxFlags & (AC_SCALABLE|AC_ER))) {
+ if (hBitStream != NULL) {
+ FDKwriteBits(hBitStream, pElInfo->elType, EL_ID_BITS);
+ }
+ bitDemand += EL_ID_BITS;
+ }
+
+ /* Iterate through sequence table */
+ i = 0;
+ ch = 0;
+ decision_bit = 0;
+ do {
+ /* some tmp values */
+ SECTION_DATA *pChSectionData = NULL;
+ INT *pChScf = NULL;
+ UINT *pChMaxValueInSfb = NULL;
+ TNS_INFO *pTnsInfo = NULL;
+ INT chGlobalGain = 0;
+ INT chBlockType = 0;
+ INT chMaxSfbPerGrp = 0;
+ INT chSfbPerGrp = 0;
+ INT chSfbCnt = 0;
+ INT chFirstScf = 0;
+
+ if (minCnt==0) {
+ if ( qcOutChannel!=NULL ) {
+ pChSectionData = &(qcOutChannel[ch]->sectionData);
+ pChScf = qcOutChannel[ch]->scf;
+ chGlobalGain = qcOutChannel[ch]->globalGain;
+ pChMaxValueInSfb = qcOutChannel[ch]->maxValueInSfb;
+ chBlockType = pChSectionData->blockType;
+ chMaxSfbPerGrp = pChSectionData->maxSfbPerGroup;
+ chSfbPerGrp = pChSectionData->sfbPerGroup;
+ chSfbCnt = pChSectionData->sfbCnt;
+ chFirstScf = pChScf[pChSectionData->firstScf];
+ }
+ else {
+ /* get values from PSY */
+ chSfbCnt = psyOutChannel[ch]->sfbCnt;
+ chSfbPerGrp = psyOutChannel[ch]->sfbPerGroup;
+ chMaxSfbPerGrp = psyOutChannel[ch]->maxSfbPerGroup;
+ }
+ pTnsInfo = &psyOutChannel[ch]->tnsInfo;
+ } /* minCnt==0 */
+
+ if ( qcOutChannel==NULL ) {
+ chBlockType = psyOutChannel[ch]->lastWindowSequence;
+ }
+
+ switch (list->id[i])
+ {
+ case element_instance_tag:
+ /* Write element instance tag */
+ if (hBitStream != NULL) {
+ FDKwriteBits(hBitStream, pElInfo->instanceTag, 4);
+ }
+ bitDemand += 4;
+ break;
+
+ case common_window:
+ /* Write common window flag */
+ decision_bit = psyOutElement->commonWindow;
+ if (hBitStream != NULL) {
+ FDKwriteBits(hBitStream, psyOutElement->commonWindow, 1);
+ }
+ bitDemand += 1;
+ break;
+
+ case ics_info:
+ /* Write individual channel info */
+ bitDemand += FDKaacEnc_encodeIcsInfo( chBlockType,
+ psyOutChannel[ch]->windowShape,
+ psyOutChannel[ch]->groupingMask,
+ chMaxSfbPerGrp,
+ hBitStream,
+ syntaxFlags);
+ break;
+
+ case ltp_data_present:
+ /* Write LTP data present flag */
+ if (hBitStream != NULL) {
+ FDKwriteBits(hBitStream, 0, 1);
+ }
+ bitDemand += 1;
+ break;
+
+ case ltp_data:
+ /* Predictor data not supported.
+ Nothing to do here. */
+ break;
+
+ case ms:
+ /* Write MS info */
+ bitDemand += FDKaacEnc_encodeMSInfo( chSfbCnt,
+ chSfbPerGrp,
+ chMaxSfbPerGrp,
+ (minCnt==0) ? psyOutElement->toolsInfo.msDigest : MS_NONE,
+ psyOutElement->toolsInfo.msMask,
+ hBitStream);
+ break;
+
+ case global_gain:
+ bitDemand += FDKaacEnc_encodeGlobalGain( chGlobalGain,
+ chFirstScf,
+ hBitStream,
+ psyOutChannel[ch]->mdctScale );
+ break;
+
+ case section_data:
+ {
+ INT siBits = FDKaacEnc_encodeSectionData(pChSectionData, hBitStream, (syntaxFlags & AC_ER_VCB11)?1:0);
+ if (hBitStream != NULL) {
+ if (siBits != qcOutChannel[ch]->sectionData.sideInfoBits) {
+ error = AAC_ENC_WRITE_SEC_ERROR;
+ }
+ }
+ bitDemand += siBits;
+ }
+ break;
+
+ case scale_factor_data:
+ {
+ INT sfDataBits = FDKaacEnc_encodeScaleFactorData( pChMaxValueInSfb,
+ pChSectionData,
+ pChScf,
+ hBitStream,
+ psyOutChannel[ch]->noiseNrg,
+ psyOutChannel[ch]->isScale,
+ chGlobalGain );
+ if ( (hBitStream != NULL)
+ && (sfDataBits != (qcOutChannel[ch]->sectionData.scalefacBits + qcOutChannel[ch]->sectionData.noiseNrgBits)) ) {
+ error = AAC_ENC_WRITE_SCAL_ERROR;
+ }
+ bitDemand += sfDataBits;
+ }
+ break;
+
+ case esc2_rvlc:
+ if (syntaxFlags & AC_ER_RVLC) {
+ /* write RVLC data into bitstream (error sens. cat. 2) */
+ error = AAC_ENC_UNSUPPORTED_AOT;
+ }
+ break;
+
+ case pulse:
+ /* Write pulse data */
+ bitDemand += FDKaacEnc_encodePulseData(hBitStream);
+ break;
+
+ case tns_data_present:
+ /* Write TNS data present flag */
+ bitDemand += FDKaacEnc_encodeTnsDataPresent(pTnsInfo,
+ chBlockType,
+ hBitStream);
+ break;
+ case tns_data:
+ /* Write TNS data */
+ bitDemand += FDKaacEnc_encodeTnsData(pTnsInfo,
+ chBlockType,
+ hBitStream);
+ break;
+
+ case gain_control_data:
+ /* Nothing to do here */
+ break;
+
+ case gain_control_data_present:
+ bitDemand += FDKaacEnc_encodeGainControlData(hBitStream);
+ break;
+
+
+ case esc1_hcr:
+ if (syntaxFlags & AC_ER_HCR)
+ {
+ error = AAC_ENC_UNKNOWN;
+ }
+ break;
+
+ case spectral_data:
+ if (hBitStream != NULL)
+ {
+ INT spectralBits = 0;
+
+ spectralBits = FDKaacEnc_encodeSpectralData( psyOutChannel[ch]->sfbOffsets,
+ pChSectionData,
+ qcOutChannel[ch]->quantSpec,
+ hBitStream );
+
+ if (spectralBits != qcOutChannel[ch]->sectionData.huffmanBits) {
+ return AAC_ENC_WRITE_SPEC_ERROR;
+ }
+ bitDemand += spectralBits;
+ }
+ break;
+
+ /* Non data cases */
+ case adtscrc_start_reg1:
+ if (hTpEnc != NULL) {
+ crcReg1 = transportEnc_CrcStartReg(hTpEnc, 192);
+ }
+ break;
+ case adtscrc_start_reg2:
+ if (hTpEnc != NULL) {
+ crcReg2 = transportEnc_CrcStartReg(hTpEnc, 128);
+ }
+ break;
+ case adtscrc_end_reg1:
+ case drmcrc_end_reg:
+ if (hTpEnc != NULL) {
+ transportEnc_CrcEndReg(hTpEnc, crcReg1);
+ }
+ break;
+ case adtscrc_end_reg2:
+ if (hTpEnc != NULL) {
+ transportEnc_CrcEndReg(hTpEnc, crcReg2);
+ }
+ break;
+ case drmcrc_start_reg:
+ if (hTpEnc != NULL) {
+ crcReg1 = transportEnc_CrcStartReg(hTpEnc, 0);
+ }
+ break;
+ case next_channel:
+ ch = (ch + 1) % numberOfChannels;
+ break;
+ case link_sequence:
+ list = list->next[decision_bit];
+ i=-1;
+ break;
+
+ default:
+ error = AAC_ENC_UNKNOWN;
+ break;
+ }
+
+ if (error != AAC_ENC_OK) {
+ return error;
+ }
+
+ i++;
+
+ } while (list->id[i] != end_of_sequence);
+
+bail:
+ if (pBitDemand != NULL) {
+ *pBitDemand = bitDemand;
+ }
+
+ return error;
+}
+
+
+//-----------------------------------------------------------------------------------------------
+
+AAC_ENCODER_ERROR FDKaacEnc_WriteBitstream(HANDLE_TRANSPORTENC hTpEnc,
+ CHANNEL_MAPPING *channelMapping,
+ QC_OUT *qcOut,
+ PSY_OUT* psyOut,
+ QC_STATE *qcKernel,
+ AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig
+ )
+{
+ HANDLE_FDK_BITSTREAM hBs = transportEnc_GetBitstream(hTpEnc);
+ AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK;
+ int i, n, doByteAlign = 1;
+ INT bitMarkUp;
+ INT frameBits;
+ /* Get first bit of raw data block.
+ In case of ADTS+PCE, AU would start at PCE.
+ This is okay because PCE assures alignment. */
+ UINT alignAnchor = FDKgetValidBits(hBs);
+
+ frameBits = bitMarkUp = alignAnchor;
+
+ if ( syntaxFlags & AC_DAB )
+ { /* Write PAD data as first element for DAB+ */
+ for (n = 0; n < qcOut->nExtensions; n++) {
+ if ( (qcOut->extension[n].type == EXT_DATA_ELEMENT)
+ && (qcOut->extension[n].nPayloadBits > 0)
+ && (qcOut->extension[n].pPayload != NULL) )
+ {
+ FDKaacEnc_writeExtensionData( hTpEnc,
+ &qcOut->extension[n],
+ 0,
+ alignAnchor,
+ syntaxFlags,
+ aot,
+ epConfig );
+
+ qcOut->extension[n].nPayloadBits = 0;
+ }
+ }
+ }
+
+ /* Channel element loop */
+ for (i=0; i<channelMapping->nElements; i++) {
+
+ ELEMENT_INFO elInfo = channelMapping->elInfo[i];
+ INT elementUsedBits = 0;
+
+ switch (elInfo.elType)
+ {
+ case ID_SCE: /* single channel */
+ case ID_CPE: /* channel pair */
+ case ID_LFE: /* low freq effects channel */
+ {
+ if ( AAC_ENC_OK != (ErrorStatus = FDKaacEnc_ChannelElementWrite( hTpEnc,
+ &elInfo,
+ qcOut->qcElement[i]->qcOutChannel,
+ psyOut->psyOutElement[i],
+ psyOut->psyOutElement[i]->psyOutChannel,
+ syntaxFlags, /* syntaxFlags (ER tools ...) */
+ aot, /* aot: AOT_AAC_LC, AOT_SBR, AOT_PS */
+ epConfig, /* epConfig -1, 0, 1 */
+ NULL,
+ 0 )) )
+ {
+ return ErrorStatus;
+ }
+
+ if ( !(syntaxFlags & AC_ER) )
+ {
+ /* Write associated extension payload */
+ for (n = 0; n < qcOut->qcElement[i]->nExtensions; n++) {
+ FDKaacEnc_writeExtensionData( hTpEnc,
+ &qcOut->qcElement[i]->extension[n],
+ 0,
+ alignAnchor,
+ syntaxFlags,
+ aot,
+ epConfig );
+ }
+ }
+ }
+ break;
+
+ /* In FDK, DSE signalling explicit done in elDSE. See channel_map.cpp */
+ default:
+ return AAC_ENC_INVALID_ELEMENTINFO_TYPE;
+
+ } /* switch */
+
+ if(elInfo.elType != ID_DSE) {
+ elementUsedBits -= bitMarkUp;
+ bitMarkUp = FDKgetValidBits(hBs);
+ elementUsedBits += bitMarkUp;
+ frameBits += elementUsedBits;
+ }
+
+ } /* for (i=0; i<channelMapping.nElements; i++) */
+
+ if ( (syntaxFlags & AC_ER) && !(syntaxFlags & AC_DRM) )
+ {
+ UCHAR channelElementExtensionWritten[(6)][(1)]; /* 0: extension not touched, 1: extension already written */
+
+ FDKmemclear(channelElementExtensionWritten, sizeof(channelElementExtensionWritten));
+
+ if ( syntaxFlags & AC_ELD ) {
+
+ for (i=0; i<channelMapping->nElements; i++) {
+ for (n = 0; n < qcOut->qcElement[i]->nExtensions; n++) {
+
+ if ( (qcOut->qcElement[i]->extension[n].type==EXT_SBR_DATA)
+ || (qcOut->qcElement[i]->extension[n].type==EXT_SBR_DATA_CRC) )
+ {
+ /* Write sbr extension payload */
+ FDKaacEnc_writeExtensionData( hTpEnc,
+ &qcOut->qcElement[i]->extension[n],
+ 0,
+ alignAnchor,
+ syntaxFlags,
+ aot,
+ epConfig );
+
+ channelElementExtensionWritten[i][n] = 1;
+ } /* SBR */
+ } /* n */
+ } /* i */
+ } /* AC_ELD */
+
+ for (i=0; i<channelMapping->nElements; i++) {
+ for (n = 0; n < qcOut->qcElement[i]->nExtensions; n++) {
+
+ if (channelElementExtensionWritten[i][n]==0)
+ {
+ /* Write all ramaining extension payloads in element */
+ FDKaacEnc_writeExtensionData( hTpEnc,
+ &qcOut->qcElement[i]->extension[n],
+ 0,
+ alignAnchor,
+ syntaxFlags,
+ aot,
+ epConfig );
+ }
+ } /* n */
+ } /* i */
+ } /* if AC_ER */
+
+ /* Extend global extension payload table with fill bits */
+ if ( syntaxFlags & AC_DRM )
+ {
+ /* Exception for Drm */
+ for (n = 0; n < qcOut->nExtensions; n++) {
+ if ( (qcOut->extension[n].type == EXT_SBR_DATA)
+ || (qcOut->extension[n].type == EXT_SBR_DATA_CRC) ) {
+ /* SBR data must be the last extension! */
+ FDKmemcpy(&qcOut->extension[qcOut->nExtensions], &qcOut->extension[n], sizeof(QC_OUT_EXTENSION));
+ break;
+ }
+ }
+ /* Do byte alignment after AAC (+ MPS) payload.
+ Assure that MPS has been written as channel assigned extension payload! */
+ if (((FDKgetValidBits(hBs)-alignAnchor+(UINT)qcOut->totFillBits)&0x7)!=(UINT)qcOut->alignBits) {
+ return AAC_ENC_WRITTEN_BITS_ERROR;
+ }
+ FDKaacEnc_ByteAlignment(hBs, qcOut->alignBits);
+ doByteAlign = 0;
+
+ } /* AC_DRM */
+
+ /* Add fill data / stuffing bits */
+ n = qcOut->nExtensions;
+ qcOut->extension[n].type = EXT_FILL_DATA;
+ qcOut->extension[n].nPayloadBits = qcOut->totFillBits;
+ qcOut->nExtensions++;
+
+ /* Write global extension payload and fill data */
+ for (n = 0; (n < qcOut->nExtensions) && (n < (2+2)); n++)
+ {
+ FDKaacEnc_writeExtensionData( hTpEnc,
+ &qcOut->extension[n],
+ 0,
+ alignAnchor,
+ syntaxFlags,
+ aot,
+ epConfig );
+
+ /* For EXT_FIL or EXT_FILL_DATA we could do an additional sanity check here */
+ }
+
+ if (!(syntaxFlags & (AC_SCALABLE|AC_ER))) {
+ FDKwriteBits(hBs, ID_END, EL_ID_BITS);
+ }
+
+ if (doByteAlign) {
+ /* Assure byte alignment*/
+ if (((alignAnchor-FDKgetValidBits(hBs))&0x7)!=(UINT)qcOut->alignBits) {
+ return AAC_ENC_WRITTEN_BITS_ERROR;
+ }
+
+ FDKaacEnc_ByteAlignment(hBs, qcOut->alignBits);
+ }
+
+ frameBits -= bitMarkUp;
+ frameBits += FDKgetValidBits(hBs);
+
+ transportEnc_EndAccessUnit(hTpEnc, &frameBits);
+
+ if (frameBits != qcOut->totalBits + qcKernel->globHdrBits){
+ return AAC_ENC_WRITTEN_BITS_ERROR;
+ }
+
+ return ErrorStatus;
+}
+
diff --git a/libAACenc/src/bitenc.h b/libAACenc/src/bitenc.h
new file mode 100644
index 0000000..692a1a2
--- /dev/null
+++ b/libAACenc/src/bitenc.h
@@ -0,0 +1,120 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: Bitstream encoder
+
+******************************************************************************/
+#ifndef _BITENC_H
+#define _BITENC_H
+
+
+#include "qc_data.h"
+#include "aacenc_tns.h"
+#include "channel_map.h"
+#include "interface.h" /* obsolete, when PSY_OUT is thrown out of the WritBS-call! */
+#include "FDK_audio.h"
+#include "aacenc.h"
+
+#include "tpenc_lib.h"
+
+typedef enum{
+ MAX_ENCODER_CHANNELS = 9,
+ MAX_BLOCK_TYPES = 4,
+ MAX_AAC_LAYERS = 9,
+ MAX_LAYERS = MAX_AAC_LAYERS , /* only one core layer if present */
+ FIRST_LAY = 1 /* default layer number for AAC nonscalable */
+} _MAX_CONST;
+
+#define BUFFER_MX_HUFFCB_SIZE (32*sizeof(INT)) /* our FDK_bitbuffer needs size of power 2 */
+
+#define EL_ID_BITS ( 3 )
+
+
+/**
+ * \brief Arbitrary order bitstream writer. This function can either assemble a bit stream
+ * and write into the bit buffer of hTpEnc or calculate the number of static bits (signal independent)
+ * TpEnc handle must be NULL in this case. Or also Calculate the minimum possible number of
+ * static bits which by disabling all tools e.g. MS, TNS and sbfCnt=0. The minCnt parameter
+ * has to be 1 in this latter case.
+ * \param hTpEnc Transport encoder handle. If NULL, the number of static bits will be returned into
+ * *pBitDemand.
+ * \param pElInfo
+ * \param qcOutChannel
+ * \param hReorderInfo
+ * \param psyOutElement
+ * \param psyOutChannel
+ * \param syntaxFlags Bit stream syntax flags as defined in FDK_audio.h (Audio Codec flags).
+ * \param aot
+ * \param epConfig
+ * \param pBitDemand Pointer to an int where the amount of bits is returned into. The returned value
+ * depends on if hTpEnc is NULL and minCnt.
+ * \param minCnt If non-zero the value returned into *pBitDemand is the absolute minimum required amount of
+ * static bits in order to write a valid bit stream.
+ * \return AAC_ENCODER_ERROR error code
+ */
+AAC_ENCODER_ERROR FDKaacEnc_ChannelElementWrite( HANDLE_TRANSPORTENC hTpEnc,
+ ELEMENT_INFO *pElInfo,
+ QC_OUT_CHANNEL *qcOutChannel[(2)],
+ PSY_OUT_ELEMENT *psyOutElement,
+ PSY_OUT_CHANNEL *psyOutChannel[(2)],
+ UINT syntaxFlags,
+ AUDIO_OBJECT_TYPE aot,
+ SCHAR epConfig,
+ INT *pBitDemand,
+ UCHAR minCnt
+ );
+/**
+ * \brief Write bit stream or account static bits
+ * \param hTpEnc transport encoder handle. If NULL, the function will
+ * not write any bit stream data but only count the amount
+ * of static (signal independent) bits
+ * \param channelMapping Channel mapping info
+ * \param qcOut
+ * \param psyOut
+ * \param qcKernel
+ * \param hBSE
+ * \param aot Audio Object Type being encoded
+ * \param syntaxFlags Flags indicating format specific detail
+ * \param epConfig Error protection config
+ */
+AAC_ENCODER_ERROR FDKaacEnc_WriteBitstream (HANDLE_TRANSPORTENC hTpEnc,
+ CHANNEL_MAPPING *channelMapping,
+ QC_OUT* qcOut,
+ PSY_OUT* psyOut,
+ QC_STATE* qcKernel,
+ AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig
+ );
+
+INT FDKaacEnc_writeExtensionData( HANDLE_TRANSPORTENC hTpEnc,
+ QC_OUT_EXTENSION *pExtension,
+ INT elInstanceTag,
+ UINT alignAnchor,
+ UINT syntaxFlags,
+ AUDIO_OBJECT_TYPE aot,
+ SCHAR epConfig
+ );
+
+#endif /* _BITENC_H */
diff --git a/libAACenc/src/block_switch.cpp b/libAACenc/src/block_switch.cpp
new file mode 100644
index 0000000..e75536a
--- /dev/null
+++ b/libAACenc/src/block_switch.cpp
@@ -0,0 +1,500 @@
+/***************************** MPEG-4 AAC Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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): M. Werner
+ Description: Block switching
+
+ 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.
+
+******************************************************************************/
+
+/****************** Includes *****************************/
+
+#include "block_switch.h"
+#include "genericStds.h"
+
+
+#define LOWOV_WINDOW _LOWOV_WINDOW
+
+/**************** internal function prototypes ***********/
+
+static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT blSwWndIdx);
+
+static void FDKaacEnc_CalcWindowEnergy( BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl,
+ INT windowLen);
+
+
+/****************** Constants *****************************/
+/* LONG START SHORT STOP LOWOV */
+static const INT blockType2windowShape[2][5] = { {SINE_WINDOW, KBD_WINDOW, WRONG_WINDOW, SINE_WINDOW, KBD_WINDOW}, /* LD */
+ {KBD_WINDOW, SINE_WINDOW, SINE_WINDOW, KBD_WINDOW, WRONG_WINDOW} }; /* LC */
+
+/* IIR high pass coeffs */
+
+#ifndef SINETABLE_16BIT
+
+static const FIXP_DBL hiPassCoeff[BLOCK_SWITCHING_IIR_LEN]=
+{
+ FL2FXCONST_DBL(-0.5095),FL2FXCONST_DBL(0.7548)
+};
+
+static const FIXP_DBL accWindowNrgFac = FL2FXCONST_DBL(0.3f); /* factor for accumulating filtered window energies */
+static const FIXP_DBL oneMinusAccWindowNrgFac = FL2FXCONST_DBL(0.7f);
+/* static const float attackRatio = 10.0; */ /* lower ratio limit for attacks */
+static const FIXP_DBL invAttackRatio = FL2FXCONST_DBL(0.1f); /* inverted lower ratio limit for attacks */
+
+/* The next constants are scaled, because they are used for comparison with scaled values*/
+/* minimum energy for attacks */
+static const FIXP_DBL minAttackNrg = (FL2FXCONST_DBL(1e+6f*NORM_PCM_ENERGY)>>BLOCK_SWITCH_ENERGY_SHIFT); /* minimum energy for attacks */
+
+#else
+
+static const FIXP_SGL hiPassCoeff[BLOCK_SWITCHING_IIR_LEN]=
+{
+ FL2FXCONST_SGL(-0.5095),FL2FXCONST_SGL(0.7548)
+};
+
+static const FIXP_DBL accWindowNrgFac = FL2FXCONST_DBL(0.3f); /* factor for accumulating filtered window energies */
+static const FIXP_SGL oneMinusAccWindowNrgFac = FL2FXCONST_SGL(0.7f);
+/* static const float attackRatio = 10.0; */ /* lower ratio limit for attacks */
+static const FIXP_SGL invAttackRatio = FL2FXCONST_SGL(0.1f); /* inverted lower ratio limit for attacks */
+/* minimum energy for attacks */
+static const FIXP_DBL minAttackNrg = (FL2FXCONST_DBL(1e+6f*NORM_PCM_ENERGY)>>BLOCK_SWITCH_ENERGY_SHIFT); /* minimum energy for attacks */
+
+#endif
+
+/**************** internal function prototypes ***********/
+
+static INT FDKaacEnc_GetWindowIndex(INT blockSwWindowIndex);
+
+static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT shortWndIdx);
+
+static void FDKaacEnc_CalcWindowEnergy( BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl,
+ INT windowLen);
+
+
+
+/****************** Routines ****************************/
+void FDKaacEnc_InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, INT isLowDelay)
+{
+ /* note: the pointer to timeSignal can be zeroed here, because it is initialized for every call
+ to FDKaacEnc_BlockSwitching anew */
+ FDKmemclear (blockSwitchingControl, sizeof(BLOCK_SWITCHING_CONTROL));
+
+ if (isLowDelay)
+ {
+ blockSwitchingControl->nBlockSwitchWindows = 4;
+ blockSwitchingControl->allowShortFrames = 0;
+ blockSwitchingControl->allowLookAhead = 0;
+ }
+ else
+ {
+ blockSwitchingControl->nBlockSwitchWindows = 8;
+ blockSwitchingControl->allowShortFrames = 1;
+ blockSwitchingControl->allowLookAhead = 1;
+ }
+
+ blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS;
+
+ /* Initialize startvalue for blocktype */
+ blockSwitchingControl->lastWindowSequence = LONG_WINDOW;
+ blockSwitchingControl->windowShape = blockType2windowShape[blockSwitchingControl->allowShortFrames][blockSwitchingControl->lastWindowSequence];
+
+}
+
+static const INT suggestedGroupingTable[TRANS_FAC][MAX_NO_OF_GROUPS] =
+{
+ /* Attack in Window 0 */ {1, 3, 3, 1},
+ /* Attack in Window 1 */ {1, 1, 3, 3},
+ /* Attack in Window 2 */ {2, 1, 3, 2},
+ /* Attack in Window 3 */ {3, 1, 3, 1},
+ /* Attack in Window 4 */ {3, 1, 1, 3},
+ /* Attack in Window 5 */ {3, 2, 1, 2},
+ /* Attack in Window 6 */ {3, 3, 1, 1},
+ /* Attack in Window 7 */ {3, 3, 1, 1}
+};
+
+/* change block type depending on current blocktype and whether there's an attack */
+/* assume no look-ahead */
+static const INT chgWndSq[2][N_BLOCKTYPES] =
+{
+ /* LONG WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW, LOWOV_WINDOW, WRONG_WINDOW */
+ /*no attack*/ {LONG_WINDOW, STOP_WINDOW, WRONG_WINDOW, LONG_WINDOW, STOP_WINDOW , WRONG_WINDOW },
+ /*attack */ {START_WINDOW, LOWOV_WINDOW, WRONG_WINDOW, START_WINDOW, LOWOV_WINDOW, WRONG_WINDOW }
+};
+
+/* change block type depending on current blocktype and whether there's an attack */
+/* assume look-ahead */
+static const INT chgWndSqLkAhd[2][2][N_BLOCKTYPES] =
+{
+ /*attack LONG WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW LOWOV_WINDOW, WRONG_WINDOW */ /* last attack */
+ /*no attack*/ { {LONG_WINDOW, SHORT_WINDOW, STOP_WINDOW, LONG_WINDOW, WRONG_WINDOW, WRONG_WINDOW}, /* no attack */
+ /*attack */ {START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, START_WINDOW, WRONG_WINDOW, WRONG_WINDOW} }, /* no attack */
+ /*no attack*/ { {LONG_WINDOW, SHORT_WINDOW, SHORT_WINDOW, LONG_WINDOW, WRONG_WINDOW, WRONG_WINDOW}, /* attack */
+ /*attack */ {START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, START_WINDOW, WRONG_WINDOW, WRONG_WINDOW} } /* attack */
+};
+
+int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE)
+{
+ UINT i;
+ FIXP_DBL enM1, enMax;
+
+ UINT nBlockSwitchWindows = blockSwitchingControl->nBlockSwitchWindows;
+
+ /* for LFE : only LONG window allowed */
+ if (isLFE) {
+
+ /* case LFE: */
+ /* only long blocks, always use sine windows (MPEG2 AAC, MPEG4 AAC) */
+ blockSwitchingControl->lastWindowSequence = LONG_WINDOW;
+ blockSwitchingControl->windowShape = SINE_WINDOW;
+ blockSwitchingControl->noOfGroups = 1;
+ blockSwitchingControl->groupLen[0] = 1;
+
+ return(0);
+ };
+
+ /* Save current attack index as last attack index */
+ blockSwitchingControl->lastattack = blockSwitchingControl->attack;
+ blockSwitchingControl->lastAttackIndex = blockSwitchingControl->attackIndex;
+
+ /* Save current window energy as last window energy */
+ FDKmemcpy(blockSwitchingControl->windowNrg[0], blockSwitchingControl->windowNrg[1], sizeof(blockSwitchingControl->windowNrg[0]));
+ FDKmemcpy(blockSwitchingControl->windowNrgF[0], blockSwitchingControl->windowNrgF[1], sizeof(blockSwitchingControl->windowNrgF[0]));
+
+ if (blockSwitchingControl->allowShortFrames)
+ {
+ /* Calculate suggested grouping info for the last frame */
+
+ /* Reset grouping info */
+ FDKmemclear (blockSwitchingControl->groupLen, sizeof(blockSwitchingControl->groupLen));
+
+ /* Set grouping info */
+ blockSwitchingControl->noOfGroups = MAX_NO_OF_GROUPS;
+
+ FDKmemcpy(blockSwitchingControl->groupLen, suggestedGroupingTable[blockSwitchingControl->lastAttackIndex], sizeof(blockSwitchingControl->groupLen));
+
+ if (blockSwitchingControl->attack == TRUE)
+ blockSwitchingControl->maxWindowNrg = FDKaacEnc_GetWindowEnergy(blockSwitchingControl->windowNrg[0], blockSwitchingControl->lastAttackIndex);
+ else
+ blockSwitchingControl->maxWindowNrg = FL2FXCONST_DBL(0.0);
+
+ }
+
+
+ /* Calculate unfiltered and filtered energies in subwindows and combine to segments */
+ FDKaacEnc_CalcWindowEnergy(blockSwitchingControl, granuleLength>>(nBlockSwitchWindows==4? 2:3 ));
+
+ /* now calculate if there is an attack */
+
+ /* reset attack */
+ blockSwitchingControl->attack = FALSE;
+
+ /* look for attack */
+ enMax = FL2FXCONST_DBL(0.0f);
+ enM1 = blockSwitchingControl->windowNrgF[0][nBlockSwitchWindows-1];
+
+ for (i=0; i<nBlockSwitchWindows; i++) {
+ FIXP_DBL tmp = fMultDiv2(oneMinusAccWindowNrgFac, blockSwitchingControl->accWindowNrg);
+ blockSwitchingControl->accWindowNrg = fMultAdd(tmp, accWindowNrgFac, enM1) ;
+
+ if (fMult(blockSwitchingControl->windowNrgF[1][i],invAttackRatio) > blockSwitchingControl->accWindowNrg ) {
+ blockSwitchingControl->attack = TRUE;
+ blockSwitchingControl->attackIndex = i;
+ }
+ enM1 = blockSwitchingControl->windowNrgF[1][i];
+ enMax = fixMax(enMax, enM1);
+ }
+
+
+ if (enMax < minAttackNrg) blockSwitchingControl->attack = FALSE;
+
+ /* Check if attack spreads over frame border */
+ if((blockSwitchingControl->attack == FALSE) && (blockSwitchingControl->lastattack == TRUE)) {
+ /* if attack is in last window repeat SHORT_WINDOW */
+ if ( ((blockSwitchingControl->windowNrgF[0][nBlockSwitchWindows-1]>>4) > fMult((FIXP_DBL)(10<<(DFRACT_BITS-1-4)), blockSwitchingControl->windowNrgF[1][1]))
+ && (blockSwitchingControl->lastAttackIndex == (INT)nBlockSwitchWindows-1)
+ )
+ {
+ blockSwitchingControl->attack = TRUE;
+ blockSwitchingControl->attackIndex = 0;
+ }
+ }
+
+
+ if(blockSwitchingControl->allowLookAhead)
+ {
+
+
+ blockSwitchingControl->lastWindowSequence =
+ chgWndSqLkAhd[blockSwitchingControl->lastattack][blockSwitchingControl->attack][blockSwitchingControl->lastWindowSequence];
+ }
+ else
+ {
+ /* Low Delay */
+ blockSwitchingControl->lastWindowSequence =
+ chgWndSq[blockSwitchingControl->attack][blockSwitchingControl->lastWindowSequence];
+ }
+
+
+ /* update window shape */
+ blockSwitchingControl->windowShape = blockType2windowShape[blockSwitchingControl->allowShortFrames][blockSwitchingControl->lastWindowSequence];
+
+ return(0);
+}
+
+
+
+static FIXP_DBL FDKaacEnc_GetWindowEnergy(const FIXP_DBL in[], const INT blSwWndIdx)
+{
+/* For coherency, change FDKaacEnc_GetWindowEnergy() to calcluate the energy for a block switching analysis windows,
+ not for a short block. The same is done FDKaacEnc_CalcWindowEnergy(). The result of FDKaacEnc_GetWindowEnergy()
+ is used for a comparision of the max energy of left/right channel. */
+
+ return in[blSwWndIdx];
+
+}
+
+
+static void FDKaacEnc_CalcWindowEnergy(BLOCK_SWITCHING_CONTROL *RESTRICT blockSwitchingControl, INT windowLen)
+{
+ INT i;
+ UINT w;
+
+ FIXP_SGL hiPassCoeff0 = hiPassCoeff[0];
+ FIXP_SGL hiPassCoeff1 = hiPassCoeff[1];
+
+ INT_PCM *timeSignal = blockSwitchingControl->timeSignal;
+
+ /* sum up scalarproduct of timesignal as windowed Energies */
+ for (w=0; w < blockSwitchingControl->nBlockSwitchWindows; w++) {
+
+ FIXP_DBL temp_windowNrg = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL temp_windowNrgF = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL temp_iirState0 = blockSwitchingControl->iirStates[0];
+ FIXP_DBL temp_iirState1 = blockSwitchingControl->iirStates[1];
+
+ /* windowNrg = sum(timesample^2) */
+ for(i=0;i<windowLen;i++)
+ {
+
+ FIXP_DBL tempUnfiltered, tempFiltred, t1, t2;
+ /* tempUnfiltered is scaled with 1 to prevent overflows during calculation of tempFiltred */
+#if SAMPLE_BITS == DFRACT_BITS
+ tempUnfiltered = (FIXP_DBL) *timeSignal++ >> 1;
+#else
+ tempUnfiltered = (FIXP_DBL) *timeSignal++ << (DFRACT_BITS-SAMPLE_BITS-1);
+#endif
+ t1 = fMultDiv2(hiPassCoeff1, tempUnfiltered-temp_iirState0);
+ t2 = fMultDiv2(hiPassCoeff0, temp_iirState1);
+ tempFiltred = (t1 - t2) << 1;
+
+ temp_iirState0 = tempUnfiltered;
+ temp_iirState1 = tempFiltred;
+
+ /* subtract 2 from overallscaling (BLOCK_SWITCH_ENERGY_SHIFT)
+ * because tempUnfiltered was already scaled with 1 (is 2 after squaring)
+ * subtract 1 from overallscaling (BLOCK_SWITCH_ENERGY_SHIFT)
+ * because of fMultDiv2 is doing a scaling by one */
+ temp_windowNrg += fPow2Div2(tempUnfiltered) >> (BLOCK_SWITCH_ENERGY_SHIFT - 1 - 2);
+ temp_windowNrgF += fPow2Div2(tempFiltred) >> (BLOCK_SWITCH_ENERGY_SHIFT - 1 - 2);
+ }
+ blockSwitchingControl->windowNrg[1][w] = temp_windowNrg;
+ blockSwitchingControl->windowNrgF[1][w] = temp_windowNrgF;
+ blockSwitchingControl->iirStates[0] = temp_iirState0;
+ blockSwitchingControl->iirStates[1] = temp_iirState1;
+ }
+}
+
+
+static const UCHAR synchronizedBlockTypeTable[5][5] =
+{
+ /* LONG_WINDOW START_WINDOW SHORT_WINDOW STOP_WINDOW LOWOV_WINDOW*/
+ /* LONG_WINDOW */ {LONG_WINDOW, START_WINDOW, SHORT_WINDOW, STOP_WINDOW, LOWOV_WINDOW},
+ /* START_WINDOW */ {START_WINDOW, START_WINDOW, SHORT_WINDOW, SHORT_WINDOW, LOWOV_WINDOW},
+ /* SHORT_WINDOW */ {SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, SHORT_WINDOW, WRONG_WINDOW},
+ /* STOP_WINDOW */ {STOP_WINDOW, SHORT_WINDOW, SHORT_WINDOW, STOP_WINDOW, LOWOV_WINDOW},
+ /* LOWOV_WINDOW */ {LOWOV_WINDOW, LOWOV_WINDOW, WRONG_WINDOW, LOWOV_WINDOW, LOWOV_WINDOW},
+};
+
+int FDKaacEnc_SyncBlockSwitching (
+ BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft,
+ BLOCK_SWITCHING_CONTROL *blockSwitchingControlRight,
+ const INT nChannels,
+ const INT commonWindow )
+{
+ UCHAR patchType = LONG_WINDOW;
+
+ if( nChannels == 2 && commonWindow == TRUE)
+ {
+ /* could be better with a channel loop (need a handle to psy_data) */
+ /* get suggested Block Types and synchronize */
+ patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlLeft->lastWindowSequence];
+ patchType = synchronizedBlockTypeTable[patchType][blockSwitchingControlRight->lastWindowSequence];
+
+ /* sanity check (no change from low overlap window to short winow and vice versa) */
+ if (patchType == WRONG_WINDOW)
+ return -1; /* mixed up AAC-LC and AAC-LD */
+
+ /* Set synchronized Blocktype */
+ blockSwitchingControlLeft->lastWindowSequence = patchType;
+ blockSwitchingControlRight->lastWindowSequence = patchType;
+
+ /* update window shape */
+ blockSwitchingControlLeft->windowShape = blockType2windowShape[blockSwitchingControlLeft->allowShortFrames][blockSwitchingControlLeft->lastWindowSequence];
+ blockSwitchingControlRight->windowShape = blockType2windowShape[blockSwitchingControlLeft->allowShortFrames][blockSwitchingControlRight->lastWindowSequence];
+ }
+
+ if (blockSwitchingControlLeft->allowShortFrames)
+ {
+ int i;
+
+ if( nChannels == 2 )
+ {
+ if (commonWindow == TRUE)
+ {
+ /* Synchronize grouping info */
+ int windowSequenceLeftOld = blockSwitchingControlLeft->lastWindowSequence;
+ int windowSequenceRightOld = blockSwitchingControlRight->lastWindowSequence;
+
+ /* Long Blocks */
+ if(patchType != SHORT_WINDOW) {
+ /* Set grouping info */
+ blockSwitchingControlLeft->noOfGroups = 1;
+ blockSwitchingControlRight->noOfGroups = 1;
+ blockSwitchingControlLeft->groupLen[0] = 1;
+ blockSwitchingControlRight->groupLen[0] = 1;
+
+ for (i = 1; i < MAX_NO_OF_GROUPS; i++)
+ {
+ blockSwitchingControlLeft->groupLen[i] = 0;
+ blockSwitchingControlRight->groupLen[i] = 0;
+ }
+ }
+
+ /* Short Blocks */
+ else {
+ /* in case all two channels were detected as short-blocks before syncing, use the grouping of channel with higher maxWindowNrg */
+ if( (windowSequenceLeftOld == SHORT_WINDOW) &&
+ (windowSequenceRightOld == SHORT_WINDOW) )
+ {
+ if(blockSwitchingControlLeft->maxWindowNrg > blockSwitchingControlRight->maxWindowNrg) {
+ /* Left Channel wins */
+ blockSwitchingControlRight->noOfGroups = blockSwitchingControlLeft->noOfGroups;
+ for (i = 0; i < MAX_NO_OF_GROUPS; i++){
+ blockSwitchingControlRight->groupLen[i] = blockSwitchingControlLeft->groupLen[i];
+ }
+ }
+ else {
+ /* Right Channel wins */
+ blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups;
+ for (i = 0; i < MAX_NO_OF_GROUPS; i++){
+ blockSwitchingControlLeft->groupLen[i] = blockSwitchingControlRight->groupLen[i];
+ }
+ }
+ }
+ else if ( (windowSequenceLeftOld == SHORT_WINDOW) &&
+ (windowSequenceRightOld != SHORT_WINDOW) )
+ {
+ /* else use grouping of short-block channel */
+ blockSwitchingControlRight->noOfGroups = blockSwitchingControlLeft->noOfGroups;
+ for (i = 0; i < MAX_NO_OF_GROUPS; i++){
+ blockSwitchingControlRight->groupLen[i] = blockSwitchingControlLeft->groupLen[i];
+ }
+ }
+ else if ( (windowSequenceRightOld == SHORT_WINDOW) &&
+ (windowSequenceLeftOld != SHORT_WINDOW) )
+ {
+ blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups;
+ for (i = 0; i < MAX_NO_OF_GROUPS; i++){
+ blockSwitchingControlLeft->groupLen[i] = blockSwitchingControlRight->groupLen[i];
+ }
+ } else {
+ /* syncing a start and stop window ... */
+ /* use a standard grouping,
+ best grouping still to be determined! rtb 2006 06 07 */
+ blockSwitchingControlLeft->noOfGroups = blockSwitchingControlRight->noOfGroups = 2;
+ blockSwitchingControlLeft->groupLen[0] = blockSwitchingControlRight->groupLen[0] = 4;
+ blockSwitchingControlLeft->groupLen[1] = blockSwitchingControlRight->groupLen[1] = 4;
+ }
+ } /* Short Blocks */
+ }
+ else {
+ /* stereo, no common window */
+ if (blockSwitchingControlLeft->lastWindowSequence!=SHORT_WINDOW){
+ blockSwitchingControlLeft->noOfGroups = 1;
+ blockSwitchingControlLeft->groupLen[0] = 1;
+ for (i = 1; i < MAX_NO_OF_GROUPS; i++)
+ {
+ blockSwitchingControlLeft->groupLen[i] = 0;
+ }
+ }
+ if (blockSwitchingControlRight->lastWindowSequence!=SHORT_WINDOW){
+ blockSwitchingControlRight->noOfGroups = 1;
+ blockSwitchingControlRight->groupLen[0] = 1;
+ for (i = 1; i < MAX_NO_OF_GROUPS; i++)
+ {
+ blockSwitchingControlRight->groupLen[i] = 0;
+ }
+ }
+ } /* common window */
+ } else {
+ /* Mono */
+ if (blockSwitchingControlLeft->lastWindowSequence!=SHORT_WINDOW){
+ blockSwitchingControlLeft->noOfGroups = 1;
+ blockSwitchingControlLeft->groupLen[0] = 1;
+
+ for (i = 1; i < MAX_NO_OF_GROUPS; i++)
+ {
+ blockSwitchingControlLeft->groupLen[i] = 0;
+ }
+ }
+ }
+ } /* allowShortFrames */
+
+#ifdef BLOCK_SWITCH_DEBUG_INFO
+ FDKprintf("l:%d\tr:%d\n", blockSwitchingControlLeft->lastWindowSequence, blockSwitchingControlRight->lastWindowSequence);
+#endif
+
+ /* Translate LOWOV_WINDOW block type to a meaningful window shape. */
+ if ( ! blockSwitchingControlLeft->allowShortFrames ) {
+ if ( blockSwitchingControlLeft->lastWindowSequence != LONG_WINDOW
+ && blockSwitchingControlLeft->lastWindowSequence != STOP_WINDOW )
+ {
+ blockSwitchingControlLeft->lastWindowSequence = LONG_WINDOW;
+ blockSwitchingControlLeft->windowShape = LOL_WINDOW;
+ }
+ }
+ if (nChannels == 2) {
+ if ( ! blockSwitchingControlRight->allowShortFrames ) {
+ if ( blockSwitchingControlRight->lastWindowSequence != LONG_WINDOW
+ && blockSwitchingControlRight->lastWindowSequence != STOP_WINDOW )
+ {
+ blockSwitchingControlRight->lastWindowSequence = LONG_WINDOW;
+ blockSwitchingControlRight->windowShape = LOL_WINDOW;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
diff --git a/libAACenc/src/block_switch.h b/libAACenc/src/block_switch.h
new file mode 100644
index 0000000..f9eaa81
--- /dev/null
+++ b/libAACenc/src/block_switch.h
@@ -0,0 +1,85 @@
+/***************************** MPEG-4 AAC Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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): M. Werner
+ Description: Block switching
+
+ 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 _BLOCK_SWITCH_H
+#define _BLOCK_SWITCH_H
+
+#include "common_fix.h"
+
+#include "psy_const.h"
+
+/****************** Defines ******************************/
+ #define BLOCK_SWITCH_WINDOWS 8 /* number of windows for energy calculation */
+
+#define BLOCK_SWITCHING_IIR_LEN 2 /* Length of HighPass-IIR-Filter for Attack-Detection */
+#define BLOCK_SWITCH_ENERGY_SHIFT 7 /* should be logDualis(BLOCK_SWITCH_WINDOW_LEN) to avoid overflow in windowNrgs. */
+
+#define LAST_WINDOW 0
+#define THIS_WINDOW 1
+
+
+/****************** Structures ***************************/
+typedef struct{
+ INT_PCM *timeSignal;
+ INT lastWindowSequence;
+ INT windowShape;
+ INT lastWindowShape;
+ UINT nBlockSwitchWindows; /* number of windows for energy calculation */
+ INT attack;
+ INT lastattack;
+ INT attackIndex;
+ INT lastAttackIndex;
+ INT allowShortFrames; /* for Low Delay, don't allow short frames */
+ INT allowLookAhead; /* for Low Delay, don't do look-ahead */
+ INT noOfGroups;
+ INT groupLen[MAX_NO_OF_GROUPS];
+ FIXP_DBL maxWindowNrg; /* max energy in subwindows */
+
+ FIXP_DBL windowNrg[2][BLOCK_SWITCH_WINDOWS]; /* time signal energy in Subwindows (last and current) */
+ FIXP_DBL windowNrgF[2][BLOCK_SWITCH_WINDOWS]; /* filtered time signal energy in segments (last and current) */
+ FIXP_DBL accWindowNrg; /* recursively accumulated windowNrgF */
+
+ FIXP_DBL iirStates[BLOCK_SWITCHING_IIR_LEN]; /* filter delay-line */
+
+} BLOCK_SWITCHING_CONTROL;
+
+
+
+
+
+void FDKaacEnc_InitBlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, INT isLowDelay);
+
+int FDKaacEnc_BlockSwitching(BLOCK_SWITCHING_CONTROL *blockSwitchingControl, const INT granuleLength, const int isLFE);
+
+int FDKaacEnc_SyncBlockSwitching(
+ BLOCK_SWITCHING_CONTROL *blockSwitchingControlLeft,
+ BLOCK_SWITCHING_CONTROL *blockSwitchingControlRight,
+ const INT noOfChannels,
+ const INT commonWindow);
+
+#endif /* #ifndef _BLOCK_SWITCH_H */
diff --git a/libAACenc/src/channel_map.cpp b/libAACenc/src/channel_map.cpp
new file mode 100644
index 0000000..0f1cb4f
--- /dev/null
+++ b/libAACenc/src/channel_map.cpp
@@ -0,0 +1,499 @@
+/************************* Fast MPEG AAC Audio Encoder **********************
+
+ (C) Copyright Fraunhofer IIS (2000)
+ 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$
+ Initial author: A. Groeschel
+ contents/description: channel mapping functionality
+
+******************************************************************************/
+
+#include "channel_map.h"
+#include "bitenc.h"
+#include "psy_const.h"
+#include "qc_data.h"
+#include "aacEnc_ram.h"
+
+
+/* channel_assignment treats the relationship of Input file channels
+ to the encoder channels.
+ This is necessary because the usual order in RIFF files (.wav)
+ is different from the elements order in the coder given
+ by Table 8.1 (implicit speaker mapping) of the AAC standard.
+
+ In mono and stereo case, this is trivial.
+ In mc case, it looks like this:
+
+ Channel Input file coder chan
+5ch:
+ front center 2 0 (SCE channel)
+ left center 0 1 (1st of 1st CPE)
+ right center 1 2 (2nd of 1st CPE)
+ left surround 3 3 (1st of 2nd CPE)
+ right surround 4 4 (2nd of 2nd CPE)
+
+5.1ch:
+ front center 2 0 (SCE channel)
+ left center 0 1 (1st of 1st CPE)
+ right center 1 2 (2nd of 1st CPE)
+ left surround 4 3 (1st of 2nd CPE)
+ right surround 5 4 (2nd of 2nd CPE)
+ LFE 3 5 (LFE)
+*/
+
+typedef struct {
+
+ CHANNEL_MODE encoderMode;
+ INT channel_assignment[/*(6)*/12];
+
+} CHANNEL_ASSIGNMENT_INFO_TAB;
+
+
+static const CHANNEL_ASSIGNMENT_INFO_TAB assignmentInfoTabMpeg[] =
+{
+ { MODE_INVALID, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* invalid */
+ { MODE_1, { 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* mono */
+ { MODE_2, { 0, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* stereo */
+ { MODE_1_2, { 0, 1, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* 3ch */
+ { MODE_1_2_1, { 0, 1, 2, 3,-1,-1,-1,-1,-1,-1,-1,-1} }, /* 4ch */
+ { MODE_1_2_2, { 0, 1, 2, 3, 4,-1,-1,-1,-1,-1,-1,-1} }, /* 5ch */
+ { MODE_1_2_2_1, { 0, 1, 2, 3, 4, 5,-1,-1,-1,-1,-1,-1} }, /* 5.1ch */
+ { MODE_1_2_2_2_1, { 0, 1, 2, 3, 4, 5, 6, 7,-1,-1,-1,-1} }, /* 7.1ch */
+};
+
+static const CHANNEL_ASSIGNMENT_INFO_TAB assignmentInfoTabWav[] =
+{
+ { MODE_INVALID, {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* invalid */
+ { MODE_1, { 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* mono */
+ { MODE_2, { 0, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* stereo */
+ { MODE_1_2, { 2, 0, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1} }, /* 3ch */
+ { MODE_1_2_1, { 2, 0, 1, 3,-1,-1,-1,-1,-1,-1,-1,-1} }, /* 4ch */
+ { MODE_1_2_2, { 2, 0, 1, 3, 4,-1,-1,-1,-1,-1,-1,-1} }, /* 5ch */
+ { MODE_1_2_2_1, { 2, 0, 1, 4, 5, 3,-1,-1,-1,-1,-1,-1} }, /* 5.1ch */
+ { MODE_1_2_2_2_1, { 2, 0, 1, 6, 7, 4, 5, 3,-1,-1,-1,-1} }, /* 7.1ch */
+};
+
+/* Channel mode configuration tab provides,
+ corresponding number of channels and elements
+*/
+static const CHANNEL_MODE_CONFIG_TAB channelModeConfig[] =
+{
+ { MODE_1, 1, 1, 1 }, /* SCE */
+ { MODE_2, 2, 2, 1 }, /* CPE */
+ { MODE_1_2, 3, 3, 2 }, /* SCE,CPE */
+ { MODE_1_2_1, 4, 4, 3 }, /* SCE,CPE,SCE */
+ { MODE_1_2_2, 5, 5, 3 }, /* SCE,CPE,CPE */
+ { MODE_1_2_2_1, 6, 5, 4 }, /* SCE,CPE,CPE,LFE */
+ { MODE_1_2_2_2_1, 8, 7, 5 }, /* SCE,CPE,CPE,CPE,LFE */
+};
+
+#define MAX_MODES (sizeof(assignmentInfoTabWav)/sizeof(CHANNEL_ASSIGNMENT_INFO_TAB))
+
+const INT* FDKaacEnc_getChannelAssignment(CHANNEL_MODE encMode, CHANNEL_ORDER co)
+{
+ const CHANNEL_ASSIGNMENT_INFO_TAB *pTab;
+ int i;
+
+ if (co == CH_ORDER_MPEG)
+ pTab = assignmentInfoTabMpeg;
+ else
+ pTab = assignmentInfoTabWav;
+
+ for(i=MAX_MODES-1; i>0; i--) {
+ if (encMode== pTab[i].encoderMode) {
+ break;
+ }
+ }
+ return (pTab[i].channel_assignment);
+}
+
+AAC_ENCODER_ERROR FDKaacEnc_DetermineEncoderMode(CHANNEL_MODE* mode, INT nChannels)
+{
+ INT i;
+ CHANNEL_MODE encMode = MODE_INVALID;
+
+ if (*mode==MODE_UNKNOWN) {
+ for (i=0; i<(INT)sizeof(channelModeConfig)/(INT)sizeof(CHANNEL_MODE_CONFIG_TAB); i++) {
+ if (channelModeConfig[i].nChannels==nChannels) {
+ encMode = channelModeConfig[i].encMode;
+ break;
+ }
+ }
+ *mode = encMode;
+ }
+ else {
+ /* check if valid channel configuration */
+ if (FDKaacEnc_GetChannelModeConfiguration(*mode)->nChannels==nChannels) {
+ encMode = *mode;
+ }
+ }
+
+ if (encMode==MODE_INVALID) {
+ return AAC_ENC_UNSUPPORTED_CHANNELCONFIG;
+ }
+
+ return AAC_ENC_OK;
+}
+
+static INT FDKaacEnc_initElement (ELEMENT_INFO* elInfo, MP4_ELEMENT_ID elType, INT* cnt, CHANNEL_MODE mode, CHANNEL_ORDER co, INT* it_cnt, const FIXP_DBL relBits) {
+
+ INT error=0;
+ INT counter =*cnt;
+
+ const INT *assign = FDKaacEnc_getChannelAssignment(mode, co);
+
+ elInfo->elType=elType;
+ elInfo->relativeBits = relBits;
+
+ switch(elInfo->elType) {
+ case ID_SCE: case ID_LFE: case ID_CCE:
+ elInfo->nChannelsInEl=1;
+ elInfo->ChannelIndex[0]=assign[counter++];
+ elInfo->instanceTag=it_cnt[elType]++;
+
+ break;
+ case ID_CPE:
+ elInfo->nChannelsInEl=2;
+ elInfo->ChannelIndex[0]=assign[counter++];
+ elInfo->ChannelIndex[1]=assign[counter++];
+ elInfo->instanceTag=it_cnt[elType]++;
+ break;
+ case ID_DSE:
+ elInfo->nChannelsInEl=0;
+ elInfo->ChannelIndex[0]=0;
+ elInfo->ChannelIndex[1]=0;
+ elInfo->instanceTag=it_cnt[elType]++;
+ break;
+ default: error=1;
+ };
+ *cnt = counter;
+ return error;
+
+}
+
+AAC_ENCODER_ERROR FDKaacEnc_InitChannelMapping(CHANNEL_MODE mode, CHANNEL_ORDER co, CHANNEL_MAPPING* cm)
+{
+ INT count=0; /* count through coder channels */
+ INT it_cnt[ID_END+1];
+ INT i;
+
+ for (i=0; i<ID_END; i++)
+ it_cnt[i]=0;
+
+ FDKmemclear(cm, sizeof(CHANNEL_MAPPING));
+
+ /* init channel mapping*/
+ for (i=0; i<(INT)sizeof(channelModeConfig)/(INT)sizeof(CHANNEL_MODE_CONFIG_TAB); i++) {
+ if (channelModeConfig[i].encMode==mode)
+ {
+ cm->encMode = channelModeConfig[i].encMode;
+ cm->nChannels = channelModeConfig[i].nChannels;
+ cm->nChannelsEff = channelModeConfig[i].nChannelsEff;
+ cm->nElements = channelModeConfig[i].nElements;
+
+ break;
+ }
+ }
+
+ /* init element info struct */
+ switch(mode) {
+ case MODE_1:
+ /* (mono) sce */
+ FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, (FIXP_DBL)MAXVAL_DBL);
+ break;
+ case MODE_2:
+ /* (stereo) cpe */
+ FDKaacEnc_initElement(&cm->elInfo[0], ID_CPE, &count, mode, co, it_cnt, (FIXP_DBL)MAXVAL_DBL);
+ break;
+
+ case MODE_1_2:
+ /* sce + cpe */
+ FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.4f));
+ FDKaacEnc_initElement(&cm->elInfo[1], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.6f));
+ break;
+
+ case MODE_1_2_1:
+ /* sce + cpe + sce */
+ FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.3f));
+ FDKaacEnc_initElement(&cm->elInfo[1], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.4f));
+ FDKaacEnc_initElement(&cm->elInfo[2], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.3f));
+ break;
+
+ case MODE_1_2_2:
+ /* sce + cpe + cpe */
+ FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.26f));
+ FDKaacEnc_initElement(&cm->elInfo[1], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.37f));
+ FDKaacEnc_initElement(&cm->elInfo[2], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.37f));
+ break;
+
+ case MODE_1_2_2_1:
+ /* (5.1) sce + cpe + cpe + lfe */
+ FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.24f));
+ FDKaacEnc_initElement(&cm->elInfo[1], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.35f));
+ FDKaacEnc_initElement(&cm->elInfo[2], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.35f));
+ FDKaacEnc_initElement(&cm->elInfo[3], ID_LFE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.06f));
+ break;
+
+ case MODE_1_2_2_2_1:
+ /* (7.1) sce + cpe + cpe + cpe + lfe */
+ FDKaacEnc_initElement(&cm->elInfo[0], ID_SCE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.18f));
+ FDKaacEnc_initElement(&cm->elInfo[1], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.26f));
+ FDKaacEnc_initElement(&cm->elInfo[2], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.26f));
+ FDKaacEnc_initElement(&cm->elInfo[3], ID_CPE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.26f));
+ FDKaacEnc_initElement(&cm->elInfo[4], ID_LFE, &count, mode, co, it_cnt, FL2FXCONST_DBL(0.04f));
+ break;
+
+ default:
+ //*chMap=0;
+ return AAC_ENC_UNSUPPORTED_CHANNELCONFIG;
+ };
+
+ /* Prevent additional element and save memory for unused PSY_OUT_ELEMENT,
+ ATS_ELEMENT, QC_OUT_ELEMENT ...
+ DSE signalling is done via elDSE flag.
+ */
+// if (dseFlag == 1) {
+// it_cnt[ID_DSE]++; /* increment DSE */
+// }
+// cm->elDSE = it_cnt[ID_DSE]; /* save number of DSE elemts */
+
+ FDK_ASSERT(cm->nElements<=(6));
+
+ //*chMap = cm;
+
+ return AAC_ENC_OK;
+}
+
+AAC_ENCODER_ERROR FDKaacEnc_InitElementBits(QC_STATE *hQC,
+ CHANNEL_MAPPING *cm,
+ INT bitrateTot,
+ INT averageBitsTot,
+ INT maxChannelBits)
+{
+ int sc_brTot = CountLeadingBits(bitrateTot);
+
+ switch(cm->encMode) {
+ case MODE_1:
+ hQC->elementBits[0]->chBitrateEl = bitrateTot;
+
+ hQC->elementBits[0]->maxBitsEl = maxChannelBits;
+
+ hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits;
+ break;
+
+ case MODE_2:
+ hQC->elementBits[0]->chBitrateEl = bitrateTot>>1;
+
+ hQC->elementBits[0]->maxBitsEl = 2*maxChannelBits;
+
+ hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits;
+ break;
+ case MODE_1_2: {
+ hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits;
+ hQC->elementBits[1]->relativeBitsEl = cm->elInfo[1].relativeBits;
+ FIXP_DBL sceRate = cm->elInfo[0].relativeBits;
+ FIXP_DBL cpeRate = cm->elInfo[1].relativeBits;
+
+ hQC->elementBits[0]->chBitrateEl = fMult(sceRate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>sc_brTot;
+ hQC->elementBits[1]->chBitrateEl = fMult(cpeRate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>(sc_brTot+1);
+
+ hQC->elementBits[0]->maxBitsEl = maxChannelBits;
+ hQC->elementBits[1]->maxBitsEl = 2*maxChannelBits;
+ break;
+ }
+ case MODE_1_2_1: {
+ /* sce + cpe + sce */
+ hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits;
+ hQC->elementBits[1]->relativeBitsEl = cm->elInfo[1].relativeBits;
+ hQC->elementBits[2]->relativeBitsEl = cm->elInfo[2].relativeBits;
+ FIXP_DBL sce1Rate = cm->elInfo[0].relativeBits;
+ FIXP_DBL cpeRate = cm->elInfo[1].relativeBits;
+ FIXP_DBL sce2Rate = cm->elInfo[2].relativeBits;
+
+ hQC->elementBits[0]->chBitrateEl = fMult(sce1Rate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>sc_brTot;
+ hQC->elementBits[1]->chBitrateEl = fMult(cpeRate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>(sc_brTot+1);
+ hQC->elementBits[2]->chBitrateEl = fMult(sce2Rate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>sc_brTot;
+
+ hQC->elementBits[0]->maxBitsEl = maxChannelBits;
+ hQC->elementBits[1]->maxBitsEl = 2*maxChannelBits;
+ hQC->elementBits[2]->maxBitsEl = maxChannelBits;
+ break;
+ }
+ case MODE_1_2_2: {
+ /* sce + cpe + cpe */
+ hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits;
+ hQC->elementBits[1]->relativeBitsEl = cm->elInfo[1].relativeBits;
+ hQC->elementBits[2]->relativeBitsEl = cm->elInfo[2].relativeBits;
+ FIXP_DBL sceRate = cm->elInfo[0].relativeBits;
+ FIXP_DBL cpe1Rate = cm->elInfo[1].relativeBits;
+ FIXP_DBL cpe2Rate = cm->elInfo[2].relativeBits;
+
+ hQC->elementBits[0]->chBitrateEl = fMult(sceRate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>sc_brTot;
+ hQC->elementBits[1]->chBitrateEl = fMult(cpe1Rate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>(sc_brTot+1);
+ hQC->elementBits[2]->chBitrateEl = fMult(cpe2Rate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>(sc_brTot+1);
+
+ hQC->elementBits[0]->maxBitsEl = maxChannelBits;
+ hQC->elementBits[1]->maxBitsEl = 2*maxChannelBits;
+ hQC->elementBits[2]->maxBitsEl = 2*maxChannelBits;
+ break;
+ }
+
+ case MODE_1_2_2_1: {
+ /* (5.1) sce + cpe + cpe + lfe */
+ hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits;
+ hQC->elementBits[1]->relativeBitsEl = cm->elInfo[1].relativeBits;
+ hQC->elementBits[2]->relativeBitsEl = cm->elInfo[2].relativeBits;
+ hQC->elementBits[3]->relativeBitsEl = cm->elInfo[3].relativeBits;
+ FIXP_DBL sceRate = cm->elInfo[0].relativeBits;
+ FIXP_DBL cpe1Rate = cm->elInfo[1].relativeBits;
+ FIXP_DBL cpe2Rate = cm->elInfo[2].relativeBits;
+ FIXP_DBL lfeRate = cm->elInfo[3].relativeBits;
+
+ int maxBitsTot = maxChannelBits * 5; /* LFE does not add to bit reservoir */
+ int sc = CountLeadingBits(fixMax(maxChannelBits,averageBitsTot));
+ int maxLfeBits = (int) FDKmax ( (INT)((fMult(lfeRate,(FIXP_DBL)(maxChannelBits<<sc))>>sc)<<1),
+ (INT)((fMult(FL2FXCONST_DBL(1.1f/2.f),fMult(lfeRate,(FIXP_DBL)(averageBitsTot<<sc)))<<1)>>sc) );
+
+ maxChannelBits = (maxBitsTot - maxLfeBits);
+ sc = CountLeadingBits(maxChannelBits);
+
+ maxChannelBits = fMult((FIXP_DBL)maxChannelBits<<sc,GetInvInt(5))>>sc;
+
+ hQC->elementBits[0]->chBitrateEl = fMult(sceRate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>sc_brTot;
+ hQC->elementBits[1]->chBitrateEl = fMult(cpe1Rate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>(sc_brTot+1);
+ hQC->elementBits[2]->chBitrateEl = fMult(cpe2Rate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>(sc_brTot+1);
+ hQC->elementBits[3]->chBitrateEl = fMult(lfeRate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>sc_brTot;
+
+ hQC->elementBits[0]->maxBitsEl = maxChannelBits;
+ hQC->elementBits[1]->maxBitsEl = 2*maxChannelBits;
+ hQC->elementBits[2]->maxBitsEl = 2*maxChannelBits;
+ hQC->elementBits[3]->maxBitsEl = maxLfeBits;
+
+ break;
+ }
+
+ case MODE_1_2_2_2_1:{
+ /* (7.1) sce + cpe + cpe + cpe + lfe */
+ hQC->elementBits[0]->relativeBitsEl = cm->elInfo[0].relativeBits;
+ hQC->elementBits[1]->relativeBitsEl = cm->elInfo[1].relativeBits;
+ hQC->elementBits[2]->relativeBitsEl = cm->elInfo[2].relativeBits;
+ hQC->elementBits[3]->relativeBitsEl = cm->elInfo[3].relativeBits;
+ hQC->elementBits[4]->relativeBitsEl = cm->elInfo[4].relativeBits;
+ FIXP_DBL sceRate = cm->elInfo[0].relativeBits;
+ FIXP_DBL cpe1Rate = cm->elInfo[1].relativeBits;
+ FIXP_DBL cpe2Rate = cm->elInfo[2].relativeBits;
+ FIXP_DBL cpe3Rate = cm->elInfo[3].relativeBits;
+ FIXP_DBL lfeRate = cm->elInfo[4].relativeBits;
+
+ int maxBitsTot = maxChannelBits * 7; /* LFE does not add to bit reservoir */
+ int sc = CountLeadingBits(fixMax(maxChannelBits,averageBitsTot));
+ int maxLfeBits = (int) FDKmax ( (INT)((fMult(lfeRate,(FIXP_DBL)(maxChannelBits<<sc))>>sc)<<1),
+ (INT)((fMult(FL2FXCONST_DBL(1.1f/2.f),fMult(lfeRate,(FIXP_DBL)(averageBitsTot<<sc)))<<1)>>sc) );
+
+ maxChannelBits = (maxBitsTot - maxLfeBits) / 7;
+
+ hQC->elementBits[0]->chBitrateEl = fMult(sceRate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>sc_brTot;
+ hQC->elementBits[1]->chBitrateEl = fMult(cpe1Rate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>(sc_brTot+1);
+ hQC->elementBits[2]->chBitrateEl = fMult(cpe2Rate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>(sc_brTot+1);
+ hQC->elementBits[3]->chBitrateEl = fMult(cpe3Rate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>(sc_brTot+1);
+ hQC->elementBits[4]->chBitrateEl = fMult(lfeRate, (FIXP_DBL)(bitrateTot<<sc_brTot))>>sc_brTot;
+
+ hQC->elementBits[0]->maxBitsEl = maxChannelBits;
+ hQC->elementBits[1]->maxBitsEl = 2*maxChannelBits;
+ hQC->elementBits[2]->maxBitsEl = 2*maxChannelBits;
+ hQC->elementBits[3]->maxBitsEl = 2*maxChannelBits;
+ hQC->elementBits[4]->maxBitsEl = maxLfeBits;
+ break;
+ }
+
+ default:
+ return AAC_ENC_UNSUPPORTED_CHANNELCONFIG;
+ }
+
+ return AAC_ENC_OK;
+}
+
+/********************************************************************************/
+/* */
+/* function: GetMonoStereoMODE(const CHANNEL_MODE mode) */
+/* */
+/* description: Determines encoder setting from channel mode. */
+/* Multichannel modes are mapped to mono or stereo modes */
+/* returns MODE_MONO in case of mono, */
+/* MODE_STEREO in case of stereo */
+/* MODE_INVALID in case of error */
+/* */
+/* input: CHANNEL_MODE mode: Encoder mode (see qc_data.h). */
+/* output: return: CM_STEREO_MODE monoStereoSetting */
+/* (MODE_INVALID: error, */
+/* MODE_MONO: mono */
+/* MODE_STEREO: stereo). */
+/* */
+/* misc: No memory is allocated. */
+/* */
+/********************************************************************************/
+
+ELEMENT_MODE FDKaacEnc_GetMonoStereoMode(const CHANNEL_MODE mode){
+
+ ELEMENT_MODE monoStereoSetting = EL_MODE_INVALID;
+
+ switch(mode){
+ case MODE_1: /* mono setups */
+ monoStereoSetting = EL_MODE_MONO;
+ break;
+ case MODE_2: /* stereo setups */
+ case MODE_1_2:
+ case MODE_1_2_1:
+ case MODE_1_2_2:
+ case MODE_1_2_2_1:
+ case MODE_1_2_2_2_1:
+ monoStereoSetting = EL_MODE_STEREO;
+ break;
+ default: /* error */
+ monoStereoSetting = EL_MODE_INVALID;
+ break;
+ }
+
+ return monoStereoSetting;
+}
+
+const CHANNEL_MODE_CONFIG_TAB* FDKaacEnc_GetChannelModeConfiguration(const CHANNEL_MODE mode)
+{
+ INT i;
+ const CHANNEL_MODE_CONFIG_TAB *cm_config = NULL;
+
+ /* get channel mode config */
+ for (i=0; i<(INT)sizeof(channelModeConfig)/(INT)sizeof(CHANNEL_MODE_CONFIG_TAB); i++) {
+ if (channelModeConfig[i].encMode==mode)
+ {
+ cm_config = &channelModeConfig[i];
+ break;
+ }
+ }
+ return cm_config;
+}
+
+/*
+void FDKaacEnc_CloseChannelMapping (CHANNEL_MAPPING** phchMap) {
+ FreeRam_ChannelMapping(phchMap);
+}
+*/
+
diff --git a/libAACenc/src/channel_map.h b/libAACenc/src/channel_map.h
new file mode 100644
index 0000000..8b60656
--- /dev/null
+++ b/libAACenc/src/channel_map.h
@@ -0,0 +1,72 @@
+/************************* Fast MPEG AAC Audio Encoder **********************
+
+ (C) Copyright Fraunhofer IIS (2000)
+ 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$
+ Initial author: A. Groeschel
+ contents/description: channel mapping functionality
+
+******************************************************************************/
+
+#ifndef _CHANNEL_MAP_H
+#define _CHANNEL_MAP_H
+
+
+#include "aacenc.h"
+#include "psy_const.h"
+#include "qc_data.h"
+
+typedef struct {
+ CHANNEL_MODE encMode;
+ INT nChannels;
+ INT nChannelsEff;
+ INT nElements;
+} CHANNEL_MODE_CONFIG_TAB;
+
+
+/* Element mode */
+typedef enum {
+ EL_MODE_INVALID = 0,
+ EL_MODE_MONO,
+ EL_MODE_STEREO
+} ELEMENT_MODE;
+
+
+AAC_ENCODER_ERROR FDKaacEnc_DetermineEncoderMode(CHANNEL_MODE* mode,
+ INT nChannels);
+
+AAC_ENCODER_ERROR FDKaacEnc_InitChannelMapping(CHANNEL_MODE mode,
+ CHANNEL_ORDER co,
+ CHANNEL_MAPPING* chMap);
+
+AAC_ENCODER_ERROR FDKaacEnc_InitElementBits(QC_STATE *hQC,
+ CHANNEL_MAPPING *cm,
+ INT bitrateTot,
+ INT averageBitsTot,
+ INT maxChannelBits);
+
+ELEMENT_MODE FDKaacEnc_GetMonoStereoMode(const CHANNEL_MODE mode);
+
+const CHANNEL_MODE_CONFIG_TAB* FDKaacEnc_GetChannelModeConfiguration(const CHANNEL_MODE mode);
+
+//void FDKaacEnc_CloseChannelMapping (CHANNEL_MAPPING** phchMap);
+
+#endif /* CHANNEL_MAP_H */
diff --git a/libAACenc/src/chaosmeasure.cpp b/libAACenc/src/chaosmeasure.cpp
new file mode 100644
index 0000000..086a0b0
--- /dev/null
+++ b/libAACenc/src/chaosmeasure.cpp
@@ -0,0 +1,99 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1997)
+ 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$
+ Initial author: M. Werner
+ contents/description: Chaos measure calculation
+
+******************************************************************************/
+
+#include "chaosmeasure.h"
+
+/*****************************************************************************
+ functionname: FDKaacEnc_FDKaacEnc_CalculateChaosMeasurePeakFast
+ description: Eberlein method of chaos measure calculation by high-pass
+ filtering amplitude spectrum
+ A special case of FDKaacEnc_CalculateChaosMeasureTonalGeneric --
+ highly optimized
+*****************************************************************************/
+static void
+FDKaacEnc_FDKaacEnc_CalculateChaosMeasurePeakFast( FIXP_DBL *RESTRICT paMDCTDataNM0,
+ INT numberOfLines,
+ FIXP_DBL *RESTRICT chaosMeasure )
+{
+ INT i, j;
+
+ /* calculate chaos measure by "peak filter" */
+ for (i=0; i<2; i++) {
+ /* make even and odd pass through data */
+ FIXP_DBL left,center; /* left, center tap of filter */
+
+ left = (FIXP_DBL)((LONG)paMDCTDataNM0[i]^((LONG)paMDCTDataNM0[i]>>(DFRACT_BITS-1)));
+ center = (FIXP_DBL)((LONG)paMDCTDataNM0[i+2]^((LONG)paMDCTDataNM0[i+2]>>(DFRACT_BITS-1)));
+
+ for (j = i+2; j < numberOfLines - 2; j+=2) {
+ FIXP_DBL right = (FIXP_DBL)((LONG)paMDCTDataNM0[j+2]^((LONG)paMDCTDataNM0[j+2]>>(DFRACT_BITS-1)));
+ FIXP_DBL tmp = (left>>1)+(right>>1);
+
+ if (tmp < center ) {
+ INT leadingBits = CntLeadingZeros(center)-1;
+ tmp = schur_div(tmp<<leadingBits, center<<leadingBits, 8);
+ chaosMeasure[j] = fMult(tmp,tmp);
+ }
+ else {
+ chaosMeasure[j] = (FIXP_DBL)MAXVAL_DBL;
+ }
+
+ left = center;
+ center = right;
+ }
+ }
+
+ /* provide chaos measure for first few lines */
+ chaosMeasure[0] = chaosMeasure[2];
+ chaosMeasure[1] = chaosMeasure[2];
+
+ /* provide chaos measure for last few lines */
+ for (i = (numberOfLines-3); i < numberOfLines; i++)
+ chaosMeasure[i] = FL2FXCONST_DBL(0.5);
+}
+
+
+/*****************************************************************************
+ functionname: FDKaacEnc_CalculateChaosMeasure
+ description: calculates a chaosmeasure for every line, different methods
+ are available. 0 means tonal, 1 means noiselike
+ returns:
+ input: MDCT data, number of lines
+ output: chaosMeasure
+*****************************************************************************/
+void
+FDKaacEnc_CalculateChaosMeasure( FIXP_DBL *paMDCTDataNM0,
+ INT numberOfLines,
+ FIXP_DBL *chaosMeasure )
+
+{
+ FDKaacEnc_FDKaacEnc_CalculateChaosMeasurePeakFast( paMDCTDataNM0,
+ numberOfLines,
+ chaosMeasure );
+}
+
diff --git a/libAACenc/src/chaosmeasure.h b/libAACenc/src/chaosmeasure.h
new file mode 100644
index 0000000..c53831f
--- /dev/null
+++ b/libAACenc/src/chaosmeasure.h
@@ -0,0 +1,41 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1997)
+ 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$
+ Initial author: M. Werner
+ contents/description: Chaos measure calculation
+
+******************************************************************************/
+
+#ifndef __CHAOSMEASURE_H
+#define __CHAOSMEASURE_H
+
+#include "common_fix.h"
+
+#include "psy_const.h"
+
+void
+FDKaacEnc_CalculateChaosMeasure( FIXP_DBL *paMDCTDataNM0,
+ INT numberOfLines,
+ FIXP_DBL *chaosMeasure );
+
+#endif
diff --git a/libAACenc/src/dyn_bits.cpp b/libAACenc/src/dyn_bits.cpp
new file mode 100644
index 0000000..8a94b6c
--- /dev/null
+++ b/libAACenc/src/dyn_bits.cpp
@@ -0,0 +1,743 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Noiseless coder module
+
+******************************************************************************/
+
+#include "dyn_bits.h"
+#include "bit_cnt.h"
+#include "psy_const.h"
+#include "aacenc_pns.h"
+#include "aacEnc_ram.h"
+#include "aacEnc_rom.h"
+
+typedef INT (*lookUpTable)[CODE_BOOK_ESC_NDX + 1];
+
+static INT FDKaacEnc_getSideInfoBits(
+ const SECTION_INFO* const huffsection,
+ const SHORT* const sideInfoTab,
+ const INT useHCR
+ )
+{
+ INT sideInfoBits;
+
+ if ( useHCR && ((huffsection->codeBook == 11) || (huffsection->codeBook >= 16)) ) {
+ sideInfoBits = 5;
+ }
+ else {
+ sideInfoBits = sideInfoTab[huffsection->sfbCnt];
+ }
+
+ return (sideInfoBits);
+}
+
+/* count bits using all possible tables */
+static void FDKaacEnc_buildBitLookUp(
+ const SHORT* const quantSpectrum,
+ const INT maxSfb,
+ const INT* const sfbOffset,
+ const UINT* const sfbMax,
+ INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
+ SECTION_INFO* const huffsection
+ )
+{
+ INT i, sfbWidth;
+
+ for (i = 0; i < maxSfb; i++)
+ {
+ huffsection[i].sfbCnt = 1;
+ huffsection[i].sfbStart = i;
+ huffsection[i].sectionBits = INVALID_BITCOUNT;
+ huffsection[i].codeBook = -1;
+ sfbWidth = sfbOffset[i + 1] - sfbOffset[i];
+ FDKaacEnc_bitCount(quantSpectrum + sfbOffset[i], sfbWidth, sfbMax[i], bitLookUp[i]);
+ }
+}
+
+/* essential helper functions */
+static INT FDKaacEnc_findBestBook(
+ const INT* const bc,
+ INT* const book,
+ const INT useVCB11
+ )
+{
+ INT minBits = INVALID_BITCOUNT, j;
+
+ int end = CODE_BOOK_ESC_NDX;
+
+
+ for (j = 0; j <= end; j++)
+ {
+ if (bc[j] < minBits)
+ {
+ minBits = bc[j];
+ *book = j;
+ }
+ }
+ return (minBits);
+}
+
+static INT FDKaacEnc_findMinMergeBits(
+ const INT* const bc1,
+ const INT* const bc2,
+ const INT useVCB11
+ )
+{
+ INT minBits = INVALID_BITCOUNT, j;
+
+ int end = CODE_BOOK_ESC_NDX;
+
+
+ for (j = 0; j <= end; j++)
+ {
+ if (bc1[j] + bc2[j] < minBits)
+ {
+ minBits = bc1[j] + bc2[j];
+ }
+ }
+ return (minBits);
+}
+
+static void FDKaacEnc_mergeBitLookUp(
+ INT* const bc1,
+ const INT* const bc2
+ )
+{
+ int j;
+
+ for (j = 0; j <= CODE_BOOK_ESC_NDX; j++)
+ {
+ bc1[j] = fixMin(bc1[j] + bc2[j], INVALID_BITCOUNT);
+ }
+}
+
+static INT FDKaacEnc_findMaxMerge(
+ const INT* const mergeGainLookUp,
+ const SECTION_INFO* const huffsection,
+ const INT maxSfb,
+ INT* const maxNdx
+ )
+{
+ INT i, maxMergeGain = 0;
+
+ for (i = 0; i + huffsection[i].sfbCnt < maxSfb; i += huffsection[i].sfbCnt)
+ {
+ if (mergeGainLookUp[i] > maxMergeGain)
+ {
+ maxMergeGain = mergeGainLookUp[i];
+ *maxNdx = i;
+ }
+ }
+ return (maxMergeGain);
+}
+
+static INT FDKaacEnc_CalcMergeGain(
+ const SECTION_INFO* const huffsection,
+ const INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
+ const SHORT* const sideInfoTab,
+ const INT ndx1,
+ const INT ndx2,
+ const INT useVCB11
+ )
+{
+ INT MergeGain, MergeBits, SplitBits;
+
+ MergeBits = sideInfoTab[huffsection[ndx1].sfbCnt + huffsection[ndx2].sfbCnt] + FDKaacEnc_findMinMergeBits(bitLookUp[ndx1], bitLookUp[ndx2], useVCB11);
+ SplitBits = huffsection[ndx1].sectionBits + huffsection[ndx2].sectionBits; /* Bit amount for splitted huffsections */
+ MergeGain = SplitBits - MergeBits;
+
+ if ( (huffsection[ndx1].codeBook==CODE_BOOK_PNS_NO)||(huffsection[ndx2].codeBook==CODE_BOOK_PNS_NO)
+ || (huffsection[ndx1].codeBook==CODE_BOOK_IS_OUT_OF_PHASE_NO)||(huffsection[ndx2].codeBook==CODE_BOOK_IS_OUT_OF_PHASE_NO)
+ || (huffsection[ndx1].codeBook==CODE_BOOK_IS_IN_PHASE_NO)||(huffsection[ndx2].codeBook==CODE_BOOK_IS_IN_PHASE_NO)
+ )
+ {
+ MergeGain = -1;
+ }
+
+ return (MergeGain);
+}
+
+
+/* sectioning Stage 0:find minimum codbooks */
+static void FDKaacEnc_gmStage0(
+ SECTION_INFO* const RESTRICT huffsection,
+ const INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
+ const INT maxSfb,
+ const INT* const noiseNrg,
+ const INT* const isBook
+ )
+{
+ INT i;
+
+ for (i = 0; i < maxSfb; i++)
+ {
+ /* Side-Info bits will be calculated in Stage 1! */
+ if (huffsection[i].sectionBits == INVALID_BITCOUNT)
+ {
+ /* intensity and pns codebooks are already allocated in bitcount.c */
+ if(noiseNrg[i] != NO_NOISE_PNS){
+ huffsection[i].codeBook=CODE_BOOK_PNS_NO;
+ huffsection[i].sectionBits = 0;
+ }
+ else if( isBook[i] ) {
+ huffsection[i].codeBook=isBook[i];
+ huffsection[i].sectionBits = 0;
+ }
+ else {
+ huffsection[i].sectionBits = FDKaacEnc_findBestBook(bitLookUp[i], &(huffsection[i].codeBook), 0); /* useVCB11 must be 0!!! */
+ }
+ }
+ }
+}
+
+/*
+ sectioning Stage 1:merge all connected regions with the same code book and
+ calculate side info
+ */
+static void FDKaacEnc_gmStage1(
+ SECTION_INFO* const RESTRICT huffsection,
+ INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
+ const INT maxSfb,
+ const SHORT* const sideInfoTab,
+ const INT useVCB11
+ )
+{
+ INT mergeStart = 0, mergeEnd;
+
+ do
+ {
+ for (mergeEnd = mergeStart + 1; mergeEnd < maxSfb; mergeEnd++)
+ {
+ if (huffsection[mergeStart].codeBook != huffsection[mergeEnd].codeBook)
+ break;
+
+
+ /* we can merge. update tables, side info bits will be updated outside of this loop */
+ huffsection[mergeStart].sfbCnt++;
+ huffsection[mergeStart].sectionBits += huffsection[mergeEnd].sectionBits;
+
+ /* update bit look up for all code books */
+ FDKaacEnc_mergeBitLookUp(bitLookUp[mergeStart], bitLookUp[mergeEnd]);
+ }
+
+ /* add side info info bits */
+ huffsection[mergeStart].sectionBits += FDKaacEnc_getSideInfoBits(&huffsection[mergeStart], sideInfoTab, useVCB11);
+ huffsection[mergeEnd - 1].sfbStart = huffsection[mergeStart].sfbStart; /* speed up prev search */
+
+ mergeStart = mergeEnd;
+
+ } while (mergeStart < maxSfb);
+}
+
+/*
+ sectioning Stage 2:greedy merge algorithm, merge connected sections with
+ maximum bit gain until no more gain is possible
+ */
+static void
+FDKaacEnc_gmStage2(
+ SECTION_INFO* const RESTRICT huffsection,
+ INT* const RESTRICT mergeGainLookUp,
+ INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
+ const INT maxSfb,
+ const SHORT* const sideInfoTab,
+ const INT useVCB11
+ )
+{
+ INT i;
+
+ for (i = 0; i + huffsection[i].sfbCnt < maxSfb; i += huffsection[i].sfbCnt)
+ {
+ mergeGainLookUp[i] = FDKaacEnc_CalcMergeGain(huffsection,
+ bitLookUp,
+ sideInfoTab,
+ i,
+ i + huffsection[i].sfbCnt,
+ useVCB11);
+ }
+
+ while (TRUE)
+ {
+ INT maxMergeGain, maxNdx = 0, maxNdxNext, maxNdxLast;
+
+ maxMergeGain = FDKaacEnc_findMaxMerge(mergeGainLookUp, huffsection, maxSfb, &maxNdx);
+
+ /* exit while loop if no more gain is possible */
+ if (maxMergeGain <= 0)
+ break;
+
+ maxNdxNext = maxNdx + huffsection[maxNdx].sfbCnt;
+
+ /* merge sections with maximum bit gain */
+ huffsection[maxNdx].sfbCnt += huffsection[maxNdxNext].sfbCnt;
+ huffsection[maxNdx].sectionBits += huffsection[maxNdxNext].sectionBits - maxMergeGain;
+
+ /* update bit look up table for merged huffsection */
+ FDKaacEnc_mergeBitLookUp(bitLookUp[maxNdx], bitLookUp[maxNdxNext]);
+
+ /* update mergeLookUpTable */
+ if (maxNdx != 0)
+ {
+ maxNdxLast = huffsection[maxNdx - 1].sfbStart;
+ mergeGainLookUp[maxNdxLast] = FDKaacEnc_CalcMergeGain(huffsection,
+ bitLookUp,
+ sideInfoTab,
+ maxNdxLast,
+ maxNdx,
+ useVCB11);
+
+ }
+ maxNdxNext = maxNdx + huffsection[maxNdx].sfbCnt;
+
+ huffsection[maxNdxNext - 1].sfbStart = huffsection[maxNdx].sfbStart;
+
+ if (maxNdxNext < maxSfb)
+ mergeGainLookUp[maxNdx] = FDKaacEnc_CalcMergeGain(huffsection,
+ bitLookUp,
+ sideInfoTab,
+ maxNdx,
+ maxNdxNext,
+ useVCB11);
+
+ }
+}
+
+/* count bits used by the noiseless coder */
+static void FDKaacEnc_noiselessCounter(
+ SECTION_DATA* const RESTRICT sectionData,
+ INT mergeGainLookUp[MAX_SFB_LONG],
+ INT bitLookUp[MAX_SFB_LONG][CODE_BOOK_ESC_NDX + 1],
+ const SHORT* const quantSpectrum,
+ const UINT* const maxValueInSfb,
+ const INT* const sfbOffset,
+ const INT blockType,
+ const INT* const noiseNrg,
+ const INT* const isBook,
+ const INT useVCB11
+ )
+{
+ INT grpNdx, i;
+ const SHORT *sideInfoTab = NULL;
+ SECTION_INFO *huffsection;
+
+ /* use appropriate side info table */
+ switch (blockType)
+ {
+ case LONG_WINDOW:
+ case START_WINDOW:
+ case STOP_WINDOW:
+ sideInfoTab = FDKaacEnc_sideInfoTabLong;
+ break;
+ case SHORT_WINDOW:
+ sideInfoTab = FDKaacEnc_sideInfoTabShort;
+ break;
+ }
+
+ sectionData->noOfSections = 0;
+ sectionData->huffmanBits = 0;
+ sectionData->sideInfoBits = 0;
+
+
+ if (sectionData->maxSfbPerGroup == 0)
+ return;
+
+ /* loop trough groups */
+ for (grpNdx = 0; grpNdx < sectionData->sfbCnt; grpNdx += sectionData->sfbPerGroup)
+ {
+ huffsection = sectionData->huffsection + sectionData->noOfSections;
+
+ /* count bits in this group */
+ FDKaacEnc_buildBitLookUp(quantSpectrum,
+ sectionData->maxSfbPerGroup,
+ sfbOffset + grpNdx,
+ maxValueInSfb + grpNdx,
+ bitLookUp,
+ huffsection);
+
+ /* 0.Stage :Find minimum Codebooks */
+ FDKaacEnc_gmStage0(huffsection, bitLookUp, sectionData->maxSfbPerGroup, noiseNrg+grpNdx, isBook+grpNdx);
+
+ /* 1.Stage :Merge all connected regions with the same code book */
+ FDKaacEnc_gmStage1(huffsection, bitLookUp, sectionData->maxSfbPerGroup, sideInfoTab, useVCB11);
+
+
+ /*
+ 2.Stage
+ greedy merge algorithm, merge connected huffsections with maximum bit
+ gain until no more gain is possible
+ */
+
+ FDKaacEnc_gmStage2(huffsection,
+ mergeGainLookUp,
+ bitLookUp,
+ sectionData->maxSfbPerGroup,
+ sideInfoTab,
+ useVCB11);
+
+
+
+ /*
+ compress output, calculate total huff and side bits
+ since we did not update the actual codebook in stage 2
+ to save time, we must set it here for later use in bitenc
+ */
+
+ for (i = 0; i < sectionData->maxSfbPerGroup; i += huffsection[i].sfbCnt)
+ {
+ if ((huffsection[i].codeBook==CODE_BOOK_PNS_NO) ||
+ (huffsection[i].codeBook==CODE_BOOK_IS_OUT_OF_PHASE_NO) ||
+ (huffsection[i].codeBook==CODE_BOOK_IS_IN_PHASE_NO))
+ {
+ huffsection[i].sectionBits=0;
+ } else {
+ /* the sections in the sectionData are now marked with the optimal code book */
+
+ FDKaacEnc_findBestBook(bitLookUp[i], &(huffsection[i].codeBook), useVCB11);
+
+ sectionData->huffmanBits += huffsection[i].sectionBits - FDKaacEnc_getSideInfoBits(&huffsection[i], sideInfoTab, useVCB11);
+ }
+
+ huffsection[i].sfbStart += grpNdx;
+
+ /* sum up side info bits (section data bits) */
+ sectionData->sideInfoBits += FDKaacEnc_getSideInfoBits(&huffsection[i], sideInfoTab, useVCB11);
+ sectionData->huffsection[sectionData->noOfSections++] = huffsection[i];
+ }
+ }
+}
+
+
+/*******************************************************************************
+
+ functionname: FDKaacEnc_scfCount
+ returns : ---
+ description : count bits used by scalefactors.
+
+ not in all cases if maxValueInSfb[] == 0 we set deltaScf
+ to zero. only if the difference of the last and future
+ scalefacGain is not greater then CODE_BOOK_SCF_LAV (60).
+
+ example:
+ ^
+ scalefacGain |
+ |
+ | last 75
+ | |
+ | |
+ | |
+ | | current 50
+ | | |
+ | | |
+ | | |
+ | | |
+ | | | future 5
+ | | | |
+ --- ... ---------------------------- ... --------->
+ sfb
+
+
+ if maxValueInSfb[] of current is zero because of a
+ notfallstrategie, we do not save bits and transmit a
+ deltaScf of 25. otherwise the deltaScf between the last
+ scalfacGain (75) and the future scalefacGain (5) is 70.
+
+********************************************************************************/
+static void FDKaacEnc_scfCount(
+ const INT* const scalefacGain,
+ const UINT* const maxValueInSfb,
+ SECTION_DATA* const RESTRICT sectionData,
+ const INT* const isScale
+ )
+{
+ INT i, j, k, m, n;
+
+ INT lastValScf = 0;
+ INT deltaScf = 0;
+ INT found = 0;
+ INT scfSkipCounter = 0;
+ INT lastValIs = 0;
+
+ sectionData->scalefacBits = 0;
+
+ if (scalefacGain == NULL)
+ return;
+
+ sectionData->firstScf = 0;
+
+ for (i=0; i<sectionData->noOfSections; i++)
+ {
+ if (sectionData->huffsection[i].codeBook != CODE_BOOK_ZERO_NO)
+ {
+ sectionData->firstScf = sectionData->huffsection[i].sfbStart;
+ lastValScf = scalefacGain[sectionData->firstScf];
+ break;
+ }
+ }
+
+ for (i=0; i<sectionData->noOfSections; i++)
+ {
+ if ((sectionData->huffsection[i].codeBook == CODE_BOOK_IS_OUT_OF_PHASE_NO) ||
+ (sectionData->huffsection[i].codeBook == CODE_BOOK_IS_IN_PHASE_NO))
+ {
+ for (j = sectionData->huffsection[i].sfbStart;
+ j < sectionData->huffsection[i].sfbStart + sectionData->huffsection[i].sfbCnt;
+ j++)
+ {
+ INT deltaIs = isScale[j]-lastValIs;
+ lastValIs = isScale[j];
+ sectionData->scalefacBits+=FDKaacEnc_bitCountScalefactorDelta(deltaIs);
+ }
+ } /* Intensity */
+ else if ((sectionData->huffsection[i].codeBook != CODE_BOOK_ZERO_NO) &&
+ (sectionData->huffsection[i].codeBook != CODE_BOOK_PNS_NO))
+ {
+ INT tmp = sectionData->huffsection[i].sfbStart + sectionData->huffsection[i].sfbCnt;
+ for (j = sectionData->huffsection[i].sfbStart; j<tmp; j++)
+ {
+ /* check if we can repeat the last value to save bits */
+ if (maxValueInSfb[j] == 0)
+ {
+ found = 0;
+ /* are scalefactors skipped? */
+ if (scfSkipCounter == 0)
+ {
+ /* end of section */
+ if (j == (tmp - 1) )
+ found = 0; /* search in other sections for maxValueInSfb != 0 */
+ else
+ {
+ /* search in this section for the next maxValueInSfb[] != 0 */
+ for (k = (j+1); k < tmp; k++)
+ {
+ if (maxValueInSfb[k] != 0)
+ {
+ found = 1;
+ if ( (fixp_abs(scalefacGain[k] - lastValScf)) <= CODE_BOOK_SCF_LAV)
+ deltaScf = 0; /* save bits */
+ else
+ {
+ /* do not save bits */
+ deltaScf = lastValScf - scalefacGain[j];
+ lastValScf = scalefacGain[j];
+ scfSkipCounter = 0;
+ }
+ break;
+ }
+ /* count scalefactor skip */
+ scfSkipCounter++;
+ }
+ }
+
+ /* search for the next maxValueInSfb[] != 0 in all other sections */
+ for (m=(i+1); (m < sectionData->noOfSections) && (found == 0); m++)
+ {
+ if ((sectionData->huffsection[m].codeBook != CODE_BOOK_ZERO_NO) && (sectionData->huffsection[m].codeBook != CODE_BOOK_PNS_NO))
+ {
+ INT end = sectionData->huffsection[m].sfbStart + sectionData->huffsection[m].sfbCnt;
+ for (n = sectionData->huffsection[m].sfbStart; n<end; n++)
+ {
+ if (maxValueInSfb[n] != 0)
+ {
+ found = 1;
+ if (fixp_abs(scalefacGain[n] - lastValScf) <= CODE_BOOK_SCF_LAV)
+ deltaScf = 0; /* save bits */
+ else
+ {
+ /* do not save bits */
+ deltaScf = lastValScf - scalefacGain[j];
+ lastValScf = scalefacGain[j];
+ scfSkipCounter = 0;
+ }
+ break;
+ }
+ /* count scalefactor skip */
+ scfSkipCounter++;
+ }
+ }
+ }
+ /* no maxValueInSfb[] != 0 found */
+ if (found == 0)
+ {
+ deltaScf = 0;
+ scfSkipCounter = 0;
+ }
+ }
+ else {
+ /* consider skipped scalefactors */
+ deltaScf = 0;
+ scfSkipCounter--;
+ }
+ }
+ else {
+ deltaScf = lastValScf - scalefacGain[j];
+ lastValScf = scalefacGain[j];
+ }
+ sectionData->scalefacBits += FDKaacEnc_bitCountScalefactorDelta(deltaScf);
+ }
+ }
+ } /* for (i=0; i<sectionData->noOfSections; i++) */
+}
+
+#ifdef PNS_PRECOUNT_ENABLE
+/*
+ preCount bits used pns
+*/
+/* estimate bits used by pns for correction of static bits */
+/* no codebook switch estimation, see AAC LD FASTENC */
+INT noisePreCount(const INT *noiseNrg, INT maxSfb)
+{
+ INT noisePCMFlag = TRUE;
+ INT lastValPns = 0, deltaPns;
+ int i, bits=0;
+
+ for (i = 0; i < maxSfb; i++) {
+ if (noiseNrg[i] != NO_NOISE_PNS) {
+
+ if (noisePCMFlag) {
+ bits+=PNS_PCM_BITS;
+ lastValPns = noiseNrg[i];
+ noisePCMFlag = FALSE;
+ }else {
+ deltaPns = noiseNrg[i]-lastValPns;
+ lastValPns = noiseNrg[i];
+ bits+=FDKaacEnc_bitCountScalefactorDelta(deltaPns);
+ }
+ }
+ }
+ return ( bits );
+}
+#endif /* PNS_PRECOUNT_ENABLE */
+
+/* count bits used by pns */
+static void FDKaacEnc_noiseCount(
+ SECTION_DATA* const RESTRICT sectionData,
+ const INT* const noiseNrg
+ )
+{
+ INT noisePCMFlag = TRUE;
+ INT lastValPns = 0, deltaPns;
+ int i, j;
+
+ sectionData->noiseNrgBits = 0;
+
+ for (i = 0; i < sectionData->noOfSections; i++) {
+ if (sectionData->huffsection[i].codeBook == CODE_BOOK_PNS_NO) {
+ int sfbStart = sectionData->huffsection[i].sfbStart;
+ int sfbEnd = sfbStart + sectionData->huffsection[i].sfbCnt;
+ for (j=sfbStart; j<sfbEnd; j++) {
+
+ if (noisePCMFlag) {
+ sectionData->noiseNrgBits+=PNS_PCM_BITS;
+ lastValPns = noiseNrg[j];
+ noisePCMFlag = FALSE;
+ } else {
+ deltaPns = noiseNrg[j]-lastValPns;
+ lastValPns = noiseNrg[j];
+ sectionData->noiseNrgBits+=FDKaacEnc_bitCountScalefactorDelta(deltaPns);
+ }
+ }
+ }
+ }
+}
+
+INT FDKaacEnc_dynBitCount(
+ BITCNTR_STATE* const hBC,
+ const SHORT* const quantSpectrum,
+ const UINT* const maxValueInSfb,
+ const INT* const scalefac,
+ const INT blockType,
+ const INT sfbCnt,
+ const INT maxSfbPerGroup,
+ const INT sfbPerGroup,
+ const INT* const sfbOffset,
+ SECTION_DATA* const RESTRICT sectionData,
+ const INT* const noiseNrg,
+ const INT* const isBook,
+ const INT* const isScale,
+ const UINT syntaxFlags
+ )
+{
+ sectionData->blockType = blockType;
+ sectionData->sfbCnt = sfbCnt;
+ sectionData->sfbPerGroup = sfbPerGroup;
+ sectionData->noOfGroups = sfbCnt / sfbPerGroup;
+ sectionData->maxSfbPerGroup = maxSfbPerGroup;
+
+ FDKaacEnc_noiselessCounter(
+ sectionData,
+ hBC->mergeGainLookUp,
+ (lookUpTable)hBC->bitLookUp,
+ quantSpectrum,
+ maxValueInSfb,
+ sfbOffset,
+ blockType,
+ noiseNrg,
+ isBook,
+ (syntaxFlags & AC_ER_VCB11)?1:0);
+
+ FDKaacEnc_scfCount(
+ scalefac,
+ maxValueInSfb,
+ sectionData,
+ isScale);
+
+ FDKaacEnc_noiseCount(sectionData,
+ noiseNrg);
+
+ return (sectionData->huffmanBits +
+ sectionData->sideInfoBits +
+ sectionData->scalefacBits +
+ sectionData->noiseNrgBits);
+}
+
+INT FDKaacEnc_BCNew(BITCNTR_STATE **phBC
+ ,UCHAR* dynamic_RAM
+ )
+{
+ BITCNTR_STATE *hBC = GetRam_aacEnc_BitCntrState();
+
+ if (hBC)
+ {
+ *phBC = hBC;
+ hBC->bitLookUp = GetRam_aacEnc_BitLookUp(0,dynamic_RAM);
+ hBC->mergeGainLookUp = GetRam_aacEnc_MergeGainLookUp(0,dynamic_RAM);
+ if (hBC->bitLookUp == 0 ||
+ hBC->mergeGainLookUp == 0)
+ {
+ return 1;
+ }
+ }
+ return (hBC == 0) ? 1 : 0;
+}
+
+void FDKaacEnc_BCClose(BITCNTR_STATE **phBC)
+{
+ if (*phBC!=NULL) {
+
+ FreeRam_aacEnc_BitCntrState(phBC);
+ }
+}
+
+
+
diff --git a/libAACenc/src/dyn_bits.h b/libAACenc/src/dyn_bits.h
new file mode 100644
index 0000000..b889ebe
--- /dev/null
+++ b/libAACenc/src/dyn_bits.h
@@ -0,0 +1,104 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Noiseless coder module
+
+******************************************************************************/
+#ifndef __DYN_BITS_H
+#define __DYN_BITS_H
+
+#include "common_fix.h"
+
+#include "psy_const.h"
+#include "aacenc_tns.h"
+
+#define MAX_SECTIONS MAX_GROUPED_SFB
+#define SECT_ESC_VAL_LONG 31
+#define SECT_ESC_VAL_SHORT 7
+#define CODE_BOOK_BITS 4
+#define SECT_BITS_LONG 5
+#define SECT_BITS_SHORT 3
+#define PNS_PCM_BITS 9
+
+typedef struct
+{
+ INT codeBook;
+ INT sfbStart;
+ INT sfbCnt;
+ INT sectionBits; /* huff + si ! */
+} SECTION_INFO;
+
+
+typedef struct
+{
+ INT blockType;
+ INT noOfGroups;
+ INT sfbCnt;
+ INT maxSfbPerGroup;
+ INT sfbPerGroup;
+ INT noOfSections;
+ SECTION_INFO huffsection[MAX_SECTIONS];
+ INT sideInfoBits; /* sectioning bits */
+ INT huffmanBits; /* huffman coded bits */
+ INT scalefacBits; /* scalefac coded bits */
+ INT noiseNrgBits; /* noiseEnergy coded bits */
+ INT firstScf; /* first scf to be coded */
+} SECTION_DATA;
+
+
+struct BITCNTR_STATE
+{
+ INT *bitLookUp;
+ INT *mergeGainLookUp;
+};
+
+
+INT FDKaacEnc_BCNew(BITCNTR_STATE **phBC
+ ,UCHAR* dynamic_RAM
+ );
+
+void FDKaacEnc_BCClose(BITCNTR_STATE **phBC);
+
+#if defined(PNS_PRECOUNT_ENABLE)
+INT noisePreCount(const INT *noiseNrg, INT maxSfb);
+#endif
+
+INT FDKaacEnc_dynBitCount(
+ BITCNTR_STATE* const hBC,
+ const SHORT* const quantSpectrum,
+ const UINT* const maxValueInSfb,
+ const INT* const scalefac,
+ const INT blockType,
+ const INT sfbCnt,
+ const INT maxSfbPerGroup,
+ const INT sfbPerGroup,
+ const INT* const sfbOffset,
+ SECTION_DATA* const RESTRICT sectionData,
+ const INT* const noiseNrg,
+ const INT* const isBook,
+ const INT* const isScale,
+ const UINT syntaxFlags
+ );
+
+#endif
diff --git a/libAACenc/src/grp_data.cpp b/libAACenc/src/grp_data.cpp
new file mode 100644
index 0000000..8cd017b
--- /dev/null
+++ b/libAACenc/src/grp_data.cpp
@@ -0,0 +1,206 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Short block grouping
+
+******************************************************************************/
+#include "psy_const.h"
+#include "interface.h"
+
+/*
+* this routine does not work in-place
+*/
+
+void
+FDKaacEnc_groupShortData(FIXP_DBL *mdctSpectrum, /* in-out */
+ SFB_THRESHOLD *sfbThreshold, /* in-out */
+ SFB_ENERGY *sfbEnergy, /* in-out */
+ SFB_ENERGY *sfbEnergyMS, /* in-out */
+ SFB_ENERGY *sfbSpreadEnergy,
+ const INT sfbCnt,
+ const INT sfbActive,
+ const INT *sfbOffset,
+ const FIXP_DBL *sfbMinSnrLdData,
+ INT *groupedSfbOffset, /* out */
+ INT *maxSfbPerGroup, /* out */
+ FIXP_DBL *groupedSfbMinSnrLdData,
+ const INT noOfGroups,
+ const INT *groupLen,
+ const INT granuleLength)
+{
+ INT i,j;
+ INT line; /* counts through lines */
+ INT sfb; /* counts through scalefactor bands */
+ INT grp; /* counts through groups */
+ INT wnd; /* counts through windows in a group */
+ INT offset; /* needed in sfbOffset grouping */
+ INT highestSfb;
+
+ INT granuleLength_short = granuleLength/TRANS_FAC;
+
+ /* for short blocks: regroup spectrum and */
+ /* group energies and thresholds according to grouping */
+ C_ALLOC_SCRATCH_START(tmpSpectrum, FIXP_DBL, (1024));
+
+ /* calculate maxSfbPerGroup */
+ highestSfb = 0;
+ for (wnd = 0; wnd < TRANS_FAC; wnd++)
+ {
+ for (sfb = sfbActive-1; sfb >= highestSfb; sfb--)
+ {
+ for (line = sfbOffset[sfb+1]-1; line >= sfbOffset[sfb]; line--)
+ {
+ if ( mdctSpectrum[wnd*granuleLength_short+line] != FL2FXCONST_SPC(0.0) ) break; /* this band is not completely zero */
+ }
+ if (line >= sfbOffset[sfb]) break; /* this band was not completely zero */
+ }
+ highestSfb = fixMax(highestSfb, sfb);
+ }
+ highestSfb = highestSfb > 0 ? highestSfb : 0;
+ *maxSfbPerGroup = highestSfb+1;
+
+ /* calculate groupedSfbOffset */
+ i = 0;
+ offset = 0;
+ for (grp = 0; grp < noOfGroups; grp++)
+ {
+ for (sfb = 0; sfb < sfbActive+1; sfb++)
+ {
+ groupedSfbOffset[i++] = offset + sfbOffset[sfb] * groupLen[grp];
+ }
+ i += sfbCnt-sfb;
+ offset += groupLen[grp] * granuleLength_short;
+ }
+ groupedSfbOffset[i++] = granuleLength;
+
+ /* calculate groupedSfbMinSnr */
+ i = 0;
+ for (grp = 0; grp < noOfGroups; grp++)
+ {
+ for (sfb = 0; sfb < sfbActive; sfb++)
+ {
+ groupedSfbMinSnrLdData[i++] = sfbMinSnrLdData[sfb];
+ }
+ i += sfbCnt-sfb;
+ }
+
+ /* sum up sfbThresholds */
+ wnd = 0;
+ i = 0;
+ for (grp = 0; grp < noOfGroups; grp++)
+ {
+ for (sfb = 0; sfb < sfbActive; sfb++)
+ {
+ FIXP_DBL thresh = sfbThreshold->Short[wnd][sfb];
+ for (j=1; j<groupLen[grp]; j++)
+ {
+ thresh += sfbThreshold->Short[wnd+j][sfb];
+ }
+ sfbThreshold->Long[i++] = thresh;
+ }
+ i += sfbCnt-sfb;
+ wnd += groupLen[grp];
+ }
+
+ /* sum up sfbEnergies left/right */
+ wnd = 0;
+ i = 0;
+ for (grp = 0; grp < noOfGroups; grp++)
+ {
+ for (sfb = 0; sfb < sfbActive; sfb++)
+ {
+ FIXP_DBL energy = sfbEnergy->Short[wnd][sfb];
+ for (j=1; j<groupLen[grp]; j++)
+ {
+ energy += sfbEnergy->Short[wnd+j][sfb];
+ }
+ sfbEnergy->Long[i++] = energy;
+ }
+ i += sfbCnt-sfb;
+ wnd += groupLen[grp];
+ }
+
+ /* sum up sfbEnergies mid/side */
+ wnd = 0;
+ i = 0;
+ for (grp = 0; grp < noOfGroups; grp++)
+ {
+ for (sfb = 0; sfb < sfbActive; sfb++)
+ {
+ FIXP_DBL energy = sfbEnergyMS->Short[wnd][sfb];
+ for (j=1; j<groupLen[grp]; j++)
+ {
+ energy += sfbEnergyMS->Short[wnd+j][sfb];
+ }
+ sfbEnergyMS->Long[i++] = energy;
+ }
+ i += sfbCnt-sfb;
+ wnd += groupLen[grp];
+ }
+
+ /* sum up sfbSpreadEnergies */
+ wnd = 0;
+ i = 0;
+ for (grp = 0; grp < noOfGroups; grp++)
+ {
+ for (sfb = 0; sfb < sfbActive; sfb++)
+ {
+ FIXP_DBL energy = sfbSpreadEnergy->Short[wnd][sfb];
+ for (j=1; j<groupLen[grp]; j++)
+ {
+ energy += sfbSpreadEnergy->Short[wnd+j][sfb];
+ }
+ sfbSpreadEnergy->Long[i++] = energy;
+ }
+ i += sfbCnt-sfb;
+ wnd += groupLen[grp];
+ }
+
+ /* re-group spectrum */
+ wnd = 0;
+ i = 0;
+ for (grp = 0; grp < noOfGroups; grp++)
+ {
+ for (sfb = 0; sfb < sfbActive; sfb++)
+ {
+ int width = sfbOffset[sfb+1]-sfbOffset[sfb];
+ FIXP_DBL *pMdctSpectrum = &mdctSpectrum[sfbOffset[sfb]] + wnd*granuleLength_short;
+ for (j = 0; j < groupLen[grp]; j++)
+ {
+ FIXP_DBL *pTmp = pMdctSpectrum;
+ for (line = width; line > 0; line--)
+ {
+ tmpSpectrum[i++] = *pTmp++;
+ }
+ pMdctSpectrum += granuleLength_short;
+ }
+ }
+ i += (groupLen[grp]*(sfbOffset[sfbCnt]-sfbOffset[sfb]));
+ wnd += groupLen[grp];
+ }
+
+ FDKmemcpy(mdctSpectrum, tmpSpectrum, granuleLength*sizeof(FIXP_DBL));
+
+ C_ALLOC_SCRATCH_END(tmpSpectrum, FIXP_DBL, (1024))
+}
diff --git a/libAACenc/src/grp_data.h b/libAACenc/src/grp_data.h
new file mode 100644
index 0000000..b28cf8c
--- /dev/null
+++ b/libAACenc/src/grp_data.h
@@ -0,0 +1,53 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Short block grouping
+
+******************************************************************************/
+#ifndef __GRP_DATA_H__
+#define __GRP_DATA_H__
+
+#include "common_fix.h"
+
+#include "psy_data.h"
+
+
+void
+FDKaacEnc_groupShortData(FIXP_DBL *mdctSpectrum, /* in-out */
+ SFB_THRESHOLD *sfbThreshold, /* in-out */
+ SFB_ENERGY *sfbEnergy, /* in-out */
+ SFB_ENERGY *sfbEnergyMS, /* in-out */
+ SFB_ENERGY *sfbSpreadEnergy,
+ const INT sfbCnt,
+ const INT sfbActive,
+ const INT *sfbOffset,
+ const FIXP_DBL *sfbMinSnrLdData,
+ INT *groupedSfbOffset, /* out */
+ INT *maxSfbPerGroup,
+ FIXP_DBL *groupedSfbMinSnrLdData,
+ const INT noOfGroups,
+ const INT *groupLen,
+ const INT granuleLength);
+
+#endif /* _INTERFACE_H */
diff --git a/libAACenc/src/intensity.cpp b/libAACenc/src/intensity.cpp
new file mode 100644
index 0000000..b4d8637
--- /dev/null
+++ b/libAACenc/src/intensity.cpp
@@ -0,0 +1,691 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (2010)
+ 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$
+
+ Initial author: A. Horndasch (code originally from lwr) / Josef Hoepfl (FDK)
+ contents/description: intensity stereo processing
+
+******************************************************************************/
+
+#include "intensity.h"
+#include "interface.h"
+#include "psy_configuration.h"
+#include "psy_const.h"
+#include "qc_main.h"
+#include "bit_cnt.h"
+
+/* only set an IS seed it left/right channel correlation is above IS_CORR_THRESH */
+#define IS_CORR_THRESH FL2FXCONST_DBL(0.95f)
+
+/* when expanding the IS region to more SFBs only accept an error that is
+ * not more than IS_TOTAL_ERROR_THRESH overall and
+ * not more than IS_LOCAL_ERROR_THRESH for the current SFB */
+#define IS_TOTAL_ERROR_THRESH FL2FXCONST_DBL(0.04f)
+#define IS_LOCAL_ERROR_THRESH FL2FXCONST_DBL(0.01f)
+
+/* the maximum allowed change of the intensity direction (unit: IS scale) - scaled with factor 0.25 - */
+#define IS_DIRECTION_DEVIATION_THRESH_SF 2
+#define IS_DIRECTION_DEVIATION_THRESH FL2FXCONST_DBL(2.0f/(1<<IS_DIRECTION_DEVIATION_THRESH_SF))
+
+/* IS regions need to have a minimal percentage of the overall loudness, e.g. 0.06 == 6% */
+#define IS_REGION_MIN_LOUDNESS FL2FXCONST_DBL(0.1f)
+
+/* only perform IS if IS_MIN_SFBS neighboring SFBs can be processed */
+#define IS_MIN_SFBS 6
+
+/* only do IS if
+ * if IS_LEFT_RIGHT_RATIO_THRESH < sfbEnergyLeft[sfb]/sfbEnergyRight[sfb] < 1 / IS_LEFT_RIGHT_RATIO_THRESH
+ * -> no IS if the panning angle is not far from the middle, MS will do */
+/* this is equivalent to a scale of +/-1.02914634566 */
+#define IS_LEFT_RIGHT_RATIO_THRESH FL2FXCONST_DBL(0.7f)
+
+/* scalefactor of realScale */
+#define REAL_SCALE_SF 1
+
+/* scalefactor overallLoudness */
+#define OVERALL_LOUDNESS_SF 6
+
+/* scalefactor for sum over max samples per goup */
+#define MAX_SFB_PER_GROUP_SF 6
+
+/* scalefactor for sum of mdct spectrum */
+#define MDCT_SPEC_SF 6
+
+
+typedef struct
+{
+
+ FIXP_DBL corr_thresh; /*!< Only set an IS seed it left/right channel correlation is above corr_thresh */
+
+ FIXP_DBL total_error_thresh; /*!< When expanding the IS region to more SFBs only accept an error that is
+ not more than 'total_error_thresh' overall. */
+
+ FIXP_DBL local_error_thresh; /*!< When expanding the IS region to more SFBs only accept an error that is
+ not more than 'local_error_thresh' for the current SFB. */
+
+ FIXP_DBL direction_deviation_thresh; /*!< The maximum allowed change of the intensity direction (unit: IS scale) */
+
+ FIXP_DBL is_region_min_loudness; /*!< IS regions need to have a minimal percentage of the overall loudness, e.g. 0.06 == 6% */
+
+ INT min_is_sfbs; /*!< Only perform IS if 'min_is_sfbs' neighboring SFBs can be processed */
+
+ FIXP_DBL left_right_ratio_threshold; /*!< No IS if the panning angle is not far from the middle, MS will do */
+
+} INTENSITY_PARAMETERS;
+
+
+/*****************************************************************************
+
+ functionname: calcSfbMaxScale
+
+ description: Calc max value in scalefactor band
+
+ input: *mdctSpectrum
+ l1
+ l2
+
+ output: none
+
+ returns: scalefactor
+
+*****************************************************************************/
+static INT
+calcSfbMaxScale(const FIXP_DBL *mdctSpectrum,
+ const INT l1,
+ const INT l2)
+{
+ INT i;
+ INT sfbMaxScale;
+ FIXP_DBL maxSpc;
+
+ maxSpc = FL2FXCONST_DBL(0.0);
+ for (i=l1; i<l2; i++) {
+ FIXP_DBL tmp = fixp_abs((FIXP_DBL)mdctSpectrum[i]);
+ maxSpc = fixMax(maxSpc, tmp);
+ }
+ sfbMaxScale = (maxSpc==FL2FXCONST_DBL(0.0)) ? (DFRACT_BITS-2) : CntLeadingZeros(maxSpc)-1;
+
+ return sfbMaxScale;
+ }
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_initIsParams
+
+ description: Initialization of intensity parameters
+
+ input: isParams
+
+ output: isParams
+
+ returns: none
+
+*****************************************************************************/
+static void
+FDKaacEnc_initIsParams(INTENSITY_PARAMETERS *isParams)
+{
+ isParams->corr_thresh = IS_CORR_THRESH;
+ isParams->total_error_thresh = IS_TOTAL_ERROR_THRESH;
+ isParams->local_error_thresh = IS_LOCAL_ERROR_THRESH;
+ isParams->direction_deviation_thresh = IS_DIRECTION_DEVIATION_THRESH;
+ isParams->is_region_min_loudness = IS_REGION_MIN_LOUDNESS;
+ isParams->min_is_sfbs = IS_MIN_SFBS;
+ isParams->left_right_ratio_threshold = IS_LEFT_RIGHT_RATIO_THRESH;
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_prepareIntensityDecision
+
+ description: Prepares intensity decision
+
+ input: sfbEnergyLeft
+ sfbEnergyRight
+ sfbEnergyLdDataLeft
+ sfbEnergyLdDataRight
+ mdctSpectrumLeft
+ sfbEnergyLdDataRight
+ isParams
+
+ output: hrrErr scale: none
+ isMask scale: none
+ realScale scale: LD_DATA_SHIFT + REAL_SCALE_SF
+ normSfbLoudness scale: none
+
+ returns: none
+
+*****************************************************************************/
+static void
+FDKaacEnc_prepareIntensityDecision(const FIXP_DBL *sfbEnergyLeft,
+ const FIXP_DBL *sfbEnergyRight,
+ const FIXP_DBL *sfbEnergyLdDataLeft,
+ const FIXP_DBL *sfbEnergyLdDataRight,
+ const FIXP_DBL *mdctSpectrumLeft,
+ const FIXP_DBL *mdctSpectrumRight,
+ const INTENSITY_PARAMETERS *isParams,
+ FIXP_DBL *hrrErr,
+ INT *isMask,
+ FIXP_DBL *realScale,
+ FIXP_DBL *normSfbLoudness,
+ const INT sfbCnt,
+ const INT sfbPerGroup,
+ const INT maxSfbPerGroup,
+ const INT *sfbOffset)
+{
+ INT j,sfb,sfboffs;
+ INT grpCounter;
+
+ /* temporary variables to compute loudness */
+ FIXP_DBL overallLoudness[MAX_NO_OF_GROUPS];
+
+ /* temporary variables to compute correlation */
+ FIXP_DBL channelCorr[MAX_GROUPED_SFB];
+ FIXP_DBL ml, mr;
+ FIXP_DBL prod_lr;
+ FIXP_DBL square_l, square_r;
+ FIXP_DBL tmp_l, tmp_r;
+ FIXP_DBL inv_n;
+
+ FDKmemclear(channelCorr, MAX_GROUPED_SFB*sizeof(FIXP_DBL));
+ FDKmemclear(normSfbLoudness, MAX_GROUPED_SFB*sizeof(FIXP_DBL));
+ FDKmemclear(overallLoudness, MAX_NO_OF_GROUPS*sizeof(FIXP_DBL));
+ FDKmemclear(realScale, MAX_GROUPED_SFB*sizeof(FIXP_DBL));
+
+ for (grpCounter = 0, sfboffs = 0; sfboffs < sfbCnt; sfboffs += sfbPerGroup, grpCounter++) {
+ overallLoudness[grpCounter] = FL2FXCONST_DBL(0.0f);
+ for (sfb = 0; sfb < maxSfbPerGroup; sfb++) {
+ INT sL,sR,s;
+ FIXP_DBL isValue = sfbEnergyLdDataLeft[sfb+sfboffs]-sfbEnergyLdDataRight[sfb+sfboffs];
+
+ /* delimitate intensity scale value to representable range */
+ realScale[sfb + sfboffs] = fixMin(FL2FXCONST_DBL(60.f/(1<<(REAL_SCALE_SF+LD_DATA_SHIFT))), fixMax(FL2FXCONST_DBL(-60.f/(1<<(REAL_SCALE_SF+LD_DATA_SHIFT))), isValue));
+
+ sL = fixMax(0,(CntLeadingZeros(sfbEnergyLeft[sfb + sfboffs])-1));
+ sR = fixMax(0,(CntLeadingZeros(sfbEnergyRight[sfb + sfboffs])-1));
+ s = (fixMin(sL,sR)>>2)<<2;
+ normSfbLoudness[sfb + sfboffs] = sqrtFixp(sqrtFixp(((sfbEnergyLeft[sfb + sfboffs]<<s) >> 1) + ((sfbEnergyRight[sfb + sfboffs]<<s) >> 1))) >> (s>>2);
+
+ overallLoudness[grpCounter] += normSfbLoudness[sfb + sfboffs] >> OVERALL_LOUDNESS_SF;
+ /* don't do intensity if
+ * - panning angle is too close to the middle or
+ * - one channel is non-existent or
+ * - if it is dual mono */
+ if( (sfbEnergyLeft[sfb + sfboffs] >= fMult(isParams->left_right_ratio_threshold,sfbEnergyRight[sfb + sfboffs]))
+ && (fMult(isParams->left_right_ratio_threshold,sfbEnergyLeft[sfb + sfboffs]) <= sfbEnergyRight[sfb + sfboffs]) ) {
+
+ /* this will prevent post processing from considering this SFB for merging */
+ hrrErr[sfb + sfboffs] = FL2FXCONST_DBL(1.0/8.0);
+ }
+ }
+ }
+
+ for (grpCounter = 0, sfboffs = 0; sfboffs < sfbCnt; sfboffs += sfbPerGroup, grpCounter++) {
+ INT invOverallLoudnessSF;
+ FIXP_DBL invOverallLoudness;
+
+ if (overallLoudness[grpCounter] == FL2FXCONST_DBL(0.0)) {
+ invOverallLoudness = FL2FXCONST_DBL(0.0);
+ invOverallLoudnessSF = 0;
+ }
+ else {
+ invOverallLoudness = fDivNorm((FIXP_DBL)MAXVAL_DBL, overallLoudness[grpCounter],&invOverallLoudnessSF);
+ invOverallLoudnessSF = invOverallLoudnessSF - OVERALL_LOUDNESS_SF + 1; /* +1: compensate fMultDiv2() in subsequent loop */
+ }
+ invOverallLoudnessSF = fixMin(fixMax(invOverallLoudnessSF,-(DFRACT_BITS-1)),DFRACT_BITS-1);
+
+ for (sfb = 0; sfb < maxSfbPerGroup; sfb++) {
+ FIXP_DBL tmp;
+
+ tmp = fMultDiv2((normSfbLoudness[sfb + sfboffs]>>OVERALL_LOUDNESS_SF)<<OVERALL_LOUDNESS_SF,invOverallLoudness);
+
+ normSfbLoudness[sfb + sfboffs] = scaleValue(tmp, invOverallLoudnessSF);
+
+ channelCorr[sfb + sfboffs] = FL2FXCONST_DBL(0.0f);
+
+ FDK_ASSERT(50 >= 49);
+ /* max width of scalefactorband is 96; width's are always even */
+ /* inv_n is scaled with factor 2 to compensate fMultDiv2() in subsequent loops */
+ inv_n = GetInvInt((sfbOffset[sfb + sfboffs + 1] - sfbOffset[sfb + sfboffs])>>1);
+
+ if (inv_n > FL2FXCONST_DBL(0.0f)) {
+ INT s,sL,sR;
+
+ /* correlation := Pearson's product-moment coefficient */
+ /* compute correlation between channels and check if it is over threshold */
+ ml = FL2FXCONST_DBL(0.0f);
+ mr = FL2FXCONST_DBL(0.0f);
+ prod_lr = FL2FXCONST_DBL(0.0f);
+ square_l = FL2FXCONST_DBL(0.0f);
+ square_r = FL2FXCONST_DBL(0.0f);
+
+ sL = calcSfbMaxScale(mdctSpectrumLeft,sfbOffset[sfb+sfboffs],sfbOffset[sfb+sfboffs+1]);
+ sR = calcSfbMaxScale(mdctSpectrumRight,sfbOffset[sfb+sfboffs],sfbOffset[sfb+sfboffs+1]);
+ s = fixMin(sL,sR);
+
+ for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; j++) {
+ ml += fMultDiv2((mdctSpectrumLeft[j] << s),inv_n); // scaled with mdctScale - s + inv_n
+ mr += fMultDiv2((mdctSpectrumRight[j] << s),inv_n); // scaled with mdctScale - s + inv_n
+ }
+ ml = fMultDiv2(ml,inv_n); // scaled with mdctScale - s + inv_n
+ mr = fMultDiv2(mr,inv_n); // scaled with mdctScale - s + inv_n
+
+ for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; j++) {
+ tmp_l = fMultDiv2((mdctSpectrumLeft[j] << s),inv_n) - ml; // scaled with mdctScale - s + inv_n
+ tmp_r = fMultDiv2((mdctSpectrumRight[j] << s),inv_n) - mr; // scaled with mdctScale - s + inv_n
+
+ prod_lr += fMultDiv2(tmp_l,tmp_r); // scaled with 2*(mdctScale - s + inv_n) + 1
+ square_l += fPow2Div2(tmp_l); // scaled with 2*(mdctScale - s + inv_n) + 1
+ square_r += fPow2Div2(tmp_r); // scaled with 2*(mdctScale - s + inv_n) + 1
+ }
+ prod_lr = prod_lr << 1; // scaled with 2*(mdctScale - s + inv_n)
+ square_l = square_l << 1; // scaled with 2*(mdctScale - s + inv_n)
+ square_r = square_r << 1; // scaled with 2*(mdctScale - s + inv_n)
+
+ if (square_l > FL2FXCONST_DBL(0.0f) && square_r > FL2FXCONST_DBL(0.0f)) {
+ INT channelCorrSF = 0;
+
+ /* local scaling of square_l and square_r is compensated after sqrt calculation */
+ sL = fixMax(0,(CntLeadingZeros(square_l)-1));
+ sR = fixMax(0,(CntLeadingZeros(square_r)-1));
+ s = ((sL + sR)>>1)<<1;
+ sL = fixMin(sL,s);
+ sR = s-sL;
+ tmp = fMult(square_l<<sL,square_r<<sR);
+ tmp = sqrtFixp(tmp);
+
+ FDK_ASSERT(tmp > FL2FXCONST_DBL(0.0f));
+
+ /* numerator and denominator have the same scaling */
+ if (prod_lr < FL2FXCONST_DBL(0.0f) ) {
+ channelCorr[sfb + sfboffs] = -(fDivNorm(-prod_lr,tmp,&channelCorrSF));
+
+ }
+ else {
+ channelCorr[sfb + sfboffs] = (fDivNorm( prod_lr,tmp,&channelCorrSF));
+ }
+ channelCorrSF = fixMin(fixMax(( channelCorrSF + ((sL+sR)>>1)),-(DFRACT_BITS-1)),DFRACT_BITS-1);
+
+ if (channelCorrSF < 0) {
+ channelCorr[sfb + sfboffs] = channelCorr[sfb + sfboffs] >> (-channelCorrSF);
+ }
+ else {
+ /* avoid overflows due to limited computational accuracy */
+ if ( fAbs(channelCorr[sfb + sfboffs]) > (((FIXP_DBL)MAXVAL_DBL)>>channelCorrSF) ) {
+ if (channelCorr[sfb + sfboffs] < FL2FXCONST_DBL(0.0f))
+ channelCorr[sfb + sfboffs] = -(FIXP_DBL) MAXVAL_DBL;
+ else
+ channelCorr[sfb + sfboffs] = (FIXP_DBL) MAXVAL_DBL;
+ }
+ else {
+ channelCorr[sfb + sfboffs] = channelCorr[sfb + sfboffs] << channelCorrSF;
+ }
+ }
+ }
+ }
+
+ /* for post processing: hrrErr is the error in terms of (too little) correlation
+ * weighted with the loudness of the SFB; SFBs with small hrrErr can be merged */
+ if (hrrErr[sfb + sfboffs] == FL2FXCONST_DBL(1.0/8.0)) {
+ continue;
+ }
+
+ hrrErr[sfb + sfboffs] = fMultDiv2((FL2FXCONST_DBL(0.25f)-(channelCorr[sfb + sfboffs]>>2)),normSfbLoudness[sfb + sfboffs]);
+
+ /* set IS mask/vector to 1, if correlation is high enough */
+ if (fAbs(channelCorr[sfb + sfboffs]) >= isParams->corr_thresh) {
+ isMask[sfb + sfboffs] = 1;
+ }
+ }
+ }
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_finalizeIntensityDecision
+
+ description: Finalizes intensity decision
+
+ input: isParams scale: none
+ hrrErr scale: none
+ realIsScale scale: LD_DATA_SHIFT + REAL_SCALE_SF
+ normSfbLoudness scale: none
+
+ output: isMask scale: none
+
+ returns: none
+
+*****************************************************************************/
+static void
+FDKaacEnc_finalizeIntensityDecision(const FIXP_DBL *hrrErr,
+ INT *isMask,
+ const FIXP_DBL *realIsScale,
+ const FIXP_DBL *normSfbLoudness,
+ const INTENSITY_PARAMETERS *isParams,
+ const INT sfbCnt,
+ const INT sfbPerGroup,
+ const INT maxSfbPerGroup)
+{
+ INT sfb,sfboffs, j;
+ INT startIsSfb = 0;
+ INT inIsBlock;
+ INT currentIsSfbCount;
+ FIXP_DBL overallHrrError;
+ FIXP_DBL isScaleLast = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL isRegionLoudness;
+
+ for (sfboffs = 0; sfboffs < sfbCnt; sfboffs += sfbPerGroup) {
+ inIsBlock = 0;
+ currentIsSfbCount = 0;
+ overallHrrError = FL2FXCONST_DBL(0.0f);
+ isRegionLoudness = FL2FXCONST_DBL(0.0f);
+ for (sfb = 0; sfb < maxSfbPerGroup; sfb++) {
+ if (isMask[sfboffs + sfb] == 1) {
+ if (currentIsSfbCount == 0) {
+ startIsSfb = sfboffs + sfb;
+ isScaleLast = realIsScale[sfboffs + sfb];
+ }
+ inIsBlock = 1;
+ currentIsSfbCount++;
+ overallHrrError += hrrErr[sfboffs + sfb] >> (MAX_SFB_PER_GROUP_SF-3);
+ isRegionLoudness += normSfbLoudness[sfboffs + sfb] >> MAX_SFB_PER_GROUP_SF;
+ }
+ else {
+ /* based on correlation, IS should not be used
+ * -> use it anyway, if overall error is below threshold
+ * and if local error does not exceed threshold
+ * otherwise: check if there are enough IS SFBs
+ */
+ if (inIsBlock) {
+ overallHrrError += hrrErr[sfboffs + sfb] >> (MAX_SFB_PER_GROUP_SF-3);
+ isRegionLoudness += normSfbLoudness[sfboffs + sfb] >> MAX_SFB_PER_GROUP_SF;
+
+ if ( (hrrErr[sfboffs + sfb] < (isParams->local_error_thresh>>3)) && (overallHrrError < (isParams->total_error_thresh>>MAX_SFB_PER_GROUP_SF)) ) {
+ currentIsSfbCount++;
+ /* overwrite correlation based decision */
+ isMask[sfboffs + sfb] = 1;
+ } else {
+ inIsBlock = 0;
+ }
+ }
+ }
+ /* check for large direction deviation */
+ if (inIsBlock) {
+ if( fAbs(isScaleLast-realIsScale[sfboffs + sfb]) < (isParams->direction_deviation_thresh>>(REAL_SCALE_SF+LD_DATA_SHIFT-IS_DIRECTION_DEVIATION_THRESH_SF)) ) {
+ isScaleLast = realIsScale[sfboffs + sfb];
+ }
+ else{
+ isMask[sfboffs + sfb] = 0;
+ inIsBlock = 0;
+ currentIsSfbCount--;
+ }
+ }
+
+ if (currentIsSfbCount > 0 && (!inIsBlock || sfb == maxSfbPerGroup - 1)) {
+ /* not enough SFBs -> do not use IS */
+ if (currentIsSfbCount < isParams->min_is_sfbs || (isRegionLoudness < isParams->is_region_min_loudness>>MAX_SFB_PER_GROUP_SF)) {
+ for(j = startIsSfb; j <= sfboffs + sfb; j++) {
+ isMask[j] = 0;
+ }
+ }
+ currentIsSfbCount = 0;
+ overallHrrError = FL2FXCONST_DBL(0.0f);
+ isRegionLoudness = FL2FXCONST_DBL(0.0f);
+ }
+ }
+ }
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_IntensityStereoProcessing
+
+ description: Intensity stereo processing tool
+
+ input: sfbEnergyLeft
+ sfbEnergyRight
+ mdctSpectrumLeft
+ mdctSpectrumRight
+ sfbThresholdLeft
+ sfbThresholdRight
+ sfbSpreadEnLeft
+ sfbSpreadEnRight
+ sfbEnergyLdDataLeft
+ sfbEnergyLdDataRight
+
+ output: isBook
+ isScale
+ pnsData->pnsFlag
+ msDigest zeroed from start to sfbCnt
+ msMask zeroed from start to sfbCnt
+ mdctSpectrumRight zeroed where isBook!=0
+ sfbEnergyRight zeroed where isBook!=0
+ sfbSpreadEnRight zeroed where isBook!=0
+ sfbThresholdRight zeroed where isBook!=0
+ sfbEnergyLdDataRight FL2FXCONST_DBL(-1.0) where isBook!=0
+ sfbThresholdLdDataRight FL2FXCONST_DBL(-0.515625f) where isBook!=0
+
+ returns: none
+
+*****************************************************************************/
+void FDKaacEnc_IntensityStereoProcessing(
+ FIXP_DBL *sfbEnergyLeft,
+ FIXP_DBL *sfbEnergyRight,
+ FIXP_DBL *mdctSpectrumLeft,
+ FIXP_DBL *mdctSpectrumRight,
+ FIXP_DBL *sfbThresholdLeft,
+ FIXP_DBL *sfbThresholdRight,
+ FIXP_DBL *sfbThresholdLdDataRight,
+ FIXP_DBL *sfbSpreadEnLeft,
+ FIXP_DBL *sfbSpreadEnRight,
+ FIXP_DBL *sfbEnergyLdDataLeft,
+ FIXP_DBL *sfbEnergyLdDataRight,
+ INT *msDigest,
+ INT *msMask,
+ const INT sfbCnt,
+ const INT sfbPerGroup,
+ const INT maxSfbPerGroup,
+ const INT *sfbOffset,
+ const INT allowIS,
+ INT *isBook,
+ INT *isScale,
+ PNS_DATA *RESTRICT pnsData[2]
+ )
+{
+ INT sfb,sfboffs, j;
+ FIXP_DBL scale;
+ FIXP_DBL lr;
+ FIXP_DBL hrrErr[MAX_GROUPED_SFB];
+ FIXP_DBL normSfbLoudness[MAX_GROUPED_SFB];
+ FIXP_DBL realIsScale[MAX_GROUPED_SFB];
+ INTENSITY_PARAMETERS isParams;
+ INT isMask[MAX_GROUPED_SFB];
+
+ FDKmemclear((void*)isBook,sfbCnt*sizeof(INT));
+ FDKmemclear((void*)isMask,sfbCnt*sizeof(INT));
+ FDKmemclear((void*)realIsScale,sfbCnt*sizeof(FIXP_DBL));
+ FDKmemclear((void*)isScale,sfbCnt*sizeof(INT));
+ FDKmemclear((void*)hrrErr,sfbCnt*sizeof(FIXP_DBL));
+
+ if (!allowIS)
+ return;
+
+ FDKaacEnc_initIsParams(&isParams);
+
+ /* compute / set the following values per SFB:
+ * - left/right ratio between channels
+ * - normalized loudness
+ * + loudness == average of energy in channels to 0.25
+ * + normalization: division by sum of all SFB loudnesses
+ * - isMask (is set to 0 if channels are the same or one is 0)
+ */
+ FDKaacEnc_prepareIntensityDecision(sfbEnergyLeft,
+ sfbEnergyRight,
+ sfbEnergyLdDataLeft,
+ sfbEnergyLdDataRight,
+ mdctSpectrumLeft,
+ mdctSpectrumRight,
+ &isParams,
+ hrrErr,
+ isMask,
+ realIsScale,
+ normSfbLoudness,
+ sfbCnt,
+ sfbPerGroup,
+ maxSfbPerGroup,
+ sfbOffset);
+
+ FDKaacEnc_finalizeIntensityDecision(hrrErr,
+ isMask,
+ realIsScale,
+ normSfbLoudness,
+ &isParams,
+ sfbCnt,
+ sfbPerGroup,
+ maxSfbPerGroup);
+
+ for (sfb=0; sfb<sfbCnt; sfb+=sfbPerGroup) {
+ for (sfboffs=0; sfboffs<maxSfbPerGroup; sfboffs++) {
+ INT sL, sR;
+ FIXP_DBL inv_n;
+
+ msMask[sfb+sfboffs] = 0;
+ if (isMask[sfb+sfboffs] == 0) {
+ continue;
+ }
+
+ if ( (sfbEnergyLeft[sfb+sfboffs] < sfbThresholdLeft[sfb+sfboffs])
+ &&(fMult(FL2FXCONST_DBL(1.0f/1.5f),sfbEnergyRight[sfb+sfboffs]) > sfbThresholdRight[sfb+sfboffs]) ) {
+ continue;
+ }
+ /* NEW: if there is a big-enough IS region, switch off PNS */
+ if (pnsData[0]) {
+ if(pnsData[0]->pnsFlag[sfb+sfboffs]) {
+ pnsData[0]->pnsFlag[sfb+sfboffs] = 0;
+ }
+ if(pnsData[1]->pnsFlag[sfb+sfboffs]) {
+ pnsData[1]->pnsFlag[sfb+sfboffs] = 0;
+ }
+ }
+
+ inv_n = GetInvInt((sfbOffset[sfb + sfboffs + 1] - sfbOffset[sfb + sfboffs])>>1); // scaled with 2 to compensate fMultDiv2() in subsequent loop
+ sL = calcSfbMaxScale(mdctSpectrumLeft,sfbOffset[sfb+sfboffs],sfbOffset[sfb+sfboffs+1]);
+ sR = calcSfbMaxScale(mdctSpectrumRight,sfbOffset[sfb+sfboffs],sfbOffset[sfb+sfboffs+1]);
+
+ lr = FL2FXCONST_DBL(0.0f);
+ for (j=sfbOffset[sfb+sfboffs]; j<sfbOffset[sfb+sfboffs+1]; j++)
+ lr += fMultDiv2(fMultDiv2(mdctSpectrumLeft[j]<<sL,mdctSpectrumRight[j]<<sR),inv_n);
+ lr = lr<<1;
+
+ if (lr < FL2FXCONST_DBL(0.0f)) {
+ /* This means OUT OF phase intensity stereo, cf. standard */
+ INT s0, s1, s2;
+ FIXP_DBL tmp, d, ed = FL2FXCONST_DBL(0.0f);
+
+ s0 = fixMin(sL,sR);
+ for (j=sfbOffset[sfb+sfboffs]; j<sfbOffset[sfb+sfboffs+1]; j++) {
+ d = ((mdctSpectrumLeft[j]<<s0)>>1) - ((mdctSpectrumRight[j]<<s0)>>1);
+ ed += fMultDiv2(d,d)>>(MDCT_SPEC_SF-1);
+ }
+ msMask[sfb+sfboffs] = 1;
+ tmp = fDivNorm(sfbEnergyLeft[sfb+sfboffs],ed,&s1);
+ s2 = (s1) + (2*s0) - 2 - MDCT_SPEC_SF;
+ if (s2 & 1) {
+ tmp = tmp>>1;
+ s2 = s2+1;
+ }
+ s2 = (s2>>1) + 1; // +1 compensate fMultDiv2() in subsequent loop
+ s2 = fixMin(fixMax(s2,-(DFRACT_BITS-1)),(DFRACT_BITS-1));
+ scale = sqrtFixp(tmp);
+ if (s2 < 0) {
+ s2 = -s2;
+ for (j=sfbOffset[sfb+sfboffs]; j<sfbOffset[sfb+sfboffs+1]; j++) {
+ mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j],scale) - fMultDiv2(mdctSpectrumRight[j],scale)) >> s2;
+ mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f);
+ }
+ }
+ else {
+ for (j=sfbOffset[sfb+sfboffs]; j<sfbOffset[sfb+sfboffs+1]; j++) {
+ mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j],scale) - fMultDiv2(mdctSpectrumRight[j],scale)) << s2;
+ mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f);
+ }
+ }
+ }
+ else {
+ /* This means IN phase intensity stereo, cf. standard */
+ INT s0,s1,s2;
+ FIXP_DBL tmp, s, es = FL2FXCONST_DBL(0.0f);
+
+ s0 = fixMin(sL,sR);
+ for (j=sfbOffset[sfb+sfboffs]; j<sfbOffset[sfb+sfboffs+1]; j++) {
+ s = ((mdctSpectrumLeft[j]<<s0)>>1) + ((mdctSpectrumRight[j]<<s0)>>1);
+ es += fMultDiv2(s,s)>>(MDCT_SPEC_SF-1); // scaled 2*(mdctScale - s0 + 1) + MDCT_SPEC_SF
+ }
+ msMask[sfb+sfboffs] = 0;
+ tmp = fDivNorm(sfbEnergyLeft[sfb+sfboffs],es,&s1);
+ s2 = (s1) + (2*s0) - 2 - MDCT_SPEC_SF;
+ if (s2 & 1) {
+ tmp = tmp>>1;
+ s2 = s2 + 1;
+ }
+ s2 = (s2>>1) + 1; // +1 compensate fMultDiv2() in subsequent loop
+ s2 = fixMin(fixMax(s2,-(DFRACT_BITS-1)),(DFRACT_BITS-1));
+ scale = sqrtFixp(tmp);
+ if (s2 < 0) {
+ s2 = -s2;
+ for (j=sfbOffset[sfb+sfboffs]; j<sfbOffset[sfb+sfboffs+1]; j++) {
+ mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j],scale) + fMultDiv2(mdctSpectrumRight[j],scale)) >> s2;
+ mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f);
+ }
+ }
+ else {
+ for (j=sfbOffset[sfb+sfboffs]; j<sfbOffset[sfb+sfboffs+1]; j++) {
+ mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j],scale) + fMultDiv2(mdctSpectrumRight[j],scale)) << s2;
+ mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f);
+ }
+ }
+ }
+
+ isBook[sfb+sfboffs] = CODE_BOOK_IS_IN_PHASE_NO;
+
+ if ( realIsScale[sfb+sfboffs] < FL2FXCONST_DBL(0.0f) ) {
+ isScale[sfb+sfboffs] = (INT)(((realIsScale[sfb+sfboffs]>>1)-FL2FXCONST_DBL(0.5f/(1<<(REAL_SCALE_SF+LD_DATA_SHIFT+1))))>>(DFRACT_BITS-1-REAL_SCALE_SF-LD_DATA_SHIFT-1)) + 1;
+ }
+ else {
+ isScale[sfb+sfboffs] = (INT)(((realIsScale[sfb+sfboffs]>>1)+FL2FXCONST_DBL(0.5f/(1<<(REAL_SCALE_SF+LD_DATA_SHIFT+1))))>>(DFRACT_BITS-1-REAL_SCALE_SF-LD_DATA_SHIFT-1));
+ }
+
+ sfbEnergyRight[sfb+sfboffs] = FL2FXCONST_DBL(0.0f);
+ sfbEnergyLdDataRight[sfb+sfboffs] = FL2FXCONST_DBL(-1.0f);
+ sfbThresholdRight[sfb+sfboffs] = FL2FXCONST_DBL(0.0f);
+ sfbThresholdLdDataRight[sfb+sfboffs] = FL2FXCONST_DBL(-0.515625f);
+ sfbSpreadEnRight[sfb+sfboffs] = FL2FXCONST_DBL(0.0f);
+
+ *msDigest = MS_SOME;
+ }
+ }
+}
+
diff --git a/libAACenc/src/intensity.h b/libAACenc/src/intensity.h
new file mode 100644
index 0000000..9165a22
--- /dev/null
+++ b/libAACenc/src/intensity.h
@@ -0,0 +1,61 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (2010)
+ 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$
+
+ Initial author: A. Horndasch (code originally from lwr and rtb) / Josef Höpfl (FDK)
+ contents/description: intensity stereo prototype
+
+******************************************************************************/
+
+#ifndef _INTENSITY_H
+#define _INTENSITY_H
+
+#include "aacenc_pns.h"
+
+
+void FDKaacEnc_IntensityStereoProcessing(
+ FIXP_DBL *sfbEnergyLeft,
+ FIXP_DBL *sfbEnergyRight,
+ FIXP_DBL *mdctSpectrumLeft,
+ FIXP_DBL *mdctSpectrumRight,
+ FIXP_DBL *sfbThresholdLeft,
+ FIXP_DBL *sfbThresholdRight,
+ FIXP_DBL *sfbThresholdLdDataRight,
+ FIXP_DBL *sfbSpreadEnLeft,
+ FIXP_DBL *sfbSpreadEnRight,
+ FIXP_DBL *sfbEnergyLdDataLeft,
+ FIXP_DBL *sfbEnergyLdDataRight,
+ INT *msDigest,
+ INT *msMask,
+ const INT sfbCnt,
+ const INT sfbPerGroup,
+ const INT maxSfbPerGroup,
+ const INT *sfbOffset,
+ const INT allowIS,
+ INT *isBook,
+ INT *isScale,
+ PNS_DATA *RESTRICT pnsData[2]
+ );
+
+#endif /* _INTENSITY_H */
+
diff --git a/libAACenc/src/interface.h b/libAACenc/src/interface.h
new file mode 100644
index 0000000..b6f747e
--- /dev/null
+++ b/libAACenc/src/interface.h
@@ -0,0 +1,100 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Interface psychoaccoustic/quantizer
+
+******************************************************************************/
+#ifndef _INTERFACE_H
+#define _INTERFACE_H
+
+#include "common_fix.h"
+
+#include "psy_data.h"
+#include "aacenc_tns.h"
+
+enum
+{
+ MS_NONE = 0,
+ MS_SOME = 1,
+ MS_ALL = 2
+};
+
+enum
+{
+ MS_ON = 1
+};
+
+struct TOOLSINFO {
+ INT msDigest; /* 0 = no MS; 1 = some MS, 2 = all MS */
+ INT msMask[MAX_GROUPED_SFB];
+};
+
+
+typedef struct {
+ INT sfbCnt;
+ INT sfbPerGroup;
+ INT maxSfbPerGroup;
+ INT lastWindowSequence;
+ INT windowShape;
+ INT groupingMask;
+ INT sfbOffsets[MAX_GROUPED_SFB+1];
+
+ INT mdctScale; /* number of transform shifts */
+ INT groupLen[MAX_NO_OF_GROUPS];
+
+ TNS_INFO tnsInfo;
+ INT noiseNrg[MAX_GROUPED_SFB];
+ INT isBook[MAX_GROUPED_SFB];
+ INT isScale[MAX_GROUPED_SFB];
+
+ /* memory located in QC_OUT_CHANNEL */
+ FIXP_DBL *mdctSpectrum;
+ FIXP_DBL *sfbEnergy;
+ FIXP_DBL *sfbSpreadEnergy;
+ FIXP_DBL *sfbThresholdLdData;
+ FIXP_DBL *sfbMinSnrLdData;
+ FIXP_DBL *sfbEnergyLdData;
+
+
+ }PSY_OUT_CHANNEL;
+
+typedef struct {
+
+ /* information specific to each channel */
+ PSY_OUT_CHANNEL* psyOutChannel[(2)];
+
+ /* information shared by both channels */
+ INT commonWindow;
+ struct TOOLSINFO toolsInfo;
+
+} PSY_OUT_ELEMENT;
+
+typedef struct {
+
+ PSY_OUT_ELEMENT* psyOutElement[(6)];
+ PSY_OUT_CHANNEL* pPsyOutChannels[(6)];
+
+}PSY_OUT;
+
+#endif /* _INTERFACE_H */
diff --git a/libAACenc/src/line_pe.cpp b/libAACenc/src/line_pe.cpp
new file mode 100644
index 0000000..cf43a81
--- /dev/null
+++ b/libAACenc/src/line_pe.cpp
@@ -0,0 +1,145 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: Perceptual entropie module
+
+******************************************************************************/
+
+#include "line_pe.h"
+#include "sf_estim.h"
+#include "bit_cnt.h"
+
+#include "genericStds.h"
+
+static const FIXP_DBL C1LdData = FL2FXCONST_DBL(3.0/LD_DATA_SCALING); /* C1 = 3.0 = log(8.0)/log(2) */
+static const FIXP_DBL C2LdData = FL2FXCONST_DBL(1.3219281/LD_DATA_SCALING); /* C2 = 1.3219281 = log(2.5)/log(2) */
+static const FIXP_DBL C3LdData = FL2FXCONST_DBL(0.5593573); /* 1-C2/C1 */
+
+
+/* constants that do not change during successive pe calculations */
+void FDKaacEnc_prepareSfbPe(PE_CHANNEL_DATA *peChanData,
+ const FIXP_DBL *sfbEnergyLdData,
+ const FIXP_DBL *sfbThresholdLdData,
+ const FIXP_DBL *sfbFormFactorLdData,
+ const INT *sfbOffset,
+ const INT sfbCnt,
+ const INT sfbPerGroup,
+ const INT maxSfbPerGroup)
+{
+ INT sfbGrp,sfb;
+ INT sfbWidth;
+ FIXP_DBL avgFormFactorLdData;
+ const FIXP_DBL formFacScaling = FL2FXCONST_DBL((float)FORM_FAC_SHIFT/LD_DATA_SCALING);
+
+ for (sfbGrp = 0;sfbGrp < sfbCnt;sfbGrp+=sfbPerGroup) {
+ for (sfb=0; sfb<maxSfbPerGroup; sfb++) {
+ if ((FIXP_DBL)sfbEnergyLdData[sfbGrp+sfb] > (FIXP_DBL)sfbThresholdLdData[sfbGrp+sfb]) {
+ sfbWidth = sfbOffset[sfbGrp+sfb+1] - sfbOffset[sfbGrp+sfb];
+ /* estimate number of active lines */
+ avgFormFactorLdData = ((-sfbEnergyLdData[sfbGrp+sfb]>>1) + (CalcLdInt(sfbWidth)>>1))>>1;
+ peChanData->sfbNLines[sfbGrp+sfb] =
+ (INT)CalcInvLdData( (sfbFormFactorLdData[sfbGrp+sfb] + formFacScaling) + avgFormFactorLdData);
+ }
+ else {
+ peChanData->sfbNLines[sfbGrp+sfb] = 0;
+ }
+ }
+ }
+}
+
+/*
+ formula for one sfb:
+ pe = n * ld(en/thr), if ld(en/thr) >= C1
+ pe = n * (C2 + C3 * ld(en/thr)), if ld(en/thr) < C1
+ n: estimated number of lines in sfb,
+ ld(x) = log(x)/log(2)
+
+ constPart is sfbPe without the threshold part n*ld(thr) or n*C3*ld(thr)
+*/
+void FDKaacEnc_calcSfbPe(PE_CHANNEL_DATA *RESTRICT peChanData,
+ const FIXP_DBL *RESTRICT sfbEnergyLdData,
+ const FIXP_DBL *RESTRICT sfbThresholdLdData,
+ const INT sfbCnt,
+ const INT sfbPerGroup,
+ const INT maxSfbPerGroup,
+ const INT *isBook,
+ const INT *isScale)
+{
+ INT sfbGrp,sfb;
+ INT nLines;
+ FIXP_DBL logDataRatio;
+ INT lastValIs = 0;
+
+ peChanData->pe = 0;
+ peChanData->constPart = 0;
+ peChanData->nActiveLines = 0;
+
+ for(sfbGrp = 0;sfbGrp < sfbCnt;sfbGrp+=sfbPerGroup){
+ for (sfb=0; sfb<maxSfbPerGroup; sfb++) {
+ if ((FIXP_DBL)sfbEnergyLdData[sfbGrp+sfb] > (FIXP_DBL)sfbThresholdLdData[sfbGrp+sfb]) {
+ logDataRatio = (FIXP_DBL)(sfbEnergyLdData[sfbGrp+sfb] - sfbThresholdLdData[sfbGrp+sfb]);
+ nLines = peChanData->sfbNLines[sfbGrp+sfb];
+ if (logDataRatio >= C1LdData) {
+ /* scale sfbPe and sfbConstPart with PE_CONSTPART_SHIFT */
+ peChanData->sfbPe[sfbGrp+sfb] = fMultDiv2(logDataRatio, (FIXP_DBL)(nLines<<(LD_DATA_SHIFT+PE_CONSTPART_SHIFT+1)));
+ peChanData->sfbConstPart[sfbGrp+sfb] =
+ fMultDiv2(sfbEnergyLdData[sfbGrp+sfb], (FIXP_DBL)(nLines<<(LD_DATA_SHIFT+PE_CONSTPART_SHIFT+1))); ;
+
+ }
+ else {
+ /* scale sfbPe and sfbConstPart with PE_CONSTPART_SHIFT */
+ peChanData->sfbPe[sfbGrp+sfb] =
+ fMultDiv2(((FIXP_DBL)C2LdData + fMult(C3LdData,logDataRatio)), (FIXP_DBL)(nLines<<(LD_DATA_SHIFT+PE_CONSTPART_SHIFT+1)));
+
+ peChanData->sfbConstPart[sfbGrp+sfb] =
+ fMultDiv2(((FIXP_DBL)C2LdData + fMult(C3LdData,sfbEnergyLdData[sfbGrp+sfb])),
+ (FIXP_DBL)(nLines<<(LD_DATA_SHIFT+PE_CONSTPART_SHIFT+1))) ;
+
+ nLines = fMultI(C3LdData, nLines);
+ }
+ peChanData->sfbNActiveLines[sfbGrp+sfb] = nLines;
+ }
+ else if( isBook[sfb] ) {
+ /* provide for cost of scale factor for Intensity */
+ INT delta = isScale[sfbGrp+sfb] - lastValIs;
+ lastValIs = isScale[sfbGrp+sfb];
+ peChanData->sfbPe[sfbGrp+sfb] = FDKaacEnc_bitCountScalefactorDelta(delta)<<PE_CONSTPART_SHIFT;
+ peChanData->sfbConstPart[sfbGrp+sfb] = 0;
+ peChanData->sfbNActiveLines[sfbGrp+sfb] = 0;
+ }
+ else {
+ peChanData->sfbPe[sfbGrp+sfb] = 0;
+ peChanData->sfbConstPart[sfbGrp+sfb] = 0;
+ peChanData->sfbNActiveLines[sfbGrp+sfb] = 0;
+ }
+ /* sum up peChanData values */
+ peChanData->pe += peChanData->sfbPe[sfbGrp+sfb];
+ peChanData->constPart += peChanData->sfbConstPart[sfbGrp+sfb];
+ peChanData->nActiveLines += peChanData->sfbNActiveLines[sfbGrp+sfb];
+ }
+ }
+ /* correct scaled pe and constPart values */
+ peChanData->pe>>=PE_CONSTPART_SHIFT;
+ peChanData->constPart>>=PE_CONSTPART_SHIFT;
+}
diff --git a/libAACenc/src/line_pe.h b/libAACenc/src/line_pe.h
new file mode 100644
index 0000000..418df27
--- /dev/null
+++ b/libAACenc/src/line_pe.h
@@ -0,0 +1,77 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: Perceptual entropie module
+
+******************************************************************************/
+#ifndef __LINE_PE_H
+#define __LINE_PE_H
+
+
+#include "common_fix.h"
+
+#include "psy_const.h"
+
+#define PE_CONSTPART_SHIFT FRACT_BITS
+
+typedef struct {
+ /* calculated by FDKaacEnc_prepareSfbPe */
+ INT sfbNLines[MAX_GROUPED_SFB]; /* number of relevant lines in sfb */
+ /* the rest is calculated by FDKaacEnc_calcSfbPe */
+ INT sfbPe[MAX_GROUPED_SFB]; /* pe for each sfb */
+ INT sfbConstPart[MAX_GROUPED_SFB]; /* constant part for each sfb */
+ INT sfbNActiveLines[MAX_GROUPED_SFB]; /* number of active lines in sfb */
+ INT pe; /* sum of sfbPe */
+ INT constPart; /* sum of sfbConstPart */
+ INT nActiveLines; /* sum of sfbNActiveLines */
+} PE_CHANNEL_DATA;
+
+typedef struct {
+ PE_CHANNEL_DATA peChannelData[(2)];
+ INT pe;
+ INT constPart;
+ INT nActiveLines;
+ INT offset;
+} PE_DATA;
+
+
+void FDKaacEnc_prepareSfbPe(PE_CHANNEL_DATA *peChanData,
+ const FIXP_DBL *sfbEnergyLdData,
+ const FIXP_DBL *sfbThresholdLdData,
+ const FIXP_DBL *sfbFormFactorLdData,
+ const INT *sfbOffset,
+ const INT sfbCnt,
+ const INT sfbPerGroup,
+ const INT maxSfbPerGroup);
+
+void FDKaacEnc_calcSfbPe(PE_CHANNEL_DATA *RESTRICT peChanData,
+ const FIXP_DBL *RESTRICT sfbEnergyLdData,
+ const FIXP_DBL *RESTRICT sfbThresholdLdData,
+ const INT sfbCnt,
+ const INT sfbPerGroup,
+ const INT maxSfbPerGroup,
+ const INT *isBook,
+ const INT *isScale);
+
+#endif
diff --git a/libAACenc/src/metadata_compressor.cpp b/libAACenc/src/metadata_compressor.cpp
new file mode 100644
index 0000000..cfb55e9
--- /dev/null
+++ b/libAACenc/src/metadata_compressor.cpp
@@ -0,0 +1,965 @@
+/********************** Fraunhofer IIS FDK AAC Encoder lib ******************
+
+ (C) Copyright Fraunhofer IIS (2011)
+ 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): M. Neusinger
+ Description: Compressor for AAC Metadata Generator
+
+ 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 "metadata_compressor.h"
+#include "channel_map.h"
+
+
+#define LOG2 0.69314718056f /* natural logarithm of 2 */
+#define ILOG2 1.442695041f /* 1/LOG2 */
+#define FIXP_ILOG2_DIV2 (FL2FXCONST_DBL(ILOG2/2))
+
+/*----------------- defines ----------------------*/
+
+#define MAX_DRC_CHANNELS (8) /*!< Max number of audio input channels. */
+#define DOWNMIX_SHIFT (3) /*!< Max 8 channel. */
+#define WEIGHTING_FILTER_SHIFT (2) /*!< Scaling used in weighting filter. */
+
+#define METADATA_INT_BITS 10
+#define METADATA_LINT_BITS 20
+#define METADATA_INT_SCALE (INT64(1)<<(METADATA_INT_BITS))
+#define METADATA_FRACT_BITS (DFRACT_BITS-1-METADATA_INT_BITS)
+#define METADATA_FRACT_SCALE (INT64(1)<<(METADATA_FRACT_BITS))
+
+/**
+ * Enum for channel assignment.
+ */
+enum {
+ L = 0,
+ R = 1,
+ C = 2,
+ LFE = 3,
+ LS = 4,
+ RS = 5,
+ S = 6,
+ LS2 = 7,
+ RS2 = 8
+};
+
+/*--------------- structure definitions --------------------*/
+
+/**
+ * Structure holds weighting filter filter states.
+ */
+struct WEIGHTING_STATES {
+ FIXP_DBL x1;
+ FIXP_DBL x2;
+ FIXP_DBL y1;
+ FIXP_DBL y2;
+};
+
+/**
+ * Dynamic Range Control compressor structure.
+ */
+struct DRC_COMP {
+
+ FIXP_DBL maxBoostThr[2]; /*!< Max boost threshold. */
+ FIXP_DBL boostThr[2]; /*!< Boost threshold. */
+ FIXP_DBL earlyCutThr[2]; /*!< Early cut threshold. */
+ FIXP_DBL cutThr[2]; /*!< Cut threshold. */
+ FIXP_DBL maxCutThr[2]; /*!< Max cut threshold. */
+
+ FIXP_DBL boostFac[2]; /*!< Precalculated factor for boost compression. */
+ FIXP_DBL earlyCutFac[2]; /*!< Precalculated factor for early cut compression. */
+ FIXP_DBL cutFac[2]; /*!< Precalculated factor for cut compression. */
+
+ FIXP_DBL maxBoost[2]; /*!< Maximum boost. */
+ FIXP_DBL maxCut[2]; /*!< Maximum cut. */
+ FIXP_DBL maxEarlyCut[2]; /*!< Maximum early cut. */
+
+ FIXP_DBL fastAttack[2]; /*!< Fast attack coefficient. */
+ FIXP_DBL fastDecay[2]; /*!< Fast release coefficient. */
+ FIXP_DBL slowAttack[2]; /*!< Slow attack coefficient. */
+ FIXP_DBL slowDecay[2]; /*!< Slow release coefficient. */
+ UINT holdOff[2]; /*!< Hold time in blocks. */
+
+ FIXP_DBL attackThr[2]; /*!< Slow/fast attack threshold. */
+ FIXP_DBL decayThr[2]; /*!< Slow/fast release threshold. */
+
+ DRC_PROFILE profile[2]; /*!< DRC profile. */
+ INT blockLength; /*!< Block length in samples. */
+ UINT sampleRate; /*!< Sample rate. */
+ CHANNEL_MODE chanConfig; /*!< Channel configuration. */
+
+ UCHAR useWeighting; /*!< Use weighting filter. */
+
+ UINT channels; /*!< Number of channels. */
+ UINT fullChannels; /*!< Number of full range channels. */
+ INT channelIdx[9]; /*!< Offsets of interleaved channel samples (L, R, C, LFE, Ls, Rs, S, Ls2, Rs2). */
+
+ FIXP_DBL smoothLevel[2]; /*!< level smoothing states */
+ FIXP_DBL smoothGain[2]; /*!< gain smoothing states */
+ UINT holdCnt[2]; /*!< hold counter */
+
+ FIXP_DBL limGain[2]; /*!< limiter gain */
+ FIXP_DBL limDecay; /*!< limiter decay (linear) */
+ FIXP_DBL prevPeak[2]; /*!< max peak of previous block (stereo/mono)*/
+
+ WEIGHTING_STATES filter[MAX_DRC_CHANNELS]; /*!< array holds weighting filter states */
+
+};
+
+/*---------------- constants -----------------------*/
+
+/**
+ * Profile tables.
+ */
+static const FIXP_DBL tabMaxBoostThr[] = {
+ (FIXP_DBL)(-43<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-53<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-55<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-65<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-50<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-40<<METADATA_FRACT_BITS)
+};
+static const FIXP_DBL tabBoostThr[] = {
+ (FIXP_DBL)(-31<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-41<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-31<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-41<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-31<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-31<<METADATA_FRACT_BITS)
+};
+static const FIXP_DBL tabEarlyCutThr[] = {
+ (FIXP_DBL)(-26<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-21<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-26<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-21<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-26<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-20<<METADATA_FRACT_BITS)
+};
+static const FIXP_DBL tabCutThr[] = {
+ (FIXP_DBL)(-16<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-11<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-16<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-21<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-16<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(-10<<METADATA_FRACT_BITS)
+};
+static const FIXP_DBL tabMaxCutThr[] = {
+ (FIXP_DBL)(4<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(9<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(4<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(9<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(4<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(4<<METADATA_FRACT_BITS)
+};
+static const FIXP_DBL tabBoostRatio[] = {
+ FL2FXCONST_DBL( ((1.f/2.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/2.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/2.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/2.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/5.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/5.f) - 1.f) )
+};
+static const FIXP_DBL tabEarlyCutRatio[] = {
+ FL2FXCONST_DBL( ((1.f/2.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/2.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/2.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/1.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/2.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/2.f) - 1.f) )
+};
+static const FIXP_DBL tabCutRatio[] = {
+ FL2FXCONST_DBL( ((1.f/20.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/20.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/20.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/ 2.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/20.f) - 1.f) ),
+ FL2FXCONST_DBL( ((1.f/20.f) - 1.f) )
+};
+static const FIXP_DBL tabMaxBoost[] = {
+ (FIXP_DBL)( 6<<METADATA_FRACT_BITS),
+ (FIXP_DBL)( 6<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(12<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(12<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(15<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(15<<METADATA_FRACT_BITS)
+};
+static const FIXP_DBL tabMaxCut[] = {
+ (FIXP_DBL)(24<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(24<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(24<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(15<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(24<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(24<<METADATA_FRACT_BITS)
+};
+static const FIXP_DBL tabFastAttack[] = {
+ FL2FXCONST_DBL((10.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((10.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((10.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((10.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((10.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL( (0.f/1000.f)/METADATA_INT_SCALE)
+};
+static const FIXP_DBL tabFastDecay[] = {
+ FL2FXCONST_DBL((1000.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((1000.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((1000.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((1000.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL( (200.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL( (0.f/1000.f)/METADATA_INT_SCALE)
+};
+static const FIXP_DBL tabSlowAttack[] = {
+ FL2FXCONST_DBL((100.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((100.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((100.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((100.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((100.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL( (0.f/1000.f)/METADATA_INT_SCALE)
+};
+static const FIXP_DBL tabSlowDecay[] = {
+ FL2FXCONST_DBL( (3000.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL( (3000.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL((10000.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL( (3000.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL( (1000.f/1000.f)/METADATA_INT_SCALE),
+ FL2FXCONST_DBL( (0.f/1000.f)/METADATA_INT_SCALE)
+};
+
+static const INT tabHoldOff[] = { 10, 10, 10, 10, 10, 0 };
+
+static const FIXP_DBL tabAttackThr[] = {
+ (FIXP_DBL)(15<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(15<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(15<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(15<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(10<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(0<<METADATA_FRACT_BITS)
+};
+static const FIXP_DBL tabDecayThr[] = {
+ (FIXP_DBL)(20<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(20<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(20<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(20<<METADATA_FRACT_BITS),
+ (FIXP_DBL)(10<<METADATA_FRACT_BITS),
+ (FIXP_DBL)( 0<<METADATA_FRACT_BITS)
+};
+
+/**
+ * Weighting filter coefficients (biquad bandpass).
+ */
+static const FIXP_DBL b0 = FL2FXCONST_DBL(0.53050662f); /* b1 = 0, b2 = -b0 */
+static const FIXP_DBL a1 = FL2FXCONST_DBL(-0.95237983f), a2 = FL2FXCONST_DBL(-0.02248836f); /* a0 = 1 */
+
+
+/*------------- function definitions ----------------*/
+
+/**
+ * \brief Calculate scaling factor for denoted processing block.
+ *
+ * \param blockLength Length of processing block.
+ *
+ * \return shiftFactor
+ */
+static UINT getShiftFactor(
+ const UINT length
+ )
+{
+ UINT ldN;
+ for(ldN=1;(((UINT)1)<<ldN) < length;ldN++);
+
+ return ldN;
+}
+
+/**
+ * \brief Sum up fixpoint values with best possible accuracy.
+ *
+ * \param value1 First input value.
+ * \param q1 Scaling factor of first input value.
+ * \param pValue2 Pointer to second input value, will be modified on return.
+ * \param pQ2 Pointer to second scaling factor, will be modified on return.
+ *
+ * \return void
+ */
+static void fixpAdd(
+ const FIXP_DBL value1,
+ const int q1,
+ FIXP_DBL *const pValue2,
+ int *const pQ2
+ )
+{
+ const int headroom1 = fNormz(fixp_abs(value1))-1;
+ const int headroom2 = fNormz(fixp_abs(*pValue2))-1;
+ int resultScale = fixMax(q1-headroom1, (*pQ2)-headroom2);
+
+ if ( (value1!=FL2FXCONST_DBL(0.f)) && (*pValue2!=FL2FXCONST_DBL(0.f)) ) {
+ resultScale++;
+ }
+
+ *pValue2 = scaleValue(value1, q1-resultScale) + scaleValue(*pValue2, (*pQ2)-resultScale);
+ *pQ2 = (*pValue2!=(FIXP_DBL)0) ? resultScale : DFRACT_BITS-1;
+}
+
+/**
+ * \brief Function for converting time constant to filter coefficient.
+ *
+ * \param t Time constant.
+ * \param sampleRate Sampling rate in Hz.
+ * \param blockLength Length of processing block in samples per channel.
+ *
+ * \return result = 1.0 - exp(-1.0/((t) * (f)))
+ */
+static FIXP_DBL tc2Coeff(
+ const FIXP_DBL t,
+ const INT sampleRate,
+ const INT blockLength
+ )
+{
+ FIXP_DBL sampleRateFract;
+ FIXP_DBL blockLengthFract;
+ FIXP_DBL f, product;
+ FIXP_DBL exponent, result;
+ INT e_res;
+
+ /* f = sampleRate/blockLength */
+ sampleRateFract = (FIXP_DBL)(sampleRate<<(DFRACT_BITS-1-METADATA_LINT_BITS));
+ blockLengthFract = (FIXP_DBL)(blockLength<<(DFRACT_BITS-1-METADATA_LINT_BITS));
+ f = fDivNorm(sampleRateFract, blockLengthFract, &e_res);
+ f = scaleValue(f, e_res-METADATA_INT_BITS); /* convert to METADATA_FRACT */
+
+ /* product = t*f */
+ product = fMultNorm(t, f, &e_res);
+ product = scaleValue(product, e_res+METADATA_INT_BITS); /* convert to METADATA_FRACT */
+
+ /* exponent = (-1.0/((t) * (f))) */
+ exponent = fDivNorm(METADATA_FRACT_SCALE, product, &e_res);
+ exponent = scaleValue(exponent, e_res-METADATA_INT_BITS); /* convert to METADATA_FRACT */
+
+ /* exponent * ld(e) */
+ exponent = fMult(exponent,FIXP_ILOG2_DIV2)<<1; /* e^(x) = 2^(x*ld(e)) */
+
+ /* exp(-1.0/((t) * (f))) */
+ result = f2Pow(-exponent, DFRACT_BITS-1-METADATA_FRACT_BITS, &e_res);
+
+ /* result = 1.0 - exp(-1.0/((t) * (f))) */
+ result = FL2FXCONST_DBL(1.0f) - scaleValue(result, e_res);
+
+ return result;
+}
+
+INT FDK_DRC_Generator_Open(
+ HDRC_COMP *phDrcComp
+ )
+{
+ INT err = 0;
+ HDRC_COMP hDcComp = NULL;
+
+ if (phDrcComp == NULL) {
+ err = -1;
+ goto bail;
+ }
+
+ /* allocate memory */
+ hDcComp = (HDRC_COMP)FDKcalloc(1, sizeof(DRC_COMP));
+
+ if (hDcComp == NULL) {
+ err = -1;
+ goto bail;
+ }
+
+ FDKmemclear(hDcComp, sizeof(DRC_COMP));
+
+ /* Return drc compressor instance */
+ *phDrcComp = hDcComp;
+ return err;
+bail:
+ FDK_DRC_Generator_Close(&hDcComp);
+ return err;
+}
+
+INT FDK_DRC_Generator_Close(
+ HDRC_COMP *phDrcComp
+ )
+{
+ if (phDrcComp == NULL) {
+ return -1;
+ }
+ if (*phDrcComp != NULL) {
+ FDKfree(*phDrcComp);
+ *phDrcComp = NULL;
+ }
+ return 0;
+}
+
+
+INT FDK_DRC_Generator_Initialize(
+ HDRC_COMP drcComp,
+ const DRC_PROFILE profileLine,
+ const DRC_PROFILE profileRF,
+ const INT blockLength,
+ const UINT sampleRate,
+ const CHANNEL_MODE channelMode,
+ const CHANNEL_ORDER channelOrder,
+ const UCHAR useWeighting
+ )
+{
+ int i;
+ CHANNEL_MAPPING channelMapping;
+
+ drcComp->limDecay = FL2FXCONST_DBL( ((0.006f / 256) * blockLength) / METADATA_INT_SCALE );
+
+ /* Save parameters. */
+ drcComp->blockLength = blockLength;
+ drcComp->sampleRate = sampleRate;
+ drcComp->chanConfig = channelMode;
+ drcComp->useWeighting = useWeighting;
+
+ if (FDK_DRC_Generator_setDrcProfile(drcComp, profileLine, profileRF)!=0) { /* expects initialized blockLength and sampleRate */
+ return (-1);
+ }
+
+ /* Set number of channels and channel offsets. */
+ if (FDKaacEnc_InitChannelMapping(channelMode, channelOrder, &channelMapping)!=AAC_ENC_OK) {
+ return (-2);
+ }
+
+ for (i = 0; i < 9; i++) drcComp->channelIdx[i] = -1;
+
+ switch (channelMode) {
+ case MODE_1: /* mono */
+ drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0];
+ break;
+ case MODE_2: /* stereo */
+ drcComp->channelIdx[L] = channelMapping.elInfo[0].ChannelIndex[0];
+ drcComp->channelIdx[R] = channelMapping.elInfo[0].ChannelIndex[1];
+ break;
+ case MODE_1_2: /* 3ch */
+ drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0];
+ drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1];
+ drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0];
+ break;
+ case MODE_1_2_1: /* 4ch */
+ drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0];
+ drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1];
+ drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0];
+ drcComp->channelIdx[S] = channelMapping.elInfo[2].ChannelIndex[0];
+ break;
+ case MODE_1_2_2: /* 5ch */
+ drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0];
+ drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1];
+ drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0];
+ drcComp->channelIdx[LS] = channelMapping.elInfo[2].ChannelIndex[0];
+ drcComp->channelIdx[RS] = channelMapping.elInfo[2].ChannelIndex[1];
+ break;
+ case MODE_1_2_2_1: /* 5.1 ch */
+ drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0];
+ drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1];
+ drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0];
+ drcComp->channelIdx[LFE] = channelMapping.elInfo[3].ChannelIndex[0];
+ drcComp->channelIdx[LS] = channelMapping.elInfo[2].ChannelIndex[0];
+ drcComp->channelIdx[RS] = channelMapping.elInfo[2].ChannelIndex[1];
+ break;
+ case MODE_1_2_2_2_1: /* 7.1 ch */
+ drcComp->channelIdx[L] = channelMapping.elInfo[1].ChannelIndex[0];
+ drcComp->channelIdx[R] = channelMapping.elInfo[1].ChannelIndex[1];
+ drcComp->channelIdx[C] = channelMapping.elInfo[0].ChannelIndex[0];
+ drcComp->channelIdx[LFE] = channelMapping.elInfo[4].ChannelIndex[0];
+ drcComp->channelIdx[LS] = channelMapping.elInfo[2].ChannelIndex[0];
+ drcComp->channelIdx[RS] = channelMapping.elInfo[2].ChannelIndex[1];
+ drcComp->channelIdx[LS2] = channelMapping.elInfo[3].ChannelIndex[0];
+ drcComp->channelIdx[RS2] = channelMapping.elInfo[3].ChannelIndex[1];
+ break;
+ case MODE_1_1:
+ case MODE_1_1_1_1:
+ case MODE_1_1_1_1_1_1:
+ case MODE_1_1_1_1_1_1_1_1:
+ case MODE_1_1_1_1_1_1_1_1_1_1_1_1:
+ case MODE_2_2:
+ case MODE_2_2_2:
+ case MODE_2_2_2_2:
+ case MODE_2_2_2_2_2_2:
+ default:
+ return (-1);
+ }
+
+ drcComp->fullChannels = channelMapping.nChannelsEff;
+ drcComp->channels = channelMapping.nChannels;
+
+ /* Init states. */
+ drcComp->smoothLevel[0] = drcComp->smoothLevel[1] = (FIXP_DBL)(-135<<METADATA_FRACT_BITS);
+
+ FDKmemclear(drcComp->smoothGain, sizeof(drcComp->smoothGain));
+ FDKmemclear(drcComp->holdCnt, sizeof(drcComp->holdCnt));
+ FDKmemclear(drcComp->limGain, sizeof(drcComp->limGain));
+ FDKmemclear(drcComp->prevPeak, sizeof(drcComp->prevPeak));
+ FDKmemclear(drcComp->filter, sizeof(drcComp->filter));
+
+ return (0);
+}
+
+
+INT FDK_DRC_Generator_setDrcProfile(
+ HDRC_COMP drcComp,
+ const DRC_PROFILE profileLine,
+ const DRC_PROFILE profileRF
+ )
+{
+ int profileIdx, i;
+
+ drcComp->profile[0] = profileLine;
+ drcComp->profile[1] = profileRF;
+
+ for (i = 0; i < 2; i++) {
+ /* get profile index */
+ switch (drcComp->profile[i]) {
+ case DRC_NONE:
+ case DRC_FILMSTANDARD: profileIdx = 0; break;
+ case DRC_FILMLIGHT: profileIdx = 1; break;
+ case DRC_MUSICSTANDARD: profileIdx = 2; break;
+ case DRC_MUSICLIGHT: profileIdx = 3; break;
+ case DRC_SPEECH: profileIdx = 4; break;
+ case DRC_DELAY_TEST: profileIdx = 5; break;
+ default: return (-1);
+ }
+
+ /* get parameters for selected profile */
+ if (profileIdx >= 0) {
+ drcComp->maxBoostThr[i] = tabMaxBoostThr[profileIdx];
+ drcComp->boostThr[i] = tabBoostThr[profileIdx];
+ drcComp->earlyCutThr[i] = tabEarlyCutThr[profileIdx];
+ drcComp->cutThr[i] = tabCutThr[profileIdx];
+ drcComp->maxCutThr[i] = tabMaxCutThr[profileIdx];
+
+ drcComp->boostFac[i] = tabBoostRatio[profileIdx];
+ drcComp->earlyCutFac[i] = tabEarlyCutRatio[profileIdx];
+ drcComp->cutFac[i] = tabCutRatio[profileIdx];
+
+ drcComp->maxBoost[i] = tabMaxBoost[profileIdx];
+ drcComp->maxCut[i] = tabMaxCut[profileIdx];
+ drcComp->maxEarlyCut[i] = - fMult((drcComp->cutThr[i] - drcComp->earlyCutThr[i]), drcComp->earlyCutFac[i]); /* no scaling after mult needed, earlyCutFac is in FIXP_DBL */
+
+ drcComp->fastAttack[i] = tc2Coeff(tabFastAttack[profileIdx], drcComp->sampleRate, drcComp->blockLength);
+ drcComp->fastDecay[i] = tc2Coeff(tabFastDecay[profileIdx], drcComp->sampleRate, drcComp->blockLength);
+ drcComp->slowAttack[i] = tc2Coeff(tabSlowAttack[profileIdx], drcComp->sampleRate, drcComp->blockLength);
+ drcComp->slowDecay[i] = tc2Coeff(tabSlowDecay[profileIdx], drcComp->sampleRate, drcComp->blockLength);
+ drcComp->holdOff[i] = tabHoldOff[profileIdx] * 256 / drcComp->blockLength;
+
+ drcComp->attackThr[i] = tabAttackThr[profileIdx];
+ drcComp->decayThr[i] = tabDecayThr[profileIdx];
+ }
+
+ drcComp->smoothGain[i] = FL2FXCONST_DBL(0.f);
+ }
+ return (0);
+}
+
+
+INT FDK_DRC_Generator_Calc(
+ HDRC_COMP drcComp,
+ const INT_PCM * const inSamples,
+ const INT dialnorm,
+ const INT drc_TargetRefLevel,
+ const INT comp_TargetRefLevel,
+ FIXP_DBL clev,
+ FIXP_DBL slev,
+ INT * const pDynrng,
+ INT * const pCompr
+ )
+{
+ int i, c;
+ FIXP_DBL peak[2];
+
+
+ /**************************************************************************
+ * compressor
+ **************************************************************************/
+ if ((drcComp->profile[0] != DRC_NONE) || (drcComp->profile[1] != DRC_NONE)) {
+ /* Calc loudness level */
+ FIXP_DBL level_b = FL2FXCONST_DBL(0.f);
+ int level_e = DFRACT_BITS-1;
+
+ /* Increase energy time resolution with shorter processing blocks. 32 is an empiric value. */
+ const int granuleLength = fixMin(32, drcComp->blockLength);
+
+ if (drcComp->useWeighting) {
+ FIXP_DBL x1, x2, y, y1, y2;
+ /* sum of filter coefficients about 2.5 -> squared value is 6.25
+ WEIGHTING_FILTER_SHIFT is 2 -> scaling about 16, therefore reduce granuleShift by 1.
+ */
+ const int granuleShift = getShiftFactor(granuleLength)-1;
+
+ for (c = 0; c < (int)drcComp->channels; c++) {
+ const INT_PCM* pSamples = &inSamples[c];
+
+ if (c == drcComp->channelIdx[LFE]) {
+ continue; /* skip LFE */
+ }
+
+ /* get filter states */
+ x1 = drcComp->filter[c].x1;
+ x2 = drcComp->filter[c].x2;
+ y1 = drcComp->filter[c].y1;
+ y2 = drcComp->filter[c].y2;
+
+ i = 0;
+
+ do {
+
+ int offset = i;
+ FIXP_DBL accu = FL2FXCONST_DBL(0.f);
+
+ for (i=offset; i < fixMin(offset+granuleLength,drcComp->blockLength); i++) {
+ /* apply weighting filter */
+ FIXP_DBL x = FX_PCM2FX_DBL((FIXP_PCM)pSamples[i*drcComp->channels]) >> WEIGHTING_FILTER_SHIFT;
+
+ /* y = b0 * (x - x2) - a1 * y1 - a2 * y2; */
+ y = fMult(b0,x-x2) - fMult(a1,y1) - fMult(a2,y2);
+
+ x2 = x1;
+ x1 = x;
+ y2 = y1;
+ y1 = y;
+
+ accu += fPow2Div2(y)>>(granuleShift-1); /* partial energy */
+ } /* i */
+
+ fixpAdd(accu, granuleShift+2*WEIGHTING_FILTER_SHIFT, &level_b, &level_e); /* sup up partial energies */
+
+ } while ( i < drcComp->blockLength );
+
+
+ /* save filter states */
+ drcComp->filter[c].x1 = x1;
+ drcComp->filter[c].x2 = x2;
+ drcComp->filter[c].y1 = y1;
+ drcComp->filter[c].y2 = y2;
+ } /* c */
+ } /* weighting */
+ else {
+ const int granuleShift = getShiftFactor(granuleLength);
+
+ for (c = 0; c < (int)drcComp->channels; c++) {
+ const INT_PCM* pSamples = &inSamples[c];
+
+ if ((int)c == drcComp->channelIdx[LFE]) {
+ continue; /* skip LFE */
+ }
+
+ i = 0;
+
+ do {
+ int offset = i;
+ FIXP_DBL accu = FL2FXCONST_DBL(0.f);
+
+ for (i=offset; i < fixMin(offset+granuleLength,drcComp->blockLength); i++) {
+ /* partial energy */
+ accu += fPow2Div2((FIXP_PCM)pSamples[i*drcComp->channels])>>(granuleShift-1);
+ } /* i */
+
+ fixpAdd(accu, granuleShift, &level_b, &level_e); /* sup up partial energies */
+
+ } while ( i < drcComp->blockLength );
+ }
+ } /* weighting */
+
+ /*
+ * Convert to dBFS, apply dialnorm
+ */
+ /* level scaling */
+
+ /* descaled level in ld64 representation */
+ FIXP_DBL ldLevel = CalcLdData(level_b) + (FIXP_DBL)((level_e-12)<<(DFRACT_BITS-1-LD_DATA_SHIFT)) - CalcLdData((FIXP_DBL)(drcComp->blockLength<<(DFRACT_BITS-1-12)));
+
+ /* if (level < 1e-10) level = 1e-10f; */
+ ldLevel = FDKmax(ldLevel, FL2FXCONST_DBL(-0.51905126482615036685473741085772f));
+
+ /* level = 10 * log(level)/log(10) + 3;
+ * = 10*log(2)/log(10) * ld(level) + 3;
+ * = 10 * 0.30102999566398119521373889472449 * ld(level) + 3
+ * = 10 * (0.30102999566398119521373889472449 * ld(level) + 0.3)
+ * = 10 * (0.30102999566398119521373889472449 * ld64(level) + 0.3/64) * 64
+ *
+ * additional scaling with METADATA_FRACT_BITS:
+ * = 10 * (0.30102999566398119521373889472449 * ld64(level) + 0.3/64) * 64 * 2^(METADATA_FRACT_BITS)
+ * = 10 * (0.30102999566398119521373889472449 * ld64(level) + 0.3/64) * 2^(METADATA_FRACT_BITS+LD_DATA_SHIFT)
+ * = 10*2^(METADATA_FRACT_BITS+LD_DATA_SHIFT) * ( 0.30102999566398119521373889472449 * ld64(level) + 0.3/64 )
+ * */
+ FIXP_DBL level = fMult((FIXP_DBL)(10<<(METADATA_FRACT_BITS+LD_DATA_SHIFT)), fMult( FL2FXCONST_DBL(0.30102999566398119521373889472449f), ldLevel) + (FIXP_DBL)(FL2FXCONST_DBL(0.3f)>>LD_DATA_SHIFT) );
+
+ /* level -= dialnorm + 31 */ /* this is fixed to Dolby-ReferenceLevel as compressor profiles are defined relative to this */
+ level -= ((FIXP_DBL)(dialnorm<<(METADATA_FRACT_BITS-16)) + (FIXP_DBL)(31<<METADATA_FRACT_BITS));
+
+ for (i = 0; i < 2; i++) {
+ if (drcComp->profile[i] == DRC_NONE) {
+ /* no compression */
+ drcComp->smoothGain[i] = FL2FXCONST_DBL(0.f);
+ }
+ else {
+ FIXP_DBL gain, alpha, lvl2smthlvl;
+
+ /* calc static gain */
+ if (level <= drcComp->maxBoostThr[i]) {
+ /* max boost */
+ gain = drcComp->maxBoost[i];
+ }
+ else if (level < drcComp->boostThr[i]) {
+ /* boost range */
+ gain = fMult((level - drcComp->boostThr[i]),drcComp->boostFac[i]);
+ }
+ else if (level <= drcComp->earlyCutThr[i]) {
+ /* null band */
+ gain = FL2FXCONST_DBL(0.f);
+ }
+ else if (level <= drcComp->cutThr[i]) {
+ /* early cut range */
+ gain = fMult((level - drcComp->earlyCutThr[i]), drcComp->earlyCutFac[i]);
+ }
+ else if (level < drcComp->maxCutThr[i]) {
+ /* cut range */
+ gain = fMult((level - drcComp->cutThr[i]), drcComp->cutFac[i]) - drcComp->maxEarlyCut[i];
+ }
+ else {
+ /* max cut */
+ gain = -drcComp->maxCut[i];
+ }
+
+ /* choose time constant */
+ lvl2smthlvl = level - drcComp->smoothLevel[i];
+ if (gain < drcComp->smoothGain[i]) {
+ /* attack */
+ if (lvl2smthlvl > drcComp->attackThr[i]) {
+ /* fast attack */
+ alpha = drcComp->fastAttack[i];
+ }
+ else {
+ /* slow attack */
+ alpha = drcComp->slowAttack[i];
+ }
+ }
+ else {
+ /* release */
+ if (lvl2smthlvl < -drcComp->decayThr[i]) {
+ /* fast release */
+ alpha = drcComp->fastDecay[i];
+ }
+ else {
+ /* slow release */
+ alpha = drcComp->slowDecay[i];
+ }
+ }
+
+ /* smooth gain & level */
+ if ((gain < drcComp->smoothGain[i]) || (drcComp->holdCnt[i] == 0)) { /* hold gain unless we have an attack or hold period is over */
+ FIXP_DBL accu;
+
+ /* drcComp->smoothLevel[i] = (1-alpha) * drcComp->smoothLevel[i] + alpha * level; */
+ accu = fMult((FL2FXCONST_DBL(1.f)-alpha), drcComp->smoothLevel[i]);
+ accu += fMult(alpha,level);
+ drcComp->smoothLevel[i] = accu;
+
+ /* drcComp->smoothGain[i] = (1-alpha) * drcComp->smoothGain[i] + alpha * gain; */
+ accu = fMult((FL2FXCONST_DBL(1.f)-alpha), drcComp->smoothGain[i]);
+ accu += fMult(alpha,gain);
+ drcComp->smoothGain[i] = accu;
+ }
+
+ /* hold counter */
+ if (drcComp->holdCnt[i]) {
+ drcComp->holdCnt[i]--;
+ }
+ if (gain < drcComp->smoothGain[i]) {
+ drcComp->holdCnt[i] = drcComp->holdOff[i];
+ }
+ } /* profile != DRC_NONE */
+ } /* for i=1..2 */
+ } else {
+ /* no compression */
+ drcComp->smoothGain[0] = FL2FXCONST_DBL(0.f);
+ drcComp->smoothGain[1] = FL2FXCONST_DBL(0.f);
+ }
+
+ /**************************************************************************
+ * limiter
+ **************************************************************************/
+
+ /* find peak level */
+ peak[0] = peak[1] = FL2FXCONST_DBL(0.f);
+ for (i = 0; i < drcComp->blockLength; i++) {
+ FIXP_DBL tmp;
+ const INT_PCM* pSamples = &inSamples[i*drcComp->channels];
+ INT_PCM maxSample = 0;
+
+ /* single channels */
+ for (c = 0; c < (int)drcComp->channels; c++) {
+ maxSample = FDKmax(maxSample, fAbs(pSamples[c]));
+ }
+ peak[0] = fixMax(peak[0], FX_PCM2FX_DBL(maxSample)>>DOWNMIX_SHIFT);
+
+ /* Lt/Rt downmix */
+ if (drcComp->fullChannels > 2) {
+ /* Lt */
+ tmp = FL2FXCONST_DBL(0.f);
+
+ if (drcComp->channelIdx[LS] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */
+ if (drcComp->channelIdx[LS2] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */
+ if (drcComp->channelIdx[RS] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */
+ if (drcComp->channelIdx[RS2] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */
+ if ((drcComp->channelIdx[LS] >= 0) && (drcComp->channelIdx[LS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */
+ if (drcComp->channelIdx[S] >= 0) tmp -= fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]])>>(DOWNMIX_SHIFT-1); /* S */
+ if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */
+ tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[L]])>>DOWNMIX_SHIFT); /* L */
+
+ peak[0] = fixMax(peak[0], fixp_abs(tmp));
+
+ /* Rt */
+ tmp = FL2FXCONST_DBL(0.f);
+ if (drcComp->channelIdx[LS] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */
+ if (drcComp->channelIdx[LS2] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */
+ if (drcComp->channelIdx[RS] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */
+ if (drcComp->channelIdx[RS2] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */
+ if ((drcComp->channelIdx[RS] >= 0) && (drcComp->channelIdx[RS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */
+ if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]])>>(DOWNMIX_SHIFT-1); /* S */
+ if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(FL2FXCONST_DBL(0.707f), (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */
+ tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[R]])>>DOWNMIX_SHIFT); /* R */
+
+ peak[0] = fixMax(peak[0], fixp_abs(tmp));
+ }
+
+ /* Lo/Ro downmix */
+ if (drcComp->fullChannels > 2) {
+ /* Lo */
+ tmp = FL2FXCONST_DBL(0.f);
+ if (drcComp->channelIdx[LS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */
+ if (drcComp->channelIdx[LS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */
+ if ((drcComp->channelIdx[LS] >= 0) && (drcComp->channelIdx[LS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */
+ if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(slev, fMult(FL2FXCONST_DBL(0.7f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]]))>>(DOWNMIX_SHIFT-1); /* S */
+ if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(clev, (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */
+ tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[L]])>>DOWNMIX_SHIFT); /* L */
+
+ peak[0] = fixMax(peak[0], fixp_abs(tmp));
+
+ /* Ro */
+ tmp = FL2FXCONST_DBL(0.f);
+ if (drcComp->channelIdx[RS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */
+ if (drcComp->channelIdx[RS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */
+ if ((drcComp->channelIdx[RS] >= 0) && (drcComp->channelIdx[RS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */
+ if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(slev, fMult(FL2FXCONST_DBL(0.7f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]]))>>(DOWNMIX_SHIFT-1); /* S */
+ if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(clev, (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */
+ tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[R]])>>DOWNMIX_SHIFT); /* R */
+
+ peak[0] = fixMax(peak[0], fixp_abs(tmp));
+ }
+
+ peak[1] = fixMax(peak[0], peak[1]);
+
+ /* Mono Downmix - for comp_val only */
+ if (drcComp->fullChannels > 1) {
+ tmp = FL2FXCONST_DBL(0.f);
+ if (drcComp->channelIdx[LS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS]])>>(DOWNMIX_SHIFT-1); /* Ls */
+ if (drcComp->channelIdx[LS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[LS2]])>>(DOWNMIX_SHIFT-1); /* Ls2 */
+ if (drcComp->channelIdx[RS] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS]])>>(DOWNMIX_SHIFT-1); /* Rs */
+ if (drcComp->channelIdx[RS2] >= 0) tmp += fMultDiv2(slev, (FIXP_PCM)pSamples[drcComp->channelIdx[RS2]])>>(DOWNMIX_SHIFT-1); /* Rs2 */
+ if ((drcComp->channelIdx[LS] >= 0) && (drcComp->channelIdx[LS2] >= 0)) tmp = fMult(FL2FXCONST_DBL(0.707f), tmp); /* 7.1ch */
+ /*if ((drcComp->channelIdx[RS] >= 0) && (drcComp->channelIdx[RS2] >= 0)) tmp *=0.707f;*/ /* 7.1ch */
+ if (drcComp->channelIdx[S] >= 0) tmp += fMultDiv2(slev, fMult(FL2FXCONST_DBL(0.7f), (FIXP_PCM)pSamples[drcComp->channelIdx[S]]))>>(DOWNMIX_SHIFT-1); /* S */
+ if (drcComp->channelIdx[C] >= 0) tmp += fMultDiv2(clev, (FIXP_PCM)pSamples[drcComp->channelIdx[C]])>>(DOWNMIX_SHIFT-1); /* C */
+ tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[L]])>>DOWNMIX_SHIFT); /* L */
+ tmp += (FX_PCM2FX_DBL((FIXP_PCM)pSamples[drcComp->channelIdx[R]])>>DOWNMIX_SHIFT); /* R */
+
+ peak[1] = fixMax(peak[1], fixp_abs(tmp));
+ }
+ }
+
+ for (i=0; i<2; i++) {
+ FIXP_DBL tmp = drcComp->prevPeak[i];
+ drcComp->prevPeak[i] = peak[i];
+ peak[i] = fixMax(peak[i], tmp);
+
+ /*
+ * Convert to dBFS, apply dialnorm
+ */
+ /* descaled peak in ld64 representation */
+ FIXP_DBL ld_peak = CalcLdData(peak[i]) + (FIXP_DBL)((LONG)DOWNMIX_SHIFT<<(DFRACT_BITS-1-LD_DATA_SHIFT));
+
+ /* if (peak < 1e-6) level = 1e-6f; */
+ ld_peak = FDKmax(ld_peak, FL2FXCONST_DBL(-0.31143075889569022011284244651463f));
+
+ /* peak[i] = 20 * log(peak[i])/log(10) + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS)
+ * peak[i] = 20 * log(2)/log(10) * ld(peak[i]) + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS)
+ * peak[i] = 10 * 2*0.30102999566398119521373889472449 * ld(peak[i]) + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS)
+ *
+ * additional scaling with METADATA_FRACT_BITS:
+ * peak[i] = (10 * 2*0.30102999566398119521373889472449 * ld64(peak[i]) * 64 + 0.2f + (drcComp->smoothGain[i]*2^METADATA_FRACT_BITS))*2^(-METADATA_FRACT_BITS)
+ * peak[i] = 10*2^(METADATA_FRACT_BITS+LD_DATA_SHIFT) * 2*0.30102999566398119521373889472449 * ld64(peak[i])
+ * + 0.2f*2^(-METADATA_FRACT_BITS) + drcComp->smoothGain[i]
+ */
+ peak[i] = fMult((FIXP_DBL)(10<<(METADATA_FRACT_BITS+LD_DATA_SHIFT)), fMult( FL2FX_DBL(2*0.30102999566398119521373889472449f), ld_peak));
+ peak[i] += (FL2FX_DBL(0.2f)>>METADATA_INT_BITS); /* add a little bit headroom */
+ peak[i] += drcComp->smoothGain[i];
+ }
+
+ /* peak -= dialnorm + 31; */ /* this is Dolby style only */
+ peak[0] -= (FIXP_DBL)((dialnorm-drc_TargetRefLevel)<<(METADATA_FRACT_BITS-16)); /* peak[0] -= dialnorm - drc_TargetRefLevel */
+
+ /* peak += 11; */ /* this is Dolby style only */ /* RF mode output is 11dB higher */
+ /*peak += comp_TargetRefLevel - drc_TargetRefLevel;*/
+ peak[1] -= (FIXP_DBL)((dialnorm-comp_TargetRefLevel)<<(METADATA_FRACT_BITS-16)); /* peak[1] -= dialnorm - comp_TargetRefLevel */
+
+ /* limiter gain */
+ drcComp->limGain[0] += drcComp->limDecay; /* linear limiter release */
+ drcComp->limGain[0] = fixMin(drcComp->limGain[0], -peak[0]);
+
+ drcComp->limGain[1] += 2*drcComp->limDecay; /* linear limiter release */
+ drcComp->limGain[1] = fixMin(drcComp->limGain[1], -peak[1]);
+
+ /*************************************************************************/
+
+ /* apply limiting, return DRC gains*/
+ {
+ FIXP_DBL tmp;
+
+ tmp = drcComp->smoothGain[0];
+ if (drcComp->limGain[0] < FL2FXCONST_DBL(0.f)) {
+ tmp += drcComp->limGain[0];
+ }
+ *pDynrng = (LONG) scaleValue(tmp, -(METADATA_FRACT_BITS-16));
+
+ tmp = drcComp->smoothGain[1];
+ if (drcComp->limGain[1] < FL2FXCONST_DBL(0.f)) {
+ tmp += drcComp->limGain[1];
+ }
+ *pCompr = (LONG) scaleValue(tmp, -(METADATA_FRACT_BITS-16));
+ }
+
+ return 0;
+}
+
+
+DRC_PROFILE FDK_DRC_Generator_getDrcProfile(const HDRC_COMP drcComp)
+{
+ return drcComp->profile[0];
+}
+
+DRC_PROFILE FDK_DRC_Generator_getCompProfile(const HDRC_COMP drcComp)
+{
+ return drcComp->profile[1];
+}
+
+
diff --git a/libAACenc/src/metadata_compressor.h b/libAACenc/src/metadata_compressor.h
new file mode 100644
index 0000000..1d53f81
--- /dev/null
+++ b/libAACenc/src/metadata_compressor.h
@@ -0,0 +1,190 @@
+/********************** Fraunhofer IIS FDK AAC Encoder lib ******************
+
+ (C) Copyright Fraunhofer IIS (2011)
+ 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): M. Neusinger
+ Description: Compressor for AAC Metadata Generator
+
+ 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 _METADATA_COMPRESSOR_H
+#define _METADATA_COMPRESSOR_H
+
+
+#include "FDK_audio.h"
+#include "common_fix.h"
+
+#include "aacenc.h"
+
+
+/**
+ * DRC compression profiles.
+ */
+typedef enum DRC_PROFILE {
+ DRC_NONE = 0,
+ DRC_FILMSTANDARD = 1,
+ DRC_FILMLIGHT = 2,
+ DRC_MUSICSTANDARD = 3,
+ DRC_MUSICLIGHT = 4,
+ DRC_SPEECH = 5,
+ DRC_DELAY_TEST = 6
+
+} DRC_PROFILE;
+
+
+/**
+ * DRC Compressor handle.
+ */
+typedef struct DRC_COMP DRC_COMP, *HDRC_COMP;
+
+/**
+ * \brief Open a DRC Compressor instance.
+ *
+ * Allocate memory for a compressor instance.
+ *
+ * \param phDrcComp A pointer to a compressor handle. Initialized on return.
+ *
+ * \return
+ * - 0, on succes.
+ * - unequal 0, on failure.
+ */
+INT FDK_DRC_Generator_Open(
+ HDRC_COMP *phDrcComp
+ );
+
+
+/**
+ * \brief Close the DRC Compressor instance.
+ *
+ * Deallocate instance and free whole memory.
+ *
+ * \param phDrcComp Pointer to the compressor handle to be deallocated.
+ *
+ * \return
+ * - 0, on succes.
+ * - unequal 0, on failure.
+ */
+INT FDK_DRC_Generator_Close(
+ HDRC_COMP *phDrcComp
+ );
+
+/**
+ * \brief Configure DRC Compressor.
+ *
+ * \param drcComp Compressor handle.
+ * \param profileLine DRC profile for line mode.
+ * \param profileRF DRC profile for RF mode.
+ * \param blockLength Length of processing block in samples per channel.
+ * \param sampleRate Sampling rate in Hz.
+ * \param channelMode Channel configuration.
+ * \param channelOrder Channel order, MPEG or WAV.
+ * \param useWeighting Use weighting filter for loudness calculation
+ *
+ * \return
+ * - 0, on success,
+ * - unequal 0, on failure
+ */
+INT FDK_DRC_Generator_Initialize(
+ HDRC_COMP drcComp,
+ const DRC_PROFILE profileLine,
+ const DRC_PROFILE profileRF,
+ const INT blockLength,
+ const UINT sampleRate,
+ const CHANNEL_MODE channelMode,
+ const CHANNEL_ORDER channelOrder,
+ const UCHAR useWeighting
+ );
+
+/**
+ * \brief Calculate DRC Compressor Gain.
+ *
+ * \param drcComp Compressor handle.
+ * \param inSamples Pointer to interleaved input audio samples.
+ * \param dialnorm Dialog Level in dB (typically -31...-1).
+ * \param drc_TargetRefLevel
+ * \param comp_TargetRefLevel
+ * \param clev Downmix center mix factor (typically 0.707, 0.595 or 0.5)
+ * \param slev Downmix surround mix factor (typically 0.707, 0.5, or 0)
+ * \param dynrng Pointer to variable receiving line mode DRC gain in dB
+ * \param compr Pointer to variable receiving RF mode DRC gain in dB
+ *
+ * \return
+ * - 0, on success,
+ * - unequal 0, on failure
+ */
+INT FDK_DRC_Generator_Calc(
+ HDRC_COMP drcComp,
+ const INT_PCM * const inSamples,
+ const INT dialnorm,
+ const INT drc_TargetRefLevel,
+ const INT comp_TargetRefLevel,
+ FIXP_DBL clev,
+ FIXP_DBL slev,
+ INT * const dynrng,
+ INT * const compr
+ );
+
+
+/**
+ * \brief Configure DRC Compressor Profile.
+ *
+ * \param drcComp Compressor handle.
+ * \param profileLine DRC profile for line mode.
+ * \param profileRF DRC profile for RF mode.
+ *
+ * \return
+ * - 0, on success,
+ * - unequal 0, on failure
+ */
+INT FDK_DRC_Generator_setDrcProfile(
+ HDRC_COMP drcComp,
+ const DRC_PROFILE profileLine,
+ const DRC_PROFILE profileRF
+ );
+
+
+/**
+ * \brief Get DRC profile for line mode.
+ *
+ * \param drcComp Compressor handle.
+ *
+ * \return Current Profile.
+ */
+DRC_PROFILE FDK_DRC_Generator_getDrcProfile(
+ const HDRC_COMP drcComp
+ );
+
+
+/**
+ * \brief Get DRC profile for RF mode.
+ *
+ * \param drcComp Compressor handle.
+ *
+ * \return Current Profile.
+ */
+DRC_PROFILE FDK_DRC_Generator_getCompProfile(
+ const HDRC_COMP drcComp
+ );
+
+
+#endif /* _METADATA_COMPRESSOR_H */
+
diff --git a/libAACenc/src/metadata_main.cpp b/libAACenc/src/metadata_main.cpp
new file mode 100644
index 0000000..f02ba3b
--- /dev/null
+++ b/libAACenc/src/metadata_main.cpp
@@ -0,0 +1,809 @@
+/********************** Fraunhofer IIS FDK AAC Encoder lib ******************
+
+ (C) Copyright Fraunhofer IIS (2011)
+ 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): V. Bacigalupo
+ Description: Metadata Encoder library interface functions
+
+ 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 "metadata_main.h"
+#include "metadata_compressor.h"
+#include "FDK_bitstream.h"
+#include "FDK_audio.h"
+#include "genericStds.h"
+
+/*----------------- defines ----------------------*/
+#define MAX_DRC_BANDS (1<<4)
+#define MAX_DRC_CHANNELS (8)
+#define MAX_DRC_FRAMELEN (2*1024)
+
+/*--------------- structure definitions --------------------*/
+
+typedef struct AAC_METADATA
+{
+ /* MPEG: Dynamic Range Control */
+ struct {
+ UCHAR prog_ref_level_present;
+ SCHAR prog_ref_level;
+
+ UCHAR dyn_rng_sgn[MAX_DRC_BANDS];
+ UCHAR dyn_rng_ctl[MAX_DRC_BANDS];
+
+ UCHAR drc_bands_present;
+ UCHAR drc_band_incr;
+ UCHAR drc_band_top[MAX_DRC_BANDS];
+ UCHAR drc_interpolation_scheme;
+ AACENC_METADATA_DRC_PROFILE drc_profile;
+ INT drc_TargetRefLevel; /* used for Limiter */
+
+ /* excluded channels */
+ UCHAR excluded_chns_present;
+ UCHAR exclude_mask[2]; /* MAX_NUMBER_CHANNELS/8 */
+ } mpegDrc;
+
+ /* ETSI: addtl ancillary data */
+ struct {
+ /* Heavy Compression */
+ UCHAR compression_on; /* flag, if compression value should be written */
+ UCHAR compression_value; /* compression value */
+ AACENC_METADATA_DRC_PROFILE comp_profile;
+ INT comp_TargetRefLevel; /* used for Limiter */
+ INT timecode_coarse_status;
+ INT timecode_fine_status;
+ } etsiAncData;
+
+ SCHAR centerMixLevel; /* center downmix level (0...7, according to table) */
+ SCHAR surroundMixLevel; /* surround downmix level (0...7, according to table) */
+ UCHAR WritePCEMixDwnIdx; /* flag */
+ UCHAR DmxLvl_On; /* flag */
+
+ UCHAR dolbySurroundMode;
+
+ UCHAR metadataMode; /* indicate meta data mode in current frame (delay line) */
+
+} AAC_METADATA;
+
+struct FDK_METADATA_ENCODER
+{
+ INT metadataMode;
+ HDRC_COMP hDrcComp;
+ AACENC_MetaData submittedMetaData;
+
+ INT nAudioDataDelay;
+ INT nMetaDataDelay;
+ INT nChannels;
+
+ INT_PCM audioDelayBuffer[MAX_DRC_CHANNELS*MAX_DRC_FRAMELEN];
+ int audioDelayIdx;
+
+ AAC_METADATA metaDataBuffer[3];
+ int metaDataDelayIdx;
+
+ UCHAR drcInfoPayload[12];
+ UCHAR drcDsePayload[8];
+
+ INT matrix_mixdown_idx;
+ AACENC_EXT_PAYLOAD exPayload[2];
+ INT nExtensions;
+
+ INT finalizeMetaData; /* Delay switch off by one frame and write default configuration to
+ finalize the metadata setup. */
+};
+
+
+/*---------------- constants -----------------------*/
+static const AACENC_MetaData defaultMetaDataSetup = {
+ AACENC_METADATA_DRC_NONE,
+ AACENC_METADATA_DRC_NONE,
+ -(31<<16),
+ -(31<<16),
+ 0,
+ -(31<<16),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+static const FIXP_DBL dmxTable[8] = {
+ ((FIXP_DBL)MAXVAL_DBL), FL2FXCONST_DBL(0.841f), FL2FXCONST_DBL(0.707f), FL2FXCONST_DBL(0.596f),
+ FL2FXCONST_DBL(0.500f), FL2FXCONST_DBL(0.422f), FL2FXCONST_DBL(0.355f), FL2FXCONST_DBL(0.000f)
+};
+
+static const UCHAR surmix2matrix_mixdown_idx[8] = {
+ 0, 0, 0, 1, 1, 2, 2, 3
+};
+
+
+/*--------------- function declarations --------------------*/
+static FDK_METADATA_ERROR WriteMetadataPayload(
+ const HANDLE_FDK_METADATA_ENCODER hMetaData,
+ const AAC_METADATA * const pMetadata
+ );
+
+static INT WriteDynamicRangeInfoPayload(
+ const AAC_METADATA* const pMetadata,
+ UCHAR* const pExtensionPayload
+ );
+
+static INT WriteEtsiAncillaryDataPayload(
+ const AAC_METADATA* const pMetadata,
+ UCHAR* const pExtensionPayload
+ );
+
+static FDK_METADATA_ERROR CompensateAudioDelay(
+ HANDLE_FDK_METADATA_ENCODER hMetaDataEnc,
+ INT_PCM * const pAudioSamples,
+ const INT nAudioSamples
+ );
+
+static FDK_METADATA_ERROR LoadSubmittedMetadata(
+ const AACENC_MetaData * const hMetadata,
+ const INT nChannels,
+ const INT metadataMode,
+ AAC_METADATA * const pAacMetaData
+ );
+
+static FDK_METADATA_ERROR ProcessCompressor(
+ AAC_METADATA *pMetadata,
+ HDRC_COMP hDrcComp,
+ const INT_PCM * const pSamples,
+ const INT nSamples
+ );
+
+/*------------- function definitions ----------------*/
+
+static DRC_PROFILE convertProfile(AACENC_METADATA_DRC_PROFILE aacProfile)
+{
+ DRC_PROFILE drcProfile = DRC_NONE;
+
+ switch(aacProfile) {
+ case AACENC_METADATA_DRC_NONE: drcProfile = DRC_NONE; break;
+ case AACENC_METADATA_DRC_FILMSTANDARD: drcProfile = DRC_FILMSTANDARD; break;
+ case AACENC_METADATA_DRC_FILMLIGHT: drcProfile = DRC_FILMLIGHT; break;
+ case AACENC_METADATA_DRC_MUSICSTANDARD: drcProfile = DRC_MUSICSTANDARD; break;
+ case AACENC_METADATA_DRC_MUSICLIGHT: drcProfile = DRC_MUSICLIGHT; break;
+ case AACENC_METADATA_DRC_SPEECH: drcProfile = DRC_SPEECH; break;
+ default: drcProfile = DRC_NONE; break;
+ }
+ return drcProfile;
+}
+
+
+/* convert dialog normalization to program reference level */
+/* NOTE: this only is correct, if the decoder target level is set to -31dB for line mode / -20dB for RF mode */
+static UCHAR dialnorm2progreflvl(const INT d)
+{
+ return ((UCHAR)FDKmax(0, FDKmin((-d + (1<<13)) >> 14, 127)));
+}
+
+/* convert program reference level to dialog normalization */
+static INT progreflvl2dialnorm(const UCHAR p)
+{
+ return -((INT)(p<<(16-2)));
+}
+
+/* encode downmix levels to Downmixing_levels_MPEG4 */
+static SCHAR encodeDmxLvls(const SCHAR cmixlev, const SCHAR surmixlev)
+{
+ SCHAR dmxLvls = 0;
+ dmxLvls |= 0x80 | (cmixlev << 4); /* center_mix_level_on */
+ dmxLvls |= 0x08 | surmixlev; /* surround_mix_level_on */
+
+ return dmxLvls;
+}
+
+/* encode AAC DRC gain (ISO/IEC 14496-3:2005 4.5.2.7) */
+static void encodeDynrng(INT gain, UCHAR* const dyn_rng_ctl, UCHAR* const dyn_rng_sgn )
+{
+ if(gain < 0)
+ {
+ *dyn_rng_sgn = 1;
+ gain = -gain;
+ }
+ else
+ {
+ *dyn_rng_sgn = 0;
+ }
+ gain = FDKmin(gain,(127<<14));
+
+ *dyn_rng_ctl = (UCHAR)((gain + (1<<13)) >> 14);
+}
+
+/* decode AAC DRC gain (ISO/IEC 14496-3:2005 4.5.2.7) */
+static INT decodeDynrng(const UCHAR dyn_rng_ctl, const UCHAR dyn_rng_sgn)
+{
+ INT tmp = ((INT)dyn_rng_ctl << (16-2));
+ if (dyn_rng_sgn) tmp = -tmp;
+
+ return tmp;
+}
+
+/* encode AAC compression value (ETSI TS 101 154 page 99) */
+static UCHAR encodeCompr(INT gain)
+{
+ UCHAR x, y;
+ INT tmp;
+
+ /* tmp = (int)((48.164f - gain) / 6.0206f * 15 + 0.5f); */
+ tmp = ((3156476 - gain) * 15 + 197283) / 394566;
+
+ if (tmp >= 240) {
+ return 0xFF;
+ }
+ else if (tmp < 0) {
+ return 0;
+ }
+ else {
+ x = tmp / 15;
+ y = tmp % 15;
+ }
+
+ return (x << 4) | y;
+}
+
+/* decode AAC compression value (ETSI TS 101 154 page 99) */
+static INT decodeCompr(const UCHAR compr)
+{
+ INT gain;
+ SCHAR x = compr >> 4; /* 4 MSB of compr */
+ UCHAR y = (compr & 0x0F); /* 4 LSB of compr */
+
+ /* gain = (INT)((48.164f - 6.0206f * x - 0.4014f * y) ); */
+ gain = (INT)( scaleValue(((LONG)FL2FXCONST_DBL(6.0206f/128.f)*(8-x) - (LONG)FL2FXCONST_DBL(0.4014f/128.f)*y), -(DFRACT_BITS-1-7-16)) );
+
+ return gain;
+}
+
+
+FDK_METADATA_ERROR FDK_MetadataEnc_Open(
+ HANDLE_FDK_METADATA_ENCODER *phMetaData
+ )
+{
+ FDK_METADATA_ERROR err = METADATA_OK;
+ HANDLE_FDK_METADATA_ENCODER hMetaData = NULL;
+
+ if (phMetaData == NULL) {
+ err = METADATA_INVALID_HANDLE;
+ goto bail;
+ }
+
+ /* allocate memory */
+ hMetaData = (HANDLE_FDK_METADATA_ENCODER) FDKcalloc(1, sizeof(FDK_METADATA_ENCODER) );
+
+ if (hMetaData == NULL) {
+ err = METADATA_MEMORY_ERROR;
+ goto bail;
+ }
+
+ FDKmemclear(hMetaData, sizeof(FDK_METADATA_ENCODER));
+
+ /* Allocate DRC Compressor. */
+ if (FDK_DRC_Generator_Open(&hMetaData->hDrcComp)!=0) {
+ err = METADATA_MEMORY_ERROR;
+ goto bail;
+ }
+
+ /* Return metadata instance */
+ *phMetaData = hMetaData;
+
+ return err;
+
+bail:
+ FDK_MetadataEnc_Close(&hMetaData);
+ return err;
+}
+
+FDK_METADATA_ERROR FDK_MetadataEnc_Close(
+ HANDLE_FDK_METADATA_ENCODER *phMetaData
+ )
+{
+ FDK_METADATA_ERROR err = METADATA_OK;
+
+ if (phMetaData == NULL) {
+ err = METADATA_INVALID_HANDLE;
+ goto bail;
+ }
+
+ if (*phMetaData != NULL) {
+ FDK_DRC_Generator_Close(&(*phMetaData)->hDrcComp);
+ FDKfree(*phMetaData);
+ *phMetaData = NULL;
+ }
+bail:
+ return err;
+}
+
+FDK_METADATA_ERROR FDK_MetadataEnc_Init(
+ HANDLE_FDK_METADATA_ENCODER hMetaData,
+ const INT resetStates,
+ const INT metadataMode,
+ const INT audioDelay,
+ const UINT frameLength,
+ const UINT sampleRate,
+ const UINT nChannels,
+ const CHANNEL_MODE channelMode,
+ const CHANNEL_ORDER channelOrder
+ )
+{
+ FDK_METADATA_ERROR err = METADATA_OK;
+ int i, nFrames, delay;
+
+ if (hMetaData==NULL) {
+ err = METADATA_INVALID_HANDLE;
+ goto bail;
+ }
+
+ /* Determine values for delay compensation. */
+ for (nFrames=0, delay=audioDelay-frameLength; delay>0; delay-=frameLength, nFrames++);
+
+ if ( (hMetaData->nChannels>MAX_DRC_CHANNELS) || ((-delay)>MAX_DRC_FRAMELEN) ) {
+ err = METADATA_INIT_ERROR;
+ goto bail;
+ }
+
+ /* Initialize with default setup. */
+ FDKmemcpy(&hMetaData->submittedMetaData, &defaultMetaDataSetup, sizeof(AACENC_MetaData));
+
+ hMetaData->finalizeMetaData = 0; /* finalize meta data only while on/off switching, else disabled */
+
+ /* Reset delay lines. */
+ if ( resetStates || (hMetaData->nAudioDataDelay!=-delay) || (hMetaData->nChannels!=(INT)nChannels) )
+ {
+ FDKmemclear(hMetaData->audioDelayBuffer, sizeof(hMetaData->audioDelayBuffer));
+ FDKmemclear(hMetaData->metaDataBuffer, sizeof(hMetaData->metaDataBuffer));
+ hMetaData->audioDelayIdx = 0;
+ hMetaData->metaDataDelayIdx = 0;
+ }
+ else {
+ /* Enable meta data. */
+ if ( (hMetaData->metadataMode==0) && (metadataMode!=0) ) {
+ /* disable meta data in all delay lines */
+ for (i=0; i<(int)(sizeof(hMetaData->metaDataBuffer)/sizeof(AAC_METADATA)); i++) {
+ LoadSubmittedMetadata(&hMetaData->submittedMetaData, nChannels, 0, &hMetaData->metaDataBuffer[i]);
+ }
+ }
+
+ /* Disable meta data.*/
+ if ( (hMetaData->metadataMode!=0) && (metadataMode==0) ) {
+ hMetaData->finalizeMetaData = hMetaData->metadataMode;
+ }
+ }
+
+ /* Initialize delay. */
+ hMetaData->nAudioDataDelay = -delay;
+ hMetaData->nMetaDataDelay = nFrames;
+ hMetaData->nChannels = nChannels;
+ hMetaData->metadataMode = metadataMode;
+
+ /* Initialize compressor. */
+ if (metadataMode != 0) {
+ if ( FDK_DRC_Generator_Initialize(
+ hMetaData->hDrcComp,
+ DRC_NONE,
+ DRC_NONE,
+ frameLength,
+ sampleRate,
+ channelMode,
+ channelOrder,
+ 1) != 0)
+ {
+ err = METADATA_INIT_ERROR;
+ }
+ }
+bail:
+ return err;
+}
+
+static FDK_METADATA_ERROR ProcessCompressor(
+ AAC_METADATA *pMetadata,
+ HDRC_COMP hDrcComp,
+ const INT_PCM * const pSamples,
+ const INT nSamples
+ )
+{
+ FDK_METADATA_ERROR err = METADATA_OK;
+
+ INT dynrng, compr;
+ DRC_PROFILE profileDrc = convertProfile(pMetadata->mpegDrc.drc_profile);
+ DRC_PROFILE profileComp = convertProfile(pMetadata->etsiAncData.comp_profile);
+
+ if ( (pMetadata==NULL) || (hDrcComp==NULL) ) {
+ err = METADATA_INVALID_HANDLE;
+ return err;
+ }
+
+ /* first, check if profile is same as last frame
+ * otherwise, update setup */
+ if ( (profileDrc != FDK_DRC_Generator_getDrcProfile(hDrcComp))
+ || (profileComp != FDK_DRC_Generator_getCompProfile(hDrcComp)) )
+ {
+ FDK_DRC_Generator_setDrcProfile(hDrcComp, profileDrc, profileComp);
+ }
+
+ /* Sanity check */
+ if (profileComp == DRC_NONE) {
+ pMetadata->etsiAncData.compression_value = 0x80; /* to ensure no external values will be written if not configured */
+ }
+
+ /* in case of embedding external values, copy this now (limiter may overwrite them) */
+ dynrng = decodeDynrng(pMetadata->mpegDrc.dyn_rng_ctl[0], pMetadata->mpegDrc.dyn_rng_sgn[0]);
+ compr = decodeCompr(pMetadata->etsiAncData.compression_value);
+
+ /* Call compressor */
+ if (FDK_DRC_Generator_Calc(hDrcComp,
+ pSamples,
+ progreflvl2dialnorm(pMetadata->mpegDrc.prog_ref_level),
+ pMetadata->mpegDrc.drc_TargetRefLevel,
+ pMetadata->etsiAncData.comp_TargetRefLevel,
+ dmxTable[pMetadata->centerMixLevel],
+ dmxTable[pMetadata->surroundMixLevel],
+ &dynrng,
+ &compr) != 0)
+ {
+ err = METADATA_ENCODE_ERROR;
+ goto bail;
+ }
+
+ /* Write DRC values */
+ pMetadata->mpegDrc.drc_band_incr = 0;
+ encodeDynrng(dynrng, pMetadata->mpegDrc.dyn_rng_ctl, pMetadata->mpegDrc.dyn_rng_sgn);
+ pMetadata->etsiAncData.compression_value = encodeCompr(compr);
+
+bail:
+ return err;
+}
+
+FDK_METADATA_ERROR FDK_MetadataEnc_Process(
+ HANDLE_FDK_METADATA_ENCODER hMetaDataEnc,
+ INT_PCM * const pAudioSamples,
+ const INT nAudioSamples,
+ const AACENC_MetaData * const pMetadata,
+ AACENC_EXT_PAYLOAD ** ppMetaDataExtPayload,
+ UINT * nMetaDataExtensions,
+ INT * matrix_mixdown_idx
+ )
+{
+ FDK_METADATA_ERROR err = METADATA_OK;
+ int metaDataDelayWriteIdx, metaDataDelayReadIdx, metadataMode;
+
+ /* Where to write new meta data info */
+ metaDataDelayWriteIdx = hMetaDataEnc->metaDataDelayIdx;
+
+ /* How to write the data */
+ metadataMode = hMetaDataEnc->metadataMode;
+
+ /* Compensate meta data delay. */
+ hMetaDataEnc->metaDataDelayIdx++;
+ if (hMetaDataEnc->metaDataDelayIdx > hMetaDataEnc->nMetaDataDelay) hMetaDataEnc->metaDataDelayIdx = 0;
+
+ /* Where to read pending meta data info from. */
+ metaDataDelayReadIdx = hMetaDataEnc->metaDataDelayIdx;
+
+ /* Submit new data if available. */
+ if (pMetadata!=NULL) {
+ FDKmemcpy(&hMetaDataEnc->submittedMetaData, pMetadata, sizeof(AACENC_MetaData));
+ }
+
+ /* Write one additional frame with default configuration of meta data. Ensure defined behaviour on decoder side. */
+ if ( (hMetaDataEnc->finalizeMetaData!=0) && (hMetaDataEnc->metadataMode==0)) {
+ FDKmemcpy(&hMetaDataEnc->submittedMetaData, &defaultMetaDataSetup, sizeof(AACENC_MetaData));
+ metadataMode = hMetaDataEnc->finalizeMetaData;
+ hMetaDataEnc->finalizeMetaData = 0;
+ }
+
+ /* Get last submitted data. */
+ if ( (err = LoadSubmittedMetadata(
+ &hMetaDataEnc->submittedMetaData,
+ hMetaDataEnc->nChannels,
+ metadataMode,
+ &hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx])) != METADATA_OK )
+ {
+ goto bail;
+ }
+
+ /* Calculate compressor if necessary and updata meta data info */
+ if (hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx].metadataMode != 0) {
+ if ( (err = ProcessCompressor(
+ &hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx],
+ hMetaDataEnc->hDrcComp,
+ pAudioSamples,
+ nAudioSamples)) != METADATA_OK)
+ {
+ /* Get last submitted data again. */
+ LoadSubmittedMetadata(
+ &hMetaDataEnc->submittedMetaData,
+ hMetaDataEnc->nChannels,
+ metadataMode,
+ &hMetaDataEnc->metaDataBuffer[metaDataDelayWriteIdx]);
+ }
+ }
+
+ /* Convert Meta Data side info to bitstream data. */
+ if ( (err = WriteMetadataPayload(hMetaDataEnc, &hMetaDataEnc->metaDataBuffer[metaDataDelayReadIdx])) != METADATA_OK ) {
+ goto bail;
+ }
+
+ /* Assign meta data to output */
+ *ppMetaDataExtPayload = hMetaDataEnc->exPayload;
+ *nMetaDataExtensions = hMetaDataEnc->nExtensions;
+ *matrix_mixdown_idx = hMetaDataEnc->matrix_mixdown_idx;
+
+bail:
+ /* Compensate audio delay, reset err status. */
+ err = CompensateAudioDelay(hMetaDataEnc, pAudioSamples, nAudioSamples);
+
+ return err;
+}
+
+
+static FDK_METADATA_ERROR CompensateAudioDelay(
+ HANDLE_FDK_METADATA_ENCODER hMetaDataEnc,
+ INT_PCM * const pAudioSamples,
+ const INT nAudioSamples
+ )
+{
+ FDK_METADATA_ERROR err = METADATA_OK;
+
+ if (hMetaDataEnc->nAudioDataDelay) {
+ int i, delaySamples = hMetaDataEnc->nAudioDataDelay*hMetaDataEnc->nChannels;
+
+ for (i = 0; i < nAudioSamples; i++) {
+ INT_PCM tmp = pAudioSamples[i];
+ pAudioSamples[i] = hMetaDataEnc->audioDelayBuffer[hMetaDataEnc->audioDelayIdx];
+ hMetaDataEnc->audioDelayBuffer[hMetaDataEnc->audioDelayIdx] = tmp;
+
+ hMetaDataEnc->audioDelayIdx++;
+ if (hMetaDataEnc->audioDelayIdx >= delaySamples) hMetaDataEnc->audioDelayIdx = 0;
+ }
+ }
+
+ return err;
+}
+
+/*-----------------------------------------------------------------------------
+
+ functionname: WriteMetadataPayload
+ description: fills anc data and extension payload
+ returns: Error status
+
+ ------------------------------------------------------------------------------*/
+static FDK_METADATA_ERROR WriteMetadataPayload(
+ const HANDLE_FDK_METADATA_ENCODER hMetaData,
+ const AAC_METADATA * const pMetadata
+ )
+{
+ FDK_METADATA_ERROR err = METADATA_OK;
+
+ if ( (hMetaData==NULL) || (pMetadata==NULL) ) {
+ err = METADATA_INVALID_HANDLE;
+ goto bail;
+ }
+
+ hMetaData->nExtensions = 0;
+ hMetaData->matrix_mixdown_idx = -1;
+
+ /* AAC-DRC */
+ if (pMetadata->metadataMode != 0)
+ {
+ hMetaData->exPayload[hMetaData->nExtensions].pData = hMetaData->drcInfoPayload;
+ hMetaData->exPayload[hMetaData->nExtensions].dataType = EXT_DYNAMIC_RANGE;
+ hMetaData->exPayload[hMetaData->nExtensions].associatedChElement = -1;
+
+ hMetaData->exPayload[hMetaData->nExtensions].dataSize =
+ WriteDynamicRangeInfoPayload(pMetadata, hMetaData->exPayload[hMetaData->nExtensions].pData);
+
+ hMetaData->nExtensions++;
+
+ /* Matrix Mixdown Coefficient in PCE */
+ if (pMetadata->WritePCEMixDwnIdx) {
+ hMetaData->matrix_mixdown_idx = surmix2matrix_mixdown_idx[pMetadata->surroundMixLevel];
+ }
+
+ /* ETSI TS 101 154 (DVB) - MPEG4 ancillary_data() */
+ if (pMetadata->metadataMode == 2) /* MP4_METADATA_MPEG_ETSI */
+ {
+ hMetaData->exPayload[hMetaData->nExtensions].pData = hMetaData->drcDsePayload;
+ hMetaData->exPayload[hMetaData->nExtensions].dataType = EXT_DATA_ELEMENT;
+ hMetaData->exPayload[hMetaData->nExtensions].associatedChElement = -1;
+
+ hMetaData->exPayload[hMetaData->nExtensions].dataSize =
+ WriteEtsiAncillaryDataPayload(pMetadata,hMetaData->exPayload[hMetaData->nExtensions].pData);
+
+ hMetaData->nExtensions++;
+ } /* metadataMode == 2 */
+
+ } /* metadataMode != 0 */
+
+bail:
+ return err;
+}
+
+static INT WriteDynamicRangeInfoPayload(
+ const AAC_METADATA* const pMetadata,
+ UCHAR* const pExtensionPayload
+ )
+{
+ const INT pce_tag_present = 0; /* yet fixed setting! */
+ const INT prog_ref_lev_res_bits = 0;
+ INT i, drc_num_bands = 1;
+
+ FDK_BITSTREAM bsWriter;
+ FDKinitBitStream(&bsWriter, pExtensionPayload, 16, 0, BS_WRITER);
+
+ /* dynamic_range_info() */
+ FDKwriteBits(&bsWriter, pce_tag_present, 1); /* pce_tag_present */
+ if (pce_tag_present) {
+ FDKwriteBits(&bsWriter, 0x0, 4); /* pce_instance_tag */
+ FDKwriteBits(&bsWriter, 0x0, 4); /* drc_tag_reserved_bits */
+ }
+
+ /* Exclude channels */
+ FDKwriteBits(&bsWriter, (pMetadata->mpegDrc.excluded_chns_present) ? 1 : 0, 1); /* excluded_chns_present*/
+
+ /* Multiband DRC */
+ FDKwriteBits(&bsWriter, (pMetadata->mpegDrc.drc_bands_present) ? 1 : 0, 1); /* drc_bands_present */
+ if (pMetadata->mpegDrc.drc_bands_present)
+ {
+ FDKwriteBits(&bsWriter, pMetadata->mpegDrc.drc_band_incr, 4); /* drc_band_incr */
+ FDKwriteBits(&bsWriter, pMetadata->mpegDrc.drc_interpolation_scheme, 4); /* drc_interpolation_scheme */
+ drc_num_bands += pMetadata->mpegDrc.drc_band_incr;
+ for (i=0; i<drc_num_bands; i++) {
+ FDKwriteBits(&bsWriter, pMetadata->mpegDrc.drc_band_top[i], 8); /* drc_band_top */
+ }
+ }
+
+ /* Program Reference Level */
+ FDKwriteBits(&bsWriter, pMetadata->mpegDrc.prog_ref_level_present, 1); /* prog_ref_level_present */
+ if (pMetadata->mpegDrc.prog_ref_level_present)
+ {
+ FDKwriteBits(&bsWriter, pMetadata->mpegDrc.prog_ref_level, 7); /* prog_ref_level */
+ FDKwriteBits(&bsWriter, prog_ref_lev_res_bits, 1); /* prog_ref_level_reserved_bits */
+ }
+
+ /* DRC Values */
+ for (i=0; i<drc_num_bands; i++) {
+ FDKwriteBits(&bsWriter, (pMetadata->mpegDrc.dyn_rng_sgn[i]) ? 1 : 0, 1); /* dyn_rng_sgn[ */
+ FDKwriteBits(&bsWriter, pMetadata->mpegDrc.dyn_rng_ctl[i], 7); /* dyn_rng_ctl */
+ }
+
+ /* return number of valid bits in extension payload. */
+ return FDKgetValidBits(&bsWriter);
+}
+
+static INT WriteEtsiAncillaryDataPayload(
+ const AAC_METADATA* const pMetadata,
+ UCHAR* const pExtensionPayload
+ )
+{
+ FDK_BITSTREAM bsWriter;
+ FDKinitBitStream(&bsWriter, pExtensionPayload, 16, 0, BS_WRITER);
+
+ /* ancillary_data_sync */
+ FDKwriteBits(&bsWriter, 0xBC, 8);
+
+ /* bs_info */
+ FDKwriteBits(&bsWriter, 0x3, 2); /* mpeg_audio_type */
+ FDKwriteBits(&bsWriter, pMetadata->dolbySurroundMode, 2); /* dolby_surround_mode */
+ FDKwriteBits(&bsWriter, 0x0, 4); /* reserved */
+
+ /* ancillary_data_status */
+ FDKwriteBits(&bsWriter, 0, 3); /* 3 bit Reserved, set to "0" */
+ FDKwriteBits(&bsWriter, (pMetadata->DmxLvl_On) ? 1 : 0, 1); /* downmixing_levels_MPEG4_status */
+ FDKwriteBits(&bsWriter, 0, 1); /* Reserved, set to "0" */
+ FDKwriteBits(&bsWriter, (pMetadata->etsiAncData.compression_on) ? 1 : 0, 1); /* audio_coding_mode_and_compression status */
+ FDKwriteBits(&bsWriter, (pMetadata->etsiAncData.timecode_coarse_status) ? 1 : 0, 1); /* coarse_grain_timecode_status */
+ FDKwriteBits(&bsWriter, (pMetadata->etsiAncData.timecode_fine_status) ? 1 : 0, 1); /* fine_grain_timecode_status */
+
+ /* downmixing_levels_MPEG4_status */
+ if (pMetadata->DmxLvl_On) {
+ FDKwriteBits(&bsWriter, encodeDmxLvls(pMetadata->centerMixLevel, pMetadata->surroundMixLevel), 8);
+ }
+
+ /* audio_coding_mode_and_compression_status */
+ if (pMetadata->etsiAncData.compression_on) {
+ FDKwriteBits(&bsWriter, 0x01, 8); /* audio coding mode */
+ FDKwriteBits(&bsWriter, pMetadata->etsiAncData.compression_value, 8); /* compression value */
+ }
+
+ /* grain-timecode coarse/fine */
+ if (pMetadata->etsiAncData.timecode_coarse_status) {
+ FDKwriteBits(&bsWriter, 0x0, 16); /* not yet supported */
+ }
+
+ if (pMetadata->etsiAncData.timecode_fine_status) {
+ FDKwriteBits(&bsWriter, 0x0, 16); /* not yet supported */
+ }
+
+ return FDKgetValidBits(&bsWriter);
+}
+
+
+static FDK_METADATA_ERROR LoadSubmittedMetadata(
+ const AACENC_MetaData * const hMetadata,
+ const INT nChannels,
+ const INT metadataMode,
+ AAC_METADATA * const pAacMetaData
+ )
+{
+ FDK_METADATA_ERROR err = METADATA_OK;
+
+ if (pAacMetaData==NULL) {
+ err = METADATA_INVALID_HANDLE;
+ }
+ else {
+ /* init struct */
+ FDKmemclear(pAacMetaData, sizeof(AAC_METADATA));
+
+ if (hMetadata!=NULL) {
+ /* convert data */
+ pAacMetaData->mpegDrc.drc_profile = hMetadata->drc_profile;
+ pAacMetaData->etsiAncData.comp_profile = hMetadata->comp_profile;
+ pAacMetaData->mpegDrc.drc_TargetRefLevel = hMetadata->drc_TargetRefLevel;
+ pAacMetaData->etsiAncData.comp_TargetRefLevel= hMetadata->comp_TargetRefLevel;
+ pAacMetaData->mpegDrc.prog_ref_level_present = hMetadata->prog_ref_level_present;
+ pAacMetaData->mpegDrc.prog_ref_level = dialnorm2progreflvl(hMetadata->prog_ref_level);
+
+ pAacMetaData->centerMixLevel = hMetadata->centerMixLevel;
+ pAacMetaData->surroundMixLevel = hMetadata->surroundMixLevel;
+ pAacMetaData->WritePCEMixDwnIdx = hMetadata->PCE_mixdown_idx_present;
+ pAacMetaData->DmxLvl_On = hMetadata->ETSI_DmxLvl_present;
+
+ pAacMetaData->etsiAncData.compression_on = 1;
+
+
+ if (nChannels == 2) {
+ pAacMetaData->dolbySurroundMode = hMetadata->dolbySurroundMode; /* dolby_surround_mode */
+ } else {
+ pAacMetaData->dolbySurroundMode = 0;
+ }
+
+ pAacMetaData->etsiAncData.timecode_coarse_status = 0; /* not yet supported - attention: Update GetEstMetadataBytesPerFrame() if enable this! */
+ pAacMetaData->etsiAncData.timecode_fine_status = 0; /* not yet supported - attention: Update GetEstMetadataBytesPerFrame() if enable this! */
+
+ pAacMetaData->metadataMode = metadataMode;
+ }
+ else {
+ pAacMetaData->metadataMode = 0; /* there is no configuration available */
+ }
+ }
+
+ return err;
+}
+
+INT FDK_MetadataEnc_GetDelay(
+ HANDLE_FDK_METADATA_ENCODER hMetadataEnc
+ )
+{
+ INT delay = 0;
+
+ if (hMetadataEnc!=NULL) {
+ delay = hMetadataEnc->nAudioDataDelay;
+ }
+
+ return delay;
+}
+
+
diff --git a/libAACenc/src/metadata_main.h b/libAACenc/src/metadata_main.h
new file mode 100644
index 0000000..715a3cf
--- /dev/null
+++ b/libAACenc/src/metadata_main.h
@@ -0,0 +1,161 @@
+/********************** Fraunhofer IIS FDK AAC Encoder lib ******************
+
+ (C) Copyright Fraunhofer IIS (2011)
+ 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): V. Bacigalupo
+ Description: Metadata Encoder library interface functions
+
+ 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 _METADATA_MAIN_H
+#define _METADATA_MAIN_H
+
+
+/* Includes ******************************************************************/
+#include "aacenc_lib.h"
+#include "aacenc.h"
+
+
+/* Defines *******************************************************************/
+
+/* Data Types ****************************************************************/
+
+typedef enum {
+ METADATA_OK = 0x0000, /*!< No error happened. All fine. */
+ METADATA_INVALID_HANDLE = 0x0020, /*!< Handle passed to function call was invalid. */
+ METADATA_MEMORY_ERROR = 0x0021, /*!< Memory allocation failed. */
+ METADATA_INIT_ERROR = 0x0040, /*!< General initialization error. */
+ METADATA_ENCODE_ERROR = 0x0060 /*!< The encoding process was interrupted by an unexpected error. */
+
+} FDK_METADATA_ERROR;
+
+/**
+ * Meta Data handle.
+ */
+typedef struct FDK_METADATA_ENCODER *HANDLE_FDK_METADATA_ENCODER;
+
+
+/**
+ * \brief Open a Meta Data instance.
+ *
+ * \param phMetadataEnc A pointer to a Meta Data handle to be allocated. Initialized on return.
+ *
+ * \return
+ * - METADATA_OK, on succes.
+ * - METADATA_INVALID_HANDLE, METADATA_MEMORY_ERROR, on failure.
+ */
+FDK_METADATA_ERROR FDK_MetadataEnc_Open(
+ HANDLE_FDK_METADATA_ENCODER *phMetadataEnc
+ );
+
+
+/**
+ * \brief Initialize a Meta Data instance.
+ *
+ * \param hMetadataEnc Meta Data handle.
+ * \param resetStates Indication for full reset of all states.
+ * \param metadataMode Configures metat data output format (0,1,2).
+ * \param audioDelay Delay cause by the audio encoder.
+ * \param frameLength Number of samples to be processes within one frame.
+ * \param sampleRate Sampling rat in Hz of audio input signal.
+ * \param nChannels Number of audio input channels.
+ * \param channelMode Channel configuration which is used by the encoder.
+ * \param channelOrder Channel order of the input data. (WAV, MPEG)
+ *
+ * \return
+ * - METADATA_OK, on succes.
+ * - METADATA_INVALID_HANDLE, METADATA_INIT_ERROR, on failure.
+ */
+FDK_METADATA_ERROR FDK_MetadataEnc_Init(
+ HANDLE_FDK_METADATA_ENCODER hMetadataEnc,
+ const INT resetStates,
+ const INT metadataMode,
+ const INT audioDelay,
+ const UINT frameLength,
+ const UINT sampleRate,
+ const UINT nChannels,
+ const CHANNEL_MODE channelMode,
+ const CHANNEL_ORDER channelOrder
+ );
+
+
+/**
+ * \brief Calculate Meta Data processing.
+ *
+ * This function treats all step necessary for meta data processing.
+ * - Receive new meta data and make usable.
+ * - Calculate DRC compressor and extract meta data info.
+ * - Make meta data available for extern use.
+ * - Apply audio data and meta data delay compensation.
+ *
+ * \param hMetadataEnc Meta Data handle.
+ * \param pAudioSamples Pointer to audio input data. Existing function overwrites audio data with delayed audio samples.
+ * \param nAudioSamples Number of input audio samples to be prcessed.
+ * \param pMetadata Pointer to Metat Data input.
+ * \param ppMetaDataExtPayload Pointer to extension payload array. Filled on return.
+ * \param nMetaDataExtensions Pointer to variable to describe number of available extension payloads. Filled on return.
+ * \param matrix_mixdown_idx Pointer to variable for matrix mixdown coefficient. Filled on return.
+ *
+ * \return
+ * - METADATA_OK, on succes.
+ * - METADATA_INVALID_HANDLE, METADATA_ENCODE_ERROR, on failure.
+ */
+FDK_METADATA_ERROR FDK_MetadataEnc_Process(
+ HANDLE_FDK_METADATA_ENCODER hMetadataEnc,
+ INT_PCM * const pAudioSamples,
+ const INT nAudioSamples,
+ const AACENC_MetaData * const pMetadata,
+ AACENC_EXT_PAYLOAD ** ppMetaDataExtPayload,
+ UINT * nMetaDataExtensions,
+ INT * matrix_mixdown_idx
+ );
+
+
+/**
+ * \brief Close the Meta Data instance.
+ *
+ * Deallocate instance and free whole memory.
+ *
+ * \param phMetaData Pointer to the Meta Data handle to be deallocated.
+ *
+ * \return
+ * - METADATA_OK, on succes.
+ * - METADATA_INVALID_HANDLE, on failure.
+ */
+FDK_METADATA_ERROR FDK_MetadataEnc_Close(
+ HANDLE_FDK_METADATA_ENCODER *phMetaData
+ );
+
+
+/**
+ * \brief Get Meta Data Encoder delay.
+ *
+ * \param hMetadataEnc Meta Data Encoder handle.
+ *
+ * \return Delay caused by Meta Data module.
+ */
+INT FDK_MetadataEnc_GetDelay(
+ HANDLE_FDK_METADATA_ENCODER hMetadataEnc
+ );
+
+
+#endif /* _METADATA_MAIN_H */
+
diff --git a/libAACenc/src/ms_stereo.cpp b/libAACenc/src/ms_stereo.cpp
new file mode 100644
index 0000000..27cb184
--- /dev/null
+++ b/libAACenc/src/ms_stereo.cpp
@@ -0,0 +1,189 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: MS stereo processing
+
+******************************************************************************/
+#include "ms_stereo.h"
+
+#include "psy_const.h"
+
+/* static const float scaleMinThres = 1.0f; */ /* 0.75f for 3db boost */
+
+void FDKaacEnc_MsStereoProcessing(PSY_DATA *RESTRICT psyData[(2)],
+ PSY_OUT_CHANNEL* psyOutChannel[2],
+ const INT *isBook,
+ INT *msDigest, /* output */
+ INT *msMask, /* output */
+ const INT sfbCnt,
+ const INT sfbPerGroup,
+ const INT maxSfbPerGroup,
+ const INT *sfbOffset)
+{
+ FIXP_DBL *sfbEnergyLeft = psyData[0]->sfbEnergy.Long; /* modified where msMask==1 */
+ FIXP_DBL *sfbEnergyRight = psyData[1]->sfbEnergy.Long; /* modified where msMask==1 */
+ const FIXP_DBL *sfbEnergyMid = psyData[0]->sfbEnergyMS.Long;
+ const FIXP_DBL *sfbEnergySide = psyData[1]->sfbEnergyMS.Long;
+ FIXP_DBL *sfbThresholdLeft = psyData[0]->sfbThreshold.Long; /* modified where msMask==1 */
+ FIXP_DBL *sfbThresholdRight = psyData[1]->sfbThreshold.Long; /* modified where msMask==1 */
+
+ FIXP_DBL *sfbSpreadEnLeft = psyData[0]->sfbSpreadEnergy.Long;
+ FIXP_DBL *sfbSpreadEnRight = psyData[1]->sfbSpreadEnergy.Long;
+
+ FIXP_DBL *sfbEnergyLeftLdData = psyOutChannel[0]->sfbEnergyLdData; /* modified where msMask==1 */
+ FIXP_DBL *sfbEnergyRightLdData = psyOutChannel[1]->sfbEnergyLdData; /* modified where msMask==1 */
+ FIXP_DBL *sfbEnergyMidLdData = psyData[0]->sfbEnergyMSLdData;
+ FIXP_DBL *sfbEnergySideLdData = psyData[1]->sfbEnergyMSLdData;
+ FIXP_DBL *sfbThresholdLeftLdData = psyOutChannel[0]->sfbThresholdLdData; /* modified where msMask==1 */
+ FIXP_DBL *sfbThresholdRightLdData = psyOutChannel[1]->sfbThresholdLdData; /* modified where msMask==1 */
+
+ FIXP_DBL *mdctSpectrumLeft = psyData[0]->mdctSpectrum; /* modified where msMask==1 */
+ FIXP_DBL *mdctSpectrumRight = psyData[1]->mdctSpectrum; /* modified where msMask==1 */
+
+ INT sfb,sfboffs, j; /* loop counters */
+ FIXP_DBL pnlrLdData, pnmsLdData;
+ FIXP_DBL minThresholdLdData;
+ FIXP_DBL minThreshold;
+ INT useMS;
+
+ INT msMaskTrueSomewhere = 0; /* to determine msDigest */
+ INT numMsMaskFalse = 0; /* number of non-intensity bands where L/R coding is used */
+
+ for(sfb=0; sfb<sfbCnt; sfb+=sfbPerGroup) {
+ for(sfboffs=0;sfboffs<maxSfbPerGroup;sfboffs++) {
+
+ if ( (isBook==NULL) ? 1 : (isBook[sfb+sfboffs] == 0) ) {
+ FIXP_DBL tmp;
+
+/*
+ minThreshold=min(sfbThresholdLeft[sfb+sfboffs], sfbThresholdRight[sfb+sfboffs])*scaleMinThres;
+ pnlr = (sfbThresholdLeft[sfb+sfboffs]/
+ max(sfbEnergyLeft[sfb+sfboffs],sfbThresholdLeft[sfb+sfboffs]))*
+ (sfbThresholdRight[sfb+sfboffs]/
+ max(sfbEnergyRight[sfb+sfboffs],sfbThresholdRight[sfb+sfboffs]));
+ pnms = (minThreshold/max(sfbEnergyMid[sfb+sfboffs],minThreshold))*
+ (minThreshold/max(sfbEnergySide[sfb+sfboffs],minThreshold));
+ useMS = (pnms > pnlr);
+*/
+
+ /* we assume that scaleMinThres == 1.0f and we can drop it */
+ minThresholdLdData = fixMin(sfbThresholdLeftLdData[sfb+sfboffs], sfbThresholdRightLdData[sfb+sfboffs]);
+
+ /* pnlrLdData = sfbThresholdLeftLdData[sfb+sfboffs] -
+ max(sfbEnergyLeftLdData[sfb+sfboffs], sfbThresholdLeftLdData[sfb+sfboffs]) +
+ sfbThresholdRightLdData[sfb+sfboffs] -
+ max(sfbEnergyRightLdData[sfb+sfboffs], sfbThresholdRightLdData[sfb+sfboffs]); */
+ tmp = fixMax(sfbEnergyLeftLdData[sfb+sfboffs], sfbThresholdLeftLdData[sfb+sfboffs]);
+ pnlrLdData = (sfbThresholdLeftLdData[sfb+sfboffs]>>1) - (tmp>>1);
+ pnlrLdData = pnlrLdData + (sfbThresholdRightLdData[sfb+sfboffs]>>1);
+ tmp = fixMax(sfbEnergyRightLdData[sfb+sfboffs], sfbThresholdRightLdData[sfb+sfboffs]);
+ pnlrLdData = pnlrLdData - (tmp>>1);
+
+ /* pnmsLdData = minThresholdLdData - max(sfbEnergyMidLdData[sfb+sfboffs], minThresholdLdData) +
+ minThresholdLdData - max(sfbEnergySideLdData[sfb+sfboffs], minThresholdLdData); */
+ tmp = fixMax(sfbEnergyMidLdData[sfb+sfboffs], minThresholdLdData);
+ pnmsLdData = minThresholdLdData - (tmp>>1);
+ tmp = fixMax(sfbEnergySideLdData[sfb+sfboffs], minThresholdLdData);
+ pnmsLdData = pnmsLdData - (tmp>>1);
+ useMS = (pnmsLdData > (pnlrLdData));
+
+
+ if (useMS) {
+ msMask[sfb+sfboffs] = 1;
+ msMaskTrueSomewhere = 1;
+ for(j=sfbOffset[sfb+sfboffs]; j<sfbOffset[sfb+sfboffs+1]; j++) {
+ FIXP_DBL specL, specR;
+ specL = mdctSpectrumLeft[j]>>1;
+ specR = mdctSpectrumRight[j]>>1;
+ mdctSpectrumLeft[j] = specL + specR;
+ mdctSpectrumRight[j] = specL - specR;
+ }
+ minThreshold = fixMin(sfbThresholdLeft[sfb+sfboffs], sfbThresholdRight[sfb+sfboffs]);
+ sfbThresholdLeft[sfb+sfboffs] = sfbThresholdRight[sfb+sfboffs] = minThreshold;
+ sfbThresholdLeftLdData[sfb+sfboffs] = sfbThresholdRightLdData[sfb+sfboffs] = minThresholdLdData;
+ sfbEnergyLeft[sfb+sfboffs] = sfbEnergyMid[sfb+sfboffs];
+ sfbEnergyRight[sfb+sfboffs] = sfbEnergySide[sfb+sfboffs];
+ sfbEnergyLeftLdData[sfb+sfboffs] = sfbEnergyMidLdData[sfb+sfboffs];
+ sfbEnergyRightLdData[sfb+sfboffs] = sfbEnergySideLdData[sfb+sfboffs];
+
+ sfbSpreadEnLeft[sfb+sfboffs] = sfbSpreadEnRight[sfb+sfboffs] =
+ fixMin( sfbSpreadEnLeft[sfb+sfboffs],
+ sfbSpreadEnRight[sfb+sfboffs] ) >> 1;
+
+ }
+ else {
+ msMask[sfb+sfboffs] = 0;
+ numMsMaskFalse++;
+ } /* useMS */
+ } /* isBook */
+ else {
+ /* keep mDigest from IS module */
+ if (msMask[sfb+sfboffs]) {
+ msMaskTrueSomewhere = 1;
+ }
+ /* prohibit MS_MASK_ALL in combination with IS */
+ numMsMaskFalse = 9;
+ } /* isBook */
+ } /* sfboffs */
+ } /* sfb */
+
+
+ if(msMaskTrueSomewhere == 1) {
+ if ((numMsMaskFalse == 0) || ((numMsMaskFalse < maxSfbPerGroup) && (numMsMaskFalse < 9))) {
+ *msDigest = SI_MS_MASK_ALL;
+ /* loop through M/S bands; if msMask==0, set it to 1 and apply M/S */
+ for (sfb = 0; sfb < sfbCnt; sfb += sfbPerGroup) {
+ for (sfboffs = 0; sfboffs < maxSfbPerGroup; sfboffs++) {
+ if (( (isBook == NULL) ? 1 : (isBook[sfb+sfboffs] == 0) ) && (msMask[sfb+sfboffs] == 0)) {
+ msMask[sfb+sfboffs] = 1;
+ /* apply M/S coding */
+ for(j=sfbOffset[sfb+sfboffs]; j<sfbOffset[sfb+sfboffs+1]; j++) {
+ FIXP_DBL specL, specR;
+ specL = mdctSpectrumLeft[j]>>1;
+ specR = mdctSpectrumRight[j]>>1;
+ mdctSpectrumLeft[j] = specL + specR;
+ mdctSpectrumRight[j] = specL - specR;
+ }
+ minThreshold = fixMin(sfbThresholdLeft[sfb+sfboffs], sfbThresholdRight[sfb+sfboffs]);
+ sfbThresholdLeft[sfb+sfboffs] = sfbThresholdRight[sfb+sfboffs] = minThreshold;
+ minThresholdLdData = fixMin(sfbThresholdLeftLdData[sfb+sfboffs], sfbThresholdRightLdData[sfb+sfboffs]);
+ sfbThresholdLeftLdData[sfb+sfboffs] = sfbThresholdRightLdData[sfb+sfboffs] = minThresholdLdData;
+ sfbEnergyLeft[sfb+sfboffs] = sfbEnergyMid[sfb+sfboffs];
+ sfbEnergyRight[sfb+sfboffs] = sfbEnergySide[sfb+sfboffs];
+ sfbEnergyLeftLdData[sfb+sfboffs] = sfbEnergyMidLdData[sfb+sfboffs];
+ sfbEnergyRightLdData[sfb+sfboffs] = sfbEnergySideLdData[sfb+sfboffs];
+
+ sfbSpreadEnLeft[sfb+sfboffs] = sfbSpreadEnRight[sfb+sfboffs] =
+ fixMin( sfbSpreadEnLeft[sfb+sfboffs],
+ sfbSpreadEnRight[sfb+sfboffs] ) >> 1;
+ }
+ }
+ }
+ } else {
+ *msDigest = SI_MS_MASK_SOME;
+ }
+ } else {
+ *msDigest = SI_MS_MASK_NONE;
+ }
+}
diff --git a/libAACenc/src/ms_stereo.h b/libAACenc/src/ms_stereo.h
new file mode 100644
index 0000000..1d74acb
--- /dev/null
+++ b/libAACenc/src/ms_stereo.h
@@ -0,0 +1,44 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: MS stereo processing
+
+******************************************************************************/
+#ifndef __MS_STEREO_H__
+#define __MS_STEREO_H__
+
+
+#include "interface.h"
+
+void FDKaacEnc_MsStereoProcessing(PSY_DATA *RESTRICT psyData[(2)],
+ PSY_OUT_CHANNEL* psyOutChannel[2],
+ const INT *isBook,
+ INT *msDigest, /* output */
+ INT *msMask, /* output */
+ const INT sfbCnt,
+ const INT sfbPerGroup,
+ const INT maxSfbPerGroup,
+ const INT *sfbOffset);
+
+#endif
diff --git a/libAACenc/src/noisedet.cpp b/libAACenc/src/noisedet.cpp
new file mode 100644
index 0000000..2f21fb9
--- /dev/null
+++ b/libAACenc/src/noisedet.cpp
@@ -0,0 +1,170 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (2001)
+ 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$
+
+ Initial author: M. Lohwasser
+ contents/description: noisedet.c
+ Routines for Noise Detection
+
+******************************************************************************/
+
+#include "noisedet.h"
+
+#include "aacenc_pns.h"
+#include "pnsparam.h"
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_fuzzyIsSmaller
+ description: Fuzzy value calculation for "testVal is smaller than refVal"
+ returns: fuzzy value
+ input: test and ref Value,
+ low and high Lim
+ output: return fuzzy value
+
+*****************************************************************************/
+static FIXP_SGL FDKaacEnc_fuzzyIsSmaller( FIXP_DBL testVal,
+ FIXP_DBL refVal,
+ FIXP_DBL loLim,
+ FIXP_DBL hiLim )
+{
+ if (refVal <= FL2FXCONST_DBL(0.0))
+ return( FL2FXCONST_SGL(0.0f) );
+ else if (testVal >= fMult((hiLim>>1)+(loLim>>1), refVal))
+ return( FL2FXCONST_SGL(0.0f) );
+ else return( (FIXP_SGL)MAXVAL_SGL );
+}
+
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_noiseDetect
+ description: detect tonal sfb's; two tests
+ Powerdistribution:
+ sfb splittet in four regions,
+ compare the energy in all sections
+ PsychTonality:
+ compare tonality from chaosmeasure with reftonality
+ returns:
+ input: spectrum of one large mdct
+ number of sfb's
+ pointer to offset of sfb's
+ pointer to noiseFuzzyMeasure (modified)
+ noiseparams struct
+ pointer to sfb energies
+ pointer to tonality calculated in chaosmeasure
+ output: noiseFuzzy Measure
+
+*****************************************************************************/
+
+void FDKaacEnc_noiseDetect(FIXP_DBL *RESTRICT mdctSpectrum,
+ INT *RESTRICT sfbMaxScaleSpec,
+ INT sfbActive,
+ const INT *RESTRICT sfbOffset,
+ FIXP_SGL *RESTRICT noiseFuzzyMeasure,
+ NOISEPARAMS *np,
+ FIXP_SGL *RESTRICT sfbtonality )
+
+{
+ int i, k, sfb, sfbWidth;
+ FIXP_SGL fuzzy, fuzzyTotal;
+ FIXP_DBL refVal, testVal;
+
+#define ALL_SFB_TONAL 0
+#define ALL_SFB_NONTONAL 0
+
+ /***** Start detection phase *****/
+ /* Start noise detection for each band based on a number of checks */
+ for (sfb=0; sfb<sfbActive; sfb++) {
+
+ fuzzyTotal = (FIXP_SGL)MAXVAL_SGL;
+ sfbWidth = sfbOffset[sfb+1] - sfbOffset[sfb];
+
+ /* Reset output for lower bands or too small bands */
+ if (sfb < np->startSfb || sfbWidth < np->minSfbWidth) {
+ noiseFuzzyMeasure[sfb] = FL2FXCONST_SGL(0.0f);
+ continue;
+ }
+
+ if ( (np->detectionAlgorithmFlags & USE_POWER_DISTRIBUTION) && (fuzzyTotal > FL2FXCONST_SGL(0.5f)) ) {
+ FIXP_DBL fhelp1, fhelp2, fhelp3, fhelp4, maxVal, minVal;
+ INT leadingBits = fixMax(0,(sfbMaxScaleSpec[sfb] - 3)); /* max sfbWidth = 96/4 ; 2^5=32 => 5/2 = 3 (spc*spc) */
+
+ /* check power distribution in four regions */
+ fhelp1 = fhelp2 = fhelp3 = fhelp4 = FL2FXCONST_DBL(0.0f);
+ k = sfbWidth >>2; /* Width of a quarter band */
+
+ for (i=sfbOffset[sfb]; i<sfbOffset[sfb]+k; i++) {
+ fhelp1 = fPow2AddDiv2(fhelp1, mdctSpectrum[i]<<leadingBits);
+ fhelp2 = fPow2AddDiv2(fhelp2, mdctSpectrum[i+k]<<leadingBits);
+ fhelp3 = fPow2AddDiv2(fhelp3, mdctSpectrum[i+2*k]<<leadingBits);
+ fhelp4 = fPow2AddDiv2(fhelp4, mdctSpectrum[i+3*k]<<leadingBits);
+ }
+
+ /* get max into fhelp: */
+ maxVal = fixMax(fhelp1, fhelp2);
+ maxVal = fixMax(maxVal, fhelp3);
+ maxVal = fixMax(maxVal, fhelp4);
+
+ /* get min into fhelp1: */
+ minVal = fixMin(fhelp1, fhelp2);
+ minVal = fixMin(minVal, fhelp3);
+ minVal = fixMin(minVal, fhelp4);
+
+ /* Normalize min and max Val */
+ leadingBits = CountLeadingBits(maxVal);
+ testVal = maxVal << leadingBits;
+ refVal = minVal << leadingBits;
+
+ /* calculate fuzzy value for power distribution */
+ testVal = fMultDiv2(testVal, np->powDistPSDcurve[sfb]);
+
+ fuzzy = FDKaacEnc_fuzzyIsSmaller(testVal, /* 1/2 * maxValue * PSDcurve */
+ refVal, /* 1 * minValue */
+ FL2FXCONST_DBL(0.495), /* 1/2 * loLim (0.99f/2) */
+ FL2FXCONST_DBL(0.505)); /* 1/2 * hiLim (1.01f/2) */
+
+ fuzzyTotal = fixMin(fuzzyTotal, fuzzy);
+ }
+
+ if ( (np->detectionAlgorithmFlags & USE_PSYCH_TONALITY) && (fuzzyTotal > FL2FXCONST_SGL(0.5f)) ) {
+ /* Detection with tonality-value of psych. acoustic (here: 1 is tonal!)*/
+
+ testVal = FX_SGL2FX_DBL(sfbtonality[sfb])>>1; /* 1/2 * sfbTonality */
+ refVal = np->refTonality;
+
+ fuzzy = FDKaacEnc_fuzzyIsSmaller(testVal,
+ refVal,
+ FL2FXCONST_DBL(0.45f), /* 1/2 * loLim (0.9f/2) */
+ FL2FXCONST_DBL(0.55f)); /* 1/2 * hiLim (1.1f/2) */
+
+ fuzzyTotal = fixMin(fuzzyTotal, fuzzy);
+ }
+
+
+ /* Output of final result */
+ noiseFuzzyMeasure[sfb] = fuzzyTotal;
+ }
+}
diff --git a/libAACenc/src/noisedet.h b/libAACenc/src/noisedet.h
new file mode 100644
index 0000000..50b3371
--- /dev/null
+++ b/libAACenc/src/noisedet.h
@@ -0,0 +1,47 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (2001)
+ 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$
+
+ Initial author: M. Lohwasser
+ contents/description: noisedet.h
+
+******************************************************************************/
+
+#ifndef __NOISEDET_H
+#define __NOISEDET_H
+
+#include "common_fix.h"
+
+#include "pnsparam.h"
+#include "psy_data.h"
+
+
+void FDKaacEnc_noiseDetect( FIXP_DBL *mdctSpectrum,
+ INT *sfbMaxScaleSpec,
+ INT sfbActive,
+ const INT *sfbOffset,
+ FIXP_SGL noiseFuzzyMeasure[],
+ NOISEPARAMS *np,
+ FIXP_SGL *sfbtonality );
+
+#endif
diff --git a/libAACenc/src/pns_func.h b/libAACenc/src/pns_func.h
new file mode 100644
index 0000000..320fe84
--- /dev/null
+++ b/libAACenc/src/pns_func.h
@@ -0,0 +1,89 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (2001)
+ 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$
+
+ Initial author: M. Lohwasser
+ contents/description: pns_func.h
+
+******************************************************************************/
+
+#ifndef _PNS_FUNC_H
+#define _PNS_FUNC_H
+
+#include "common_fix.h"
+
+#include "aacenc_pns.h"
+#include "psy_data.h"
+
+
+
+AAC_ENCODER_ERROR FDKaacEnc_InitPnsConfiguration(PNS_CONFIG *pnsConf,
+ INT bitRate,
+ INT sampleRate,
+ INT usePns,
+ INT sfbCnt,
+ const INT *sfbOffset,
+ const INT numChan,
+ const INT isLC );
+
+void FDKaacEnc_PnsDetect( PNS_CONFIG *pnsConf,
+ PNS_DATA *pnsData,
+ const INT lastWindowSequence,
+ const INT sfbActive,
+ const INT maxSfbPerGroup,
+ FIXP_DBL *sfbThresholdLdData,
+ const INT *sfbOffset,
+ FIXP_DBL *mdctSpectrum,
+ INT *sfbMaxScaleSpec,
+ FIXP_SGL *sfbtonality,
+ int tnsOrder,
+ INT tnsPredictionGain,
+ INT tnsActive,
+ FIXP_DBL *sfbEnergyLdData,
+ INT *noiseNrg );
+
+void FDKaacEnc_CodePnsChannel( const INT sfbActive,
+ PNS_CONFIG *pnsConf,
+ INT *pnsFlag,
+ FIXP_DBL *sfbEnergy,
+ INT *noiseNrg,
+ FIXP_DBL *sfbThreshold );
+
+void FDKaacEnc_PreProcessPnsChannelPair( const INT sfbActive,
+ FIXP_DBL *sfbEnergyLeft,
+ FIXP_DBL *sfbEnergyRight,
+ FIXP_DBL *sfbEnergyLeftLD,
+ FIXP_DBL *sfbEnergyRightLD,
+ FIXP_DBL *sfbEnergyMid,
+ PNS_CONFIG *pnsConfLeft,
+ PNS_DATA *pnsDataLeft,
+ PNS_DATA *pnsDataRight );
+
+void FDKaacEnc_PostProcessPnsChannelPair( const INT sfbActive,
+ PNS_CONFIG *pnsConf,
+ PNS_DATA *pnsDataLeft,
+ PNS_DATA *pnsDataRight,
+ INT *msMask,
+ INT *msDigest );
+
+#endif /* _PNS_FUNC_H */
diff --git a/libAACenc/src/pnsparam.cpp b/libAACenc/src/pnsparam.cpp
new file mode 100644
index 0000000..0babc4a
--- /dev/null
+++ b/libAACenc/src/pnsparam.cpp
@@ -0,0 +1,248 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (2001)
+ 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$
+ Initial author: M.Lohwasser
+ contents/description: PNS parameters depending on bitrate and bandwidth
+
+******************************************************************************/
+
+#include "pnsparam.h"
+#include "psy_configuration.h"
+
+typedef struct {
+ SHORT startFreq;
+ /* Parameters for detection */
+ FIXP_SGL refPower;
+ FIXP_SGL refTonality;
+ SHORT tnsGainThreshold; /* scaled by TNS_PREDGAIN_SCALE (=1000) */
+ SHORT tnsPNSGainThreshold; /* scaled by TNS_PREDGAIN_SCALE (=1000) */
+ FIXP_SGL gapFillThr;
+ SHORT minSfbWidth;
+ USHORT detectionAlgorithmFlags;
+} PNS_INFO_TAB;
+
+
+typedef struct {
+ ULONG brFrom;
+ ULONG brTo;
+ UCHAR S22050;
+ UCHAR S24000;
+ UCHAR S32000;
+ UCHAR S44100;
+ UCHAR S48000;
+} AUTO_PNS_TAB;
+
+static const AUTO_PNS_TAB levelTable_mono[]= {
+ {0, 11999, 1, 1, 1, 1, 1,},
+ {12000, 19999, 1, 1, 1, 1, 1,},
+ {20000, 28999, 2, 1, 1, 1, 1,},
+ {29000, 40999, 4, 4, 4, 2, 2,},
+ {41000, 55999, 9, 9, 7, 7, 7,},
+ {56000, 79999, 0, 0, 0, 9, 9,},
+ {80000, 99999, 0, 0, 0, 0, 0,},
+ {100000,999999, 0, 0, 0, 0, 0,},
+};
+
+static const AUTO_PNS_TAB levelTable_stereo[]= {
+ {0, 11999, 1, 1, 1, 1, 1,},
+ {12000, 19999, 3, 1, 1, 1, 1,},
+ {20000, 28999, 3, 3, 3, 2, 2,},
+ {29000, 40999, 7, 6, 6, 5, 5,},
+ {41000, 55999, 9, 9, 7, 7, 7,},
+ {56000, 79999, 0, 0, 0, 0, 0,},
+ {80000, 99999, 0, 0, 0, 0, 0,},
+ {100000,999999, 0, 0, 0, 0, 0,},
+};
+
+
+static const PNS_INFO_TAB pnsInfoTab[] = {
+/*0 pns off */
+/*1*/ { 4000, FL2FXCONST_SGL(0.04), FL2FXCONST_SGL(0.06), 1150, 1200, FL2FXCONST_SGL(0.02), 8,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS /*| JUST_LONG_WINDOW*/ },
+/*2*/ { 4000, FL2FXCONST_SGL(0.04), FL2FXCONST_SGL(0.07), 1130, 1300, FL2FXCONST_SGL(0.05), 8,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS /*| JUST_LONG_WINDOW*/ },
+/*3*/ { 4100, FL2FXCONST_SGL(0.04), FL2FXCONST_SGL(0.07), 1100, 1400, FL2FXCONST_SGL(0.10), 8,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS /*| JUST_LONG_WINDOW*/ },
+/*4*/ { 4100, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.10), 1100, 1400, FL2FXCONST_SGL(0.15), 8,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS /*| JUST_LONG_WINDOW*/ },
+/*5*/ { 4300, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.10), 1100, 1400, FL2FXCONST_SGL(0.15), 8,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW },
+/*6*/ { 5000, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.10), 1100, 1400, FL2FXCONST_SGL(0.25), 8,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW },
+/*7*/ { 5500, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.12), 1100, 1400, FL2FXCONST_SGL(0.35), 8,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW },
+/*8*/ { 6000, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.12), 1080, 1400, FL2FXCONST_SGL(0.40), 8,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW },
+/*9*/ { 6000, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.14), 1070, 1400, FL2FXCONST_SGL(0.45), 8,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW },
+};
+
+static const AUTO_PNS_TAB levelTable_lowComplexity[]= {
+ //{0, 23999, 1, 1, 1, 1, 1,},
+ //{24000, 31999, 2, 2, 2, 2, 2,},
+ {0, 27999, 0, 0, 0, 0, 0,},
+ {28000, 31999, 2, 2, 2, 2, 2,},
+ {32000, 47999, 3, 3, 3, 3, 3,},
+ {48000, 48000, 4, 4, 4, 4, 4,},
+ {48001, 999999, 0, 0, 0, 0, 0,},
+};
+
+/* conversion of old LC tuning tables to new (LD enc) structure (only entries which are actually used were converted) */
+static const PNS_INFO_TAB pnsInfoTab_lowComplexity[] = {
+/*0 pns off */
+ /* DEFAULT parameter set */
+/*1*/ { 4100, FL2FXCONST_SGL(0.03), FL2FXCONST_SGL(0.16), 1100, 1400, FL2FXCONST_SGL(0.5), 16,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW },
+/*2*/ { 4100, FL2FXCONST_SGL(0.05), FL2FXCONST_SGL(0.10), 1410, 1400, FL2FXCONST_SGL(0.5), 16,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW },
+/*3*/ { 4100, FL2FXCONST_SGL(0.05), FL2FXCONST_SGL(0.10), 1100, 1400, FL2FXCONST_SGL(0.5), 16,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW },
+ /* LOWSUBST -> PNS is used less often than with DEFAULT parameter set (for br: 48000 - 79999) */
+/*4*/ { 4100, FL2FXCONST_SGL(0.20), FL2FXCONST_SGL(0.10), 1410, 1400, FL2FXCONST_SGL(0.5), 16,
+ USE_POWER_DISTRIBUTION | USE_PSYCH_TONALITY | USE_TNS_GAIN_THR | USE_TNS_PNS | JUST_LONG_WINDOW },
+};
+
+/****************************************************************************
+ function to look up used pns level
+****************************************************************************/
+int FDKaacEnc_lookUpPnsUse (int bitRate, int sampleRate, int numChan, const int isLC) {
+
+ int hUsePns=0, size, i;
+ const AUTO_PNS_TAB *levelTable;
+
+ if (isLC) {
+ levelTable = &levelTable_lowComplexity[0];
+ size = sizeof(levelTable_lowComplexity);
+ } else
+ { /* (E)LD */
+ levelTable = (numChan > 1) ? &levelTable_stereo[0] : &levelTable_mono[0];
+ size = (numChan > 1) ? sizeof(levelTable_stereo) : sizeof(levelTable_mono);
+ }
+
+ for(i = 0; i < (int) (size/sizeof(AUTO_PNS_TAB)); i++) {
+ if(((ULONG)bitRate >= levelTable[i].brFrom) &&
+ ((ULONG)bitRate <= levelTable[i].brTo) )
+ break;
+ }
+
+ /* sanity check */
+ if ((int)(sizeof(pnsInfoTab)/sizeof(PNS_INFO_TAB)) < i ) {
+ return (PNS_TABLE_ERROR);
+ }
+
+ switch (sampleRate) {
+ case 22050: hUsePns = levelTable[i].S22050; break;
+ case 24000: hUsePns = levelTable[i].S24000; break;
+ case 32000: hUsePns = levelTable[i].S32000; break;
+ case 44100: hUsePns = levelTable[i].S44100; break;
+ case 48000: hUsePns = levelTable[i].S48000; break;
+ default:
+ if (isLC) {
+ hUsePns = levelTable[i].S48000;
+ }
+ break;
+ }
+
+ return (hUsePns);
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_GetPnsParam
+ description: Gets PNS parameters depending on bitrate and bandwidth
+ returns: error status
+ input: Noiseparams struct, bitrate, sampling rate,
+ number of sfb's, pointer to sfb offset
+ output: PNS parameters
+
+*****************************************************************************/
+AAC_ENCODER_ERROR FDKaacEnc_GetPnsParam(NOISEPARAMS *np,
+ INT bitRate,
+ INT sampleRate,
+ INT sfbCnt,
+ const INT *sfbOffset,
+ INT *usePns,
+ INT numChan,
+ const int isLC)
+
+{
+ int i, hUsePns;
+ const PNS_INFO_TAB *pnsInfo;
+
+ if (isLC) {
+ np->detectionAlgorithmFlags = IS_LOW_COMLEXITY;
+ pnsInfo = pnsInfoTab_lowComplexity;
+ }
+ else
+ {
+ np->detectionAlgorithmFlags = 0;
+ pnsInfo = pnsInfoTab;
+ }
+
+ if (*usePns<=0)
+ return AAC_ENC_OK;
+
+ /* new pns params */
+ hUsePns = FDKaacEnc_lookUpPnsUse (bitRate, sampleRate, numChan, isLC);
+ if (hUsePns == 0) {
+ *usePns = 0;
+ return AAC_ENC_OK;
+ }
+ if (hUsePns == PNS_TABLE_ERROR)
+ return AAC_ENC_PNS_TABLE_ERROR;
+
+ /* select correct row of tuning table */
+ pnsInfo += hUsePns-1;
+
+ np->startSfb = FDKaacEnc_FreqToBandWithRounding( pnsInfo->startFreq,
+ sampleRate,
+ sfbCnt,
+ sfbOffset );
+
+ np->detectionAlgorithmFlags |= pnsInfo->detectionAlgorithmFlags;
+
+ np->refPower = FX_SGL2FX_DBL(pnsInfo->refPower);
+ np->refTonality = FX_SGL2FX_DBL(pnsInfo->refTonality);
+ np->tnsGainThreshold = pnsInfo->tnsGainThreshold;
+ np->tnsPNSGainThreshold = pnsInfo->tnsPNSGainThreshold;
+ np->minSfbWidth = pnsInfo->minSfbWidth;
+
+ np->gapFillThr = (FIXP_SGL)pnsInfo->gapFillThr;
+
+ /* assuming a constant dB/Hz slope in the signal's PSD curve,
+ the detection threshold needs to be corrected for the width of the band */
+ for ( i = 0; i < (sfbCnt-1); i++)
+ {
+ INT qtmp, sfbWidth;
+ FIXP_DBL tmp;
+
+ sfbWidth = sfbOffset[i+1]-sfbOffset[i];
+
+ tmp = fPow(np->refPower, 0, sfbWidth, DFRACT_BITS-1-5, &qtmp);
+ np->powDistPSDcurve[i] = (FIXP_SGL)((LONG)(scaleValue(tmp, qtmp) >> 16));
+ }
+ np->powDistPSDcurve[sfbCnt] = np->powDistPSDcurve[sfbCnt-1];
+
+ return AAC_ENC_OK;
+}
diff --git a/libAACenc/src/pnsparam.h b/libAACenc/src/pnsparam.h
new file mode 100644
index 0000000..7d947c6
--- /dev/null
+++ b/libAACenc/src/pnsparam.h
@@ -0,0 +1,78 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (2001)
+ 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.
+
+ Initial author: M. Lohwasser
+ contents/description: PNS parameters depending on bitrate and bandwidth
+
+******************************************************************************/
+
+#ifndef __PNSPARAM_H
+#define __PNSPARAM_H
+
+#include "aacenc.h"
+#include "common_fix.h"
+#include "psy_const.h"
+
+#define NUM_PNSINFOTAB 4
+#define PNS_TABLE_ERROR -1
+
+/* detection algorithm flags */
+#define USE_POWER_DISTRIBUTION (1<<0)
+#define USE_PSYCH_TONALITY (1<<1)
+#define USE_TNS_GAIN_THR (1<<2)
+#define USE_TNS_PNS (1<<3)
+#define JUST_LONG_WINDOW (1<<4)
+/* additional algorithm flags */
+#define IS_LOW_COMLEXITY (1<<5)
+
+typedef struct
+{
+ /* PNS start band */
+ short startSfb;
+
+ /* detection algorithm flags */
+ USHORT detectionAlgorithmFlags;
+
+ /* Parameters for detection */
+ FIXP_DBL refPower;
+ FIXP_DBL refTonality;
+ INT tnsGainThreshold;
+ INT tnsPNSGainThreshold;
+ INT minSfbWidth;
+ FIXP_SGL powDistPSDcurve[MAX_GROUPED_SFB];
+ FIXP_SGL gapFillThr;
+} NOISEPARAMS;
+
+int FDKaacEnc_lookUpPnsUse (int bitRate, int sampleRate, int numChan, const int isLC);
+
+/****** Definition of prototypes ******/
+
+AAC_ENCODER_ERROR FDKaacEnc_GetPnsParam(NOISEPARAMS *np,
+ INT bitRate,
+ INT sampleRate,
+ INT sfbCnt,
+ const INT *sfbOffset,
+ INT *usePns,
+ INT numChan,
+ const INT isLC);
+
+#endif
diff --git a/libAACenc/src/pre_echo_control.cpp b/libAACenc/src/pre_echo_control.cpp
new file mode 100644
index 0000000..dd34e22
--- /dev/null
+++ b/libAACenc/src/pre_echo_control.cpp
@@ -0,0 +1,108 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) copyright Fraunhofer IIS (1999)
+ 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.Werner
+ contents/description: Pre echo control
+
+ 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 "pre_echo_control.h"
+#include "psy_configuration.h"
+
+void FDKaacEnc_InitPreEchoControl(FIXP_DBL *RESTRICT pbThresholdNm1,
+ INT *calcPreEcho,
+ INT numPb,
+ FIXP_DBL *RESTRICT sfbPcmQuantThreshold,
+ INT *mdctScalenm1)
+{
+ *mdctScalenm1 = PCM_QUANT_THR_SCALE>>1;
+
+ FDKmemcpy(pbThresholdNm1, sfbPcmQuantThreshold, numPb*sizeof(FIXP_DBL));
+
+ *calcPreEcho = 1;
+}
+
+
+void FDKaacEnc_PreEchoControl(FIXP_DBL *RESTRICT pbThresholdNm1,
+ INT calcPreEcho,
+ INT numPb,
+ INT maxAllowedIncreaseFactor,
+ FIXP_SGL minRemainingThresholdFactor,
+ FIXP_DBL *RESTRICT pbThreshold,
+ INT mdctScale,
+ INT *mdctScalenm1)
+{
+ int i;
+ FIXP_DBL tmpThreshold1, tmpThreshold2;
+ int scaling;
+
+ /* If lastWindowSequence in previous frame was start- or stop-window,
+ skip preechocontrol calculation */
+ if (calcPreEcho==0) {
+ /* copy thresholds to internal memory */
+ FDKmemcpy(pbThresholdNm1, pbThreshold, numPb*sizeof(FIXP_DBL));
+ *mdctScalenm1 = mdctScale;
+ return;
+ }
+
+ if ( mdctScale > *mdctScalenm1 ) {
+ /* if current thresholds are downscaled more than the ones from the last block */
+ scaling = 2*(mdctScale-*mdctScalenm1);
+ for(i = 0; i < numPb; i++) {
+
+ /* multiplication with return data type fract ist equivalent to int multiplication */
+ FDK_ASSERT(scaling>=0);
+ tmpThreshold1 = maxAllowedIncreaseFactor * (pbThresholdNm1[i]>>scaling);
+ tmpThreshold2 = fMult(minRemainingThresholdFactor, pbThreshold[i]);
+
+ FIXP_DBL tmp = pbThreshold[i];
+
+ /* copy thresholds to internal memory */
+ pbThresholdNm1[i] = tmp;
+
+ tmp = fixMin(tmp, tmpThreshold1);
+ pbThreshold[i] = fixMax(tmp, tmpThreshold2);
+ }
+ }
+ else {
+ /* if thresholds of last block are more downscaled than the current ones */
+ scaling = 2*(*mdctScalenm1-mdctScale);
+ for(i = 0; i < numPb; i++) {
+
+ /* multiplication with return data type fract ist equivalent to int multiplication */
+ tmpThreshold1 = (maxAllowedIncreaseFactor>>1) * pbThresholdNm1[i];
+ tmpThreshold2 = fMult(minRemainingThresholdFactor, pbThreshold[i]);
+
+ /* copy thresholds to internal memory */
+ pbThresholdNm1[i] = pbThreshold[i];
+
+ FDK_ASSERT(scaling>=0);
+ if((pbThreshold[i]>>(scaling+1)) > tmpThreshold1) {
+ pbThreshold[i] = tmpThreshold1<<(scaling+1);
+ }
+ pbThreshold[i] = fixMax(pbThreshold[i], tmpThreshold2);
+ }
+ }
+
+ *mdctScalenm1 = mdctScale;
+}
diff --git a/libAACenc/src/pre_echo_control.h b/libAACenc/src/pre_echo_control.h
new file mode 100644
index 0000000..ded5057
--- /dev/null
+++ b/libAACenc/src/pre_echo_control.h
@@ -0,0 +1,51 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Pre echo control
+
+******************************************************************************/
+#ifndef __PRE_ECHO_CONTROL_H
+#define __PRE_ECHO_CONTROL_H
+
+#include "common_fix.h"
+
+
+void FDKaacEnc_InitPreEchoControl(FIXP_DBL *pbThresholdnm1,
+ INT *calcPreEcho,
+ INT numPb,
+ FIXP_DBL *sfbPcmQuantThreshold,
+ INT *mdctScalenm1);
+
+
+void FDKaacEnc_PreEchoControl(FIXP_DBL *pbThresholdNm1,
+ INT calcPreEcho,
+ INT numPb,
+ INT maxAllowedIncreaseFactor,
+ FIXP_SGL minRemainingThresholdFactor,
+ FIXP_DBL *pbThreshold,
+ INT mdctScale,
+ INT *mdctScalenm1);
+
+#endif
+
diff --git a/libAACenc/src/psy_configuration.cpp b/libAACenc/src/psy_configuration.cpp
new file mode 100644
index 0000000..731abf4
--- /dev/null
+++ b/libAACenc/src/psy_configuration.cpp
@@ -0,0 +1,594 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Psychoaccoustic configuration
+
+******************************************************************************/
+
+#include "psy_configuration.h"
+#include "adj_thr.h"
+#include "aacEnc_rom.h"
+
+#include "genericStds.h"
+
+#include "FDK_trigFcts.h"
+
+typedef struct{
+ LONG sampleRate;
+ const SFB_PARAM_LONG *paramLong;
+ const SFB_PARAM_SHORT *paramShort;
+}SFB_INFO_TAB;
+
+
+static const SFB_INFO_TAB sfbInfoTab[] = {
+ {8000, &p_FDKaacEnc_8000_long_1024, &p_FDKaacEnc_8000_short_128},
+ {11025, &p_FDKaacEnc_11025_long_1024, &p_FDKaacEnc_11025_short_128},
+ {12000, &p_FDKaacEnc_12000_long_1024, &p_FDKaacEnc_12000_short_128},
+ {16000, &p_FDKaacEnc_16000_long_1024, &p_FDKaacEnc_16000_short_128},
+ {22050, &p_FDKaacEnc_22050_long_1024, &p_FDKaacEnc_22050_short_128},
+ {24000, &p_FDKaacEnc_24000_long_1024, &p_FDKaacEnc_24000_short_128},
+ {32000, &p_FDKaacEnc_32000_long_1024, &p_FDKaacEnc_32000_short_128},
+ {44100, &p_FDKaacEnc_44100_long_1024, &p_FDKaacEnc_44100_short_128},
+ {48000, &p_FDKaacEnc_48000_long_1024, &p_FDKaacEnc_48000_short_128},
+ {64000, &p_FDKaacEnc_64000_long_1024, &p_FDKaacEnc_64000_short_128},
+ {88200, &p_FDKaacEnc_88200_long_1024, &p_FDKaacEnc_88200_short_128},
+ {96000, &p_FDKaacEnc_96000_long_1024, &p_FDKaacEnc_96000_short_128}
+
+};
+
+/* 22050 and 24000 Hz */
+static const SFB_PARAM_LONG p_22050_long_512 = {
+ 31,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 8, 8, 8, 12, 12, 12, 16, 20, 24,
+ 28, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32}
+};
+
+/* 32000 Hz */
+static const SFB_PARAM_LONG p_32000_long_512 = {
+ 37,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 8, 8, 8, 8, 8, 12,
+ 12, 12, 12, 16, 16, 16, 20, 24, 24, 28,
+ 32, 32, 32, 32, 32, 32, 32}
+};
+
+/* 44100 Hz */
+static const SFB_PARAM_LONG p_44100_long_512 = {
+ 36,
+ {4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 8, 8, 8, 8, 8,
+ 12, 12, 12, 12, 16, 20, 24, 28, 32, 32,
+ 32, 32, 32, 32, 32, 52}
+};
+
+static const SFB_INFO_TAB sfbInfoTabLD512[] = {
+ { 8000, &p_22050_long_512, NULL},
+ {11025, &p_22050_long_512, NULL},
+ {12000, &p_22050_long_512, NULL},
+ {16000, &p_22050_long_512, NULL},
+ {22050, &p_22050_long_512, NULL},
+ {24000, &p_22050_long_512, NULL},
+ {32000, &p_32000_long_512, NULL},
+ {44100, &p_44100_long_512, NULL},
+ {48000, &p_44100_long_512, NULL},
+ {64000, &p_44100_long_512, NULL},
+ {88200, &p_44100_long_512, NULL},
+ {96000, &p_44100_long_512, NULL},
+
+};
+
+
+/* 22050 and 24000 Hz */
+static const SFB_PARAM_LONG p_22050_long_480 = {
+ 30,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 8, 8, 8, 12, 12, 12, 16, 20, 24,
+ 28, 32, 32, 32, 32, 32, 32, 32, 32, 32}
+};
+
+/* 32000 Hz */
+static const SFB_PARAM_LONG p_32000_long_480 = {
+ 37,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 8, 8, 8, 8,
+ 8, 8, 12, 12, 12, 16, 16, 20, 24, 32,
+ 32, 32, 32, 32, 32, 32, 32}
+};
+
+/* 44100 Hz */
+static const SFB_PARAM_LONG p_44100_long_480 = {
+ 35,
+ { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 8, 8, 8, 8, 8, 12,
+ 12, 12, 12, 12, 16, 16, 24, 28, 32, 32,
+ 32, 32, 32, 32, 48}
+};
+
+static const SFB_INFO_TAB sfbInfoTabLD480[] = {
+ { 8000, &p_22050_long_480, NULL},
+ {11025, &p_22050_long_480, NULL},
+ {12000, &p_22050_long_480, NULL},
+ {16000, &p_22050_long_480, NULL},
+ {22050, &p_22050_long_480, NULL},
+ {24000, &p_22050_long_480, NULL},
+ {32000, &p_32000_long_480, NULL},
+ {44100, &p_44100_long_480, NULL},
+ {48000, &p_44100_long_480, NULL},
+ {64000, &p_44100_long_480, NULL},
+ {88200, &p_44100_long_480, NULL},
+ {96000, &p_44100_long_480, NULL},
+
+};
+
+/* Fixed point precision definitions */
+#define Q_BARCVAL (25)
+
+static AAC_ENCODER_ERROR FDKaacEnc_initSfbTable(LONG sampleRate, INT blockType, INT granuleLength, INT *sfbOffset, INT *sfbCnt)
+{
+ INT i, specStartOffset = 0;
+ const UCHAR* sfbWidth = NULL;
+ const SFB_INFO_TAB *sfbInfo = NULL;
+ int size;
+
+ /*
+ select table
+ */
+ switch(granuleLength) {
+ case 1024:
+ case 960:
+ sfbInfo = sfbInfoTab;
+ size = (INT)(sizeof(sfbInfoTab)/sizeof(SFB_INFO_TAB));
+ break;
+ case 512:
+ sfbInfo = sfbInfoTabLD512;
+ size = sizeof(sfbInfoTabLD512);
+ break;
+ case 480:
+ sfbInfo = sfbInfoTabLD480;
+ size = sizeof(sfbInfoTabLD480);
+ break;
+ default:
+ return AAC_ENC_INVALID_FRAME_LENGTH;
+ }
+
+ for(i = 0; i < size; i++){
+ if(sfbInfo[i].sampleRate == sampleRate){
+ switch(blockType){
+ case LONG_WINDOW:
+ case START_WINDOW:
+ case STOP_WINDOW:
+ sfbWidth = sfbInfo[i].paramLong->sfbWidth;
+ *sfbCnt = sfbInfo[i].paramLong->sfbCnt;
+ break;
+ case SHORT_WINDOW:
+ sfbWidth = sfbInfo[i].paramShort->sfbWidth;
+ *sfbCnt = sfbInfo[i].paramShort->sfbCnt;
+ granuleLength /= TRANS_FAC;
+ break;
+ }
+ break;
+ }
+ }
+ if (i == size) {
+ return AAC_ENC_UNSUPPORTED_SAMPLINGRATE;
+ }
+
+ /*
+ calc sfb offsets
+ */
+ for(i = 0; i < *sfbCnt; i++){
+ sfbOffset[i] = specStartOffset;
+ specStartOffset += sfbWidth[i];
+ if (specStartOffset >= granuleLength) {
+ i++;
+ break;
+ }
+ }
+ *sfbCnt = fixMin(i,*sfbCnt);
+ sfbOffset[*sfbCnt] = fixMin(specStartOffset,granuleLength);
+
+ return AAC_ENC_OK;
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_BarcLineValue
+ description: Calculates barc value for one frequency line
+ returns: barc value of line
+ input: number of lines in transform, index of line to check, Fs
+ output:
+
+*****************************************************************************/
+static FIXP_DBL FDKaacEnc_BarcLineValue(INT noOfLines, INT fftLine, LONG samplingFreq)
+{
+
+ FIXP_DBL FOURBY3EM4 = (FIXP_DBL)0x45e7b273; /* 4.0/3 * 0.0001 in q43 */
+ FIXP_DBL PZZZ76 = (FIXP_DBL)0x639d5e4a; /* 0.00076 in q41 */
+ FIXP_DBL ONE3P3 = (FIXP_DBL)0x35333333; /* 13.3 in q26 */
+ FIXP_DBL THREEP5 = (FIXP_DBL)0x1c000000; /* 3.5 in q27 */
+ FIXP_DBL INV480 = (FIXP_DBL)0x44444444; // 1/480 in q39
+
+ FIXP_DBL center_freq, x1, x2;
+ FIXP_DBL bvalFFTLine, atan1, atan2;
+
+ /* Theoritical maximum of center_freq (samp_freq*0.5) is 96khz * 0.5 = 48000 */
+ /* Theoritical maximum of x1 is 1.3333333e-4f * center_freq = 6.4, can keep in q28 */
+ /* Theoritical maximum of x2 is 0.00076f * center_freq = 36.48, can keep in q25 */
+
+ center_freq = fftLine * samplingFreq; /* q11 or q8 */
+
+ switch (noOfLines) {
+ case 1024:
+ center_freq = center_freq << 2; /* q13 */
+ break;
+ case 128:
+ center_freq = center_freq << 5; /* q13 */
+ break;
+ case 512:
+ center_freq = (fftLine * samplingFreq) << 3; // q13
+ break;
+ case 480:
+ center_freq = fMult(center_freq, INV480) << 4; // q13
+ break;
+ default:
+ center_freq = (FIXP_DBL)0;
+ }
+
+ x1 = fMult(center_freq, FOURBY3EM4); /* q13 * q43 - (DFRACT_BITS-1) = q25 */
+ x2 = fMult(center_freq, PZZZ76) << 2; /* q13 * q41 - (DFRACT_BITS-1) + 2 = q25 */
+
+ atan1 = fixp_atan(x1);
+ atan2 = fixp_atan(x2);
+
+ /* q25 (q26 * q30 - (DFRACT_BITS-1)) + q25 (q27 * q30 * q30) */
+ bvalFFTLine = fMult(ONE3P3, atan2) + fMult(THREEP5, fMult(atan1, atan1));
+ return(bvalFFTLine);
+
+}
+
+/*
+ do not consider energies below a certain input signal level,
+ i.e. of -96dB or 1 bit at 16 bit PCM resolution,
+ might need to be configurable to e.g. 24 bit PCM Input or a lower
+ resolution for low bit rates
+*/
+static void FDKaacEnc_InitMinPCMResolution(int numPb,
+ int *pbOffset,
+ FIXP_DBL *sfbPCMquantThreshold)
+{
+ /* PCM_QUANT_NOISE = FDKpow(10.0f, - 20.f / 10.0f) * ABS_LOW * NORM_PCM_ENERGY * FDKpow(2,PCM_QUANT_THR_SCALE) */
+ #define PCM_QUANT_NOISE ((FIXP_DBL)0x00547062)
+
+ for( int i = 0; i < numPb; i++ ) {
+ sfbPCMquantThreshold[i] = (pbOffset[i+1] - pbOffset[i]) * PCM_QUANT_NOISE;
+ }
+}
+
+static FIXP_DBL getMaskFactor(
+ const FIXP_DBL dbVal_fix,
+ const INT dbVal_e,
+ const FIXP_DBL ten_fix,
+ const INT ten_e
+ )
+{
+ INT q_msk;
+ FIXP_DBL mask_factor;
+
+ mask_factor = fPow(ten_fix, DFRACT_BITS-1-ten_e, -dbVal_fix, DFRACT_BITS-1-dbVal_e, &q_msk);
+ q_msk = fixMin(DFRACT_BITS-1,fixMax(-(DFRACT_BITS-1),q_msk));
+
+ if ( (q_msk>0) && (mask_factor>(FIXP_DBL)MAXVAL_DBL>>q_msk) ) {
+ mask_factor = (FIXP_DBL)MAXVAL_DBL;
+ }
+ else {
+ mask_factor = scaleValue(mask_factor, q_msk);
+ }
+
+ return (mask_factor);
+}
+
+static void FDKaacEnc_initSpreading(INT numPb,
+ FIXP_DBL *pbBarcValue,
+ FIXP_DBL *pbMaskLoFactor,
+ FIXP_DBL *pbMaskHiFactor,
+ FIXP_DBL *pbMaskLoFactorSprEn,
+ FIXP_DBL *pbMaskHiFactorSprEn,
+ const LONG bitrate,
+ const INT blockType)
+
+{
+ INT i;
+ FIXP_DBL MASKLOWSPREN, MASKHIGHSPREN;
+
+ FIXP_DBL MASKHIGH = (FIXP_DBL)0x30000000; /* 1.5 in q29 */
+ FIXP_DBL MASKLOW = (FIXP_DBL)0x60000000; /* 3.0 in q29 */
+ FIXP_DBL MASKLOWSPRENLONG = (FIXP_DBL)0x60000000; /* 3.0 in q29 */
+ FIXP_DBL MASKHIGHSPRENLONG = (FIXP_DBL)0x40000000; /* 2.0 in q29 */
+ FIXP_DBL MASKHIGHSPRENLONGLOWBR = (FIXP_DBL)0x30000000; /* 1.5 in q29 */
+ FIXP_DBL MASKLOWSPRENSHORT = (FIXP_DBL)0x40000000; /* 2.0 in q29 */
+ FIXP_DBL MASKHIGHSPRENSHORT = (FIXP_DBL)0x30000000; /* 1.5 in q29 */
+ FIXP_DBL TEN = (FIXP_DBL)0x50000000; /* 10.0 in q27 */
+
+ if (blockType != SHORT_WINDOW)
+ {
+ MASKLOWSPREN = MASKLOWSPRENLONG;
+ MASKHIGHSPREN = (bitrate>20000)?MASKHIGHSPRENLONG:MASKHIGHSPRENLONGLOWBR;
+ }
+ else
+ {
+ MASKLOWSPREN = MASKLOWSPRENSHORT;
+ MASKHIGHSPREN = MASKHIGHSPRENSHORT;
+ }
+
+ for(i=0; i<numPb; i++)
+ {
+ if (i > 0)
+ {
+ pbMaskHiFactor[i] = getMaskFactor(
+ fMult(MASKHIGH, (pbBarcValue[i] - pbBarcValue[i-1])), 23,
+ TEN, 27);
+
+ pbMaskLoFactor[i-1] = getMaskFactor(
+ fMult(MASKLOW, (pbBarcValue[i] - pbBarcValue[i-1])), 23,
+ TEN, 27);
+
+ pbMaskHiFactorSprEn[i] = getMaskFactor(
+ fMult(MASKHIGHSPREN, (pbBarcValue[i] - pbBarcValue[i-1])), 23,
+ TEN, 27);
+
+ pbMaskLoFactorSprEn[i-1] = getMaskFactor(
+ fMult(MASKLOWSPREN, (pbBarcValue[i] - pbBarcValue[i-1])), 23,
+ TEN, 27);
+ }
+ else
+ {
+ pbMaskHiFactor[i] = (FIXP_DBL)0;
+ pbMaskLoFactor[numPb-1] = (FIXP_DBL)0;
+ pbMaskHiFactorSprEn[i] = (FIXP_DBL)0;
+ pbMaskLoFactorSprEn[numPb-1] = (FIXP_DBL)0;
+ }
+ }
+}
+
+static void FDKaacEnc_initBarcValues(INT numPb,
+ INT *pbOffset,
+ INT numLines,
+ INT samplingFrequency,
+ FIXP_DBL *pbBval)
+{
+ INT i;
+ FIXP_DBL MAX_BARC = (FIXP_DBL)0x30000000; /* 24.0 in q25 */
+
+ for(i=0; i<numPb; i++)
+ {
+ FIXP_DBL v1, v2, cur_bark;
+ v1 = FDKaacEnc_BarcLineValue(numLines, pbOffset[i], samplingFrequency);
+ v2 = FDKaacEnc_BarcLineValue(numLines, pbOffset[i+1], samplingFrequency);
+ cur_bark = (v1 >> 1) + (v2 >> 1);
+ pbBval[i] = fixMin(cur_bark, MAX_BARC);
+ }
+}
+
+static void FDKaacEnc_initMinSnr(const LONG bitrate,
+ const LONG samplerate,
+ const INT numLines,
+ const INT *sfbOffset,
+ const INT sfbActive,
+ const INT blockType,
+ FIXP_DBL *sfbMinSnrLdData)
+{
+ INT sfb;
+
+ /* Fix conversion variables */
+ INT qbfac, qperwin, qdiv, qpeprt_const, qpeprt;
+ INT qtmp, qsnr, sfbWidth;
+
+ FIXP_DBL MAX_BARC = (FIXP_DBL)0x30000000; /* 24.0 in q25 */
+ FIXP_DBL MAX_BARCP1 = (FIXP_DBL)0x32000000; /* 25.0 in q25 */
+ FIXP_DBL BITS2PEFAC = (FIXP_DBL)0x4b851eb8; /* 1.18 in q30 */
+ FIXP_DBL PERS2P4 = (FIXP_DBL)0x624dd2f2; /* 0.024 in q36 */
+ FIXP_DBL ONEP5 = (FIXP_DBL)0x60000000; /* 1.5 in q30 */
+ FIXP_DBL MAX_SNR = (FIXP_DBL)0x33333333; /* 0.8 in q30 */
+ FIXP_DBL MIN_SNR = (FIXP_DBL)0x003126e9; /* 0.003 in q30 */
+
+ FIXP_DBL barcFactor, pePerWindow, pePart, barcWidth;
+ FIXP_DBL pePart_const, tmp, snr, one_qsnr, one_point5;
+
+ /* relative number of active barks */
+ barcFactor = fDivNorm(fixMin(FDKaacEnc_BarcLineValue(numLines, sfbOffset[sfbActive], samplerate), MAX_BARC),
+ MAX_BARCP1, &qbfac);
+
+ qbfac = DFRACT_BITS-1-qbfac;
+
+ pePerWindow = fDivNorm(bitrate, samplerate, &qperwin);
+ qperwin = DFRACT_BITS-1-qperwin;
+ pePerWindow = fMult(pePerWindow, BITS2PEFAC); qperwin = qperwin + 30 - (DFRACT_BITS-1);
+ pePerWindow = fMult(pePerWindow, PERS2P4); qperwin = qperwin + 36 - (DFRACT_BITS-1);
+
+ switch (numLines) {
+ case 1024:
+ qperwin = qperwin - 10;
+ break;
+ case 128:
+ qperwin = qperwin - 7;
+ break;
+ case 512:
+ qperwin = qperwin - 9;
+ break;
+ case 480:
+ qperwin = qperwin - 9;
+ pePerWindow = fMult(pePerWindow, FL2FXCONST_DBL(480.f/512.f));
+ break;
+ }
+
+ /* for short blocks it is assumed that more bits are available */
+ if (blockType == SHORT_WINDOW)
+ {
+ pePerWindow = fMult(pePerWindow, ONEP5);
+ qperwin = qperwin + 30 - (DFRACT_BITS-1);
+ }
+ pePart_const = fDivNorm(pePerWindow, barcFactor, &qdiv); qpeprt_const = qperwin - qbfac + DFRACT_BITS-1-qdiv;
+
+ for (sfb = 0; sfb < sfbActive; sfb++)
+ {
+ barcWidth = FDKaacEnc_BarcLineValue(numLines, sfbOffset[sfb+1], samplerate) -
+ FDKaacEnc_BarcLineValue(numLines, sfbOffset[sfb], samplerate);
+
+ /* adapt to sfb bands */
+ pePart = fMult(pePart_const, barcWidth); qpeprt = qpeprt_const + 25 - (DFRACT_BITS-1);
+
+ /* pe -> snr calculation */
+ sfbWidth = (sfbOffset[sfb+1] - sfbOffset[sfb]);
+ pePart = fDivNorm(pePart, sfbWidth, &qdiv); qpeprt += DFRACT_BITS-1-qdiv;
+
+ tmp = f2Pow(pePart, DFRACT_BITS-1-qpeprt, &qtmp);
+ qtmp = DFRACT_BITS-1-qtmp;
+
+ /* Subtract 1.5 */
+ qsnr = fixMin(qtmp, 30);
+ tmp = tmp >> (qtmp - qsnr);
+
+ if((30+1-qsnr) > (DFRACT_BITS-1))
+ one_point5 = (FIXP_DBL)0;
+ else
+ one_point5 = (FIXP_DBL)(ONEP5 >> (30+1-qsnr));
+
+ snr = (tmp>>1) - (one_point5); qsnr -= 1;
+
+ /* max(snr, 1.0) */
+ if(qsnr > 0)
+ one_qsnr = (FIXP_DBL)(1 << qsnr);
+ else
+ one_qsnr = (FIXP_DBL)0;
+
+ snr = fixMax(one_qsnr, snr);
+
+ /* 1/snr */
+ snr = fDivNorm(one_qsnr, snr, &qsnr);
+ qsnr = DFRACT_BITS-1-qsnr;
+ snr = (qsnr > 30)? (snr>>(qsnr-30)):snr;
+
+ /* upper limit is -1 dB */
+ snr = (snr > MAX_SNR) ? MAX_SNR : snr;
+
+ /* lower limit is -25 dB */
+ snr = (snr < MIN_SNR) ? MIN_SNR : snr;
+ snr = snr << 1;
+
+ sfbMinSnrLdData[sfb] = CalcLdData(snr);
+ }
+}
+
+AAC_ENCODER_ERROR FDKaacEnc_InitPsyConfiguration(INT bitrate,
+ INT samplerate,
+ INT bandwidth,
+ INT blocktype,
+ INT granuleLength,
+ INT useIS,
+ PSY_CONFIGURATION *psyConf,
+ FB_TYPE filterbank)
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ INT sfb;
+ FIXP_DBL sfbBarcVal[MAX_SFB];
+ const INT frameLengthLong = granuleLength;
+ const INT frameLengthShort = granuleLength/TRANS_FAC;
+
+ FDKmemclear(psyConf, sizeof(PSY_CONFIGURATION));
+ psyConf->granuleLength = granuleLength;
+ psyConf->filterbank = filterbank;
+
+ psyConf->allowIS = (useIS) && ( (bitrate/bandwidth) < 5 );
+
+ /* init sfb table */
+ ErrorStatus = FDKaacEnc_initSfbTable(samplerate,blocktype,granuleLength,psyConf->sfbOffset,&psyConf->sfbCnt);
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ /* calculate barc values for each pb */
+ FDKaacEnc_initBarcValues(psyConf->sfbCnt,
+ psyConf->sfbOffset,
+ psyConf->sfbOffset[psyConf->sfbCnt],
+ samplerate,
+ sfbBarcVal);
+
+ FDKaacEnc_InitMinPCMResolution(psyConf->sfbCnt,
+ psyConf->sfbOffset,
+ psyConf->sfbPcmQuantThreshold);
+
+ /* calculate spreading function */
+ FDKaacEnc_initSpreading(psyConf->sfbCnt,
+ sfbBarcVal,
+ psyConf->sfbMaskLowFactor,
+ psyConf->sfbMaskHighFactor,
+ psyConf->sfbMaskLowFactorSprEn,
+ psyConf->sfbMaskHighFactorSprEn,
+ bitrate,
+ blocktype);
+
+ /* init ratio */
+
+ psyConf->maxAllowedIncreaseFactor = 2; /* integer */
+ psyConf->minRemainingThresholdFactor = (FIXP_SGL)0x0148; /* FL2FXCONST_SGL(0.01f); */ /* fract */
+
+ psyConf->clipEnergy = (FIXP_DBL)0x773593ff; /* FL2FXCONST_DBL(1.0e9*NORM_PCM_ENERGY); */
+
+ if (blocktype!=SHORT_WINDOW) {
+ psyConf->lowpassLine = (INT)((2*bandwidth*frameLengthLong)/samplerate);
+ psyConf->lowpassLineLFE = LFE_LOWPASS_LINE;
+ }
+ else {
+ psyConf->lowpassLine = (INT)((2*bandwidth*frameLengthShort)/samplerate);
+ psyConf->lowpassLineLFE = 0; /* LFE only in lonf blocks */
+ /* psyConf->clipEnergy /= (TRANS_FAC * TRANS_FAC); */
+ psyConf->clipEnergy >>= 6;
+ }
+
+ for (sfb = 0; sfb < psyConf->sfbCnt; sfb++){
+ if (psyConf->sfbOffset[sfb] >= psyConf->lowpassLine)
+ break;
+ }
+ psyConf->sfbActive = sfb;
+
+ for (sfb = 0; sfb < psyConf->sfbCnt; sfb++){
+ if (psyConf->sfbOffset[sfb] >= psyConf->lowpassLineLFE)
+ break;
+ }
+ psyConf->sfbActiveLFE = sfb;
+
+ /* calculate minSnr */
+ FDKaacEnc_initMinSnr(bitrate,
+ samplerate,
+ psyConf->sfbOffset[psyConf->sfbCnt],
+ psyConf->sfbOffset,
+ psyConf->sfbActive,
+ blocktype,
+ psyConf->sfbMinSnrLdData);
+
+ return AAC_ENC_OK;
+}
+
diff --git a/libAACenc/src/psy_configuration.h b/libAACenc/src/psy_configuration.h
new file mode 100644
index 0000000..aa60500
--- /dev/null
+++ b/libAACenc/src/psy_configuration.h
@@ -0,0 +1,102 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Psychoaccoustic configuration
+
+******************************************************************************/
+#ifndef _PSY_CONFIGURATION_H
+#define _PSY_CONFIGURATION_H
+
+
+#include "aacenc.h"
+#include "common_fix.h"
+
+#include "psy_const.h"
+#include "aacenc_tns.h"
+#include "aacenc_pns.h"
+
+#define THR_SHIFTBITS 4
+#define PCM_QUANT_THR_SCALE 16
+
+#define C_RATIO (FIXP_DBL)0x02940a10 /* FL2FXCONST_DBL(0.001258925f) << THR_SHIFTBITS; */ /* pow(10.0f, -(29.0f/10.0f)) */
+
+typedef struct{
+
+ INT sfbCnt; /* number of existing sf bands */
+ INT sfbActive; /* number of sf bands containing energy after lowpass */
+ INT sfbActiveLFE;
+ INT sfbOffset[MAX_SFB+1];
+
+ INT filterbank; /* LC, LD or ELD */
+
+ FIXP_DBL sfbPcmQuantThreshold[MAX_SFB];
+
+ INT maxAllowedIncreaseFactor; /* preecho control */
+ FIXP_SGL minRemainingThresholdFactor;
+
+ INT lowpassLine;
+ INT lowpassLineLFE;
+ FIXP_DBL clipEnergy; /* for level dependend tmn */
+
+ FIXP_DBL sfbMaskLowFactor[MAX_SFB];
+ FIXP_DBL sfbMaskHighFactor[MAX_SFB];
+
+ FIXP_DBL sfbMaskLowFactorSprEn[MAX_SFB];
+ FIXP_DBL sfbMaskHighFactorSprEn[MAX_SFB];
+
+ FIXP_DBL sfbMinSnrLdData[MAX_SFB]; /* minimum snr (formerly known as bmax) */
+
+ TNS_CONFIG tnsConf;
+ PNS_CONFIG pnsConf;
+
+ INT granuleLength;
+ INT allowIS;
+
+}PSY_CONFIGURATION;
+
+
+typedef struct{
+ UCHAR sfbCnt; /* Number of scalefactor bands */
+ UCHAR sfbWidth[MAX_SFB_LONG]; /* Width of scalefactor bands for long blocks */
+}SFB_PARAM_LONG;
+
+typedef struct{
+ UCHAR sfbCnt; /* Number of scalefactor bands */
+ UCHAR sfbWidth[MAX_SFB_SHORT]; /* Width of scalefactor bands for short blocks */
+}SFB_PARAM_SHORT;
+
+
+AAC_ENCODER_ERROR FDKaacEnc_InitPsyConfiguration(INT bitrate,
+ INT samplerate,
+ INT bandwidth,
+ INT blocktype,
+ INT granuleLength,
+ INT useIS,
+ PSY_CONFIGURATION *psyConf,
+ FB_TYPE filterbank);
+
+#endif /* _PSY_CONFIGURATION_H */
+
+
+
diff --git a/libAACenc/src/psy_const.h b/libAACenc/src/psy_const.h
new file mode 100644
index 0000000..d9d59d9
--- /dev/null
+++ b/libAACenc/src/psy_const.h
@@ -0,0 +1,99 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Global psychoaccoustic constants
+
+******************************************************************************/
+#ifndef _PSYCONST_H
+#define _PSYCONST_H
+
+
+#define TRUE 1
+#define FALSE 0
+
+ #define TRANS_FAC 8 /* encoder short long ratio */
+
+#define FRAME_MAXLEN_SHORT ((1024)/TRANS_FAC)
+#define FRAME_LEN_SHORT_128 ((1024)/TRANS_FAC)
+#define FRAME_LEN_SHORT_120 (FRAME_LEN_LONG_960/TRANS_FAC)
+
+/* Filterbank type*/
+enum FB_TYPE {
+ FB_LC = 0,
+ FB_LD = 1,
+ FB_ELD = 2
+};
+
+/* Block types */
+#define N_BLOCKTYPES 6
+enum
+{
+ LONG_WINDOW = 0,
+ START_WINDOW,
+ SHORT_WINDOW,
+ STOP_WINDOW,
+ _LOWOV_WINDOW, /* Do not use this block type out side of block_switch.cpp */
+ WRONG_WINDOW
+};
+
+/* Window shapes */
+enum
+{
+ SINE_WINDOW = 0,
+ KBD_WINDOW = 1,
+ LOL_WINDOW = 2 /* Low OverLap window shape for AAC-LD */
+};
+
+/*
+ MS stuff
+*/
+enum
+{
+ SI_MS_MASK_NONE = 0,
+ SI_MS_MASK_SOME = 1,
+ SI_MS_MASK_ALL = 2
+};
+
+
+ #define MAX_NO_OF_GROUPS 4
+ #define MAX_SFB_LONG 51 /* 51 for a memory optimized implementation, maybe 64 for convenient debugging */
+ #define MAX_SFB_SHORT 15 /* 15 for a memory optimized implementation, maybe 16 for convenient debugging */
+
+#define MAX_SFB (MAX_SFB_SHORT > MAX_SFB_LONG ? MAX_SFB_SHORT : MAX_SFB_LONG) /* = 51 */
+#define MAX_GROUPED_SFB (MAX_NO_OF_GROUPS*MAX_SFB_SHORT > MAX_SFB_LONG ? \
+ MAX_NO_OF_GROUPS*MAX_SFB_SHORT : MAX_SFB_LONG) /* = 60 */
+
+#define MAX_INPUT_BUFFER_SIZE (2*(1024)) /* 2048 */
+
+
+#define PCM_LEVEL 1.0f
+#define NORM_PCM (PCM_LEVEL/32768.0f)
+#define NORM_PCM_ENERGY (NORM_PCM*NORM_PCM)
+#define LOG_NORM_PCM -15
+
+#define TNS_PREDGAIN_SCALE (1000)
+
+#define LFE_LOWPASS_LINE 12
+
+#endif /* _PSYCONST_H */
diff --git a/libAACenc/src/psy_data.h b/libAACenc/src/psy_data.h
new file mode 100644
index 0000000..af3cde8
--- /dev/null
+++ b/libAACenc/src/psy_data.h
@@ -0,0 +1,89 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Psychoaccoustic data
+
+******************************************************************************/
+#ifndef _PSY_DATA_H
+#define _PSY_DATA_H
+
+
+#include "block_switch.h"
+
+/* Be careful with MAX_SFB_LONG as length of the .Long arrays.
+ * sfbEnergy.Long and sfbEnergyMS.Long and sfbThreshold.Long are used as a temporary storage for the regrouped
+ * short energies and thresholds between FDKaacEnc_groupShortData() and BuildInterface() in FDKaacEnc_psyMain().
+ * The space required for this is MAX_GROUPED_SFB ( = MAX_NO_OF_GROUPS*MAX_SFB_SHORT ).
+ * However, this is not important if unions are used (which is not possible with pfloat). */
+
+typedef shouldBeUnion{
+ FIXP_DBL Long[MAX_GROUPED_SFB];
+ FIXP_DBL Short[TRANS_FAC][MAX_SFB_SHORT];
+}SFB_THRESHOLD;
+
+typedef shouldBeUnion{
+ FIXP_DBL Long[MAX_GROUPED_SFB];
+ FIXP_DBL Short[TRANS_FAC][MAX_SFB_SHORT];
+}SFB_ENERGY;
+
+typedef shouldBeUnion{
+ FIXP_DBL Long[MAX_GROUPED_SFB];
+ FIXP_DBL Short[TRANS_FAC][MAX_SFB_SHORT];
+}SFB_LD_ENERGY;
+
+typedef shouldBeUnion{
+ INT Long[MAX_GROUPED_SFB];
+ INT Short[TRANS_FAC][MAX_SFB_SHORT];
+}SFB_MAX_SCALE;
+
+
+typedef struct{
+ INT_PCM* psyInputBuffer;
+ FIXP_DBL RESTRICT overlapAddBuffer[1024];
+
+ BLOCK_SWITCHING_CONTROL blockSwitchingControl; /* block switching */
+ FIXP_DBL sfbThresholdnm1[MAX_SFB]; /* FDKaacEnc_PreEchoControl */
+ INT mdctScalenm1; /* scale of last block's mdct (FDKaacEnc_PreEchoControl) */
+ INT calcPreEcho;
+ INT isLFE;
+}PSY_STATIC;
+
+
+typedef struct{
+ FIXP_DBL *mdctSpectrum;
+ SFB_THRESHOLD sfbThreshold; /* adapt */
+ SFB_ENERGY sfbEnergy; /* sfb energies */
+ SFB_LD_ENERGY sfbEnergyLdData; /* sfb energies in ldData format */
+ SFB_MAX_SCALE sfbMaxScaleSpec;
+ SFB_ENERGY sfbEnergyMS; /* mid/side sfb energies */
+ FIXP_DBL sfbEnergyMSLdData[MAX_GROUPED_SFB]; /* mid/side sfb energies in ldData format */
+ SFB_ENERGY sfbSpreadEnergy;
+ INT mdctScale; /* exponent of data in mdctSpectrum */
+ INT groupedSfbOffset[MAX_GROUPED_SFB+1];
+ INT sfbActive;
+ INT lowpassLine;
+}PSY_DATA;
+
+
+#endif /* _PSY_DATA_H */
diff --git a/libAACenc/src/psy_main.cpp b/libAACenc/src/psy_main.cpp
new file mode 100644
index 0000000..bfc8b3b
--- /dev/null
+++ b/libAACenc/src/psy_main.cpp
@@ -0,0 +1,1338 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Psychoaccoustic major function block
+
+******************************************************************************/
+
+#include "psy_const.h"
+
+#include "block_switch.h"
+#include "transform.h"
+#include "spreading.h"
+#include "pre_echo_control.h"
+#include "band_nrg.h"
+#include "psy_configuration.h"
+#include "psy_data.h"
+#include "ms_stereo.h"
+#include "interface.h"
+#include "psy_main.h"
+#include "grp_data.h"
+#include "tns_func.h"
+#include "pns_func.h"
+#include "tonality.h"
+#include "aacEnc_ram.h"
+#include "intensity.h"
+
+
+#ifdef PSY_MAIN_DEBUG_INFO
+FDKFILE *fSpectrumOut;
+#endif
+
+/* blending to reduce gibbs artifacts */
+#define FADE_OUT_LEN 6
+static const FIXP_DBL fadeOutFactor[FADE_OUT_LEN] = {1840644096, 1533870080, 1227096064, 920322048, 613548032, 306774016};
+
+/* forward definitions */
+
+
+static inline int isLowDelay( AUDIO_OBJECT_TYPE aot )
+{
+ return (aot==AOT_ER_AAC_LD || aot==AOT_ER_AAC_ELD);
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_PsyNew
+ description: allocates memory for psychoacoustic
+ returns: an error code
+ input: pointer to a psych handle
+
+*****************************************************************************/
+AAC_ENCODER_ERROR FDKaacEnc_PsyNew(PSY_INTERNAL **phpsy,
+ const INT nElements,
+ const INT nChannels
+ ,UCHAR *dynamic_RAM
+ )
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ PSY_INTERNAL *hPsy;
+ INT i;
+
+ hPsy = GetRam_aacEnc_PsyInternal();
+ *phpsy = hPsy;
+ if (hPsy == NULL) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto bail;
+ }
+
+ for (i=0; i<nElements; i++) {
+ /* PSY_ELEMENT */
+ hPsy->psyElement[i] = GetRam_aacEnc_PsyElement(i);
+ if (hPsy->psyElement[i] == NULL) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto bail;
+ }
+ }
+
+ for (i=0; i<nChannels; i++) {
+ /* PSY_STATIC */
+ hPsy->pStaticChannels[i] = GetRam_aacEnc_PsyStatic(i);
+ if (hPsy->pStaticChannels[i]==NULL) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto bail;
+ }
+ /* AUDIO INPUT BUFFER */
+ hPsy->pStaticChannels[i]->psyInputBuffer = GetRam_aacEnc_PsyInputBuffer(i);
+ if (hPsy->pStaticChannels[i]->psyInputBuffer==NULL) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto bail;
+ }
+ }
+
+ /* reusable psych memory */
+ hPsy->psyDynamic = GetRam_aacEnc_PsyDynamic(0, dynamic_RAM);
+
+ return AAC_ENC_OK;
+
+bail:
+ FDKaacEnc_PsyClose(phpsy, NULL);
+
+ return ErrorStatus;
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_PsyOutNew
+ description: allocates memory for psyOut struc
+ returns: an error code
+ input: pointer to a psych handle
+
+*****************************************************************************/
+AAC_ENCODER_ERROR FDKaacEnc_PsyOutNew(PSY_OUT **phpsyOut,
+ const INT nElements,
+ const INT nChannels,
+ const INT nSubFrames
+ ,UCHAR *dynamic_RAM
+ )
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ int n, i;
+ int elInc = 0, chInc = 0;
+
+ for (n=0; n<nSubFrames; n++) {
+ phpsyOut[n] = GetRam_aacEnc_PsyOut(n);
+
+ if (phpsyOut[n] == NULL) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto bail;
+ }
+
+ for (i=0; i<nChannels; i++) {
+ phpsyOut[n]->pPsyOutChannels[i] = GetRam_aacEnc_PsyOutChannel(chInc++);
+ }
+
+ for (i=0; i<nElements; i++) {
+ phpsyOut[n]->psyOutElement[i] = GetRam_aacEnc_PsyOutElements(elInc++);
+ if (phpsyOut[n]->psyOutElement[i] == NULL) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto bail;
+ }
+ }
+ } /* nSubFrames */
+
+ return AAC_ENC_OK;
+
+bail:
+ FDKaacEnc_PsyClose(NULL, phpsyOut);
+ return ErrorStatus;
+}
+
+
+AAC_ENCODER_ERROR FDKaacEnc_psyInitStates(PSY_INTERNAL *hPsy,
+ PSY_STATIC* psyStatic,
+ AUDIO_OBJECT_TYPE audioObjectType)
+{
+ /* init input buffer */
+ FDKmemclear(psyStatic->psyInputBuffer, MAX_INPUT_BUFFER_SIZE*sizeof(INT_PCM));
+
+ FDKaacEnc_InitBlockSwitching(&psyStatic->blockSwitchingControl,
+ isLowDelay(audioObjectType)
+ );
+
+ return AAC_ENC_OK;
+}
+
+
+AAC_ENCODER_ERROR FDKaacEnc_psyInit(PSY_INTERNAL *hPsy,
+ PSY_OUT **phpsyOut,
+ const INT nSubFrames,
+ const INT nMaxChannels,
+ const AUDIO_OBJECT_TYPE audioObjectType,
+ CHANNEL_MAPPING *cm)
+{
+ AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK;
+ int i, ch, n, chInc = 0, resetChannels = 3;
+
+ if ( (nMaxChannels>2) && (cm->nChannels==2) ) {
+ chInc = 1;
+ FDKaacEnc_psyInitStates(hPsy, hPsy->pStaticChannels[0], audioObjectType);
+ }
+
+ if ( (nMaxChannels==2) ) {
+ resetChannels = 0;
+ }
+
+ for (i=0; i<cm->nElements; i++) {
+ for (ch=0; ch<cm->elInfo[i].nChannelsInEl; ch++) {
+ if (cm->elInfo[i].elType!=ID_LFE) {
+ hPsy->psyElement[i]->psyStatic[ch] = hPsy->pStaticChannels[chInc];
+ if (chInc>=resetChannels) {
+ FDKaacEnc_psyInitStates(hPsy, hPsy->psyElement[i]->psyStatic[ch], audioObjectType);
+ }
+ hPsy->psyElement[i]->psyStatic[ch]->isLFE = 0;
+ }
+ else {
+ hPsy->psyElement[i]->psyStatic[ch] = hPsy->pStaticChannels[nMaxChannels-1];
+ hPsy->psyElement[i]->psyStatic[ch]->isLFE = 1;
+ }
+ chInc++;
+ }
+ }
+
+ for (n=0; n<nSubFrames; n++) {
+ chInc = 0;
+ for (i=0; i<cm->nElements; i++) {
+ for (ch=0; ch<cm->elInfo[i].nChannelsInEl; ch++) {
+ phpsyOut[n]->psyOutElement[i]->psyOutChannel[ch] = phpsyOut[n]->pPsyOutChannels[chInc++];
+ }
+ }
+ }
+
+ return ErrorStatus;
+}
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_psyMainInit
+ description: initializes psychoacoustic
+ returns: an error code
+
+*****************************************************************************/
+
+AAC_ENCODER_ERROR FDKaacEnc_psyMainInit(PSY_INTERNAL *hPsy,
+ AUDIO_OBJECT_TYPE audioObjectType,
+ CHANNEL_MAPPING *cm,
+ INT sampleRate,
+ INT granuleLength,
+ INT bitRate,
+ INT tnsMask,
+ INT bandwidth,
+ INT usePns,
+ INT useIS,
+ UINT syntaxFlags,
+ ULONG initFlags)
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ int i, ch;
+ int channelsEff = cm->nChannelsEff;
+ int tnsChannels = 0;
+ FB_TYPE filterBank;
+
+#ifdef PSY_MAIN_DEBUG_INFO
+ fSpectrumOut = FDKfopen("psy_main_spectrum2.raw", "wb");
+#endif
+
+ switch(FDKaacEnc_GetMonoStereoMode(cm->encMode)) {
+ /* ... and map to tnsChannels */
+ case EL_MODE_MONO: tnsChannels = 1; break;
+ case EL_MODE_STEREO: tnsChannels = 2; break;
+ default: tnsChannels = 0;
+ }
+
+ switch (audioObjectType)
+ {
+ default: filterBank = FB_LC; break;
+ case AOT_ER_AAC_LD: filterBank = FB_LD; break;
+ case AOT_ER_AAC_ELD: filterBank = FB_ELD; break;
+ }
+
+ hPsy->granuleLength = granuleLength;
+
+ ErrorStatus = FDKaacEnc_InitPsyConfiguration(bitRate/channelsEff, sampleRate, bandwidth, LONG_WINDOW, hPsy->granuleLength, useIS, &(hPsy->psyConf[0]), filterBank);
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ ErrorStatus = FDKaacEnc_InitTnsConfiguration(
+ (bitRate*tnsChannels)/channelsEff,
+ sampleRate,
+ tnsChannels,
+ LONG_WINDOW,
+ hPsy->granuleLength,
+ (syntaxFlags&AC_SBR_PRESENT)?1:0,
+ &(hPsy->psyConf[0].tnsConf),
+ &hPsy->psyConf[0],
+ (INT)(tnsMask&2),
+ (INT)(tnsMask&8) );
+
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ if (granuleLength > 512) {
+ ErrorStatus = FDKaacEnc_InitPsyConfiguration(bitRate/channelsEff, sampleRate, bandwidth, SHORT_WINDOW, hPsy->granuleLength, useIS, &hPsy->psyConf[1], filterBank);
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ ErrorStatus = FDKaacEnc_InitTnsConfiguration(
+ (bitRate*tnsChannels)/channelsEff,
+ sampleRate,
+ tnsChannels,
+ SHORT_WINDOW,
+ hPsy->granuleLength,
+ (syntaxFlags&AC_SBR_PRESENT)?1:0,
+ &hPsy->psyConf[1].tnsConf,
+ &hPsy->psyConf[1],
+ (INT)(tnsMask&1),
+ (INT)(tnsMask&4) );
+
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ }
+
+
+ for (i=0; i<cm->nElements; i++) {
+ for (ch=0; ch<cm->elInfo[i].nChannelsInEl; ch++) {
+ if (initFlags) {
+ /* reset states */
+ FDKaacEnc_psyInitStates(hPsy, hPsy->psyElement[i]->psyStatic[ch], audioObjectType);
+ }
+
+ FDKaacEnc_InitPreEchoControl(hPsy->psyElement[i]->psyStatic[ch]->sfbThresholdnm1,
+ &hPsy->psyElement[i]->psyStatic[ch]->calcPreEcho,
+ hPsy->psyConf[0].sfbCnt,
+ hPsy->psyConf[0].sfbPcmQuantThreshold,
+ &hPsy->psyElement[i]->psyStatic[ch]->mdctScalenm1);
+ }
+ }
+
+ ErrorStatus = FDKaacEnc_InitPnsConfiguration(&hPsy->psyConf[0].pnsConf,
+ bitRate/channelsEff,
+ sampleRate,
+ usePns,
+ hPsy->psyConf[0].sfbCnt,
+ hPsy->psyConf[0].sfbOffset,
+ cm->elInfo[0].nChannelsInEl,
+ (hPsy->psyConf[0].filterbank == FB_LC));
+ if (ErrorStatus != AAC_ENC_OK)
+ return ErrorStatus;
+
+ ErrorStatus = FDKaacEnc_InitPnsConfiguration(&hPsy->psyConf[1].pnsConf,
+ bitRate/channelsEff,
+ sampleRate,
+ usePns,
+ hPsy->psyConf[1].sfbCnt,
+ hPsy->psyConf[1].sfbOffset,
+ cm->elInfo[1].nChannelsInEl,
+ (hPsy->psyConf[1].filterbank == FB_LC));
+ return ErrorStatus;
+}
+
+
+static
+void FDKaacEnc_deinterleaveInputBuffer(INT_PCM *pOutputSamples,
+ INT_PCM *pInputSamples,
+ INT nSamples,
+ INT nChannels)
+{
+ INT k;
+ /* deinterlave input samples and write to output buffer */
+ for (k=0; k<nSamples; k++) {
+ pOutputSamples[k] = pInputSamples[k*nChannels];
+ }
+}
+
+
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_psyMain
+ description: psychoacoustic
+ returns: an error code
+
+ This function assumes that enough input data is in the modulo buffer.
+
+*****************************************************************************/
+
+AAC_ENCODER_ERROR FDKaacEnc_psyMain(INT channels,
+ PSY_ELEMENT *psyElement,
+ PSY_DYNAMIC *psyDynamic,
+ PSY_CONFIGURATION *psyConf,
+ PSY_OUT_ELEMENT *RESTRICT psyOutElement,
+ INT_PCM *pInput,
+ INT *chIdx,
+ INT totalChannels
+ )
+{
+ INT commonWindow = 1;
+ INT maxSfbPerGroup[(2)];
+ INT mdctSpectrum_e;
+ INT ch; /* counts through channels */
+ INT w; /* counts through windows */
+ INT sfb; /* counts through scalefactor bands */
+ INT line; /* counts through lines */
+
+ PSY_CONFIGURATION *RESTRICT hPsyConfLong = &psyConf[0];
+ PSY_CONFIGURATION *RESTRICT hPsyConfShort = &psyConf[1];
+ PSY_OUT_CHANNEL **RESTRICT psyOutChannel = psyOutElement->psyOutChannel;
+ FIXP_SGL sfbTonality[(2)][MAX_SFB_LONG];
+
+ PSY_STATIC **RESTRICT psyStatic = psyElement->psyStatic;
+
+ PSY_DATA *RESTRICT psyData[(2)];
+ TNS_DATA *RESTRICT tnsData[(2)];
+ PNS_DATA *RESTRICT pnsData[(2)];
+
+ INT zeroSpec = TRUE; /* means all spectral lines are zero */
+
+ INT blockSwitchingOffset;
+
+ PSY_CONFIGURATION *RESTRICT hThisPsyConf[(2)];
+ INT windowLength[(2)];
+ INT nWindows[(2)];
+ INT wOffset;
+
+ INT maxSfb[(2)];
+ INT *pSfbMaxScaleSpec[(2)];
+ FIXP_DBL *pSfbEnergy[(2)];
+ FIXP_DBL *pSfbSpreadEnergy[(2)];
+ FIXP_DBL *pSfbEnergyLdData[(2)];
+ FIXP_DBL *pSfbEnergyMS[(2)];
+ FIXP_DBL *pSfbThreshold[(2)];
+
+ INT isShortWindow[(2)];
+
+
+ if (hPsyConfLong->filterbank == FB_LC) {
+ blockSwitchingOffset = psyConf->granuleLength + (9*psyConf->granuleLength/(2*TRANS_FAC));
+ } else {
+ blockSwitchingOffset = psyConf->granuleLength;
+ }
+
+ for(ch = 0; ch < channels; ch++)
+ {
+ psyData[ch] = &psyDynamic->psyData[ch];
+ tnsData[ch] = &psyDynamic->tnsData[ch];
+ pnsData[ch] = &psyDynamic->pnsData[ch];
+
+ psyData[ch]->mdctSpectrum = psyOutChannel[ch]->mdctSpectrum;
+ }
+
+ /* block switching */
+ if (hPsyConfLong->filterbank != FB_ELD)
+ {
+ int err;
+
+ for(ch = 0; ch < channels; ch++)
+ {
+ C_ALLOC_SCRATCH_START(timeSignal, INT_PCM, (1024));
+ psyStatic[ch]->blockSwitchingControl.timeSignal = timeSignal;
+
+ /* deinterleave input data and use for block switching */
+ FDKaacEnc_deinterleaveInputBuffer( psyStatic[ch]->blockSwitchingControl.timeSignal,
+ &pInput[chIdx[ch]],
+ psyConf->granuleLength,
+ totalChannels);
+
+
+ FDKaacEnc_BlockSwitching (&psyStatic[ch]->blockSwitchingControl,
+ psyConf->granuleLength
+ ,psyStatic[ch]->isLFE
+ );
+
+
+ /* fill up internal input buffer, to 2xframelength samples */
+ FDKmemcpy(psyStatic[ch]->psyInputBuffer+blockSwitchingOffset,
+ psyStatic[ch]->blockSwitchingControl.timeSignal,
+ (2*psyConf->granuleLength-blockSwitchingOffset)*sizeof(INT_PCM));
+
+ C_ALLOC_SCRATCH_END(timeSignal, INT_PCM, (1024));
+ }
+
+ /* synch left and right block type */
+ err = FDKaacEnc_SyncBlockSwitching(&psyStatic[0]->blockSwitchingControl,
+ &psyStatic[1]->blockSwitchingControl,
+ channels,
+ commonWindow);
+
+ if (err) {
+ return AAC_ENC_UNSUPPORTED_AOT; /* mixed up LC and LD */
+ }
+
+ }
+ else {
+ for(ch = 0; ch < channels; ch++)
+ {
+ /* deinterleave input data and use for block switching */
+ FDKaacEnc_deinterleaveInputBuffer( psyStatic[ch]->psyInputBuffer + blockSwitchingOffset,
+ &pInput[chIdx[ch]],
+ psyConf->granuleLength,
+ totalChannels);
+ }
+ }
+
+ for(ch = 0; ch < channels; ch++)
+ isShortWindow[ch]=(psyStatic[ch]->blockSwitchingControl.lastWindowSequence == SHORT_WINDOW);
+
+ /* set parameters according to window length */
+ for(ch = 0; ch < channels; ch++)
+ {
+ if(isShortWindow[ch]) {
+ hThisPsyConf[ch] = hPsyConfShort;
+ windowLength[ch] = psyConf->granuleLength/TRANS_FAC;
+ nWindows[ch] = TRANS_FAC;
+ maxSfb[ch] = MAX_SFB_SHORT;
+
+ pSfbMaxScaleSpec[ch] = psyData[ch]->sfbMaxScaleSpec.Short[0];
+ pSfbEnergy[ch] = psyData[ch]->sfbEnergy.Short[0];
+ pSfbSpreadEnergy[ch] = psyData[ch]->sfbSpreadEnergy.Short[0];
+ pSfbEnergyLdData[ch] = psyData[ch]->sfbEnergyLdData.Short[0];
+ pSfbEnergyMS[ch] = psyData[ch]->sfbEnergyMS.Short[0];
+ pSfbThreshold[ch] = psyData[ch]->sfbThreshold.Short[0];
+
+ } else
+ {
+ hThisPsyConf[ch] = hPsyConfLong;
+ windowLength[ch] = psyConf->granuleLength;
+ nWindows[ch] = 1;
+ maxSfb[ch] = MAX_GROUPED_SFB;
+
+ pSfbMaxScaleSpec[ch] = psyData[ch]->sfbMaxScaleSpec.Long;
+ pSfbEnergy[ch] = psyData[ch]->sfbEnergy.Long;
+ pSfbSpreadEnergy[ch] = psyData[ch]->sfbSpreadEnergy.Long;
+ pSfbEnergyLdData[ch] = psyData[ch]->sfbEnergyLdData.Long;
+ pSfbEnergyMS[ch] = psyData[ch]->sfbEnergyMS.Long;
+ pSfbThreshold[ch] = psyData[ch]->sfbThreshold.Long;
+ }
+ }
+
+ /* Transform and get mdctScaling for all channels and windows. */
+ for(ch = 0; ch < channels; ch++)
+ {
+ /* update number of active bands */
+ if (psyStatic[ch]->isLFE) {
+ psyData[ch]->sfbActive = hThisPsyConf[ch]->sfbActiveLFE;
+ psyData[ch]->lowpassLine = hThisPsyConf[ch]->lowpassLineLFE;
+ } else
+ {
+ psyData[ch]->sfbActive = hThisPsyConf[ch]->sfbActive;
+ psyData[ch]->lowpassLine = hThisPsyConf[ch]->lowpassLine;
+ }
+
+ for(w = 0; w < nWindows[ch]; w++) {
+
+ wOffset = w*windowLength[ch];
+
+ FDKaacEnc_Transform_Real( psyStatic[ch]->psyInputBuffer + wOffset,
+ psyData[ch]->mdctSpectrum+wOffset,
+ psyStatic[ch]->blockSwitchingControl.lastWindowSequence,
+ psyStatic[ch]->blockSwitchingControl.windowShape,
+ &psyStatic[ch]->blockSwitchingControl.lastWindowShape,
+ psyConf->granuleLength,
+ &mdctSpectrum_e,
+ hThisPsyConf[ch]->filterbank
+ ,psyStatic[ch]->overlapAddBuffer
+ );
+
+ /* Low pass / highest sfb */
+ FDKmemclear(&psyData[ch]->mdctSpectrum[psyData[ch]->lowpassLine+wOffset],
+ (windowLength[ch]-psyData[ch]->lowpassLine)*sizeof(FIXP_DBL));
+
+ if (hPsyConfLong->filterbank != FB_LC) {
+ /* Do blending to reduce gibbs artifacts */
+ for (int i=0; i<FADE_OUT_LEN; i++) {
+ psyData[ch]->mdctSpectrum[psyData[ch]->lowpassLine+wOffset - FADE_OUT_LEN + i] = fMult(psyData[ch]->mdctSpectrum[psyData[ch]->lowpassLine+wOffset - FADE_OUT_LEN + i], fadeOutFactor[i]);
+ }
+ }
+
+
+ /* Check for zero spectrum. These loops will usually terminate very, very early. */
+ for(line=0; (line<psyData[ch]->lowpassLine) && (zeroSpec==TRUE); line++) {
+ if (psyData[ch]->mdctSpectrum[line+wOffset] != (FIXP_DBL)0) {
+ zeroSpec = FALSE;
+ break;
+ }
+ }
+
+ } /* w loop */
+
+ psyData[ch]->mdctScale = mdctSpectrum_e;
+
+ /* rotate internal time samples */
+ FDKmemmove(psyStatic[ch]->psyInputBuffer,
+ psyStatic[ch]->psyInputBuffer+psyConf->granuleLength,
+ psyConf->granuleLength*sizeof(INT_PCM));
+
+
+ /* ... and get remaining samples from input buffer */
+ FDKaacEnc_deinterleaveInputBuffer( psyStatic[ch]->psyInputBuffer+psyConf->granuleLength,
+ &pInput[ (2*psyConf->granuleLength-blockSwitchingOffset)*totalChannels + chIdx[ch] ],
+ blockSwitchingOffset-psyConf->granuleLength,
+ totalChannels);
+
+ } /* ch */
+
+ /* Do some rescaling to get maximum possible accuracy for energies */
+ if ( zeroSpec == FALSE) {
+
+ /* Calc possible spectrum leftshift for each sfb (1 means: 1 bit left shift is possible without overflow) */
+ INT minSpecShift = MAX_SHIFT_DBL;
+ INT nrgShift = MAX_SHIFT_DBL;
+ INT finalShift = MAX_SHIFT_DBL;
+ FIXP_DBL currNrg = 0;
+ FIXP_DBL maxNrg = 0;
+
+ for(ch = 0; ch < channels; ch++) {
+ for(w = 0; w < nWindows[ch]; w++) {
+ wOffset = w*windowLength[ch];
+ FDKaacEnc_CalcSfbMaxScaleSpec(psyData[ch]->mdctSpectrum+wOffset,
+ hThisPsyConf[ch]->sfbOffset,
+ pSfbMaxScaleSpec[ch]+w*maxSfb[ch],
+ psyData[ch]->sfbActive);
+
+ for (sfb = 0; sfb<psyData[ch]->sfbActive; sfb++)
+ minSpecShift = fixMin(minSpecShift, (pSfbMaxScaleSpec[ch]+w*maxSfb[ch])[sfb]);
+ }
+
+ }
+
+ /* Calc possible energy leftshift for each sfb (1 means: 1 bit left shift is possible without overflow) */
+ for(ch = 0; ch < channels; ch++) {
+ for(w = 0; w < nWindows[ch]; w++) {
+ wOffset = w*windowLength[ch];
+ currNrg = FDKaacEnc_CheckBandEnergyOptim(psyData[ch]->mdctSpectrum+wOffset,
+ pSfbMaxScaleSpec[ch]+w*maxSfb[ch],
+ hThisPsyConf[ch]->sfbOffset,
+ psyData[ch]->sfbActive,
+ pSfbEnergy[ch]+w*maxSfb[ch],
+ pSfbEnergyLdData[ch]+w*maxSfb[ch],
+ minSpecShift-4);
+
+ maxNrg = fixMax(maxNrg, currNrg);
+ }
+ }
+
+ if ( maxNrg != (FIXP_DBL)0 ) {
+ nrgShift = (CountLeadingBits(maxNrg)>>1) + (minSpecShift-4);
+ }
+
+ /* 2check: Hasn't this decision to be made for both channels? */
+ /* For short windows 1 additional bit headroom is necessary to prevent overflows when summing up energies in FDKaacEnc_groupShortData() */
+ if(isShortWindow[0]) nrgShift--;
+
+ /* both spectrum and energies mustn't overflow */
+ finalShift = fixMin(minSpecShift, nrgShift);
+
+ /* do not shift more than 3 bits more to the left than signal without blockfloating point
+ * would be to avoid overflow of scaled PCM quantization thresholds */
+ if (finalShift > psyData[0]->mdctScale + 3 )
+ finalShift = psyData[0]->mdctScale + 3;
+
+ FDK_ASSERT(finalShift >= 0); /* right shift is not allowed */
+
+ /* correct sfbEnergy and sfbEnergyLdData with new finalShift */
+ FIXP_DBL ldShift = finalShift * FL2FXCONST_DBL(2.0/64);
+ for(ch = 0; ch < channels; ch++) {
+ for(w = 0; w < nWindows[ch]; w++) {
+ for(sfb=0; sfb<psyData[ch]->sfbActive; sfb++) {
+ INT scale = fixMax(0, (pSfbMaxScaleSpec[ch]+w*maxSfb[ch])[sfb]-4);
+ scale = fixMin((scale-finalShift)<<1, DFRACT_BITS-1);
+ if (scale >= 0) (pSfbEnergy[ch]+w*maxSfb[ch])[sfb] >>= (scale);
+ else (pSfbEnergy[ch]+w*maxSfb[ch])[sfb] <<= (-scale);
+ (pSfbThreshold[ch]+w*maxSfb[ch])[sfb] = fMult((pSfbEnergy[ch]+w*maxSfb[ch])[sfb], C_RATIO);
+ (pSfbEnergyLdData[ch]+w*maxSfb[ch])[sfb] += ldShift;
+ }
+ }
+ }
+
+ if ( finalShift != 0 ) {
+ for (ch = 0; ch < channels; ch++) {
+ for(w = 0; w < nWindows[ch]; w++) {
+ wOffset = w*windowLength[ch];
+ for(line=0; line<psyData[ch]->lowpassLine; line++) {
+ psyData[ch]->mdctSpectrum[line+wOffset] <<= finalShift;
+ }
+ /* update sfbMaxScaleSpec */
+ for (sfb = 0; sfb<psyData[ch]->sfbActive; sfb++)
+ (pSfbMaxScaleSpec[ch]+w*maxSfb[ch])[sfb] -= finalShift;
+ }
+ /* update mdctScale */
+ psyData[ch]->mdctScale -= finalShift;
+ }
+ }
+
+ } else {
+ /* all spectral lines are zero */
+ for (ch = 0; ch < channels; ch++) {
+ psyData[ch]->mdctScale = 0; /* otherwise mdctScale would be for example 7 and PCM quantization thresholds would be shifted
+ * 14 bits to the right causing some of them to become 0 (which causes problems later) */
+ /* clear sfbMaxScaleSpec */
+ for(w = 0; w < nWindows[ch]; w++) {
+ for (sfb = 0; sfb<psyData[ch]->sfbActive; sfb++) {
+ (pSfbMaxScaleSpec[ch]+w*maxSfb[ch])[sfb] = 0;
+ (pSfbEnergy[ch]+w*maxSfb[ch])[sfb] = (FIXP_DBL)0;
+ (pSfbEnergyLdData[ch]+w*maxSfb[ch])[sfb] = FL2FXCONST_DBL(-1.0f);
+ (pSfbThreshold[ch]+w*maxSfb[ch])[sfb] = (FIXP_DBL)0;
+ }
+ }
+ }
+ }
+
+ /* Advance psychoacoustics: Tonality and TNS */
+ if (psyStatic[0]->isLFE) {
+ tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive = 0;
+ }
+ else
+ {
+
+ for(ch = 0; ch < channels; ch++) {
+ if (!isShortWindow[ch]) {
+ /* tonality */
+ FDKaacEnc_CalculateFullTonality( psyData[ch]->mdctSpectrum,
+ pSfbMaxScaleSpec[ch],
+ pSfbEnergyLdData[ch],
+ sfbTonality[ch],
+ psyData[ch]->sfbActive,
+ hThisPsyConf[ch]->sfbOffset,
+ hThisPsyConf[ch]->pnsConf.usePns);
+ }
+ }
+
+ if (hPsyConfLong->tnsConf.tnsActive || hPsyConfShort->tnsConf.tnsActive) {
+ INT tnsActive[TRANS_FAC];
+ INT nrgScaling[2] = {0,0};
+ INT tnsSpecShift = 0;
+
+ for(ch = 0; ch < channels; ch++) {
+ for(w = 0; w < nWindows[ch]; w++) {
+
+ wOffset = w*windowLength[ch];
+ /* TNS */
+ FDKaacEnc_TnsDetect(
+ tnsData[ch],
+ &hThisPsyConf[ch]->tnsConf,
+ &psyOutChannel[ch]->tnsInfo,
+ hThisPsyConf[ch]->sfbCnt,
+ psyData[ch]->mdctSpectrum+wOffset,
+ w,
+ psyStatic[ch]->blockSwitchingControl.lastWindowSequence
+ );
+ }
+ }
+
+ if (channels == 2) {
+ FDKaacEnc_TnsSync(
+ tnsData[1],
+ tnsData[0],
+ &psyOutChannel[1]->tnsInfo,
+ &psyOutChannel[0]->tnsInfo,
+
+ psyStatic[1]->blockSwitchingControl.lastWindowSequence,
+ psyStatic[0]->blockSwitchingControl.lastWindowSequence,
+ &hThisPsyConf[1]->tnsConf);
+ }
+
+ FDK_ASSERT(commonWindow=1); /* all checks for TNS do only work for common windows (which is always set)*/
+ for(w = 0; w < nWindows[0]; w++)
+ {
+ if (isShortWindow[0])
+ tnsActive[w] = tnsData[0]->dataRaw.Short.subBlockInfo[w].tnsActive ||
+ ((channels == 2) ? tnsData[1]->dataRaw.Short.subBlockInfo[w].tnsActive : 0);
+ else
+ tnsActive[w] = tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive ||
+ ((channels == 2) ? tnsData[1]->dataRaw.Long.subBlockInfo.tnsActive : 0);
+ }
+
+ for(ch = 0; ch < channels; ch++) {
+ if (tnsActive[0] && !isShortWindow[ch]) {
+ /* Scale down spectrum if tns is active in one of the two channels with same lastWindowSequence */
+ /* first part of threshold calculation; it's not necessary to update sfbMaxScaleSpec */
+ INT shift = 1;
+ for(sfb=0; sfb<hThisPsyConf[ch]->lowpassLine; sfb++) {
+ psyData[ch]->mdctSpectrum[sfb] = psyData[ch]->mdctSpectrum[sfb] >> shift;
+ }
+
+ /* update thresholds */
+ for (sfb=0; sfb<psyData[ch]->sfbActive; sfb++) {
+ pSfbThreshold[ch][sfb] >>= (2*shift);
+ }
+
+ psyData[ch]->mdctScale += shift; /* update mdctScale */
+
+ /* calc sfbEnergies after tnsEncode again ! */
+
+ }
+ }
+
+ for(ch = 0; ch < channels; ch++) {
+ for(w = 0; w < nWindows[ch]; w++)
+ {
+ wOffset = w*windowLength[ch];
+ FDKaacEnc_TnsEncode(
+ &psyOutChannel[ch]->tnsInfo,
+ tnsData[ch],
+ hThisPsyConf[ch]->sfbCnt,
+ &hThisPsyConf[ch]->tnsConf,
+ hThisPsyConf[ch]->sfbOffset[psyData[ch]->sfbActive],/*hThisPsyConf[ch]->lowpassLine*/ /* filter stops before that line ! */
+ psyData[ch]->mdctSpectrum+wOffset,
+ w,
+ psyStatic[ch]->blockSwitchingControl.lastWindowSequence);
+
+ if(tnsActive[w]) {
+ /* Calc sfb-bandwise mdct-energies for left and right channel again, */
+ /* if tns active in current channel or in one channel with same lastWindowSequence left and right */
+ FDKaacEnc_CalcSfbMaxScaleSpec(psyData[ch]->mdctSpectrum+wOffset,
+ hThisPsyConf[ch]->sfbOffset,
+ pSfbMaxScaleSpec[ch]+w*maxSfb[ch],
+ psyData[ch]->sfbActive);
+ }
+ }
+ }
+
+ for(ch = 0; ch < channels; ch++) {
+ for(w = 0; w < nWindows[ch]; w++) {
+
+ if (tnsActive[w]) {
+
+ if (isShortWindow[ch]) {
+ FDKaacEnc_CalcBandEnergyOptimShort(psyData[ch]->mdctSpectrum+w*windowLength[ch],
+ pSfbMaxScaleSpec[ch]+w*maxSfb[ch],
+ hThisPsyConf[ch]->sfbOffset,
+ psyData[ch]->sfbActive,
+ pSfbEnergy[ch]+w*maxSfb[ch]);
+ }
+ else {
+ nrgScaling[ch] = /* with tns, energy calculation can overflow; -> scaling */
+ FDKaacEnc_CalcBandEnergyOptimLong(psyData[ch]->mdctSpectrum,
+ pSfbMaxScaleSpec[ch],
+ hThisPsyConf[ch]->sfbOffset,
+ psyData[ch]->sfbActive,
+ pSfbEnergy[ch],
+ pSfbEnergyLdData[ch]);
+ tnsSpecShift = fixMax(tnsSpecShift, nrgScaling[ch]); /* nrgScaling is set only if nrg would have an overflow */
+ }
+ } /* if tnsActive */
+ }
+ } /* end channel loop */
+
+ /* adapt scaling to prevent nrg overflow, only for long blocks */
+ for(ch = 0; ch < channels; ch++) {
+ if ( (tnsSpecShift!=0) && !isShortWindow[ch] ) {
+ /* scale down spectrum, nrg's and thresholds, if there was an overflow in sfbNrg calculation after tns */
+ for(line=0; line<hThisPsyConf[ch]->lowpassLine; line++) {
+ psyData[ch]->mdctSpectrum[line] >>= tnsSpecShift;
+ }
+ INT scale = (tnsSpecShift-nrgScaling[ch])<<1;
+ for(sfb=0; sfb<psyData[ch]->sfbActive; sfb++) {
+ pSfbEnergyLdData[ch][sfb] -= scale*FL2FXCONST_DBL(1.0/LD_DATA_SCALING);
+ pSfbEnergy[ch][sfb] >>= scale;
+ pSfbThreshold[ch][sfb] >>= (tnsSpecShift<<1);
+ }
+ psyData[ch]->mdctScale += tnsSpecShift; /* update mdctScale; not necessary to update sfbMaxScaleSpec */
+
+ }
+ } /* end channel loop */
+
+ } /* TNS active */
+ } /* !isLFE */
+
+
+
+
+
+#ifdef PSY_MAIN_DEBUG_INFO
+ for(ch = 0; ch < channels; ch++) {
+ FDKfwrite(psyData[ch]->mdctSpectrum, sizeof(FIXP_DBL), psyConf->granuleLength, fSpectrumOut);
+ }
+#endif
+
+ /* Advance thresholds */
+ for(ch = 0; ch < channels; ch++) {
+ INT headroom;
+
+ FIXP_DBL clipEnergy;
+ INT energyShift = psyData[ch]->mdctScale*2 ;
+ INT clipNrgShift = energyShift - THR_SHIFTBITS ;
+
+ if(isShortWindow[ch])
+ headroom = 6;
+ else
+ headroom = 0;
+
+ if (clipNrgShift >= 0)
+ clipEnergy = hThisPsyConf[ch]->clipEnergy >> clipNrgShift ;
+ else if (clipNrgShift>=-headroom)
+ clipEnergy = hThisPsyConf[ch]->clipEnergy << -clipNrgShift ;
+ else
+ clipEnergy = (FIXP_DBL)MAXVAL_DBL ;
+
+ for(w = 0; w < nWindows[ch]; w++)
+ {
+ INT i;
+ /* limit threshold to avoid clipping */
+ for (i=0; i<psyData[ch]->sfbActive; i++) {
+ *(pSfbThreshold[ch]+w*maxSfb[ch]+i) = fixMin(*(pSfbThreshold[ch]+w*maxSfb[ch]+i), clipEnergy);
+ }
+
+ /* spreading */
+ FDKaacEnc_SpreadingMax(psyData[ch]->sfbActive,
+ hThisPsyConf[ch]->sfbMaskLowFactor,
+ hThisPsyConf[ch]->sfbMaskHighFactor,
+ pSfbThreshold[ch]+w*maxSfb[ch]);
+
+
+ /* PCM quantization threshold */
+ energyShift += PCM_QUANT_THR_SCALE;
+ if (energyShift>=0) {
+ energyShift = fixMin(DFRACT_BITS-1,energyShift);
+ for (i=0; i<psyData[ch]->sfbActive;i++) {
+ *(pSfbThreshold[ch]+w*maxSfb[ch]+i) = fixMax(*(pSfbThreshold[ch]+w*maxSfb[ch]+i) >> THR_SHIFTBITS,
+ (hThisPsyConf[ch]->sfbPcmQuantThreshold[i] >> energyShift));
+ }
+ } else {
+ energyShift = fixMin(DFRACT_BITS-1,-energyShift);
+ for (i=0; i<psyData[ch]->sfbActive;i++) {
+ *(pSfbThreshold[ch]+w*maxSfb[ch]+i) = fixMax(*(pSfbThreshold[ch]+w*maxSfb[ch]+i) >> THR_SHIFTBITS,
+ (hThisPsyConf[ch]->sfbPcmQuantThreshold[i] << energyShift));
+ }
+ }
+
+ if (!psyStatic[ch]->isLFE)
+ {
+ /* preecho control */
+ if(psyStatic[ch]->blockSwitchingControl.lastWindowSequence == STOP_WINDOW) {
+ /* prevent FDKaacEnc_PreEchoControl from comparing stop
+ thresholds with short thresholds */
+ for (i=0; i<psyData[ch]->sfbActive;i++) {
+ psyStatic[ch]->sfbThresholdnm1[i] = (FIXP_DBL)MAXVAL_DBL;
+ }
+
+ psyStatic[ch]->mdctScalenm1 = 0;
+ psyStatic[ch]->calcPreEcho = 0;
+ }
+
+ FDKaacEnc_PreEchoControl( psyStatic[ch]->sfbThresholdnm1,
+ psyStatic[ch]->calcPreEcho,
+ psyData[ch]->sfbActive,
+ hThisPsyConf[ch]->maxAllowedIncreaseFactor,
+ hThisPsyConf[ch]->minRemainingThresholdFactor,
+ pSfbThreshold[ch]+w*maxSfb[ch],
+ psyData[ch]->mdctScale,
+ &psyStatic[ch]->mdctScalenm1);
+
+ psyStatic[ch]->calcPreEcho = 1;
+
+ if(psyStatic[ch]->blockSwitchingControl.lastWindowSequence == START_WINDOW)
+ {
+ /* prevent FDKaacEnc_PreEchoControl in next frame to compare start
+ thresholds with short thresholds */
+ for (i=0; i<psyData[ch]->sfbActive;i++) {
+ psyStatic[ch]->sfbThresholdnm1[i] = (FIXP_DBL)MAXVAL_DBL;
+ }
+
+ psyStatic[ch]->mdctScalenm1 = 0;
+ psyStatic[ch]->calcPreEcho = 0;
+ }
+
+ }
+
+ /* spread energy to avoid hole detection */
+ FDKmemcpy(pSfbSpreadEnergy[ch]+w*maxSfb[ch], pSfbEnergy[ch]+w*maxSfb[ch], psyData[ch]->sfbActive*sizeof(FIXP_DBL));
+
+ FDKaacEnc_SpreadingMax(psyData[ch]->sfbActive,
+ hThisPsyConf[ch]->sfbMaskLowFactorSprEn,
+ hThisPsyConf[ch]->sfbMaskHighFactorSprEn,
+ pSfbSpreadEnergy[ch]+w*maxSfb[ch]);
+ }
+ }
+
+ /* Calc bandwise energies for mid and side channel. Do it only if 2 channels exist */
+ if (channels==2) {
+ for(w = 0; w < nWindows[1]; w++) {
+ wOffset = w*windowLength[1];
+ FDKaacEnc_CalcBandNrgMSOpt(psyData[0]->mdctSpectrum+wOffset,
+ psyData[1]->mdctSpectrum+wOffset,
+ pSfbMaxScaleSpec[0]+w*maxSfb[0],
+ pSfbMaxScaleSpec[1]+w*maxSfb[1],
+ hThisPsyConf[1]->sfbOffset,
+ psyData[0]->sfbActive,
+ pSfbEnergyMS[0]+w*maxSfb[0],
+ pSfbEnergyMS[1]+w*maxSfb[1],
+ (psyStatic[1]->blockSwitchingControl.lastWindowSequence != SHORT_WINDOW),
+ psyData[0]->sfbEnergyMSLdData,
+ psyData[1]->sfbEnergyMSLdData);
+ }
+ }
+
+ /* group short data (maxSfb[ch] for short blocks is determined here) */
+ for(ch=0;ch<channels;ch++)
+ {
+ INT noSfb, i;
+ if(isShortWindow[ch])
+ {
+ int sfbGrp;
+ noSfb = psyStatic[ch]->blockSwitchingControl.noOfGroups * hPsyConfShort->sfbCnt;
+ /* At this point, energies and thresholds are copied/regrouped from the ".Short" to the ".Long" arrays */
+ FDKaacEnc_groupShortData( psyData[ch]->mdctSpectrum,
+ &psyData[ch]->sfbThreshold,
+ &psyData[ch]->sfbEnergy,
+ &psyData[ch]->sfbEnergyMS,
+ &psyData[ch]->sfbSpreadEnergy,
+ hPsyConfShort->sfbCnt,
+ psyData[ch]->sfbActive,
+ hPsyConfShort->sfbOffset,
+ hPsyConfShort->sfbMinSnrLdData,
+ psyData[ch]->groupedSfbOffset,
+ &maxSfbPerGroup[ch],
+ psyOutChannel[ch]->sfbMinSnrLdData,
+ psyStatic[ch]->blockSwitchingControl.noOfGroups,
+ psyStatic[ch]->blockSwitchingControl.groupLen,
+ psyConf[1].granuleLength);
+
+
+ /* calculate ldData arrays (short values are in .Long-arrays after FDKaacEnc_groupShortData) */
+ for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) {
+ LdDataVector(&psyData[ch]->sfbEnergy.Long[sfbGrp], &psyOutChannel[ch]->sfbEnergyLdData[sfbGrp], psyData[ch]->sfbActive);
+ }
+
+ /* calc sfbThrld and set Values smaller 2^-31 to 2^-33*/
+ for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) {
+ LdDataVector(&psyData[ch]->sfbThreshold.Long[sfbGrp], &psyOutChannel[ch]->sfbThresholdLdData[sfbGrp], psyData[ch]->sfbActive);
+ for (sfb=0;sfb<psyData[ch]->sfbActive;sfb++) {
+ psyOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb] =
+ fixMax(psyOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb], FL2FXCONST_DBL(-0.515625f));
+ }
+ }
+
+ if ( channels==2 ) {
+ for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) {
+ LdDataVector(&psyData[ch]->sfbEnergyMS.Long[sfbGrp], &psyData[ch]->sfbEnergyMSLdData[sfbGrp], psyData[ch]->sfbActive);
+ }
+ }
+
+ FDKmemcpy(psyOutChannel[ch]->sfbOffsets, psyData[ch]->groupedSfbOffset, (MAX_GROUPED_SFB+1)*sizeof(INT));
+
+ } else {
+ /* maxSfb[ch] for long blocks */
+ for (sfb = psyData[ch]->sfbActive-1; sfb >= 0; sfb--) {
+ for (line = hPsyConfLong->sfbOffset[sfb+1]-1; line >= hPsyConfLong->sfbOffset[sfb]; line--) {
+ if (psyData[ch]->mdctSpectrum[line] != FL2FXCONST_SGL(0.0f)) break;
+ }
+ if (line > hPsyConfLong->sfbOffset[sfb]) break;
+ }
+ maxSfbPerGroup[ch] = sfb + 1;
+ /* ensure at least one section in ICS; workaround for existing decoder crc implementation */
+ maxSfbPerGroup[ch] = fixMax(fixMin(5,psyData[ch]->sfbActive),maxSfbPerGroup[ch]);
+
+ /* sfbNrgLdData is calculated in FDKaacEnc_advancePsychLong, copy in psyOut structure */
+ FDKmemcpy(psyOutChannel[ch]->sfbEnergyLdData, psyData[ch]->sfbEnergyLdData.Long, psyData[ch]->sfbActive*sizeof(FIXP_DBL));
+
+ FDKmemcpy(psyOutChannel[ch]->sfbOffsets, hPsyConfLong->sfbOffset, (MAX_GROUPED_SFB+1)*sizeof(INT));
+
+ /* sfbMinSnrLdData modified in adjust threshold, copy necessary */
+ FDKmemcpy(psyOutChannel[ch]->sfbMinSnrLdData, hPsyConfLong->sfbMinSnrLdData, psyData[ch]->sfbActive*sizeof(FIXP_DBL));
+
+ /* sfbEnergyMSLdData ist already calculated in FDKaacEnc_CalcBandNrgMSOpt; only in long case */
+
+ /* calc sfbThrld and set Values smaller 2^-31 to 2^-33*/
+ LdDataVector(psyData[ch]->sfbThreshold.Long, psyOutChannel[ch]->sfbThresholdLdData, psyData[ch]->sfbActive);
+ for (i=0;i<psyData[ch]->sfbActive;i++) {
+ psyOutChannel[ch]->sfbThresholdLdData[i] =
+ fixMax(psyOutChannel[ch]->sfbThresholdLdData[i], FL2FXCONST_DBL(-0.515625f));
+ }
+
+
+ }
+
+
+ }
+
+
+ /*
+ Intensity parameter intialization.
+ */
+ for(ch=0;ch<channels;ch++) {
+ FDKmemclear(psyOutChannel[ch]->isBook, MAX_GROUPED_SFB*sizeof(INT));
+ FDKmemclear(psyOutChannel[ch]->isScale, MAX_GROUPED_SFB*sizeof(INT));
+ }
+
+ for(ch=0;ch<channels;ch++) {
+ INT win = (isShortWindow[ch]?1:0);
+ if (!psyStatic[ch]->isLFE)
+ {
+ /* PNS Decision */
+ FDKaacEnc_PnsDetect( &(psyConf[0].pnsConf),
+ pnsData[ch],
+ psyStatic[ch]->blockSwitchingControl.lastWindowSequence,
+ psyData[ch]->sfbActive,
+ maxSfbPerGroup[ch], /* count of Sfb which are not zero. */
+ psyOutChannel[ch]->sfbThresholdLdData,
+ psyConf[win].sfbOffset,
+ psyData[ch]->mdctSpectrum,
+ psyData[ch]->sfbMaxScaleSpec.Long,
+ sfbTonality[ch],
+ psyOutChannel[ch]->tnsInfo.order[0][0],
+ tnsData[ch]->dataRaw.Long.subBlockInfo.predictionGain,
+ tnsData[ch]->dataRaw.Long.subBlockInfo.tnsActive,
+ psyOutChannel[ch]->sfbEnergyLdData,
+ psyOutChannel[ch]->noiseNrg );
+ } /* !isLFE */
+ }
+
+ /*
+ stereo Processing
+ */
+ if(channels == 2)
+ {
+ psyOutElement->toolsInfo.msDigest = MS_NONE;
+ psyOutElement->commonWindow = commonWindow;
+ if (psyOutElement->commonWindow)
+ maxSfbPerGroup[0] = maxSfbPerGroup[1] =
+ fixMax(maxSfbPerGroup[0], maxSfbPerGroup[1]);
+
+ if(psyStatic[0]->blockSwitchingControl.lastWindowSequence != SHORT_WINDOW)
+ {
+ /* PNS preprocessing depending on ms processing: PNS not in Short Window! */
+ FDKaacEnc_PreProcessPnsChannelPair(
+ psyData[0]->sfbActive,
+ (&psyData[0]->sfbEnergy)->Long,
+ (&psyData[1]->sfbEnergy)->Long,
+ psyOutChannel[0]->sfbEnergyLdData,
+ psyOutChannel[1]->sfbEnergyLdData,
+ psyData[0]->sfbEnergyMS.Long,
+ &(psyConf[0].pnsConf),
+ pnsData[0],
+ pnsData[1]);
+
+ FDKaacEnc_IntensityStereoProcessing(
+ psyData[0]->sfbEnergy.Long,
+ psyData[1]->sfbEnergy.Long,
+ psyData[0]->mdctSpectrum,
+ psyData[1]->mdctSpectrum,
+ psyData[0]->sfbThreshold.Long,
+ psyData[1]->sfbThreshold.Long,
+ psyOutChannel[1]->sfbThresholdLdData,
+ psyData[0]->sfbSpreadEnergy.Long,
+ psyData[1]->sfbSpreadEnergy.Long,
+ psyOutChannel[0]->sfbEnergyLdData,
+ psyOutChannel[1]->sfbEnergyLdData,
+ &psyOutElement->toolsInfo.msDigest,
+ psyOutElement->toolsInfo.msMask,
+ psyConf[0].sfbCnt,
+ psyConf[0].sfbCnt,
+ maxSfbPerGroup[0],
+ psyConf[0].sfbOffset,
+ psyConf[0].allowIS && commonWindow,
+ psyOutChannel[1]->isBook,
+ psyOutChannel[1]->isScale,
+ pnsData);
+
+ FDKaacEnc_MsStereoProcessing(
+ psyData,
+ psyOutChannel,
+ psyOutChannel[1]->isBook,
+ &psyOutElement->toolsInfo.msDigest,
+ psyOutElement->toolsInfo.msMask,
+ psyData[0]->sfbActive,
+ psyData[0]->sfbActive,
+ maxSfbPerGroup[0],
+ psyOutChannel[0]->sfbOffsets);
+
+ /* PNS postprocessing */
+ FDKaacEnc_PostProcessPnsChannelPair(psyData[0]->sfbActive,
+ &(psyConf[0].pnsConf),
+ pnsData[0],
+ pnsData[1],
+ psyOutElement->toolsInfo.msMask,
+ &psyOutElement->toolsInfo.msDigest);
+
+ } else {
+ FDKaacEnc_IntensityStereoProcessing(
+ psyData[0]->sfbEnergy.Long,
+ psyData[1]->sfbEnergy.Long,
+ psyData[0]->mdctSpectrum,
+ psyData[1]->mdctSpectrum,
+ psyData[0]->sfbThreshold.Long,
+ psyData[1]->sfbThreshold.Long,
+ psyOutChannel[1]->sfbThresholdLdData,
+ psyData[0]->sfbSpreadEnergy.Long,
+ psyData[1]->sfbSpreadEnergy.Long,
+ psyOutChannel[0]->sfbEnergyLdData,
+ psyOutChannel[1]->sfbEnergyLdData,
+ &psyOutElement->toolsInfo.msDigest,
+ psyOutElement->toolsInfo.msMask,
+ psyStatic[0]->blockSwitchingControl.noOfGroups*hPsyConfShort->sfbCnt,
+ psyConf[1].sfbCnt,
+ maxSfbPerGroup[0],
+ psyData[0]->groupedSfbOffset,
+ psyConf[0].allowIS && commonWindow,
+ psyOutChannel[1]->isBook,
+ psyOutChannel[1]->isScale,
+ pnsData);
+
+ /* it's OK to pass the ".Long" arrays here. They contain grouped short data since FDKaacEnc_groupShortData() */
+ FDKaacEnc_MsStereoProcessing( psyData,
+ psyOutChannel,
+ psyOutChannel[1]->isBook,
+ &psyOutElement->toolsInfo.msDigest,
+ psyOutElement->toolsInfo.msMask,
+ psyStatic[0]->blockSwitchingControl.noOfGroups*hPsyConfShort->sfbCnt,
+ hPsyConfShort->sfbCnt,
+ maxSfbPerGroup[0],
+ psyOutChannel[0]->sfbOffsets);
+ }
+ }
+
+ /*
+ PNS Coding
+ */
+ for(ch=0;ch<channels;ch++) {
+ if (psyStatic[ch]->isLFE) {
+ /* no PNS coding */
+ for(sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) {
+ psyOutChannel[ch]->noiseNrg[sfb] = NO_NOISE_PNS;
+ }
+ } else
+ {
+ FDKaacEnc_CodePnsChannel(psyData[ch]->sfbActive,
+ &(psyConf[ch].pnsConf),
+ pnsData[ch]->pnsFlag,
+ psyData[ch]->sfbEnergyLdData.Long,
+ psyOutChannel[ch]->noiseNrg, /* this is the energy that will be written to the bitstream */
+ psyOutChannel[ch]->sfbThresholdLdData);
+ }
+ }
+
+ /*
+ build output
+ */
+ for(ch=0;ch<channels;ch++)
+ {
+ INT j, grp, mask;
+
+ psyOutChannel[ch]->maxSfbPerGroup = maxSfbPerGroup[ch];
+ psyOutChannel[ch]->mdctScale = psyData[ch]->mdctScale;
+
+ if(isShortWindow[ch]==0) {
+
+ psyOutChannel[ch]->sfbCnt = hPsyConfLong->sfbActive;
+ psyOutChannel[ch]->sfbPerGroup = hPsyConfLong->sfbActive;
+ psyOutChannel[ch]->lastWindowSequence = psyStatic[ch]->blockSwitchingControl.lastWindowSequence;
+ psyOutChannel[ch]->windowShape = psyStatic[ch]->blockSwitchingControl.windowShape;
+ }
+ else {
+ INT sfbCnt = psyStatic[ch]->blockSwitchingControl.noOfGroups*hPsyConfShort->sfbCnt;
+
+ psyOutChannel[ch]->sfbCnt = sfbCnt;
+ psyOutChannel[ch]->sfbPerGroup = hPsyConfShort->sfbCnt;
+ psyOutChannel[ch]->lastWindowSequence = SHORT_WINDOW;
+ psyOutChannel[ch]->windowShape = SINE_WINDOW;
+ }
+
+ /* generate grouping mask */
+ mask = 0;
+ for (grp = 0; grp < psyStatic[ch]->blockSwitchingControl.noOfGroups; grp++)
+ {
+ mask <<= 1;
+ for (j=1; j<psyStatic[ch]->blockSwitchingControl.groupLen[grp]; j++) {
+ mask = (mask<<1) | 1 ;
+ }
+ }
+ psyOutChannel[ch]->groupingMask = mask;
+
+ /* build interface */
+ FDKmemcpy(psyOutChannel[ch]->groupLen,psyStatic[ch]->blockSwitchingControl.groupLen,MAX_NO_OF_GROUPS*sizeof(INT));
+ FDKmemcpy(psyOutChannel[ch]->sfbEnergy,(&psyData[ch]->sfbEnergy)->Long, MAX_GROUPED_SFB*sizeof(FIXP_DBL));
+ FDKmemcpy(psyOutChannel[ch]->sfbSpreadEnergy,(&psyData[ch]->sfbSpreadEnergy)->Long, MAX_GROUPED_SFB*sizeof(FIXP_DBL));
+// FDKmemcpy(psyOutChannel[ch]->mdctSpectrum, psyData[ch]->mdctSpectrum, (1024)*sizeof(FIXP_DBL));
+ }
+
+ return AAC_ENC_OK;
+}
+
+
+void FDKaacEnc_PsyClose(PSY_INTERNAL **phPsyInternal,
+ PSY_OUT **phPsyOut)
+{
+ int n, i;
+
+#ifdef PSY_MAIN_DEBUG_INFO
+ if(fSpectrumOut!=NULL)
+ FDKfclose(fSpectrumOut);
+#endif
+
+ if(phPsyInternal!=NULL) {
+ PSY_INTERNAL *hPsyInternal = *phPsyInternal;
+
+ if (hPsyInternal)
+ {
+ for (i=0; i<(6); i++) {
+ if (hPsyInternal->pStaticChannels[i]) {
+ if (hPsyInternal->pStaticChannels[i]->psyInputBuffer)
+ FreeRam_aacEnc_PsyInputBuffer(&hPsyInternal->pStaticChannels[i]->psyInputBuffer); /* AUDIO INPUT BUFFER */
+
+ FreeRam_aacEnc_PsyStatic(&hPsyInternal->pStaticChannels[i]); /* PSY_STATIC */
+ }
+ }
+
+ for (i=0; i<(6); i++) {
+ if (hPsyInternal->psyElement[i])
+ FreeRam_aacEnc_PsyElement(&hPsyInternal->psyElement[i]); /* PSY_ELEMENT */
+ }
+
+
+ FreeRam_aacEnc_PsyInternal(phPsyInternal);
+ }
+ }
+
+ if (phPsyOut!=NULL) {
+ for (n=0; n<(1); n++) {
+ if (phPsyOut[n])
+ {
+ for (i=0; i<(6); i++) {
+ if (phPsyOut[n]->pPsyOutChannels[i])
+ FreeRam_aacEnc_PsyOutChannel(&phPsyOut[n]->pPsyOutChannels[i]); /* PSY_OUT_CHANNEL */
+ }
+
+ for (i=0; i<(6); i++) {
+ if (phPsyOut[n]->psyOutElement[i])
+ FreeRam_aacEnc_PsyOutElements(&phPsyOut[n]->psyOutElement[i]); /* PSY_OUT_ELEMENTS */
+ }
+
+ FreeRam_aacEnc_PsyOut(&phPsyOut[n]);
+ }
+ }
+ }
+}
diff --git a/libAACenc/src/psy_main.h b/libAACenc/src/psy_main.h
new file mode 100644
index 0000000..cb8819c
--- /dev/null
+++ b/libAACenc/src/psy_main.h
@@ -0,0 +1,111 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Psychoaccoustic major function block
+
+******************************************************************************/
+#ifndef _PSYMAIN_H
+#define _PSYMAIN_H
+
+
+#include "psy_configuration.h"
+#include "qc_data.h"
+#include "aacenc_pns.h"
+
+/*
+ psych internal
+*/
+typedef struct {
+
+ PSY_STATIC* psyStatic[(2)];
+
+}PSY_ELEMENT;
+
+typedef struct {
+
+ PSY_DATA psyData[(2)];
+ TNS_DATA tnsData[(2)];
+ PNS_DATA pnsData[(2)];
+
+}PSY_DYNAMIC;
+
+
+typedef struct {
+
+ PSY_CONFIGURATION psyConf[2]; /* LONG / SHORT */
+ PSY_ELEMENT* psyElement[(6)];
+ PSY_STATIC* pStaticChannels[(6)];
+ PSY_DYNAMIC* psyDynamic;
+ INT granuleLength;
+
+}PSY_INTERNAL;
+
+
+AAC_ENCODER_ERROR FDKaacEnc_PsyNew(PSY_INTERNAL **phpsy,
+ const INT nElements,
+ const INT nChannels
+ ,UCHAR *dynamic_RAM
+ );
+
+AAC_ENCODER_ERROR FDKaacEnc_PsyOutNew(PSY_OUT **phpsyOut,
+ const INT nElements,
+ const INT nChannels,
+ const INT nSubFrames
+ ,UCHAR *dynamic_RAM
+ );
+
+AAC_ENCODER_ERROR FDKaacEnc_psyInit(PSY_INTERNAL *hPsy,
+ PSY_OUT **phpsyOut,
+ const INT nSubFrames,
+ const INT nMaxChannels,
+ const AUDIO_OBJECT_TYPE audioObjectType,
+ CHANNEL_MAPPING *cm);
+
+AAC_ENCODER_ERROR FDKaacEnc_psyMainInit(PSY_INTERNAL *hPsy,
+ AUDIO_OBJECT_TYPE audioObjectType,
+ CHANNEL_MAPPING *cm,
+ INT sampleRate,
+ INT granuleLength,
+ INT bitRate,
+ INT tnsMask,
+ INT bandwidth,
+ INT usePns,
+ INT useIS,
+ UINT syntaxFlags,
+ ULONG initFlags);
+
+AAC_ENCODER_ERROR FDKaacEnc_psyMain(INT channels,
+ PSY_ELEMENT *psyElement,
+ PSY_DYNAMIC *psyDynamic,
+ PSY_CONFIGURATION *psyConf,
+ PSY_OUT_ELEMENT *psyOutElement,
+ INT_PCM *pInput,
+ INT *chIdx,
+ INT totalChannels
+ );
+
+void FDKaacEnc_PsyClose(PSY_INTERNAL **phPsyInternal,
+ PSY_OUT **phPsyOut);
+
+#endif /* _PSYMAIN_H */
diff --git a/libAACenc/src/qc_data.h b/libAACenc/src/qc_data.h
new file mode 100644
index 0000000..bbcffde
--- /dev/null
+++ b/libAACenc/src/qc_data.h
@@ -0,0 +1,214 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: Quantizing & coding data
+
+******************************************************************************/
+#ifndef _QC_DATA_H
+#define _QC_DATA_H
+
+
+#include "psy_const.h"
+#include "dyn_bits.h"
+#include "adj_thr_data.h"
+#include "line_pe.h"
+#include "FDK_audio.h"
+#include "interface.h"
+
+
+typedef enum {
+ QCDATA_BR_MODE_INVALID = -1,
+ QCDATA_BR_MODE_CBR = 0,
+ QCDATA_BR_MODE_VBR_1 = 1, /* 32 kbps/channel */
+ QCDATA_BR_MODE_VBR_2 = 2, /* 40 kbps/channel */
+ QCDATA_BR_MODE_VBR_3 = 3, /* 48 kbps/channel */
+ QCDATA_BR_MODE_VBR_4 = 4, /* 64 kbps/channel */
+ QCDATA_BR_MODE_VBR_5 = 5, /* 96 kbps/channel */
+ QCDATA_BR_MODE_FF = 6, /* Fixed frame mode. */
+ QCDATA_BR_MODE_SFR = 7 /* Superframe mode. */
+
+
+} QCDATA_BR_MODE;
+
+typedef struct {
+ MP4_ELEMENT_ID elType;
+ INT instanceTag;
+ INT nChannelsInEl;
+ INT ChannelIndex[2];
+ FIXP_DBL relativeBits;
+} ELEMENT_INFO;
+
+typedef struct {
+ CHANNEL_MODE encMode;
+ INT nChannels;
+ INT nChannelsEff;
+ INT nElements;
+ ELEMENT_INFO elInfo[(6)];
+// INT elDSE; /* DSE element signalling */
+} CHANNEL_MAPPING;
+
+typedef struct {
+ INT paddingRest;
+} PADDING;
+
+
+/* Quantizing & coding stage */
+
+struct QC_INIT{
+ CHANNEL_MAPPING* channelMapping;
+ INT sceCpe; /* not used yet */
+ INT maxBits; /* maximum number of bits in reservoir */
+ INT averageBits; /* average number of bits we should use */
+ INT bitRes;
+ INT staticBits; /* Bits per frame consumed by transport layers. */
+ QCDATA_BR_MODE bitrateMode;
+ INT meanPe;
+ INT chBitrate;
+ INT invQuant;
+ INT maxIterations; /* Maximum number of allowed iterations before FDKaacEnc_crashRecovery() is applied. */
+ FIXP_DBL maxBitFac;
+ INT bitrate;
+ INT nSubFrames; /* helper variable */
+ INT minBits; /* minimal number of bits in one frame*/
+
+ PADDING padding;
+};
+
+typedef struct
+{
+ FIXP_DBL mdctSpectrum[(1024)];
+
+ SHORT quantSpec[(1024)];
+
+ UINT maxValueInSfb[MAX_GROUPED_SFB];
+ INT scf[MAX_GROUPED_SFB];
+ INT globalGain;
+ SECTION_DATA sectionData;
+
+ FIXP_DBL sfbFormFactorLdData[MAX_GROUPED_SFB];
+
+ FIXP_DBL sfbThresholdLdData[MAX_GROUPED_SFB];
+ FIXP_DBL sfbMinSnrLdData[MAX_GROUPED_SFB];
+ FIXP_DBL sfbEnergyLdData[MAX_GROUPED_SFB];
+ FIXP_DBL sfbEnergy[MAX_GROUPED_SFB];
+ FIXP_DBL sfbWeightedEnergyLdData[MAX_GROUPED_SFB];
+
+ FIXP_DBL sfbEnFacLd[MAX_GROUPED_SFB];
+
+ FIXP_DBL sfbSpreadEnergy[MAX_GROUPED_SFB];
+
+} QC_OUT_CHANNEL;
+
+
+typedef struct
+{
+ EXT_PAYLOAD_TYPE type; /* type of the extension payload */
+ INT nPayloadBits; /* size of the payload */
+ UCHAR *pPayload; /* pointer to payload */
+
+} QC_OUT_EXTENSION;
+
+
+typedef struct
+{
+ INT staticBitsUsed; /* for verification purposes */
+ INT dynBitsUsed; /* for verification purposes */
+
+ INT extBitsUsed; /* bit consumption of extended fill elements */
+ INT nExtensions; /* number of extension payloads for this element */
+ QC_OUT_EXTENSION extension[(1)]; /* reffering extension payload */
+
+ INT grantedDynBits;
+
+ INT grantedPe;
+ INT grantedPeCorr;
+
+ PE_DATA peData;
+
+ QC_OUT_CHANNEL *qcOutChannel[(2)];
+
+
+} QC_OUT_ELEMENT;
+
+typedef struct
+{
+ QC_OUT_ELEMENT *qcElement[(6)];
+ QC_OUT_CHANNEL *pQcOutChannels[(6)];
+ QC_OUT_EXTENSION extension[(2+2)]; /* global extension payload */
+ INT nExtensions; /* number of extension payloads for this AU */
+ INT maxDynBits; /* maximal allowed dynamic bits in frame */
+ INT grantedDynBits; /* granted dynamic bits in frame */
+ INT totFillBits; /* fill bits */
+ INT elementExtBits; /* element associated extension payload bits, e.g. sbr, drc ... */
+ INT globalExtBits; /* frame/au associated extension payload bits (anc data ...) */
+ INT staticBits; /* aac side info bits */
+
+ INT totalNoRedPe;
+ INT totalGrantedPeCorr;
+
+ INT usedDynBits; /* number of dynamic bits in use */
+ INT alignBits; /* AU alignment bits */
+ INT totalBits; /* sum of static, dyn, sbr, fill, align and dse bits */
+
+} QC_OUT;
+
+typedef struct {
+ INT chBitrateEl; /* channel bitrate in element (totalbitrate*el_relativeBits/el_channels) */
+ INT maxBitsEl; /* used in crash recovery */
+ INT bitResLevelEl; /* update bitreservoir level in each call of FDKaacEnc_QCMain */
+ INT maxBitResBitsEl; /* nEffChannels*6144 - averageBitsInFrame */
+ FIXP_DBL relativeBitsEl; /* Bits relative to total Bits*/
+} ELEMENT_BITS;
+
+typedef struct
+{
+ /* this is basically struct QC_INIT */
+
+ INT globHdrBits;
+ INT maxBitsPerFrame; /* maximal allowed bits per frame, 6144*nChannelsEff */
+ INT minBitsPerFrame; /* minimal allowd bits per fram, superframing - DRM */
+ INT nElements;
+ QCDATA_BR_MODE bitrateMode;
+ INT bitDistributenMode; /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */
+ INT bitResTot;
+ INT bitResTotMax;
+ INT maxIterations; /* Maximum number of allowed iterations before FDKaacEnc_crashRecovery() is applied. */
+ INT invQuant;
+
+ FIXP_DBL vbrQualFactor;
+ FIXP_DBL maxBitFac;
+
+ PADDING padding;
+
+ ELEMENT_BITS *elementBits[(6)];
+ BITCNTR_STATE *hBitCounter;
+ ADJ_THR_STATE *hAdjThr;
+
+} QC_STATE;
+
+#endif /* _QC_DATA_H */
+
+
+
+
diff --git a/libAACenc/src/qc_main.cpp b/libAACenc/src/qc_main.cpp
new file mode 100644
index 0000000..df9c4c4
--- /dev/null
+++ b/libAACenc/src/qc_main.cpp
@@ -0,0 +1,1551 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: Quantizing & coding
+
+******************************************************************************/
+
+#include "qc_main.h"
+#include "quantize.h"
+#include "interface.h"
+#include "adj_thr.h"
+#include "sf_estim.h"
+#include "bit_cnt.h"
+#include "dyn_bits.h"
+#include "channel_map.h"
+#include "aacEnc_ram.h"
+
+#include "genericStds.h"
+
+
+typedef struct {
+ QCDATA_BR_MODE bitrateMode;
+ LONG vbrQualFactor;
+} TAB_VBR_QUAL_FACTOR;
+
+static const TAB_VBR_QUAL_FACTOR tableVbrQualFactor[] = {
+ {QCDATA_BR_MODE_CBR, FL2FXCONST_DBL(0.00f)},
+ {QCDATA_BR_MODE_VBR_1, FL2FXCONST_DBL(0.160f)}, /* 32 kbps mono AAC-LC + SBR + PS */
+ {QCDATA_BR_MODE_VBR_2, FL2FXCONST_DBL(0.148f)}, /* 64 kbps stereo AAC-LC + SBR */
+ {QCDATA_BR_MODE_VBR_3, FL2FXCONST_DBL(0.135f)}, /* 80 - 96 kbps stereo AAC-LC */
+ {QCDATA_BR_MODE_VBR_4, FL2FXCONST_DBL(0.111f)}, /* 128 kbps stereo AAC-LC */
+ {QCDATA_BR_MODE_VBR_5, FL2FXCONST_DBL(0.070f)}, /* 192 kbps stereo AAC-LC */
+ {QCDATA_BR_MODE_SFR, FL2FXCONST_DBL(0.00f)},
+ {QCDATA_BR_MODE_FF, FL2FXCONST_DBL(0.00f)}
+};
+
+static INT isConstantBitrateMode(
+ const QCDATA_BR_MODE bitrateMode
+ )
+{
+ return ( ((bitrateMode==QCDATA_BR_MODE_CBR) || (bitrateMode==QCDATA_BR_MODE_SFR) || (bitrateMode==QCDATA_BR_MODE_FF)) ? 1 : 0 );
+}
+
+
+
+typedef enum{
+ FRAME_LEN_BYTES_MODULO = 1,
+ FRAME_LEN_BYTES_INT = 2
+}FRAME_LEN_RESULT_MODE;
+
+/* forward declarations */
+
+static INT FDKaacEnc_calcMaxValueInSfb(INT sfbCnt,
+ INT maxSfbPerGroup,
+ INT sfbPerGroup,
+ INT *RESTRICT sfbOffset,
+ SHORT *RESTRICT quantSpectrum,
+ UINT *RESTRICT maxValue);
+
+static void FDKaacEnc_crashRecovery(INT nChannels,
+ PSY_OUT_ELEMENT* psyOutElement,
+ QC_OUT* qcOut,
+ QC_OUT_ELEMENT *qcElement,
+ INT bitsToSave,
+ AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig);
+
+static
+AAC_ENCODER_ERROR FDKaacEnc_reduceBitConsumption(int* iterations,
+ const int maxIterations,
+ int gainAdjustment,
+ int* chConstraintsFulfilled,
+ int* calculateQuant,
+ int nChannels,
+ PSY_OUT_ELEMENT* psyOutElement,
+ QC_OUT* qcOut,
+ QC_OUT_ELEMENT* qcOutElement,
+ ELEMENT_BITS* elBits,
+ AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig);
+
+
+void FDKaacEnc_QCClose (QC_STATE **phQCstate, QC_OUT **phQC);
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_calcFrameLen
+ description:
+ returns:
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_calcFrameLen(INT bitRate,
+ INT sampleRate,
+ INT granuleLength,
+ FRAME_LEN_RESULT_MODE mode)
+{
+
+ INT result;
+
+ result = ((granuleLength)>>3)*(bitRate);
+
+ switch(mode) {
+ case FRAME_LEN_BYTES_MODULO:
+ result %= sampleRate;
+ break;
+ case FRAME_LEN_BYTES_INT:
+ result /= sampleRate;
+ break;
+ }
+ return(result);
+}
+
+/*****************************************************************************
+
+ functionname:FDKaacEnc_framePadding
+ description: Calculates if padding is needed for actual frame
+ returns:
+ input:
+ output:
+
+*****************************************************************************/
+static INT FDKaacEnc_framePadding(INT bitRate,
+ INT sampleRate,
+ INT granuleLength,
+ INT *paddingRest)
+{
+ INT paddingOn;
+ INT difference;
+
+ paddingOn = 0;
+
+ difference = FDKaacEnc_calcFrameLen( bitRate,
+ sampleRate,
+ granuleLength,
+ FRAME_LEN_BYTES_MODULO );
+ *paddingRest-=difference;
+
+ if (*paddingRest <= 0 ) {
+ paddingOn = 1;
+ *paddingRest += sampleRate;
+ }
+
+ return( paddingOn );
+}
+
+
+/*********************************************************************************
+
+ functionname: FDKaacEnc_QCOutNew
+ description:
+ return:
+
+**********************************************************************************/
+AAC_ENCODER_ERROR FDKaacEnc_QCOutNew(QC_OUT **phQC,
+ const INT nElements,
+ const INT nChannels,
+ const INT nSubFrames
+ ,UCHAR *dynamic_RAM
+ )
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ int n, i;
+ int elInc = 0, chInc = 0;
+
+ for (n=0; n<nSubFrames; n++) {
+ phQC[n] = GetRam_aacEnc_QCout(n);
+ if (phQC[n] == NULL) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto QCOutNew_bail;
+ }
+
+ for (i=0; i<nChannels; i++) {
+ phQC[n]->pQcOutChannels[i] = GetRam_aacEnc_QCchannel(chInc, dynamic_RAM);
+ if ( phQC[n]->pQcOutChannels[i] == NULL
+ )
+ {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto QCOutNew_bail;
+ }
+ chInc++;
+ } /* nChannels */
+
+ for (i=0; i<nElements; i++) {
+ phQC[n]->qcElement[i] = GetRam_aacEnc_QCelement(elInc);
+ if (phQC[n]->qcElement[i] == NULL)
+ {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto QCOutNew_bail;
+ }
+ elInc++;
+ } /* nElements */
+
+ } /* nSubFrames */
+
+
+ return AAC_ENC_OK;
+
+QCOutNew_bail:
+ return ErrorStatus;
+}
+
+/*********************************************************************************
+
+ functionname: FDKaacEnc_QCOutInit
+ description:
+ return:
+
+**********************************************************************************/
+AAC_ENCODER_ERROR FDKaacEnc_QCOutInit(QC_OUT *phQC[(1)],
+ const INT nSubFrames,
+ const CHANNEL_MAPPING *cm)
+{
+ INT n,i,ch;
+
+ for (n=0; n<nSubFrames; n++) {
+ INT chInc = 0;
+ for (i=0; i<cm->nElements; i++) {
+ for (ch=0; ch<cm->elInfo[i].nChannelsInEl; ch++) {
+ phQC[n]->qcElement[i]->qcOutChannel[ch] = phQC[n]->pQcOutChannels[chInc];
+ chInc++;
+ } /* chInEl */
+ } /* nElements */
+ } /* nSubFrames */
+
+ return AAC_ENC_OK;
+}
+
+/*********************************************************************************
+
+ functionname: FDKaacEnc_QCNew
+ description:
+ return:
+
+**********************************************************************************/
+AAC_ENCODER_ERROR FDKaacEnc_QCNew(QC_STATE **phQC,
+ INT nElements
+ ,UCHAR* dynamic_RAM
+ )
+{
+ AAC_ENCODER_ERROR ErrorStatus;
+ int i;
+
+ QC_STATE* hQC = GetRam_aacEnc_QCstate();
+ *phQC = hQC;
+ if (hQC == NULL) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto QCNew_bail;
+ }
+
+ if (FDKaacEnc_AdjThrNew(&hQC->hAdjThr, nElements)) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto QCNew_bail;
+ }
+
+ if (FDKaacEnc_BCNew(&(hQC->hBitCounter), dynamic_RAM)) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto QCNew_bail;
+ }
+
+ for (i=0; i<nElements; i++) {
+ hQC->elementBits[i] = GetRam_aacEnc_ElementBits(i);
+ if (hQC->elementBits[i] == NULL) {
+ ErrorStatus = AAC_ENC_NO_MEMORY;
+ goto QCNew_bail;
+ }
+ }
+
+ return AAC_ENC_OK;
+
+QCNew_bail:
+ FDKaacEnc_QCClose(phQC, NULL);
+ return ErrorStatus;
+}
+
+/*********************************************************************************
+
+ functionname: FDKaacEnc_QCInit
+ description:
+ return:
+
+**********************************************************************************/
+AAC_ENCODER_ERROR FDKaacEnc_QCInit(QC_STATE *hQC,
+ struct QC_INIT *init)
+{
+ hQC->maxBitsPerFrame = init->maxBits;
+ hQC->minBitsPerFrame = init->minBits;
+ hQC->nElements = init->channelMapping->nElements;
+ hQC->bitResTotMax = init->bitRes;
+ hQC->bitResTot = init->bitRes;
+ hQC->maxBitFac = init->maxBitFac;
+ hQC->bitrateMode = init->bitrateMode;
+ hQC->invQuant = init->invQuant;
+ hQC->maxIterations = init->maxIterations;
+
+ if ( isConstantBitrateMode(hQC->bitrateMode) ) {
+ INT bitresPerChannel = (hQC->bitResTotMax / init->channelMapping->nChannelsEff);
+ /* 0: full bitreservoir, 1: reduced bitreservoir, 2: disabled bitreservoir */
+ hQC->bitDistributenMode = (bitresPerChannel>50) ? 0 : (bitresPerChannel>0) ? 1 : 2;
+ }
+ else {
+ hQC->bitDistributenMode = 0; /* full bitreservoir */
+ }
+
+
+ hQC->padding.paddingRest = init->padding.paddingRest;
+
+ hQC->globHdrBits = init->staticBits; /* Bit overhead due to transport */
+
+ FDKaacEnc_InitElementBits(hQC,
+ init->channelMapping,
+ init->bitrate,
+ (init->averageBits/init->nSubFrames) - hQC->globHdrBits,
+ hQC->maxBitsPerFrame/init->channelMapping->nChannelsEff);
+
+ switch(hQC->bitrateMode){
+ case QCDATA_BR_MODE_CBR:
+ case QCDATA_BR_MODE_VBR_1:
+ case QCDATA_BR_MODE_VBR_2:
+ case QCDATA_BR_MODE_VBR_3:
+ case QCDATA_BR_MODE_VBR_4:
+ case QCDATA_BR_MODE_VBR_5:
+ case QCDATA_BR_MODE_SFR:
+ case QCDATA_BR_MODE_FF:
+ if((int)hQC->bitrateMode < (int)(sizeof(tableVbrQualFactor)/sizeof(TAB_VBR_QUAL_FACTOR))){
+ hQC->vbrQualFactor = (FIXP_DBL)tableVbrQualFactor[hQC->bitrateMode].vbrQualFactor;
+ } else {
+ hQC->vbrQualFactor = FL2FXCONST_DBL(0.f); /* default setting */
+ }
+ break;
+ case QCDATA_BR_MODE_INVALID:
+ default:
+ hQC->vbrQualFactor = FL2FXCONST_DBL(0.f);
+ break;
+ }
+
+ FDKaacEnc_AdjThrInit(hQC->hAdjThr,
+ init->meanPe,
+ hQC->elementBits, /* or channelBitrates, was: channelBitrate */
+ init->channelMapping->nElements,
+ hQC->vbrQualFactor);
+
+ return AAC_ENC_OK;
+}
+
+
+
+/*********************************************************************************
+
+ functionname: FDKaacEnc_QCMainPrepare
+ description:
+ return:
+
+**********************************************************************************/
+AAC_ENCODER_ERROR FDKaacEnc_QCMainPrepare(ELEMENT_INFO *elInfo,
+ ATS_ELEMENT* RESTRICT adjThrStateElement,
+ PSY_OUT_ELEMENT* RESTRICT psyOutElement,
+ QC_OUT_ELEMENT* RESTRICT qcOutElement,
+ AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig
+ )
+{
+ AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK;
+ INT nChannels = elInfo->nChannelsInEl;
+
+ PSY_OUT_CHANNEL** RESTRICT psyOutChannel = psyOutElement->psyOutChannel; /* may be modified in-place */
+
+ FDKaacEnc_CalcFormFactor(qcOutElement->qcOutChannel, psyOutChannel, nChannels);
+
+ /* prepare and calculate PE without reduction */
+ FDKaacEnc_peCalculation(&qcOutElement->peData, psyOutChannel, qcOutElement->qcOutChannel, &psyOutElement->toolsInfo, adjThrStateElement, nChannels);
+
+ ErrorStatus = FDKaacEnc_ChannelElementWrite( NULL, elInfo, NULL,
+ psyOutElement,
+ psyOutElement->psyOutChannel,
+ syntaxFlags,
+ aot,
+ epConfig,
+ &qcOutElement->staticBitsUsed,
+ 0 );
+
+ return ErrorStatus;
+}
+
+/*********************************************************************************
+
+ functionname: FDKaacEnc_AdjustBitrate
+ description: adjusts framelength via padding on a frame to frame basis,
+ to achieve a bitrate that demands a non byte aligned
+ framelength
+ return: errorcode
+
+**********************************************************************************/
+AAC_ENCODER_ERROR FDKaacEnc_AdjustBitrate(QC_STATE *RESTRICT hQC,
+ CHANNEL_MAPPING *RESTRICT cm,
+ INT *avgTotalBits,
+ INT bitRate, /* total bitrate */
+ INT sampleRate, /* output sampling rate */
+ INT granuleLength) /* frame length */
+{
+ INT paddingOn;
+ INT frameLen;
+
+ /* Do we need an extra padding byte? */
+ paddingOn = FDKaacEnc_framePadding(bitRate,
+ sampleRate,
+ granuleLength,
+ &hQC->padding.paddingRest);
+
+ frameLen = paddingOn + FDKaacEnc_calcFrameLen(bitRate,
+ sampleRate,
+ granuleLength,
+ FRAME_LEN_BYTES_INT);
+
+ *avgTotalBits = frameLen<<3;
+
+ return AAC_ENC_OK;
+}
+
+static AAC_ENCODER_ERROR FDKaacEnc_distributeElementDynBits(QC_STATE* hQC,
+ QC_OUT_ELEMENT* qcElement[(6)],
+ CHANNEL_MAPPING* cm,
+ INT codeBits)
+{
+
+ INT i, firstEl = cm->nElements-1;
+ INT totalBits = 0;
+
+ for (i=(cm->nElements-1); i>=0; i--) {
+ if ((cm->elInfo[i].elType == ID_SCE) || (cm->elInfo[i].elType == ID_CPE) ||
+ (cm->elInfo[i].elType == ID_LFE))
+ {
+ qcElement[i]->grantedDynBits = (INT)fMult(hQC->elementBits[i]->relativeBitsEl, (FIXP_DBL)codeBits);
+ totalBits += qcElement[i]->grantedDynBits;
+ firstEl = i;
+ }
+ }
+ qcElement[firstEl]->grantedDynBits += codeBits - totalBits;
+
+ return AAC_ENC_OK;
+}
+
+/**
+ * \brief Verify whether minBitsPerFrame criterion can be satisfied.
+ *
+ * This function evaluates the bit consumption only if minBitsPerFrame parameter is not 0.
+ * In hyperframing mode the difference between grantedDynBits and usedDynBits of all sub frames
+ * results the number of fillbits to be written.
+ * This bits can be distrubitued in superframe to reach minBitsPerFrame bit consumption in single AU's.
+ * The return value denotes if enough desired fill bits are available to achieve minBitsPerFrame in all frames.
+ * This check can only be used within superframes.
+ *
+ * \param qcOut Pointer to coding data struct.
+ * \param minBitsPerFrame Minimal number of bits to be consumed in each frame.
+ * \param nSubFrames Number of frames in superframe
+ *
+ * \return
+ * - 1: all fine
+ * - 0: criterion not fulfilled
+ */
+static int checkMinFrameBitsDemand(
+ QC_OUT** qcOut,
+ const INT minBitsPerFrame,
+ const INT nSubFrames
+ )
+{
+ int result = 1; /* all fine*/
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/*********************************************************************************
+
+ functionname: FDKaacEnc_getMinimalStaticBitdemand
+ description: calculate minmal size of static bits by reduction ,
+ to zero spectrum and deactivating tns and MS
+ return: number of static bits
+
+**********************************************************************************/
+static int FDKaacEnc_getMinimalStaticBitdemand(CHANNEL_MAPPING* cm,
+ PSY_OUT** psyOut)
+{
+ AUDIO_OBJECT_TYPE aot = AOT_AAC_LC;
+ UINT syntaxFlags = 0;
+ SCHAR epConfig = -1;
+ int i, bitcount = 0;
+
+ for (i=0; i<cm->nElements; i++) {
+ ELEMENT_INFO elInfo = cm->elInfo[i];
+
+ if ( (elInfo.elType == ID_SCE)
+ || (elInfo.elType == ID_CPE)
+ || (elInfo.elType == ID_LFE) )
+ {
+ INT minElBits = 0;
+
+ FDKaacEnc_ChannelElementWrite( NULL, &elInfo, NULL,
+ psyOut[0]->psyOutElement[i],
+ psyOut[0]->psyOutElement[i]->psyOutChannel,
+ syntaxFlags,
+ aot,
+ epConfig,
+ &minElBits,
+ 1 );
+ bitcount += minElBits;
+ }
+ }
+
+ return bitcount;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static AAC_ENCODER_ERROR FDKaacEnc_prepareBitDistribution(QC_STATE* hQC,
+ PSY_OUT** psyOut,
+ QC_OUT** qcOut,
+ CHANNEL_MAPPING* cm,
+ QC_OUT_ELEMENT* qcElement[(1)][(6)],
+ INT avgTotalBits,
+ INT *totalAvailableBits,
+ INT *avgTotalDynBits)
+{
+ int i;
+ /* get maximal allowed dynamic bits */
+ qcOut[0]->grantedDynBits = (fixMin(hQC->maxBitsPerFrame, avgTotalBits) - hQC->globHdrBits)&~7;
+ qcOut[0]->grantedDynBits -= (qcOut[0]->globalExtBits + qcOut[0]->staticBits + qcOut[0]->elementExtBits);
+ qcOut[0]->maxDynBits = ((hQC->maxBitsPerFrame)&~7) - (qcOut[0]->globalExtBits + qcOut[0]->staticBits + qcOut[0]->elementExtBits);
+ /* assure that enough bits are available */
+ if ((qcOut[0]->grantedDynBits+hQC->bitResTot) < 0) {
+ /* crash recovery allows to reduce static bits to a minimum */
+ if ( (qcOut[0]->grantedDynBits+hQC->bitResTot) < (FDKaacEnc_getMinimalStaticBitdemand(cm, psyOut)-qcOut[0]->staticBits) )
+ return AAC_ENC_BITRES_TOO_LOW;
+ }
+
+ /* distribute dynamic bits to each element */
+ FDKaacEnc_distributeElementDynBits(hQC,
+ qcElement[0],
+ cm,
+ qcOut[0]->grantedDynBits);
+
+ *avgTotalDynBits = 0; /*frameDynBits;*/
+
+ *totalAvailableBits = avgTotalBits;
+
+ /* sum up corrected granted PE */
+ qcOut[0]->totalGrantedPeCorr = 0;
+
+ for (i=0; i<cm->nElements; i++)
+ {
+ ELEMENT_INFO elInfo = cm->elInfo[i];
+ int nChannels = elInfo.nChannelsInEl;
+
+ if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) ||
+ (elInfo.elType == ID_LFE))
+ {
+ /* for ( all sub frames ) ... */
+ FDKaacEnc_DistributeBits(hQC->hAdjThr,
+ hQC->hAdjThr->adjThrStateElem[i],
+ psyOut[0]->psyOutElement[i]->psyOutChannel,
+ &qcElement[0][i]->peData,
+ &qcElement[0][i]->grantedPe,
+ &qcElement[0][i]->grantedPeCorr,
+ nChannels,
+ psyOut[0]->psyOutElement[i]->commonWindow,
+ qcElement[0][i]->grantedDynBits,
+ hQC->elementBits[i]->bitResLevelEl,
+ hQC->elementBits[i]->maxBitResBitsEl,
+ hQC->maxBitFac,
+ hQC->bitDistributenMode);
+
+ *totalAvailableBits += hQC->elementBits[i]->bitResLevelEl;
+ /* get total corrected granted PE */
+ qcOut[0]->totalGrantedPeCorr += qcElement[0][i]->grantedPeCorr;
+ } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */
+
+ } /* -end- element loop */
+
+ *totalAvailableBits = FDKmin(hQC->maxBitsPerFrame, (*totalAvailableBits));
+
+ return AAC_ENC_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+static AAC_ENCODER_ERROR FDKaacEnc_updateUsedDynBits(INT* sumDynBitsConsumed,
+ QC_OUT_ELEMENT* qcElement[(6)],
+ CHANNEL_MAPPING* cm)
+{
+ INT i;
+
+ *sumDynBitsConsumed = 0;
+
+ for (i=0; i<cm->nElements; i++)
+ {
+ ELEMENT_INFO elInfo = cm->elInfo[i];
+
+ if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) ||
+ (elInfo.elType == ID_LFE))
+ {
+ /* sum up bits consumed */
+ *sumDynBitsConsumed += qcElement[i]->dynBitsUsed;
+ } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */
+
+ } /* -end- element loop */
+
+ return AAC_ENC_OK;
+}
+
+
+static INT FDKaacEnc_getTotalConsumedDynBits(QC_OUT** qcOut,
+ INT nSubFrames)
+{
+ INT c, totalBits=0;
+
+ /* sum up bit consumption for all sub frames */
+ for (c=0; c<nSubFrames; c++)
+ {
+ /* bit consumption not valid if dynamic bits
+ not available in one sub frame */
+ if (qcOut[c]->usedDynBits==-1) return -1;
+ totalBits += qcOut[c]->usedDynBits;
+ }
+
+ return totalBits;
+
+}
+
+static INT FDKaacEnc_getTotalConsumedBits(QC_OUT** qcOut,
+ QC_OUT_ELEMENT* qcElement[(1)][(6)],
+ CHANNEL_MAPPING* cm,
+ INT globHdrBits,
+ INT nSubFrames)
+{
+ int c, i;
+ int totalUsedBits = 0;
+
+ for (c = 0 ; c < nSubFrames ; c++ )
+ {
+ int dataBits = 0;
+ for (i=0; i<cm->nElements; i++)
+ {
+ if ((cm->elInfo[i].elType == ID_SCE) || (cm->elInfo[i].elType == ID_CPE) ||
+ (cm->elInfo[i].elType == ID_LFE))
+ {
+ dataBits += qcElement[c][i]->dynBitsUsed + qcElement[c][i]->staticBitsUsed + qcElement[c][i]->extBitsUsed;
+ }
+ }
+ dataBits += qcOut[c]->globalExtBits;
+
+ totalUsedBits += (8 - (dataBits) % 8) % 8;
+ totalUsedBits += dataBits + globHdrBits; /* header bits for every frame */
+ }
+ return totalUsedBits;
+}
+
+static AAC_ENCODER_ERROR FDKaacEnc_BitResRedistribution(
+ QC_STATE *const hQC,
+ const CHANNEL_MAPPING *const cm,
+ const INT avgTotalBits
+ )
+{
+ /* check bitreservoir fill level */
+ if (hQC->bitResTot < 0) {
+ return AAC_ENC_BITRES_TOO_LOW;
+ }
+ else if (hQC->bitResTot > hQC->bitResTotMax) {
+ return AAC_ENC_BITRES_TOO_HIGH;
+ }
+ else {
+ INT i, firstEl = cm->nElements-1;
+ INT totalBits = 0, totalBits_max = 0;
+
+ int totalBitreservoir = FDKmin(hQC->bitResTot, (hQC->maxBitsPerFrame-avgTotalBits));
+ int totalBitreservoirMax = FDKmin(hQC->bitResTotMax, (hQC->maxBitsPerFrame-avgTotalBits));
+
+ int sc_bitResTot = CountLeadingBits(totalBitreservoir);
+ int sc_bitResTotMax = CountLeadingBits(totalBitreservoirMax);
+
+ for (i=(cm->nElements-1); i>=0; i--) {
+ if ((cm->elInfo[i].elType == ID_SCE) || (cm->elInfo[i].elType == ID_CPE) ||
+ (cm->elInfo[i].elType == ID_LFE))
+ {
+ hQC->elementBits[i]->bitResLevelEl = (INT)fMult(hQC->elementBits[i]->relativeBitsEl, (FIXP_DBL)(totalBitreservoir<<sc_bitResTot))>>sc_bitResTot;
+ totalBits += hQC->elementBits[i]->bitResLevelEl;
+
+ hQC->elementBits[i]->maxBitResBitsEl = (INT)fMult(hQC->elementBits[i]->relativeBitsEl, (FIXP_DBL)(totalBitreservoirMax<<sc_bitResTotMax))>>sc_bitResTotMax;
+ totalBits_max += hQC->elementBits[i]->maxBitResBitsEl;
+
+ firstEl = i;
+ }
+ }
+ hQC->elementBits[firstEl]->bitResLevelEl += totalBitreservoir - totalBits;
+ hQC->elementBits[firstEl]->maxBitResBitsEl += totalBitreservoirMax - totalBits_max;
+ }
+
+ return AAC_ENC_OK;
+}
+
+
+AAC_ENCODER_ERROR FDKaacEnc_QCMain(QC_STATE* RESTRICT hQC,
+ PSY_OUT** psyOut,
+ QC_OUT** qcOut,
+ INT avgTotalBits,
+ CHANNEL_MAPPING* cm
+ ,AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig
+ )
+{
+ int i, c;
+ AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK;
+ INT avgTotalDynBits = 0; /* maximal allowd dynamic bits for all frames */
+ INT totalAvailableBits = 0;
+ INT nSubFrames = 1;
+
+ /*-------------------------------------------- */
+ /* redistribute total bitreservoir to elements */
+ ErrorStatus = FDKaacEnc_BitResRedistribution(hQC, cm, avgTotalBits);
+ if (ErrorStatus != AAC_ENC_OK) {
+ return ErrorStatus;
+ }
+
+ /*-------------------------------------------- */
+ /* fastenc needs one time threshold simulation,
+ in case of multiple frames, one more guess has to be calculated */
+
+ /*-------------------------------------------- */
+ /* helper pointer */
+ QC_OUT_ELEMENT* qcElement[(1)][(6)];
+
+ /* work on a copy of qcChannel and qcElement */
+ for (i=0; i<cm->nElements; i++)
+ {
+ ELEMENT_INFO elInfo = cm->elInfo[i];
+
+ if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) ||
+ (elInfo.elType == ID_LFE))
+ {
+ /* for ( all sub frames ) ... */
+ for (c = 0 ; c < nSubFrames ; c++ )
+ {
+ {
+ qcElement[c][i] = qcOut[c]->qcElement[i];
+ }
+ }
+ }
+ }
+
+ /*-------------------------------------------- */
+ /*-------------------------------------------- */
+ if ( isConstantBitrateMode(hQC->bitrateMode) )
+ {
+ /* calc granted dynamic bits for sub frame and
+ distribute it to each element */
+ ErrorStatus = FDKaacEnc_prepareBitDistribution(
+ hQC,
+ psyOut,
+ qcOut,
+ cm,
+ qcElement,
+ avgTotalBits,
+ &totalAvailableBits,
+ &avgTotalDynBits);
+
+ if (ErrorStatus != AAC_ENC_OK) {
+ return ErrorStatus;
+ }
+ }
+ else {
+ qcOut[0]->grantedDynBits = ((hQC->maxBitsPerFrame - (hQC->globHdrBits))&~7)
+ - (qcOut[0]->globalExtBits + qcOut[0]->staticBits + qcOut[0]->elementExtBits);
+ qcOut[0]->maxDynBits = qcOut[0]->grantedDynBits;
+
+ totalAvailableBits = hQC->maxBitsPerFrame;
+ avgTotalDynBits = 0;
+ }
+
+#ifdef PNS_PRECOUNT_ENABLE
+ /* Calculate estimated pns bits and substract them from grantedDynBits to get a more accurate number of available bits. */
+ if (syntaxFlags & (AC_LD|AC_ELD))
+ {
+ int estimatedPnsBits = 0, ch;
+
+ for (ch=0; ch<cm->nChannels; ch++) {
+ qcOut[0]->pQcOutChannels[ch]->sectionData.noiseNrgBits = noisePreCount(psyOut[0]->pPsyOutChannels[ch]->noiseNrg, psyOut[0]->pPsyOutChannels[ch]->maxSfbPerGroup);
+ estimatedPnsBits += qcOut[0]->pQcOutChannels[ch]->sectionData.noiseNrgBits;
+ }
+ qcOut[0]->grantedDynBits -= estimatedPnsBits;
+ }
+#endif
+
+ /* for ( all sub frames ) ... */
+ for (c = 0 ; c < nSubFrames ; c++ )
+ {
+ /* for CBR and VBR mode */
+ FDKaacEnc_AdjustThresholds(hQC->hAdjThr->adjThrStateElem,
+ qcElement[c],
+ qcOut[c],
+ psyOut[c]->psyOutElement,
+ isConstantBitrateMode(hQC->bitrateMode),
+ cm);
+
+ } /* -end- sub frame counter */
+
+ /*-------------------------------------------- */
+ INT iterations[(1)][(6)];
+ INT chConstraintsFulfilled[(1)][(6)][(2)];
+ INT calculateQuant[(1)][(6)][(2)];
+ INT constraintsFulfilled[(1)][(6)];
+ /*-------------------------------------------- */
+
+
+ /* for ( all sub frames ) ... */
+ for (c = 0 ; c < nSubFrames ; c++ )
+ {
+ for (i=0; i<cm->nElements; i++)
+ {
+ ELEMENT_INFO elInfo = cm->elInfo[i];
+ INT ch, nChannels = elInfo.nChannelsInEl;
+
+ if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) ||
+ (elInfo.elType == ID_LFE))
+ {
+ /* Turn thresholds into scalefactors, optimize bit consumption and verify conformance */
+ FDKaacEnc_EstimateScaleFactors(psyOut[c]->psyOutElement[i]->psyOutChannel,
+ qcElement[c][i]->qcOutChannel,
+ hQC->invQuant,
+ cm->elInfo[i].nChannelsInEl);
+
+
+ /*-------------------------------------------- */
+ constraintsFulfilled[c][i] = 1;
+ iterations[c][i] = 0 ;
+
+ for (ch = 0; ch < nChannels; ch++)
+ {
+ chConstraintsFulfilled[c][i][ch] = 1;
+ calculateQuant[c][i][ch] = 1;
+ }
+
+ /*-------------------------------------------- */
+
+ } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */
+
+ } /* -end- element loop */
+
+ qcOut[c]->usedDynBits = -1;
+
+ } /* -end- sub frame counter */
+
+
+
+ INT quantizationDone = 0;
+ INT sumDynBitsConsumedTotal = 0;
+ INT decreaseBitConsumption = -1; /* no direction yet! */
+
+ /*-------------------------------------------- */
+ /* -start- Quantization loop ... */
+ /*-------------------------------------------- */
+ do /* until max allowed bits per frame and maxDynBits!=-1*/
+ {
+ quantizationDone = 0;
+
+ c = 0; /* get frame to process */
+
+ for (i=0; i<cm->nElements; i++)
+ {
+ ELEMENT_INFO elInfo = cm->elInfo[i];
+ INT ch, nChannels = elInfo.nChannelsInEl;
+
+ if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) ||
+ (elInfo.elType == ID_LFE))
+ {
+ do /* until spectral values < MAX_QUANT */
+ {
+ /*-------------------------------------------- */
+ if (!constraintsFulfilled[c][i])
+ {
+ FDKaacEnc_reduceBitConsumption(&iterations[c][i],
+ hQC->maxIterations,
+ (decreaseBitConsumption) ? 1 : -1,
+ chConstraintsFulfilled[c][i],
+ calculateQuant[c][i],
+ nChannels,
+ psyOut[c]->psyOutElement[i],
+ qcOut[c],
+ qcElement[c][i],
+ hQC->elementBits[i],
+ aot,
+ syntaxFlags,
+ epConfig);
+ }
+
+ /*-------------------------------------------- */
+ /*-------------------------------------------- */
+ constraintsFulfilled[c][i] = 1 ;
+
+ /*-------------------------------------------- */
+ /* quantize spectrum (per each channel) */
+ for (ch = 0; ch < nChannels; ch++)
+ {
+ /*-------------------------------------------- */
+ chConstraintsFulfilled[c][i][ch] = 1;
+
+ /*-------------------------------------------- */
+
+ if (calculateQuant[c][i][ch])
+ {
+ QC_OUT_CHANNEL* qcOutCh = qcElement[c][i]->qcOutChannel[ch];
+ PSY_OUT_CHANNEL* psyOutCh = psyOut[c]->psyOutElement[i]->psyOutChannel[ch];
+
+ calculateQuant[c][i][ch] = 0; /* calculate quantization only if necessary */
+
+ /*-------------------------------------------- */
+ FDKaacEnc_QuantizeSpectrum(psyOutCh->sfbCnt,
+ psyOutCh->maxSfbPerGroup,
+ psyOutCh->sfbPerGroup,
+ psyOutCh->sfbOffsets,
+ qcOutCh->mdctSpectrum,
+ qcOutCh->globalGain,
+ qcOutCh->scf,
+ qcOutCh->quantSpec) ;
+
+ /*-------------------------------------------- */
+ if (FDKaacEnc_calcMaxValueInSfb(psyOutCh->sfbCnt,
+ psyOutCh->maxSfbPerGroup,
+ psyOutCh->sfbPerGroup,
+ psyOutCh->sfbOffsets,
+ qcOutCh->quantSpec,
+ qcOutCh->maxValueInSfb) > MAX_QUANT)
+ {
+ chConstraintsFulfilled[c][i][ch] = 0;
+ constraintsFulfilled[c][i] = 0 ;
+ /* if quanizted value out of range; increase global gain! */
+ decreaseBitConsumption = 1;
+ }
+
+ /*-------------------------------------------- */
+
+ } /* if calculateQuant[c][i][ch] */
+
+ } /* channel loop */
+
+ /*-------------------------------------------- */
+ /* quantize spectrum (per each channel) */
+
+ /*-------------------------------------------- */
+
+ } while (!constraintsFulfilled[c][i]) ; /* does not regard bit consumption */
+
+
+ /*-------------------------------------------- */
+ /*-------------------------------------------- */
+ qcElement[c][i]->dynBitsUsed = 0 ; /* reset dynamic bits */
+
+ /* quantization valid in current channel! */
+ for (ch = 0; ch < nChannels; ch++)
+ {
+ QC_OUT_CHANNEL* qcOutCh = qcElement[c][i]->qcOutChannel[ch];
+ PSY_OUT_CHANNEL *psyOutCh = psyOut[c]->psyOutElement[i]->psyOutChannel[ch];
+
+ /* count dynamic bits */
+ INT chDynBits = FDKaacEnc_dynBitCount(hQC->hBitCounter,
+ qcOutCh->quantSpec,
+ qcOutCh->maxValueInSfb,
+ qcOutCh->scf,
+ psyOutCh->lastWindowSequence,
+ psyOutCh->sfbCnt,
+ psyOutCh->maxSfbPerGroup,
+ psyOutCh->sfbPerGroup,
+ psyOutCh->sfbOffsets,
+ &qcOutCh->sectionData,
+ psyOutCh->noiseNrg,
+ psyOutCh->isBook,
+ psyOutCh->isScale,
+ syntaxFlags) ;
+
+ /* sum up dynamic channel bits */
+ qcElement[c][i]->dynBitsUsed += chDynBits;
+ }
+
+ /* save dynBitsUsed for correction of bits2pe relation */
+ if(hQC->hAdjThr->adjThrStateElem[i]->dynBitsLast==-1) {
+ hQC->hAdjThr->adjThrStateElem[i]->dynBitsLast = qcElement[c][i]->dynBitsUsed;
+ }
+ } /* -end- if(ID_SCE || ID_CPE || ID_LFE) */
+
+ } /* -end- element loop */
+
+ /* update dynBits of current subFrame */
+ FDKaacEnc_updateUsedDynBits(&qcOut[c]->usedDynBits,
+ qcElement[c],
+ cm);
+
+ /* get total consumed bits, dyn bits in all sub frames have to be valid */
+ sumDynBitsConsumedTotal = FDKaacEnc_getTotalConsumedDynBits(qcOut, nSubFrames);
+
+ if (sumDynBitsConsumedTotal==-1)
+ {
+ quantizationDone = 0; /* bit consumption not valid in all sub frames */
+ }
+ else
+ {
+ int sumBitsConsumedTotal = FDKaacEnc_getTotalConsumedBits(qcOut, qcElement, cm, hQC->globHdrBits, nSubFrames);
+
+ /* in all frames are valid dynamic bits */
+ if (sumBitsConsumedTotal < totalAvailableBits && (decreaseBitConsumption==1) && checkMinFrameBitsDemand(qcOut,hQC->minBitsPerFrame,nSubFrames)
+ /*()*/ )
+ {
+ quantizationDone = 1; /* exit bit adjustment */
+ }
+ if (sumBitsConsumedTotal > totalAvailableBits && (decreaseBitConsumption==0) )
+// /*()*/ )
+ {
+ quantizationDone = 0; /* reset! */
+ break;
+ }
+ }
+
+
+ /*-------------------------------------------- */
+
+ int emergencyIterations = 1;
+ int dynBitsOvershoot = 0;
+
+ for (c = 0 ; c < nSubFrames ; c++ )
+ {
+ for (i=0; i<cm->nElements; i++)
+ {
+ ELEMENT_INFO elInfo = cm->elInfo[i];
+
+ if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) ||
+ (elInfo.elType == ID_LFE))
+ {
+ /* iteration limitation */
+ emergencyIterations &= ((iterations[c][i] < hQC->maxIterations) ? 0 : 1);
+ }
+ }
+ /* detection if used dyn bits exceeds the maximal allowed criterion */
+ dynBitsOvershoot |= ((qcOut[c]->usedDynBits > qcOut[c]->maxDynBits) ? 1 : 0);
+ }
+
+ if (quantizationDone==0 || dynBitsOvershoot)
+ {
+
+ int sumBitsConsumedTotal = FDKaacEnc_getTotalConsumedBits(qcOut, qcElement, cm, hQC->globHdrBits, nSubFrames);
+
+ if ( (sumDynBitsConsumedTotal >= avgTotalDynBits) || (sumDynBitsConsumedTotal==0) ) {
+ quantizationDone = 1;
+ }
+ if (emergencyIterations && (sumBitsConsumedTotal < totalAvailableBits)) {
+ quantizationDone = 1;
+ }
+ if ((sumBitsConsumedTotal > totalAvailableBits) || !checkMinFrameBitsDemand(qcOut,hQC->minBitsPerFrame,nSubFrames)) {
+ quantizationDone = 0;
+ }
+ if ((sumBitsConsumedTotal < totalAvailableBits) && checkMinFrameBitsDemand(qcOut,hQC->minBitsPerFrame,nSubFrames)) {
+ decreaseBitConsumption = 0;
+ }
+ else {
+ decreaseBitConsumption = 1;
+ }
+
+ if (dynBitsOvershoot) {
+ quantizationDone = 0;
+ decreaseBitConsumption = 1;
+ }
+
+ /* reset constraints fullfilled flags */
+ FDKmemclear(constraintsFulfilled, sizeof(constraintsFulfilled));
+ FDKmemclear(chConstraintsFulfilled, sizeof(chConstraintsFulfilled));
+
+
+ }/* quantizationDone */
+
+ } while (!quantizationDone) ;
+
+ /*-------------------------------------------- */
+ /* ... -end- Quantization loop */
+ /*-------------------------------------------- */
+
+ /*-------------------------------------------- */
+ /*-------------------------------------------- */
+
+ return AAC_ENC_OK;
+}
+
+
+static AAC_ENCODER_ERROR FDKaacEnc_reduceBitConsumption(int* iterations,
+ const int maxIterations,
+ int gainAdjustment,
+ int* chConstraintsFulfilled,
+ int* calculateQuant,
+ int nChannels,
+ PSY_OUT_ELEMENT* psyOutElement,
+ QC_OUT* qcOut,
+ QC_OUT_ELEMENT* qcOutElement,
+ ELEMENT_BITS* elBits,
+ AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig)
+{
+ int ch;
+
+ /** SOLVING PROBLEM **/
+ if ((*iterations)++ >= maxIterations)
+ {
+ if (qcOutElement->dynBitsUsed==0) {
+ }
+ /* crash recovery */
+ else {
+ INT bitsToSave = 0;
+ if ( (bitsToSave = fixMax((qcOutElement->dynBitsUsed + 8) - (elBits->bitResLevelEl + qcOutElement->grantedDynBits),
+ (qcOutElement->dynBitsUsed + qcOutElement->staticBitsUsed + 8) - (elBits->maxBitsEl))) > 0 )
+ {
+ FDKaacEnc_crashRecovery(nChannels,
+ psyOutElement,
+ qcOut,
+ qcOutElement,
+ bitsToSave,
+ aot,
+ syntaxFlags,
+ epConfig) ;
+ }
+ else
+ {
+ for (ch = 0; ch < nChannels; ch++)
+ {
+ qcOutElement->qcOutChannel[ch]->globalGain += 1;
+ }
+ }
+ for (ch = 0; ch < nChannels; ch++)
+ {
+ calculateQuant[ch] = 1;
+ }
+ }
+ }
+ else /* iterations >= maxIterations */
+ {
+ /* increase gain (+ next iteration) */
+ for (ch = 0; ch < nChannels; ch++)
+ {
+ if(!chConstraintsFulfilled[ch])
+ {
+ qcOutElement->qcOutChannel[ch]->globalGain += gainAdjustment ;
+ calculateQuant[ch] = 1; /* global gain has changed, recalculate quantization in next iteration! */
+ }
+ }
+ }
+
+ return AAC_ENC_OK;
+}
+
+AAC_ENCODER_ERROR FDKaacEnc_updateFillBits(CHANNEL_MAPPING* cm,
+ QC_STATE* qcKernel,
+ ELEMENT_BITS* RESTRICT elBits[(6)],
+ QC_OUT** qcOut)
+{
+ switch (qcKernel->bitrateMode) {
+ case QCDATA_BR_MODE_SFR:
+ break;
+
+ case QCDATA_BR_MODE_FF:
+ break;
+
+ case QCDATA_BR_MODE_VBR_1:
+ case QCDATA_BR_MODE_VBR_2:
+ case QCDATA_BR_MODE_VBR_3:
+ case QCDATA_BR_MODE_VBR_4:
+ case QCDATA_BR_MODE_VBR_5:
+ qcOut[0]->totFillBits = (qcOut[0]->grantedDynBits - qcOut[0]->usedDynBits)&7; /* precalculate alignment bits */
+ break;
+
+ case QCDATA_BR_MODE_CBR:
+ case QCDATA_BR_MODE_INVALID:
+ default:
+ INT bitResSpace = qcKernel->bitResTotMax - qcKernel->bitResTot ;
+ /* processing fill-bits */
+ INT deltaBitRes = qcOut[0]->grantedDynBits - qcOut[0]->usedDynBits ;
+ qcOut[0]->totFillBits = fixMax((deltaBitRes&7), (deltaBitRes - (fixMax(0,bitResSpace-7)&~7)));
+ break;
+ } /* switch (qcKernel->bitrateMode) */
+
+ return AAC_ENC_OK;
+}
+
+
+
+
+/*********************************************************************************
+
+ functionname: FDKaacEnc_calcMaxValueInSfb
+ description:
+ return:
+
+**********************************************************************************/
+
+static INT FDKaacEnc_calcMaxValueInSfb(INT sfbCnt,
+ INT maxSfbPerGroup,
+ INT sfbPerGroup,
+ INT *RESTRICT sfbOffset,
+ SHORT *RESTRICT quantSpectrum,
+ UINT *RESTRICT maxValue)
+{
+ INT sfbOffs,sfb;
+ INT maxValueAll = 0;
+
+ for (sfbOffs=0;sfbOffs<sfbCnt;sfbOffs+=sfbPerGroup)
+ for (sfb = 0; sfb < maxSfbPerGroup; sfb++)
+ {
+ INT line;
+ INT maxThisSfb = 0;
+ for (line = sfbOffset[sfbOffs+sfb]; line < sfbOffset[sfbOffs+sfb+1]; line++)
+ {
+ INT tmp = fixp_abs(quantSpectrum[line]);
+ maxThisSfb = fixMax(tmp, maxThisSfb);
+ }
+
+ maxValue[sfbOffs+sfb] = maxThisSfb;
+ maxValueAll = fixMax(maxThisSfb, maxValueAll);
+ }
+ return maxValueAll;
+}
+
+
+/*********************************************************************************
+
+ functionname: FDKaacEnc_updateBitres
+ description:
+ return:
+
+**********************************************************************************/
+void FDKaacEnc_updateBitres(CHANNEL_MAPPING *cm,
+ QC_STATE* qcKernel,
+ QC_OUT** qcOut)
+{
+ switch (qcKernel->bitrateMode) {
+ case QCDATA_BR_MODE_FF:
+ case QCDATA_BR_MODE_VBR_1:
+ case QCDATA_BR_MODE_VBR_2:
+ case QCDATA_BR_MODE_VBR_3:
+ case QCDATA_BR_MODE_VBR_4:
+ case QCDATA_BR_MODE_VBR_5:
+ /* variable bitrate */
+ qcKernel->bitResTot = FDKmin(qcKernel->maxBitsPerFrame, qcKernel->bitResTotMax);
+ break;
+
+ case QCDATA_BR_MODE_CBR:
+ case QCDATA_BR_MODE_SFR:
+ case QCDATA_BR_MODE_INVALID:
+ default:
+ int c = 0;
+ /* constant bitrate */
+ {
+ qcKernel->bitResTot += qcOut[c]->grantedDynBits - (qcOut[c]->usedDynBits + qcOut[c]->totFillBits + qcOut[c]->alignBits);
+ }
+ break;
+ }
+}
+
+/*********************************************************************************
+
+ functionname: FDKaacEnc_FinalizeBitConsumption
+ description:
+ return:
+
+**********************************************************************************/
+AAC_ENCODER_ERROR FDKaacEnc_FinalizeBitConsumption(CHANNEL_MAPPING *cm,
+ QC_STATE *qcKernel,
+ QC_OUT *qcOut,
+ QC_OUT_ELEMENT** qcElement,
+ HANDLE_TRANSPORTENC hTpEnc,
+ AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig)
+{
+ QC_OUT_EXTENSION fillExtPayload;
+ INT totFillBits, alignBits;
+
+ {
+ int exactTpBits;
+ int max_iter = 3;
+
+ /* Get total consumed bits in AU */
+ qcOut->totalBits = qcOut->staticBits + qcOut->usedDynBits + qcOut->totFillBits +
+ qcOut->elementExtBits + qcOut->globalExtBits;
+
+ /* Now we can get the exact transport bit amount, and hopefully it is equal to the estimated value */
+ exactTpBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits);
+
+ while (exactTpBits != qcKernel->globHdrBits && (max_iter-- > 0))
+ {
+ INT diffBits = qcKernel->globHdrBits-exactTpBits;
+ if (diffBits >= 0) {
+ /* move bits from header to payload */
+ qcOut->totFillBits += diffBits;
+ qcOut->totalBits += diffBits;
+ qcOut->grantedDynBits += diffBits;
+ }
+ else {
+ /* get missing bits from bitreservoir */
+ qcKernel->bitResTot += diffBits;
+ }
+ qcKernel->globHdrBits = exactTpBits;
+ exactTpBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits);
+ }
+ FDK_ASSERT(exactTpBits == qcKernel->globHdrBits);
+ }
+
+ /* Save total fill bits and distribut to alignment and fill bits */
+ totFillBits = qcOut->totFillBits;
+
+ /* fake a fill extension payload */
+ FDKmemclear(&fillExtPayload, sizeof(QC_OUT_EXTENSION));
+
+ fillExtPayload.type = EXT_FILL_DATA;
+ fillExtPayload.nPayloadBits = totFillBits;
+
+ /* ask bitstream encoder how many of that bits can be written in a fill extension data entity */
+ qcOut->totFillBits = FDKaacEnc_writeExtensionData( NULL,
+ &fillExtPayload,
+ 0, 0,
+ syntaxFlags,
+ aot,
+ epConfig );
+
+ /* now distribute extra fillbits and alignbits */
+ alignBits = 7 - (qcOut->staticBits + qcOut->usedDynBits + qcOut->elementExtBits
+ + qcOut->totFillBits + qcOut->globalExtBits -1)%8;
+
+ /* Maybe we could remove this */
+ if( ((alignBits + qcOut->totFillBits - totFillBits)==8) && (qcOut->totFillBits>8) )
+ qcOut->totFillBits -= 8;
+
+ qcOut->totalBits = qcOut->staticBits + qcOut->usedDynBits + qcOut->totFillBits +
+ alignBits + qcOut->elementExtBits + qcOut->globalExtBits;
+
+ if ( (qcOut->totalBits>qcKernel->maxBitsPerFrame) || (qcOut->totalBits<qcKernel->minBitsPerFrame) ) {
+ return AAC_ENC_QUANT_ERROR;
+ }
+
+ qcOut->alignBits = alignBits;
+
+ return AAC_ENC_OK;
+}
+
+
+
+/*********************************************************************************
+
+ functionname: FDKaacEnc_crashRecovery
+ description: fulfills constraints by means of brute force...
+ => bits are saved by cancelling out spectral lines!!
+ (beginning at the highest frequencies)
+ return: errorcode
+
+**********************************************************************************/
+
+static void FDKaacEnc_crashRecovery(INT nChannels,
+ PSY_OUT_ELEMENT* psyOutElement,
+ QC_OUT* qcOut,
+ QC_OUT_ELEMENT *qcElement,
+ INT bitsToSave,
+ AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig)
+{
+ INT ch ;
+ INT savedBits = 0 ;
+ INT sfb, sfbGrp ;
+ INT bitsPerScf[(2)][MAX_GROUPED_SFB] ;
+ INT sectionToScf[(2)][MAX_GROUPED_SFB] ;
+ INT *sfbOffset ;
+ INT sect, statBitsNew ;
+ QC_OUT_CHANNEL **qcChannel = qcElement->qcOutChannel;
+ PSY_OUT_CHANNEL **psyChannel = psyOutElement->psyOutChannel;
+
+ /* create a table which converts frq-bins to bit-demand... [bitsPerScf] */
+ /* ...and another one which holds the corresponding sections [sectionToScf] */
+ for (ch = 0; ch < nChannels; ch++)
+ {
+ sfbOffset = psyChannel[ch]->sfbOffsets ;
+
+ for (sect = 0; sect < qcChannel[ch]->sectionData.noOfSections; sect++)
+ {
+ INT sfb ;
+ INT codeBook = qcChannel[ch]->sectionData.huffsection[sect].codeBook ;
+
+ for (sfb = qcChannel[ch]->sectionData.huffsection[sect].sfbStart;
+ sfb < qcChannel[ch]->sectionData.huffsection[sect].sfbStart +
+ qcChannel[ch]->sectionData.huffsection[sect].sfbCnt;
+ sfb++)
+ {
+ bitsPerScf[ch][sfb] = 0;
+ if ( (codeBook != CODE_BOOK_PNS_NO) /*&&
+ (sfb < (qcChannel[ch]->sectionData.noOfGroups*qcChannel[ch]->sectionData.maxSfbPerGroup))*/ )
+ {
+ INT sfbStartLine = sfbOffset[sfb] ;
+ INT noOfLines = sfbOffset[sfb+1] - sfbStartLine ;
+ bitsPerScf[ch][sfb] = FDKaacEnc_countValues(&(qcChannel[ch]->quantSpec[sfbStartLine]), noOfLines, codeBook) ;
+ }
+ sectionToScf[ch][sfb] = sect ;
+ }
+
+ }
+ }
+
+ /* LOWER [maxSfb] IN BOTH CHANNELS!! */
+ /* Attention: in case of stereo: maxSfbL == maxSfbR, GroupingL == GroupingR ; */
+
+ for (sfb = qcChannel[0]->sectionData.maxSfbPerGroup-1; sfb >= 0; sfb--)
+ {
+ for (sfbGrp = 0; sfbGrp < psyChannel[0]->sfbCnt; sfbGrp += psyChannel[0]->sfbPerGroup)
+ {
+ for (ch = 0; ch < nChannels; ch++)
+ {
+ int sect = sectionToScf[ch][sfbGrp+sfb];
+ qcChannel[ch]->sectionData.huffsection[sect].sfbCnt-- ;
+ savedBits += bitsPerScf[ch][sfbGrp+sfb] ;
+
+ if (qcChannel[ch]->sectionData.huffsection[sect].sfbCnt == 0) {
+ savedBits += (psyChannel[ch]->lastWindowSequence!=SHORT_WINDOW) ? FDKaacEnc_sideInfoTabLong[0]
+ : FDKaacEnc_sideInfoTabShort[0];
+ }
+ }
+ }
+
+ /* ...have enough bits been saved? */
+ if (savedBits >= bitsToSave)
+ break ;
+
+ } /* sfb loop */
+
+ /* if not enough bits saved,
+ clean whole spectrum and remove side info overhead */
+ if (sfb == -1) {
+ sfb = 0 ;
+ }
+
+ for (ch = 0; ch < nChannels; ch++)
+ {
+ qcChannel[ch]->sectionData.maxSfbPerGroup = sfb ;
+ psyChannel[ch]->maxSfbPerGroup = sfb ;
+ /* when no spectrum is coded save tools info in bitstream */
+ if(sfb==0) {
+ FDKmemclear(&psyChannel[ch]->tnsInfo, sizeof(TNS_INFO));
+ FDKmemclear(&psyOutElement->toolsInfo, sizeof(TOOLSINFO));
+ }
+ }
+ /* dynamic bits will be updated in iteration loop */
+
+ { /* if stop sfb has changed save bits in side info, e.g. MS or TNS coding */
+ ELEMENT_INFO elInfo;
+
+ FDKmemclear(&elInfo, sizeof(ELEMENT_INFO));
+ elInfo.nChannelsInEl = nChannels;
+ elInfo.elType = (nChannels == 2) ? ID_CPE : ID_SCE;
+
+ FDKaacEnc_ChannelElementWrite( NULL, &elInfo, NULL,
+ psyOutElement,
+ psyChannel,
+ syntaxFlags,
+ aot,
+ epConfig,
+ &statBitsNew,
+ 0 );
+ }
+
+ savedBits = qcElement->staticBitsUsed - statBitsNew;
+
+ /* update static and dynamic bits */
+ qcElement->staticBitsUsed -= savedBits;
+ qcElement->grantedDynBits += savedBits;
+
+ qcOut->staticBits -= savedBits;
+ qcOut->grantedDynBits += savedBits;
+ qcOut->maxDynBits += savedBits;
+
+
+}
+
+
+
+void FDKaacEnc_QCClose (QC_STATE **phQCstate, QC_OUT **phQC)
+{
+ int n, i;
+
+ if (phQC!=NULL) {
+
+ for (n=0;n<(1);n++) {
+ if (phQC[n] != NULL) {
+ QC_OUT *hQC = phQC[n];
+ for (i=0; i<(6); i++) {
+ }
+
+ for (i=0; i<(6); i++) {
+ if (hQC->qcElement[i])
+ FreeRam_aacEnc_QCelement(&hQC->qcElement[i]);
+ }
+
+ FreeRam_aacEnc_QCout(&phQC[n]);
+ }
+ }
+ }
+
+ if (phQCstate!=NULL) {
+ if (*phQCstate != NULL) {
+ QC_STATE *hQCstate = *phQCstate;
+
+ if (hQCstate->hAdjThr != NULL)
+ FDKaacEnc_AdjThrClose(&hQCstate->hAdjThr);
+
+ if (hQCstate->hBitCounter != NULL)
+ FDKaacEnc_BCClose(&hQCstate->hBitCounter);
+
+ for (i=0; i<(6); i++) {
+ if (hQCstate->elementBits[i]!=NULL) {
+ FreeRam_aacEnc_ElementBits(&hQCstate->elementBits[i]);
+ }
+ }
+ FreeRam_aacEnc_QCstate(phQCstate);
+ }
+ }
+}
+
diff --git a/libAACenc/src/qc_main.h b/libAACenc/src/qc_main.h
new file mode 100644
index 0000000..1335a22
--- /dev/null
+++ b/libAACenc/src/qc_main.h
@@ -0,0 +1,108 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: Quantizing & coding
+
+******************************************************************************/
+#ifndef _QC_MAIN_H
+#define _QC_MAIN_H
+
+
+#include "aacenc.h"
+#include "qc_data.h"
+#include "interface.h"
+#include "psy_main.h"
+#include "tpenc_lib.h"
+
+/* Quantizing & coding stage */
+
+AAC_ENCODER_ERROR FDKaacEnc_QCOutNew(QC_OUT **phQC,
+ const INT nElements,
+ const INT nChannels,
+ const INT nSubFrames
+ ,UCHAR *dynamic_RAM
+ );
+
+AAC_ENCODER_ERROR FDKaacEnc_QCOutInit(QC_OUT *phQC[(1)],
+ const INT nSubFrames,
+ const CHANNEL_MAPPING *cm);
+
+AAC_ENCODER_ERROR FDKaacEnc_QCNew(QC_STATE **phQC,
+ INT nElements
+ ,UCHAR* dynamic_RAM
+ );
+
+AAC_ENCODER_ERROR FDKaacEnc_QCInit(QC_STATE *hQC, struct QC_INIT *init);
+
+AAC_ENCODER_ERROR FDKaacEnc_QCMainPrepare(
+ ELEMENT_INFO *elInfo,
+ ATS_ELEMENT* RESTRICT adjThrStateElement,
+ PSY_OUT_ELEMENT* RESTRICT psyOutElement,
+ QC_OUT_ELEMENT* RESTRICT qcOutElement, /* returns error code */
+ AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig
+ );
+
+
+AAC_ENCODER_ERROR FDKaacEnc_QCMain(QC_STATE* RESTRICT hQC,
+ PSY_OUT** psyOut,
+ QC_OUT** qcOut,
+ INT avgTotalBits,
+ CHANNEL_MAPPING* cm
+ ,AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig
+ );
+
+AAC_ENCODER_ERROR FDKaacEnc_updateFillBits(CHANNEL_MAPPING* cm,
+ QC_STATE* qcKernel,
+ ELEMENT_BITS* RESTRICT elBits[(6)],
+ QC_OUT** qcOut);
+
+
+void FDKaacEnc_updateBitres( CHANNEL_MAPPING *cm,
+ QC_STATE *qcKernel,
+ QC_OUT **qcOut);
+
+AAC_ENCODER_ERROR FDKaacEnc_FinalizeBitConsumption( CHANNEL_MAPPING *cm,
+ QC_STATE *hQC,
+ QC_OUT *qcOut,
+ QC_OUT_ELEMENT** qcElement,
+ HANDLE_TRANSPORTENC hTpEnc,
+ AUDIO_OBJECT_TYPE aot,
+ UINT syntaxFlags,
+ SCHAR epConfig
+ );
+
+AAC_ENCODER_ERROR FDKaacEnc_AdjustBitrate(QC_STATE *RESTRICT hQC,
+ CHANNEL_MAPPING *RESTRICT cm,
+ INT *avgTotalBits,
+ INT bitRate,
+ INT sampleRate,
+ INT granuleLength);
+
+void FDKaacEnc_QCClose (QC_STATE **phQCstate, QC_OUT **phQC);
+
+#endif /* _QC_MAIN_H */
diff --git a/libAACenc/src/quantize.cpp b/libAACenc/src/quantize.cpp
new file mode 100644
index 0000000..b8eb5de
--- /dev/null
+++ b/libAACenc/src/quantize.cpp
@@ -0,0 +1,323 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Quantization
+
+******************************************************************************/
+
+#include "quantize.h"
+
+#include "aacEnc_rom.h"
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_quantizeLines
+ description: quantizes spectrum lines
+ returns:
+ input: global gain, number of lines to process, spectral data
+ output: quantized spectrum
+
+*****************************************************************************/
+static void FDKaacEnc_quantizeLines(INT gain,
+ INT noOfLines,
+ FIXP_DBL *mdctSpectrum,
+ SHORT *quaSpectrum)
+{
+ int line;
+ FIXP_DBL k = FL2FXCONST_DBL(-0.0946f + 0.5f)>>16;
+ FIXP_QTD quantizer = FDKaacEnc_quantTableQ[(-gain)&3];
+ INT quantizershift = ((-gain)>>2)+1;
+
+
+ for (line = 0; line < noOfLines; line++)
+ {
+ FIXP_DBL accu = fMultDiv2(mdctSpectrum[line],quantizer);
+
+ if (accu < FL2FXCONST_DBL(0.0f))
+ {
+ accu=-accu;
+ /* normalize */
+ INT accuShift = CntLeadingZeros(accu) - 1; /* CountLeadingBits() is not necessary here since test value is always > 0 */
+ accu <<= accuShift;
+ INT tabIndex = (INT)(accu>>(DFRACT_BITS-2-MANT_DIGITS))&(~MANT_SIZE);
+ INT totalShift = quantizershift-accuShift+1;
+ accu = fMultDiv2(FDKaacEnc_mTab_3_4[tabIndex],FDKaacEnc_quantTableE[totalShift&3]);
+ totalShift = (16-4)-(3*(totalShift>>2));
+ FDK_ASSERT(totalShift >=0); /* MAX_QUANT_VIOLATION */
+ accu>>=totalShift;
+ quaSpectrum[line] = (SHORT)(-((LONG)(k + accu) >> (DFRACT_BITS-1-16)));
+ }
+ else if(accu > FL2FXCONST_DBL(0.0f))
+ {
+ /* normalize */
+ INT accuShift = CntLeadingZeros(accu) - 1; /* CountLeadingBits() is not necessary here since test value is always > 0 */
+ accu <<= accuShift;
+ INT tabIndex = (INT)(accu>>(DFRACT_BITS-2-MANT_DIGITS))&(~MANT_SIZE);
+ INT totalShift = quantizershift-accuShift+1;
+ accu = fMultDiv2(FDKaacEnc_mTab_3_4[tabIndex],FDKaacEnc_quantTableE[totalShift&3]);
+ totalShift = (16-4)-(3*(totalShift>>2));
+ FDK_ASSERT(totalShift >=0); /* MAX_QUANT_VIOLATION */
+ accu>>=totalShift;
+ quaSpectrum[line] = (SHORT)((LONG)(k + accu) >> (DFRACT_BITS-1-16));
+ }
+ else
+ quaSpectrum[line]=0;
+ }
+}
+
+
+/*****************************************************************************
+
+ functionname:iFDKaacEnc_quantizeLines
+ description: iquantizes spectrum lines
+ mdctSpectrum = iquaSpectrum^4/3 *2^(0.25*gain)
+ input: global gain, number of lines to process,quantized spectrum
+ output: spectral data
+
+*****************************************************************************/
+static void FDKaacEnc_invQuantizeLines(INT gain,
+ INT noOfLines,
+ SHORT *quantSpectrum,
+ FIXP_DBL *mdctSpectrum)
+
+{
+ INT iquantizermod;
+ INT iquantizershift;
+ INT line;
+
+ iquantizermod = gain&3;
+ iquantizershift = gain>>2;
+
+ for (line = 0; line < noOfLines; line++) {
+
+ if(quantSpectrum[line] < 0) {
+ FIXP_DBL accu;
+ INT ex,specExp,tabIndex;
+ FIXP_DBL s,t;
+
+ accu = (FIXP_DBL) -quantSpectrum[line];
+
+ ex = CountLeadingBits(accu);
+ accu <<= ex;
+ specExp = (DFRACT_BITS-1) - ex;
+
+ FDK_ASSERT(specExp < 14); /* this fails if abs(value) > 8191 */
+
+ tabIndex = (INT)(accu>>(DFRACT_BITS-2-MANT_DIGITS))&(~MANT_SIZE);
+
+ /* calculate "mantissa" ^4/3 */
+ s = FDKaacEnc_mTab_4_3Elc[tabIndex];
+
+ /* get approperiate exponent multiplier for specExp^3/4 combined with scfMod */
+ t = FDKaacEnc_specExpMantTableCombElc[iquantizermod][specExp];
+
+ /* multiply "mantissa" ^4/3 with exponent multiplier */
+ accu = fMult(s,t);
+
+ /* get approperiate exponent shifter */
+ specExp = FDKaacEnc_specExpTableComb[iquantizermod][specExp]-1; /* -1 to avoid overflows in accu */
+
+ if ((-iquantizershift-specExp) < 0)
+ accu <<= -(-iquantizershift-specExp);
+ else
+ accu >>= -iquantizershift-specExp;
+
+ mdctSpectrum[line] = -accu;
+ }
+ else if (quantSpectrum[line] > 0) {
+ FIXP_DBL accu;
+ INT ex,specExp,tabIndex;
+ FIXP_DBL s,t;
+
+ accu = (FIXP_DBL)(INT)quantSpectrum[line];
+
+ ex = CountLeadingBits(accu);
+ accu <<= ex;
+ specExp = (DFRACT_BITS-1) - ex;
+
+ FDK_ASSERT(specExp < 14); /* this fails if abs(value) > 8191 */
+
+ tabIndex = (INT)(accu>>(DFRACT_BITS-2-MANT_DIGITS))&(~MANT_SIZE);
+
+ /* calculate "mantissa" ^4/3 */
+ s = FDKaacEnc_mTab_4_3Elc[tabIndex];
+
+ /* get approperiate exponent multiplier for specExp^3/4 combined with scfMod */
+ t = FDKaacEnc_specExpMantTableCombElc[iquantizermod][specExp];
+
+ /* multiply "mantissa" ^4/3 with exponent multiplier */
+ accu = fMult(s,t);
+
+ /* get approperiate exponent shifter */
+ specExp = FDKaacEnc_specExpTableComb[iquantizermod][specExp]-1; /* -1 to avoid overflows in accu */
+
+ if (( -iquantizershift-specExp) < 0)
+ accu <<= -(-iquantizershift-specExp);
+ else
+ accu >>= -iquantizershift-specExp;
+
+ mdctSpectrum[line] = accu;
+ }
+ else {
+ mdctSpectrum[line] = FL2FXCONST_DBL(0.0f);
+ }
+ }
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_QuantizeSpectrum
+ description: quantizes the entire spectrum
+ returns:
+ input: number of scalefactor bands to be quantized, ...
+ output: quantized spectrum
+
+*****************************************************************************/
+void FDKaacEnc_QuantizeSpectrum(INT sfbCnt,
+ INT maxSfbPerGroup,
+ INT sfbPerGroup,
+ INT *sfbOffset,
+ FIXP_DBL *mdctSpectrum,
+ INT globalGain,
+ INT *scalefactors,
+ SHORT *quantizedSpectrum)
+{
+ INT sfbOffs,sfb;
+
+ /* in FDKaacEnc_quantizeLines quaSpectrum is calculated with:
+ spec^(3/4) * 2^(-3/16*QSS) * 2^(3/4*scale) + k
+ simplify scaling calculation and reduce QSS before:
+ spec^(3/4) * 2^(-3/16*(QSS - 4*scale)) */
+
+ for(sfbOffs=0;sfbOffs<sfbCnt;sfbOffs+=sfbPerGroup)
+ for (sfb = 0; sfb < maxSfbPerGroup; sfb++)
+ {
+ INT scalefactor = scalefactors[sfbOffs+sfb] ;
+
+ FDKaacEnc_quantizeLines(globalGain - scalefactor, /* QSS */
+ sfbOffset[sfbOffs+sfb+1] - sfbOffset[sfbOffs+sfb],
+ mdctSpectrum + sfbOffset[sfbOffs+sfb],
+ quantizedSpectrum + sfbOffset[sfbOffs+sfb]);
+ }
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_calcSfbDist
+ description: calculates distortion of quantized values
+ returns: distortion
+ input: gain, number of lines to process, spectral data
+ output:
+
+*****************************************************************************/
+FIXP_DBL FDKaacEnc_calcSfbDist(FIXP_DBL *mdctSpectrum,
+ SHORT *quantSpectrum,
+ INT noOfLines,
+ INT gain
+ )
+{
+ INT i,scale;
+ FIXP_DBL xfsf;
+ FIXP_DBL diff;
+ FIXP_DBL invQuantSpec;
+
+ xfsf = FL2FXCONST_DBL(0.0f);
+
+ for (i=0; i<noOfLines; i++) {
+ /* quantization */
+ FDKaacEnc_quantizeLines(gain,
+ 1,
+ &mdctSpectrum[i],
+ &quantSpectrum[i]);
+
+ /* inverse quantization */
+ FDKaacEnc_invQuantizeLines(gain,1,&quantSpectrum[i],&invQuantSpec);
+
+ /* dist */
+ diff = fixp_abs(fixp_abs(invQuantSpec) - fixp_abs(mdctSpectrum[i]>>1));
+
+ scale = CountLeadingBits(diff);
+ diff = scaleValue(diff, scale);
+ diff = fPow2(diff);
+ scale = fixMin(2*(scale-1), DFRACT_BITS-1);
+
+ diff = scaleValue(diff, -scale);
+
+ xfsf = xfsf + diff;
+ }
+
+ xfsf = CalcLdData(xfsf);
+
+ return xfsf;
+}
+
+/*****************************************************************************
+
+ functionname: FDKaacEnc_calcSfbQuantEnergyAndDist
+ description: calculates energy and distortion of quantized values
+ returns:
+ input: gain, number of lines to process, quantized spectral data,
+ spectral data
+ output: energy, distortion
+
+*****************************************************************************/
+void FDKaacEnc_calcSfbQuantEnergyAndDist(FIXP_DBL *mdctSpectrum,
+ SHORT *quantSpectrum,
+ INT noOfLines,
+ INT gain,
+ FIXP_DBL *en,
+ FIXP_DBL *dist)
+{
+ INT i,scale;
+ FIXP_DBL invQuantSpec;
+ FIXP_DBL diff;
+
+ *en = FL2FXCONST_DBL(0.0f);
+ *dist = FL2FXCONST_DBL(0.0f);
+
+ for (i=0; i<noOfLines; i++) {
+ /* inverse quantization */
+ FDKaacEnc_invQuantizeLines(gain,1,&quantSpectrum[i],&invQuantSpec);
+
+ /* energy */
+ *en += fPow2(invQuantSpec);
+
+ /* dist */
+ diff = fixp_abs(fixp_abs(invQuantSpec) - fixp_abs(mdctSpectrum[i]>>1));
+
+ scale = CountLeadingBits(diff);
+ diff = scaleValue(diff, scale);
+ diff = fPow2(diff);
+
+ scale = fixMin(2*(scale-1), DFRACT_BITS-1);
+
+ diff = scaleValue(diff, -scale);
+
+ *dist += diff;
+ }
+
+ *en = CalcLdData(*en)+FL2FXCONST_DBL(0.03125f);
+ *dist = CalcLdData(*dist);
+}
+
diff --git a/libAACenc/src/quantize.h b/libAACenc/src/quantize.h
new file mode 100644
index 0000000..8568ef7
--- /dev/null
+++ b/libAACenc/src/quantize.h
@@ -0,0 +1,56 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Quantization
+
+******************************************************************************/
+#ifndef _QUANTIZE_H_
+#define _QUANTIZE_H_
+
+#include "common_fix.h"
+
+/* quantizing */
+
+#define MAX_QUANT 8191
+
+void FDKaacEnc_QuantizeSpectrum(INT sfbCnt,
+ INT maxSfbPerGroup,
+ INT sfbPerGroup,
+ INT *sfbOffset, FIXP_DBL *mdctSpectrum,
+ INT globalGain, INT *scalefactors,
+ SHORT *quantizedSpectrum);
+
+FIXP_DBL FDKaacEnc_calcSfbDist(FIXP_DBL *mdctSpectrum,
+ SHORT *quantSpectrum,
+ INT noOfLines,
+ INT gain);
+
+void FDKaacEnc_calcSfbQuantEnergyAndDist(FIXP_DBL *mdctSpectrum,
+ SHORT *quantSpectrum,
+ INT noOfLines,
+ INT gain,
+ FIXP_DBL *en,
+ FIXP_DBL *dist);
+
+#endif /* _QUANTIZE_H_ */
diff --git a/libAACenc/src/sf_estim.cpp b/libAACenc/src/sf_estim.cpp
new file mode 100644
index 0000000..59b20ed
--- /dev/null
+++ b/libAACenc/src/sf_estim.cpp
@@ -0,0 +1,1243 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: Scale factor estimation
+
+******************************************************************************/
+
+#include "sf_estim.h"
+#include "aacEnc_rom.h"
+#include "quantize.h"
+#include "bit_cnt.h"
+
+
+
+
+#define AS_PE_FAC_SHIFT 7
+#define DIST_FAC_SHIFT 3
+#define AS_PE_FAC_FLOAT (float)(1 << AS_PE_FAC_SHIFT)
+static const INT MAX_SCF_DELTA = 60;
+
+
+static const FIXP_DBL PE_C1 = FL2FXCONST_DBL(3.0f/AS_PE_FAC_FLOAT); /* (log(8.0)/log(2)) >> AS_PE_FAC_SHIFT */
+static const FIXP_DBL PE_C2 = FL2FXCONST_DBL(1.3219281f/AS_PE_FAC_FLOAT); /* (log(2.5)/log(2)) >> AS_PE_FAC_SHIFT */
+static const FIXP_DBL PE_C3 = FL2FXCONST_DBL(0.5593573f); /* 1-C2/C1 */
+
+
+/*
+ Function; FDKaacEnc_FDKaacEnc_CalcFormFactorChannel
+
+ Description: Calculates the formfactor
+
+ sf: scale factor of the mdct spectrum
+ sfbFormFactorLdData is scaled with the factor 1/(((2^sf)^0.5) * (2^FORM_FAC_SHIFT))
+*/
+static void
+FDKaacEnc_FDKaacEnc_CalcFormFactorChannel(FIXP_DBL *RESTRICT sfbFormFactorLdData,
+ PSY_OUT_CHANNEL *RESTRICT psyOutChan)
+{
+ INT j, sfb, sfbGrp;
+ FIXP_DBL formFactor;
+
+ int tmp0 = psyOutChan->sfbCnt;
+ int tmp1 = psyOutChan->maxSfbPerGroup;
+ int step = psyOutChan->sfbPerGroup;
+ for(sfbGrp = 0; sfbGrp < tmp0; sfbGrp += step) {
+ for (sfb = 0; sfb < tmp1; sfb++) {
+ formFactor = FL2FXCONST_DBL(0.0f);
+ /* calc sum of sqrt(spec) */
+ for(j=psyOutChan->sfbOffsets[sfbGrp+sfb]; j<psyOutChan->sfbOffsets[sfbGrp+sfb+1]; j++ ) {
+ formFactor += sqrtFixp(fixp_abs(psyOutChan->mdctSpectrum[j]))>>FORM_FAC_SHIFT;
+ }
+ sfbFormFactorLdData[sfbGrp+sfb] = CalcLdData(formFactor);
+ }
+ /* set sfbFormFactor for sfbs with zero spec to zero. Just for debugging. */
+ for ( ; sfb < psyOutChan->sfbPerGroup; sfb++) {
+ sfbFormFactorLdData[sfbGrp+sfb] = FL2FXCONST_DBL(-1.0f);
+ }
+ }
+}
+
+/*
+ Function: FDKaacEnc_CalcFormFactor
+
+ Description: Calls FDKaacEnc_FDKaacEnc_CalcFormFactorChannel() for each channel
+*/
+
+void
+FDKaacEnc_CalcFormFactor(QC_OUT_CHANNEL *qcOutChannel[(2)],
+ PSY_OUT_CHANNEL *psyOutChannel[(2)],
+ const INT nChannels)
+{
+ INT j;
+ for (j=0; j<nChannels; j++) {
+ FDKaacEnc_FDKaacEnc_CalcFormFactorChannel(qcOutChannel[j]->sfbFormFactorLdData, psyOutChannel[j]);
+ }
+}
+
+/*
+ Function: FDKaacEnc_calcSfbRelevantLines
+
+ Description: Calculates sfbNRelevantLines
+
+ sfbNRelevantLines is scaled with the factor 1/((2^FORM_FAC_SHIFT) * 2.0)
+*/
+static void
+FDKaacEnc_calcSfbRelevantLines( const FIXP_DBL *const sfbFormFactorLdData,
+ const FIXP_DBL *const sfbEnergyLdData,
+ const FIXP_DBL *const sfbThresholdLdData,
+ const INT *const sfbOffsets,
+ const INT sfbCnt,
+ const INT sfbPerGroup,
+ const INT maxSfbPerGroup,
+ FIXP_DBL *sfbNRelevantLines)
+{
+ INT sfbOffs, sfb;
+ FIXP_DBL sfbWidthLdData;
+ FIXP_DBL asPeFacLdData = FL2FXCONST_DBL(0.109375); /* AS_PE_FAC_SHIFT*ld64(2) */
+ FIXP_DBL accu;
+
+ /* sfbNRelevantLines[i] = 2^( (sfbFormFactorLdData[i] - 0.25 * (sfbEnergyLdData[i] - ld64(sfbWidth[i]/(2^7)) - AS_PE_FAC_SHIFT*ld64(2)) * 64); */
+
+ FDKmemclear(sfbNRelevantLines, sfbCnt * sizeof(FIXP_DBL));
+
+ for (sfbOffs=0; sfbOffs<sfbCnt; sfbOffs+=sfbPerGroup) {
+ for(sfb=0; sfb<maxSfbPerGroup; sfb++) {
+ /* calc sum of sqrt(spec) */
+ if((FIXP_DBL)sfbEnergyLdData[sfbOffs+sfb] > (FIXP_DBL)sfbThresholdLdData[sfbOffs+sfb]) {
+ INT sfbWidth = sfbOffsets[sfbOffs+sfb+1] - sfbOffsets[sfbOffs+sfb];
+
+ /* avgFormFactorLdData = sqrtFixp(sqrtFixp(sfbEnergyLdData[sfbOffs+sfb]/sfbWidth)); */
+ /* sfbNRelevantLines[sfbOffs+sfb] = sfbFormFactor[sfbOffs+sfb] / avgFormFactorLdData; */
+ sfbWidthLdData = (FIXP_DBL)(sfbWidth << (DFRACT_BITS-1-AS_PE_FAC_SHIFT));
+ sfbWidthLdData = CalcLdData(sfbWidthLdData);
+
+ accu = sfbEnergyLdData[sfbOffs+sfb] - sfbWidthLdData - asPeFacLdData;
+ accu = sfbFormFactorLdData[sfbOffs+sfb] - (accu >> 2);
+
+ sfbNRelevantLines[sfbOffs+sfb] = CalcInvLdData(accu) >> 1;
+ }
+ }
+ }
+}
+
+/*
+ Function: FDKaacEnc_countSingleScfBits
+
+ Description:
+
+ scfBitsFract is scaled by 1/(2^(2*AS_PE_FAC_SHIFT))
+*/
+static FIXP_DBL FDKaacEnc_countSingleScfBits(INT scf, INT scfLeft, INT scfRight)
+{
+ FIXP_DBL scfBitsFract;
+
+ scfBitsFract = (FIXP_DBL) ( FDKaacEnc_bitCountScalefactorDelta(scfLeft-scf)
+ + FDKaacEnc_bitCountScalefactorDelta(scf-scfRight) );
+
+ scfBitsFract = scfBitsFract << (DFRACT_BITS-1-(2*AS_PE_FAC_SHIFT));
+
+ return scfBitsFract; /* output scaled by 1/(2^(2*AS_PE_FAC)) */
+}
+
+/*
+ Function: FDKaacEnc_calcSingleSpecPe
+
+ specPe is scaled by 1/(2^(2*AS_PE_FAC_SHIFT))
+*/
+static FIXP_DBL FDKaacEnc_calcSingleSpecPe(INT scf, FIXP_DBL sfbConstPePart, FIXP_DBL nLines)
+{
+ FIXP_DBL specPe = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL ldRatio;
+ FIXP_DBL scfFract;
+
+ scfFract = (FIXP_DBL)(scf << (DFRACT_BITS-1-AS_PE_FAC_SHIFT));
+
+ ldRatio = sfbConstPePart - fMult(FL2FXCONST_DBL(0.375f),scfFract);
+
+ if (ldRatio >= PE_C1) {
+ specPe = fMult(FL2FXCONST_DBL(0.7f),fMult(nLines,ldRatio));
+ }
+ else {
+ specPe = fMult(FL2FXCONST_DBL(0.7f),fMult(nLines,(PE_C2 + fMult(PE_C3,ldRatio))));
+ }
+
+ return specPe; /* output scaled by 1/(2^(2*AS_PE_FAC)) */
+}
+
+/*
+ Function: FDKaacEnc_countScfBitsDiff
+
+ scfBitsDiff is scaled by 1/(2^(2*AS_PE_FAC_SHIFT))
+*/
+static FIXP_DBL FDKaacEnc_countScfBitsDiff(INT *scfOld,
+ INT *scfNew,
+ INT sfbCnt,
+ INT startSfb,
+ INT stopSfb)
+{
+ FIXP_DBL scfBitsFract;
+ INT scfBitsDiff = 0;
+ INT sfb = 0, sfbLast;
+ INT sfbPrev, sfbNext;
+
+ /* search for first relevant sfb */
+ sfbLast = startSfb;
+ while ((sfbLast<stopSfb) && (scfOld[sfbLast]==FDK_INT_MIN))
+ sfbLast++;
+ /* search for previous relevant sfb and count diff */
+ sfbPrev = startSfb - 1;
+ while ((sfbPrev>=0) && (scfOld[sfbPrev]==FDK_INT_MIN))
+ sfbPrev--;
+ if (sfbPrev>=0)
+ scfBitsDiff += FDKaacEnc_bitCountScalefactorDelta(scfNew[sfbPrev]-scfNew[sfbLast]) -
+ FDKaacEnc_bitCountScalefactorDelta(scfOld[sfbPrev]-scfOld[sfbLast]);
+ /* now loop through all sfbs and count diffs of relevant sfbs */
+ for (sfb=sfbLast+1; sfb<stopSfb; sfb++) {
+ if (scfOld[sfb]!=FDK_INT_MIN) {
+ scfBitsDiff += FDKaacEnc_bitCountScalefactorDelta(scfNew[sfbLast]-scfNew[sfb]) -
+ FDKaacEnc_bitCountScalefactorDelta(scfOld[sfbLast]-scfOld[sfb]);
+ sfbLast = sfb;
+ }
+ }
+ /* search for next relevant sfb and count diff */
+ sfbNext = stopSfb;
+ while ((sfbNext<sfbCnt) && (scfOld[sfbNext]==FDK_INT_MIN))
+ sfbNext++;
+ if (sfbNext<sfbCnt)
+ scfBitsDiff += FDKaacEnc_bitCountScalefactorDelta(scfNew[sfbLast]-scfNew[sfbNext]) -
+ FDKaacEnc_bitCountScalefactorDelta(scfOld[sfbLast]-scfOld[sfbNext]);
+
+ scfBitsFract = (FIXP_DBL) (scfBitsDiff << (DFRACT_BITS-1-(2*AS_PE_FAC_SHIFT)));
+
+ return scfBitsFract;
+}
+
+/*
+ Function: FDKaacEnc_calcSpecPeDiff
+
+ specPeDiff is scaled by 1/(2^(2*AS_PE_FAC_SHIFT))
+*/
+static FIXP_DBL FDKaacEnc_calcSpecPeDiff(PSY_OUT_CHANNEL *psyOutChan,
+ QC_OUT_CHANNEL *qcOutChannel,
+ INT *scfOld,
+ INT *scfNew,
+ FIXP_DBL *sfbConstPePart,
+ FIXP_DBL *sfbFormFactorLdData,
+ FIXP_DBL *sfbNRelevantLines,
+ INT startSfb,
+ INT stopSfb)
+{
+ FIXP_DBL specPeDiff = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL scfFract = FL2FXCONST_DBL(0.0f);
+ INT sfb;
+
+ /* loop through all sfbs and count pe difference */
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scfOld[sfb]!=FDK_INT_MIN) {
+ FIXP_DBL ldRatioOld, ldRatioNew, pOld, pNew;
+
+ /* sfbConstPePart[sfb] = (float)log(psyOutChan->sfbEnergy[sfb] * 6.75f / sfbFormFactor[sfb]) * LOG2_1; */
+ /* 0.02152255861f = log(6.75)/log(2)/AS_PE_FAC_FLOAT; LOG2_1 is 1.0 for log2 */
+ /* 0.09375f = log(64.0)/log(2.0)/64.0 = scale of sfbFormFactorLdData */
+ if (sfbConstPePart[sfb] == (FIXP_DBL)FDK_INT_MIN)
+ sfbConstPePart[sfb] = ((psyOutChan->sfbEnergyLdData[sfb] - sfbFormFactorLdData[sfb] - FL2FXCONST_DBL(0.09375f)) >> 1) + FL2FXCONST_DBL(0.02152255861f);
+
+ scfFract = (FIXP_DBL) (scfOld[sfb] << (DFRACT_BITS-1-AS_PE_FAC_SHIFT));
+ ldRatioOld = sfbConstPePart[sfb] - fMult(FL2FXCONST_DBL(0.375f),scfFract);
+
+ scfFract = (FIXP_DBL) (scfNew[sfb] << (DFRACT_BITS-1-AS_PE_FAC_SHIFT));
+ ldRatioNew = sfbConstPePart[sfb] - fMult(FL2FXCONST_DBL(0.375f),scfFract);
+
+ if (ldRatioOld >= PE_C1)
+ pOld = ldRatioOld;
+ else
+ pOld = PE_C2 + fMult(PE_C3,ldRatioOld);
+
+ if (ldRatioNew >= PE_C1)
+ pNew = ldRatioNew;
+ else
+ pNew = PE_C2 + fMult(PE_C3,ldRatioNew);
+
+ specPeDiff += fMult(FL2FXCONST_DBL(0.7f),fMult(sfbNRelevantLines[sfb],(pNew - pOld)));
+ }
+ }
+
+ return specPeDiff;
+}
+
+/*
+ Function: FDKaacEnc_improveScf
+
+ Description: Calculate the distortion by quantization and inverse quantization of the spectrum with
+ various scalefactors. The scalefactor which provides the best results will be used.
+*/
+static INT FDKaacEnc_improveScf(FIXP_DBL *spec,
+ SHORT *quantSpec,
+ SHORT *quantSpecTmp,
+ INT sfbWidth,
+ FIXP_DBL threshLdData,
+ INT scf,
+ INT minScf,
+ FIXP_DBL *distLdData,
+ INT *minScfCalculated
+ )
+{
+ FIXP_DBL sfbDistLdData;
+ INT scfBest = scf;
+ INT k;
+ FIXP_DBL distFactorLdData = FL2FXCONST_DBL(-0.0050301265); /* ld64(1/1.25) */
+
+ /* calc real distortion */
+ sfbDistLdData = FDKaacEnc_calcSfbDist(spec,
+ quantSpec,
+ sfbWidth,
+ scf);
+ *minScfCalculated = scf;
+ /* nmr > 1.25 -> try to improve nmr */
+ if (sfbDistLdData > (threshLdData-distFactorLdData)) {
+ INT scfEstimated = scf;
+ FIXP_DBL sfbDistBestLdData = sfbDistLdData;
+ INT cnt;
+ /* improve by bigger scf ? */
+ cnt = 0;
+
+ while ((sfbDistLdData > (threshLdData-distFactorLdData)) && (cnt++ < 3)) {
+ scf++;
+ sfbDistLdData = FDKaacEnc_calcSfbDist(spec,
+ quantSpecTmp,
+ sfbWidth,
+ scf);
+
+ if (sfbDistLdData < sfbDistBestLdData) {
+ scfBest = scf;
+ sfbDistBestLdData = sfbDistLdData;
+ for (k=0; k<sfbWidth; k++)
+ quantSpec[k] = quantSpecTmp[k];
+ }
+ }
+ /* improve by smaller scf ? */
+ cnt = 0;
+ scf = scfEstimated;
+ sfbDistLdData = sfbDistBestLdData;
+ while ((sfbDistLdData > (threshLdData-distFactorLdData)) && (cnt++ < 1) && (scf > minScf)) {
+ scf--;
+ sfbDistLdData = FDKaacEnc_calcSfbDist(spec,
+ quantSpecTmp,
+ sfbWidth,
+ scf);
+
+ if (sfbDistLdData < sfbDistBestLdData) {
+ scfBest = scf;
+ sfbDistBestLdData = sfbDistLdData;
+ for (k=0; k<sfbWidth; k++)
+ quantSpec[k] = quantSpecTmp[k];
+ }
+ *minScfCalculated = scf;
+ }
+ *distLdData = sfbDistBestLdData;
+ }
+ else { /* nmr <= 1.25 -> try to find bigger scf to use less bits */
+ FIXP_DBL sfbDistBestLdData = sfbDistLdData;
+ FIXP_DBL sfbDistAllowedLdData = fixMin(sfbDistLdData-distFactorLdData,threshLdData);
+ int cnt;
+ for (cnt=0; cnt<3; cnt++) {
+ scf++;
+ sfbDistLdData = FDKaacEnc_calcSfbDist(spec,
+ quantSpecTmp,
+ sfbWidth,
+ scf);
+
+ if (sfbDistLdData < sfbDistAllowedLdData) {
+ *minScfCalculated = scfBest+1;
+ scfBest = scf;
+ sfbDistBestLdData = sfbDistLdData;
+ for (k=0; k<sfbWidth; k++)
+ quantSpec[k] = quantSpecTmp[k];
+ }
+ }
+ *distLdData = sfbDistBestLdData;
+ }
+
+ /* return best scalefactor */
+ return scfBest;
+}
+
+/*
+ Function: FDKaacEnc_assimilateSingleScf
+
+*/
+static void FDKaacEnc_assimilateSingleScf(PSY_OUT_CHANNEL *psyOutChan,
+ QC_OUT_CHANNEL *qcOutChannel,
+ SHORT *quantSpec,
+ SHORT *quantSpecTmp,
+ INT *scf,
+ INT *minScf,
+ FIXP_DBL *sfbDist,
+ FIXP_DBL *sfbConstPePart,
+ FIXP_DBL *sfbFormFactorLdData,
+ FIXP_DBL *sfbNRelevantLines,
+ INT *minScfCalculated,
+ INT restartOnSuccess)
+{
+ INT sfbLast, sfbAct, sfbNext;
+ INT scfAct, *scfLast, *scfNext, scfMin, scfMax;
+ INT sfbWidth, sfbOffs;
+ FIXP_DBL enLdData;
+ FIXP_DBL sfbPeOld, sfbPeNew;
+ FIXP_DBL sfbDistNew;
+ INT i, k;
+ INT success = 0;
+ FIXP_DBL deltaPe = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL deltaPeNew, deltaPeTmp;
+ INT prevScfLast[MAX_GROUPED_SFB], prevScfNext[MAX_GROUPED_SFB];
+ FIXP_DBL deltaPeLast[MAX_GROUPED_SFB];
+ INT updateMinScfCalculated;
+
+ /* setINT(FDK_INT_MAX, prevScfLast, psyOutChan->sfbActive); */
+ /* setINT(FDK_INT_MAX, prevScfNext, psyOutChan->sfbActive); */
+ /* setFLOAT(FLT_MAX, deltaPeLast, psyOutChan->sfbActive); */
+
+ for (i=0; i<psyOutChan->sfbCnt; i++) {
+ prevScfLast[i] = FDK_INT_MAX;
+ prevScfNext[i] = FDK_INT_MAX;
+ deltaPeLast[i] = (FIXP_DBL)FDK_INT_MAX;
+ }
+
+ sfbLast = -1;
+ sfbAct = -1;
+ sfbNext = -1;
+ scfLast = 0;
+ scfNext = 0;
+ scfMin = FDK_INT_MAX;
+ scfMax = FDK_INT_MAX;
+ do {
+ /* search for new relevant sfb */
+ sfbNext++;
+ while ((sfbNext < psyOutChan->sfbCnt) && (scf[sfbNext] == FDK_INT_MIN))
+ sfbNext++;
+ if ((sfbLast>=0) && (sfbAct>=0) && (sfbNext<psyOutChan->sfbCnt)) {
+ /* relevant scfs to the left and to the right */
+ scfAct = scf[sfbAct];
+ scfLast = scf + sfbLast;
+ scfNext = scf + sfbNext;
+ scfMin = fixMin(*scfLast, *scfNext);
+ scfMax = fixMax(*scfLast, *scfNext);
+ }
+ else if ((sfbLast==-1) && (sfbAct>=0) && (sfbNext<psyOutChan->sfbCnt)) {
+ /* first relevant scf */
+ scfAct = scf[sfbAct];
+ scfLast = &scfAct;
+ scfNext = scf + sfbNext;
+ scfMin = *scfNext;
+ scfMax = *scfNext;
+ }
+ else if ((sfbLast>=0) && (sfbAct>=0) && (sfbNext==psyOutChan->sfbCnt)) {
+ /* last relevant scf */
+ scfAct = scf[sfbAct];
+ scfLast = scf + sfbLast;
+ scfNext = &scfAct;
+ scfMin = *scfLast;
+ scfMax = *scfLast;
+ }
+ if (sfbAct>=0)
+ scfMin = fixMax(scfMin, minScf[sfbAct]);
+
+ if ((sfbAct >= 0) &&
+ (sfbLast>=0 || sfbNext<psyOutChan->sfbCnt) &&
+ (scfAct > scfMin) &&
+ (scfAct <= scfMin+MAX_SCF_DELTA) &&
+ (scfAct >= scfMax-MAX_SCF_DELTA) &&
+ (*scfLast != prevScfLast[sfbAct] ||
+ *scfNext != prevScfNext[sfbAct] ||
+ deltaPe < deltaPeLast[sfbAct])) {
+ /* bigger than neighbouring scf found, try to use smaller scf */
+ success = 0;
+
+ sfbWidth = psyOutChan->sfbOffsets[sfbAct+1] - psyOutChan->sfbOffsets[sfbAct];
+ sfbOffs = psyOutChan->sfbOffsets[sfbAct];
+
+ /* estimate required bits for actual scf */
+ enLdData = qcOutChannel->sfbEnergyLdData[sfbAct];
+
+ /* sfbConstPePart[sfbAct] = (float)log(6.75f*en/sfbFormFactor[sfbAct]) * LOG2_1; */
+ /* 0.02152255861f = log(6.75)/log(2)/AS_PE_FAC_FLOAT; LOG2_1 is 1.0 for log2 */
+ /* 0.09375f = log(64.0)/log(2.0)/64.0 = scale of sfbFormFactorLdData */
+ if (sfbConstPePart[sfbAct] == (FIXP_DBL)FDK_INT_MIN) {
+ sfbConstPePart[sfbAct] = ((enLdData - sfbFormFactorLdData[sfbAct] - FL2FXCONST_DBL(0.09375f)) >> 1) + FL2FXCONST_DBL(0.02152255861f);
+ }
+
+ sfbPeOld = FDKaacEnc_calcSingleSpecPe(scfAct,sfbConstPePart[sfbAct],sfbNRelevantLines[sfbAct])
+ +FDKaacEnc_countSingleScfBits(scfAct, *scfLast, *scfNext);
+
+ deltaPeNew = deltaPe;
+ updateMinScfCalculated = 1;
+
+ do {
+ /* estimate required bits for smaller scf */
+ scfAct--;
+ /* check only if the same check was not done before */
+ if (scfAct < minScfCalculated[sfbAct] && scfAct>=scfMax-MAX_SCF_DELTA){
+ /* estimate required bits for new scf */
+ sfbPeNew = FDKaacEnc_calcSingleSpecPe(scfAct,sfbConstPePart[sfbAct],sfbNRelevantLines[sfbAct])
+ +FDKaacEnc_countSingleScfBits(scfAct,*scfLast, *scfNext);
+
+ /* use new scf if no increase in pe and
+ quantization error is smaller */
+ deltaPeTmp = deltaPe + sfbPeNew - sfbPeOld;
+ /* 0.0006103515625f = 10.0f/(2^(2*AS_PE_FAC_SHIFT)) */
+ if (deltaPeTmp < FL2FXCONST_DBL(0.0006103515625f)) {
+ /* distortion of new scf */
+ sfbDistNew = FDKaacEnc_calcSfbDist(qcOutChannel->mdctSpectrum+sfbOffs,
+ quantSpecTmp+sfbOffs,
+ sfbWidth,
+ scfAct);
+
+ if (sfbDistNew < sfbDist[sfbAct]) {
+ /* success, replace scf by new one */
+ scf[sfbAct] = scfAct;
+ sfbDist[sfbAct] = sfbDistNew;
+
+ for (k=0; k<sfbWidth; k++)
+ quantSpec[sfbOffs+k] = quantSpecTmp[sfbOffs+k];
+
+ deltaPeNew = deltaPeTmp;
+ success = 1;
+ }
+ /* mark as already checked */
+ if (updateMinScfCalculated)
+ minScfCalculated[sfbAct] = scfAct;
+ }
+ else {
+ /* from this scf value on not all new values have been checked */
+ updateMinScfCalculated = 0;
+ }
+ }
+ } while (scfAct > scfMin);
+
+ deltaPe = deltaPeNew;
+
+ /* save parameters to avoid multiple computations of the same sfb */
+ prevScfLast[sfbAct] = *scfLast;
+ prevScfNext[sfbAct] = *scfNext;
+ deltaPeLast[sfbAct] = deltaPe;
+ }
+
+ if (success && restartOnSuccess) {
+ /* start again at first sfb */
+ sfbLast = -1;
+ sfbAct = -1;
+ sfbNext = -1;
+ scfLast = 0;
+ scfNext = 0;
+ scfMin = FDK_INT_MAX;
+ scfMax = FDK_INT_MAX;
+ success = 0;
+ }
+ else {
+ /* shift sfbs for next band */
+ sfbLast = sfbAct;
+ sfbAct = sfbNext;
+ }
+ } while (sfbNext < psyOutChan->sfbCnt);
+}
+
+/*
+ Function: FDKaacEnc_assimilateMultipleScf
+
+*/
+static void FDKaacEnc_assimilateMultipleScf(PSY_OUT_CHANNEL *psyOutChan,
+ QC_OUT_CHANNEL *qcOutChannel,
+ SHORT *quantSpec,
+ SHORT *quantSpecTmp,
+ INT *scf,
+ INT *minScf,
+ FIXP_DBL *sfbDist,
+ FIXP_DBL *sfbConstPePart,
+ FIXP_DBL *sfbFormFactorLdData,
+ FIXP_DBL *sfbNRelevantLines)
+{
+ INT sfb, startSfb, stopSfb;
+ INT scfTmp[MAX_GROUPED_SFB], scfMin, scfMax, scfAct;
+ INT possibleRegionFound;
+ INT sfbWidth, sfbOffs, i, k;
+ FIXP_DBL sfbDistNew[MAX_GROUPED_SFB], distOldSum, distNewSum;
+ INT deltaScfBits;
+ FIXP_DBL deltaSpecPe;
+ FIXP_DBL deltaPe = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL deltaPeNew;
+ INT sfbCnt = psyOutChan->sfbCnt;
+
+ /* calc min and max scalfactors */
+ scfMin = FDK_INT_MAX;
+ scfMax = FDK_INT_MIN;
+ for (sfb=0; sfb<sfbCnt; sfb++) {
+ if (scf[sfb]!=FDK_INT_MIN) {
+ scfMin = fixMin(scfMin, scf[sfb]);
+ scfMax = fixMax(scfMax, scf[sfb]);
+ }
+ }
+
+ if (scfMax != FDK_INT_MIN && scfMax <= scfMin+MAX_SCF_DELTA) {
+
+ scfAct = scfMax;
+
+ do {
+ /* try smaller scf */
+ scfAct--;
+ for (i=0; i<MAX_GROUPED_SFB; i++)
+ scfTmp[i] = scf[i];
+ stopSfb = 0;
+ do {
+ /* search for region where all scfs are bigger than scfAct */
+ sfb = stopSfb;
+ while (sfb<sfbCnt && (scf[sfb]==FDK_INT_MIN || scf[sfb] <= scfAct))
+ sfb++;
+ startSfb = sfb;
+ sfb++;
+ while (sfb<sfbCnt && (scf[sfb]==FDK_INT_MIN || scf[sfb] > scfAct))
+ sfb++;
+ stopSfb = sfb;
+
+ /* check if in all sfb of a valid region scfAct >= minScf[sfb] */
+ possibleRegionFound = 0;
+ if (startSfb < sfbCnt) {
+ possibleRegionFound = 1;
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scf[sfb] != FDK_INT_MIN)
+ if (scfAct < minScf[sfb]) {
+ possibleRegionFound = 0;
+ break;
+ }
+ }
+ }
+
+ if (possibleRegionFound) { /* region found */
+
+ /* replace scfs in region by scfAct */
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scfTmp[sfb] != FDK_INT_MIN)
+ scfTmp[sfb] = scfAct;
+ }
+
+ /* estimate change in bit demand for new scfs */
+ deltaScfBits = FDKaacEnc_countScfBitsDiff(scf,scfTmp,sfbCnt,startSfb,stopSfb);
+
+ deltaSpecPe = FDKaacEnc_calcSpecPeDiff(psyOutChan, qcOutChannel, scf, scfTmp, sfbConstPePart,
+ sfbFormFactorLdData, sfbNRelevantLines,
+ startSfb, stopSfb);
+
+ deltaPeNew = deltaPe + (FIXP_DBL)deltaScfBits + deltaSpecPe;
+
+ /* new bit demand small enough ? */
+ /* 0.0006103515625f = 10.0f/(2^(2*AS_PE_FAC_SHIFT)) */
+ if (deltaPeNew < FL2FXCONST_DBL(0.0006103515625f)) {
+
+ /* quantize and calc sum of new distortion */
+ distOldSum = distNewSum = FL2FXCONST_DBL(0.0f);
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scfTmp[sfb] != FDK_INT_MIN) {
+ distOldSum += CalcInvLdData(sfbDist[sfb]) >> DIST_FAC_SHIFT;
+
+ sfbWidth = psyOutChan->sfbOffsets[sfb+1] - psyOutChan->sfbOffsets[sfb];
+ sfbOffs = psyOutChan->sfbOffsets[sfb];
+
+ sfbDistNew[sfb] = FDKaacEnc_calcSfbDist(qcOutChannel->mdctSpectrum+sfbOffs,
+ quantSpecTmp+sfbOffs,
+ sfbWidth,
+ scfAct);
+
+ if (sfbDistNew[sfb] >qcOutChannel->sfbThresholdLdData[sfb]) {
+ /* no improvement, skip further dist. calculations */
+ distNewSum = distOldSum << 1;
+ break;
+ }
+ distNewSum += CalcInvLdData(sfbDistNew[sfb]) >> DIST_FAC_SHIFT;
+ }
+ }
+ /* distortion smaller ? -> use new scalefactors */
+ if (distNewSum < distOldSum) {
+ deltaPe = deltaPeNew;
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scf[sfb] != FDK_INT_MIN) {
+ sfbWidth = psyOutChan->sfbOffsets[sfb+1] -
+ psyOutChan->sfbOffsets[sfb];
+ sfbOffs = psyOutChan->sfbOffsets[sfb];
+ scf[sfb] = scfAct;
+ sfbDist[sfb] = sfbDistNew[sfb];
+
+ for (k=0; k<sfbWidth; k++)
+ quantSpec[sfbOffs+k] = quantSpecTmp[sfbOffs+k];
+ }
+ }
+ }
+
+ }
+ }
+
+ } while (stopSfb <= sfbCnt);
+
+ } while (scfAct > scfMin);
+ }
+}
+
+/*
+ Function: FDKaacEnc_FDKaacEnc_assimilateMultipleScf2
+
+*/
+static void FDKaacEnc_FDKaacEnc_assimilateMultipleScf2(PSY_OUT_CHANNEL *psyOutChan,
+ QC_OUT_CHANNEL *qcOutChannel,
+ SHORT *quantSpec,
+ SHORT *quantSpecTmp,
+ INT *scf,
+ INT *minScf,
+ FIXP_DBL *sfbDist,
+ FIXP_DBL *sfbConstPePart,
+ FIXP_DBL *sfbFormFactorLdData,
+ FIXP_DBL *sfbNRelevantLines)
+{
+ INT sfb, startSfb, stopSfb;
+ INT scfTmp[MAX_GROUPED_SFB], scfAct, scfNew;
+ INT scfPrev, scfNext, scfPrevNextMin, scfPrevNextMax, scfLo, scfHi;
+ INT scfMin, scfMax;
+ INT *sfbOffs = psyOutChan->sfbOffsets;
+ FIXP_DBL sfbDistNew[MAX_GROUPED_SFB], sfbDistMax[MAX_GROUPED_SFB];
+ FIXP_DBL distOldSum, distNewSum;
+ INT deltaScfBits;
+ FIXP_DBL deltaSpecPe;
+ FIXP_DBL deltaPe = FL2FXCONST_DBL(0.0f);
+ FIXP_DBL deltaPeNew = FL2FXCONST_DBL(0.0f);
+ INT sfbCnt = psyOutChan->sfbCnt;
+ INT bSuccess, bCheckScf;
+ INT i,k;
+
+ /* calc min and max scalfactors */
+ scfMin = FDK_INT_MAX;
+ scfMax = FDK_INT_MIN;
+ for (sfb=0; sfb<sfbCnt; sfb++) {
+ if (scf[sfb]!=FDK_INT_MIN) {
+ scfMin = fixMin(scfMin, scf[sfb]);
+ scfMax = fixMax(scfMax, scf[sfb]);
+ }
+ }
+
+ stopSfb = 0;
+ scfAct = FDK_INT_MIN;
+ do {
+ /* search for region with same scf values scfAct */
+ scfPrev = scfAct;
+
+ sfb = stopSfb;
+ while (sfb<sfbCnt && (scf[sfb]==FDK_INT_MIN))
+ sfb++;
+ startSfb = sfb;
+ scfAct = scf[startSfb];
+ sfb++;
+ while (sfb<sfbCnt && ((scf[sfb]==FDK_INT_MIN) || (scf[sfb]==scf[startSfb])))
+ sfb++;
+ stopSfb = sfb;
+
+ if (stopSfb < sfbCnt)
+ scfNext = scf[stopSfb];
+ else
+ scfNext = scfAct;
+
+ if (scfPrev == FDK_INT_MIN)
+ scfPrev = scfAct;
+
+ scfPrevNextMax = fixMax(scfPrev, scfNext);
+ scfPrevNextMin = fixMin(scfPrev, scfNext);
+
+ /* try to reduce bits by checking scf values in the range
+ scf[startSfb]...scfHi */
+ scfHi = fixMax(scfPrevNextMax, scfAct);
+ /* try to find a better solution by reducing the scf difference to
+ the nearest possible lower scf */
+ if (scfPrevNextMax >= scfAct)
+ scfLo = fixMin(scfAct, scfPrevNextMin);
+ else
+ scfLo = scfPrevNextMax;
+
+ if (startSfb < sfbCnt && scfHi-scfLo <= MAX_SCF_DELTA) { /* region found */
+ /* 1. try to save bits by coarser quantization */
+ if (scfHi > scf[startSfb]) {
+ /* calculate the allowed distortion */
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scf[sfb] != FDK_INT_MIN) {
+ /* sfbDistMax[sfb] = (float)pow(qcOutChannel->sfbThreshold[sfb]*sfbDist[sfb]*sfbDist[sfb],1.0f/3.0f); */
+ /* sfbDistMax[sfb] = fixMax(sfbDistMax[sfb],qcOutChannel->sfbEnergy[sfb]*FL2FXCONST_DBL(1.e-3f)); */
+ /* -0.15571537944 = ld64(1.e-3f)*/
+ sfbDistMax[sfb] = fMult(FL2FXCONST_DBL(1.0f/3.0f),qcOutChannel->sfbThresholdLdData[sfb])+fMult(FL2FXCONST_DBL(1.0f/3.0f),sfbDist[sfb])+fMult(FL2FXCONST_DBL(1.0f/3.0f),sfbDist[sfb]);
+ sfbDistMax[sfb] = fixMax(sfbDistMax[sfb],qcOutChannel->sfbEnergyLdData[sfb]-FL2FXCONST_DBL(0.15571537944));
+ sfbDistMax[sfb] = fixMin(sfbDistMax[sfb],qcOutChannel->sfbThresholdLdData[sfb]);
+ }
+ }
+
+ /* loop over all possible scf values for this region */
+ bCheckScf = 1;
+ for (scfNew=scf[startSfb]+1; scfNew<=scfHi; scfNew++) {
+ for (k=0; k<MAX_GROUPED_SFB; k++)
+ scfTmp[k] = scf[k];
+
+ /* replace scfs in region by scfNew */
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scfTmp[sfb] != FDK_INT_MIN)
+ scfTmp[sfb] = scfNew;
+ }
+
+ /* estimate change in bit demand for new scfs */
+ deltaScfBits = FDKaacEnc_countScfBitsDiff(scf,scfTmp,sfbCnt,startSfb,stopSfb);
+
+ deltaSpecPe = FDKaacEnc_calcSpecPeDiff(psyOutChan, qcOutChannel, scf, scfTmp, sfbConstPePart,
+ sfbFormFactorLdData, sfbNRelevantLines,
+ startSfb, stopSfb);
+
+ deltaPeNew = deltaPe + (FIXP_DBL)deltaScfBits + deltaSpecPe;
+
+ /* new bit demand small enough ? */
+ if (deltaPeNew < FL2FXCONST_DBL(0.0f)) {
+ bSuccess = 1;
+
+ /* quantize and calc sum of new distortion */
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scfTmp[sfb] != FDK_INT_MIN) {
+ sfbDistNew[sfb] = FDKaacEnc_calcSfbDist(qcOutChannel->mdctSpectrum+sfbOffs[sfb],
+ quantSpecTmp+sfbOffs[sfb],
+ sfbOffs[sfb+1]-sfbOffs[sfb],
+ scfNew);
+
+ if (sfbDistNew[sfb] > sfbDistMax[sfb]) {
+ /* no improvement, skip further dist. calculations */
+ bSuccess = 0;
+ if (sfbDistNew[sfb] == qcOutChannel->sfbEnergyLdData[sfb]) {
+ /* if whole sfb is already quantized to 0, further
+ checks with even coarser quant. are useless*/
+ bCheckScf = 0;
+ }
+ break;
+ }
+ }
+ }
+ if (bCheckScf==0) /* further calculations useless ? */
+ break;
+ /* distortion small enough ? -> use new scalefactors */
+ if (bSuccess) {
+ deltaPe = deltaPeNew;
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scf[sfb] != FDK_INT_MIN) {
+ scf[sfb] = scfNew;
+ sfbDist[sfb] = sfbDistNew[sfb];
+
+ for (k=0; k<sfbOffs[sfb+1]-sfbOffs[sfb]; k++)
+ quantSpec[sfbOffs[sfb]+k] = quantSpecTmp[sfbOffs[sfb]+k];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* 2. only if coarser quantization was not successful, try to find
+ a better solution by finer quantization and reducing bits for
+ scalefactor coding */
+ if (scfAct==scf[startSfb] &&
+ scfLo < scfAct &&
+ scfMax-scfMin <= MAX_SCF_DELTA) {
+
+ int bminScfViolation = 0;
+
+ for (k=0; k<MAX_GROUPED_SFB; k++)
+ scfTmp[k] = scf[k];
+
+ scfNew = scfLo;
+
+ /* replace scfs in region by scfNew and
+ check if in all sfb scfNew >= minScf[sfb] */
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scfTmp[sfb] != FDK_INT_MIN) {
+ scfTmp[sfb] = scfNew;
+ if (scfNew < minScf[sfb])
+ bminScfViolation = 1;
+ }
+ }
+
+ if (!bminScfViolation) {
+ /* estimate change in bit demand for new scfs */
+ deltaScfBits = FDKaacEnc_countScfBitsDiff(scf,scfTmp,sfbCnt,startSfb,stopSfb);
+
+ deltaSpecPe = FDKaacEnc_calcSpecPeDiff(psyOutChan, qcOutChannel, scf, scfTmp, sfbConstPePart,
+ sfbFormFactorLdData, sfbNRelevantLines,
+ startSfb, stopSfb);
+
+ deltaPeNew = deltaPe + (FIXP_DBL)deltaScfBits + deltaSpecPe;
+ }
+
+ /* new bit demand small enough ? */
+ if (!bminScfViolation && deltaPeNew < FL2FXCONST_DBL(0.0f)) {
+
+ /* quantize and calc sum of new distortion */
+ distOldSum = distNewSum = FL2FXCONST_DBL(0.0f);
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scfTmp[sfb] != FDK_INT_MIN) {
+ distOldSum += CalcInvLdData(sfbDist[sfb]) >> DIST_FAC_SHIFT;
+
+ sfbDistNew[sfb] = FDKaacEnc_calcSfbDist(qcOutChannel->mdctSpectrum+sfbOffs[sfb],
+ quantSpecTmp+sfbOffs[sfb],
+ sfbOffs[sfb+1]-sfbOffs[sfb],
+ scfNew);
+
+ if (sfbDistNew[sfb] > qcOutChannel->sfbThresholdLdData[sfb]) {
+ /* no improvement, skip further dist. calculations */
+ distNewSum = distOldSum << 1;
+ break;
+ }
+ distNewSum += CalcInvLdData(sfbDistNew[sfb]) >> DIST_FAC_SHIFT;
+ }
+ }
+ /* distortion smaller ? -> use new scalefactors */
+ if (distNewSum < fMult(FL2FXCONST_DBL(0.8f),distOldSum)) {
+ deltaPe = deltaPeNew;
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scf[sfb] != FDK_INT_MIN) {
+ scf[sfb] = scfNew;
+ sfbDist[sfb] = sfbDistNew[sfb];
+
+ for (k=0; k<sfbOffs[sfb+1]-sfbOffs[sfb]; k++)
+ quantSpec[sfbOffs[sfb]+k] = quantSpecTmp[sfbOffs[sfb]+k];
+ }
+ }
+ }
+ }
+ }
+
+ /* 3. try to find a better solution (save bits) by only reducing the
+ scalefactor without new quantization */
+ if (scfMax-scfMin <= MAX_SCF_DELTA-3) { /* 3 bec. scf is reduced 3 times,
+ see for loop below */
+
+ for (k=0; k<sfbCnt; k++)
+ scfTmp[k] = scf[k];
+
+ for (i=0; i<3; i++) {
+ scfNew = scfTmp[startSfb]-1;
+ /* replace scfs in region by scfNew */
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scfTmp[sfb] != FDK_INT_MIN)
+ scfTmp[sfb] = scfNew;
+ }
+ /* estimate change in bit demand for new scfs */
+ deltaScfBits = FDKaacEnc_countScfBitsDiff(scf,scfTmp,sfbCnt,startSfb,stopSfb);
+ deltaPeNew = deltaPe + (FIXP_DBL)deltaScfBits;
+ /* new bit demand small enough ? */
+ if (deltaPeNew <= FL2FXCONST_DBL(0.0f)) {
+
+ bSuccess = 1;
+ distOldSum = distNewSum = FL2FXCONST_DBL(0.0f);
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scfTmp[sfb] != FDK_INT_MIN) {
+ FIXP_DBL sfbEnQ;
+ /* calc the energy and distortion of the quantized spectrum for
+ a smaller scf */
+ FDKaacEnc_calcSfbQuantEnergyAndDist(qcOutChannel->mdctSpectrum+sfbOffs[sfb],
+ quantSpec+sfbOffs[sfb],
+ sfbOffs[sfb+1]-sfbOffs[sfb], scfNew,
+ &sfbEnQ, &sfbDistNew[sfb]);
+
+ distOldSum += CalcInvLdData(sfbDist[sfb]) >> DIST_FAC_SHIFT;
+ distNewSum += CalcInvLdData(sfbDistNew[sfb]) >> DIST_FAC_SHIFT;
+
+ /* 0.00259488556167 = ld64(1.122f) */
+ /* -0.00778722686652 = ld64(0.7079f) */
+ if ((sfbDistNew[sfb] > (sfbDist[sfb]+FL2FXCONST_DBL(0.00259488556167f))) || (sfbEnQ < (qcOutChannel->sfbEnergyLdData[sfb] - FL2FXCONST_DBL(0.00778722686652f)))){
+ bSuccess = 0;
+ break;
+ }
+ }
+ }
+ /* distortion smaller ? -> use new scalefactors */
+ if (distNewSum < distOldSum && bSuccess) {
+ deltaPe = deltaPeNew;
+ for (sfb=startSfb; sfb<stopSfb; sfb++) {
+ if (scf[sfb] != FDK_INT_MIN) {
+ scf[sfb] = scfNew;
+ sfbDist[sfb] = sfbDistNew[sfb];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } while (stopSfb <= sfbCnt);
+
+}
+
+static void
+FDKaacEnc_FDKaacEnc_EstimateScaleFactorsChannel(QC_OUT_CHANNEL *qcOutChannel,
+ PSY_OUT_CHANNEL *psyOutChannel,
+ INT *RESTRICT scf,
+ INT *RESTRICT globalGain,
+ FIXP_DBL *RESTRICT sfbFormFactorLdData
+ ,const INT invQuant,
+ SHORT *RESTRICT quantSpec
+ )
+{
+ INT i, j, sfb, sfbOffs;
+ INT scfInt;
+ INT maxSf;
+ INT minSf;
+ FIXP_DBL threshLdData;
+ FIXP_DBL energyLdData;
+ FIXP_DBL energyPartLdData;
+ FIXP_DBL thresholdPartLdData;
+ FIXP_DBL scfFract;
+ FIXP_DBL maxSpec;
+ FIXP_DBL absSpec;
+ INT minScfCalculated[MAX_GROUPED_SFB];
+ FIXP_DBL sfbDistLdData[MAX_GROUPED_SFB];
+ C_ALLOC_SCRATCH_START(quantSpecTmp, SHORT, (1024));
+ INT minSfMaxQuant[MAX_GROUPED_SFB];
+
+ FIXP_DBL threshConstLdData=FL2FXCONST_DBL(0.04304511722f); /* log10(6.75)/log10(2.0)/64.0 */
+ FIXP_DBL convConst=FL2FXCONST_DBL(0.30102999566f); /* log10(2.0) */
+ FIXP_DBL c1Const=FL2FXCONST_DBL(-0.27083183594f); /* C1 = -69.33295 => C1/2^8 */
+
+
+
+ if (invQuant>0) {
+ FDKmemclear(quantSpec, (1024)*sizeof(SHORT));
+ }
+
+ /* scfs without energy or with thresh>energy are marked with FDK_INT_MIN */
+ for(i=0; i<psyOutChannel->sfbCnt; i++) {
+ scf[i] = FDK_INT_MIN;
+ }
+
+ for (i=0; i<MAX_GROUPED_SFB; i++) {
+ minSfMaxQuant[i] = FDK_INT_MIN;
+ }
+
+ for (sfbOffs=0; sfbOffs<psyOutChannel->sfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) {
+ for(sfb=0; sfb<psyOutChannel->maxSfbPerGroup; sfb++) {
+
+ threshLdData = qcOutChannel->sfbThresholdLdData[sfbOffs+sfb];
+ energyLdData = qcOutChannel->sfbEnergyLdData[sfbOffs+sfb];
+
+ sfbDistLdData[sfbOffs+sfb] = energyLdData;
+
+
+ if (energyLdData > threshLdData) {
+ FIXP_DBL tmp;
+
+ /* energyPart = (float)log10(sfbFormFactor[sfbOffs+sfb]); */
+ /* 0.09375f = log(64.0)/log(2.0)/64.0 = scale of sfbFormFactorLdData */
+ energyPartLdData = sfbFormFactorLdData[sfbOffs+sfb] + FL2FXCONST_DBL(0.09375f);
+
+ /* influence of allowed distortion */
+ /* thresholdPart = (float)log10(6.75*thresh+FLT_MIN); */
+ thresholdPartLdData = threshConstLdData + threshLdData;
+
+ /* scf calc */
+ /* scfFloat = 8.8585f * (thresholdPart - energyPart); */
+ scfFract = thresholdPartLdData - energyPartLdData;
+ /* conversion from log2 to log10 */
+ scfFract = fMult(convConst,scfFract);
+ /* (8.8585f * scfFract)/8 = 8/8 * scfFract + 0.8585 * scfFract/8 */
+ scfFract = scfFract + fMult(FL2FXCONST_DBL(0.8585f),scfFract >> 3);
+
+ /* integer scalefactor */
+ /* scfInt = (int)floor(scfFloat); */
+ scfInt = (INT)(scfFract>>((DFRACT_BITS-1)-3-LD_DATA_SHIFT)); /* 3 bits => scfFract/8.0; 6 bits => ld64 */
+
+ /* maximum of spectrum */
+ maxSpec = FL2FXCONST_DBL(0.0f);
+
+ for(j=psyOutChannel->sfbOffsets[sfbOffs+sfb]; j<psyOutChannel->sfbOffsets[sfbOffs+sfb+1]; j++ ){
+ absSpec = fixp_abs(qcOutChannel->mdctSpectrum[j]);
+ maxSpec = (absSpec > maxSpec) ? absSpec : maxSpec;
+ }
+
+ /* lower scf limit to avoid quantized values bigger than MAX_QUANT */
+ /* C1 = -69.33295f, C2 = 5.77078f = 4/log(2) */
+ /* minSfMaxQuant[sfbOffs+sfb] = (int)ceil(C1 + C2*log(maxSpec)); */
+ /* C1/2^8 + 4/log(2.0)*log(maxSpec)/2^8 => C1/2^8 + log(maxSpec)/log(2.0)*4/2^8 => C1/2^8 + log(maxSpec)/log(2.0)/64.0 */
+
+ //minSfMaxQuant[sfbOffs+sfb] = ((INT) ((c1Const + CalcLdData(maxSpec)) >> ((DFRACT_BITS-1)-8))) + 1;
+ tmp = CalcLdData(maxSpec);
+ if (c1Const>FL2FXCONST_DBL(-1.f)-tmp) {
+ minSfMaxQuant[sfbOffs+sfb] = ((INT) ((c1Const + tmp) >> ((DFRACT_BITS-1)-8))) + 1;
+ }
+ else {
+ minSfMaxQuant[sfbOffs+sfb] = ((INT) (FL2FXCONST_DBL(-1.f) >> ((DFRACT_BITS-1)-8))) + 1;
+ }
+
+ scfInt = fixMax(scfInt, minSfMaxQuant[sfbOffs+sfb]);
+
+
+ /* find better scalefactor with analysis by synthesis */
+ if (invQuant>0) {
+ scfInt = FDKaacEnc_improveScf(qcOutChannel->mdctSpectrum+psyOutChannel->sfbOffsets[sfbOffs+sfb],
+ quantSpec+psyOutChannel->sfbOffsets[sfbOffs+sfb],
+ quantSpecTmp+psyOutChannel->sfbOffsets[sfbOffs+sfb],
+ psyOutChannel->sfbOffsets[sfbOffs+sfb+1]-psyOutChannel->sfbOffsets[sfbOffs+sfb],
+ threshLdData, scfInt, minSfMaxQuant[sfbOffs+sfb],
+ &sfbDistLdData[sfbOffs+sfb], &minScfCalculated[sfbOffs+sfb]
+ );
+ }
+ scf[sfbOffs+sfb] = scfInt;
+ }
+ }
+ }
+
+
+ if (invQuant>1) {
+ /* try to decrease scf differences */
+ FIXP_DBL sfbConstPePart[MAX_GROUPED_SFB];
+ FIXP_DBL sfbNRelevantLines[MAX_GROUPED_SFB];
+
+ for (i=0; i<psyOutChannel->sfbCnt; i++)
+ sfbConstPePart[i] = (FIXP_DBL)FDK_INT_MIN;
+
+ FDKaacEnc_calcSfbRelevantLines( sfbFormFactorLdData,
+ qcOutChannel->sfbEnergyLdData,
+ qcOutChannel->sfbThresholdLdData,
+ psyOutChannel->sfbOffsets,
+ psyOutChannel->sfbCnt,
+ psyOutChannel->sfbPerGroup,
+ psyOutChannel->maxSfbPerGroup,
+ sfbNRelevantLines);
+
+
+ FDKaacEnc_assimilateSingleScf(psyOutChannel, qcOutChannel, quantSpec, quantSpecTmp, scf,
+ minSfMaxQuant, sfbDistLdData, sfbConstPePart,
+ sfbFormFactorLdData, sfbNRelevantLines, minScfCalculated, 1);
+
+
+ FDKaacEnc_assimilateMultipleScf(psyOutChannel, qcOutChannel, quantSpec, quantSpecTmp, scf,
+ minSfMaxQuant, sfbDistLdData, sfbConstPePart,
+ sfbFormFactorLdData, sfbNRelevantLines);
+
+
+ FDKaacEnc_FDKaacEnc_assimilateMultipleScf2(psyOutChannel, qcOutChannel, quantSpec, quantSpecTmp, scf,
+ minSfMaxQuant, sfbDistLdData, sfbConstPePart,
+ sfbFormFactorLdData, sfbNRelevantLines);
+
+ }
+
+
+ /* get min scalefac */
+ minSf = FDK_INT_MAX;
+ for (sfbOffs=0; sfbOffs<psyOutChannel->sfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) {
+ for (sfb = 0; sfb < psyOutChannel->maxSfbPerGroup; sfb++) {
+ if (scf[sfbOffs+sfb]!=FDK_INT_MIN)
+ minSf = fixMin(minSf,scf[sfbOffs+sfb]);
+ }
+ }
+
+ /* limit scf delta */
+ for (sfbOffs=0; sfbOffs<psyOutChannel->sfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) {
+ for (sfb = 0; sfb < psyOutChannel->maxSfbPerGroup; sfb++) {
+ if ((scf[sfbOffs+sfb] != FDK_INT_MIN) && (minSf+MAX_SCF_DELTA) < scf[sfbOffs+sfb]) {
+ scf[sfbOffs+sfb] = minSf + MAX_SCF_DELTA;
+ if (invQuant > 0) { /* changed bands need to be quantized again */
+ sfbDistLdData[sfbOffs+sfb] =
+ FDKaacEnc_calcSfbDist(qcOutChannel->mdctSpectrum+psyOutChannel->sfbOffsets[sfbOffs+sfb],
+ quantSpec+psyOutChannel->sfbOffsets[sfbOffs+sfb],
+ psyOutChannel->sfbOffsets[sfbOffs+sfb+1]-psyOutChannel->sfbOffsets[sfbOffs+sfb],
+ scf[sfbOffs+sfb]
+ );
+ }
+ }
+ }
+ }
+
+
+ /* get max scalefac for global gain */
+ maxSf = FDK_INT_MIN;
+ for (sfbOffs=0; sfbOffs<psyOutChannel->sfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) {
+ for (sfb = 0; sfb < psyOutChannel->maxSfbPerGroup; sfb++) {
+ maxSf = fixMax(maxSf,scf[sfbOffs+sfb]);
+ }
+ }
+
+ /* calc loop scalefactors, if spec is not all zero (i.e. maxSf == -99) */
+ if( maxSf > FDK_INT_MIN ) {
+ *globalGain = maxSf;
+ for (sfbOffs=0; sfbOffs<psyOutChannel->sfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) {
+ for (sfb = 0; sfb < psyOutChannel->maxSfbPerGroup; sfb++) {
+ if( scf[sfbOffs+sfb] == FDK_INT_MIN ) {
+ scf[sfbOffs+sfb] = 0;
+ /* set band explicitely to zero */
+ for(j=psyOutChannel->sfbOffsets[sfbOffs+sfb]; j<psyOutChannel->sfbOffsets[sfbOffs+sfb+1]; j++ ) {
+ qcOutChannel->mdctSpectrum[j] = FL2FXCONST_DBL(0.0f);
+ }
+ }
+ else {
+ scf[sfbOffs+sfb] = maxSf - scf[sfbOffs+sfb];
+ }
+ }
+ }
+ }
+ else{
+ *globalGain = 0;
+ /* set spectrum explicitely to zero */
+ for (sfbOffs=0; sfbOffs<psyOutChannel->sfbCnt; sfbOffs+=psyOutChannel->sfbPerGroup) {
+ for (sfb = 0; sfb < psyOutChannel->maxSfbPerGroup; sfb++) {
+ scf[sfbOffs+sfb] = 0;
+ /* set band explicitely to zero */
+ for(j=psyOutChannel->sfbOffsets[sfbOffs+sfb]; j<psyOutChannel->sfbOffsets[sfbOffs+sfb+1]; j++ ) {
+ qcOutChannel->mdctSpectrum[j] = FL2FXCONST_DBL(0.0f);
+ }
+ }
+ }
+ }
+
+ /* free quantSpecTmp from scratch */
+ C_ALLOC_SCRATCH_END(quantSpecTmp, SHORT, (1024));
+
+
+}
+
+void
+FDKaacEnc_EstimateScaleFactors(PSY_OUT_CHANNEL *psyOutChannel[],
+ QC_OUT_CHANNEL* qcOutChannel[],
+ const int invQuant,
+ const int nChannels)
+{
+ int ch;
+
+ for (ch = 0; ch < nChannels; ch++)
+ {
+ FDKaacEnc_FDKaacEnc_EstimateScaleFactorsChannel(qcOutChannel[ch],
+ psyOutChannel[ch],
+ qcOutChannel[ch]->scf,
+ &qcOutChannel[ch]->globalGain,
+ qcOutChannel[ch]->sfbFormFactorLdData
+ ,invQuant,
+ qcOutChannel[ch]->quantSpec
+ );
+ }
+
+}
+
diff --git a/libAACenc/src/sf_estim.h b/libAACenc/src/sf_estim.h
new file mode 100644
index 0000000..8b486af
--- /dev/null
+++ b/libAACenc/src/sf_estim.h
@@ -0,0 +1,54 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: Scale factor estimation
+
+******************************************************************************/
+#ifndef _SF_ESTIM_H
+#define _SF_ESTIM_H
+
+#include "common_fix.h"
+
+
+#include "psy_const.h"
+#include "qc_data.h"
+#include "interface.h"
+
+#define FORM_FAC_SHIFT 6
+
+
+void
+FDKaacEnc_CalcFormFactor(QC_OUT_CHANNEL *qcOutChannel[(2)],
+ PSY_OUT_CHANNEL *psyOutChannel[(2)],
+ const INT nChannels);
+
+void
+FDKaacEnc_EstimateScaleFactors(PSY_OUT_CHANNEL *psyOutChannel[],
+ QC_OUT_CHANNEL* qcOutChannel[],
+ const int invQuant,
+ const int nChannels);
+
+
+
+#endif
diff --git a/libAACenc/src/spreading.cpp b/libAACenc/src/spreading.cpp
new file mode 100644
index 0000000..fc2f2f6
--- /dev/null
+++ b/libAACenc/src/spreading.cpp
@@ -0,0 +1,52 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Spreading of energy
+
+******************************************************************************/
+
+#include "spreading.h"
+
+void FDKaacEnc_SpreadingMax(const INT pbCnt,
+ const FIXP_DBL *RESTRICT maskLowFactor,
+ const FIXP_DBL *RESTRICT maskHighFactor,
+ FIXP_DBL *RESTRICT pbSpreadEnergy)
+{
+ int i;
+ FIXP_DBL delay;
+
+ /* slope to higher frequencies */
+ delay = pbSpreadEnergy[0];
+ for (i=1; i<pbCnt; i++) {
+ delay = fixMax(pbSpreadEnergy[i], fMult(maskHighFactor[i], delay));
+ pbSpreadEnergy[i] = delay;
+ }
+
+ /* slope to lower frequencies */
+ delay = pbSpreadEnergy[pbCnt-1];
+ for (i=pbCnt-2; i>=0; i--) {
+ delay = fixMax(pbSpreadEnergy[i], fMult(maskLowFactor[i],delay));
+ pbSpreadEnergy[i] = delay;
+ }
+}
diff --git a/libAACenc/src/spreading.h b/libAACenc/src/spreading.h
new file mode 100644
index 0000000..dcb0923
--- /dev/null
+++ b/libAACenc/src/spreading.h
@@ -0,0 +1,40 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: Spreading of energy and weighted tonality
+
+******************************************************************************/
+
+#ifndef _SPREADING_H
+#define _SPREADING_H
+
+#include "common_fix.h"
+
+
+void FDKaacEnc_SpreadingMax(const INT pbCnt,
+ const FIXP_DBL *RESTRICT maskLowFactor,
+ const FIXP_DBL *RESTRICT maskHighFactor,
+ FIXP_DBL *RESTRICT pbSpreadEnergy);
+
+#endif /* #ifndef _SPREADING_H */
diff --git a/libAACenc/src/tns_func.h b/libAACenc/src/tns_func.h
new file mode 100644
index 0000000..ac619f6
--- /dev/null
+++ b/libAACenc/src/tns_func.h
@@ -0,0 +1,81 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: Alex Goeschel
+ contents/description: Temporal noise shaping
+
+******************************************************************************/
+#ifndef _TNS_FUNC_H
+#define _TNS_FUNC_H
+
+#include "common_fix.h"
+
+#include "psy_configuration.h"
+
+AAC_ENCODER_ERROR FDKaacEnc_InitTnsConfiguration(INT bitrate,
+ INT samplerate,
+ INT channels,
+ INT blocktype,
+ INT granuleLength,
+ INT ldSbrPresent,
+ TNS_CONFIG *tnsConfig,
+ PSY_CONFIGURATION *psyConfig,
+ INT active,
+ INT useTnsPeak );
+
+INT FDKaacEnc_TnsDetect(
+ TNS_DATA *tnsData,
+ const TNS_CONFIG *tC,
+ TNS_INFO* tnsInfo,
+ INT sfbCnt,
+ FIXP_DBL *spectrum,
+ INT subBlockNumber,
+ INT blockType
+ );
+
+
+
+void FDKaacEnc_TnsSync(
+ TNS_DATA *tnsDataDest,
+ const TNS_DATA *tnsDataSrc,
+ TNS_INFO *tnsInfoDest,
+ TNS_INFO *tnsInfoSrc,
+ const INT blockTypeDest,
+ const INT blockTypeSrc,
+ const TNS_CONFIG *tC
+ );
+
+INT FDKaacEnc_TnsEncode(
+ TNS_INFO* tnsInfo,
+ TNS_DATA* tnsData,
+ const INT numOfSfb,
+ const TNS_CONFIG *tC,
+ const INT lowPassLine,
+ FIXP_DBL* spectrum,
+ const INT subBlockNumber,
+ const INT blockType
+ );
+
+
+
+#endif /* _TNS_FUNC_H */
diff --git a/libAACenc/src/tns_param.cpp b/libAACenc/src/tns_param.cpp
new file mode 100644
index 0000000..36a62e8
--- /dev/null
+++ b/libAACenc/src/tns_param.cpp
@@ -0,0 +1,31 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M.Werner
+ contents/description: TNS parameters
+
+******************************************************************************/
+
+#include "tns_param.h"
+
+
diff --git a/libAACenc/src/tns_param.h b/libAACenc/src/tns_param.h
new file mode 100644
index 0000000..d9a11e5
--- /dev/null
+++ b/libAACenc/src/tns_param.h
@@ -0,0 +1,33 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) copyright Fraunhofer-IIS (1999)
+ 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$
+ Initial author: Alex Goeschel
+ contents/description: Temporal noise shaping
+
+******************************************************************************/
+#ifndef _TNS_PARAM_H
+#define _TNS_PARAM_H
+
+
+
+#endif /* _TNS_PARAM_H */
diff --git a/libAACenc/src/tonality.cpp b/libAACenc/src/tonality.cpp
new file mode 100644
index 0000000..54b4b6e
--- /dev/null
+++ b/libAACenc/src/tonality.cpp
@@ -0,0 +1,147 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (c) copyright Fraunhofer IIS (1996)
+ 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: M. Werner
+ contents/description: Convert chaos measure to the tonality index
+
+ 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 "tonality.h"
+#include "chaosmeasure.h"
+
+/*static const FIXP_SGL maxtone = FL2FXCONST_SGL(0.5);*/
+/*static const FIXP_SGL mintone = FL2FXCONST_SGL(0.05);*/
+/*static const float convtone = 2.0f;*/ /* 1.0/mintone */
+
+/* -1.0/log(maxtone/mintone) */
+static const FIXP_DBL normlog = (FIXP_DBL)0xd977d949; /*FL2FXCONST_DBL(-0.4342944819f * FDKlog(2.0)/FDKlog(2.7182818)); */
+
+static void FDKaacEnc_CalcSfbTonality(FIXP_DBL *RESTRICT spectrum,
+ INT *RESTRICT sfbMaxScaleSpec,
+ FIXP_DBL *RESTRICT chaosMeasure,
+ FIXP_SGL *RESTRICT sfbTonality,
+ INT sfbCnt,
+ const INT *RESTRICT sfbOffset,
+ FIXP_DBL *RESTRICT sfbEnergyLD64 );
+
+
+void FDKaacEnc_CalculateFullTonality(FIXP_DBL *RESTRICT spectrum,
+ INT *RESTRICT sfbMaxScaleSpec,
+ FIXP_DBL *RESTRICT sfbEnergyLD64,
+ FIXP_SGL *RESTRICT sfbTonality,
+ INT sfbCnt,
+ const INT *sfbOffset,
+ INT usePns)
+{
+ INT j;
+#if defined(ARCH_PREFER_MULT_32x16)
+ FIXP_SGL alpha_0 = FL2FXCONST_SGL(0.25f); /* used in smooth ChaosMeasure */
+ FIXP_SGL alpha_1 = FL2FXCONST_SGL(1.0f-0.25f); /* used in smooth ChaosMeasure */
+#else
+ FIXP_DBL alpha_0 = FL2FXCONST_DBL(0.25f); /* used in smooth ChaosMeasure */
+ FIXP_DBL alpha_1 = FL2FXCONST_DBL(1.0f-0.25f); /* used in smooth ChaosMeasure */
+#endif
+ INT numberOfLines = sfbOffset[sfbCnt];
+
+ if (!usePns)
+ return;
+
+ C_ALLOC_SCRATCH_START(chaosMeasurePerLine, FIXP_DBL, (1024));
+ /* calculate chaos measure */
+ FDKaacEnc_CalculateChaosMeasure(spectrum,
+ numberOfLines,
+ chaosMeasurePerLine);
+
+ /* smooth ChaosMeasure */
+ for (j=1;j<numberOfLines;j++) {
+ FIXP_DBL tmp = fMultDiv2(alpha_1, chaosMeasurePerLine[j]);
+ chaosMeasurePerLine[j] = fMultAdd(tmp, alpha_0, chaosMeasurePerLine[j-1]);
+ }
+
+ FDKaacEnc_CalcSfbTonality(spectrum,
+ sfbMaxScaleSpec,
+ chaosMeasurePerLine,
+ sfbTonality,
+ sfbCnt,
+ sfbOffset,
+ sfbEnergyLD64);
+
+ C_ALLOC_SCRATCH_END(chaosMeasurePerLine, FIXP_DBL, (1024));
+}
+
+
+/*****************************************************************************
+
+ functionname: CalculateTonalityIndex
+ description: computes tonality values out of unpredictability values
+ limits range and computes log()
+ returns:
+ input: ptr to energies, ptr to chaos measure values,
+ number of sfb
+ output: sfb wise tonality values
+
+*****************************************************************************/
+static void FDKaacEnc_CalcSfbTonality(FIXP_DBL *RESTRICT spectrum,
+ INT *RESTRICT sfbMaxScaleSpec,
+ FIXP_DBL *RESTRICT chaosMeasure,
+ FIXP_SGL *RESTRICT sfbTonality,
+ INT sfbCnt,
+ const INT *RESTRICT sfbOffset,
+ FIXP_DBL *RESTRICT sfbEnergyLD64 )
+{
+ INT i, j;
+
+ for (i=0; i<sfbCnt; i++) {
+ FIXP_DBL chaosMeasureSfbLD64;
+ INT shiftBits = fixMax(0,sfbMaxScaleSpec[i] - 4); /* max sfbWidth = 96 ; 2^7=128 => 7/2 = 4 (spc*spc) */
+
+ FIXP_DBL chaosMeasureSfb = FL2FXCONST_DBL(0.0);
+
+ /* calc chaosMeasurePerSfb */
+ for (j=(sfbOffset[i+1]-sfbOffset[i])-1; j>=0; j--) {
+ FIXP_DBL tmp = (*spectrum++)<<shiftBits;
+ FIXP_DBL lineNrg = fMultDiv2(tmp, tmp);
+ chaosMeasureSfb = fMultAddDiv2(chaosMeasureSfb, lineNrg, *chaosMeasure++);
+ }
+
+ /* calc tonalityPerSfb */
+ if (chaosMeasureSfb != FL2FXCONST_DBL(0.0))
+ {
+ /* add ld(convtone)/64 and 2/64 bec.fMultDiv2 */
+ chaosMeasureSfbLD64 = CalcLdData((chaosMeasureSfb)) - sfbEnergyLD64[i];
+ chaosMeasureSfbLD64 += FL2FXCONST_DBL(3.0f/64) - ((FIXP_DBL)(shiftBits)<<(DFRACT_BITS-6));
+
+ if (chaosMeasureSfbLD64 > FL2FXCONST_DBL(-0.0519051) ) /* > ld(0.05)+ld(2) */
+ {
+ if (chaosMeasureSfbLD64 <= FL2FXCONST_DBL(0.0) )
+ sfbTonality[i] = FX_DBL2FX_SGL(fMultDiv2( chaosMeasureSfbLD64 , normlog ) << 7);
+ else
+ sfbTonality[i] = FL2FXCONST_SGL(0.0);
+ }
+ else
+ sfbTonality[i] = (FIXP_SGL)MAXVAL_SGL;
+ }
+ else
+ sfbTonality[i] = (FIXP_SGL)MAXVAL_SGL;
+ }
+}
diff --git a/libAACenc/src/tonality.h b/libAACenc/src/tonality.h
new file mode 100644
index 0000000..8c6e4ed
--- /dev/null
+++ b/libAACenc/src/tonality.h
@@ -0,0 +1,46 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) copyright Fraunhofer - IIS (1996)
+ 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$
+ author: M. Lohwasser
+ contents/description: Calculate tonality index
+
+******************************************************************************/
+
+#ifndef __TONALITY_H
+#define __TONALITY_H
+
+#include "common_fix.h"
+
+
+#include "chaosmeasure.h"
+
+
+void FDKaacEnc_CalculateFullTonality( FIXP_DBL *RESTRICT spectrum,
+ INT *RESTRICT sfbMaxScaleSpec,
+ FIXP_DBL *RESTRICT sfbEnergyLD64,
+ FIXP_SGL *RESTRICT sfbTonality,
+ INT sfbCnt,
+ const INT *sfbOffset,
+ INT usePns);
+
+#endif
diff --git a/libAACenc/src/transform.cpp b/libAACenc/src/transform.cpp
new file mode 100644
index 0000000..99b8a6b
--- /dev/null
+++ b/libAACenc/src/transform.cpp
@@ -0,0 +1,203 @@
+/*****************************************************************************
+
+ (C) copyright Fraunhofer IIS (2001)
+ 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$
+ Description: FDKaacLdEnc_MdctTransform480:
+ The module FDKaacLdEnc_MdctTransform will perform the MDCT.
+ The MDCT supports the sine window and
+
+ the zero padded window. The algorithm of the MDCT
+ can be divided in Windowing, PreModulation, Fft and
+ PostModulation.
+
+ 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 "transform.h"
+
+#include "dct.h"
+#include "psy_const.h"
+#include "aacEnc_rom.h"
+#include "FDK_tools_rom.h"
+
+INT FDKaacEnc_Transform_Real (const INT_PCM * pTimeData,
+ FIXP_DBL *RESTRICT mdctData,
+ const INT blockType,
+ const INT windowShape,
+ INT *prevWindowShape,
+ const INT frameLength,
+ INT *mdctData_e,
+ INT filterType
+ ,FIXP_DBL * RESTRICT overlapAddBuffer
+ )
+{
+ const INT_PCM * RESTRICT timeData;
+
+ INT i;
+ /* tl: transform length
+ fl: left window slope length
+ nl: left window slope offset
+ fr: right window slope length
+ nr: right window slope offset
+ See FDK_tools/doc/intern/mdct.tex for more detail. */
+ int tl, fl, nl, fr, nr;
+
+ const FIXP_WTP * RESTRICT pLeftWindowPart;
+ const FIXP_WTP * RESTRICT pRightWindowPart;
+
+ /*
+ * MDCT scale:
+ * + 1: fMultDiv2() in windowing.
+ * + 1: Because of factor 1/2 in Princen-Bradley compliant windowed TDAC.
+ */
+ *mdctData_e = 1+1;
+
+ tl = frameLength;
+ timeData = pTimeData;
+
+ switch( blockType ) {
+ case LONG_WINDOW:
+ {
+ int offset = (windowShape == LOL_WINDOW) ? ((frameLength * 3)>>2) : 0;
+ fl = frameLength - offset;
+ fr = frameLength - offset;
+ }
+ break;
+ case STOP_WINDOW:
+ fl = frameLength >> 3;
+ fr = frameLength;
+ break;
+ case START_WINDOW: /* or StopStartSequence */
+ fl = frameLength;
+ fr = frameLength >> 3;
+ break;
+ case SHORT_WINDOW:
+ fl = fr = frameLength >> 3;
+ tl >>= 3;
+ timeData = pTimeData + 3*fl + (fl/2);
+ break;
+ default:
+ FDK_ASSERT(0);
+ return -1;
+ break;
+ }
+
+ /* Taken from FDK_tools/src/mdct.cpp Derive NR and NL */
+ nr = (tl - fr)>>1;
+ nl = (tl - fl)>>1;
+
+ pLeftWindowPart = FDKgetWindowSlope(fl, *prevWindowShape);
+ pRightWindowPart = FDKgetWindowSlope(fr, windowShape);
+
+ /* windowing */
+ if (filterType != FB_ELD)
+ {
+ /* Left window slope offset */
+ for (i=0; i<nl ; i++)
+ {
+#if SAMPLE_BITS == DFRACT_BITS /* SPC_BITS and DFRACT_BITS should be equal. */
+ mdctData[(tl/2)+i] = - (FIXP_DBL) timeData[tl-i-1] >> ( 1 );
+#else
+ mdctData[(tl/2)+i] = - (FIXP_DBL) timeData[tl-i-1] << (DFRACT_BITS - SAMPLE_BITS - 1);
+#endif
+ }
+ /* Left window slope */
+ for (i=0; i<fl/2; i++)
+ {
+ FIXP_DBL tmp0;
+ tmp0 = fMultDiv2((FIXP_PCM)timeData[i+nl], pLeftWindowPart[i].v.im);
+ mdctData[(tl/2)+i+nl] = fMultSubDiv2(tmp0, (FIXP_PCM)timeData[tl-nl-i-1], pLeftWindowPart[i].v.re);
+ }
+
+ /* Right window slope offset */
+ for(i=0; i<nr; i++)
+ {
+#if SAMPLE_BITS == DFRACT_BITS /* This should be SPC_BITS instead of DFRACT_BITS. */
+ mdctData[(tl/2)-1-i] = - (FIXP_DBL) timeData[tl+i] >> (1);
+#else
+ mdctData[(tl/2)-1-i] = - (FIXP_DBL) timeData[tl+i] << (DFRACT_BITS - SAMPLE_BITS - 1);
+#endif
+ }
+ /* Right window slope */
+ for (i=0; i<fr/2; i++)
+ {
+ FIXP_DBL tmp1;
+ tmp1 = fMultDiv2((FIXP_PCM)timeData[tl+nr+i], pRightWindowPart[i].v.re);
+ mdctData[(tl/2)-nr-i-1] = -fMultAddDiv2(tmp1, (FIXP_PCM)timeData[(tl*2)-nr-i-1], pRightWindowPart[i].v.im);
+ }
+ }
+
+ if (filterType == FB_ELD)
+ {
+ const FIXP_WTB *pWindowELD=NULL;
+ int i, N = frameLength, L = frameLength;
+
+ if (frameLength == 512) {
+ pWindowELD = ELDAnalysis512;
+ } else {
+ pWindowELD = ELDAnalysis480;
+ }
+
+ for(i=0;i<N/4;i++)
+ {
+ FIXP_DBL z0, outval;
+
+ z0 = (fMult((FIXP_PCM)timeData[L+N*3/4-1-i], pWindowELD[N/2-1-i])<< (WTS0-1)) + (fMult((FIXP_PCM)timeData[L+N*3/4+i], pWindowELD[N/2+i])<< (WTS0-1));
+
+ outval = (fMultDiv2((FIXP_PCM)timeData[L+N*3/4-1-i], pWindowELD[N+N/2-1-i]) >> (-WTS1));
+ outval += (fMultDiv2((FIXP_PCM)timeData[L+N*3/4+i], pWindowELD[N+N/2+i]) >> (-WTS1) );
+ outval += (fMultDiv2(overlapAddBuffer[N/2+i], pWindowELD[2*N+i])>> (-WTS2-1));
+
+ overlapAddBuffer[N/2+i] = overlapAddBuffer[i];
+
+ overlapAddBuffer[i] = z0;
+ mdctData[i] = overlapAddBuffer[N/2+i] + (fMultDiv2(overlapAddBuffer[N+N/2-1-i], pWindowELD[2*N+N/2+i]) >> (-WTS2-1));
+
+ mdctData[N-1-i] = outval;
+ overlapAddBuffer[N+N/2-1-i] = outval;
+ }
+
+ for(i=N/4;i<N/2;i++)
+ {
+ FIXP_DBL z0, outval;
+
+ z0 = fMult((FIXP_PCM)timeData[L+N*3/4-1-i], pWindowELD[N/2-1-i]) << (WTS0-1);
+
+ outval = (fMultDiv2((FIXP_PCM)timeData[L+N*3/4-1-i], pWindowELD[N+N/2-1-i]) >> (-WTS1)) ;
+ outval += (fMultDiv2(overlapAddBuffer[N/2+i], pWindowELD[2*N+i]) >> (-WTS2-1));
+
+ overlapAddBuffer[N/2+i] = overlapAddBuffer[i] + (fMult((FIXP_PCM)timeData[L-N/4+i], pWindowELD[N/2+i])<< (WTS0-1) );
+
+ overlapAddBuffer[i] = z0;
+ mdctData[i] = overlapAddBuffer[N/2+i] + (fMultDiv2(overlapAddBuffer[N+N/2-1-i], pWindowELD[2*N+N/2+i]) >> (-WTS2-1));
+
+ mdctData[N-1-i] = outval;
+ overlapAddBuffer[N+N/2-1-i] = outval;
+ }
+ }
+
+ dct_IV(mdctData, tl, mdctData_e);
+
+ *prevWindowShape = windowShape;
+
+ return 0;
+}
+
diff --git a/libAACenc/src/transform.h b/libAACenc/src/transform.h
new file mode 100644
index 0000000..6be93b5
--- /dev/null
+++ b/libAACenc/src/transform.h
@@ -0,0 +1,60 @@
+/******************************** MPEG Audio Encoder **************************
+
+ (C) Copyright Fraunhofer IIS (1999)
+ 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$
+ Initial author: M. Werner
+ contents/description: MDCT Transform
+
+******************************************************************************/
+#ifndef _TRANSFORM_H
+#define _TRANSFORM_H
+
+#include "common_fix.h"
+
+#define WTS0 1
+#define WTS1 0
+#define WTS2 -2
+
+/**
+ * \brief: Performe MDCT transform of time domain data.
+ * \param timeData pointer to time domain input signal.
+ * \param mdctData pointer to store frequency domain output data.
+ * \param blockType index indicating the type of block. Either
+ * LONG_WINDOW, START_WINDOW, SHORT_WINDOW or STOP_WINDOW.
+ * \param windowShape index indicating the window slope type to be used.
+ * Values allowed are either SINE_WINDOW or KBD_WINDOW.
+ * \param frameLength length of the block. Either 1024 or 960.
+ * \param mdctData_e pointer to an INT where the exponent of the frequency
+ * domain output data is stored into.
+ * \return 0 in case of success, non-zero in case of error (inconsistent parameters).
+ */
+INT FDKaacEnc_Transform_Real (const INT_PCM *timeData,
+ FIXP_DBL *RESTRICT mdctData,
+ const INT blockType,
+ const INT windowShape,
+ INT *prevWindowShape,
+ const INT frameLength,
+ INT *mdctData_e,
+ INT filterType
+ ,FIXP_DBL * RESTRICT overlapAddBuffer
+ );
+#endif