aboutsummaryrefslogtreecommitdiffstats
path: root/fdk-aac/libFDK/src/FDK_decorrelate.cpp
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
committerMatthias P. Braendli <matthias.braendli@mpb.li>2019-11-11 11:38:02 +0100
commit0e5af65c467b2423a0b857ae3ad98c91acc1e190 (patch)
treed07f69550d8886271e44fe79c4dcfb299cafbd38 /fdk-aac/libFDK/src/FDK_decorrelate.cpp
parentefe406d9724f959c8bc2a31802559ca6d41fd897 (diff)
downloadODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.gz
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.tar.bz2
ODR-AudioEnc-0e5af65c467b2423a0b857ae3ad98c91acc1e190.zip
Include patched FDK-AAC in the repository
The initial idea was to get the DAB+ patch into upstream, but since that follows the android source releases, there is no place for a custom DAB+ patch there. So instead of having to maintain a patched fdk-aac that has to have the same .so version as the distribution package on which it is installed, we prefer having a separate fdk-aac-dab library to avoid collision. At that point, there's no reason to keep fdk-aac in a separate repository, as odr-audioenc is the only tool that needs DAB+ encoding support. Including it here simplifies installation, and makes it consistent with toolame-dab, also shipped in this repository. DAB+ decoding support (needed by ODR-SourceCompanion, dablin, etisnoop, welle.io and others) can be done using upstream FDK-AAC.
Diffstat (limited to 'fdk-aac/libFDK/src/FDK_decorrelate.cpp')
-rw-r--r--fdk-aac/libFDK/src/FDK_decorrelate.cpp1746
1 files changed, 1746 insertions, 0 deletions
diff --git a/fdk-aac/libFDK/src/FDK_decorrelate.cpp b/fdk-aac/libFDK/src/FDK_decorrelate.cpp
new file mode 100644
index 0000000..c5de79a
--- /dev/null
+++ b/fdk-aac/libFDK/src/FDK_decorrelate.cpp
@@ -0,0 +1,1746 @@
+/* -----------------------------------------------------------------------------
+Software License for The Fraunhofer FDK AAC Codec Library for Android
+
+© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
+Forschung e.V. All rights reserved.
+
+ 1. INTRODUCTION
+The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
+that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
+scheme for digital audio. This FDK AAC Codec software is intended to be used on
+a wide variety of Android devices.
+
+AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
+general perceptual audio codecs. AAC-ELD is considered the best-performing
+full-bandwidth communications codec by independent studies and is widely
+deployed. AAC has been standardized by ISO and IEC as part of the MPEG
+specifications.
+
+Patent licenses for necessary patent claims for the FDK AAC Codec (including
+those of Fraunhofer) may be obtained through Via Licensing
+(www.vialicensing.com) or through the respective patent owners individually for
+the purpose of encoding or decoding bit streams in products that are compliant
+with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
+Android devices already license these patent claims through Via Licensing or
+directly from the patent owners, and therefore FDK AAC Codec software may
+already be covered under those patent licenses when it is used for those
+licensed purposes only.
+
+Commercially-licensed AAC software libraries, including floating-point versions
+with enhanced sound quality, are also available from Fraunhofer. Users are
+encouraged to check the Fraunhofer website for additional applications
+information and documentation.
+
+2. COPYRIGHT LICENSE
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted without payment of copyright license fees provided that you
+satisfy the following conditions:
+
+You must retain the complete text of this software license in redistributions of
+the FDK AAC Codec or your modifications thereto in source code form.
+
+You must retain the complete text of this software license in the documentation
+and/or other materials provided with redistributions of the FDK AAC Codec or
+your modifications thereto in binary form. You must make available free of
+charge copies of the complete source code of the FDK AAC Codec and your
+modifications thereto to recipients of copies in binary form.
+
+The name of Fraunhofer may not be used to endorse or promote products derived
+from this library without prior written permission.
+
+You may not charge copyright license fees for anyone to use, copy or distribute
+the FDK AAC Codec software or your modifications thereto.
+
+Your modified versions of the FDK AAC Codec must carry prominent notices stating
+that you changed the software and the date of any change. For modified versions
+of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
+must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
+AAC Codec Library for Android."
+
+3. NO PATENT LICENSE
+
+NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
+limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
+Fraunhofer provides no warranty of patent non-infringement with respect to this
+software.
+
+You may use this FDK AAC Codec software or modifications thereto only for
+purposes that are authorized by appropriate patent licenses.
+
+4. DISCLAIMER
+
+This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
+holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+including but not limited to the implied warranties of merchantability and
+fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
+or consequential damages, including but not limited to procurement of substitute
+goods or services; loss of use, data, or profits, or business interruption,
+however caused and on any theory of liability, whether in contract, strict
+liability, or tort (including negligence), arising in any way out of the use of
+this software, even if advised of the possibility of such damage.
+
+5. CONTACT INFORMATION
+
+Fraunhofer Institute for Integrated Circuits IIS
+Attention: Audio and Multimedia Departments - FDK AAC LL
+Am Wolfsmantel 33
+91058 Erlangen, Germany
+
+www.iis.fraunhofer.de/amm
+amm-info@iis.fraunhofer.de
+----------------------------------------------------------------------------- */
+
+/******************* Library for basic calculation routines ********************
+
+ Author(s): Markus Lohwasser
+
+ Description: FDK Tools Decorrelator
+
+*******************************************************************************/
+
+#include "FDK_decorrelate.h"
+
+#define PC_NUM_BANDS (8)
+#define PC_NUM_HYB_BANDS (PC_NUM_BANDS - 3 + 10)
+
+#define DUCK_ALPHA (0.8f)
+#define DUCK_GAMMA (1.5f)
+#define ABS_THR (1e-9f * 32768 * 32768)
+#define ABS_THR_FDK ((FIXP_DBL)1)
+
+#define DECORR_ZERO_PADDING 0
+
+#define DECORR_FILTER_ORDER_BAND_0_MPS (20)
+#define DECORR_FILTER_ORDER_BAND_1_MPS (15)
+#define DECORR_FILTER_ORDER_BAND_2_MPS (6)
+#define DECORR_FILTER_ORDER_BAND_3_MPS (3)
+
+#define DECORR_FILTER_ORDER_BAND_0_USAC (10)
+#define DECORR_FILTER_ORDER_BAND_1_USAC (8)
+#define DECORR_FILTER_ORDER_BAND_2_USAC (3)
+#define DECORR_FILTER_ORDER_BAND_3_USAC (2)
+
+#define DECORR_FILTER_ORDER_BAND_0_LD (0)
+#define DECORR_FILTER_ORDER_BAND_1_LD (DECORR_FILTER_ORDER_BAND_1_MPS)
+#define DECORR_FILTER_ORDER_BAND_2_LD (DECORR_FILTER_ORDER_BAND_2_MPS)
+#define DECORR_FILTER_ORDER_BAND_3_LD (DECORR_FILTER_ORDER_BAND_3_MPS)
+
+#define MAX_DECORR_SEED_MPS \
+ (5) /* 4 is worst case for 7272 mode for low power */
+ /* 5 is worst case for 7271 and 7272 mode for high quality */
+#define MAX_DECORR_SEED_USAC (1)
+#define MAX_DECORR_SEED_LD (4)
+
+#define DECORR_FILTER_ORDER_PS (12)
+#define NUM_DECORR_CONFIGS \
+ (3) /* different configs defined by bsDecorrConfig bitstream field */
+
+/* REV_bandOffset_... tables map (hybrid) bands to the corresponding reverb
+ bands. Within each reverb band the same processing is applied. Instead of QMF
+ split frequencies the corresponding hybrid band offsets are stored directly
+ */
+static const UCHAR REV_bandOffset_MPS_HQ[NUM_DECORR_CONFIGS][(4)] = {
+ {8, 21, 30, 71}, {8, 56, 71, 71}, {0, 21, 71, 71}};
+/* REV_bandOffset_USAC[] are equivalent to REV_bandOffset_MPS_HQ */
+static const UCHAR REV_bandOffset_PS_HQ[(4)] = {30, 42, 71, 71};
+static const UCHAR REV_bandOffset_PS_LP[(4)] = {14, 42, 71, 71};
+static const UCHAR REV_bandOffset_LD[NUM_DECORR_CONFIGS][(4)] = {
+ {0, 14, 23, 64}, {0, 49, 64, 64}, {0, 14, 64, 64}};
+
+/* REV_delay_... tables define the number of delay elements within each reverb
+ * band */
+/* REV_filterOrder_... tables define the filter order within each reverb band */
+static const UCHAR REV_delay_MPS[(4)] = {8, 7, 2, 1};
+static const SCHAR REV_filterOrder_MPS[(4)] = {
+ DECORR_FILTER_ORDER_BAND_0_MPS, DECORR_FILTER_ORDER_BAND_1_MPS,
+ DECORR_FILTER_ORDER_BAND_2_MPS, DECORR_FILTER_ORDER_BAND_3_MPS};
+static const UCHAR REV_delay_PS_HQ[(4)] = {2, 14, 1, 0};
+static const UCHAR REV_delay_PS_LP[(4)] = {8, 14, 1, 0};
+static const SCHAR REV_filterOrder_PS[(4)] = {DECORR_FILTER_ORDER_PS, -1, -1,
+ -1};
+static const UCHAR REV_delay_USAC[(4)] = {11, 10, 5, 2};
+static const SCHAR REV_filterOrder_USAC[(4)] = {
+ DECORR_FILTER_ORDER_BAND_0_USAC, DECORR_FILTER_ORDER_BAND_1_USAC,
+ DECORR_FILTER_ORDER_BAND_2_USAC, DECORR_FILTER_ORDER_BAND_3_USAC};
+
+/* REV_filtType_... tables define the type of processing (filtering with
+ different properties or pure delay) done in each reverb band. This is mapped
+ to specialized routines. */
+static const REVBAND_FILT_TYPE REV_filtType_MPS[(4)] = {
+ COMMON_REAL, COMMON_REAL, COMMON_REAL, COMMON_REAL};
+
+static const REVBAND_FILT_TYPE REV_filtType_PS[(4)] = {INDEP_CPLX_PS, DELAY,
+ DELAY, NOT_EXIST};
+
+/* initialization values of ring buffer offsets for the 3 concatenated allpass
+ * filters (PS type decorrelator). */
+static const UCHAR stateBufferOffsetInit[(3)] = {0, 6, 14};
+
+static const REVBAND_FILT_TYPE REV_filtType_LD[(4)] = {
+ NOT_EXIST, COMMON_REAL, COMMON_REAL, COMMON_REAL};
+
+/*** mapping of hybrid bands to processing (/parameter?) bands ***/
+/* table for PS decorr running in legacy PS decoder. */
+static const UCHAR kernels_20_to_71_PS[(71) + 1] = {
+ 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 14,
+ 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19};
+
+/*** mapping of processing (/parameter?) bands to hybrid bands ***/
+/* table for PS decorr running in legacy PS decoder. */
+static const UCHAR kernels_20_to_71_offset_PS[(20) + 1] = {
+ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 21, 25, 30, 42, 71};
+
+static const UCHAR kernels_28_to_71[(71) + 1] = {
+ 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23,
+ 23, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26,
+ 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27};
+
+static const UCHAR kernels_28_to_71_offset[(28) + 1] = {
+ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 21, 23, 25, 27, 30, 33, 37, 42, 48, 55, 71};
+
+/* LD-MPS defined in SAOC standart (mapping qmf -> param bands)*/
+static const UCHAR kernels_23_to_64[(64) + 1] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 13, 13, 14,
+ 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
+ 19, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+};
+
+static const UCHAR kernels_23_to_64_offset[(23) + 1] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 14, 16, 18, 20, 23, 26, 30, 35, 41, 48, 64};
+
+static inline int SpatialDecGetProcessingBand(int hybridBand,
+ const UCHAR *tab) {
+ return tab[hybridBand];
+}
+
+/* helper inline function */
+static inline int SpatialDecGetQmfBand(int paramBand, const UCHAR *tab) {
+ return (int)tab[paramBand];
+}
+
+#define DUCKER_MAX_NRG_SCALE (24)
+#define DUCKER_HEADROOM_BITS (3)
+
+#define FILTER_SF (2)
+
+#ifdef ARCH_PREFER_MULT_32x32
+#define FIXP_DUCK_GAIN FIXP_DBL
+#define FX_DBL2FX_DUCK_GAIN
+#define FL2FXCONST_DUCK FL2FXCONST_DBL
+#else
+#define FIXP_DUCK_GAIN FIXP_SGL
+#define FX_DBL2FX_DUCK_GAIN FX_DBL2FX_SGL
+#define FL2FXCONST_DUCK FL2FXCONST_SGL
+#endif
+#define PS_DUCK_PEAK_DECAY_FACTOR (0.765928338364649f)
+#define PS_DUCK_FILTER_COEFF (0.25f)
+#define DUCK_ALPHA_FDK FL2FXCONST_DUCK(DUCK_ALPHA)
+#define DUCK_ONE_MINUS_ALPHA_X4_FDK FL2FXCONST_DUCK(4.0f * (1.0f - DUCK_ALPHA))
+#define DUCK_GAMMA_FDK FL2FXCONST_DUCK(DUCK_GAMMA / 2)
+#define PS_DUCK_PEAK_DECAY_FACTOR_FDK FL2FXCONST_DUCK(PS_DUCK_PEAK_DECAY_FACTOR)
+#define PS_DUCK_FILTER_COEFF_FDK FL2FXCONST_DUCK(PS_DUCK_FILTER_COEFF)
+RAM_ALIGN
+const FIXP_STP DecorrPsCoeffsCplx[][4] = {
+ {STCP(0x5d6940eb, 0x5783153e), STCP(0xadcd41a8, 0x0e0373ed),
+ STCP(0xbad41f3e, 0x14fba045), STCP(0xc1eb6694, 0x0883227d)},
+ {STCP(0x5d6940eb, 0xa87ceac2), STCP(0xadcd41a8, 0xf1fc8c13),
+ STCP(0xbad41f3e, 0xeb045fbb), STCP(0xc1eb6694, 0xf77cdd83)},
+ {STCP(0xaec24162, 0x62e9d75b), STCP(0xb7169316, 0x28751048),
+ STCP(0xd224c0cc, 0x37e05050), STCP(0xc680864f, 0x18e88cba)},
+ {STCP(0xaec24162, 0x9d1628a5), STCP(0xb7169316, 0xd78aefb8),
+ STCP(0xd224c0cc, 0xc81fafb0), STCP(0xc680864f, 0xe7177346)},
+ {STCP(0x98012341, 0x4aa00ed1), STCP(0xc89ca1b2, 0xc1ab6bff),
+ STCP(0xf8ea394e, 0xb8106bf4), STCP(0xcf542d73, 0xd888b99b)},
+ {STCP(0x43b137b3, 0x6ca2ca40), STCP(0xe0649cc4, 0xb2d69cca),
+ STCP(0x22130c21, 0xc0405382), STCP(0xdbbf8fba, 0xcce3c7cc)},
+ {STCP(0x28fc4d71, 0x86bd3b87), STCP(0x09ccfeb9, 0xad319baf),
+ STCP(0x46e51f02, 0xf1e5ea55), STCP(0xf30d5e34, 0xc2b0e335)},
+ {STCP(0xc798f756, 0x72e73c7d), STCP(0x3b6c3c1e, 0xc580dc72),
+ STCP(0x2828a6ba, 0x3c1a14fb), STCP(0x14b733bb, 0xc4dcaae1)},
+ {STCP(0x46dcadd3, 0x956795c7), STCP(0x52f32fae, 0xf78048cd),
+ STCP(0xd7d75946, 0x3c1a14fb), STCP(0x306017cb, 0xd82c0a75)},
+ {STCP(0xabe197de, 0x607a675e), STCP(0x460cef6e, 0x2d3b264e),
+ STCP(0xb91ae0fe, 0xf1e5ea55), STCP(0x3e03e5e0, 0xf706590e)},
+ {STCP(0xb1b4f509, 0x9abcaf5f), STCP(0xfeb0b4be, 0x535fb8ba),
+ STCP(0x1ba96f8e, 0xbd37e6d8), STCP(0x30f6dbbb, 0x271a0743)},
+ {STCP(0xce75b52a, 0x89f9be61), STCP(0xb26e4dda, 0x101054c5),
+ STCP(0x1a475d2e, 0x3f714b19), STCP(0xf491f154, 0x3a6baf46)},
+ {STCP(0xee8fdfcb, 0x813181fa), STCP(0xe11e1a00, 0xbb9a6039),
+ STCP(0xc3e582f5, 0xe71ab533), STCP(0xc9eb35e2, 0x0ffd212a)},
+ {STCP(0x0fd7d92f, 0x80fbf975), STCP(0x38adccbc, 0xd571bbf4),
+ STCP(0x38c3aefc, 0xe87cc794), STCP(0xdafe8c3d, 0xd9b16100)},
+ {STCP(0x300d9e10, 0x895cc359), STCP(0x32b9843e, 0x2b52adcc),
+ STCP(0xe9ded9f4, 0x356ce0ed), STCP(0x0fdd5ca3, 0xd072932e)},
+ {STCP(0x4d03b4f8, 0x99c2dec3), STCP(0xe2bc8d94, 0x3744e195),
+ STCP(0xeb40ec55, 0xcde9ed22), STCP(0x2e67e231, 0xf893470b)},
+ {STCP(0x64c4deb3, 0xb112790f), STCP(0xc7b32682, 0xf099172d),
+ STCP(0x2ebf44cf, 0x135d014a), STCP(0x1a2bacd5, 0x23334254)},
+ {STCP(0x75b5f9aa, 0xcdb81e14), STCP(0x028d9bb1, 0xc9dc45b9),
+ STCP(0xd497893f, 0x11faeee9), STCP(0xee40ff71, 0x24a91b85)},
+ {STCP(0x7eb1cd81, 0xedc3feec), STCP(0x31491897, 0xf765f6d8),
+ STCP(0x1098dc89, 0xd7ee574e), STCP(0xda6b816d, 0x011f35cf)},
+ {STCP(0x7f1cde01, 0x0f0b7727), STCP(0x118ce49d, 0x2a5ecda4),
+ STCP(0x0f36ca28, 0x24badaa3), STCP(0xef2908a4, 0xe1ee3743)},
+ {STCP(0x76efee25, 0x2f4e8c3a), STCP(0xdde3be2a, 0x17f92215),
+ STCP(0xde9bf36c, 0xf22b4839), STCP(0x1128fc0c, 0xe5c95f5a)},
+ {STCP(0x66b87d65, 0x4c5ede42), STCP(0xe43f351a, 0xe6bf22dc),
+ STCP(0x1e0d3e85, 0xf38d5a9a), STCP(0x1c0f44a3, 0x02c92fe3)},
+ {STCP(0x4f8f36b7, 0x6445680f), STCP(0x10867ea2, 0xe3072740),
+ STCP(0xf4ef6cfa, 0x1ab67076), STCP(0x09562a8a, 0x1742bb8b)},
+ {STCP(0x3304f6ec, 0x7564812a), STCP(0x1be4f1a8, 0x0894d75a),
+ STCP(0xf6517f5b, 0xe8a05d98), STCP(0xf1bb0053, 0x10a78853)},
+ {STCP(0x1307b2c5, 0x7e93d532), STCP(0xfe098e27, 0x18f02a58),
+ STCP(0x1408d459, 0x084c6e44), STCP(0xedafe5bd, 0xfbc15b2e)},
+ {STCP(0xf1c111cd, 0x7f346c97), STCP(0xeb5ca6a0, 0x02efee93),
+ STCP(0xef4df9b6, 0x06ea5be4), STCP(0xfc149289, 0xf0d53ce4)},
+ {STCP(0xd1710001, 0x773b6beb), STCP(0xfa1aeb8c, 0xf06655ff),
+ STCP(0x05884983, 0xf2a4c7c5), STCP(0x094f13df, 0xf79c01bf)},
+ {STCP(0xb446be0b, 0x6732cfca), STCP(0x0a743752, 0xf9220dfa),
+ STCP(0x04263722, 0x0a046a2c), STCP(0x08ced80b, 0x0347e9c2)},
+ {STCP(0x9c3b1202, 0x503018a5), STCP(0x05fcf01a, 0x05cd8529),
+ STCP(0xf95263e2, 0xfd3bdb3f), STCP(0x00c68cf9, 0x0637cb7f)},
+ {STCP(0x8aee2710, 0x33c187ec), STCP(0xfdd253f8, 0x038e09b9),
+ STCP(0x0356ce0f, 0xfe9ded9f), STCP(0xfd6c3054, 0x01c8060a)}};
+
+const FIXP_DECORR DecorrNumeratorReal0_USAC
+ [MAX_DECORR_SEED_USAC][DECORR_FILTER_ORDER_BAND_0_USAC + 1] = {
+ {DECORR(0x05bf4880), DECORR(0x08321c00), DECORR(0xe9315ee0),
+ DECORR(0x07d9dd20), DECORR(0x02224994), DECORR(0x0009d200),
+ DECORR(0xf8a29358), DECORR(0xf4e310d0), DECORR(0xef901fc0),
+ DECORR(0xebda0460), DECORR(0x40000000)}};
+
+const FIXP_DECORR DecorrNumeratorReal1_USAC
+ [MAX_DECORR_SEED_USAC][DECORR_FILTER_ORDER_BAND_1_USAC + 1] = {
+ {DECORR(0xf82f8378), DECORR(0xfef588c2), DECORR(0x02eddbd8),
+ DECORR(0x041c2450), DECORR(0xf7edcd60), DECORR(0x07e29310),
+ DECORR(0xfa4ece48), DECORR(0xed9f8a20), DECORR(0x40000000)}};
+
+/* identical to MPS coeffs for reverb band 3: DecorrNumeratorReal3[0] */
+const FIXP_DECORR
+ DecorrNumeratorReal2_USAC[MAX_DECORR_SEED_USAC]
+ [DECORR_FILTER_ORDER_BAND_2_USAC + 1] = {
+ {DECORR(0x0248e8a8), DECORR(0xfde95838),
+ DECORR(0x084823c0), DECORR(0x40000000)}};
+
+const FIXP_DECORR
+ DecorrNumeratorReal3_USAC[MAX_DECORR_SEED_USAC]
+ [DECORR_FILTER_ORDER_BAND_3_USAC + 1] = {
+ {DECORR(0xff2b020c), DECORR(0x02393830),
+ DECORR(0x40000000)}};
+
+/* const FIXP_DECORR DecorrNumeratorReal0_LD[MAX_DECORR_SEED_LD][] does not
+ * exist */
+
+RAM_ALIGN
+const FIXP_DECORR DecorrNumeratorReal1_LD[MAX_DECORR_SEED_LD]
+ [DECORR_FILTER_ORDER_BAND_1_LD + 1] = {
+ {
+ DECORR(0xf310cb29),
+ DECORR(0x1932d745),
+ DECORR(0x0cc2d917),
+ DECORR(0xddde064e),
+ DECORR(0xf234a626),
+ DECORR(0x198551a6),
+ DECORR(0x17141b6a),
+ DECORR(0xf298803d),
+ DECORR(0xef98be92),
+ DECORR(0x09ea1706),
+ DECORR(0x28fbdff4),
+ DECORR(0x1a869eb9),
+ DECORR(0xdeefe147),
+ DECORR(0xcde2adda),
+ DECORR(0x13ddc619),
+ DECORR(0x40000000),
+ },
+ {
+ DECORR(0x041d7dbf),
+ DECORR(0x01b7309c),
+ DECORR(0xfb599834),
+ DECORR(0x092fc5ed),
+ DECORR(0xf2fd7c25),
+ DECORR(0xdd51e2eb),
+ DECORR(0xf62fe72b),
+ DECORR(0x0b15d588),
+ DECORR(0xf1f091a7),
+ DECORR(0xed1bbbfe),
+ DECORR(0x03526899),
+ DECORR(0x180cb256),
+ DECORR(0xecf1433d),
+ DECORR(0xf626ab95),
+ DECORR(0x197dd27e),
+ DECORR(0x40000000),
+ },
+ {
+ DECORR(0x157a786c),
+ DECORR(0x0028c98c),
+ DECORR(0xf5eff57b),
+ DECORR(0x11f7d04f),
+ DECORR(0xf390d28d),
+ DECORR(0x18947081),
+ DECORR(0xe5dc2319),
+ DECORR(0xf4cc0235),
+ DECORR(0x2394d47f),
+ DECORR(0xe069230e),
+ DECORR(0x03a1a773),
+ DECORR(0xfbc9b092),
+ DECORR(0x15a0173b),
+ DECORR(0x0e9ecdf0),
+ DECORR(0xd309b2c7),
+ DECORR(0x40000000),
+ },
+ {
+ DECORR(0xe0ce703b),
+ DECORR(0xe508b672),
+ DECORR(0xef362398),
+ DECORR(0xffe788ef),
+ DECORR(0x2fda3749),
+ DECORR(0x4671c0c6),
+ DECORR(0x3c003494),
+ DECORR(0x2387707c),
+ DECORR(0xd2107d2e),
+ DECORR(0xb3e47e08),
+ DECORR(0xacd0abca),
+ DECORR(0xc70791df),
+ DECORR(0x0b586e85),
+ DECORR(0x2f11cda7),
+ DECORR(0x3a4a210b),
+ DECORR(0x40000000),
+ },
+};
+
+RAM_ALIGN
+const FIXP_DECORR DecorrNumeratorReal2_LD[MAX_DECORR_SEED_LD]
+ [DECORR_FILTER_ORDER_BAND_2_LD + 1 +
+ DECORR_ZERO_PADDING] = {
+ {
+ DECORR(0xffb4a234),
+ DECORR(0x01ac71a2),
+ DECORR(0xf2bca010),
+ DECORR(0xfe3d7593),
+ DECORR(0x093e9976),
+ DECORR(0xf2c5f3f5),
+ DECORR(0x40000000),
+ },
+ {
+ DECORR(0xe303afb8),
+ DECORR(0xcd70c2bb),
+ DECORR(0xf1e2ad7e),
+ DECORR(0x0c8ffbe2),
+ DECORR(0x21f80abf),
+ DECORR(0x3d08410c),
+ DECORR(0x40000000),
+ },
+ {
+ DECORR(0xe26809d5),
+ DECORR(0x0efbcfa4),
+ DECORR(0x210c1a97),
+ DECORR(0xfe60af4e),
+ DECORR(0xeda01a51),
+ DECORR(0x00faf468),
+ DECORR(0x40000000),
+ },
+ {
+ DECORR(0x1edc5d64),
+ DECORR(0xe5b2e35c),
+ DECORR(0xe94b1c45),
+ DECORR(0x30a6f1e1),
+ DECORR(0xf04e52de),
+ DECORR(0xe30de45a),
+ DECORR(0x40000000),
+ },
+};
+
+RAM_ALIGN
+const FIXP_DECORR DecorrNumeratorReal3_LD[MAX_DECORR_SEED_LD]
+ [DECORR_FILTER_ORDER_BAND_3_LD + 1] = {
+ {
+ DECORR(0x0248e8a7),
+ DECORR(0xfde9583b),
+ DECORR(0x084823bb),
+ DECORR(0x40000000),
+ },
+ {
+ DECORR(0x1db22d0e),
+ DECORR(0xfc773992),
+ DECORR(0x0e819a74),
+ DECORR(0x40000000),
+ },
+ {
+ DECORR(0x0fcb923a),
+ DECORR(0x0154b7ff),
+ DECORR(0xe70cb647),
+ DECORR(0x40000000),
+ },
+ {
+ DECORR(0xe39f559b),
+ DECORR(0xe06dd6ca),
+ DECORR(0x19f71f71),
+ DECORR(0x40000000),
+ },
+};
+
+FIXP_DBL *getAddrDirectSignalMaxVal(HANDLE_DECORR_DEC self) {
+ return &(self->ducker.maxValDirectData);
+}
+
+static INT DecorrFilterInit(DECORR_FILTER_INSTANCE *const self,
+ FIXP_MPS *pStateBufferCplx,
+ FIXP_DBL *pDelayBufferCplx, INT *offsetStateBuffer,
+ INT *offsetDelayBuffer, INT const decorr_seed,
+ INT const reverb_band, INT const useFractDelay,
+ INT const noSampleDelay, INT const filterOrder,
+ FDK_DECORR_TYPE const decorrType) {
+ INT errorCode = 0;
+ switch (decorrType) {
+ case DECORR_USAC:
+ if (useFractDelay) {
+ return 1;
+ } else {
+ FDK_ASSERT(decorr_seed == 0);
+
+ switch (reverb_band) {
+ case 0:
+ self->numeratorReal = DecorrNumeratorReal0_USAC[decorr_seed];
+ break;
+ case 1:
+ self->numeratorReal = DecorrNumeratorReal1_USAC[decorr_seed];
+ break;
+ case 2:
+ self->numeratorReal = DecorrNumeratorReal2_USAC[decorr_seed];
+ break;
+ case 3:
+ self->numeratorReal = DecorrNumeratorReal3_USAC[decorr_seed];
+ break;
+ }
+ }
+ break;
+ case DECORR_LD:
+ FDK_ASSERT(decorr_seed < MAX_DECORR_SEED_LD);
+ switch (reverb_band) {
+ case 0:
+ self->numeratorReal = NULL;
+ break;
+ case 1:
+ self->numeratorReal = DecorrNumeratorReal1_LD[decorr_seed];
+ break;
+ case 2:
+ self->numeratorReal = DecorrNumeratorReal2_LD[decorr_seed];
+ break;
+ case 3:
+ self->numeratorReal = DecorrNumeratorReal3_LD[decorr_seed];
+ break;
+ }
+ break;
+ default:
+ return 1;
+ }
+
+ self->stateCplx = pStateBufferCplx + (*offsetStateBuffer);
+ *offsetStateBuffer += 2 * filterOrder;
+ self->DelayBufferCplx = pDelayBufferCplx + (*offsetDelayBuffer);
+ *offsetDelayBuffer += 2 * noSampleDelay;
+
+ return errorCode;
+}
+
+/*******************************************************************************
+*******************************************************************************/
+static INT DecorrFilterInitPS(DECORR_FILTER_INSTANCE *const self,
+ FIXP_MPS *pStateBufferCplx,
+ FIXP_DBL *pDelayBufferCplx,
+ INT *offsetStateBuffer, INT *offsetDelayBuffer,
+ INT const hybridBand, INT const reverbBand,
+ INT const noSampleDelay) {
+ INT errorCode = 0;
+
+ if (reverbBand == 0) {
+ self->coeffsPacked = DecorrPsCoeffsCplx[hybridBand];
+
+ self->stateCplx = pStateBufferCplx + (*offsetStateBuffer);
+ *offsetStateBuffer += 2 * DECORR_FILTER_ORDER_PS;
+ }
+
+ self->DelayBufferCplx = pDelayBufferCplx + (*offsetDelayBuffer);
+ *offsetDelayBuffer += 2 * noSampleDelay;
+
+ return errorCode;
+}
+
+LNK_SECTION_CODE_L1
+static INT DecorrFilterApplyPASS(DECORR_FILTER_INSTANCE const filter[],
+ FIXP_DBL *dataRealIn, FIXP_DBL *dataImagIn,
+ FIXP_DBL *dataRealOut, FIXP_DBL *dataImagOut,
+ INT start, INT stop,
+ INT reverbBandNoSampleDelay,
+ INT reverbBandDelayBufferIndex) {
+ INT i;
+ INT offset = 2 * reverbBandNoSampleDelay;
+ FIXP_MPS *pDelayBuffer =
+ &filter[start].DelayBufferCplx[reverbBandDelayBufferIndex];
+
+ /* Memory for the delayline has been allocated in a consecutive order, so we
+ can address from filter to filter with a constant length.
+ Be aware that real and imaginary part of the delayline are stored in
+ interleaved order.
+ */
+ if (dataImagIn == NULL) {
+ for (i = start; i < stop; i++) {
+ FIXP_DBL tmp;
+
+ tmp = *pDelayBuffer;
+ *pDelayBuffer = dataRealIn[i];
+ dataRealOut[i] = tmp;
+ pDelayBuffer += offset;
+ }
+ } else {
+ if ((i = stop - start) != 0) {
+ dataRealIn += start;
+ dataImagIn += start;
+ dataRealOut += start;
+ dataImagOut += start;
+#ifdef FUNCTION_DecorrFilterApplyPASS_func1
+ DecorrFilterApplyPASS_func1(i, dataRealIn, dataImagIn, dataRealOut,
+ dataImagOut, pDelayBuffer, offset);
+#else
+ do {
+ FIXP_DBL delay_re, delay_im, real, imag;
+
+ real = *dataRealIn++;
+ imag = *dataImagIn++;
+ delay_re = pDelayBuffer[0];
+ delay_im = pDelayBuffer[1];
+ pDelayBuffer[0] = real;
+ pDelayBuffer[1] = imag;
+ *dataRealOut++ = delay_re;
+ *dataImagOut++ = delay_im;
+ pDelayBuffer += offset;
+ } while (--i != 0);
+#endif
+ }
+ }
+
+ return (INT)0;
+}
+
+#ifndef FUNCTION_DecorrFilterApplyREAL
+LNK_SECTION_CODE_L1
+static INT DecorrFilterApplyREAL(DECORR_FILTER_INSTANCE const filter[],
+ FIXP_DBL *dataRealIn, FIXP_DBL *dataImagIn,
+ FIXP_DBL *dataRealOut, FIXP_DBL *dataImagOut,
+ INT start, INT stop, INT reverbFilterOrder,
+ INT reverbBandNoSampleDelay,
+ INT reverbBandDelayBufferIndex) {
+ INT i, j;
+ FIXP_DBL xReal, xImag, yReal, yImag;
+
+ const FIXP_DECORR *pFilter = filter[start].numeratorReal;
+
+ INT offsetDelayBuffer = (2 * reverbBandNoSampleDelay) - 1;
+ FIXP_MPS *pDelayBuffer =
+ &filter[start].DelayBufferCplx[reverbBandDelayBufferIndex];
+
+ INT offsetStates = 2 * reverbFilterOrder;
+ FIXP_DBL *pStates = filter[start].stateCplx;
+
+ /* Memory for the delayline has been allocated in a consecutive order, so we
+ can address from filter to filter with a constant length. The same is valid
+ for the states.
+ Be aware that real and imaginary part of the delayline and the states are
+ stored in interleaved order.
+ All filter in a reverb band have the same filter coefficients.
+ Exploit symmetry: numeratorReal[i] =
+ denominatorReal[reverbFilterLength-1-i] Do not accumulate the highest
+ states which are always zero.
+ */
+ if (reverbFilterOrder == 2) {
+ FIXP_DECORR nFilt0L, nFilt0H;
+
+ nFilt0L = pFilter[0];
+ nFilt0H = pFilter[1];
+
+ for (i = start; i < stop; i++) {
+ xReal = *pDelayBuffer;
+ *pDelayBuffer = dataRealIn[i];
+ pDelayBuffer++;
+
+ xImag = *pDelayBuffer;
+ *pDelayBuffer = dataImagIn[i];
+ pDelayBuffer += offsetDelayBuffer;
+
+ yReal = (pStates[0] + fMultDiv2(xReal, nFilt0L)) << FILTER_SF;
+ yImag = (pStates[1] + fMultDiv2(xImag, nFilt0L)) << FILTER_SF;
+
+ dataRealOut[i] = yReal;
+ dataImagOut[i] = yImag;
+
+ pStates[0] =
+ pStates[2] + fMultDiv2(xReal, nFilt0H) - fMultDiv2(yReal, nFilt0H);
+ pStates[1] =
+ pStates[3] + fMultDiv2(xImag, nFilt0H) - fMultDiv2(yImag, nFilt0H);
+ pStates[2] = (xReal >> FILTER_SF) - fMultDiv2(yReal, nFilt0L);
+ pStates[3] = (xImag >> FILTER_SF) - fMultDiv2(yImag, nFilt0L);
+ pStates += offsetStates;
+ }
+ } else if (reverbFilterOrder == 3) {
+ FIXP_DECORR nFilt0L, nFilt0H, nFilt1L;
+
+ nFilt0L = pFilter[0];
+ nFilt0H = pFilter[1];
+ nFilt1L = pFilter[2];
+
+ for (i = start; i < stop; i++) {
+ xReal = *pDelayBuffer;
+ *pDelayBuffer = dataRealIn[i];
+ pDelayBuffer++;
+
+ xImag = *pDelayBuffer;
+ *pDelayBuffer = dataImagIn[i];
+ pDelayBuffer += offsetDelayBuffer;
+
+ yReal = (pStates[0] + fMultDiv2(xReal, nFilt0L)) << FILTER_SF;
+ yImag = (pStates[1] + fMultDiv2(xImag, nFilt0L)) << FILTER_SF;
+
+ dataRealOut[i] = yReal;
+ dataImagOut[i] = yImag;
+
+ pStates[0] =
+ pStates[2] + fMultDiv2(xReal, nFilt0H) - fMultDiv2(yReal, nFilt1L);
+ pStates[1] =
+ pStates[3] + fMultDiv2(xImag, nFilt0H) - fMultDiv2(yImag, nFilt1L);
+ pStates[2] =
+ pStates[4] + fMultDiv2(xReal, nFilt1L) - fMultDiv2(yReal, nFilt0H);
+ pStates[3] =
+ pStates[5] + fMultDiv2(xImag, nFilt1L) - fMultDiv2(yImag, nFilt0H);
+ pStates[4] = (xReal >> FILTER_SF) - fMultDiv2(yReal, nFilt0L);
+ pStates[5] = (xImag >> FILTER_SF) - fMultDiv2(yImag, nFilt0L);
+ pStates += offsetStates;
+ }
+ } else if (reverbFilterOrder == 6) {
+ FIXP_DECORR nFilt0L, nFilt0H, nFilt1L, nFilt1H, nFilt2L, nFilt2H;
+
+ nFilt0L = pFilter[0];
+ nFilt0H = pFilter[1];
+ nFilt1L = pFilter[2];
+ nFilt1H = pFilter[3];
+ nFilt2L = pFilter[4];
+ nFilt2H = pFilter[5];
+
+ for (i = start; i < stop; i++) {
+ xReal = *pDelayBuffer;
+ *pDelayBuffer = dataRealIn[i];
+ pDelayBuffer++;
+
+ xImag = *pDelayBuffer;
+ *pDelayBuffer = dataImagIn[i];
+ pDelayBuffer += offsetDelayBuffer;
+
+ yReal = (pStates[0] + fMultDiv2(xReal, nFilt0L)) << FILTER_SF;
+ yImag = (pStates[1] + fMultDiv2(xImag, nFilt0L)) << FILTER_SF;
+ dataRealOut[i] = yReal;
+ dataImagOut[i] = yImag;
+
+ pStates[0] =
+ pStates[2] + fMultDiv2(xReal, nFilt0H) - fMultDiv2(yReal, nFilt2H);
+ pStates[1] =
+ pStates[3] + fMultDiv2(xImag, nFilt0H) - fMultDiv2(yImag, nFilt2H);
+ pStates[2] =
+ pStates[4] + fMultDiv2(xReal, nFilt1L) - fMultDiv2(yReal, nFilt2L);
+ pStates[3] =
+ pStates[5] + fMultDiv2(xImag, nFilt1L) - fMultDiv2(yImag, nFilt2L);
+ pStates[4] =
+ pStates[6] + fMultDiv2(xReal, nFilt1H) - fMultDiv2(yReal, nFilt1H);
+ pStates[5] =
+ pStates[7] + fMultDiv2(xImag, nFilt1H) - fMultDiv2(yImag, nFilt1H);
+ pStates[6] =
+ pStates[8] + fMultDiv2(xReal, nFilt2L) - fMultDiv2(yReal, nFilt1L);
+ pStates[7] =
+ pStates[9] + fMultDiv2(xImag, nFilt2L) - fMultDiv2(yImag, nFilt1L);
+ pStates[8] =
+ pStates[10] + fMultDiv2(xReal, nFilt2H) - fMultDiv2(yReal, nFilt0H);
+ pStates[9] =
+ pStates[11] + fMultDiv2(xImag, nFilt2H) - fMultDiv2(yImag, nFilt0H);
+ pStates[10] = (xReal >> FILTER_SF) - fMultDiv2(yReal, nFilt0L);
+ pStates[11] = (xImag >> FILTER_SF) - fMultDiv2(yImag, nFilt0L);
+ pStates += offsetStates;
+ }
+ } else {
+ FIXP_DECORR nFilt0L, nFilt0H;
+ for (i = start; i < stop; i++) {
+ xReal = *pDelayBuffer;
+ *pDelayBuffer = dataRealIn[i];
+ pDelayBuffer++;
+
+ xImag = *pDelayBuffer;
+ *pDelayBuffer = dataImagIn[i];
+ pDelayBuffer += offsetDelayBuffer;
+
+ nFilt0L = pFilter[0];
+ yReal = (pStates[0] + fMultDiv2(xReal, nFilt0L)) << 2;
+ yImag = (pStates[1] + fMultDiv2(xImag, nFilt0L)) << 2;
+ dataRealOut[i] = yReal;
+ dataImagOut[i] = yImag;
+
+ for (j = 1; j < reverbFilterOrder; j++) {
+ nFilt0L = pFilter[j];
+ nFilt0H = pFilter[reverbFilterOrder - j];
+ pStates[2 * j - 2] = pStates[2 * j] + fMultDiv2(xReal, nFilt0L) -
+ fMultDiv2(yReal, nFilt0H);
+ pStates[2 * j - 1] = pStates[2 * j + 1] + fMultDiv2(xImag, nFilt0L) -
+ fMultDiv2(yImag, nFilt0H);
+ }
+ nFilt0L = pFilter[j];
+ nFilt0H = pFilter[reverbFilterOrder - j];
+ pStates[2 * j - 2] =
+ fMultDiv2(xReal, nFilt0L) - fMultDiv2(yReal, nFilt0H);
+ pStates[2 * j - 1] =
+ fMultDiv2(xImag, nFilt0L) - fMultDiv2(yImag, nFilt0H);
+
+ pStates += offsetStates;
+ }
+ }
+
+ return (INT)0;
+}
+#endif /* #ifndef FUNCTION_DecorrFilterApplyREAL */
+
+#ifndef FUNCTION_DecorrFilterApplyCPLX_PS
+LNK_SECTION_CODE_L1
+static INT DecorrFilterApplyCPLX_PS(
+ DECORR_FILTER_INSTANCE const filter[], FIXP_DBL *dataRealIn,
+ FIXP_DBL *dataImagIn, FIXP_DBL *dataRealOut, FIXP_DBL *dataImagOut,
+ INT start, INT stop, INT reverbFilterOrder, INT reverbBandNoSampleDelay,
+ INT reverbBandDelayBufferIndex, UCHAR *stateBufferOffset) {
+ /* r = real, j = imaginary */
+ FIXP_DBL r_data_a, j_data_a, r_data_b, j_data_b, r_stage_mult, j_stage_mult;
+ FIXP_STP rj_coeff;
+
+ /* get pointer to current position in input delay buffer of filter with
+ * starting-index */
+ FIXP_DBL *pDelayBuffer =
+ &filter[start].DelayBufferCplx[reverbBandDelayBufferIndex]; /* increases
+ by 2 every
+ other call
+ of this
+ function */
+ /* determine the increment for this pointer to get to the correct position in
+ * the delay buffer of the next filter */
+ INT offsetDelayBuffer = (2 * reverbBandNoSampleDelay) - 1;
+
+ /* pointer to current position in state buffer */
+ FIXP_DBL *pStates = filter[start].stateCplx;
+ INT pStatesIncrement = 2 * reverbFilterOrder;
+
+ /* stateBufferOffset-pointers */
+ FIXP_DBL *pStateBufferOffset0 = pStates + stateBufferOffset[0];
+ FIXP_DBL *pStateBufferOffset1 = pStates + stateBufferOffset[1];
+ FIXP_DBL *pStateBufferOffset2 = pStates + stateBufferOffset[2];
+
+ /* traverse all hybrid-bands inbetween start- and stop-index */
+ for (int i = start; i < stop; i++) {
+ /* 1. input delay (real/imaginary values interleaved) */
+
+ /* load delayed real input value */
+ r_data_a = *pDelayBuffer;
+ /* store incoming real data value to delay buffer and increment pointer */
+ *pDelayBuffer++ = dataRealIn[i];
+
+ /* load delayed imaginary input value */
+ j_data_a = *pDelayBuffer;
+ /* store incoming imaginary data value to delay buffer */
+ *pDelayBuffer = dataImagIn[i];
+ /* increase delay buffer by offset */
+ pDelayBuffer += offsetDelayBuffer;
+
+ /* 2. Phi(k)-stage */
+
+ /* create pointer to coefficient table (real and imaginary coefficients
+ * interleaved) */
+ const FIXP_STP *pCoeffs = filter[i].coeffsPacked;
+
+ /* the first two entries of the coefficient table are the
+ * Phi(k)-multiplicants */
+ rj_coeff = *pCoeffs++;
+ /* multiply value from input delay buffer by looked-up values */
+ cplxMultDiv2(&r_data_b, &j_data_b, r_data_a, j_data_a, rj_coeff);
+
+ /* 3. process all three filter stages */
+
+ /* stage 0 */
+
+ /* get coefficients from lookup table */
+ rj_coeff = *pCoeffs++;
+
+ /* multiply output of last stage by coefficient */
+ cplxMultDiv2(&r_stage_mult, &j_stage_mult, r_data_b, j_data_b, rj_coeff);
+ r_stage_mult <<= 1;
+ j_stage_mult <<= 1;
+
+ /* read and add value from state buffer (this is the input for the next
+ * stage) */
+ r_data_a = r_stage_mult + pStateBufferOffset0[0];
+ j_data_a = j_stage_mult + pStateBufferOffset0[1];
+
+ /* negate r_data_a to perform multiplication with complex conjugate of
+ * rj_coeff */
+ cplxMultDiv2(&r_stage_mult, &j_stage_mult, -r_data_a, j_data_a, rj_coeff);
+
+ /* add stage input to shifted result */
+ r_stage_mult = r_data_b + (r_stage_mult << 1);
+ j_stage_mult = j_data_b - (j_stage_mult << 1);
+
+ /* store result to state buffer */
+ pStateBufferOffset0[0] = r_stage_mult;
+ pStateBufferOffset0[1] = j_stage_mult;
+ pStateBufferOffset0 += pStatesIncrement;
+
+ /* stage 1 */
+
+ /* get coefficients from lookup table */
+ rj_coeff = *pCoeffs++;
+
+ /* multiply output of last stage by coefficient */
+ cplxMultDiv2(&r_stage_mult, &j_stage_mult, r_data_a, j_data_a, rj_coeff);
+ r_stage_mult <<= 1;
+ j_stage_mult <<= 1;
+
+ /* read and add value from state buffer (this is the input for the next
+ * stage) */
+ r_data_b = r_stage_mult + pStateBufferOffset1[0];
+ j_data_b = j_stage_mult + pStateBufferOffset1[1];
+
+ /* negate r_data_b to perform multiplication with complex conjugate of
+ * rj_coeff */
+ cplxMultDiv2(&r_stage_mult, &j_stage_mult, -r_data_b, j_data_b, rj_coeff);
+
+ /* add stage input to shifted result */
+ r_stage_mult = r_data_a + (r_stage_mult << 1);
+ j_stage_mult = j_data_a - (j_stage_mult << 1);
+
+ /* store result to state buffer */
+ pStateBufferOffset1[0] = r_stage_mult;
+ pStateBufferOffset1[1] = j_stage_mult;
+ pStateBufferOffset1 += pStatesIncrement;
+
+ /* stage 2 */
+
+ /* get coefficients from lookup table */
+ rj_coeff = *pCoeffs++;
+
+ /* multiply output of last stage by coefficient */
+ cplxMultDiv2(&r_stage_mult, &j_stage_mult, r_data_b, j_data_b, rj_coeff);
+ r_stage_mult <<= 1;
+ j_stage_mult <<= 1;
+
+ /* read and add value from state buffer (this is the input for the next
+ * stage) */
+ r_data_a = r_stage_mult + pStateBufferOffset2[0];
+ j_data_a = j_stage_mult + pStateBufferOffset2[1];
+
+ /* negate r_data_a to perform multiplication with complex conjugate of
+ * rj_coeff */
+ cplxMultDiv2(&r_stage_mult, &j_stage_mult, -r_data_a, j_data_a, rj_coeff);
+
+ /* add stage input to shifted result */
+ r_stage_mult = r_data_b + (r_stage_mult << 1);
+ j_stage_mult = j_data_b - (j_stage_mult << 1);
+
+ /* store result to state buffer */
+ pStateBufferOffset2[0] = r_stage_mult;
+ pStateBufferOffset2[1] = j_stage_mult;
+ pStateBufferOffset2 += pStatesIncrement;
+
+ /* write filter output */
+ dataRealOut[i] = r_data_a << 1;
+ dataImagOut[i] = j_data_a << 1;
+
+ } /* end of band/filter loop (outer loop) */
+
+ /* update stateBufferOffset with respect to ring buffer boundaries */
+ if (stateBufferOffset[0] == 4)
+ stateBufferOffset[0] = 0;
+ else
+ stateBufferOffset[0] += 2;
+
+ if (stateBufferOffset[1] == 12)
+ stateBufferOffset[1] = 6;
+ else
+ stateBufferOffset[1] += 2;
+
+ if (stateBufferOffset[2] == 22)
+ stateBufferOffset[2] = 14;
+ else
+ stateBufferOffset[2] += 2;
+
+ return (INT)0;
+}
+
+#endif /* FUNCTION_DecorrFilterApplyCPLX_PS */
+
+/*******************************************************************************
+*******************************************************************************/
+static INT DuckerInit(DUCKER_INSTANCE *const self, int const hybridBands,
+ int partiallyComplex, const FDK_DUCKER_TYPE duckerType,
+ const int nParamBands, int initStatesFlag) {
+ INT errorCode = 0;
+
+ if (self) {
+ switch (nParamBands) {
+ case (20):
+ FDK_ASSERT(hybridBands == 71);
+ self->mapHybBands2ProcBands = kernels_20_to_71_PS;
+ self->mapProcBands2HybBands = kernels_20_to_71_offset_PS;
+ self->parameterBands = (20);
+ break;
+ case (28):
+
+ self->mapHybBands2ProcBands = kernels_28_to_71;
+ self->mapProcBands2HybBands = kernels_28_to_71_offset;
+ self->parameterBands = (28);
+ break;
+ case (23):
+ FDK_ASSERT(hybridBands == 64 || hybridBands == 32);
+ self->mapHybBands2ProcBands = kernels_23_to_64;
+ self->mapProcBands2HybBands = kernels_23_to_64_offset;
+ self->parameterBands = (23);
+ break;
+ default:
+ return 1;
+ }
+ self->qs_next = &self->mapProcBands2HybBands[1];
+
+ self->maxValDirectData = FL2FXCONST_DBL(-1.0f);
+ self->maxValReverbData = FL2FXCONST_DBL(-1.0f);
+ self->scaleDirectNrg = 2 * DUCKER_MAX_NRG_SCALE;
+ self->scaleReverbNrg = 2 * DUCKER_MAX_NRG_SCALE;
+ self->scaleSmoothDirRevNrg = 2 * DUCKER_MAX_NRG_SCALE;
+ self->headroomSmoothDirRevNrg = 2 * DUCKER_MAX_NRG_SCALE;
+ self->hybridBands = hybridBands;
+ self->partiallyComplex = partiallyComplex;
+
+ if (initStatesFlag && (duckerType == DUCKER_PS)) {
+ int pb;
+ for (pb = 0; pb < self->parameterBands; pb++) {
+ self->SmoothDirRevNrg[pb] = (FIXP_MPS)0;
+ }
+ }
+ } else
+ errorCode = 1;
+
+ return errorCode;
+}
+
+ /*******************************************************************************
+ *******************************************************************************/
+
+#ifndef FUNCTION_DuckerCalcEnergy
+static INT DuckerCalcEnergy(DUCKER_INSTANCE *const self,
+ FIXP_DBL const inputReal[(71)],
+ FIXP_DBL const inputImag[(71)],
+ FIXP_DBL energy[(28)], FIXP_DBL inputMaxVal,
+ SCHAR *nrgScale, int mode, /* 1:(ps) 0:(else) */
+ int startHybBand) {
+ INT err = 0;
+ int qs, maxHybBand;
+ int maxHybridBand = self->hybridBands - 1;
+
+ maxHybBand = maxHybridBand;
+
+ FDKmemclear(energy, (28) * sizeof(FIXP_DBL));
+
+ if (mode == 1) {
+ int pb;
+ int clz;
+ FIXP_DBL maxVal = FL2FXCONST_DBL(-1.0f);
+
+ if (maxVal == FL2FXCONST_DBL(-1.0f)) {
+#ifdef FUNCTION_DuckerCalcEnergy_func2
+ maxVal = DuckerCalcEnergy_func2(inputReal, inputImag, startHybBand,
+ maxHybBand, maxHybridBand);
+#else
+ FIXP_DBL localMaxVal = FL2FXCONST_DBL(0.0f);
+ for (qs = startHybBand; qs <= maxHybBand; qs++) {
+ localMaxVal |= fAbs(inputReal[qs]);
+ localMaxVal |= fAbs(inputImag[qs]);
+ }
+ for (; qs <= maxHybridBand; qs++) {
+ localMaxVal |= fAbs(inputReal[qs]);
+ }
+ maxVal = localMaxVal;
+#endif
+ }
+
+ clz = fixMax(0, CntLeadingZeros(maxVal) - DUCKER_HEADROOM_BITS);
+ clz = fixMin(clz, DUCKER_MAX_NRG_SCALE);
+ *nrgScale = (SCHAR)clz << 1;
+
+ /* Initialize pb since it would stay uninitialized for the case startHybBand
+ * > maxHybBand. */
+ pb = SpatialDecGetProcessingBand(maxHybBand, self->mapHybBands2ProcBands);
+ for (qs = startHybBand; qs <= maxHybBand; qs++) {
+ pb = SpatialDecGetProcessingBand(qs, self->mapHybBands2ProcBands);
+ energy[pb] =
+ fAddSaturate(energy[pb], fPow2Div2(inputReal[qs] << clz) +
+ fPow2Div2(inputImag[qs] << clz));
+ }
+ pb++;
+
+ for (; pb <= SpatialDecGetProcessingBand(maxHybridBand,
+ self->mapHybBands2ProcBands);
+ pb++) {
+ FDK_ASSERT(pb != SpatialDecGetProcessingBand(
+ qs - 1, self->mapHybBands2ProcBands));
+ int qs_next;
+ FIXP_DBL nrg = 0;
+ qs_next = (int)self->qs_next[pb];
+ for (; qs < qs_next; qs++) {
+ nrg = fAddSaturate(nrg, fPow2Div2(inputReal[qs] << clz));
+ }
+ energy[pb] = nrg;
+ }
+ } else {
+ int clz;
+ FIXP_DBL maxVal = FL2FXCONST_DBL(-1.0f);
+
+ maxVal = inputMaxVal;
+
+ if (maxVal == FL2FXCONST_DBL(-1.0f)) {
+#ifdef FUNCTION_DuckerCalcEnergy_func2
+ maxVal = DuckerCalcEnergy_func2(inputReal, inputImag, startHybBand,
+ maxHybBand, maxHybridBand);
+#else
+ FIXP_DBL localMaxVal = FL2FXCONST_DBL(0.0f);
+ for (qs = startHybBand; qs <= maxHybBand; qs++) {
+ localMaxVal |= fAbs(inputReal[qs]);
+ localMaxVal |= fAbs(inputImag[qs]);
+ }
+ for (; qs <= maxHybridBand; qs++) {
+ localMaxVal |= fAbs(inputReal[qs]);
+ }
+ maxVal = localMaxVal;
+#endif
+ }
+
+ clz = fixMax(0, CntLeadingZeros(maxVal) - DUCKER_HEADROOM_BITS);
+ clz = fixMin(clz, DUCKER_MAX_NRG_SCALE);
+ *nrgScale = (SCHAR)clz << 1;
+
+#ifdef FUNCTION_DuckerCalcEnergy_func4
+ DuckerCalcEnergy_func4(inputReal, inputImag, energy,
+ self->mapHybBands2ProcBands, clz, startHybBand,
+ maxHybBand, maxHybridBand);
+#else
+ for (qs = startHybBand; qs <= maxHybBand; qs++) {
+ int pb = SpatialDecGetProcessingBand(qs, self->mapHybBands2ProcBands);
+ energy[pb] =
+ fAddSaturate(energy[pb], fPow2Div2(inputReal[qs] << clz) +
+ fPow2Div2(inputImag[qs] << clz));
+ }
+
+ for (; qs <= maxHybridBand; qs++) {
+ int pb = SpatialDecGetProcessingBand(qs, self->mapHybBands2ProcBands);
+ energy[pb] = fAddSaturate(energy[pb], fPow2Div2(inputReal[qs] << clz));
+ }
+#endif /* FUNCTION_DuckerCalcEnergy_func4 */
+ }
+
+ {
+ /* Catch overflows which have been observed in erred bitstreams to avoid
+ * assertion failures later. */
+ int pb;
+ for (pb = 0; pb < (28); pb++) {
+ energy[pb] = (FIXP_DBL)((LONG)energy[pb] & (LONG)MAXVAL_DBL);
+ }
+ }
+ return err;
+}
+#endif /* #ifndef FUNCTION_DuckerCalcEnergy */
+
+LNK_SECTION_CODE_L1
+static INT DuckerApply(DUCKER_INSTANCE *const self,
+ FIXP_DBL const directNrg[(28)],
+ FIXP_DBL outputReal[(71)], FIXP_DBL outputImag[(71)],
+ int startHybBand) {
+ INT err = 0;
+ int qs = startHybBand;
+ int qs_next = 0;
+ int pb = 0;
+ int startParamBand = 0;
+ int hybBands;
+ int hybridBands = self->hybridBands;
+
+ C_ALLOC_SCRATCH_START(reverbNrg, FIXP_DBL, (28));
+
+ FIXP_DBL *smoothDirRevNrg = &self->SmoothDirRevNrg[0];
+ FIXP_DUCK_GAIN duckGain = 0;
+
+ int doScaleNrg = 0;
+ int scaleDirectNrg = 0;
+ int scaleReverbNrg = 0;
+ int scaleSmoothDirRevNrg = 0;
+ FIXP_DBL maxDirRevNrg = FL2FXCONST_DBL(0.0);
+
+ hybBands = hybridBands;
+
+ startParamBand =
+ SpatialDecGetProcessingBand(startHybBand, self->mapHybBands2ProcBands);
+
+ DuckerCalcEnergy(self, outputReal, outputImag, reverbNrg,
+ self->maxValReverbData, &(self->scaleReverbNrg), 0,
+ startHybBand);
+
+ if ((self->scaleDirectNrg != self->scaleReverbNrg) ||
+ (self->scaleDirectNrg != self->scaleSmoothDirRevNrg) ||
+ (self->headroomSmoothDirRevNrg == 0)) {
+ int scale;
+
+ scale = fixMin(self->scaleDirectNrg, self->scaleSmoothDirRevNrg +
+ self->headroomSmoothDirRevNrg - 1);
+ scale = fixMin(scale, self->scaleReverbNrg);
+
+ scaleDirectNrg = fMax(fMin(self->scaleDirectNrg - scale, (DFRACT_BITS - 1)),
+ -(DFRACT_BITS - 1));
+ scaleReverbNrg = fMax(fMin(self->scaleReverbNrg - scale, (DFRACT_BITS - 1)),
+ -(DFRACT_BITS - 1));
+ scaleSmoothDirRevNrg =
+ fMax(fMin(self->scaleSmoothDirRevNrg - scale, (DFRACT_BITS - 1)),
+ -(DFRACT_BITS - 1));
+
+ self->scaleSmoothDirRevNrg = (SCHAR)scale;
+
+ doScaleNrg = 1;
+ }
+ for (pb = startParamBand; pb < self->parameterBands; pb++) {
+ FIXP_DBL tmp1;
+ FIXP_DBL tmp2;
+ INT s;
+
+ /* smoothDirRevNrg[2*pb ] = fMult(smoothDirRevNrg[2*pb ],DUCK_ALPHA_FDK) +
+ fMultDiv2(directNrg[pb],DUCK_ONE_MINUS_ALPHA_X4_FDK);
+ smoothDirRevNrg[2*pb+1] = fMult(smoothDirRevNrg[2*pb+1],DUCK_ALPHA_FDK) +
+ fMultDiv2(reverbNrg[pb],DUCK_ONE_MINUS_ALPHA_X4_FDK); tmp1 =
+ fMult(smoothDirRevNrg[2*pb],DUCK_GAMMA_FDK); tmp2 =
+ smoothDirRevNrg[2*pb+1] >> 1;
+ */
+ tmp1 = smoothDirRevNrg[2 * pb + 0];
+ tmp2 = smoothDirRevNrg[2 * pb + 1];
+ tmp1 = fMult(tmp1, DUCK_ALPHA_FDK);
+ tmp2 = fMult(tmp2, DUCK_ALPHA_FDK);
+
+ if (doScaleNrg) {
+ int scaleSmoothDirRevNrg_asExponent = -scaleSmoothDirRevNrg;
+
+ tmp1 = scaleValue(tmp1, scaleSmoothDirRevNrg_asExponent);
+ tmp2 = scaleValue(tmp2, scaleSmoothDirRevNrg_asExponent);
+ tmp1 = fMultAddDiv2(tmp1, scaleValue(directNrg[pb], -scaleDirectNrg),
+ DUCK_ONE_MINUS_ALPHA_X4_FDK);
+ tmp2 = fMultAddDiv2(tmp2, scaleValue(reverbNrg[pb], -scaleReverbNrg),
+ DUCK_ONE_MINUS_ALPHA_X4_FDK);
+ } else {
+ tmp1 = fMultAddDiv2(tmp1, directNrg[pb], DUCK_ONE_MINUS_ALPHA_X4_FDK);
+ tmp2 = fMultAddDiv2(tmp2, reverbNrg[pb], DUCK_ONE_MINUS_ALPHA_X4_FDK);
+ }
+
+ smoothDirRevNrg[2 * pb] = tmp1;
+ smoothDirRevNrg[2 * pb + 1] = tmp2;
+
+ maxDirRevNrg |= fAbs(tmp1);
+ maxDirRevNrg |= fAbs(tmp2);
+
+ tmp1 = fMult(tmp1, DUCK_GAMMA_FDK);
+ tmp2 = tmp2 >> 1;
+
+ qs_next = fMin((int)self->qs_next[pb], self->hybridBands);
+
+ if (tmp2 > tmp1) { /* true for about 20% */
+ /* gain smaller than 1.0 */
+ tmp1 = sqrtFixp(tmp1);
+ tmp2 = invSqrtNorm2(tmp2, &s);
+ duckGain = FX_DBL2FX_DUCK_GAIN(fMultDiv2(tmp1, tmp2) << s);
+ } else { /* true for about 80 % */
+ tmp2 = smoothDirRevNrg[2 * pb] >> 1;
+ tmp1 = fMult(smoothDirRevNrg[2 * pb + 1], DUCK_GAMMA_FDK);
+ if (tmp2 > tmp1) { /* true for about 20% */
+ if (tmp1 <= (tmp2 >> 2)) {
+ /* limit gain to 2.0 */
+ if (qs < hybBands) {
+ for (; qs < qs_next; qs++) {
+ outputReal[qs] = outputReal[qs] << 1;
+ outputImag[qs] = outputImag[qs] << 1;
+ }
+ } else {
+ for (; qs < qs_next; qs++) {
+ outputReal[qs] = outputReal[qs] << 1;
+ }
+ }
+ /* skip general gain*output section */
+ continue;
+ } else {
+ /* gain from 1.0 to 2.0 */
+ tmp2 = sqrtFixp(tmp2 >> 2);
+ tmp1 = invSqrtNorm2(tmp1, &s);
+ duckGain = FX_DBL2FX_DUCK_GAIN(fMult(tmp1, tmp2) << s);
+ }
+ } else { /* true for about 60% */
+ /* gain = 1.0; output does not change; update qs index */
+ qs = qs_next;
+ continue;
+ }
+ }
+
+#ifdef FUNCTION_DuckerApply_func1
+ qs = DuckerApply_func1(qs, hybBands, qs_next, outputReal, outputImag,
+ duckGain);
+#else
+ /* general gain*output section */
+ if (qs < hybBands) { /* true for about 39% */
+ for (; qs < qs_next; qs++) { /* runs about 2 times */
+ outputReal[qs] = fMultDiv2(outputReal[qs], duckGain) << 2;
+ outputImag[qs] = fMultDiv2(outputImag[qs], duckGain) << 2;
+ }
+ } else {
+ for (; qs < qs_next; qs++) {
+ outputReal[qs] = fMultDiv2(outputReal[qs], duckGain) << 2;
+ }
+ }
+#endif
+ } /* pb */
+
+ self->headroomSmoothDirRevNrg =
+ (SCHAR)fixMax(0, CntLeadingZeros(maxDirRevNrg) - 1);
+
+ C_ALLOC_SCRATCH_END(reverbNrg, FIXP_DBL, (28));
+
+ return err;
+}
+
+LNK_SECTION_CODE_L1
+static INT DuckerApplyPS(DUCKER_INSTANCE *const self,
+ FIXP_DBL const directNrg[(28)],
+ FIXP_DBL outputReal[(71)], FIXP_DBL outputImag[(71)],
+ int startHybBand) {
+ int qs = startHybBand;
+ int pb = 0;
+ int startParamBand =
+ SpatialDecGetProcessingBand(startHybBand, self->mapHybBands2ProcBands);
+ int hybBands;
+
+ int doScaleNrg = 0;
+ int scaleDirectNrg = 0;
+ int scaleSmoothDirRevNrg = 0;
+ FIXP_DBL maxDirRevNrg = FL2FXCONST_DBL(0.0);
+
+ if ((self->scaleDirectNrg != self->scaleSmoothDirRevNrg) ||
+ (self->headroomSmoothDirRevNrg == 0)) {
+ int scale;
+
+ scale = fixMin(self->scaleDirectNrg, self->scaleSmoothDirRevNrg +
+ self->headroomSmoothDirRevNrg - 2);
+
+ scaleDirectNrg = fMax(fMin(self->scaleDirectNrg - scale, (DFRACT_BITS - 1)),
+ -(DFRACT_BITS - 1));
+ scaleSmoothDirRevNrg =
+ fMax(fMin(self->scaleSmoothDirRevNrg - scale, (DFRACT_BITS - 1)),
+ -(DFRACT_BITS - 1));
+
+ self->scaleSmoothDirRevNrg = (SCHAR)scale;
+
+ doScaleNrg = 1;
+ }
+
+ hybBands = self->hybridBands;
+
+ FDK_ASSERT((self->parameterBands == (28)) || (self->parameterBands == (20)));
+ for (pb = startParamBand; pb < self->parameterBands; pb++) {
+ FIXP_DBL directNrg2 = directNrg[pb];
+
+ if (doScaleNrg) {
+ directNrg2 = scaleValue(directNrg2, -scaleDirectNrg);
+ self->peakDiff[pb] =
+ scaleValue(self->peakDiff[pb], -scaleSmoothDirRevNrg);
+ self->peakDecay[pb] =
+ scaleValue(self->peakDecay[pb], -scaleSmoothDirRevNrg);
+ self->SmoothDirRevNrg[pb] =
+ scaleValue(self->SmoothDirRevNrg[pb], -scaleSmoothDirRevNrg);
+ }
+ self->peakDecay[pb] = fixMax(
+ directNrg2, fMult(self->peakDecay[pb], PS_DUCK_PEAK_DECAY_FACTOR_FDK));
+ self->peakDiff[pb] =
+ self->peakDiff[pb] +
+ fMult(PS_DUCK_FILTER_COEFF_FDK,
+ (self->peakDecay[pb] - directNrg2 - self->peakDiff[pb]));
+ self->SmoothDirRevNrg[pb] =
+ fixMax(self->SmoothDirRevNrg[pb] +
+ fMult(PS_DUCK_FILTER_COEFF_FDK,
+ (directNrg2 - self->SmoothDirRevNrg[pb])),
+ FL2FXCONST_DBL(0));
+
+ maxDirRevNrg |= fAbs(self->peakDiff[pb]);
+ maxDirRevNrg |= fAbs(self->SmoothDirRevNrg[pb]);
+
+ if ((self->peakDiff[pb] == FL2FXCONST_DBL(0)) &&
+ (self->SmoothDirRevNrg[pb] == FL2FXCONST_DBL(0))) {
+ int qs_next;
+
+ qs = fMax(qs, SpatialDecGetQmfBand(pb, self->mapProcBands2HybBands));
+ qs_next = fMin((int)self->qs_next[pb], self->hybridBands);
+
+ FIXP_DBL *pOutputReal = &outputReal[qs];
+ FIXP_DBL *pOutputImag = &outputImag[qs];
+
+ if (qs < hybBands) {
+ for (; qs < qs_next; qs++) {
+ *pOutputReal++ = FL2FXCONST_DBL(0);
+ *pOutputImag++ = FL2FXCONST_DBL(0);
+ }
+ } else {
+ for (; qs < qs_next; qs++) {
+ *pOutputReal++ = FL2FXCONST_DBL(0);
+ }
+ }
+ } else if (self->peakDiff[pb] != FL2FXCONST_DBL(0)) {
+ FIXP_DBL multiplication =
+ fMult(FL2FXCONST_DUCK(0.75f), self->peakDiff[pb]);
+ if (multiplication > (self->SmoothDirRevNrg[pb] >> 1)) {
+ FIXP_DBL num, denom, duckGain;
+ int scale, qs_next;
+
+ /* implement x/y as (sqrt(x)*invSqrt(y))^2 */
+ num = sqrtFixp(self->SmoothDirRevNrg[pb] >> 1);
+ denom = self->peakDiff[pb] +
+ FL2FXCONST_DBL(ABS_THR / (32768.0f * 32768.0f * 128.0f * 1.5f));
+ denom = invSqrtNorm2(denom, &scale);
+
+ /* duck output whether duckGain != 1.f */
+ qs = fMax(qs, SpatialDecGetQmfBand(pb, self->mapProcBands2HybBands));
+ qs_next = fMin((int)self->qs_next[pb], self->hybridBands);
+
+ duckGain = fMult(num, denom);
+ duckGain = fPow2Div2(duckGain << scale);
+ duckGain = fMultDiv2(FL2FXCONST_DUCK(2.f / 3.f), duckGain) << 3;
+
+ FIXP_DBL *pOutputReal = &outputReal[qs];
+ FIXP_DBL *pOutputImag = &outputImag[qs];
+
+ if (qs < hybBands) {
+ for (; qs < qs_next; qs++) {
+ *pOutputReal = fMult(*pOutputReal, duckGain);
+ pOutputReal++; /* don't move in front of "=" above, because then the
+ fract class treats it differently and provides
+ wrong argument to fMult() (seen on win32/msvc8) */
+ *pOutputImag = fMult(*pOutputImag, duckGain);
+ pOutputImag++;
+ }
+ } else {
+ for (; qs < qs_next; qs++) {
+ *pOutputReal = fMult(*pOutputReal, duckGain);
+ pOutputReal++;
+ }
+ }
+ }
+ }
+ } /* pb */
+
+ self->headroomSmoothDirRevNrg =
+ (SCHAR)fixMax(0, CntLeadingZeros(maxDirRevNrg) - 1);
+
+ return 0;
+}
+
+INT FDKdecorrelateOpen(HANDLE_DECORR_DEC hDecorrDec, FIXP_DBL *bufferCplx,
+ const INT bufLen) {
+ HANDLE_DECORR_DEC self = hDecorrDec;
+
+ if (bufLen < (2 * ((825) + (373)))) return 1;
+
+ /* assign all memory to stateBufferCplx. It is reassigned during
+ * FDKdecorrelateInit() */
+ self->stateBufferCplx = bufferCplx;
+ self->L_stateBufferCplx = 0;
+
+ self->delayBufferCplx = NULL;
+ self->L_delayBufferCplx = 0;
+
+ return 0;
+}
+
+static int distributeBuffer(HANDLE_DECORR_DEC self, const int L_stateBuf,
+ const int L_delayBuf) {
+ /* factor 2 because of complex values */
+ if ((2 * ((825) + (373))) < 2 * (L_stateBuf + L_delayBuf)) {
+ return 1;
+ }
+
+ self->L_stateBufferCplx = 2 * L_stateBuf;
+ self->delayBufferCplx = self->stateBufferCplx + 2 * L_stateBuf;
+ self->L_delayBufferCplx = 2 * L_delayBuf;
+
+ return 0;
+}
+INT FDKdecorrelateInit(HANDLE_DECORR_DEC hDecorrDec, const INT nrHybBands,
+ const FDK_DECORR_TYPE decorrType,
+ const FDK_DUCKER_TYPE duckerType, const INT decorrConfig,
+ const INT seed, const INT partiallyComplex,
+ const INT useFractDelay, const INT isLegacyPS,
+ const INT initStatesFlag) {
+ INT errorCode = 0;
+ int i, rb, i_start;
+ int nParamBands = 28;
+
+ INT offsetStateBuffer = 0;
+ INT offsetDelayBuffer = 0;
+
+ const UCHAR *REV_bandOffset;
+
+ const SCHAR *REV_filterOrder;
+
+ hDecorrDec->partiallyComplex = partiallyComplex;
+ hDecorrDec->numbins = nrHybBands;
+
+ switch (decorrType) {
+ case DECORR_PS:
+ /* ignore decorrConfig, seed */
+ if (partiallyComplex) {
+ hDecorrDec->REV_bandOffset = REV_bandOffset_PS_LP;
+ hDecorrDec->REV_delay = REV_delay_PS_LP;
+ errorCode = distributeBuffer(hDecorrDec, (168), (533));
+ } else {
+ hDecorrDec->REV_bandOffset = REV_bandOffset_PS_HQ;
+ hDecorrDec->REV_delay = REV_delay_PS_HQ;
+ errorCode = distributeBuffer(hDecorrDec, (360), (257));
+ }
+ hDecorrDec->REV_filterOrder = REV_filterOrder_PS;
+ hDecorrDec->REV_filtType = REV_filtType_PS;
+
+ /* Initialize ring buffer offsets for PS specific filter implementation.
+ */
+ for (i = 0; i < (3); i++)
+ hDecorrDec->stateBufferOffset[i] = stateBufferOffsetInit[i];
+
+ break;
+ case DECORR_USAC:
+ if (partiallyComplex) return 1;
+ if (seed != 0) return 1;
+ hDecorrDec->REV_bandOffset =
+ REV_bandOffset_MPS_HQ[decorrConfig]; /* reverb band layout is
+ inherited from MPS standard */
+ hDecorrDec->REV_filterOrder = REV_filterOrder_USAC;
+ hDecorrDec->REV_delay = REV_delay_USAC;
+ if (useFractDelay) {
+ return 1; /* not yet supported */
+ } else {
+ hDecorrDec->REV_filtType = REV_filtType_MPS; /* the filter types are
+ inherited from MPS
+ standard */
+ }
+ /* bsDecorrConfig == 1 is worst case */
+ errorCode = distributeBuffer(hDecorrDec, (509), (643));
+ break;
+ case DECORR_LD:
+ if (partiallyComplex) return 1;
+ if (useFractDelay) return 1;
+ if (decorrConfig > 2) return 1;
+ if (seed > (MAX_DECORR_SEED_LD - 1)) return 1;
+ if (!(nrHybBands == 64 || nrHybBands == 32))
+ return 1; /* actually just qmf bands and no hybrid bands */
+ hDecorrDec->REV_bandOffset = REV_bandOffset_LD[decorrConfig];
+ hDecorrDec->REV_filterOrder = REV_filterOrder_MPS; /* the filter orders
+ are inherited from
+ MPS standard */
+ hDecorrDec->REV_delay =
+ REV_delay_MPS; /* the delays in each reverb band are inherited from
+ MPS standard */
+ hDecorrDec->REV_filtType = REV_filtType_LD;
+ errorCode = distributeBuffer(hDecorrDec, (825), (373));
+ break;
+ default:
+ return 1;
+ }
+
+ if (errorCode) {
+ return errorCode;
+ }
+
+ if (initStatesFlag) {
+ FDKmemclear(
+ hDecorrDec->stateBufferCplx,
+ hDecorrDec->L_stateBufferCplx * sizeof(*hDecorrDec->stateBufferCplx));
+ FDKmemclear(
+ hDecorrDec->delayBufferCplx,
+ hDecorrDec->L_delayBufferCplx * sizeof(*hDecorrDec->delayBufferCplx));
+ FDKmemclear(hDecorrDec->reverbBandDelayBufferIndex,
+ sizeof(hDecorrDec->reverbBandDelayBufferIndex));
+ }
+
+ REV_bandOffset = hDecorrDec->REV_bandOffset;
+
+ REV_filterOrder = hDecorrDec->REV_filterOrder;
+
+ i_start = 0;
+ for (rb = 0; rb < (4); rb++) {
+ int i_stop;
+
+ i_stop = REV_bandOffset[rb];
+
+ if (i_stop <= i_start) {
+ continue;
+ }
+
+ for (i = i_start; i < i_stop; i++) {
+ switch (decorrType) {
+ case DECORR_PS:
+ errorCode = DecorrFilterInitPS(
+ &hDecorrDec->Filter[i], hDecorrDec->stateBufferCplx,
+ hDecorrDec->delayBufferCplx, &offsetStateBuffer,
+ &offsetDelayBuffer, i, rb, hDecorrDec->REV_delay[rb]);
+ break;
+ default:
+ errorCode = DecorrFilterInit(
+ &hDecorrDec->Filter[i], hDecorrDec->stateBufferCplx,
+ hDecorrDec->delayBufferCplx, &offsetStateBuffer,
+ &offsetDelayBuffer, seed, rb, useFractDelay,
+ hDecorrDec->REV_delay[rb], REV_filterOrder[rb], decorrType);
+ break;
+ }
+ }
+
+ i_start = i_stop;
+ } /* loop over reverbBands */
+
+ if (!(offsetStateBuffer <= hDecorrDec->L_stateBufferCplx) ||
+ !(offsetDelayBuffer <= hDecorrDec->L_delayBufferCplx)) {
+ return errorCode = 1;
+ }
+
+ if (duckerType == DUCKER_AUTOMATIC) {
+ /* Choose correct ducker type according to standards: */
+ switch (decorrType) {
+ case DECORR_PS:
+ hDecorrDec->ducker.duckerType = DUCKER_PS;
+ if (isLegacyPS) {
+ nParamBands = (20);
+ } else {
+ nParamBands = (28);
+ }
+ break;
+ case DECORR_USAC:
+ hDecorrDec->ducker.duckerType = DUCKER_MPS;
+ nParamBands = (28);
+ break;
+ case DECORR_LD:
+ hDecorrDec->ducker.duckerType = DUCKER_MPS;
+ nParamBands = (23);
+ break;
+ default:
+ return 1;
+ }
+ }
+
+ errorCode = DuckerInit(
+ &hDecorrDec->ducker, hDecorrDec->numbins, hDecorrDec->partiallyComplex,
+ hDecorrDec->ducker.duckerType, nParamBands, initStatesFlag);
+
+ return errorCode;
+}
+
+INT FDKdecorrelateClose(HANDLE_DECORR_DEC hDecorrDec) {
+ INT err = 0;
+
+ if (hDecorrDec == NULL) {
+ return 1;
+ }
+
+ hDecorrDec->stateBufferCplx = NULL;
+ hDecorrDec->L_stateBufferCplx = 0;
+ hDecorrDec->delayBufferCplx = NULL;
+ hDecorrDec->L_delayBufferCplx = 0;
+
+ return err;
+}
+
+LNK_SECTION_CODE_L1
+INT FDKdecorrelateApply(HANDLE_DECORR_DEC hDecorrDec, FIXP_DBL *dataRealIn,
+ FIXP_DBL *dataImagIn, FIXP_DBL *dataRealOut,
+ FIXP_DBL *dataImagOut, const INT startHybBand) {
+ HANDLE_DECORR_DEC self = hDecorrDec;
+ INT err = 0;
+ INT rb, stop, start;
+
+ if (self != NULL) {
+ int nHybBands = 0;
+ /* copy new samples */
+ nHybBands = self->numbins;
+
+ FIXP_DBL directNrg[(28)];
+
+ DuckerCalcEnergy(
+ &self->ducker, dataRealIn, dataImagIn, directNrg,
+ self->ducker.maxValDirectData, &(self->ducker.scaleDirectNrg),
+ (self->ducker.duckerType == DUCKER_PS) ? 1 : 0, startHybBand);
+
+ /* complex-valued hybrid bands */
+ for (stop = 0, rb = 0; rb < (4); rb++) {
+ start = fMax(stop, startHybBand);
+ stop = fMin(self->REV_bandOffset[rb], (UCHAR)nHybBands);
+
+ if (start < stop) {
+ switch (hDecorrDec->REV_filtType[rb]) {
+ case DELAY:
+ err = DecorrFilterApplyPASS(&self->Filter[0], dataRealIn,
+ dataImagIn, dataRealOut, dataImagOut,
+ start, stop, self->REV_delay[rb],
+ self->reverbBandDelayBufferIndex[rb]);
+ break;
+ case INDEP_CPLX_PS:
+ err = DecorrFilterApplyCPLX_PS(
+ &self->Filter[0], dataRealIn, dataImagIn, dataRealOut,
+ dataImagOut, start, stop, self->REV_filterOrder[rb],
+ self->REV_delay[rb], self->reverbBandDelayBufferIndex[rb],
+ self->stateBufferOffset);
+ break;
+ case COMMON_REAL:
+ err = DecorrFilterApplyREAL(
+ &self->Filter[0], dataRealIn, dataImagIn, dataRealOut,
+ dataImagOut, start, stop, self->REV_filterOrder[rb],
+ self->REV_delay[rb], self->reverbBandDelayBufferIndex[rb]);
+ break;
+ default:
+ err = 1;
+ break;
+ }
+ if (err != 0) {
+ goto bail;
+ }
+ } /* if start < stop */
+ } /* loop over reverb bands */
+
+ for (rb = 0; rb < (4); rb++) {
+ self->reverbBandDelayBufferIndex[rb] += 2;
+ if (self->reverbBandDelayBufferIndex[rb] >= 2 * self->REV_delay[rb])
+ self->reverbBandDelayBufferIndex[rb] = 0;
+ }
+
+ switch (self->ducker.duckerType) {
+ case DUCKER_PS:
+ err = DuckerApplyPS(&self->ducker, directNrg, dataRealOut, dataImagOut,
+ startHybBand);
+ if (err != 0) goto bail;
+ break;
+ default:
+ err = DuckerApply(&self->ducker, directNrg, dataRealOut, dataImagOut,
+ startHybBand);
+ if (err != 0) goto bail;
+ break;
+ }
+ }
+
+bail:
+ return err;
+}