/* ----------------------------------------------------------------------------- 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; }