diff options
author | Dave Burke <daveburke@google.com> | 2012-04-17 09:51:45 -0700 |
---|---|---|
committer | Dave Burke <daveburke@google.com> | 2012-04-17 23:04:43 -0700 |
commit | 9bf37cc9712506b2483650c82d3c41152337ef7e (patch) | |
tree | 77db44e2bae06e3d144b255628be2b7a55c581d3 /libAACenc/src | |
parent | a37315fe10ee143d6d0b28c19d41a476a23e63ea (diff) | |
download | fdk-aac-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.gz fdk-aac-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.bz2 fdk-aac-9bf37cc9712506b2483650c82d3c41152337ef7e.zip |
Fraunhofer AAC codec.
License boilerplate update to follow.
Change-Id: I2810460c11a58b6d148d84673cc031f3685e79b5
Diffstat (limited to 'libAACenc/src')
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 |