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