aboutsummaryrefslogtreecommitdiffstats
path: root/libAACenc
diff options
context:
space:
mode:
authorDave Burke <daveburke@google.com>2012-04-17 09:51:45 -0700
committerDave Burke <daveburke@google.com>2012-04-17 23:04:43 -0700
commit9bf37cc9712506b2483650c82d3c41152337ef7e (patch)
tree77db44e2bae06e3d144b255628be2b7a55c581d3 /libAACenc
parenta37315fe10ee143d6d0b28c19d41a476a23e63ea (diff)
downloadfdk-aac-dabplus-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.gz
fdk-aac-dabplus-9bf37cc9712506b2483650c82d3c41152337ef7e.tar.bz2
fdk-aac-dabplus-9bf37cc9712506b2483650c82d3c41152337ef7e.zip
Fraunhofer AAC codec.
License boilerplate update to follow. Change-Id: I2810460c11a58b6d148d84673cc031f3685e79b5
Diffstat (limited to 'libAACenc')
-rw-r--r--libAACenc/Android.mk1
-rw-r--r--libAACenc/include/aacenc_lib.h1150
-rw-r--r--libAACenc/src/Android.mk53
-rw-r--r--libAACenc/src/aacEnc_ram.cpp132
-rw-r--r--libAACenc/src/aacEnc_ram.h163
-rw-r--r--libAACenc/src/aacEnc_rom.cpp1170
-rw-r--r--libAACenc/src/aacEnc_rom.h141
-rw-r--r--libAACenc/src/aacenc.cpp952
-rw-r--r--libAACenc/src/aacenc.h232
-rw-r--r--libAACenc/src/aacenc_hcr.cpp31
-rw-r--r--libAACenc/src/aacenc_hcr.h33
-rw-r--r--libAACenc/src/aacenc_lib.cpp1696
-rw-r--r--libAACenc/src/aacenc_pns.cpp532
-rw-r--r--libAACenc/src/aacenc_pns.h52
-rw-r--r--libAACenc/src/aacenc_tns.cpp1286
-rw-r--r--libAACenc/src/aacenc_tns.h135
-rw-r--r--libAACenc/src/adj_thr.cpp2262
-rw-r--r--libAACenc/src/adj_thr.h79
-rw-r--r--libAACenc/src/adj_thr_data.h88
-rw-r--r--libAACenc/src/band_nrg.cpp297
-rw-r--r--libAACenc/src/band_nrg.h86
-rw-r--r--libAACenc/src/bandwidth.cpp316
-rw-r--r--libAACenc/src/bandwidth.h44
-rw-r--r--libAACenc/src/bit_cnt.cpp1060
-rw-r--r--libAACenc/src/bit_cnt.h124
-rw-r--r--libAACenc/src/bitenc.cpp1431
-rw-r--r--libAACenc/src/bitenc.h120
-rw-r--r--libAACenc/src/block_switch.cpp500
-rw-r--r--libAACenc/src/block_switch.h85
-rw-r--r--libAACenc/src/channel_map.cpp499
-rw-r--r--libAACenc/src/channel_map.h72
-rw-r--r--libAACenc/src/chaosmeasure.cpp99
-rw-r--r--libAACenc/src/chaosmeasure.h41
-rw-r--r--libAACenc/src/dyn_bits.cpp743
-rw-r--r--libAACenc/src/dyn_bits.h104
-rw-r--r--libAACenc/src/grp_data.cpp206
-rw-r--r--libAACenc/src/grp_data.h53
-rw-r--r--libAACenc/src/intensity.cpp691
-rw-r--r--libAACenc/src/intensity.h61
-rw-r--r--libAACenc/src/interface.h100
-rw-r--r--libAACenc/src/line_pe.cpp145
-rw-r--r--libAACenc/src/line_pe.h77
-rw-r--r--libAACenc/src/metadata_compressor.cpp965
-rw-r--r--libAACenc/src/metadata_compressor.h190
-rw-r--r--libAACenc/src/metadata_main.cpp809
-rw-r--r--libAACenc/src/metadata_main.h161
-rw-r--r--libAACenc/src/ms_stereo.cpp189
-rw-r--r--libAACenc/src/ms_stereo.h44
-rw-r--r--libAACenc/src/noisedet.cpp170
-rw-r--r--libAACenc/src/noisedet.h47
-rw-r--r--libAACenc/src/pns_func.h89
-rw-r--r--libAACenc/src/pnsparam.cpp248
-rw-r--r--libAACenc/src/pnsparam.h78
-rw-r--r--libAACenc/src/pre_echo_control.cpp108
-rw-r--r--libAACenc/src/pre_echo_control.h51
-rw-r--r--libAACenc/src/psy_configuration.cpp594
-rw-r--r--libAACenc/src/psy_configuration.h102
-rw-r--r--libAACenc/src/psy_const.h99
-rw-r--r--libAACenc/src/psy_data.h89
-rw-r--r--libAACenc/src/psy_main.cpp1338
-rw-r--r--libAACenc/src/psy_main.h111
-rw-r--r--libAACenc/src/qc_data.h214
-rw-r--r--libAACenc/src/qc_main.cpp1551
-rw-r--r--libAACenc/src/qc_main.h108
-rw-r--r--libAACenc/src/quantize.cpp323
-rw-r--r--libAACenc/src/quantize.h56
-rw-r--r--libAACenc/src/sf_estim.cpp1243
-rw-r--r--libAACenc/src/sf_estim.h54
-rw-r--r--libAACenc/src/spreading.cpp52
-rw-r--r--libAACenc/src/spreading.h40
-rw-r--r--libAACenc/src/tns_func.h81
-rw-r--r--libAACenc/src/tns_param.cpp31
-rw-r--r--libAACenc/src/tns_param.h33
-rw-r--r--libAACenc/src/tonality.cpp147
-rw-r--r--libAACenc/src/tonality.h46
-rw-r--r--libAACenc/src/transform.cpp203
-rw-r--r--libAACenc/src/transform.h60
77 files changed, 26866 insertions, 0 deletions
diff --git a/libAACenc/Android.mk b/libAACenc/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/libAACenc/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/libAACenc/include/aacenc_lib.h b/libAACenc/include/aacenc_lib.h
new file mode 100644
index 0000000..d67d378
--- /dev/null
+++ b/libAACenc/include/aacenc_lib.h
@@ -0,0 +1,1150 @@
+/**************************** 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
+******************************************************************************/
+
+/**
+ * \file aacenc_lib.h
+ * \brief FDK AAC Encoder library interface header file.
+ *
+\mainpage Introduction
+
+\section Scope
+
+This document describes the high-level interface and usage of the ISO/MPEG-2/4 AAC Encoder
+library developed by the Fraunhofer Institute for Integrated Circuits (IIS).
+
+The library implements encoding on the basis of the MPEG-2 and MPEG-4 AAC Low-Complexity
+standard, and depending on the library's configuration, MPEG-4 High-Efficiency AAC v2 and/or AAC-ELD standard.
+
+All references to SBR (Spectral Band Replication) are only applicable to HE-AAC or AAC-ELD versions
+of the library. All references to PS (Parametric Stereo) are only applicable to HE-AAC v2
+versions of the library.
+
+\section encBasics Encoder Basics
+
+This document can only give a rough overview about the ISO/MPEG-2 and ISO/MPEG-4 AAC audio coding
+standard. To understand all the terms in this document, you are encouraged to read the following documents.
+
+- ISO/IEC 13818-7 (MPEG-2 AAC), which defines the syntax of MPEG-2 AAC audio bitstreams.
+- ISO/IEC 14496-3 (MPEG-4 AAC, subparts 1 and 4), which defines the syntax of MPEG-4 AAC audio bitstreams.
+- Lutzky, Schuller, Gayer, Kr&auml;mer, Wabnik, "A guideline to audio codec delay", 116th AES Convention, May 8, 2004
+
+MPEG Advanced Audio Coding is based on a time-to-frequency mapping of the signal. The signal is
+partitioned into overlapping portions and transformed into frequency domain. The spectral components
+are then quantized and coded. \n
+An MPEG-2 or MPEG-4 AAC audio bitstream is composed of frames. Contrary to MPEG-1/2 Layer-3 (mp3), the
+length of individual frames is not restricted to a fixed number of bytes, but can take on any length
+between 1 and 768 bytes.
+
+
+\page LIBUSE Library Usage
+
+\section InterfaceDescription API Files
+
+All API header files are located in the folder /include of the release package. All header files
+are provided for usage in C/C++ programs. The AAC encoder library API functions are located at
+aacenc_lib.h.
+
+In binary releases the encoder core resides in statically linkable libraries called for example
+libAACenc.a/libFDK.a (LINUX) or FDK_fastaaclib.lib (MS Visual C++) for the plain AAC-LC core encoder
+and libSBRenc.a (LINUX) or FDK_sbrEncLib.lib (MS Visual C++) for the SBR (Spectral Band
+Replication) and PS (Parametric Stereo) modules.
+
+\section CallingSequence Calling Sequence
+
+For encoding of ISO/MPEG-2/4 AAC bitstreams the following sequence is mandatory. Input read and output
+write functions as well as the corresponding open and close functions are left out, since they may be
+implemented differently according to the user's specific requirements. The example implementation in
+main.cpp uses file-based input/output.
+
+-# Call aacEncOpen() to allocate encoder instance with required \ref encOpen "configuration".\n
+\dontinclude main.cpp
+\skipline hAacEncoder =
+\skipline aacEncOpen
+-# Call aacEncoder_SetParam() for each parameter to be set. AOT, samplingrate, channelMode, bitrate and transport type are \ref encParams "mandatory".
+\code
+ ErrorStatus = aacEncoder_SetParam(hAacEncoder, parameter, value);
+\endcode
+-# Call aacEncEncode() with NULL parameters to \ref encReconf "initialize" encoder instance with present parameter set.
+\skipline aacEncEncode
+-# Call aacEncInfo() to retrieve a configuration data block to be transmitted out of band. This is required when using RFC3640 or RFC3016 like transport.
+\dontinclude main.cpp
+\skipline encInfo
+\skipline aacEncInfo
+-# Encode input audio data in loop.
+\skip Encode as long as
+\skipline do
+\until {
+Feed \ref feedInBuf "input buffer" with new audio data and provide input/output \ref bufDes "arguments" to aacEncEncode().
+\skipline aacEncEncode
+\until ;
+Write \ref writeOutData "output data" to file or audio device. \skipline while
+-# Call aacEncClose() and destroy encoder instance.
+\skipline aacEncClose
+
+\section encOpen Encoder Instance Allocation
+
+The assignment of the aacEncOpen() function is very flexible and can be used in the following way.
+- If the amount of memory consumption is not an issue, the encoder instance can be allocated
+for the maximum number of possible audio channels (for example 6 or 8) with the full functional range supported by the library.
+This is the default open procedure for the AAC encoder if memory consumption does not need to be minimized.
+\code aacEncOpen(&hAacEncoder,0,0) \endcode
+- If the required MPEG-4 AOTs do not call for the full functional range of the library, encoder modules can be allocated selectively.
+\verbatim
+------------------------------------------------------
+ AAC | SBR | PS | MD | FLAGS | value
+-----+-----+-----+----+-----------------------+-------
+ X | - | - | - | (0x01) | 0x01
+ X | X | - | - | (0x01|0x02) | 0x03
+ X | X | X | - | (0x01|0x02|0x04) | 0x07
+ X | - | - | X | (0x01 |0x10) | 0x11
+ X | X | - | X | (0x01|0x02 |0x10) | 0x13
+ X | X | X | X | (0x01|0x02|0x04|0x10) | 0x17
+------------------------------------------------------
+ - AAC: Allocate AAC Core Encoder module.
+ - SBR: Allocate Spectral Band Replication module.
+ - PS: Allocate Parametric Stereo module.
+ - MD: Allocate Meta Data module within AAC encoder.
+\endverbatim
+\code aacEncOpen(&hAacEncoder,value,0) \endcode
+- Specifying the maximum number of channels to be supported in the encoder instance can be done as follows.
+ - For example allocate an encoder instance which supports 2 channels for all supported AOTs.
+ The library itself may be capable of encoding up to 6 or 8 channels but in this example only 2 channel encoding is required and thus only buffers for 2 channels are allocated to save data memory.
+\code aacEncOpen(&hAacEncoder,0,2) \endcode
+ - Additionally the maximum number of supported channels in the SBR module can be denoted separately.\n
+ In this example the encoder instance provides a maximum of 6 channels out of which up to 2 channels support SBR.
+ This encoder instance can produce for example 5.1 channel AAC-LC streams or stereo HE-AAC (v2) streams.
+ HE-AAC 5.1 multi channel is not possible since only 2 out of 6 channels support SBR, which saves data memory.
+\code aacEncOpen(&hAacEncoder,0,6|(2<<8)) \endcode
+\n
+
+\section bufDes Input/Output Arguments
+
+\subsection allocIOBufs Provide Buffer Descriptors
+In the present encoder API, the input and output buffers are described with \ref AACENC_BufDesc "buffer descriptors". This mechanism allows a flexible handling
+of input and output buffers without impact to the actual encoding call. Optional buffers are necessary e.g. for ancillary data, meta data input or additional output
+buffers describing superframing data in DAB+ or DRM+.\n
+At least one input buffer for audio input data and one output buffer for bitstream data must be allocated. The input buffer size can be a user defined multiple
+of the number of input channels. PCM input data will be copied from the user defined PCM buffer to an internal input buffer and so input data can be less than one AAC audio frame.
+The output buffer size should be 6144 bits per channel excluding the LFE channel.
+If the output data does not fit into the provided buffer, an AACENC_ERROR will be returned by aacEncEncode().
+\dontinclude main.cpp
+\skipline inputBuffer
+\until outputBuffer
+All input and output buffer must be clustered in input and output buffer arrays.
+\skipline inBuffer
+\until outBufferElSize
+Allocate buffer descriptors
+\skipline AACENC_BufDesc
+\skipline AACENC_BufDesc
+Initialize input buffer descriptor
+\skipline inBufDesc
+\until bufElSizes
+Initialize output buffer descriptor
+\skipline outBufDesc
+\until bufElSizes
+
+\subsection argLists Provide Input/Output Argument Lists
+The input and output arguments of an aacEncEncode() call are described in argument structures.
+\dontinclude main.cpp
+\skipline AACENC_InArgs
+\skipline AACENC_OutArgs
+
+\section feedInBuf Feed Input Buffer
+The input buffer should be handled as a modulo buffer. New audio data in the form of pulse-code-
+modulated samples (PCM) must be read from external and be fed to the input buffer depending on its
+fill level. The required sample bitrate (represented by the data type INT_PCM which is 16, 24 or 32
+bits wide) is fixed and depends on library configuration (usually 16 bit).
+
+\dontinclude main.cpp
+\skipline WAV_InputRead
+\until ;
+After the encoder's internal buffer is fed with incoming audio samples, and aacEncEncode()
+processed the new input data, update/move remaining samples in input buffer, simulating a modulo buffer:
+\skipline outargs.numInSamples>0
+\until }
+
+\section writeOutData Output Bitstream Data
+If any AAC bitstream data is available, write it to output file or device. This can be done once the
+following condition is true:
+\dontinclude main.cpp
+\skip Valid bitstream available
+\skipline outargs
+
+\skipline outBytes>0
+
+If you use file I/O then for example call mpegFileWrite_Write() from the library libMpegFileWrite
+
+\dontinclude main.cpp
+\skipline mpegFileWrite_Write
+
+\section cfgMetaData Meta Data Configuration
+
+If the present library is configured with Metadata support, it is possible to insert meta data side info into the generated
+audio bitstream while encoding.
+
+To work with meta data the encoder instance has to be \ref encOpen "allocated" with meta data support. The meta data mode must be be configured with
+the ::AACENC_METADATA_MODE parameter and aacEncoder_SetParam() function.
+\code aacEncoder_SetParam(hAacEncoder, AACENC_METADATA_MODE, 0-2); \endcode
+
+This configuration indicates how to embed meta data into bitstrem. Either no insertion, MPEG or ETSI style.
+The meta data itself must be specified within the meta data setup structure AACENC_MetaData.
+
+Changing one of the AACENC_MetaData setup parameters can be achieved from outside the library within ::IN_METADATA_SETUP input
+buffer. There is no need to supply meta data setup structure every frame. If there is no new meta setup data available, the
+encoder uses the previous setup or the default configuration in initial state.
+
+In general the audio compressor and limiter within the encoder library can be configured with the ::AACENC_METADATA_DRC_PROFILE parameter
+AACENC_MetaData::drc_profile and and AACENC_MetaData::comp_profile.
+\n
+
+\section encReconf Encoder Reconfiguration
+
+The encoder library allows reconfiguration of the encoder instance with new settings
+continuously between encoding frames. Each parameter to be changed must be set with
+a single aacEncoder_SetParam() call. The internal status of each parameter can be
+retrieved with an aacEncoder_GetParam() call.\n
+There is no stand-alone reconfiguration function available. When parameters were
+modified from outside the library, an internal control mechanism triggers the necessary
+reconfiguration process which will be applied at the beginning of the following
+aacEncEncode() call. This state can be observed from external via the AACENC_INIT_STATUS
+and aacEncoder_GetParam() function. The reconfiguration process can also be applied
+immediately when all parameters of an aacEncEncode() call are NULL with a valid encoder
+handle.\n\n
+The internal reconfiguration process can be controlled from extern with the following access.
+\code aacEncoder_SetParam(hAacEncoder, AACENC_CONTROL_STATE, AACENC_CTRLFLAGS); \endcode
+
+
+\section encParams Encoder Parametrization
+
+All parameteres listed in ::AACENC_PARAM can be modified within an encoder instance.
+
+\subsection encMandatory Mandatory Encoder Parameters
+The following parameters must be specified when the encoder instance is initialized.
+\code
+aacEncoder_SetParam(hAacEncoder, AACENC_AOT, value);
+aacEncoder_SetParam(hAacEncoder, AACENC_BITRATE, value);
+aacEncoder_SetParam(hAacEncoder, AACENC_SAMPLERATE, value);
+aacEncoder_SetParam(hAacEncoder, AACENC_CHANNELMODE, value);
+\endcode
+Beyond that is an internal auto mode which preinitizializes the ::AACENC_BITRATE parameter
+if the parameter was not set from extern. The bitrate depends on the number of effective
+channels and sampling rate and is determined as follows.
+\code
+AAC-LC (AOT_AAC_LC): 1.5 bits per sample
+HE-AAC (AOT_SBR): 0.625 bits per sample
+HE-AAC v2 (AOT_PS): 0.5 bits per sample
+\endcode
+
+\subsection channelMode Channel Mode Configuration
+The input audio data is described with the ::AACENC_CHANNELMODE parameter in the
+aacEncoder_SetParam() call. It is not possible to use the encoder instance with a 'number of
+input channels' argument. Instead, the channelMode must be set as follows.
+\code aacEncoder_SetParam(hAacEncoder, AACENC_CHANNELMODE, value); \endcode
+The parameter is specified in ::CHANNEL_MODE and can be mapped from the number of input channels
+in the following way.
+\dontinclude main.cpp
+\skip CHANNEL_MODE chMode = MODE_INVALID;
+\until return
+
+\subsection encQual Audio Quality Considerations
+The default encoder configuration is suggested to be used. Encoder tools such as TNS and PNS
+are activated by default and are internally controlled (see \ref BEHAVIOUR_TOOLS).
+
+There is an additional quality parameter called ::AACENC_AFTERBURNER. In the default
+configuration this quality switch is deactivated because it would cause a workload
+increase which might be significant. If workload is not an issue in the application
+we recommended to activate this feature.
+\code aacEncoder_SetParam(hAacEncoder, AACENC_AFTERBURNER, 1); \endcode
+
+
+\section audiochCfg Audio Channel Configuration
+The MPEG standard refers often to the so-called Channel Configuration. This Channel Configuration is used for a fixed Channel
+Mapping. The configurations 1-7 are predefined in MPEG standard and used for implicit signalling within the encoded bitstream.
+For user defined Configurations the Channel Configuration is set to 0 and the Channel Mapping must be explecitly described with an appropriate
+Program Config Element. The present Encoder implementation does not allow the user to configure this Channel Configuration from
+extern. The Encoder implementation supports fixed Channel Modes which are mapped to Channel Configuration as follow.
+\verbatim
+--------------------------------------------------------------------
+ ChannelMode | ChCfg | front_El | side_El | back_El | lfe_El
+-----------------+--------+----------+----------+----------+--------
+MODE_1 | 1 | SCE | | |
+MODE_2 | 2 | CPE | | |
+MODE_1_2 | 3 | SCE, CPE | | |
+MODE_1_2_1 | 4 | SCE, CPE | | SCE |
+MODE_1_2_2 | 5 | SCE, CPE | | CPE |
+MODE_1_2_2_1 | 6 | SCE, CPE | | CPE | LFE
+--------------------------------------------------------------------
+ - SCE: Single Channel Element.
+ - CPE: Channel Pair.
+ - SCE: Low Frequency Element.
+\endverbatim
+
+Moreover, the Table describes all fixed Channel Elements for each Channel Mode which are assigned to a speaker arrangement. The
+arrangement includes front, side, back and lfe Audio Channel Elements.\n
+This mapping of Audio Channel Elements is defined in MPEG standard for Channel Config 1-7. The Channel assignment for MODE_1_1,
+MODE_2_2 and MODE_2_1 is used from the ARIB standard. All other configurations are defined as suggested in MPEG.\n
+In case of Channel Config 0 or writing matrix mixdown coefficients, the encoder enables the writing of Program Config Element
+itself as described in \ref encPCE. The configuration used in Program Config Element refers to the denoted Table.\n
+Beside the Channel Element assignment the Channel Modes are resposible for audio input data channel mapping. The Channel Mapping
+of the audio data depends on the selected ::AACENC_CHANNELORDER which can be MPEG or WAV like order.\n
+Following Table describes the complete channel mapping for both Channel Order configurations.
+\verbatim
+---------------------------------------------------------------------------------
+ChannelMode | MPEG-Channelorder | WAV-Channelorder
+-----------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---
+MODE_1 | 0 | | | | | | | | 0 | | | | | | |
+MODE_2 | 0 | 1 | | | | | | | 0 | 1 | | | | | |
+MODE_1_2 | 0 | 1 | 2 | | | | | | 2 | 0 | 1 | | | | |
+MODE_1_2_1 | 0 | 1 | 2 | 3 | | | | | 2 | 0 | 1 | 3 | | | |
+MODE_1_2_2 | 0 | 1 | 2 | 3 | 4 | | | | 2 | 0 | 1 | 3 | 4 | | |
+MODE_1_2_2_1 | 0 | 1 | 2 | 3 | 4 | 5 | | | 2 | 0 | 1 | 4 | 5 | 3 | |
+---------------------------------------------------------------------------------
+\endverbatim
+
+The denoted mapping is important for correct audio channel assignment when using MPEG or WAV ordering. The incoming audio
+channels are distributed MPEG like starting at the front channels and ending at the back channels. The distribution is used as
+described in Table concering Channel Config and fix channel elements. Please see the following example for clarification.
+
+\verbatim
+Example: MODE_1_2_2_1 - WAV-Channelorder 5.1
+------------------------------------------
+ Input Channel | Coder Channel
+--------------------+---------------------
+ 2 (front center) | 0 (SCE channel)
+ 0 (left center) | 1 (1st of 1st CPE)
+ 1 (right center) | 2 (2nd of 1st CPE)
+ 4 (left surround) | 3 (1st of 2nd CPE)
+ 5 (right surround) | 4 (2nd of 2nd CPE)
+ 3 (LFE) | 5 (LFE)
+------------------------------------------
+\endverbatim
+
+
+\section suppBitrates Supported Bitrates
+
+The FDK AAC Encoder provides a wide range of supported bitrates.
+The minimum and maximum allowed bitrate depends on the Audio Object Type. For AAC-LC the minimum
+bitrate is the bitrate that is required to write the most basic and minimal valid bitstream.
+It consists of the bitstream format header information and other static/mandatory information
+within the AAC payload. The maximum AAC framesize allowed by the MPEG-4 standard
+determines the maximum allowed bitrate for AAC-LC. For HE-AAC and HE-AAC v2 a library internal
+look-up table is used.
+
+A good working point in terms of audio quality, sampling rate and bitrate, is at 1 to 1.5
+bits/audio sample for AAC-LC, 0.625 bits/audio sample for HE-AAC and 0.5 bits/audio sample
+for HE-AAC v2. For example for one channel with a sampling frequency of 48 kHz, the range from
+48 kbit/s to 72 kbit/s achieves reasonable audio quality for AAC-LC.
+
+For HE-AAC and HE-AAC v2 the lowest possible audio input sampling frequency is 16 kHz because then the
+AAC-LC core encoder operates in dual rate mode at its lowest possible sampling frequency, which is 8 kHz.
+HE-AAC v2 requires stereo input audio data.
+
+The following table lists the supported bitrates for AAC-LC, HE-AAC and HE-AAC v2 encoding depending
+on input sampling frequency ("Hz") and number of input channels ("chan"). The minimum and maximum
+allowed bitrate ("BR Min", "BR Max") is given in bits per second.
+In case the desired combination of bitrate and sampling frequency is not available ("NA") for HE-AAC or
+HE-AAC v2 then the encoder will automatically switch to AAC-LC and give a command line warning.
+Please note that in HE-AAC or HE-AAC v2 mode the encoder supports much higher bitrates than are
+appropriate for HE-AAC or HE-AAC v2. For example, at a bitrate of more than 64 kbit/s for a stereo
+audio signal at 44.1 kHz it usually makes sense to use AAC-LC, which will produce better audio
+quality at that bitrate than HE-AAC or HE-AAC v2.
+
+
+\verbatim
+ Config AAC-LC HE-AAC (SBR) HE-AACv2 (SBR+PS)
+
+ Hz chan BR Min BR Max BR Min BR Max BR Min BR Max
+
+8000 1 758 48000 NA NA NA NA
+11025 1 1045 66150 NA NA NA NA
+12000 1 1137 72000 NA NA NA NA
+16000 1 1516 96000 8000 48000 NA NA
+22050 1 2089 132300 8000 64000 NA NA
+24000 1 2274 144000 8000 64000 NA NA
+32000 1 3032 192000 8000 64000 NA NA
+44100 1 4178 264576 8000 64000 NA NA
+48000 1 4547 288000 12000 64000 NA NA
+64000 1 6063 384000 24000 160000 NA NA
+88200 1 8355 529200 24000 160000 NA NA
+96000 1 9094 576000 24000 160000 NA NA
+-----------------------------------------------------------------------------------
+8000 2 1071 96000 NA NA NA NA
+11025 2 1476 132300 NA NA NA NA
+12000 2 1606 144000 NA NA NA NA
+16000 2 2141 192000 16000 96000 8000 48000
+22050 2 2951 264600 16000 128000 8000 64000
+24000 2 3211 288000 16000 128000 8000 64000
+32000 2 4282 384000 16000 128000 8000 64000
+44100 2 5900 529152 16000 128000 8000 64000
+48000 2 6422 576000 16000 128000 12000 64000
+64000 2 8563 768000 32000 256000 24000 160000
+88200 2 11801 1058400 32000 256000 24000 160000
+96000 2 12844 1152000 32000 256000 24000 160000
+-----------------------------------------------------------------------------------
+8000 3 1383 144000 NA NA NA NA
+11025 3 1906 198450 NA NA NA NA
+12000 3 2075 216000 NA NA NA NA
+16000 3 2766 288000 26667 120000 NA NA
+22050 3 3812 396900 26667 160000 NA NA
+24000 3 4149 432000 26667 160000 NA NA
+32000 3 5532 576000 26667 160000 NA NA
+44100 3 7623 793728 26667 160000 NA NA
+48000 3 8297 864000 29996 160000 NA NA
+64000 3 11063 1152000 59996 400000 NA NA
+88200 3 15246 1587600 59996 400000 NA NA
+96000 3 16594 1728000 59996 400000 NA NA
+-----------------------------------------------------------------------------------
+8000 4 1696 192000 NA NA NA NA
+11025 4 2337 264600 NA NA NA NA
+12000 4 2543 288000 NA NA NA NA
+16000 4 3391 384000 40000 160000 NA NA
+22050 4 4673 529200 40000 213330 NA NA
+24000 4 5086 576000 40000 213330 NA NA
+32000 4 6782 768000 40000 213330 NA NA
+44100 4 9345 1058304 40000 213330 NA NA
+48000 4 10172 1152000 40000 213330 NA NA
+64000 4 13563 1536000 80000 533330 NA NA
+88200 4 18691 2116800 80000 533330 NA NA
+96000 4 20344 2304000 80000 533330 NA NA
+-----------------------------------------------------------------------------------
+8000 5 2008 240000 NA NA NA NA
+11025 5 2768 330750 NA NA NA NA
+12000 5 3012 360000 NA NA NA NA
+16000 5 4016 480000 43244 184612 NA NA
+22050 5 5535 661500 43244 246152 NA NA
+24000 5 6024 720000 43244 246152 NA NA
+32000 5 8032 960000 43244 246152 NA NA
+44100 5 11068 1322880 43244 246152 NA NA
+48000 5 12047 1440000 46140 246152 NA NA
+64000 5 16063 1920000 92296 615384 NA NA
+88200 5 22137 2646000 92296 615384 NA NA
+96000 5 24094 2880000 92296 615384 NA NA
+-----------------------------------------------------------------------------------
+8000 5.1 2321 240000 NA NA NA NA
+11025 5.1 3198 330750 NA NA NA NA
+12000 5.1 3481 360000 NA NA NA NA
+16000 5.1 4641 480000 45715 199990 NA NA
+22050 5.1 6396 661500 45715 266658 NA NA
+24000 5.1 6961 720000 45715 266658 NA NA
+32000 5.1 9282 960000 45715 266658 NA NA
+44100 5.1 12790 1322880 45715 266658 NA NA
+48000 5.1 13922 1440000 49982 266658 NA NA
+64000 5.1 18563 1920000 99982 666658 NA NA
+88200 5.1 25582 2646000 99982 666658 NA NA
+96000 5.1 27844 2880000 99982 666658 NA NA
+
+\endverbatim \n
+
+\section reommendedConfig Recommended Sampling Rate and Bitrate Combinations
+
+The following table provides an overview of recommended encoder configuration parameters
+which we determined by virtue of numerous listening tests.
+
+\subsection reommendedConfigLC AAC-LC, HE-AAC, HE-AACv2.
+\verbatim
+-----------------------------------------------------------------------------------
+Audio Object Type | Bit Rate Range | Supported | Preferred | No. of
+ | [bit/s] | Sampling Rates | Sampl. | Chan.
+ | | [kHz] | Rate |
+ | | | [kHz] |
+-------------------+------------------+-----------------------+------------+-------
+AAC LC + SBR + PS | 8000 - 11999 | 22.05, 24.00 | 24.00 | 2
+AAC LC + SBR + PS | 12000 - 17999 | 32.00 | 32.00 | 2
+AAC LC + SBR + PS | 18000 - 39999 | 32.00, 44.10, 48.00 | 44.10 | 2
+AAC LC + SBR + PS | 40000 - 56000 | 32.00, 44.10, 48.00 | 48.00 | 2
+-------------------+------------------+-----------------------+------------+-------
+AAC LC + SBR | 8000 - 11999 | 22.05, 24.00 | 24.00 | 1
+AAC LC + SBR | 12000 - 17999 | 32.00 | 32.00 | 1
+AAC LC + SBR | 18000 - 39999 | 32.00, 44.10, 48.00 | 44.10 | 1
+AAC LC + SBR | 40000 - 56000 | 32.00, 44.10, 48.00 | 48.00 | 1
+AAC LC + SBR | 16000 - 27999 | 32.00, 44.10, 48.00 | 32.00 | 2
+AAC LC + SBR | 28000 - 63999 | 32.00, 44.10, 48.00 | 44.10 | 2
+AAC LC + SBR | 64000 - 128000 | 32.00, 44.10, 48.00 | 48.00 | 2
+-------------------+------------------+-----------------------+------------+-------
+AAC LC + SBR | 64000 - 69999 | 32.00, 44.10, 48.00 | 32.00 | 5, 5.1
+AAC LC + SBR | 70000 - 159999 | 32.00, 44.10, 48.00 | 44.10 | 5, 5.1
+AAC LC + SBR | 160000 - 319999 | 32.00, 44.10, 48.00 | 48.00 | 5, 5.1
+AAC LC + SBR | 320000 - 640000 | 64.00, 88.20, 96.00 | 96.00 | 5, 5.1
+-------------------+------------------+-----------------------+------------+-------
+AAC LC | 8000 - 15999 | 11.025, 12.00, 16.00 | 12.00 | 1
+AAC LC | 16000 - 23999 | 16.00 | 16.00 | 1
+AAC LC | 24000 - 31999 | 16.00, 22.05, 24.00 | 24.00 | 1
+AAC LC | 32000 - 55999 | 32.00 | 32.00 | 1
+AAC LC | 56000 - 160000 | 32.00, 44.10, 48.00 | 44.10 | 1
+AAC LC | 160001 - 288000 | 48.00 | 48.00 | 1
+-------------------+------------------+-----------------------+------------+-------
+AAC LC | 16000 - 23999 | 11.025, 12.00, 16.00 | 12.00 | 2
+AAC LC | 24000 - 31999 | 16.00 | 16.00 | 2
+AAC LC | 32000 - 39999 | 16.00, 22.05, 24.00 | 22.05 | 2
+AAC LC | 40000 - 95999 | 32.00 | 32.00 | 2
+AAC LC | 96000 - 111999 | 32.00, 44.10, 48.00 | 32.00 | 2
+AAC LC | 112000 - 320001 | 32.00, 44.10, 48.00 | 44.10 | 2
+AAC LC | 320002 - 576000 | 48.00 | 48.00 | 2
+-------------------+------------------+-----------------------+------------+-------
+AAC LC | 160000 - 239999 | 32.00 | 32.00 | 5, 5.1
+AAC LC | 240000 - 279999 | 32.00, 44.10, 48.00 | 32.00 | 5, 5.1
+AAC LC | 280000 - 800000 | 32.00, 44.10, 48.00 | 44.10 | 5, 5.1
+-----------------------------------------------------------------------------------
+\endverbatim \n
+
+\subsection reommendedConfigLD AAC-LD, AAC-ELD, AAC-ELD with SBR.
+\verbatim
+-----------------------------------------------------------------------------------
+Audio Object Type | Bit Rate Range | Supported | Preferred | No. of
+ | [bit/s] | Sampling Rates | Sampl. | Chan.
+ | | [kHz] | Rate |
+ | | | [kHz] |
+-------------------+------------------+-----------------------+------------+-------
+ELD + SBR | 16000 - 24999 | 32.00 - 44.10 | 32.00 | 1
+ELD + SBR | 25000 - 31999 | 32.00 - 48.00 | 32.00 | 1
+ELD + SBR | 32000 - 64000 | 32.00 - 48.00 | 48.00 | 1
+-------------------+------------------+-----------------------+------------+-------
+ELD + SBR | 32000 - 51999 | 32.00 - 48.00 | 44.10 | 2
+ELD + SBR | 52000 - 128000 | 32.00 - 48.00 | 48.00 | 2
+-------------------+------------------+-----------------------+------------+-------
+ELD + SBR | 72000 - 192000 | 44.10 - 48.00 | 48.00 | 3
+-------------------+------------------+-----------------------+------------+-------
+ELD + SBR | 96000 - 256000 | 44.10 - 48.00 | 48.00 | 4
+-------------------+------------------+-----------------------+------------+-------
+ELD + SBR | 120000 - 320000 | 44.10 - 48.00 | 48.00 | 5
+-------------------+------------------+-----------------------+------------+-------
+LD, ELD | 16000 - 19999 | 16.00 - 24.00 | 16.00 | 1
+LD, ELD | 20000 - 39999 | 16.00 - 32.00 | 24.00 | 1
+LD, ELD | 40000 - 49999 | 22.05 - 32.00 | 32.00 | 1
+LD, ELD | 50000 - 61999 | 24.00 - 44.10 | 32.00 | 1
+LD, ELD | 62000 - 84999 | 32.00 - 48.00 | 44.10 | 1
+LD, ELD | 85000 - 192000 | 44.10 - 48.00 | 48.00 | 1
+-------------------+------------------+-----------------------+------------+-------
+LD, ELD | 64000 - 75999 | 24.00 - 32.00 | 32.00 | 2
+LD, ELD | 76000 - 97999 | 24.00 - 44.10 | 32.00 | 2
+LD, ELD | 98000 - 135999 | 32.00 - 48.00 | 44.10 | 2
+LD, ELD | 136000 - 384000 | 44.10 - 48.00 | 48.00 | 2
+-------------------+------------------+-----------------------+------------+-------
+LD, ELD | 96000 - 113999 | 24.00 - 32.00 | 32.00 | 3
+LD, ELD | 114000 - 146999 | 24.00 - 44.10 | 32.00 | 3
+LD, ELD | 147000 - 203999 | 32.00 - 48.00 | 44.10 | 3
+LD, ELD | 204000 - 576000 | 44.10 - 48.00 | 48.00 | 3
+-------------------+------------------+-----------------------+------------+-------
+LD, ELD | 128000 - 151999 | 24.00 - 32.00 | 32.00 | 4
+LD, ELD | 152000 - 195999 | 24.00 - 44.10 | 32.00 | 4
+LD, ELD | 196000 - 271999 | 32.00 - 48.00 | 44.10 | 4
+LD, ELD | 272000 - 768000 | 44.10 - 48.00 | 48.00 | 4
+-------------------+------------------+-----------------------+------------+-------
+LD, ELD | 160000 - 189999 | 24.00 - 32.00 | 32.00 | 5
+LD, ELD | 190000 - 244999 | 24.00 - 44.10 | 32.00 | 5
+LD, ELD | 245000 - 339999 | 32.00 - 48.00 | 44.10 | 5
+LD, ELD | 340000 - 960000 | 44.10 - 48.00 | 48.00 | 5
+-----------------------------------------------------------------------------------
+\endverbatim \n
+
+\page ENCODERBEHAVIOUR Encoder Behaviour
+
+\section BEHAVIOUR_BANDWIDTH Bandwidth
+
+The FDK AAC encoder usually does not use the full frequency range of the input signal, but restricts the bandwidth
+according to certain library-internal settings. They can be changed in the table "bandWidthTable" in the
+file bandwidth.cpp (if available), or via command-line argument "-w" (see chapter \ref CommandLineUsage).
+
+However it is not recommended to change these settings, because they are based on numerious listening
+tests and careful tweaks to ensure the best overall encoding quality.
+
+Theoretically a signal of for example 48 kHz can contain frequencies up to 24 kHz, but to use this full range
+in an audio encoder usually does not make sense. Usually the encoder has a very limited amount of
+bits to spend (typically 128 kbit/s for stereo 48 kHz content) and to allow full range bandwidth would
+waste a lot of these bits for frequencies the human ear is hardly able to perceive anyway, if at all. Hence it
+is wise to use the available bits for the really important frequency range and just skip the rest.
+At lower bitrates (e. g. <= 80 kbit/s for stereo 48 kHz content) the encoder will choose an even smaller
+bandwidth, because an encoded signal with smaller bandwidth and hence less artifacts sounds better than a signal
+with higher bandwidth but then more coding artefacts across all frequencies. These artefacts would occur if
+small bitrates and high bandwidths are chosen because the available bits are just not enough to encode all
+frequencies well.
+
+Unfortunately some people evaluate encoding quality based on possible bandwidth as well, but it is a two-sided
+sword considering the trade-off described above.
+
+Another aspect is workload consumption. The higher the allowed bandwidth, the more frequency lines have to be
+processed, which in turn increases the workload.
+
+\section FRAMESIZES_AND_BIT_RESERVOIR Frame Sizes & Bit Reservoir
+
+For AAC there is a difference between constant bit rate and constant frame
+length due to the so-called bit reservoir technique, which allows the encoder to use less
+bits in an AAC frame for those audio signal sections which are easy to encode,
+and then spend them at a later point in
+time for more complex audio sections. The extent to which this "bit exchange"
+is done is limited to allow for reliable and relatively low delay real time
+streaming.
+Over a longer period in time the bitrate will be constant in the AAC constant
+bitrate mode, e.g. for ISDN transmission. This means that in AAC each bitstream
+frame will in general have a different length in bytes but over time it
+will reach the target bitrate. One could also make an MPEG compliant
+AAC encoder which always produces constant length packages for each AAC frame,
+but the audio quality would be considerably worse since the bit reservoir
+technique would have to be switched off completely. A higher bit rate would have
+to be used to get the same audio quality as with an enabled bit reservoir.
+
+The maximum AAC frame length, regardless of the available bit reservoir, is defined
+as 6144 bits per channel.
+
+For mp3 by the way, the same bit reservoir technique exists, but there each bit
+stream frame has a constant length for a given bit rate (ignoring the
+padding byte). In mp3 there is a so-called "back pointer" which tells
+the decoder which bits belong to the current mp3 frame - and in general some or
+many bits have been transmitted in an earlier mp3 frame. Basically this leads to
+the same "bit exchange between mp3 frames" as in AAC but with virtually constant
+length frames.
+
+This variable frame length at "constant bit rate" is not something special
+in this Fraunhofer IIS AAC encoder. AAC has been designed in that way.
+
+\subsection BEHAVIOUR_ESTIM_AVG_FRAMESIZES Estimating Average Frame Sizes
+
+A HE-AAC v1 or v2 audio frame contains 2048 PCM samples per channel (there is
+also one mode with 1920 samples per channel but this is only for special purposes
+such as DAB+ digital radio).
+
+The number of HE-AAC frames \f$N\_FRAMES\f$ per second at 44.1 kHz is:
+
+\f[
+N\_FRAMES = 44100 / 2048 = 21.5332
+\f]
+
+At a bit rate of 8 kbps the average number of bits per frame \f$N\_BITS\_PER\_FRAME\f$ is:
+
+\f[
+N\_BITS\_PER\_FRAME = 8000 / 21.5332 = 371.52
+\f]
+
+which is about 46.44 bytes per encoded frame.
+
+At a bit rate of 32 kbps, which is quite high for single channel HE-AAC v1, it is:
+
+\f[
+N\_BITS\_PER\_FRAME = 32000 / 21.5332 = 1486
+\f]
+
+which is about 185.76 bytes per encoded frame.
+
+These bits/frame figures are average figures where each AAC frame generally has a different
+size in bytes. To calculate the same for AAC-LC just use 1024 instead of 2048 PCM samples per
+frame and channel.
+For AAC-LD/ELD it is either 480 or 512 PCM samples per frame and channel.
+
+
+\section BEHAVIOUR_TOOLS Encoder Tools
+
+The AAC encoder supports TNS, PNS, MS, Intensity and activates these tools depending on the audio signal and
+the encoder configuration (i.e. bitrate or AOT). It is not required to configure these tools manually.
+
+PNS improves encoding quality only for certain bitrates. Therefore it makes sense to activate PNS only for
+these bitrates and save the processing power required for PNS (about 10 % of the encoder) when using other
+bitrates. This is done automatically inside the encoder library. PNS is disabled inside the encoder library if
+an MPEG-2 AOT is choosen since PNS is an MPEG-4 AAC feature.
+
+If SBR is activated, the encoder automatically deactivates PNS internally. If TNS is disabled but PNS is allowed,
+the encoder deactivates PNS calculation internally.
+
+
+*/
+
+#ifndef _AAC_ENC_LIB_H_
+#define _AAC_ENC_LIB_H_
+
+#include "machine_type.h"
+#include "FDK_audio.h"
+
+
+/**
+ * AAC encoder error codes.
+ */
+typedef enum {
+ AACENC_OK = 0x0000, /*!< No error happened. All fine. */
+
+ AACENC_INVALID_HANDLE = 0x0020, /*!< Handle passed to function call was invalid. */
+ AACENC_MEMORY_ERROR = 0x0021, /*!< Memory allocation failed. */
+ AACENC_UNSUPPORTED_PARAMETER = 0x0022, /*!< Parameter not available. */
+ AACENC_INVALID_CONFIG = 0x0023, /*!< Configuration not provided. */
+
+ AACENC_INIT_ERROR = 0x0040, /*!< General initialization error. */
+ AACENC_INIT_AAC_ERROR = 0x0041, /*!< AAC library initialization error. */
+ AACENC_INIT_SBR_ERROR = 0x0042, /*!< SBR library initialization error. */
+ AACENC_INIT_TP_ERROR = 0x0043, /*!< Transport library initialization error. */
+ AACENC_INIT_META_ERROR = 0x0044, /*!< Meta data library initialization error. */
+
+ AACENC_ENCODE_ERROR = 0x0060, /*!< The encoding process was interrupted by an unexpected error. */
+
+ AACENC_ENCODE_EOF = 0x0080 /*!< End of file reached. */
+
+} AACENC_ERROR;
+
+
+/**
+ * AAC encoder buffer descriptors identifier.
+ * This identifier are used within buffer descriptors AACENC_BufDesc::bufferIdentifiers.
+ */
+typedef enum {
+ /* Input buffer identifier. */
+ IN_AUDIO_DATA = 0, /*!< Audio input buffer, interleaved INT_PCM samples. */
+ IN_ANCILLRY_DATA = 1, /*!< Ancillary data to be embedded into bitstream. */
+ IN_METADATA_SETUP = 2, /*!< Setup structure for embedding meta data. */
+
+ /* Output buffer identifier. */
+ OUT_BITSTREAM_DATA = 3, /*!< Buffer holds bitstream output data. */
+ OUT_AU_SIZES = 4 /*!< Buffer contains sizes of each access unit. This information
+ is necessary for superframing. */
+
+} AACENC_BufferIdentifier;
+
+
+/**
+ * AAC encoder handle.
+ */
+typedef struct AACENCODER *HANDLE_AACENCODER;
+
+
+/**
+ * Provides some info about the encoder configuration.
+ */
+typedef struct {
+
+ UINT maxOutBufBytes; /*!< Maximum number of encoder bitstream bytes within one frame.
+ Size depends on maximum number of supported channels in encoder instance.
+ For superframing (as used for example in DAB+), size has to be a multiple accordingly. */
+
+ UINT maxAncBytes; /*!< Maximum number of ancillary data bytes which can be inserted into
+ bitstream within one frame. */
+
+ UINT inBufFillLevel; /*!< Internal input buffer fill level in samples per channel. This parameter
+ will automatically be cleared if samplingrate or channel(Mode/Order) changes. */
+
+ UINT inputChannels; /*!< Number of input channels expected in encoding process. */
+
+ UINT frameLength; /*!< Amount of input audio samples consumed each frame per channel, depending
+ on audio object type configuration. */
+
+ UINT encoderDelay; /*!< Codec delay in PCM samples/channel. Depends on framelength and AOT. Does not
+ include framing delay for filling up encoder PCM input buffer. */
+
+ UCHAR confBuf[64]; /*!< Configuration buffer in binary format as an AudioSpecificConfig
+ or StreamMuxConfig according to the selected transport type. */
+
+ UINT confSize; /*!< Number of valid bytes in confBuf. */
+
+} AACENC_InfoStruct;
+
+
+/**
+ * Describes the input and output buffers for an aacEncEncode() call.
+ */
+typedef struct {
+ INT numBufs; /*!< Number of buffers. */
+ void **bufs; /*!< Pointer to vector containing buffer addresses. */
+ INT *bufferIdentifiers; /*!< Identifier of each buffer element. See ::AACENC_BufferIdentifier. */
+ INT *bufSizes; /*!< Size of each buffer in 8-bit bytes. */
+ INT *bufElSizes; /*!< Size of each buffer element in bytes. */
+
+} AACENC_BufDesc;
+
+
+/**
+ * Defines the input arguments for an aacEncEncode() call.
+ */
+typedef struct {
+ INT numInSamples; /*!< Number of valid input audio samples (multiple of input channels). */
+ INT numAncBytes; /*!< Number of ancillary data bytes to be encoded. */
+
+} AACENC_InArgs;
+
+
+/**
+ * Defines the output arguments for an aacEncEncode() call.
+ */
+typedef struct {
+ INT numOutBytes; /*!< Number of valid bitstream bytes generated during aacEncEncode(). */
+ INT numInSamples; /*!< Number of input audio samples consumed by the encoder. */
+ INT numAncBytes; /*!< Number of ancillary data bytes consumed by the encoder. */
+
+} AACENC_OutArgs;
+
+
+/**
+ * Meta Data Compression Profiles.
+ */
+typedef enum {
+ AACENC_METADATA_DRC_NONE = 0, /*!< None. */
+ AACENC_METADATA_DRC_FILMSTANDARD = 1, /*!< Film standard. */
+ AACENC_METADATA_DRC_FILMLIGHT = 2, /*!< Film light. */
+ AACENC_METADATA_DRC_MUSICSTANDARD = 3, /*!< Music standard. */
+ AACENC_METADATA_DRC_MUSICLIGHT = 4, /*!< Music light. */
+ AACENC_METADATA_DRC_SPEECH = 5 /*!< Speech. */
+
+} AACENC_METADATA_DRC_PROFILE;
+
+
+/**
+ * Meta Data setup structure.
+ */
+typedef struct {
+
+ AACENC_METADATA_DRC_PROFILE drc_profile; /*!< MPEG DRC compression profile. See ::AACENC_METADATA_DRC_PROFILE. */
+ AACENC_METADATA_DRC_PROFILE comp_profile; /*!< ETSI heavy compression profile. See ::AACENC_METADATA_DRC_PROFILE. */
+
+ INT drc_TargetRefLevel; /*!< Used to define expected level to:
+ Scaled with 16 bit. x*2^16. */
+ INT comp_TargetRefLevel; /*!< Adjust limiter to avoid overload.
+ Scaled with 16 bit. x*2^16. */
+
+ INT prog_ref_level_present; /*!< Flag, if prog_ref_level is present */
+ INT prog_ref_level; /*!< Programme Reference Level = Dialogue Level:
+ -31.75dB .. 0 dB ; stepsize: 0.25dB
+ Scaled with 16 bit. x*2^16.*/
+
+ UCHAR PCE_mixdown_idx_present; /*!< Flag, if dmx-idx should be written in programme config element */
+ UCHAR ETSI_DmxLvl_present; /*!< Flag, if dmx-lvl should be written in ETSI-ancData */
+
+ SCHAR centerMixLevel; /*!< Center downmix level (0...7, according to table) */
+ SCHAR surroundMixLevel; /*!< Surround downmix level (0...7, according to table) */
+
+ UCHAR dolbySurroundMode; /*!< Indication for Dolby Surround Encoding Mode.
+ - 0: Dolby Surround mode not indicated
+ - 1: 2-ch audio part is not Dolby surround encoded
+ - 2: 2-ch audio part is Dolby surround encoded */
+} AACENC_MetaData;
+
+
+/**
+ * AAC encoder control flags.
+ *
+ * In interaction with the ::AACENC_CONTROL_STATE parameter it is possible to get information about the internal
+ * initialization process. It is also possible to overwrite the internal state from extern when necessary.
+ */
+typedef enum
+{
+ AACENC_INIT_NONE = 0x0000, /*!< Do not trigger initialization. */
+ AACENC_INIT_CONFIG = 0x0001, /*!< Initialize all encoder modules configuration. */
+ AACENC_INIT_STATES = 0x0002, /*!< Reset all encoder modules history buffer. */
+ AACENC_INIT_TRANSPORT = 0x1000, /*!< Initialize transport lib with new parameters. */
+ AACENC_RESET_INBUFFER = 0x2000, /*!< Reset fill level of internal input buffer. */
+ AACENC_INIT_ALL = 0xFFFF /*!< Initialize all. */
+}
+AACENC_CTRLFLAGS;
+
+
+/**
+ * \brief AAC encoder setting parameters.
+ *
+ * Use aacEncoder_SetParam() function to configure, or use aacEncoder_GetParam() function to read
+ * the internal status of the following parameters.
+ */
+typedef enum
+{
+ AACENC_AOT = 0x0100, /*!< Audio object type. See ::AUDIO_OBJECT_TYPE in FDK_audio.h.
+ - 2: MPEG-4 AAC Low Complexity.
+ - 5: MPEG-4 AAC Low Complexity with Spectral Band Replication (HE-AAC).
+ - 29: MPEG-4 AAC Low Complexity with Spectral Band Replication and Parametric Stereo (HE-AAC v2).
+ This configuration can be used only with stereo input audio data.
+ - 23: MPEG-4 AAC Low-Delay.
+ - 39: MPEG-4 AAC Enhanced Low-Delay. Since there is no ::AUDIO_OBJECT_TYPE for ELD in
+ combination with SBR defined, enable SBR explicitely by ::AACENC_SBR_MODE parameter.
+ - 129: MPEG-2 AAC Low Complexity.
+ - 132: MPEG-2 AAC Low Complexity with Spectral Band Replication (HE-AAC).
+ - 156: MPEG-2 AAC Low Complexity with Spectral Band Replication and Parametric Stereo (HE-AAC v2).
+ This configuration can be used only with stereo input audio data. */
+
+ AACENC_BITRATE = 0x0101, /*!< Total encoder bitrate. This parameter is mandatory and interacts with ::AACENC_BITRATEMODE.
+ - CBR: Bitrate in bits/second.
+ See \ref suppBitrates for details. */
+
+ AACENC_BITRATEMODE = 0x0102, /*!< Bitrate mode. Configuration can be different kind of bitrate configurations:
+ - 0: Constant bitrate, use bitrate according to ::AACENC_BITRATE. (default)
+ Within none LD/ELD ::AUDIO_OBJECT_TYPE, the CBR mode makes use of full allowed bitreservoir.
+ In contrast, at Low-Delay ::AUDIO_OBJECT_TYPE the bitreservoir is kept very small.
+ - 8: LD/ELD full bitreservoir for packet based transmission. */
+
+ AACENC_SAMPLERATE = 0x0103, /*!< Audio input data sampling rate. Encoder supports following sampling rates:
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 */
+
+ AACENC_SBR_MODE = 0x0104, /*!< Configure SBR independently of the chosen Audio Object Type ::AUDIO_OBJECT_TYPE:.
+ This parameter is only available for ELD.
+ - 0: Disable Spectral Band Replication.
+ - 1: Enable Spectral Band Replication. */
+
+ AACENC_GRANULE_LENGTH = 0x0105, /*!< Core encoder (AAC) audio frame length in samples:
+ - 1024: Default configuration.
+ - 512: Optional length in LD/ELD configuration.
+ - 480: Default LD/ELD configuration. */
+
+ AACENC_CHANNELMODE = 0x0106, /*!< Set explicit channel mode. Channel mode must match with number of input channels.
+ - 1-6: MPEG channel modes supported, see ::CHANNEL_MODE in FDK_audio.h. */
+
+ AACENC_CHANNELORDER = 0x0107, /*!< Input audio data channel ordering scheme:
+ - 0: MPEG channel ordering (e. g. 5.1: C, L, R, SL, SR, LFE). (default)
+ - 1: WAVE file format channel ordering (e. g. 5.1: L, R, C, LFE, SL, SR). */
+
+ AACENC_AFTERBURNER = 0x0200, /*!< This parameter controls the use of the afterburner feature.
+ The afterburner is a type of analysis by synthesis algorithm which increases the
+ audio quality but also the required processing power. It is recommended to always
+ activate this if additional memory consumption and processing power consumption
+ is not a problem. If increased MHz and memory consumption are an issue then the MHz
+ and memory cost of this optional module need to be evaluated against the improvement
+ in audio quality on a case by case basis.
+ - 0: Disable afterburner (default).
+ - 1: Enable afterburner. */
+
+ AACENC_BANDWIDTH = 0x0203, /*!< Core encoder audio bandwidth:
+ - 0: Determine bandwidth internally (default, see chapter \ref BEHAVIOUR_BANDWIDTH).
+ - 1 to fs/2: Frequency bandwidth in Hertz. (Experts only, better do not
+ touch this value to avoid degraded audio quality) */
+
+ AACENC_TRANSMUX = 0x0300, /*!< Transport type to be used. See ::TRANSPORT_TYPE in FDK_audio.h. Following
+ types can be configured in encoder library:
+ - 0: raw access units
+ - 1: ADIF bitstream format
+ - 2: ADTS bitstream format
+ - 6: Audio Mux Elements (LATM) with muxConfigPresent = 1
+ - 7: Audio Mux Elements (LATM) with muxConfigPresent = 0, out of band StreamMuxConfig
+ - 10: Audio Sync Stream (LOAS) */
+
+ AACENC_HEADER_PERIOD = 0x0301, /*!< Frame count period for sending in-band configuration buffers within LATM/LOAS
+ transport layer. Additionally this parameter configures the PCE repetition period
+ in raw_data_block(). See \ref encPCE.
+ - 0xFF: auto-mode default 10 for TT_MP4_ADTS, TT_MP4_LOAS and TT_MP4_LATM_MCP1, otherwise 0.
+ - n: Frame count period. */
+
+ AACENC_SIGNALING_MODE = 0x0302, /*!< Signaling mode of the extension AOT:
+ - 0: Implicit backward compatible signaling. (default)
+ - 1: Explicit SBR and implicit PS signaling.
+ - 2: Explicit hierarchical signaling.
+
+ The use of backward-compatible implicit signaling is recommended if the user specically
+ aims at preserving compatibility with decoders only capable of decoding AAC-LC. Otherwise
+ use non-backward-compatible explicit signaling.
+ Bitstream formats ADTS and ADIF can only do implicit signaling. */
+
+ AACENC_TPSUBFRAMES = 0x0303, /*!< Number of sub frames in a transport frame for LOAS/LATM or ADTS (default 1).
+ - ADTS: Maximum number of sub frames restricted to 4.
+ - LOAS/LATM: Maximum number of sub frames restricted to 2.*/
+
+ AACENC_PROTECTION = 0x0306, /*!< Configure protection in tranpsort layer:
+ - 0: No protection. (default)
+ - 1: CRC active for ADTS bitstream format. */
+
+ AACENC_ANCILLARY_BITRATE = 0x0500, /*!< Constant ancillary data bitrate in bits/second.
+ - 0: Either no ancillary data or insert exact number of bytes, denoted via
+ input parameter, numAncBytes in AACENC_InArgs.
+ - else: Insert ancillary data with specified bitrate. */
+
+ AACENC_METADATA_MODE = 0x0600, /*!< Configure Meta Data. See ::AACENC_MetaData for further details:
+ - 0: Do not embed any metadata.
+ - 1: Embed MPEG defined metadata only.
+ - 2: Embed all metadata. */
+
+ AACENC_CONTROL_STATE = 0xFF00, /*!< There is an automatic process which internally reconfigures the encoder instance
+ when a configuration parameter changed or an error occured. This paramerter allows
+ overwriting or getting the control status of this process. See ::AACENC_CTRLFLAGS. */
+
+ AACENC_NONE = 0xFFFF /*!< ------ */
+
+} AACENC_PARAM;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Open an instance of the encoder.
+ *
+ * Allocate memory for an encoder instance with a functional range denoted by the function parameters.
+ * Preinitialize encoder instance with default configuration.
+ *
+ * \param phAacEncoder A pointer to an encoder handle. Initialized on return.
+ * \param encModules Specify encoder modules to be supported in this encoder instance:
+ * - 0x0: Allocate memory for all available encoder modules.
+ * - else: Select memory allocation regarding encoder modules. Following flags are possible and can be combined.
+ * - 0x01: AAC module.
+ * - 0x02: SBR module.
+ * - 0x04: PS module.
+ * - 0x10: Metadata module.
+ * - example: (0x01|0x02|0x04|0x10) allocates all modules and is equivalent to default configuration denotet by 0x0.
+ * \param maxChannels Number of channels to be allocated. This parameter can be used in different ways:
+ * - 0: Allocate maximum number of AAC and SBR channels as supported by the library.
+ * - nChannels: Use same maximum number of channels for allocating memory in AAC and SBR module.
+ * - nChannels | (nSbrCh<<8): Number of SBR channels can be different to AAC channels to save data memory.
+ *
+ * \return
+ * - AACENC_OK, on succes.
+ * - AACENC_INVALID_HANDLE, AACENC_MEMORY_ERROR, AACENC_INVALID_CONFIG, on failure.
+ */
+AACENC_ERROR aacEncOpen(
+ HANDLE_AACENCODER *phAacEncoder,
+ const UINT encModules,
+ const UINT maxChannels
+ );
+
+
+/**
+ * \brief Close the encoder instance.
+ *
+ * Deallocate encoder instance and free whole memory.
+ *
+ * \param phAacEncoder Pointer to the encoder handle to be deallocated.
+ *
+ * \return
+ * - AACENC_OK, on success.
+ * - AACENC_INVALID_HANDLE, on failure.
+ */
+AACENC_ERROR aacEncClose(
+ HANDLE_AACENCODER *phAacEncoder
+ );
+
+
+/**
+ * \brief Encode audio data.
+ *
+ * This function is mainly for encoding audio data. In addition the function can be used for an encoder (re)configuration
+ * process.
+ * - PCM input data will be retrieved from external input buffer until the fill level allows encoding a single frame.
+ * This functionality allows an external buffer with reduced size in comparison to the AAC or HE-AAC audio frame length.
+ * - If the value of the input samples argument is zero, just internal reinitialization will be applied if it is
+ * requested.
+ * - At the end of a file the flushing process can be triggerd via setting the value of the input samples argument to -1.
+ * The encoder delay lines are fully flushed when the encoder returns no valid bitstream data AACENC_OutArgs::numOutBytes.
+ * Furthermore the end of file is signaled by the return value AACENC_ENCODE_EOF.
+ * - If an error occured in the previous frame or any of the encoder parameters changed, an internal reinitialization
+ * process will be applied before encoding the incoming audio samples.
+ * - The function can also be used for an independent reconfiguration process without encoding. The first parameter has to be a
+ * valid encoder handle and all other parameters can be set to NULL.
+ * - If the size of the external bitbuffer in outBufDesc is not sufficient for writing the whole bitstream, an internal
+ * error will be the return value and a reconfiguration will be triggered.
+ *
+ * \param hAacEncoder A valid AAC encoder handle.
+ * \param inBufDesc Input buffer descriptor, see AACENC_BufDesc:
+ * - At least one input buffer with audio data is expected.
+ * - Optionally a second input buffer with ancillary data can be fed.
+ * \param outBufDesc Output buffer descriptor, see AACENC_BufDesc:
+ * - Provide one output buffer for the encoded bitstream.
+ * \param inargs Input arguments, see AACENC_InArgs.
+ * \param outargs Output arguments, AACENC_OutArgs.
+ *
+ * \return
+ * - AACENC_OK, on success.
+ * - AACENC_INVALID_HANDLE, AACENC_ENCODE_ERROR, on failure in encoding process.
+ * - AACENC_INVALID_CONFIG, AACENC_INIT_ERROR, AACENC_INIT_AAC_ERROR, AACENC_INIT_SBR_ERROR, AACENC_INIT_TP_ERROR,
+ * AACENC_INIT_META_ERROR, on failure in encoder initialization.
+ * - AACENC_ENCODE_EOF, when flushing fully concluded.
+ */
+AACENC_ERROR aacEncEncode(
+ const HANDLE_AACENCODER hAacEncoder,
+ const AACENC_BufDesc *inBufDesc,
+ const AACENC_BufDesc *outBufDesc,
+ const AACENC_InArgs *inargs,
+ AACENC_OutArgs *outargs
+ );
+
+
+/**
+ * \brief Acquire info about present encoder instance.
+ *
+ * This function retrieves information of the encoder configuration. In addition to informative internal states,
+ * a configuration data block of the current encoder settings will be returned. The format is either Audio Specific Config
+ * in case of Raw Packets transport format or StreamMuxConfig in case of LOAS/LATM transport format. The configuration
+ * data block is binary coded as specified in ISO/IEC 14496-3 (MPEG-4 audio), to be used directly for MPEG-4 File Format
+ * or RFC3016 or RFC3640 applications.
+ *
+ * \param hAacEncoder A valid AAC encoder handle.
+ * \param pInfo Pointer to AACENC_InfoStruct. Filled on return.
+ *
+ * \return
+ * - AACENC_OK, on succes.
+ * - AACENC_INIT_ERROR, on failure.
+ */
+AACENC_ERROR aacEncInfo(
+ const HANDLE_AACENCODER hAacEncoder,
+ AACENC_InfoStruct *pInfo
+ );
+
+
+/**
+ * \brief Set one single AAC encoder parameter.
+ *
+ * This function allows configuration of all encoder parameters specified in ::AACENC_PARAM. Each parameter must be
+ * set with a separate function call. An internal validation of the configuration value range will be done and an
+ * internal reconfiguration will be signaled. The actual configuration adoption is part of the subsequent aacEncEncode() call.
+ *
+ * \param hAacEncoder A valid AAC encoder handle.
+ * \param param Parameter to be set. See ::AACENC_PARAM.
+ * \param value Parameter value. See parameter description in ::AACENC_PARAM.
+ *
+ * \return
+ * - AACENC_OK, on success.
+ * - AACENC_INVALID_HANDLE, AACENC_UNSUPPORTED_PARAMETER, AACENC_INVALID_CONFIG, on failure.
+ */
+AACENC_ERROR aacEncoder_SetParam(
+ const HANDLE_AACENCODER hAacEncoder,
+ const AACENC_PARAM param,
+ const UINT value
+ );
+
+
+/**
+ * \brief Get one single AAC encoder parameter.
+ *
+ * This function is the complement to aacEncoder_SetParam(). After encoder reinitialization with user defined settings,
+ * the internal status can be obtained of each parameter, specified with ::AACENC_PARAM.
+ *
+ * \param hAacEncoder A valid AAC encoder handle.
+ * \param param Parameter to be returned. See ::AACENC_PARAM.
+ *
+ * \return Internal configuration value of specifed parameter ::AACENC_PARAM.
+ */
+UINT aacEncoder_GetParam(
+ const HANDLE_AACENCODER hAacEncoder,
+ const AACENC_PARAM param
+ );
+
+
+/**
+ * \brief Get information about encoder library build.
+ *
+ * Fill a given LIB_INFO structure with library version information.
+ *
+ * \param info Pointer to an allocated LIB_INFO struct.
+ *
+ * \return
+ * - AACENC_OK, on success.
+ * - AACENC_INVALID_HANDLE, AACENC_INIT_ERROR, on failure.
+ */
+AACENC_ERROR aacEncGetLibInfo(
+ LIB_INFO *info
+ );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AAC_ENC_LIB_H_ */
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