aboutsummaryrefslogtreecommitdiffstats
path: root/libSBRdec/src/hbe.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libSBRdec/src/hbe.cpp')
-rw-r--r--libSBRdec/src/hbe.cpp2198
1 files changed, 2198 insertions, 0 deletions
diff --git a/libSBRdec/src/hbe.cpp b/libSBRdec/src/hbe.cpp
new file mode 100644
index 0000000..53b21c9
--- /dev/null
+++ b/libSBRdec/src/hbe.cpp
@@ -0,0 +1,2198 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** SBR decoder library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+/*!
+ \file
+ \brief Fast FFT routines prototypes
+ \author Fabian Haussel
+*/
+
+#include "hbe.h"
+#include "qmf.h"
+#include "env_extr.h"
+
+#define HBE_MAX_QMF_BANDS (40)
+
+#define HBE_MAX_OUT_SLOTS (11)
+
+#define QMF_WIN_LEN \
+ (12 + 6 - 4 - 1) /* 6 subband slots extra delay to align with HQ - 4 slots \
+ to compensate for critical sampling delay - 1 slot to \
+ align critical sampling exactly (w additional time \
+ domain delay)*/
+
+#ifndef PI
+#define PI 3.14159265358979323846
+#endif
+
+static const int xProducts[MAX_STRETCH_HBE - 1] = {
+ 1, 1, 1}; /* Cross products on(1)/off(0) for T=2,3,4. */
+static const int startSubband2kL[33] = {
+ 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6,
+ 6, 8, 8, 8, 8, 8, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12};
+
+static const int pmin = 12;
+
+static const FIXP_DBL hintReal_F[4][3] = {
+ {FL2FXCONST_DBL(0.39840335f), FL2FXCONST_DBL(0.39840335f),
+ FL2FXCONST_DBL(-0.39840335f)},
+ {FL2FXCONST_DBL(0.39840335f), FL2FXCONST_DBL(-0.39840335f),
+ FL2FXCONST_DBL(-0.39840335f)},
+ {FL2FXCONST_DBL(-0.39840335f), FL2FXCONST_DBL(-0.39840335f),
+ FL2FXCONST_DBL(0.39840335f)},
+ {FL2FXCONST_DBL(-0.39840335f), FL2FXCONST_DBL(0.39840335f),
+ FL2FXCONST_DBL(0.39840335f)}};
+
+static const FIXP_DBL factors[4] = {
+ FL2FXCONST_DBL(0.39840335f), FL2FXCONST_DBL(-0.39840335f),
+ FL2FXCONST_DBL(-0.39840335f), FL2FXCONST_DBL(0.39840335f)};
+
+#define PSCALE 32
+
+static const FIXP_DBL p_F[128] = {FL2FXCONST_DBL(0.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(1.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(2.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(3.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(4.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(5.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(6.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(7.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(8.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(9.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(10.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(11.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(12.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(13.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(14.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(15.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(16.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(17.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(18.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(19.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(20.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(21.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(22.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(23.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(24.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(25.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(26.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(27.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(28.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(29.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(30.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(31.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(32.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(33.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(34.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(35.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(36.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(37.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(38.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(39.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(40.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(41.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(42.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(43.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(44.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(45.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(46.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(47.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(48.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(49.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(50.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(51.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(52.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(53.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(54.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(55.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(56.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(57.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(58.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(59.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(60.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(61.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(62.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(63.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(64.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(65.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(66.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(67.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(68.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(69.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(70.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(71.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(72.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(73.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(74.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(75.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(76.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(77.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(78.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(79.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(80.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(81.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(82.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(83.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(84.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(85.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(86.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(87.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(88.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(89.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(90.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(91.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(92.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(93.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(94.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(95.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(96.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(97.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(98.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(99.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(100.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(101.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(102.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(103.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(104.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(105.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(106.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(107.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(108.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(109.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(110.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(111.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(112.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(113.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(114.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(115.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(116.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(117.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(118.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(119.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(120.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(121.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(122.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(123.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(124.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(125.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(126.f / (PSCALE * 12.f)),
+ FL2FXCONST_DBL(127.f / (PSCALE * 12.f))};
+
+static const FIXP_DBL band_F[64] = {
+ FL2FXCONST_DBL((0.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((1.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((2.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((3.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((4.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((5.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((6.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((7.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((8.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((9.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((10.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((11.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((12.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((13.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((14.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((15.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((16.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((17.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((18.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((19.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((20.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((21.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((22.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((23.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((24.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((25.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((26.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((27.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((28.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((29.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((30.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((31.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((32.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((33.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((34.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((35.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((36.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((37.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((38.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((39.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((40.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((41.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((42.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((43.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((44.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((45.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((46.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((47.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((48.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((49.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((50.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((51.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((52.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((53.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((54.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((55.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((56.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((57.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((58.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((59.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((60.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((61.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((62.f * 2.f + 1) / (PSCALE << 2)),
+ FL2FXCONST_DBL((63.f * 2.f + 1) / (PSCALE << 2))};
+
+static const FIXP_DBL tr_str[3] = {FL2FXCONST_DBL(1.f / 4.f),
+ FL2FXCONST_DBL(2.f / 4.f),
+ FL2FXCONST_DBL(3.f / 4.f)};
+
+static const FIXP_DBL stretchfac[3] = {FL2FXCONST_DBL(1.f / 2.f),
+ FL2FXCONST_DBL(1.f / 3.f),
+ FL2FXCONST_DBL(1.f / 4.f)};
+
+static const FIXP_DBL cos_F[64] = {
+ 26353028, -79043208, 131685776, -184244944, 236697216, -289006912,
+ 341142496, -393072608, 444773984, -496191392, 547325824, -598114752,
+ 648559104, -698597248, 748230016, -797411904, 846083200, -894275136,
+ 941928192, -989013760, 1035474624, -1081340672, 1126555136, -1171063296,
+ 1214893696, -1257992192, 1300332544, -1341889408, 1382612736, -1422503808,
+ 1461586944, -1499741440, 1537039104, -1573364864, 1608743808, -1643196672,
+ 1676617344, -1709028992, 1740450560, -1770784896, 1800089472, -1828273536,
+ 1855357440, -1881356288, 1906190080, -1929876608, 1952428928, -1973777664,
+ 1993962880, -2012922240, 2030670208, -2047216000, 2062508288, -2076559488,
+ 2089376128, -2100932224, 2111196800, -2120214784, 2127953792, -2134394368,
+ 2139565056, -2143444864, 2146026624, -2147321856};
+
+static const FIXP_DBL twiddle[121] = {1073741824,
+ 1071442860,
+ 1064555814,
+ 1053110176,
+ 1037154959,
+ 1016758484,
+ 992008094,
+ 963009773,
+ 929887697,
+ 892783698,
+ 851856663,
+ 807281846,
+ 759250125,
+ 707967178,
+ 653652607,
+ 596538995,
+ 536870912,
+ 474903865,
+ 410903207,
+ 345142998,
+ 277904834,
+ 209476638,
+ 140151432,
+ 70226075,
+ 0,
+ -70226075,
+ -140151432,
+ -209476638,
+ -277904834,
+ -345142998,
+ -410903207,
+ -474903865,
+ -536870912,
+ -596538995,
+ -653652607,
+ -707967178,
+ -759250125,
+ -807281846,
+ -851856663,
+ -892783698,
+ -929887697,
+ -963009773,
+ -992008094,
+ -1016758484,
+ -1037154959,
+ -1053110176,
+ -1064555814,
+ -1071442860,
+ -1073741824,
+ -1071442860,
+ -1064555814,
+ -1053110176,
+ -1037154959,
+ -1016758484,
+ -992008094,
+ -963009773,
+ -929887697,
+ -892783698,
+ -851856663,
+ -807281846,
+ -759250125,
+ -707967178,
+ -653652607,
+ -596538995,
+ -536870912,
+ -474903865,
+ -410903207,
+ -345142998,
+ -277904834,
+ -209476638,
+ -140151432,
+ -70226075,
+ 0,
+ 70226075,
+ 140151432,
+ 209476638,
+ 277904834,
+ 345142998,
+ 410903207,
+ 474903865,
+ 536870912,
+ 596538995,
+ 653652607,
+ 707967178,
+ 759250125,
+ 807281846,
+ 851856663,
+ 892783698,
+ 929887697,
+ 963009773,
+ 992008094,
+ 1016758484,
+ 1037154959,
+ 1053110176,
+ 1064555814,
+ 1071442860,
+ 1073741824,
+ 1071442860,
+ 1064555814,
+ 1053110176,
+ 1037154959,
+ 1016758484,
+ 992008094,
+ 963009773,
+ 929887697,
+ 892783698,
+ 851856663,
+ 807281846,
+ 759250125,
+ 707967178,
+ 653652607,
+ 596538995,
+ 536870912,
+ 474903865,
+ 410903207,
+ 345142998,
+ 277904834,
+ 209476638,
+ 140151432,
+ 70226075,
+ 0};
+
+#if FIXP_QTW == FIXP_SGL
+#define HTW(x) (x)
+#else
+#define HTW(x) FX_DBL2FX_QTW(FX_SGL2FX_DBL((const FIXP_SGL)x))
+#endif
+
+static const FIXP_QTW post_twiddle_cos_8[8] = {
+ HTW(-1606), HTW(4756), HTW(-7723), HTW(10394),
+ HTW(-12665), HTW(14449), HTW(-15679), HTW(16305)};
+
+static const FIXP_QTW post_twiddle_cos_16[16] = {
+ HTW(-804), HTW(2404), HTW(-3981), HTW(5520), HTW(-7005), HTW(8423),
+ HTW(-9760), HTW(11003), HTW(-12140), HTW(13160), HTW(-14053), HTW(14811),
+ HTW(-15426), HTW(15893), HTW(-16207), HTW(16364)};
+
+static const FIXP_QTW post_twiddle_cos_24[24] = {
+ HTW(-536), HTW(1606), HTW(-2669), HTW(3720), HTW(-4756), HTW(5771),
+ HTW(-6762), HTW(7723), HTW(-8652), HTW(9543), HTW(-10394), HTW(11200),
+ HTW(-11958), HTW(12665), HTW(-13318), HTW(13913), HTW(-14449), HTW(14924),
+ HTW(-15334), HTW(15679), HTW(-15956), HTW(16165), HTW(-16305), HTW(16375)};
+
+static const FIXP_QTW post_twiddle_cos_32[32] = {
+ HTW(-402), HTW(1205), HTW(-2006), HTW(2801), HTW(-3590), HTW(4370),
+ HTW(-5139), HTW(5897), HTW(-6639), HTW(7366), HTW(-8076), HTW(8765),
+ HTW(-9434), HTW(10080), HTW(-10702), HTW(11297), HTW(-11866), HTW(12406),
+ HTW(-12916), HTW(13395), HTW(-13842), HTW(14256), HTW(-14635), HTW(14978),
+ HTW(-15286), HTW(15557), HTW(-15791), HTW(15986), HTW(-16143), HTW(16261),
+ HTW(-16340), HTW(16379)};
+
+static const FIXP_QTW post_twiddle_cos_40[40] = {
+ HTW(-322), HTW(965), HTW(-1606), HTW(2245), HTW(-2880), HTW(3511),
+ HTW(-4137), HTW(4756), HTW(-5368), HTW(5971), HTW(-6566), HTW(7150),
+ HTW(-7723), HTW(8285), HTW(-8833), HTW(9368), HTW(-9889), HTW(10394),
+ HTW(-10883), HTW(11356), HTW(-11810), HTW(12247), HTW(-12665), HTW(13063),
+ HTW(-13441), HTW(13799), HTW(-14135), HTW(14449), HTW(-14741), HTW(15011),
+ HTW(-15257), HTW(15480), HTW(-15679), HTW(15853), HTW(-16003), HTW(16129),
+ HTW(-16229), HTW(16305), HTW(-16356), HTW(16381)};
+
+static const FIXP_QTW post_twiddle_sin_8[8] = {
+ HTW(16305), HTW(-15679), HTW(14449), HTW(-12665),
+ HTW(10394), HTW(-7723), HTW(4756), HTW(-1606)};
+
+static const FIXP_QTW post_twiddle_sin_16[16] = {
+ HTW(16364), HTW(-16207), HTW(15893), HTW(-15426), HTW(14811), HTW(-14053),
+ HTW(13160), HTW(-12140), HTW(11003), HTW(-9760), HTW(8423), HTW(-7005),
+ HTW(5520), HTW(-3981), HTW(2404), HTW(-804)};
+
+static const FIXP_QTW post_twiddle_sin_24[24] = {
+ HTW(16375), HTW(-16305), HTW(16165), HTW(-15956), HTW(15679), HTW(-15334),
+ HTW(14924), HTW(-14449), HTW(13913), HTW(-13318), HTW(12665), HTW(-11958),
+ HTW(11200), HTW(-10394), HTW(9543), HTW(-8652), HTW(7723), HTW(-6762),
+ HTW(5771), HTW(-4756), HTW(3720), HTW(-2669), HTW(1606), HTW(-536)};
+
+static const FIXP_QTW post_twiddle_sin_32[32] = {
+ HTW(16379), HTW(-16340), HTW(16261), HTW(-16143), HTW(15986), HTW(-15791),
+ HTW(15557), HTW(-15286), HTW(14978), HTW(-14635), HTW(14256), HTW(-13842),
+ HTW(13395), HTW(-12916), HTW(12406), HTW(-11866), HTW(11297), HTW(-10702),
+ HTW(10080), HTW(-9434), HTW(8765), HTW(-8076), HTW(7366), HTW(-6639),
+ HTW(5897), HTW(-5139), HTW(4370), HTW(-3590), HTW(2801), HTW(-2006),
+ HTW(1205), HTW(-402)};
+
+static const FIXP_QTW post_twiddle_sin_40[40] = {
+ HTW(16381), HTW(-16356), HTW(16305), HTW(-16229), HTW(16129), HTW(-16003),
+ HTW(15853), HTW(-15679), HTW(15480), HTW(-15257), HTW(15011), HTW(-14741),
+ HTW(14449), HTW(-14135), HTW(13799), HTW(-13441), HTW(13063), HTW(-12665),
+ HTW(12247), HTW(-11810), HTW(11356), HTW(-10883), HTW(10394), HTW(-9889),
+ HTW(9368), HTW(-8833), HTW(8285), HTW(-7723), HTW(7150), HTW(-6566),
+ HTW(5971), HTW(-5368), HTW(4756), HTW(-4137), HTW(3511), HTW(-2880),
+ HTW(2245), HTW(-1606), HTW(965), HTW(-322)};
+
+static const FIXP_DBL preModCos[32] = {
+ -749875776, 786681536, 711263552, -821592064, -670937792, 854523392,
+ 628995648, -885396032, -585538240, 914135680, 540670208, -940673088,
+ -494499680, 964944384, 447137824, -986891008, -398698816, 1006460096,
+ 349299264, -1023604544, -299058240, 1038283072, 248096752, -1050460288,
+ -196537584, 1060106816, 144504928, -1067199488, -92124160, 1071721152,
+ 39521456, -1073660992};
+
+static const FIXP_DBL preModSin[32] = {
+ 768510144, 730789760, -804379072, -691308864, 838310208, 650162560,
+ -870221760, -607449920, 900036928, 563273856, -927683776, -517740896,
+ 953095808, 470960608, -976211712, -423045728, 996975808, 374111712,
+ -1015338112, -324276416, 1031254400, 273659904, -1044686336, -222384144,
+ 1055601472, 170572640, -1063973632, -118350192, 1069782528, 65842640,
+ -1073014208, -13176464};
+
+/* The cube root function */
+/*****************************************************************************
+
+ functionname: invCubeRootNorm2
+ description: delivers 1/cuberoot(op) in Q1.31 format and modified exponent
+
+*****************************************************************************/
+#define CUBE_ROOT_BITS 7
+#define CUBE_ROOT_VALUES (128 + 2)
+#define CUBE_ROOT_BITS_MASK 0x7f
+#define CUBE_ROOT_FRACT_BITS_MASK 0x007FFFFF
+/* Inverse cube root table for operands running from 0.5 to 1.0 */
+/* (INT) (1.0/cuberoot((op))); */
+/* Implicit exponent is 1. */
+
+LNK_SECTION_CONSTDATA
+static const FIXP_DBL invCubeRootTab[CUBE_ROOT_VALUES] = {
+ (0x50a28be6), (0x506d1172), (0x503823c4), (0x5003c05a), (0x4fcfe4c0),
+ (0x4f9c8e92), (0x4f69bb7d), (0x4f37693b), (0x4f059594), (0x4ed43e5f),
+ (0x4ea36181), (0x4e72fcea), (0x4e430e98), (0x4e139495), (0x4de48cf5),
+ (0x4db5f5db), (0x4d87cd73), (0x4d5a11f2), (0x4d2cc19c), (0x4cffdabb),
+ (0x4cd35ba4), (0x4ca742b7), (0x4c7b8e5c), (0x4c503d05), (0x4c254d2a),
+ (0x4bfabd50), (0x4bd08c00), (0x4ba6b7cd), (0x4b7d3f53), (0x4b542134),
+ (0x4b2b5c18), (0x4b02eeb1), (0x4adad7b8), (0x4ab315ea), (0x4a8ba80d),
+ (0x4a648cec), (0x4a3dc35b), (0x4a174a30), (0x49f1204a), (0x49cb448d),
+ (0x49a5b5e2), (0x49807339), (0x495b7b86), (0x4936cdc2), (0x491268ec),
+ (0x48ee4c08), (0x48ca761f), (0x48a6e63e), (0x48839b76), (0x486094de),
+ (0x483dd190), (0x481b50ad), (0x47f91156), (0x47d712b3), (0x47b553f0),
+ (0x4793d43c), (0x477292c9), (0x47518ece), (0x4730c785), (0x47103c2d),
+ (0x46efec06), (0x46cfd655), (0x46affa61), (0x46905777), (0x4670ece4),
+ (0x4651b9f9), (0x4632be0b), (0x4613f871), (0x45f56885), (0x45d70da5),
+ (0x45b8e72f), (0x459af487), (0x457d3511), (0x455fa835), (0x45424d5d),
+ (0x452523f6), (0x45082b6e), (0x44eb6337), (0x44cecac5), (0x44b2618d),
+ (0x44962708), (0x447a1ab1), (0x445e3c02), (0x44428a7c), (0x4427059e),
+ (0x440bacec), (0x43f07fe9), (0x43d57e1c), (0x43baa70e), (0x439ffa48),
+ (0x43857757), (0x436b1dc8), (0x4350ed2b), (0x4336e511), (0x431d050c),
+ (0x43034cb2), (0x42e9bb98), (0x42d05156), (0x42b70d85), (0x429defc0),
+ (0x4284f7a2), (0x426c24cb), (0x425376d8), (0x423aed6a), (0x42228823),
+ (0x420a46a6), (0x41f22898), (0x41da2d9f), (0x41c25561), (0x41aa9f86),
+ (0x41930bba), (0x417b99a5), (0x416448f5), (0x414d1956), (0x41360a76),
+ (0x411f1c06), (0x41084db5), (0x40f19f35), (0x40db1039), (0x40c4a074),
+ (0x40ae4f9b), (0x40981d64), (0x40820985), (0x406c13b6), (0x40563bb1),
+ (0x4040812e), (0x402ae3e7), (0x40156399), (0x40000000), (0x3FEAB8D9)};
+/* n.a. */
+static const FIXP_DBL invCubeRootCorrection[3] = {0x40000000, 0x50A28BE6,
+ 0x6597FA95};
+
+/*****************************************************************************
+ * \brief calculate 1.0/cube_root(op), op contains mantissa and exponent
+ * \param op_m: (i) mantissa of operand, must not be zero (0x0000.0000) or
+ * negative
+ * \param op_e: (i) pointer to the exponent of the operand (must be initialized)
+ * and .. (o) pointer to the exponent of the result
+ * \return: (o) mantissa of the result
+ * \description:
+ * This routine calculates the cube root of the input operand, that is
+ * given with its mantissa in Q31 format (FIXP_DBL) and its exponent (INT).
+ * The resulting mantissa is returned in format Q31. The exponent (*op_e)
+ * is modified accordingly. It is not assured, that the result is fully
+ * left-aligned but assumed to have not more than 2 bits headroom. There is one
+ * macro to activate the use of this algorithm: FUNCTION_invCubeRootNorm2 By
+ * means of activating the macro INVCUBEROOTNORM2_LINEAR_INTERPOLATE_HQ, a
+ * slightly higher precision is reachable (by default, not active). For DEBUG
+ * purpose only: a FDK_ASSERT macro validates, if the input mantissa is greater
+ * zero.
+ *
+ */
+static
+#ifdef __arm__
+ FIXP_DBL __attribute__((always_inline))
+ invCubeRootNorm2(FIXP_DBL op_m, INT* op_e)
+#else
+ FIXP_DBL
+ invCubeRootNorm2(FIXP_DBL op_m, INT* op_e)
+#endif
+{
+ FDK_ASSERT(op_m > FIXP_DBL(0));
+
+ /* normalize input, calculate shift value */
+ INT exponent = (INT)fNormz(op_m) - 1;
+ op_m <<= exponent;
+
+ INT index = (INT)(op_m >> (DFRACT_BITS - 1 - (CUBE_ROOT_BITS + 1))) &
+ CUBE_ROOT_BITS_MASK;
+ FIXP_DBL fract = (FIXP_DBL)(((INT)op_m & CUBE_ROOT_FRACT_BITS_MASK)
+ << (CUBE_ROOT_BITS + 1));
+ FIXP_DBL diff = invCubeRootTab[index + 1] - invCubeRootTab[index];
+ op_m = fMultAddDiv2(invCubeRootTab[index], diff << 1, fract);
+#if defined(INVCUBEROOTNORM2_LINEAR_INTERPOLATE_HQ)
+ /* reg1 = t[i] + (t[i+1]-t[i])*fract ... already computed ... +
+ * (1-fract)fract*(t[i+2]-t[i+1])/2 */
+ if (fract != (FIXP_DBL)0) {
+ /* fract = fract * (1 - fract) */
+ fract = fMultDiv2(fract, (FIXP_DBL)((LONG)0x80000000 - (LONG)fract)) << 1;
+ diff = diff - (invCubeRootTab[index + 2] - invCubeRootTab[index + 1]);
+ op_m = fMultAddDiv2(op_m, fract, diff);
+ }
+#endif /* INVCUBEROOTNORM2_LINEAR_INTERPOLATE_HQ */
+
+ /* calculate the output exponent = input * exp/3 = cubicroot(m)*2^(exp/3)
+ * where 2^(exp/3) = 2^k'*2 or 2^k'*2^(1/3) or 2^k'*2^(2/3) */
+ exponent = exponent - *op_e + 3;
+ INT shift_tmp =
+ ((INT)fMultDiv2((FIXP_SGL)fAbs(exponent), (FIXP_SGL)0x5556)) >> 16;
+ if (exponent < 0) {
+ shift_tmp = -shift_tmp;
+ }
+ INT rem = exponent - 3 * shift_tmp;
+ if (rem < 0) {
+ rem += 3;
+ shift_tmp--;
+ }
+
+ *op_e = shift_tmp;
+ op_m = fMultDiv2(op_m, invCubeRootCorrection[rem]) << 2;
+
+ return (op_m);
+}
+
+ /*****************************************************************************
+
+ functionname: invFourthRootNorm2
+ description: delivers 1/FourthRoot(op) in Q1.31 format and modified
+ exponent
+
+ *****************************************************************************/
+
+#define FOURTHROOT_BITS 7
+#define FOURTHROOT_VALUES (128 + 2)
+#define FOURTHROOT_BITS_MASK 0x7f
+#define FOURTHROOT_FRACT_BITS_MASK 0x007FFFFF
+
+LNK_SECTION_CONSTDATA
+static const FIXP_DBL invFourthRootTab[FOURTHROOT_VALUES] = {
+ (0x4c1bf829), (0x4bf61977), (0x4bd09843), (0x4bab72ef), (0x4b86a7eb),
+ (0x4b6235ac), (0x4b3e1ab6), (0x4b1a5592), (0x4af6e4d4), (0x4ad3c718),
+ (0x4ab0fb03), (0x4a8e7f42), (0x4a6c5288), (0x4a4a7393), (0x4a28e126),
+ (0x4a079a0c), (0x49e69d16), (0x49c5e91f), (0x49a57d04), (0x498557ac),
+ (0x49657802), (0x4945dcf9), (0x49268588), (0x490770ac), (0x48e89d6a),
+ (0x48ca0ac9), (0x48abb7d6), (0x488da3a6), (0x486fcd4f), (0x485233ed),
+ (0x4834d6a3), (0x4817b496), (0x47faccf0), (0x47de1ee0), (0x47c1a999),
+ (0x47a56c51), (0x47896643), (0x476d96af), (0x4751fcd6), (0x473697ff),
+ (0x471b6773), (0x47006a81), (0x46e5a079), (0x46cb08ae), (0x46b0a279),
+ (0x46966d34), (0x467c683d), (0x466292f4), (0x4648ecbc), (0x462f74fe),
+ (0x46162b20), (0x45fd0e91), (0x45e41ebe), (0x45cb5b19), (0x45b2c315),
+ (0x459a562a), (0x458213cf), (0x4569fb81), (0x45520cbc), (0x453a4701),
+ (0x4522a9d1), (0x450b34b0), (0x44f3e726), (0x44dcc0ba), (0x44c5c0f7),
+ (0x44aee768), (0x4498339e), (0x4481a527), (0x446b3b96), (0x4454f67e),
+ (0x443ed576), (0x4428d815), (0x4412fdf3), (0x43fd46ad), (0x43e7b1de),
+ (0x43d23f23), (0x43bcee1e), (0x43a7be6f), (0x4392afb8), (0x437dc19d),
+ (0x4368f3c5), (0x435445d6), (0x433fb779), (0x432b4856), (0x4316f81a),
+ (0x4302c66f), (0x42eeb305), (0x42dabd8a), (0x42c6e5ad), (0x42b32b21),
+ (0x429f8d96), (0x428c0cc2), (0x4278a859), (0x42656010), (0x4252339e),
+ (0x423f22bc), (0x422c2d23), (0x4219528b), (0x420692b2), (0x41f3ed51),
+ (0x41e16228), (0x41cef0f2), (0x41bc9971), (0x41aa5b62), (0x41983687),
+ (0x41862aa2), (0x41743775), (0x41625cc3), (0x41509a50), (0x413eefe2),
+ (0x412d5d3e), (0x411be22b), (0x410a7e70), (0x40f931d5), (0x40e7fc23),
+ (0x40d6dd24), (0x40c5d4a2), (0x40b4e268), (0x40a40642), (0x40933ffc),
+ (0x40828f64), (0x4071f447), (0x40616e73), (0x4050fdb9), (0x4040a1e6),
+ (0x40305acc), (0x4020283c), (0x40100a08), (0x40000000), (0x3ff009f9),
+};
+
+static const FIXP_DBL invFourthRootCorrection[4] = {0x40000000, 0x4C1BF829,
+ 0x5A82799A, 0x6BA27E65};
+
+/* The fourth root function */
+/*****************************************************************************
+ * \brief calculate 1.0/fourth_root(op), op contains mantissa and exponent
+ * \param op_m: (i) mantissa of operand, must not be zero (0x0000.0000) or
+ * negative
+ * \param op_e: (i) pointer to the exponent of the operand (must be initialized)
+ * and .. (o) pointer to the exponent of the result
+ * \return: (o) mantissa of the result
+ * \description:
+ * This routine calculates the cube root of the input operand, that is
+ * given with its mantissa in Q31 format (FIXP_DBL) and its exponent (INT).
+ * The resulting mantissa is returned in format Q31. The exponent (*op_e)
+ * is modified accordingly. It is not assured, that the result is fully
+ * left-aligned but assumed to have not more than 2 bits headroom. There is one
+ * macro to activate the use of this algorithm: FUNCTION_invFourthRootNorm2 By
+ * means of activating the macro INVFOURTHROOTNORM2_LINEAR_INTERPOLATE_HQ, a
+ * slightly higher precision is reachable (by default, not active). For DEBUG
+ * purpose only: a FDK_ASSERT macro validates, if the input mantissa is greater
+ * zero.
+ *
+ */
+
+/* #define INVFOURTHROOTNORM2_LINEAR_INTERPOLATE_HQ */
+
+static
+#ifdef __arm__
+ FIXP_DBL __attribute__((always_inline))
+ invFourthRootNorm2(FIXP_DBL op_m, INT* op_e)
+#else
+ FIXP_DBL
+ invFourthRootNorm2(FIXP_DBL op_m, INT* op_e)
+#endif
+{
+ FDK_ASSERT(op_m > FL2FXCONST_DBL(0.0));
+
+ /* normalize input, calculate shift value */
+ INT exponent = (INT)fNormz(op_m) - 1;
+ op_m <<= exponent;
+
+ INT index = (INT)(op_m >> (DFRACT_BITS - 1 - (FOURTHROOT_BITS + 1))) &
+ FOURTHROOT_BITS_MASK;
+ FIXP_DBL fract = (FIXP_DBL)(((INT)op_m & FOURTHROOT_FRACT_BITS_MASK)
+ << (FOURTHROOT_BITS + 1));
+ FIXP_DBL diff = invFourthRootTab[index + 1] - invFourthRootTab[index];
+ op_m = invFourthRootTab[index] + (fMultDiv2(diff, fract) << 1);
+
+#if defined(INVFOURTHROOTNORM2_LINEAR_INTERPOLATE_HQ)
+ /* reg1 = t[i] + (t[i+1]-t[i])*fract ... already computed ... +
+ * (1-fract)fract*(t[i+2]-t[i+1])/2 */
+ if (fract != (FIXP_DBL)0) {
+ /* fract = fract * (1 - fract) */
+ fract = fMultDiv2(fract, (FIXP_DBL)((LONG)0x80000000 - (LONG)fract)) << 1;
+ diff = diff - (invFourthRootTab[index + 2] - invFourthRootTab[index + 1]);
+ op_m = fMultAddDiv2(op_m, fract, diff);
+ }
+#endif /* INVFOURTHROOTNORM2_LINEAR_INTERPOLATE_HQ */
+
+ exponent = exponent - *op_e + 4;
+ INT rem = exponent & 0x00000003;
+ INT shift_tmp = (exponent >> 2);
+
+ *op_e = shift_tmp;
+ op_m = fMultDiv2(op_m, invFourthRootCorrection[rem]) << 2;
+
+ return (op_m);
+}
+
+/*****************************************************************************
+
+ functionname: inv3EigthRootNorm2
+ description: delivers 1/cubert(op) normalized to .5...1 and the shift value
+of the OUTPUT
+
+*****************************************************************************/
+#define THREEIGTHROOT_BITS 7
+#define THREEIGTHROOT_VALUES (128 + 2)
+#define THREEIGTHROOT_BITS_MASK 0x7f
+#define THREEIGTHROOT_FRACT_BITS_MASK 0x007FFFFF
+
+LNK_SECTION_CONSTDATA
+static const FIXP_DBL inv3EigthRootTab[THREEIGTHROOT_VALUES] = {
+ (0x45cae0f2), (0x45b981bf), (0x45a8492a), (0x45973691), (0x45864959),
+ (0x457580e6), (0x4564dca4), (0x45545c00), (0x4543fe6b), (0x4533c35a),
+ (0x4523aa44), (0x4513b2a4), (0x4503dbf7), (0x44f425be), (0x44e48f7b),
+ (0x44d518b6), (0x44c5c0f7), (0x44b687c8), (0x44a76cb8), (0x44986f58),
+ (0x44898f38), (0x447acbef), (0x446c2514), (0x445d9a3f), (0x444f2b0d),
+ (0x4440d71a), (0x44329e07), (0x44247f73), (0x44167b04), (0x4408905e),
+ (0x43fabf28), (0x43ed070b), (0x43df67b0), (0x43d1e0c5), (0x43c471f7),
+ (0x43b71af6), (0x43a9db71), (0x439cb31c), (0x438fa1ab), (0x4382a6d2),
+ (0x4375c248), (0x4368f3c5), (0x435c3b03), (0x434f97bc), (0x434309ac),
+ (0x43369091), (0x432a2c28), (0x431ddc30), (0x4311a06c), (0x4305789c),
+ (0x42f96483), (0x42ed63e5), (0x42e17688), (0x42d59c30), (0x42c9d4a6),
+ (0x42be1fb1), (0x42b27d1a), (0x42a6ecac), (0x429b6e2f), (0x42900172),
+ (0x4284a63f), (0x42795c64), (0x426e23b0), (0x4262fbf2), (0x4257e4f9),
+ (0x424cde96), (0x4241e89a), (0x423702d8), (0x422c2d23), (0x4221674d),
+ (0x4216b12c), (0x420c0a94), (0x4201735b), (0x41f6eb57), (0x41ec725f),
+ (0x41e2084b), (0x41d7acf3), (0x41cd6030), (0x41c321db), (0x41b8f1ce),
+ (0x41aecfe5), (0x41a4bbf8), (0x419ab5e6), (0x4190bd89), (0x4186d2bf),
+ (0x417cf565), (0x41732558), (0x41696277), (0x415faca1), (0x415603b4),
+ (0x414c6792), (0x4142d818), (0x4139552a), (0x412fdea6), (0x41267470),
+ (0x411d1668), (0x4113c472), (0x410a7e70), (0x41014445), (0x40f815d4),
+ (0x40eef302), (0x40e5dbb4), (0x40dccfcd), (0x40d3cf33), (0x40cad9cb),
+ (0x40c1ef7b), (0x40b9102a), (0x40b03bbd), (0x40a7721c), (0x409eb32e),
+ (0x4095feda), (0x408d5508), (0x4084b5a0), (0x407c208b), (0x407395b2),
+ (0x406b14fd), (0x40629e56), (0x405a31a6), (0x4051ced8), (0x404975d5),
+ (0x40412689), (0x4038e0dd), (0x4030a4bd), (0x40287215), (0x402048cf),
+ (0x401828d7), (0x4010121a), (0x40080483), (0x40000000), (0x3ff8047d),
+};
+
+/* The last value is rounded in order to avoid any overflow due to the values
+ * range of the root table */
+static const FIXP_DBL inv3EigthRootCorrection[8] = {
+ 0x40000000, 0x45CAE0F2, 0x4C1BF829, 0x52FF6B55,
+ 0x5A82799A, 0x62B39509, 0x6BA27E65, 0x75606373};
+
+/* The 3/8 root function */
+/*****************************************************************************
+ * \brief calculate 1.0/3Eigth_root(op) = 1.0/(x)^(3/8), op contains mantissa
+ * and exponent
+ * \param op_m: (i) mantissa of operand, must not be zero (0x0000.0000) or
+ * negative
+ * \param op_e: (i) pointer to the exponent of the operand (must be initialized)
+ * and .. (o) pointer to the exponent of the result
+ * \return: (o) mantissa of the result
+ * \description:
+ * This routine calculates the cube root of the input operand, that is
+ * given with its mantissa in Q31 format (FIXP_DBL) and its exponent (INT).
+ * The resulting mantissa is returned in format Q31. The exponent (*op_e)
+ * is modified accordingly. It is not assured, that the result is fully
+ * left-aligned but assumed to have not more than 2 bits headroom. There is one
+ * macro to activate the use of this algorithm: FUNCTION_inv3EigthRootNorm2 By
+ * means of activating the macro INVTHREEIGTHROOTNORM2_LINEAR_INTERPOLATE_HQ, a
+ * slightly higher precision is reachable (by default, not active). For DEBUG
+ * purpose only: a FDK_ASSERT macro validates, if the input mantissa is greater
+ * zero.
+ *
+ */
+
+/* #define INVTHREEIGTHROOTNORM2_LINEAR_INTERPOLATE_HQ */
+
+static
+#ifdef __arm__
+ FIXP_DBL __attribute__((always_inline))
+ inv3EigthRootNorm2(FIXP_DBL op_m, INT* op_e)
+#else
+ FIXP_DBL
+ inv3EigthRootNorm2(FIXP_DBL op_m, INT* op_e)
+#endif
+{
+ FDK_ASSERT(op_m > FL2FXCONST_DBL(0.0));
+
+ /* normalize input, calculate shift op_mue */
+ INT exponent = (INT)fNormz(op_m) - 1;
+ op_m <<= exponent;
+
+ INT index = (INT)(op_m >> (DFRACT_BITS - 1 - (THREEIGTHROOT_BITS + 1))) &
+ THREEIGTHROOT_BITS_MASK;
+ FIXP_DBL fract = (FIXP_DBL)(((INT)op_m & THREEIGTHROOT_FRACT_BITS_MASK)
+ << (THREEIGTHROOT_BITS + 1));
+ FIXP_DBL diff = inv3EigthRootTab[index + 1] - inv3EigthRootTab[index];
+ op_m = inv3EigthRootTab[index] + (fMultDiv2(diff, fract) << 1);
+
+#if defined(INVTHREEIGTHROOTNORM2_LINEAR_INTERPOLATE_HQ)
+ /* op_m = t[i] + (t[i+1]-t[i])*fract ... already computed ... +
+ * (1-fract)fract*(t[i+2]-t[i+1])/2 */
+ if (fract != (FIXP_DBL)0) {
+ /* fract = fract * (1 - fract) */
+ fract = fMultDiv2(fract, (FIXP_DBL)((LONG)0x80000000 - (LONG)fract)) << 1;
+ diff = diff - (inv3EigthRootTab[index + 2] - inv3EigthRootTab[index + 1]);
+ op_m = fMultAddDiv2(op_m, fract, diff);
+ }
+#endif /* INVTHREEIGTHROOTNORM2_LINEAR_INTERPOLATE_HQ */
+
+ exponent = exponent - *op_e + 8;
+ INT rem = exponent & 0x00000007;
+ INT shift_tmp = (exponent >> 3);
+
+ *op_e = shift_tmp * 3;
+ op_m = fMultDiv2(op_m, inv3EigthRootCorrection[rem]) << 2;
+
+ return (fMult(op_m, fMult(op_m, op_m)));
+}
+
+SBR_ERROR
+QmfTransposerCreate(HANDLE_HBE_TRANSPOSER* hQmfTransposer, const int frameSize,
+ int bDisableCrossProducts, int bSbr41) {
+ HANDLE_HBE_TRANSPOSER hQmfTran = NULL;
+
+ int i;
+
+ if (hQmfTransposer != NULL) {
+ /* Memory allocation */
+ /*--------------------------------------------------------------------------------------------*/
+ hQmfTran =
+ (HANDLE_HBE_TRANSPOSER)FDKcalloc(1, sizeof(struct hbeTransposer));
+ if (hQmfTran == NULL) {
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ for (i = 0; i < MAX_STRETCH_HBE - 1; i++) {
+ hQmfTran->bXProducts[i] = (bDisableCrossProducts ? 0 : xProducts[i]);
+ }
+
+ hQmfTran->timeDomainWinLen = frameSize;
+ if (frameSize == 768) {
+ hQmfTran->noCols =
+ (8 * frameSize / 3) / QMF_SYNTH_CHANNELS; /* 32 for 24:64 */
+ } else {
+ hQmfTran->noCols =
+ (bSbr41 + 1) * 2 * frameSize /
+ QMF_SYNTH_CHANNELS; /* 32 for 32:64 and 64 for 16:64 -> identical to
+ sbrdec->no_cols */
+ }
+
+ hQmfTran->noChannels = frameSize / hQmfTran->noCols;
+
+ hQmfTran->qmfInBufSize = QMF_WIN_LEN;
+ hQmfTran->qmfOutBufSize = 2 * (hQmfTran->noCols / 2 + QMF_WIN_LEN - 1);
+
+ hQmfTran->inBuf_F =
+ (INT_PCM*)FDKcalloc(QMF_SYNTH_CHANNELS + 20 + 1, sizeof(INT_PCM));
+ /* buffered time signal needs to be delayed by synthesis_size; max
+ * synthesis_size = 20; */
+ if (hQmfTran->inBuf_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ hQmfTran->qmfInBufReal_F =
+ (FIXP_DBL**)FDKcalloc(hQmfTran->qmfInBufSize, sizeof(FIXP_DBL*));
+ hQmfTran->qmfInBufImag_F =
+ (FIXP_DBL**)FDKcalloc(hQmfTran->qmfInBufSize, sizeof(FIXP_DBL*));
+
+ if (hQmfTran->qmfInBufReal_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ if (hQmfTran->qmfInBufImag_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ for (i = 0; i < hQmfTran->qmfInBufSize; i++) {
+ hQmfTran->qmfInBufReal_F[i] = (FIXP_DBL*)FDKaalloc(
+ QMF_SYNTH_CHANNELS * sizeof(FIXP_DBL), ALIGNMENT_DEFAULT);
+ hQmfTran->qmfInBufImag_F[i] = (FIXP_DBL*)FDKaalloc(
+ QMF_SYNTH_CHANNELS * sizeof(FIXP_DBL), ALIGNMENT_DEFAULT);
+ if (hQmfTran->qmfInBufReal_F[i] == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ if (hQmfTran->qmfInBufImag_F[i] == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ }
+
+ hQmfTran->qmfHBEBufReal_F =
+ (FIXP_DBL**)FDKcalloc(HBE_MAX_OUT_SLOTS, sizeof(FIXP_DBL*));
+ hQmfTran->qmfHBEBufImag_F =
+ (FIXP_DBL**)FDKcalloc(HBE_MAX_OUT_SLOTS, sizeof(FIXP_DBL*));
+
+ if (hQmfTran->qmfHBEBufReal_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ if (hQmfTran->qmfHBEBufImag_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ for (i = 0; i < HBE_MAX_OUT_SLOTS; i++) {
+ hQmfTran->qmfHBEBufReal_F[i] =
+ (FIXP_DBL*)FDKcalloc(QMF_SYNTH_CHANNELS, sizeof(FIXP_DBL));
+ hQmfTran->qmfHBEBufImag_F[i] =
+ (FIXP_DBL*)FDKcalloc(QMF_SYNTH_CHANNELS, sizeof(FIXP_DBL));
+ if (hQmfTran->qmfHBEBufReal_F[i] == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ if (hQmfTran->qmfHBEBufImag_F[i] == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+ }
+
+ hQmfTran->qmfBufferCodecTempSlot_F =
+ (FIXP_DBL*)FDKcalloc(QMF_SYNTH_CHANNELS / 2, sizeof(FIXP_DBL));
+ if (hQmfTran->qmfBufferCodecTempSlot_F == NULL) {
+ QmfTransposerClose(hQmfTran);
+ return SBRDEC_MEM_ALLOC_FAILED;
+ }
+
+ hQmfTran->bSbr41 = bSbr41;
+
+ hQmfTran->highband_exp[0] = 0;
+ hQmfTran->highband_exp[1] = 0;
+ hQmfTran->target_exp[0] = 0;
+ hQmfTran->target_exp[1] = 0;
+
+ *hQmfTransposer = hQmfTran;
+ }
+
+ return SBRDEC_OK;
+}
+
+SBR_ERROR QmfTransposerReInit(HANDLE_HBE_TRANSPOSER hQmfTransposer,
+ UCHAR* FreqBandTable[2], UCHAR NSfb[2])
+/* removed bSbr41 from parameterlist:
+ don't know where to get this value from
+ at call-side */
+{
+ int L, sfb, patch, stopPatch, qmfErr;
+
+ if (hQmfTransposer != NULL) {
+ const FIXP_QTW* tmp_t_cos;
+ const FIXP_QTW* tmp_t_sin;
+
+ hQmfTransposer->startBand = FreqBandTable[0][0];
+ hQmfTransposer->stopBand = FreqBandTable[0][NSfb[0]];
+
+ hQmfTransposer->synthSize =
+ 4 * ((hQmfTransposer->startBand + 4) / 8 + 1); /* 8, 12, 16, 20 */
+ hQmfTransposer->kstart = startSubband2kL[hQmfTransposer->startBand];
+
+ /* don't know where to take this information from */
+ /* hQmfTransposer->bSbr41 = bSbr41; */
+
+ if (hQmfTransposer->bSbr41) {
+ if (hQmfTransposer->kstart + hQmfTransposer->synthSize > 16)
+ hQmfTransposer->kstart = 16 - hQmfTransposer->synthSize;
+ } else if (hQmfTransposer->timeDomainWinLen == 768) {
+ if (hQmfTransposer->kstart + hQmfTransposer->synthSize > 24)
+ hQmfTransposer->kstart = 24 - hQmfTransposer->synthSize;
+ }
+
+ hQmfTransposer->synthesisQmfPreModCos_F =
+ &preModCos[hQmfTransposer->kstart];
+ hQmfTransposer->synthesisQmfPreModSin_F =
+ &preModSin[hQmfTransposer->kstart];
+
+ L = 2 * hQmfTransposer->synthSize; /* 8, 16, 24, 32, 40 */
+ /* Change analysis post twiddles */
+
+ switch (L) {
+ case 8:
+ tmp_t_cos = post_twiddle_cos_8;
+ tmp_t_sin = post_twiddle_sin_8;
+ break;
+ case 16:
+ tmp_t_cos = post_twiddle_cos_16;
+ tmp_t_sin = post_twiddle_sin_16;
+ break;
+ case 24:
+ tmp_t_cos = post_twiddle_cos_24;
+ tmp_t_sin = post_twiddle_sin_24;
+ break;
+ case 32:
+ tmp_t_cos = post_twiddle_cos_32;
+ tmp_t_sin = post_twiddle_sin_32;
+ break;
+ case 40:
+ tmp_t_cos = post_twiddle_cos_40;
+ tmp_t_sin = post_twiddle_sin_40;
+ break;
+ default:
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ qmfErr = qmfInitSynthesisFilterBank(
+ &hQmfTransposer->HBESynthesisQMF, hQmfTransposer->synQmfStates,
+ hQmfTransposer->noCols, 0, hQmfTransposer->synthSize,
+ hQmfTransposer->synthSize, 1);
+ if (qmfErr != 0) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ qmfErr = qmfInitAnalysisFilterBank(
+ &hQmfTransposer->HBEAnalysiscQMF, hQmfTransposer->anaQmfStates,
+ hQmfTransposer->noCols / 2, 0, 2 * hQmfTransposer->synthSize,
+ 2 * hQmfTransposer->synthSize, 0);
+
+ if (qmfErr != 0) {
+ return SBRDEC_UNSUPPORTED_CONFIG;
+ }
+
+ hQmfTransposer->HBEAnalysiscQMF.t_cos = tmp_t_cos;
+ hQmfTransposer->HBEAnalysiscQMF.t_sin = tmp_t_sin;
+
+ FDKmemset(hQmfTransposer->xOverQmf, 0,
+ MAX_NUM_PATCHES * sizeof(int)); /* global */
+ sfb = 0;
+ if (hQmfTransposer->bSbr41) {
+ stopPatch = MAX_NUM_PATCHES;
+ hQmfTransposer->maxStretch = MAX_STRETCH_HBE;
+ } else {
+ stopPatch = MAX_STRETCH_HBE;
+ }
+
+ for (patch = 1; patch <= stopPatch; patch++) {
+ while (sfb <= NSfb[0] &&
+ FreqBandTable[0][sfb] <= patch * hQmfTransposer->startBand)
+ sfb++;
+ if (sfb <= NSfb[0]) {
+ /* If the distance is larger than three QMF bands - try aligning to high
+ * resolution frequency bands instead. */
+ if ((patch * hQmfTransposer->startBand - FreqBandTable[0][sfb - 1]) <=
+ 3) {
+ hQmfTransposer->xOverQmf[patch - 1] = FreqBandTable[0][sfb - 1];
+ } else {
+ int sfb_tmp = 0;
+ while (sfb_tmp <= NSfb[1] &&
+ FreqBandTable[1][sfb_tmp] <= patch * hQmfTransposer->startBand)
+ sfb_tmp++;
+ hQmfTransposer->xOverQmf[patch - 1] = FreqBandTable[1][sfb_tmp - 1];
+ }
+ } else {
+ hQmfTransposer->xOverQmf[patch - 1] = hQmfTransposer->stopBand;
+ hQmfTransposer->maxStretch = fMin(patch, MAX_STRETCH_HBE);
+ break;
+ }
+ }
+
+ hQmfTransposer->highband_exp[0] = 0;
+ hQmfTransposer->highband_exp[1] = 0;
+ hQmfTransposer->target_exp[0] = 0;
+ hQmfTransposer->target_exp[1] = 0;
+ }
+
+ return SBRDEC_OK;
+}
+
+void QmfTransposerClose(HANDLE_HBE_TRANSPOSER hQmfTransposer) {
+ int i;
+
+ if (hQmfTransposer != NULL) {
+ if (hQmfTransposer->inBuf_F) FDKfree(hQmfTransposer->inBuf_F);
+
+ if (hQmfTransposer->qmfInBufReal_F) {
+ for (i = 0; i < hQmfTransposer->qmfInBufSize; i++) {
+ FDKafree(hQmfTransposer->qmfInBufReal_F[i]);
+ }
+ FDKfree(hQmfTransposer->qmfInBufReal_F);
+ }
+
+ if (hQmfTransposer->qmfInBufImag_F) {
+ for (i = 0; i < hQmfTransposer->qmfInBufSize; i++) {
+ FDKafree(hQmfTransposer->qmfInBufImag_F[i]);
+ }
+ FDKfree(hQmfTransposer->qmfInBufImag_F);
+ }
+
+ if (hQmfTransposer->qmfHBEBufReal_F) {
+ for (i = 0; i < HBE_MAX_OUT_SLOTS; i++) {
+ FDKfree(hQmfTransposer->qmfHBEBufReal_F[i]);
+ }
+ FDKfree(hQmfTransposer->qmfHBEBufReal_F);
+ }
+
+ if (hQmfTransposer->qmfHBEBufImag_F) {
+ for (i = 0; i < HBE_MAX_OUT_SLOTS; i++) {
+ FDKfree(hQmfTransposer->qmfHBEBufImag_F[i]);
+ }
+ FDKfree(hQmfTransposer->qmfHBEBufImag_F);
+ }
+
+ FDKfree(hQmfTransposer->qmfBufferCodecTempSlot_F);
+
+ FDKfree(hQmfTransposer);
+ }
+}
+
+inline void scaleUp(FIXP_DBL* real_m, FIXP_DBL* imag_m, INT* _e) {
+ INT reserve;
+ /* shift gc_r and gc_i up if possible */
+ reserve = CntLeadingZeros((INT(*real_m) ^ INT((*real_m >> 31))) |
+ (INT(*imag_m) ^ INT((*imag_m >> 31)))) -
+ 1;
+ reserve = fMax(reserve - 1,
+ 0); /* Leave one bit headroom such that (real_m^2 + imag_m^2)
+ does not overflow later if both are 0x80000000. */
+ reserve = fMin(reserve, *_e);
+ FDK_ASSERT(reserve >= 0);
+ *real_m <<= reserve;
+ *imag_m <<= reserve;
+ *_e -= reserve;
+}
+
+static void calculateCenterFIXP(FIXP_DBL gammaVecReal, FIXP_DBL gammaVecImag,
+ FIXP_DBL* centerReal, FIXP_DBL* centerImag,
+ INT* exponent, int stretch, int mult) {
+ scaleUp(&gammaVecReal, &gammaVecImag, exponent);
+ FIXP_DBL energy = fPow2Div2(gammaVecReal) + fPow2Div2(gammaVecImag);
+
+ if (energy != FL2FXCONST_DBL(0.f)) {
+ FIXP_DBL gc_r_m, gc_i_m, factor_m = (FIXP_DBL)0;
+ INT factor_e, gc_e;
+ factor_e = 2 * (*exponent) + 1;
+
+ switch (stretch) {
+ case 2:
+ factor_m = invFourthRootNorm2(energy, &factor_e);
+ break;
+ case 3:
+ factor_m = invCubeRootNorm2(energy, &factor_e);
+ break;
+ case 4:
+ factor_m = inv3EigthRootNorm2(energy, &factor_e);
+ break;
+ }
+
+ gc_r_m = fMultDiv2(gammaVecReal,
+ factor_m); /* exponent = HBE_SCALE + factor_e + 1 */
+ gc_i_m = fMultDiv2(gammaVecImag,
+ factor_m); /* exponent = HBE_SCALE + factor_e + 1*/
+ gc_e = *exponent + factor_e + 1;
+
+ scaleUp(&gc_r_m, &gc_i_m, &gc_e);
+
+ switch (mult) {
+ case 0:
+ *centerReal = gc_r_m;
+ *centerImag = gc_i_m;
+ break;
+ case 1:
+ *centerReal = fPow2Div2(gc_r_m) - fPow2Div2(gc_i_m);
+ *centerImag = fMult(gc_r_m, gc_i_m);
+ gc_e = 2 * gc_e + 1;
+ break;
+ case 2:
+ FIXP_DBL tmp_r = gc_r_m;
+ FIXP_DBL tmp_i = gc_i_m;
+ gc_r_m = fPow2Div2(gc_r_m) - fPow2Div2(gc_i_m);
+ gc_i_m = fMult(tmp_r, gc_i_m);
+ gc_e = 3 * gc_e + 1 + 1;
+ cplxMultDiv2(&centerReal[0], &centerImag[0], gc_r_m, gc_i_m, tmp_r,
+ tmp_i);
+ break;
+ }
+
+ scaleUp(centerReal, centerImag, &gc_e);
+
+ FDK_ASSERT(gc_e >= 0);
+ *exponent = gc_e;
+ } else {
+ *centerReal = energy; /* energy = 0 */
+ *centerImag = energy; /* energy = 0 */
+ *exponent = (INT)energy;
+ }
+}
+
+static int getHBEScaleFactorFrame(const int bSbr41, const int maxStretch,
+ const int pitchInBins) {
+ if (pitchInBins >= pmin * (1 + bSbr41)) {
+ /* crossproducts enabled */
+ return 26;
+ } else {
+ return (maxStretch == 2) ? 24 : 25;
+ }
+}
+
+static void addHighBandPart(FIXP_DBL g_r_m, FIXP_DBL g_i_m, INT g_e,
+ FIXP_DBL mult, FIXP_DBL gammaCenterReal_m,
+ FIXP_DBL gammaCenterImag_m, INT gammaCenter_e,
+ INT stretch, INT scale_factor_hbe,
+ FIXP_DBL* qmfHBEBufReal_F,
+ FIXP_DBL* qmfHBEBufImag_F) {
+ if ((g_r_m | g_i_m) != FL2FXCONST_DBL(0.f)) {
+ FIXP_DBL factor_m = (FIXP_DBL)0;
+ INT factor_e;
+ INT add = (stretch == 4) ? 1 : 0;
+ INT shift = (stretch == 4) ? 1 : 2;
+
+ scaleUp(&g_r_m, &g_i_m, &g_e);
+ FIXP_DBL energy = fPow2AddDiv2(fPow2Div2(g_r_m), g_i_m);
+ factor_e = 2 * g_e + 1;
+
+ switch (stretch) {
+ case 2:
+ factor_m = invFourthRootNorm2(energy, &factor_e);
+ break;
+ case 3:
+ factor_m = invCubeRootNorm2(energy, &factor_e);
+ break;
+ case 4:
+ factor_m = inv3EigthRootNorm2(energy, &factor_e);
+ break;
+ }
+
+ factor_m = fMult(factor_m, mult);
+
+ FIXP_DBL tmp_r, tmp_i;
+ cplxMultDiv2(&tmp_r, &tmp_i, g_r_m, g_i_m, gammaCenterReal_m,
+ gammaCenterImag_m);
+
+ g_r_m = fMultDiv2(tmp_r, factor_m) << shift;
+ g_i_m = fMultDiv2(tmp_i, factor_m) << shift;
+ g_e = scale_factor_hbe - (g_e + factor_e + gammaCenter_e + add);
+ fMax((INT)0, g_e);
+ *qmfHBEBufReal_F += g_r_m >> g_e;
+ *qmfHBEBufImag_F += g_i_m >> g_e;
+ }
+}
+
+void QmfTransposerApply(HANDLE_HBE_TRANSPOSER hQmfTransposer,
+ FIXP_DBL** qmfBufferCodecReal,
+ FIXP_DBL** qmfBufferCodecImag, int nColsIn,
+ FIXP_DBL** ppQmfBufferOutReal_F,
+ FIXP_DBL** ppQmfBufferOutImag_F,
+ FIXP_DBL lpcFilterStatesReal[2 + (3 * (4))][(64)],
+ FIXP_DBL lpcFilterStatesImag[2 + (3 * (4))][(64)],
+ int pitchInBins, int scale_lb, int scale_hbe,
+ int* scale_hb, int timeStep, int firstSlotOffsset,
+ int ov_len,
+ KEEP_STATES_SYNCED_MODE keepStatesSyncedMode) {
+ int i, j, stretch, band, sourceband, r, s;
+ int qmfVocoderColsIn = hQmfTransposer->noCols / 2;
+ int bSbr41 = hQmfTransposer->bSbr41;
+
+ const int winLength[3] = {10, 8, 6};
+ const int slotOffset = 6; /* hQmfTransposer->winLen-6; */
+
+ int qmfOffset = 2 * hQmfTransposer->kstart;
+ int scale_border = (nColsIn == 64) ? 32 : nColsIn;
+
+ INT slot_stretch4[9] = {0, 0, 0, 0, 2, 4, 6, 8, 10};
+ INT slot_stretch2[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ INT slot_stretch3[10] = {0, 0, 0, 1, 3, 4, 6, 7, 9, 10};
+ INT filt_stretch3[10] = {0, 0, 0, 1, 0, 1, 0, 1, 0, 1};
+ INT filt_dummy[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ INT* pSlotStretch;
+ INT* pFilt;
+
+ int offset = 0; /* where to take QmfTransposer data */
+
+ int signPreMod =
+ (hQmfTransposer->synthesisQmfPreModCos_F[0] < FL2FXCONST_DBL(0.f)) ? 1
+ : -1;
+
+ int scale_factor_hbe =
+ getHBEScaleFactorFrame(bSbr41, hQmfTransposer->maxStretch, pitchInBins);
+
+ if (keepStatesSyncedMode != KEEP_STATES_SYNCED_OFF) {
+ offset = hQmfTransposer->noCols - ov_len - LPC_ORDER;
+ }
+
+ hQmfTransposer->highband_exp[0] = hQmfTransposer->highband_exp[1];
+ hQmfTransposer->target_exp[0] = hQmfTransposer->target_exp[1];
+
+ hQmfTransposer->highband_exp[1] = scale_factor_hbe;
+ hQmfTransposer->target_exp[1] =
+ fixMax(hQmfTransposer->highband_exp[1], hQmfTransposer->highband_exp[0]);
+
+ scale_factor_hbe = hQmfTransposer->target_exp[1];
+
+ int shift_ov = hQmfTransposer->target_exp[0] - hQmfTransposer->target_exp[1];
+
+ if (shift_ov != 0) {
+ for (i = 0; i < HBE_MAX_OUT_SLOTS; i++) {
+ for (band = 0; band < QMF_SYNTH_CHANNELS; band++) {
+ if (shift_ov >= 0) {
+ hQmfTransposer->qmfHBEBufReal_F[i][band] <<= shift_ov;
+ hQmfTransposer->qmfHBEBufImag_F[i][band] <<= shift_ov;
+ } else {
+ hQmfTransposer->qmfHBEBufReal_F[i][band] >>= (-shift_ov);
+ hQmfTransposer->qmfHBEBufImag_F[i][band] >>= (-shift_ov);
+ }
+ }
+ }
+ }
+
+ if ((keepStatesSyncedMode == KEEP_STATES_SYNCED_OFF) && shift_ov != 0) {
+ for (i = timeStep * firstSlotOffsset; i < ov_len; i++) {
+ for (band = hQmfTransposer->startBand; band < hQmfTransposer->stopBand;
+ band++) {
+ if (shift_ov >= 0) {
+ ppQmfBufferOutReal_F[i][band] <<= shift_ov;
+ ppQmfBufferOutImag_F[i][band] <<= shift_ov;
+ } else {
+ ppQmfBufferOutReal_F[i][band] >>= (-shift_ov);
+ ppQmfBufferOutImag_F[i][band] >>= (-shift_ov);
+ }
+ }
+ }
+
+ /* shift lpc filterstates */
+ for (i = 0; i < timeStep * firstSlotOffsset + LPC_ORDER; i++) {
+ for (band = 0; band < (64); band++) {
+ if (shift_ov >= 0) {
+ lpcFilterStatesReal[i][band] <<= shift_ov;
+ lpcFilterStatesImag[i][band] <<= shift_ov;
+ } else {
+ lpcFilterStatesReal[i][band] >>= (-shift_ov);
+ lpcFilterStatesImag[i][band] >>= (-shift_ov);
+ }
+ }
+ }
+ }
+
+ FIXP_DBL twid_m_new[3][2]; /* [stretch][cos/sin] */
+ INT stepsize = 1 + !bSbr41, sine_offset = 24, mod = 96;
+ INT mult[3] = {1, 2, 3};
+
+ for (s = 0; s <= MAX_STRETCH_HBE - 2; s++) {
+ twid_m_new[s][0] = twiddle[(mult[s] * (stepsize * pitchInBins)) % mod];
+ twid_m_new[s][1] =
+ twiddle[((mult[s] * (stepsize * pitchInBins)) + sine_offset) % mod];
+ }
+
+ /* Time-stretch */
+ for (j = 0; j < qmfVocoderColsIn; j++) {
+ int sign = -1, k, z, addrshift, codecTemp_e;
+ /* update inbuf */
+ for (i = 0; i < hQmfTransposer->synthSize; i++) {
+ hQmfTransposer->inBuf_F[i] =
+ hQmfTransposer->inBuf_F[i + 2 * hQmfTransposer->synthSize];
+ }
+
+ /* run synthesis for two sbr slots as transposer uses
+ half slots double bands representation */
+ for (z = 0; z < 2; z++) {
+ int scale_factor = ((nColsIn == 64) && ((2 * j + z) < scale_border))
+ ? scale_lb
+ : scale_hbe;
+ codecTemp_e = scale_factor - 1; /* -2 for Div2 and cos/sin scale of 1 */
+
+ for (k = 0; k < hQmfTransposer->synthSize; k++) {
+ int ki = hQmfTransposer->kstart + k;
+ hQmfTransposer->qmfBufferCodecTempSlot_F[k] =
+ fMultDiv2(signPreMod * hQmfTransposer->synthesisQmfPreModCos_F[k],
+ qmfBufferCodecReal[2 * j + z][ki]);
+ hQmfTransposer->qmfBufferCodecTempSlot_F[k] +=
+ fMultDiv2(signPreMod * hQmfTransposer->synthesisQmfPreModSin_F[k],
+ qmfBufferCodecImag[2 * j + z][ki]);
+ }
+
+ C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, (HBE_MAX_QMF_BANDS << 1));
+
+ qmfSynthesisFilteringSlot(
+ &hQmfTransposer->HBESynthesisQMF,
+ hQmfTransposer->qmfBufferCodecTempSlot_F, NULL, 0,
+ -7 - hQmfTransposer->HBESynthesisQMF.filterScale - codecTemp_e + 1,
+ hQmfTransposer->inBuf_F + hQmfTransposer->synthSize * (z + 1), 1,
+ pWorkBuffer);
+
+ C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, (HBE_MAX_QMF_BANDS << 1));
+ }
+
+ C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, (HBE_MAX_QMF_BANDS << 1));
+
+ qmfAnalysisFilteringSlot(&hQmfTransposer->HBEAnalysiscQMF,
+ hQmfTransposer->qmfInBufReal_F[QMF_WIN_LEN - 1],
+ hQmfTransposer->qmfInBufImag_F[QMF_WIN_LEN - 1],
+ hQmfTransposer->inBuf_F + 1, 1, pWorkBuffer);
+
+ C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, (HBE_MAX_QMF_BANDS << 1));
+
+ if ((keepStatesSyncedMode == KEEP_STATES_SYNCED_NORMAL) &&
+ j <= qmfVocoderColsIn - ((LPC_ORDER + ov_len + QMF_WIN_LEN - 1) >> 1)) {
+ /* update in buffer */
+ for (i = 0; i < QMF_WIN_LEN - 1; i++) {
+ FDKmemcpy(
+ hQmfTransposer->qmfInBufReal_F[i],
+ hQmfTransposer->qmfInBufReal_F[i + 1],
+ sizeof(FIXP_DBL) * hQmfTransposer->HBEAnalysiscQMF.no_channels);
+ FDKmemcpy(
+ hQmfTransposer->qmfInBufImag_F[i],
+ hQmfTransposer->qmfInBufImag_F[i + 1],
+ sizeof(FIXP_DBL) * hQmfTransposer->HBEAnalysiscQMF.no_channels);
+ }
+ continue;
+ }
+
+ for (stretch = 2; stretch <= hQmfTransposer->maxStretch; stretch++) {
+ int start = slotOffset - winLength[stretch - 2] / 2;
+ int stop = slotOffset + winLength[stretch - 2] / 2;
+
+ FIXP_DBL factor = FL2FXCONST_DBL(1.f / 3.f);
+
+ for (band = hQmfTransposer->xOverQmf[stretch - 2];
+ band < hQmfTransposer->xOverQmf[stretch - 1]; band++) {
+ FIXP_DBL gammaCenterReal_m[2] = {(FIXP_DBL)0, (FIXP_DBL)0},
+ gammaCenterImag_m[2] = {(FIXP_DBL)0, (FIXP_DBL)0};
+ INT gammaCenter_e[2] = {0, 0};
+
+ FIXP_DBL gammaVecReal_m[2] = {(FIXP_DBL)0, (FIXP_DBL)0},
+ gammaVecImag_m[2] = {(FIXP_DBL)0, (FIXP_DBL)0};
+ INT gammaVec_e[2] = {0, 0};
+
+ FIXP_DBL wingain = (FIXP_DBL)0;
+
+ gammaCenter_e[0] =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ gammaCenter_e[1] =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+
+ /* interpolation filters for 3rd order */
+ sourceband = 2 * band / stretch - qmfOffset;
+ FDK_ASSERT(sourceband >= 0);
+
+ /* maximum gammaCenter_e == 20 */
+ calculateCenterFIXP(
+ hQmfTransposer->qmfInBufReal_F[slotOffset][sourceband],
+ hQmfTransposer->qmfInBufImag_F[slotOffset][sourceband],
+ &gammaCenterReal_m[0], &gammaCenterImag_m[0], &gammaCenter_e[0],
+ stretch, stretch - 2);
+
+ if (stretch == 4) {
+ r = band - 2 * (band / 2);
+ sourceband += (r == 0) ? -1 : 1;
+ pSlotStretch = slot_stretch4;
+ factor = FL2FXCONST_DBL(2.f / 3.f);
+ pFilt = filt_dummy;
+ } else if (stretch == 2) {
+ r = 0;
+ sourceband = 2 * band / stretch - qmfOffset;
+ pSlotStretch = slot_stretch2;
+ factor = FL2FXCONST_DBL(1.f / 3.f);
+ pFilt = filt_dummy;
+ } else {
+ r = 2 * band - 3 * (2 * band / 3);
+ sourceband = 2 * band / stretch - qmfOffset;
+ pSlotStretch = slot_stretch3;
+ factor = FL2FXCONST_DBL(1.4142f / 3.0f);
+ pFilt = filt_stretch3;
+ }
+
+ if (r == 2) {
+ calculateCenterFIXP(
+ hQmfTransposer->qmfInBufReal_F[slotOffset][sourceband + 1],
+ hQmfTransposer->qmfInBufImag_F[slotOffset][sourceband + 1],
+ &gammaCenterReal_m[1], &gammaCenterImag_m[1], &gammaCenter_e[1],
+ stretch, stretch - 2);
+
+ factor = FL2FXCONST_DBL(1.4142f / 6.0f);
+ }
+
+ if (r == 2) {
+ for (k = start; k < stop; k++) {
+ gammaVecReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[pSlotStretch[k]][sourceband];
+ gammaVecReal_m[1] =
+ hQmfTransposer->qmfInBufReal_F[pSlotStretch[k]][sourceband + 1];
+ gammaVecImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[pSlotStretch[k]][sourceband];
+ gammaVecImag_m[1] =
+ hQmfTransposer->qmfInBufImag_F[pSlotStretch[k]][sourceband + 1];
+ gammaVec_e[0] = gammaVec_e[1] =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+
+ if (pFilt[k] == 1) {
+ FIXP_DBL tmpRealF = gammaVecReal_m[0], tmpImagF;
+ gammaVecReal_m[0] =
+ (fMult(gammaVecReal_m[0], hintReal_F[sourceband % 4][1]) -
+ fMult(gammaVecImag_m[0],
+ hintReal_F[(sourceband + 3) % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVecImag_m[0] =
+ (fMult(tmpRealF, hintReal_F[(sourceband + 3) % 4][1]) +
+ fMult(gammaVecImag_m[0], hintReal_F[sourceband % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+
+ tmpRealF = hQmfTransposer
+ ->qmfInBufReal_F[pSlotStretch[k] + 1][sourceband];
+ tmpImagF = hQmfTransposer
+ ->qmfInBufImag_F[pSlotStretch[k] + 1][sourceband];
+
+ gammaVecReal_m[0] +=
+ (fMult(tmpRealF, hintReal_F[sourceband % 4][1]) -
+ fMult(tmpImagF, hintReal_F[(sourceband + 1) % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVecImag_m[0] +=
+ (fMult(tmpRealF, hintReal_F[(sourceband + 1) % 4][1]) +
+ fMult(tmpImagF, hintReal_F[sourceband % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVec_e[0]++;
+
+ tmpRealF = gammaVecReal_m[1];
+
+ gammaVecReal_m[1] =
+ (fMult(gammaVecReal_m[1], hintReal_F[sourceband % 4][2]) -
+ fMult(gammaVecImag_m[1],
+ hintReal_F[(sourceband + 3) % 4][2])) >>
+ 1;
+ gammaVecImag_m[1] =
+ (fMult(tmpRealF, hintReal_F[(sourceband + 3) % 4][2]) +
+ fMult(gammaVecImag_m[1], hintReal_F[sourceband % 4][2])) >>
+ 1;
+
+ tmpRealF =
+ hQmfTransposer
+ ->qmfInBufReal_F[pSlotStretch[k] + 1][sourceband + 1];
+ tmpImagF =
+ hQmfTransposer
+ ->qmfInBufImag_F[pSlotStretch[k] + 1][sourceband + 1];
+
+ gammaVecReal_m[1] +=
+ (fMult(tmpRealF, hintReal_F[sourceband % 4][2]) -
+ fMult(tmpImagF, hintReal_F[(sourceband + 1) % 4][2])) >>
+ 1;
+ gammaVecImag_m[1] +=
+ (fMult(tmpRealF, hintReal_F[(sourceband + 1) % 4][2]) +
+ fMult(tmpImagF, hintReal_F[sourceband % 4][2])) >>
+ 1;
+ gammaVec_e[1]++;
+ }
+
+ addHighBandPart(gammaVecReal_m[1], gammaVecImag_m[1], gammaVec_e[1],
+ factor, gammaCenterReal_m[0], gammaCenterImag_m[0],
+ gammaCenter_e[0], stretch, scale_factor_hbe,
+ &hQmfTransposer->qmfHBEBufReal_F[k][band],
+ &hQmfTransposer->qmfHBEBufImag_F[k][band]);
+
+ addHighBandPart(gammaVecReal_m[0], gammaVecImag_m[0], gammaVec_e[0],
+ factor, gammaCenterReal_m[1], gammaCenterImag_m[1],
+ gammaCenter_e[1], stretch, scale_factor_hbe,
+ &hQmfTransposer->qmfHBEBufReal_F[k][band],
+ &hQmfTransposer->qmfHBEBufImag_F[k][band]);
+ }
+ } else {
+ for (k = start; k < stop; k++) {
+ gammaVecReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[pSlotStretch[k]][sourceband];
+ gammaVecImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[pSlotStretch[k]][sourceband];
+ gammaVec_e[0] =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+
+ if (pFilt[k] == 1) {
+ FIXP_DBL tmpRealF = gammaVecReal_m[0], tmpImagF;
+ gammaVecReal_m[0] =
+ (fMult(gammaVecReal_m[0], hintReal_F[sourceband % 4][1]) -
+ fMult(gammaVecImag_m[0],
+ hintReal_F[(sourceband + 3) % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVecImag_m[0] =
+ (fMult(tmpRealF, hintReal_F[(sourceband + 3) % 4][1]) +
+ fMult(gammaVecImag_m[0], hintReal_F[sourceband % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+
+ tmpRealF = hQmfTransposer
+ ->qmfInBufReal_F[pSlotStretch[k] + 1][sourceband];
+ tmpImagF = hQmfTransposer
+ ->qmfInBufImag_F[pSlotStretch[k] + 1][sourceband];
+
+ gammaVecReal_m[0] +=
+ (fMult(tmpRealF, hintReal_F[sourceband % 4][1]) -
+ fMult(tmpImagF, hintReal_F[(sourceband + 1) % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVecImag_m[0] +=
+ (fMult(tmpRealF, hintReal_F[(sourceband + 1) % 4][1]) +
+ fMult(tmpImagF, hintReal_F[sourceband % 4][1])) >>
+ 1; /* sum should be <= 1 because of sin/cos multiplication */
+ gammaVec_e[0]++;
+ }
+
+ addHighBandPart(gammaVecReal_m[0], gammaVecImag_m[0], gammaVec_e[0],
+ factor, gammaCenterReal_m[0], gammaCenterImag_m[0],
+ gammaCenter_e[0], stretch, scale_factor_hbe,
+ &hQmfTransposer->qmfHBEBufReal_F[k][band],
+ &hQmfTransposer->qmfHBEBufImag_F[k][band]);
+ }
+ }
+
+ /* pitchInBins is given with the resolution of a 768 bins FFT and we
+ * need 64 QMF units so factor 768/64 = 12 */
+ if (pitchInBins >= pmin * (1 + bSbr41)) {
+ int tr, ti1, ti2, mTr = 0, ts1 = 0, ts2 = 0, mVal_e = 0, temp_e = 0;
+ int sqmag0_e =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+
+ FIXP_DBL mVal_F = FL2FXCONST_DBL(0.f), sqmag0_F, sqmag1_F, sqmag2_F,
+ temp_F, f1_F; /* all equal exponent */
+ sign = -1;
+
+ sourceband = 2 * band / stretch - qmfOffset; /* consistent with the
+ already computed for
+ stretch = 3,4. */
+ FDK_ASSERT(sourceband >= 0);
+
+ FIXP_DBL sqmag0R_F =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][sourceband];
+ FIXP_DBL sqmag0I_F =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][sourceband];
+ scaleUp(&sqmag0R_F, &sqmag0I_F, &sqmag0_e);
+
+ sqmag0_F = fPow2Div2(sqmag0R_F);
+ sqmag0_F += fPow2Div2(sqmag0I_F);
+ sqmag0_e = 2 * sqmag0_e + 1;
+
+ for (tr = 1; tr < stretch; tr++) {
+ int sqmag1_e =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ int sqmag2_e =
+ SCALE2EXP(-hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+
+ FIXP_DBL tmp_band = band_F[band];
+ FIXP_DBL tr_p =
+ fMult(p_F[pitchInBins] >> bSbr41, tr_str[tr - 1]); /* scale 7 */
+ f1_F =
+ fMult(tmp_band - tr_p, stretchfac[stretch - 2]); /* scale 7 */
+ ti1 = (INT)(f1_F >> (DFRACT_BITS - 1 - 7)) - qmfOffset;
+ ti2 = (INT)(((f1_F) + ((p_F[pitchInBins] >> bSbr41) >> 2)) >>
+ (DFRACT_BITS - 1 - 7)) -
+ qmfOffset;
+
+ if (ti1 >= 0 && ti2 < 2 * hQmfTransposer->synthSize) {
+ FIXP_DBL sqmag1R_F =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ti1];
+ FIXP_DBL sqmag1I_F =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ti1];
+ scaleUp(&sqmag1R_F, &sqmag1I_F, &sqmag1_e);
+ sqmag1_F = fPow2Div2(sqmag1R_F);
+ sqmag1_F += fPow2Div2(sqmag1I_F);
+ sqmag1_e = 2 * sqmag1_e + 1;
+
+ FIXP_DBL sqmag2R_F =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ti2];
+ FIXP_DBL sqmag2I_F =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ti2];
+ scaleUp(&sqmag2R_F, &sqmag2I_F, &sqmag2_e);
+ sqmag2_F = fPow2Div2(sqmag2R_F);
+ sqmag2_F += fPow2Div2(sqmag2I_F);
+ sqmag2_e = 2 * sqmag2_e + 1;
+
+ int shift1 = fMin(fMax(sqmag1_e, sqmag2_e) - sqmag1_e, 31);
+ int shift2 = fMin(fMax(sqmag1_e, sqmag2_e) - sqmag2_e, 31);
+
+ temp_F = fMin((sqmag1_F >> shift1), (sqmag2_F >> shift2));
+ temp_e = fMax(sqmag1_e, sqmag2_e);
+
+ int shift3 = fMin(fMax(temp_e, mVal_e) - temp_e, 31);
+ int shift4 = fMin(fMax(temp_e, mVal_e) - mVal_e, 31);
+
+ if ((temp_F >> shift3) > (mVal_F >> shift4)) {
+ mVal_F = temp_F;
+ mVal_e = temp_e; /* equals sqmag2_e + shift2 */
+ mTr = tr;
+ ts1 = ti1;
+ ts2 = ti2;
+ }
+ }
+ }
+
+ int shift1 = fMin(fMax(sqmag0_e, mVal_e) - sqmag0_e, 31);
+ int shift2 = fMin(fMax(sqmag0_e, mVal_e) - mVal_e, 31);
+
+ if ((mVal_F >> shift2) > (sqmag0_F >> shift1) && ts1 >= 0 &&
+ ts2 < 2 * hQmfTransposer->synthSize) {
+ INT gammaOut_e[2];
+ FIXP_DBL gammaOutReal_m[2], gammaOutImag_m[2];
+ FIXP_DBL tmpReal_m = (FIXP_DBL)0, tmpImag_m = (FIXP_DBL)0;
+
+ int Tcenter, Tvec;
+
+ Tcenter = stretch - mTr; /* default phase power parameters */
+ Tvec = mTr;
+ switch (stretch) /* 2 tap block creation design depends on stretch
+ order */
+ {
+ case 2:
+ wingain =
+ FL2FXCONST_DBL(5.f / 12.f); /* sum of taps divided by two */
+
+ if (hQmfTransposer->bXProducts[0]) {
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts1];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts1];
+
+ for (k = 0; k < 2; k++) {
+ gammaVecReal_m[k] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset - 1 + k][ts2];
+ gammaVecImag_m[k] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset - 1 + k][ts2];
+ }
+
+ gammaCenter_e[0] = SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ gammaVec_e[0] = gammaVec_e[1] = SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ }
+ break;
+
+ case 4:
+ wingain =
+ FL2FXCONST_DBL(6.f / 12.f); /* sum of taps divided by two */
+ if (hQmfTransposer->bXProducts[2]) {
+ if (mTr == 1) {
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts1];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts1];
+
+ for (k = 0; k < 2; k++) {
+ gammaVecReal_m[k] =
+ hQmfTransposer
+ ->qmfInBufReal_F[slotOffset + 2 * (k - 1)][ts2];
+ gammaVecImag_m[k] =
+ hQmfTransposer
+ ->qmfInBufImag_F[slotOffset + 2 * (k - 1)][ts2];
+ }
+ } else if (mTr == 2) {
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts1];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts1];
+
+ for (k = 0; k < 2; k++) {
+ gammaVecReal_m[k] =
+ hQmfTransposer
+ ->qmfInBufReal_F[slotOffset + (k - 1)][ts2];
+ gammaVecImag_m[k] =
+ hQmfTransposer
+ ->qmfInBufImag_F[slotOffset + (k - 1)][ts2];
+ }
+ } else /* (mTr == 3) */
+ {
+ sign = 1;
+ Tcenter = mTr; /* opposite phase power parameters as ts2 is
+ center */
+ Tvec = stretch - mTr;
+
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts2];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts2];
+
+ for (k = 0; k < 2; k++) {
+ gammaVecReal_m[k] =
+ hQmfTransposer
+ ->qmfInBufReal_F[slotOffset + 2 * (k - 1)][ts1];
+ gammaVecImag_m[k] =
+ hQmfTransposer
+ ->qmfInBufImag_F[slotOffset + 2 * (k - 1)][ts1];
+ }
+ }
+
+ gammaCenter_e[0] = SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ gammaVec_e[0] = gammaVec_e[1] = SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ }
+ break;
+
+ case 3:
+ wingain = FL2FXCONST_DBL(5.6568f /
+ 12.f); /* sum of taps divided by two */
+
+ if (hQmfTransposer->bXProducts[1]) {
+ FIXP_DBL tmpReal_F, tmpImag_F;
+ if (mTr == 1) {
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts1];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts1];
+ gammaVecReal_m[1] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts2];
+ gammaVecImag_m[1] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts2];
+
+ addrshift = -2;
+ tmpReal_F =
+ hQmfTransposer
+ ->qmfInBufReal_F[addrshift + slotOffset][ts2];
+ tmpImag_F =
+ hQmfTransposer
+ ->qmfInBufImag_F[addrshift + slotOffset][ts2];
+
+ gammaVecReal_m[0] =
+ (fMult(factors[ts2 % 4], tmpReal_F) -
+ fMult(factors[(ts2 + 3) % 4], tmpImag_F)) >>
+ 1;
+ gammaVecImag_m[0] =
+ (fMult(factors[(ts2 + 3) % 4], tmpReal_F) +
+ fMult(factors[ts2 % 4], tmpImag_F)) >>
+ 1;
+
+ tmpReal_F =
+ hQmfTransposer
+ ->qmfInBufReal_F[addrshift + 1 + slotOffset][ts2];
+ tmpImag_F =
+ hQmfTransposer
+ ->qmfInBufImag_F[addrshift + 1 + slotOffset][ts2];
+
+ gammaVecReal_m[0] +=
+ (fMult(factors[ts2 % 4], tmpReal_F) -
+ fMult(factors[(ts2 + 1) % 4], tmpImag_F)) >>
+ 1;
+ gammaVecImag_m[0] +=
+ (fMult(factors[(ts2 + 1) % 4], tmpReal_F) +
+ fMult(factors[ts2 % 4], tmpImag_F)) >>
+ 1;
+
+ } else /* (mTr == 2) */
+ {
+ sign = 1;
+ Tcenter = mTr; /* opposite phase power parameters as ts2 is
+ center */
+ Tvec = stretch - mTr;
+
+ gammaCenterReal_m[0] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts2];
+ gammaCenterImag_m[0] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts2];
+ gammaVecReal_m[1] =
+ hQmfTransposer->qmfInBufReal_F[slotOffset][ts1];
+ gammaVecImag_m[1] =
+ hQmfTransposer->qmfInBufImag_F[slotOffset][ts1];
+
+ addrshift = -2;
+ tmpReal_F =
+ hQmfTransposer
+ ->qmfInBufReal_F[addrshift + slotOffset][ts1];
+ tmpImag_F =
+ hQmfTransposer
+ ->qmfInBufImag_F[addrshift + slotOffset][ts1];
+
+ gammaVecReal_m[0] =
+ (fMult(factors[ts1 % 4], tmpReal_F) -
+ fMult(factors[(ts1 + 3) % 4], tmpImag_F)) >>
+ 1;
+ gammaVecImag_m[0] =
+ (fMult(factors[(ts1 + 3) % 4], tmpReal_F) +
+ fMult(factors[ts1 % 4], tmpImag_F)) >>
+ 1;
+
+ tmpReal_F =
+ hQmfTransposer
+ ->qmfInBufReal_F[addrshift + 1 + slotOffset][ts1];
+ tmpImag_F =
+ hQmfTransposer
+ ->qmfInBufImag_F[addrshift + 1 + slotOffset][ts1];
+
+ gammaVecReal_m[0] +=
+ (fMult(factors[ts1 % 4], tmpReal_F) -
+ fMult(factors[(ts1 + 1) % 4], tmpImag_F)) >>
+ 1;
+ gammaVecImag_m[0] +=
+ (fMult(factors[(ts1 + 1) % 4], tmpReal_F) +
+ fMult(factors[ts1 % 4], tmpImag_F)) >>
+ 1;
+ }
+
+ gammaCenter_e[0] = gammaVec_e[1] = SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor);
+ gammaVec_e[0] =
+ SCALE2EXP(
+ -hQmfTransposer->HBEAnalysiscQMF.outScalefactor) +
+ 1;
+ }
+ break;
+ default:
+ FDK_ASSERT(0);
+ break;
+ } /* stretch cases */
+
+ /* parameter controlled phase modification parts */
+ /* maximum *_e == 20 */
+ calculateCenterFIXP(gammaCenterReal_m[0], gammaCenterImag_m[0],
+ &gammaCenterReal_m[0], &gammaCenterImag_m[0],
+ &gammaCenter_e[0], stretch, Tcenter - 1);
+ calculateCenterFIXP(gammaVecReal_m[0], gammaVecImag_m[0],
+ &gammaVecReal_m[0], &gammaVecImag_m[0],
+ &gammaVec_e[0], stretch, Tvec - 1);
+ calculateCenterFIXP(gammaVecReal_m[1], gammaVecImag_m[1],
+ &gammaVecReal_m[1], &gammaVecImag_m[1],
+ &gammaVec_e[1], stretch, Tvec - 1);
+
+ /* Final multiplication of prepared parts */
+ for (k = 0; k < 2; k++) {
+ gammaOutReal_m[k] =
+ fMultDiv2(gammaVecReal_m[k], gammaCenterReal_m[0]) -
+ fMultDiv2(gammaVecImag_m[k], gammaCenterImag_m[0]);
+ gammaOutImag_m[k] =
+ fMultDiv2(gammaVecReal_m[k], gammaCenterImag_m[0]) +
+ fMultDiv2(gammaVecImag_m[k], gammaCenterReal_m[0]);
+ gammaOut_e[k] = gammaCenter_e[0] + gammaVec_e[k] + 1;
+ }
+
+ scaleUp(&gammaOutReal_m[0], &gammaOutImag_m[0], &gammaOut_e[0]);
+ scaleUp(&gammaOutReal_m[1], &gammaOutImag_m[1], &gammaOut_e[1]);
+ FDK_ASSERT(gammaOut_e[0] >= 0);
+ FDK_ASSERT(gammaOut_e[0] < 32);
+
+ tmpReal_m = gammaOutReal_m[0];
+ tmpImag_m = gammaOutImag_m[0];
+
+ INT modstretch4 = ((stretch == 4) && (mTr == 2));
+
+ FIXP_DBL cos_twid = twid_m_new[stretch - 2 - modstretch4][0];
+ FIXP_DBL sin_twid = sign * twid_m_new[stretch - 2 - modstretch4][1];
+
+ gammaOutReal_m[0] =
+ fMult(tmpReal_m, cos_twid) -
+ fMult(tmpImag_m, sin_twid); /* sum should be <= 1 because of
+ sin/cos multiplication */
+ gammaOutImag_m[0] =
+ fMult(tmpImag_m, cos_twid) +
+ fMult(tmpReal_m, sin_twid); /* sum should be <= 1 because of
+ sin/cos multiplication */
+
+ /* wingain */
+ for (k = 0; k < 2; k++) {
+ gammaOutReal_m[k] = (fMult(gammaOutReal_m[k], wingain) << 1);
+ gammaOutImag_m[k] = (fMult(gammaOutImag_m[k], wingain) << 1);
+ }
+
+ gammaOutReal_m[1] >>= 1;
+ gammaOutImag_m[1] >>= 1;
+ gammaOut_e[0] += 2;
+ gammaOut_e[1] += 2;
+
+ /* OLA including window scaling by wingain/3 */
+ for (k = 0; k < 2; k++) /* need k=1 to correspond to
+ grainModImag[slotOffset] -> out to
+ j*2+(slotOffset-offset) */
+ {
+ hQmfTransposer->qmfHBEBufReal_F[(k + slotOffset - 1)][band] +=
+ gammaOutReal_m[k] >> (scale_factor_hbe - gammaOut_e[k]);
+ hQmfTransposer->qmfHBEBufImag_F[(k + slotOffset - 1)][band] +=
+ gammaOutImag_m[k] >> (scale_factor_hbe - gammaOut_e[k]);
+ }
+ } /* mVal > qThrQMF * qThrQMF * sqmag0 && ts1 > 0 && ts2 < 64 */
+ } /* p >= pmin */
+ } /* for band */
+ } /* for stretch */
+
+ for (i = 0; i < QMF_WIN_LEN - 1; i++) {
+ FDKmemcpy(hQmfTransposer->qmfInBufReal_F[i],
+ hQmfTransposer->qmfInBufReal_F[i + 1],
+ sizeof(FIXP_DBL) * hQmfTransposer->HBEAnalysiscQMF.no_channels);
+ FDKmemcpy(hQmfTransposer->qmfInBufImag_F[i],
+ hQmfTransposer->qmfInBufImag_F[i + 1],
+ sizeof(FIXP_DBL) * hQmfTransposer->HBEAnalysiscQMF.no_channels);
+ }
+
+ if (keepStatesSyncedMode != KEEP_STATES_SYNCED_NOOUT) {
+ if (2 * j >= offset) {
+ /* copy first two slots of internal buffer to output */
+ if (keepStatesSyncedMode == KEEP_STATES_SYNCED_OUTDIFF) {
+ for (i = 0; i < 2; i++) {
+ FDKmemcpy(&ppQmfBufferOutReal_F[2 * j - offset + i]
+ [hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer
+ ->qmfHBEBufReal_F[i][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ FDKmemcpy(&ppQmfBufferOutImag_F[2 * j - offset + i]
+ [hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer
+ ->qmfHBEBufImag_F[i][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ }
+ } else {
+ for (i = 0; i < 2; i++) {
+ FDKmemcpy(&ppQmfBufferOutReal_F[2 * j + i + ov_len]
+ [hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer
+ ->qmfHBEBufReal_F[i][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ FDKmemcpy(&ppQmfBufferOutImag_F[2 * j + i + ov_len]
+ [hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer
+ ->qmfHBEBufImag_F[i][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ }
+ }
+ }
+ }
+
+ /* move slots up */
+ for (i = 0; i < HBE_MAX_OUT_SLOTS - 2; i++) {
+ FDKmemcpy(
+ &hQmfTransposer->qmfHBEBufReal_F[i][hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer->qmfHBEBufReal_F[i + 2][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ FDKmemcpy(
+ &hQmfTransposer->qmfHBEBufImag_F[i][hQmfTransposer->xOverQmf[0]],
+ &hQmfTransposer->qmfHBEBufImag_F[i + 2][hQmfTransposer->xOverQmf[0]],
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ }
+
+ /* finally set last two slot to zero */
+ for (i = 0; i < 2; i++) {
+ FDKmemset(&hQmfTransposer->qmfHBEBufReal_F[HBE_MAX_OUT_SLOTS - 1 - i]
+ [hQmfTransposer->xOverQmf[0]],
+ 0,
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ FDKmemset(&hQmfTransposer->qmfHBEBufImag_F[HBE_MAX_OUT_SLOTS - 1 - i]
+ [hQmfTransposer->xOverQmf[0]],
+ 0,
+ (QMF_SYNTH_CHANNELS - hQmfTransposer->xOverQmf[0]) *
+ sizeof(FIXP_DBL));
+ }
+ } /* qmfVocoderColsIn */
+
+ if (keepStatesSyncedMode != KEEP_STATES_SYNCED_NOOUT) {
+ if (keepStatesSyncedMode == KEEP_STATES_SYNCED_OUTDIFF) {
+ for (i = 0; i < ov_len + LPC_ORDER; i++) {
+ for (band = hQmfTransposer->startBand; band < hQmfTransposer->stopBand;
+ band++) {
+ FIXP_DBL tmpR = ppQmfBufferOutReal_F[i][band];
+ FIXP_DBL tmpI = ppQmfBufferOutImag_F[i][band];
+
+ ppQmfBufferOutReal_F[i][band] =
+ fMult(tmpR, cos_F[band]) -
+ fMult(tmpI, (-cos_F[64 - band - 1])); /* sum should be <= 1
+ because of sin/cos
+ multiplication */
+ ppQmfBufferOutImag_F[i][band] =
+ fMult(tmpR, (-cos_F[64 - band - 1])) +
+ fMult(tmpI, cos_F[band]); /* sum should by <= 1 because of sin/cos
+ multiplication */
+ }
+ }
+ } else {
+ for (i = offset; i < hQmfTransposer->noCols; i++) {
+ for (band = hQmfTransposer->startBand; band < hQmfTransposer->stopBand;
+ band++) {
+ FIXP_DBL tmpR = ppQmfBufferOutReal_F[i + ov_len][band];
+ FIXP_DBL tmpI = ppQmfBufferOutImag_F[i + ov_len][band];
+
+ ppQmfBufferOutReal_F[i + ov_len][band] =
+ fMult(tmpR, cos_F[band]) -
+ fMult(tmpI, (-cos_F[64 - band - 1])); /* sum should be <= 1
+ because of sin/cos
+ multiplication */
+ ppQmfBufferOutImag_F[i + ov_len][band] =
+ fMult(tmpR, (-cos_F[64 - band - 1])) +
+ fMult(tmpI, cos_F[band]); /* sum should by <= 1 because of sin/cos
+ multiplication */
+ }
+ }
+ }
+ }
+
+ *scale_hb = EXP2SCALE(scale_factor_hbe);
+}
+
+int* GetxOverBandQmfTransposer(HANDLE_HBE_TRANSPOSER hQmfTransposer) {
+ if (hQmfTransposer)
+ return hQmfTransposer->xOverQmf;
+ else
+ return NULL;
+}
+
+int Get41SbrQmfTransposer(HANDLE_HBE_TRANSPOSER hQmfTransposer) {
+ if (hQmfTransposer != NULL)
+ return hQmfTransposer->bSbr41;
+ else
+ return 0;
+}