1*e5436536SAndroid Build Coastguard Worker /* -----------------------------------------------------------------------------
2*e5436536SAndroid Build Coastguard Worker Software License for The Fraunhofer FDK AAC Codec Library for Android
3*e5436536SAndroid Build Coastguard Worker
4*e5436536SAndroid Build Coastguard Worker © Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
5*e5436536SAndroid Build Coastguard Worker Forschung e.V. All rights reserved.
6*e5436536SAndroid Build Coastguard Worker
7*e5436536SAndroid Build Coastguard Worker 1. INTRODUCTION
8*e5436536SAndroid Build Coastguard Worker The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9*e5436536SAndroid Build Coastguard Worker that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10*e5436536SAndroid Build Coastguard Worker scheme for digital audio. This FDK AAC Codec software is intended to be used on
11*e5436536SAndroid Build Coastguard Worker a wide variety of Android devices.
12*e5436536SAndroid Build Coastguard Worker
13*e5436536SAndroid Build Coastguard Worker AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14*e5436536SAndroid Build Coastguard Worker general perceptual audio codecs. AAC-ELD is considered the best-performing
15*e5436536SAndroid Build Coastguard Worker full-bandwidth communications codec by independent studies and is widely
16*e5436536SAndroid Build Coastguard Worker deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17*e5436536SAndroid Build Coastguard Worker specifications.
18*e5436536SAndroid Build Coastguard Worker
19*e5436536SAndroid Build Coastguard Worker Patent licenses for necessary patent claims for the FDK AAC Codec (including
20*e5436536SAndroid Build Coastguard Worker those of Fraunhofer) may be obtained through Via Licensing
21*e5436536SAndroid Build Coastguard Worker (www.vialicensing.com) or through the respective patent owners individually for
22*e5436536SAndroid Build Coastguard Worker the purpose of encoding or decoding bit streams in products that are compliant
23*e5436536SAndroid Build Coastguard Worker with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24*e5436536SAndroid Build Coastguard Worker Android devices already license these patent claims through Via Licensing or
25*e5436536SAndroid Build Coastguard Worker directly from the patent owners, and therefore FDK AAC Codec software may
26*e5436536SAndroid Build Coastguard Worker already be covered under those patent licenses when it is used for those
27*e5436536SAndroid Build Coastguard Worker licensed purposes only.
28*e5436536SAndroid Build Coastguard Worker
29*e5436536SAndroid Build Coastguard Worker Commercially-licensed AAC software libraries, including floating-point versions
30*e5436536SAndroid Build Coastguard Worker with enhanced sound quality, are also available from Fraunhofer. Users are
31*e5436536SAndroid Build Coastguard Worker encouraged to check the Fraunhofer website for additional applications
32*e5436536SAndroid Build Coastguard Worker information and documentation.
33*e5436536SAndroid Build Coastguard Worker
34*e5436536SAndroid Build Coastguard Worker 2. COPYRIGHT LICENSE
35*e5436536SAndroid Build Coastguard Worker
36*e5436536SAndroid Build Coastguard Worker Redistribution and use in source and binary forms, with or without modification,
37*e5436536SAndroid Build Coastguard Worker are permitted without payment of copyright license fees provided that you
38*e5436536SAndroid Build Coastguard Worker satisfy the following conditions:
39*e5436536SAndroid Build Coastguard Worker
40*e5436536SAndroid Build Coastguard Worker You must retain the complete text of this software license in redistributions of
41*e5436536SAndroid Build Coastguard Worker the FDK AAC Codec or your modifications thereto in source code form.
42*e5436536SAndroid Build Coastguard Worker
43*e5436536SAndroid Build Coastguard Worker You must retain the complete text of this software license in the documentation
44*e5436536SAndroid Build Coastguard Worker and/or other materials provided with redistributions of the FDK AAC Codec or
45*e5436536SAndroid Build Coastguard Worker your modifications thereto in binary form. You must make available free of
46*e5436536SAndroid Build Coastguard Worker charge copies of the complete source code of the FDK AAC Codec and your
47*e5436536SAndroid Build Coastguard Worker modifications thereto to recipients of copies in binary form.
48*e5436536SAndroid Build Coastguard Worker
49*e5436536SAndroid Build Coastguard Worker The name of Fraunhofer may not be used to endorse or promote products derived
50*e5436536SAndroid Build Coastguard Worker from this library without prior written permission.
51*e5436536SAndroid Build Coastguard Worker
52*e5436536SAndroid Build Coastguard Worker You may not charge copyright license fees for anyone to use, copy or distribute
53*e5436536SAndroid Build Coastguard Worker the FDK AAC Codec software or your modifications thereto.
54*e5436536SAndroid Build Coastguard Worker
55*e5436536SAndroid Build Coastguard Worker Your modified versions of the FDK AAC Codec must carry prominent notices stating
56*e5436536SAndroid Build Coastguard Worker that you changed the software and the date of any change. For modified versions
57*e5436536SAndroid Build Coastguard Worker of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58*e5436536SAndroid Build Coastguard Worker must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59*e5436536SAndroid Build Coastguard Worker AAC Codec Library for Android."
60*e5436536SAndroid Build Coastguard Worker
61*e5436536SAndroid Build Coastguard Worker 3. NO PATENT LICENSE
62*e5436536SAndroid Build Coastguard Worker
63*e5436536SAndroid Build Coastguard Worker NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64*e5436536SAndroid Build Coastguard Worker limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65*e5436536SAndroid Build Coastguard Worker Fraunhofer provides no warranty of patent non-infringement with respect to this
66*e5436536SAndroid Build Coastguard Worker software.
67*e5436536SAndroid Build Coastguard Worker
68*e5436536SAndroid Build Coastguard Worker You may use this FDK AAC Codec software or modifications thereto only for
69*e5436536SAndroid Build Coastguard Worker purposes that are authorized by appropriate patent licenses.
70*e5436536SAndroid Build Coastguard Worker
71*e5436536SAndroid Build Coastguard Worker 4. DISCLAIMER
72*e5436536SAndroid Build Coastguard Worker
73*e5436536SAndroid Build Coastguard Worker This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74*e5436536SAndroid Build Coastguard Worker holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75*e5436536SAndroid Build Coastguard Worker including but not limited to the implied warranties of merchantability and
76*e5436536SAndroid Build Coastguard Worker fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77*e5436536SAndroid Build Coastguard Worker CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78*e5436536SAndroid Build Coastguard Worker or consequential damages, including but not limited to procurement of substitute
79*e5436536SAndroid Build Coastguard Worker goods or services; loss of use, data, or profits, or business interruption,
80*e5436536SAndroid Build Coastguard Worker however caused and on any theory of liability, whether in contract, strict
81*e5436536SAndroid Build Coastguard Worker liability, or tort (including negligence), arising in any way out of the use of
82*e5436536SAndroid Build Coastguard Worker this software, even if advised of the possibility of such damage.
83*e5436536SAndroid Build Coastguard Worker
84*e5436536SAndroid Build Coastguard Worker 5. CONTACT INFORMATION
85*e5436536SAndroid Build Coastguard Worker
86*e5436536SAndroid Build Coastguard Worker Fraunhofer Institute for Integrated Circuits IIS
87*e5436536SAndroid Build Coastguard Worker Attention: Audio and Multimedia Departments - FDK AAC LL
88*e5436536SAndroid Build Coastguard Worker Am Wolfsmantel 33
89*e5436536SAndroid Build Coastguard Worker 91058 Erlangen, Germany
90*e5436536SAndroid Build Coastguard Worker
91*e5436536SAndroid Build Coastguard Worker www.iis.fraunhofer.de/amm
92*e5436536SAndroid Build Coastguard Worker [email protected]
93*e5436536SAndroid Build Coastguard Worker ----------------------------------------------------------------------------- */
94*e5436536SAndroid Build Coastguard Worker
95*e5436536SAndroid Build Coastguard Worker /******************* Library for basic calculation routines ********************
96*e5436536SAndroid Build Coastguard Worker
97*e5436536SAndroid Build Coastguard Worker Author(s): Josef Hoepfl, Manuel Jander, Youliy Ninov, Daniel Hagel
98*e5436536SAndroid Build Coastguard Worker
99*e5436536SAndroid Build Coastguard Worker Description: MDCT/MDST routines
100*e5436536SAndroid Build Coastguard Worker
101*e5436536SAndroid Build Coastguard Worker *******************************************************************************/
102*e5436536SAndroid Build Coastguard Worker
103*e5436536SAndroid Build Coastguard Worker #include "mdct.h"
104*e5436536SAndroid Build Coastguard Worker
105*e5436536SAndroid Build Coastguard Worker #include "FDK_tools_rom.h"
106*e5436536SAndroid Build Coastguard Worker #include "dct.h"
107*e5436536SAndroid Build Coastguard Worker #include "fixpoint_math.h"
108*e5436536SAndroid Build Coastguard Worker
mdct_init(H_MDCT hMdct,FIXP_DBL * overlap,INT overlapBufferSize)109*e5436536SAndroid Build Coastguard Worker void mdct_init(H_MDCT hMdct, FIXP_DBL *overlap, INT overlapBufferSize) {
110*e5436536SAndroid Build Coastguard Worker hMdct->overlap.freq = overlap;
111*e5436536SAndroid Build Coastguard Worker // FDKmemclear(overlap, overlapBufferSize*sizeof(FIXP_DBL));
112*e5436536SAndroid Build Coastguard Worker hMdct->prev_fr = 0;
113*e5436536SAndroid Build Coastguard Worker hMdct->prev_nr = 0;
114*e5436536SAndroid Build Coastguard Worker hMdct->prev_tl = 0;
115*e5436536SAndroid Build Coastguard Worker hMdct->ov_size = overlapBufferSize;
116*e5436536SAndroid Build Coastguard Worker hMdct->prevAliasSymmetry = 0;
117*e5436536SAndroid Build Coastguard Worker hMdct->prevPrevAliasSymmetry = 0;
118*e5436536SAndroid Build Coastguard Worker hMdct->pFacZir = NULL;
119*e5436536SAndroid Build Coastguard Worker hMdct->pAsymOvlp = NULL;
120*e5436536SAndroid Build Coastguard Worker }
121*e5436536SAndroid Build Coastguard Worker
122*e5436536SAndroid Build Coastguard Worker /*
123*e5436536SAndroid Build Coastguard Worker This program implements the forward MDCT transform on an input block of data.
124*e5436536SAndroid Build Coastguard Worker The input block is in a form (A,B,C,D) where A,B,C and D are the respective
125*e5436536SAndroid Build Coastguard Worker 1/4th segments of the block. The program takes the input block and folds it in
126*e5436536SAndroid Build Coastguard Worker the form:
127*e5436536SAndroid Build Coastguard Worker (-D-Cr,A-Br). This block is twice shorter and here the 'r' suffix denotes
128*e5436536SAndroid Build Coastguard Worker flipping of the sequence (reversing the order of the samples). While folding the
129*e5436536SAndroid Build Coastguard Worker input block in the above mentioned shorter block the program windows the data.
130*e5436536SAndroid Build Coastguard Worker Because the two operations (windowing and folding) are not implemented
131*e5436536SAndroid Build Coastguard Worker sequentially, but together the program's structure is not easy to understand.
132*e5436536SAndroid Build Coastguard Worker Once the output (already windowed) block (-D-Cr,A-Br) is ready it is passed to
133*e5436536SAndroid Build Coastguard Worker the DCT IV for processing.
134*e5436536SAndroid Build Coastguard Worker */
mdct_block(H_MDCT hMdct,const INT_PCM * RESTRICT timeData,const INT noInSamples,FIXP_DBL * RESTRICT mdctData,const INT nSpec,const INT tl,const FIXP_WTP * pRightWindowPart,const INT fr,SHORT * pMdctData_e)135*e5436536SAndroid Build Coastguard Worker INT mdct_block(H_MDCT hMdct, const INT_PCM *RESTRICT timeData,
136*e5436536SAndroid Build Coastguard Worker const INT noInSamples, FIXP_DBL *RESTRICT mdctData,
137*e5436536SAndroid Build Coastguard Worker const INT nSpec, const INT tl, const FIXP_WTP *pRightWindowPart,
138*e5436536SAndroid Build Coastguard Worker const INT fr, SHORT *pMdctData_e) {
139*e5436536SAndroid Build Coastguard Worker int i, n;
140*e5436536SAndroid Build Coastguard Worker /* tl: transform length
141*e5436536SAndroid Build Coastguard Worker fl: left window slope length
142*e5436536SAndroid Build Coastguard Worker nl: left window slope offset
143*e5436536SAndroid Build Coastguard Worker fr: right window slope length
144*e5436536SAndroid Build Coastguard Worker nr: right window slope offset
145*e5436536SAndroid Build Coastguard Worker See FDK_tools/doc/intern/mdct.tex for more detail. */
146*e5436536SAndroid Build Coastguard Worker int fl, nl, nr;
147*e5436536SAndroid Build Coastguard Worker const FIXP_WTP *wls, *wrs;
148*e5436536SAndroid Build Coastguard Worker
149*e5436536SAndroid Build Coastguard Worker wrs = pRightWindowPart;
150*e5436536SAndroid Build Coastguard Worker
151*e5436536SAndroid Build Coastguard Worker /* Detect FRprevious / FL mismatches and override parameters accordingly */
152*e5436536SAndroid Build Coastguard Worker if (hMdct->prev_fr ==
153*e5436536SAndroid Build Coastguard Worker 0) { /* At start just initialize and pass parameters as they are */
154*e5436536SAndroid Build Coastguard Worker hMdct->prev_fr = fr;
155*e5436536SAndroid Build Coastguard Worker hMdct->prev_wrs = wrs;
156*e5436536SAndroid Build Coastguard Worker hMdct->prev_tl = tl;
157*e5436536SAndroid Build Coastguard Worker }
158*e5436536SAndroid Build Coastguard Worker
159*e5436536SAndroid Build Coastguard Worker /* Derive NR */
160*e5436536SAndroid Build Coastguard Worker nr = (tl - fr) >> 1;
161*e5436536SAndroid Build Coastguard Worker
162*e5436536SAndroid Build Coastguard Worker /* Skip input samples if tl is smaller than block size */
163*e5436536SAndroid Build Coastguard Worker timeData += (noInSamples - tl) >> 1;
164*e5436536SAndroid Build Coastguard Worker
165*e5436536SAndroid Build Coastguard Worker /* windowing */
166*e5436536SAndroid Build Coastguard Worker for (n = 0; n < nSpec; n++) {
167*e5436536SAndroid Build Coastguard Worker /*
168*e5436536SAndroid Build Coastguard Worker * MDCT scale:
169*e5436536SAndroid Build Coastguard Worker * + 1: fMultDiv2() in windowing.
170*e5436536SAndroid Build Coastguard Worker * + 1: Because of factor 1/2 in Princen-Bradley compliant windowed TDAC.
171*e5436536SAndroid Build Coastguard Worker */
172*e5436536SAndroid Build Coastguard Worker INT mdctData_e = 1 + 1;
173*e5436536SAndroid Build Coastguard Worker
174*e5436536SAndroid Build Coastguard Worker /* Derive left parameters */
175*e5436536SAndroid Build Coastguard Worker wls = hMdct->prev_wrs;
176*e5436536SAndroid Build Coastguard Worker fl = hMdct->prev_fr;
177*e5436536SAndroid Build Coastguard Worker nl = (tl - fl) >> 1;
178*e5436536SAndroid Build Coastguard Worker
179*e5436536SAndroid Build Coastguard Worker /* Here we implement a simplified version of what happens after the this
180*e5436536SAndroid Build Coastguard Worker piece of code (see the comments below). We implement the folding of A and B
181*e5436536SAndroid Build Coastguard Worker segments to (A-Br) but A is zero, because in this part of the MDCT sequence
182*e5436536SAndroid Build Coastguard Worker the window coefficients with which A must be multiplied are zero. */
183*e5436536SAndroid Build Coastguard Worker for (i = 0; i < nl; i++) {
184*e5436536SAndroid Build Coastguard Worker #if SAMPLE_BITS == DFRACT_BITS /* SPC_BITS and DFRACT_BITS should be equal. */
185*e5436536SAndroid Build Coastguard Worker mdctData[(tl / 2) + i] = -((FIXP_DBL)timeData[tl - i - 1] >> (1));
186*e5436536SAndroid Build Coastguard Worker #else
187*e5436536SAndroid Build Coastguard Worker mdctData[(tl / 2) + i] = -(FIXP_DBL)timeData[tl - i - 1]
188*e5436536SAndroid Build Coastguard Worker << (DFRACT_BITS - SAMPLE_BITS - 1); /* 0(A)-Br */
189*e5436536SAndroid Build Coastguard Worker #endif
190*e5436536SAndroid Build Coastguard Worker }
191*e5436536SAndroid Build Coastguard Worker
192*e5436536SAndroid Build Coastguard Worker /* Implements the folding and windowing of the left part of the sequence,
193*e5436536SAndroid Build Coastguard Worker that is segments A and B. The A segment is multiplied by the respective left
194*e5436536SAndroid Build Coastguard Worker window coefficient and placed in a temporary variable.
195*e5436536SAndroid Build Coastguard Worker
196*e5436536SAndroid Build Coastguard Worker tmp0 = fMultDiv2((FIXP_PCM)timeData[i+nl], pLeftWindowPart[i].v.im);
197*e5436536SAndroid Build Coastguard Worker
198*e5436536SAndroid Build Coastguard Worker After this the B segment taken in reverse order is multiplied by the left
199*e5436536SAndroid Build Coastguard Worker window and subtracted from the previously derived temporary variable, so
200*e5436536SAndroid Build Coastguard Worker that finally we implement the A-Br operation. This output is written to the
201*e5436536SAndroid Build Coastguard Worker right part of the MDCT output : (-D-Cr,A-Br).
202*e5436536SAndroid Build Coastguard Worker
203*e5436536SAndroid Build Coastguard Worker mdctData[(tl/2)+i+nl] = fMultSubDiv2(tmp0, (FIXP_PCM)timeData[tl-nl-i-1],
204*e5436536SAndroid Build Coastguard Worker pLeftWindowPart[i].v.re);//A*window-Br*window
205*e5436536SAndroid Build Coastguard Worker
206*e5436536SAndroid Build Coastguard Worker The (A-Br) data is written to the output buffer (mdctData) without being
207*e5436536SAndroid Build Coastguard Worker flipped. */
208*e5436536SAndroid Build Coastguard Worker for (i = 0; i < fl / 2; i++) {
209*e5436536SAndroid Build Coastguard Worker FIXP_DBL tmp0;
210*e5436536SAndroid Build Coastguard Worker tmp0 = fMultDiv2((FIXP_PCM)timeData[i + nl], wls[i].v.im); /* a*window */
211*e5436536SAndroid Build Coastguard Worker mdctData[(tl / 2) + i + nl] =
212*e5436536SAndroid Build Coastguard Worker fMultSubDiv2(tmp0, (FIXP_PCM)timeData[tl - nl - i - 1],
213*e5436536SAndroid Build Coastguard Worker wls[i].v.re); /* A*window-Br*window */
214*e5436536SAndroid Build Coastguard Worker }
215*e5436536SAndroid Build Coastguard Worker
216*e5436536SAndroid Build Coastguard Worker /* Right window slope offset */
217*e5436536SAndroid Build Coastguard Worker /* Here we implement a simplified version of what happens after the this
218*e5436536SAndroid Build Coastguard Worker piece of code (see the comments below). We implement the folding of C and D
219*e5436536SAndroid Build Coastguard Worker segments to (-D-Cr) but D is zero, because in this part of the MDCT sequence
220*e5436536SAndroid Build Coastguard Worker the window coefficients with which D must be multiplied are zero. */
221*e5436536SAndroid Build Coastguard Worker for (i = 0; i < nr; i++) {
222*e5436536SAndroid Build Coastguard Worker #if SAMPLE_BITS == \
223*e5436536SAndroid Build Coastguard Worker DFRACT_BITS /* This should be SPC_BITS instead of DFRACT_BITS. */
224*e5436536SAndroid Build Coastguard Worker mdctData[(tl / 2) - 1 - i] = -((FIXP_DBL)timeData[tl + i] >> (1));
225*e5436536SAndroid Build Coastguard Worker #else
226*e5436536SAndroid Build Coastguard Worker mdctData[(tl / 2) - 1 - i] =
227*e5436536SAndroid Build Coastguard Worker -(FIXP_DBL)timeData[tl + i]
228*e5436536SAndroid Build Coastguard Worker << (DFRACT_BITS - SAMPLE_BITS - 1); /* -C flipped at placing */
229*e5436536SAndroid Build Coastguard Worker #endif
230*e5436536SAndroid Build Coastguard Worker }
231*e5436536SAndroid Build Coastguard Worker
232*e5436536SAndroid Build Coastguard Worker /* Implements the folding and windowing of the right part of the sequence,
233*e5436536SAndroid Build Coastguard Worker that is, segments C and D. The C segment is multiplied by the respective
234*e5436536SAndroid Build Coastguard Worker right window coefficient and placed in a temporary variable.
235*e5436536SAndroid Build Coastguard Worker
236*e5436536SAndroid Build Coastguard Worker tmp1 = fMultDiv2((FIXP_PCM)timeData[tl+nr+i], pRightWindowPart[i].v.re);
237*e5436536SAndroid Build Coastguard Worker
238*e5436536SAndroid Build Coastguard Worker After this the D segment taken in reverse order is multiplied by the right
239*e5436536SAndroid Build Coastguard Worker window and added from the previously derived temporary variable, so that we
240*e5436536SAndroid Build Coastguard Worker get (C+Dr) operation. This output is negated to get (-C-Dr) and written to
241*e5436536SAndroid Build Coastguard Worker the left part of the MDCT output while being reversed (flipped) at the same
242*e5436536SAndroid Build Coastguard Worker time, so that from (-C-Dr) we get (-D-Cr)=> (-D-Cr,A-Br).
243*e5436536SAndroid Build Coastguard Worker
244*e5436536SAndroid Build Coastguard Worker mdctData[(tl/2)-nr-i-1] = -fMultAddDiv2(tmp1,
245*e5436536SAndroid Build Coastguard Worker (FIXP_PCM)timeData[(tl*2)-nr-i-1], pRightWindowPart[i].v.im);*/
246*e5436536SAndroid Build Coastguard Worker for (i = 0; i < fr / 2; i++) {
247*e5436536SAndroid Build Coastguard Worker FIXP_DBL tmp1;
248*e5436536SAndroid Build Coastguard Worker tmp1 = fMultDiv2((FIXP_PCM)timeData[tl + nr + i],
249*e5436536SAndroid Build Coastguard Worker wrs[i].v.re); /* C*window */
250*e5436536SAndroid Build Coastguard Worker mdctData[(tl / 2) - nr - i - 1] =
251*e5436536SAndroid Build Coastguard Worker -fMultAddDiv2(tmp1, (FIXP_PCM)timeData[(tl * 2) - nr - i - 1],
252*e5436536SAndroid Build Coastguard Worker wrs[i].v.im); /* -(C*window+Dr*window) and flip before
253*e5436536SAndroid Build Coastguard Worker placing -> -Cr - D */
254*e5436536SAndroid Build Coastguard Worker }
255*e5436536SAndroid Build Coastguard Worker
256*e5436536SAndroid Build Coastguard Worker /* We pass the shortened folded data (-D-Cr,A-Br) to the MDCT function */
257*e5436536SAndroid Build Coastguard Worker dct_IV(mdctData, tl, &mdctData_e);
258*e5436536SAndroid Build Coastguard Worker
259*e5436536SAndroid Build Coastguard Worker pMdctData_e[n] = (SHORT)mdctData_e;
260*e5436536SAndroid Build Coastguard Worker
261*e5436536SAndroid Build Coastguard Worker timeData += tl;
262*e5436536SAndroid Build Coastguard Worker mdctData += tl;
263*e5436536SAndroid Build Coastguard Worker
264*e5436536SAndroid Build Coastguard Worker hMdct->prev_wrs = wrs;
265*e5436536SAndroid Build Coastguard Worker hMdct->prev_fr = fr;
266*e5436536SAndroid Build Coastguard Worker hMdct->prev_tl = tl;
267*e5436536SAndroid Build Coastguard Worker }
268*e5436536SAndroid Build Coastguard Worker
269*e5436536SAndroid Build Coastguard Worker return nSpec * tl;
270*e5436536SAndroid Build Coastguard Worker }
271*e5436536SAndroid Build Coastguard Worker
imdct_gain(FIXP_DBL * pGain_m,int * pGain_e,int tl)272*e5436536SAndroid Build Coastguard Worker void imdct_gain(FIXP_DBL *pGain_m, int *pGain_e, int tl) {
273*e5436536SAndroid Build Coastguard Worker FIXP_DBL gain_m = *pGain_m;
274*e5436536SAndroid Build Coastguard Worker int gain_e = *pGain_e;
275*e5436536SAndroid Build Coastguard Worker int log2_tl;
276*e5436536SAndroid Build Coastguard Worker
277*e5436536SAndroid Build Coastguard Worker gain_e += -MDCT_OUTPUT_GAIN - MDCT_OUT_HEADROOM + 1;
278*e5436536SAndroid Build Coastguard Worker if (tl == 0) {
279*e5436536SAndroid Build Coastguard Worker /* Dont regard the 2/N factor from the IDCT. It is compensated for somewhere
280*e5436536SAndroid Build Coastguard Worker * else. */
281*e5436536SAndroid Build Coastguard Worker *pGain_e = gain_e;
282*e5436536SAndroid Build Coastguard Worker return;
283*e5436536SAndroid Build Coastguard Worker }
284*e5436536SAndroid Build Coastguard Worker
285*e5436536SAndroid Build Coastguard Worker log2_tl = DFRACT_BITS - 1 - fNormz((FIXP_DBL)tl);
286*e5436536SAndroid Build Coastguard Worker gain_e += -log2_tl;
287*e5436536SAndroid Build Coastguard Worker
288*e5436536SAndroid Build Coastguard Worker /* Detect non-radix 2 transform length and add amplitude compensation factor
289*e5436536SAndroid Build Coastguard Worker which cannot be included into the exponent above */
290*e5436536SAndroid Build Coastguard Worker switch ((tl) >> (log2_tl - 2)) {
291*e5436536SAndroid Build Coastguard Worker case 0x7: /* 10 ms, 1/tl = 1.0/(FDKpow(2.0, -log2_tl) *
292*e5436536SAndroid Build Coastguard Worker 0.53333333333333333333) */
293*e5436536SAndroid Build Coastguard Worker if (gain_m == (FIXP_DBL)0) {
294*e5436536SAndroid Build Coastguard Worker gain_m = FL2FXCONST_DBL(0.53333333333333333333f);
295*e5436536SAndroid Build Coastguard Worker } else {
296*e5436536SAndroid Build Coastguard Worker gain_m = fMult(gain_m, FL2FXCONST_DBL(0.53333333333333333333f));
297*e5436536SAndroid Build Coastguard Worker }
298*e5436536SAndroid Build Coastguard Worker break;
299*e5436536SAndroid Build Coastguard Worker case 0x6: /* 3/4 of radix 2, 1/tl = 1.0/(FDKpow(2.0, -log2_tl) * 2.0/3.0) */
300*e5436536SAndroid Build Coastguard Worker if (gain_m == (FIXP_DBL)0) {
301*e5436536SAndroid Build Coastguard Worker gain_m = FL2FXCONST_DBL(2.0 / 3.0f);
302*e5436536SAndroid Build Coastguard Worker } else {
303*e5436536SAndroid Build Coastguard Worker gain_m = fMult(gain_m, FL2FXCONST_DBL(2.0 / 3.0f));
304*e5436536SAndroid Build Coastguard Worker }
305*e5436536SAndroid Build Coastguard Worker break;
306*e5436536SAndroid Build Coastguard Worker case 0x5: /* 0.8 of radix 2 (e.g. tl 160), 1/tl = 1.0/(FDKpow(2.0, -log2_tl)
307*e5436536SAndroid Build Coastguard Worker * 0.8/1.5) */
308*e5436536SAndroid Build Coastguard Worker if (gain_m == (FIXP_DBL)0) {
309*e5436536SAndroid Build Coastguard Worker gain_m = FL2FXCONST_DBL(0.53333333333333333333f);
310*e5436536SAndroid Build Coastguard Worker } else {
311*e5436536SAndroid Build Coastguard Worker gain_m = fMult(gain_m, FL2FXCONST_DBL(0.53333333333333333333f));
312*e5436536SAndroid Build Coastguard Worker }
313*e5436536SAndroid Build Coastguard Worker break;
314*e5436536SAndroid Build Coastguard Worker case 0x4:
315*e5436536SAndroid Build Coastguard Worker /* radix 2, nothing to do. */
316*e5436536SAndroid Build Coastguard Worker break;
317*e5436536SAndroid Build Coastguard Worker default:
318*e5436536SAndroid Build Coastguard Worker /* unsupported */
319*e5436536SAndroid Build Coastguard Worker FDK_ASSERT(0);
320*e5436536SAndroid Build Coastguard Worker break;
321*e5436536SAndroid Build Coastguard Worker }
322*e5436536SAndroid Build Coastguard Worker
323*e5436536SAndroid Build Coastguard Worker *pGain_m = gain_m;
324*e5436536SAndroid Build Coastguard Worker *pGain_e = gain_e;
325*e5436536SAndroid Build Coastguard Worker }
326*e5436536SAndroid Build Coastguard Worker
imdct_drain(H_MDCT hMdct,FIXP_DBL * output,INT nrSamplesRoom)327*e5436536SAndroid Build Coastguard Worker INT imdct_drain(H_MDCT hMdct, FIXP_DBL *output, INT nrSamplesRoom) {
328*e5436536SAndroid Build Coastguard Worker int buffered_samples = 0;
329*e5436536SAndroid Build Coastguard Worker
330*e5436536SAndroid Build Coastguard Worker if (nrSamplesRoom > 0) {
331*e5436536SAndroid Build Coastguard Worker buffered_samples = hMdct->ov_offset;
332*e5436536SAndroid Build Coastguard Worker
333*e5436536SAndroid Build Coastguard Worker FDK_ASSERT(buffered_samples <= nrSamplesRoom);
334*e5436536SAndroid Build Coastguard Worker
335*e5436536SAndroid Build Coastguard Worker if (buffered_samples > 0) {
336*e5436536SAndroid Build Coastguard Worker FDKmemcpy(output, hMdct->overlap.time,
337*e5436536SAndroid Build Coastguard Worker buffered_samples * sizeof(FIXP_DBL));
338*e5436536SAndroid Build Coastguard Worker hMdct->ov_offset = 0;
339*e5436536SAndroid Build Coastguard Worker }
340*e5436536SAndroid Build Coastguard Worker }
341*e5436536SAndroid Build Coastguard Worker return buffered_samples;
342*e5436536SAndroid Build Coastguard Worker }
343*e5436536SAndroid Build Coastguard Worker
imdct_copy_ov_and_nr(H_MDCT hMdct,FIXP_DBL * pTimeData,INT nrSamples)344*e5436536SAndroid Build Coastguard Worker INT imdct_copy_ov_and_nr(H_MDCT hMdct, FIXP_DBL *pTimeData, INT nrSamples) {
345*e5436536SAndroid Build Coastguard Worker FIXP_DBL *pOvl;
346*e5436536SAndroid Build Coastguard Worker int nt, nf, i;
347*e5436536SAndroid Build Coastguard Worker
348*e5436536SAndroid Build Coastguard Worker nt = fMin(hMdct->ov_offset, nrSamples);
349*e5436536SAndroid Build Coastguard Worker nrSamples -= nt;
350*e5436536SAndroid Build Coastguard Worker nf = fMin(hMdct->prev_nr, nrSamples);
351*e5436536SAndroid Build Coastguard Worker FDKmemcpy(pTimeData, hMdct->overlap.time, nt * sizeof(FIXP_DBL));
352*e5436536SAndroid Build Coastguard Worker pTimeData += nt;
353*e5436536SAndroid Build Coastguard Worker
354*e5436536SAndroid Build Coastguard Worker pOvl = hMdct->overlap.freq + hMdct->ov_size - 1;
355*e5436536SAndroid Build Coastguard Worker if (hMdct->prevPrevAliasSymmetry == 0) {
356*e5436536SAndroid Build Coastguard Worker for (i = 0; i < nf; i++) {
357*e5436536SAndroid Build Coastguard Worker FIXP_DBL x = -(*pOvl--);
358*e5436536SAndroid Build Coastguard Worker *pTimeData = IMDCT_SCALE_DBL(x);
359*e5436536SAndroid Build Coastguard Worker pTimeData++;
360*e5436536SAndroid Build Coastguard Worker }
361*e5436536SAndroid Build Coastguard Worker } else {
362*e5436536SAndroid Build Coastguard Worker for (i = 0; i < nf; i++) {
363*e5436536SAndroid Build Coastguard Worker FIXP_DBL x = (*pOvl--);
364*e5436536SAndroid Build Coastguard Worker *pTimeData = IMDCT_SCALE_DBL(x);
365*e5436536SAndroid Build Coastguard Worker pTimeData++;
366*e5436536SAndroid Build Coastguard Worker }
367*e5436536SAndroid Build Coastguard Worker }
368*e5436536SAndroid Build Coastguard Worker
369*e5436536SAndroid Build Coastguard Worker return (nt + nf);
370*e5436536SAndroid Build Coastguard Worker }
371*e5436536SAndroid Build Coastguard Worker
imdct_adapt_parameters(H_MDCT hMdct,int * pfl,int * pnl,int tl,const FIXP_WTP * wls,int noOutSamples)372*e5436536SAndroid Build Coastguard Worker void imdct_adapt_parameters(H_MDCT hMdct, int *pfl, int *pnl, int tl,
373*e5436536SAndroid Build Coastguard Worker const FIXP_WTP *wls, int noOutSamples) {
374*e5436536SAndroid Build Coastguard Worker int fl = *pfl, nl = *pnl;
375*e5436536SAndroid Build Coastguard Worker int window_diff, use_current = 0, use_previous = 0;
376*e5436536SAndroid Build Coastguard Worker if (hMdct->prev_tl == 0) {
377*e5436536SAndroid Build Coastguard Worker hMdct->prev_wrs = wls;
378*e5436536SAndroid Build Coastguard Worker hMdct->prev_fr = fl;
379*e5436536SAndroid Build Coastguard Worker hMdct->prev_nr = (noOutSamples - fl) >> 1;
380*e5436536SAndroid Build Coastguard Worker hMdct->prev_tl = noOutSamples;
381*e5436536SAndroid Build Coastguard Worker hMdct->ov_offset = 0;
382*e5436536SAndroid Build Coastguard Worker use_current = 1;
383*e5436536SAndroid Build Coastguard Worker }
384*e5436536SAndroid Build Coastguard Worker
385*e5436536SAndroid Build Coastguard Worker window_diff = (hMdct->prev_fr - fl) >> 1;
386*e5436536SAndroid Build Coastguard Worker
387*e5436536SAndroid Build Coastguard Worker /* check if the previous window slope can be adjusted to match the current
388*e5436536SAndroid Build Coastguard Worker * window slope */
389*e5436536SAndroid Build Coastguard Worker if (hMdct->prev_nr + window_diff > 0) {
390*e5436536SAndroid Build Coastguard Worker use_current = 1;
391*e5436536SAndroid Build Coastguard Worker }
392*e5436536SAndroid Build Coastguard Worker /* check if the current window slope can be adjusted to match the previous
393*e5436536SAndroid Build Coastguard Worker * window slope */
394*e5436536SAndroid Build Coastguard Worker if (nl - window_diff > 0) {
395*e5436536SAndroid Build Coastguard Worker use_previous = 1;
396*e5436536SAndroid Build Coastguard Worker }
397*e5436536SAndroid Build Coastguard Worker
398*e5436536SAndroid Build Coastguard Worker /* if both is possible choose the larger of both window slope lengths */
399*e5436536SAndroid Build Coastguard Worker if (use_current && use_previous) {
400*e5436536SAndroid Build Coastguard Worker if (fl < hMdct->prev_fr) {
401*e5436536SAndroid Build Coastguard Worker use_current = 0;
402*e5436536SAndroid Build Coastguard Worker }
403*e5436536SAndroid Build Coastguard Worker }
404*e5436536SAndroid Build Coastguard Worker /*
405*e5436536SAndroid Build Coastguard Worker * If the previous transform block is big enough, enlarge previous window
406*e5436536SAndroid Build Coastguard Worker * overlap, if not, then shrink current window overlap.
407*e5436536SAndroid Build Coastguard Worker */
408*e5436536SAndroid Build Coastguard Worker if (use_current) {
409*e5436536SAndroid Build Coastguard Worker hMdct->prev_nr += window_diff;
410*e5436536SAndroid Build Coastguard Worker hMdct->prev_fr = fl;
411*e5436536SAndroid Build Coastguard Worker hMdct->prev_wrs = wls;
412*e5436536SAndroid Build Coastguard Worker } else {
413*e5436536SAndroid Build Coastguard Worker nl -= window_diff;
414*e5436536SAndroid Build Coastguard Worker fl = hMdct->prev_fr;
415*e5436536SAndroid Build Coastguard Worker }
416*e5436536SAndroid Build Coastguard Worker
417*e5436536SAndroid Build Coastguard Worker *pfl = fl;
418*e5436536SAndroid Build Coastguard Worker *pnl = nl;
419*e5436536SAndroid Build Coastguard Worker }
420*e5436536SAndroid Build Coastguard Worker
421*e5436536SAndroid Build Coastguard Worker /*
422*e5436536SAndroid Build Coastguard Worker This program implements the inverse modulated lapped transform, a generalized
423*e5436536SAndroid Build Coastguard Worker version of the inverse MDCT transform. Setting none of the MLT_*_ALIAS_FLAG
424*e5436536SAndroid Build Coastguard Worker flags computes the IMDCT, setting all of them computes the IMDST. Other
425*e5436536SAndroid Build Coastguard Worker combinations of these flags compute type III transforms used by the RSVD60
426*e5436536SAndroid Build Coastguard Worker multichannel tool for transitions between MDCT/MDST. The following description
427*e5436536SAndroid Build Coastguard Worker relates to the IMDCT only.
428*e5436536SAndroid Build Coastguard Worker
429*e5436536SAndroid Build Coastguard Worker If we pass the data block (A,B,C,D,E,F) to the FORWARD MDCT it will produce two
430*e5436536SAndroid Build Coastguard Worker outputs. The first one will be over the (A,B,C,D) part =>(-D-Cr,A-Br) and the
431*e5436536SAndroid Build Coastguard Worker second one will be over the (C,D,E,F) part => (-F-Er,C-Dr), since there is a
432*e5436536SAndroid Build Coastguard Worker overlap between consequtive passes of the algorithm. This overlap is over the
433*e5436536SAndroid Build Coastguard Worker (C,D) segments. The two outputs will be given sequentially to the DCT IV
434*e5436536SAndroid Build Coastguard Worker algorithm. At the INVERSE MDCT side we get two consecutive outputs from the IDCT
435*e5436536SAndroid Build Coastguard Worker IV algorithm, namely the same blocks: (-D-Cr,A-Br) and (-F-Er,C-Dr). The first
436*e5436536SAndroid Build Coastguard Worker of them lands in the Overlap buffer and the second is in the working one, which,
437*e5436536SAndroid Build Coastguard Worker one algorithm pass later will substitute the one residing in the overlap
438*e5436536SAndroid Build Coastguard Worker register. The IMDCT algorithm has to produce the C and D segments from the two
439*e5436536SAndroid Build Coastguard Worker buffers. In order to do this we take the left part of the overlap
440*e5436536SAndroid Build Coastguard Worker buffer(-D-Cr,A-Br), namely (-D-Cr) and add it appropriately to the right part of
441*e5436536SAndroid Build Coastguard Worker the working buffer (-F-Er,C-Dr), namely (C-Dr), so that we get first the C
442*e5436536SAndroid Build Coastguard Worker segment and later the D segment. We do this in the following way: From the right
443*e5436536SAndroid Build Coastguard Worker part of the working buffer(C-Dr) we subtract the flipped left part of the
444*e5436536SAndroid Build Coastguard Worker overlap buffer(-D-Cr):
445*e5436536SAndroid Build Coastguard Worker
446*e5436536SAndroid Build Coastguard Worker Result = (C-Dr) - flipped(-D-Cr) = C -Dr + Dr + C = 2C
447*e5436536SAndroid Build Coastguard Worker We divide by two and get the C segment. What we did is adding the right part of
448*e5436536SAndroid Build Coastguard Worker the first frame to the left part of the second one. While applying these
449*e5436536SAndroid Build Coastguard Worker operation we multiply the respective segments with the appropriate window
450*e5436536SAndroid Build Coastguard Worker functions.
451*e5436536SAndroid Build Coastguard Worker
452*e5436536SAndroid Build Coastguard Worker In order to get the D segment we do the following:
453*e5436536SAndroid Build Coastguard Worker From the negated second part of the working buffer(C-Dr) we subtract the flipped
454*e5436536SAndroid Build Coastguard Worker first part of the overlap buffer (-D-Cr):
455*e5436536SAndroid Build Coastguard Worker
456*e5436536SAndroid Build Coastguard Worker Result= - (C -Dr) - flipped(-D-Cr)= -C +Dr +Dr +C = 2Dr.
457*e5436536SAndroid Build Coastguard Worker After dividing by two and flipping we get the D segment.What we did is adding
458*e5436536SAndroid Build Coastguard Worker the right part of the first frame to the left part of the second one. While
459*e5436536SAndroid Build Coastguard Worker applying these operation we multiply the respective segments with the
460*e5436536SAndroid Build Coastguard Worker appropriate window functions.
461*e5436536SAndroid Build Coastguard Worker
462*e5436536SAndroid Build Coastguard Worker Once we have obtained the C and D segments the overlap buffer is emptied and the
463*e5436536SAndroid Build Coastguard Worker current buffer is sent in it, so that the E and F segments are available for
464*e5436536SAndroid Build Coastguard Worker decoding in the next algorithm pass.*/
imlt_block(H_MDCT hMdct,FIXP_DBL * output,FIXP_DBL * spectrum,const SHORT scalefactor[],const INT nSpec,const INT noOutSamples,const INT tl,const FIXP_WTP * wls,INT fl,const FIXP_WTP * wrs,const INT fr,FIXP_DBL gain,int flags)465*e5436536SAndroid Build Coastguard Worker INT imlt_block(H_MDCT hMdct, FIXP_DBL *output, FIXP_DBL *spectrum,
466*e5436536SAndroid Build Coastguard Worker const SHORT scalefactor[], const INT nSpec,
467*e5436536SAndroid Build Coastguard Worker const INT noOutSamples, const INT tl, const FIXP_WTP *wls,
468*e5436536SAndroid Build Coastguard Worker INT fl, const FIXP_WTP *wrs, const INT fr, FIXP_DBL gain,
469*e5436536SAndroid Build Coastguard Worker int flags) {
470*e5436536SAndroid Build Coastguard Worker FIXP_DBL *pOvl;
471*e5436536SAndroid Build Coastguard Worker FIXP_DBL *pOut0 = output, *pOut1;
472*e5436536SAndroid Build Coastguard Worker INT nl, nr;
473*e5436536SAndroid Build Coastguard Worker int w, i, nrSamples = 0, specShiftScale, transform_gain_e = 0;
474*e5436536SAndroid Build Coastguard Worker int currAliasSymmetry = (flags & MLT_FLAG_CURR_ALIAS_SYMMETRY);
475*e5436536SAndroid Build Coastguard Worker
476*e5436536SAndroid Build Coastguard Worker /* Derive NR and NL */
477*e5436536SAndroid Build Coastguard Worker nr = (tl - fr) >> 1;
478*e5436536SAndroid Build Coastguard Worker nl = (tl - fl) >> 1;
479*e5436536SAndroid Build Coastguard Worker
480*e5436536SAndroid Build Coastguard Worker /* Include 2/N IMDCT gain into gain factor and exponent. */
481*e5436536SAndroid Build Coastguard Worker imdct_gain(&gain, &transform_gain_e, tl);
482*e5436536SAndroid Build Coastguard Worker
483*e5436536SAndroid Build Coastguard Worker /* Detect FRprevious / FL mismatches and override parameters accordingly */
484*e5436536SAndroid Build Coastguard Worker if (hMdct->prev_fr != fl) {
485*e5436536SAndroid Build Coastguard Worker imdct_adapt_parameters(hMdct, &fl, &nl, tl, wls, noOutSamples);
486*e5436536SAndroid Build Coastguard Worker }
487*e5436536SAndroid Build Coastguard Worker
488*e5436536SAndroid Build Coastguard Worker pOvl = hMdct->overlap.freq + hMdct->ov_size - 1;
489*e5436536SAndroid Build Coastguard Worker
490*e5436536SAndroid Build Coastguard Worker if (noOutSamples > nrSamples) {
491*e5436536SAndroid Build Coastguard Worker /* Purge buffered output. */
492*e5436536SAndroid Build Coastguard Worker for (i = 0; i < hMdct->ov_offset; i++) {
493*e5436536SAndroid Build Coastguard Worker *pOut0 = hMdct->overlap.time[i];
494*e5436536SAndroid Build Coastguard Worker pOut0++;
495*e5436536SAndroid Build Coastguard Worker }
496*e5436536SAndroid Build Coastguard Worker nrSamples = hMdct->ov_offset;
497*e5436536SAndroid Build Coastguard Worker hMdct->ov_offset = 0;
498*e5436536SAndroid Build Coastguard Worker }
499*e5436536SAndroid Build Coastguard Worker
500*e5436536SAndroid Build Coastguard Worker for (w = 0; w < nSpec; w++) {
501*e5436536SAndroid Build Coastguard Worker FIXP_DBL *pSpec, *pCurr;
502*e5436536SAndroid Build Coastguard Worker const FIXP_WTP *pWindow;
503*e5436536SAndroid Build Coastguard Worker
504*e5436536SAndroid Build Coastguard Worker /* Detect FRprevious / FL mismatches and override parameters accordingly */
505*e5436536SAndroid Build Coastguard Worker if (hMdct->prev_fr != fl) {
506*e5436536SAndroid Build Coastguard Worker imdct_adapt_parameters(hMdct, &fl, &nl, tl, wls, noOutSamples);
507*e5436536SAndroid Build Coastguard Worker }
508*e5436536SAndroid Build Coastguard Worker
509*e5436536SAndroid Build Coastguard Worker specShiftScale = transform_gain_e;
510*e5436536SAndroid Build Coastguard Worker
511*e5436536SAndroid Build Coastguard Worker /* Setup window pointers */
512*e5436536SAndroid Build Coastguard Worker pWindow = hMdct->prev_wrs;
513*e5436536SAndroid Build Coastguard Worker
514*e5436536SAndroid Build Coastguard Worker /* Current spectrum */
515*e5436536SAndroid Build Coastguard Worker pSpec = spectrum + w * tl;
516*e5436536SAndroid Build Coastguard Worker
517*e5436536SAndroid Build Coastguard Worker /* DCT IV of current spectrum. */
518*e5436536SAndroid Build Coastguard Worker if (currAliasSymmetry == 0) {
519*e5436536SAndroid Build Coastguard Worker if (hMdct->prevAliasSymmetry == 0) {
520*e5436536SAndroid Build Coastguard Worker dct_IV(pSpec, tl, &specShiftScale);
521*e5436536SAndroid Build Coastguard Worker } else {
522*e5436536SAndroid Build Coastguard Worker FIXP_DBL _tmp[1024 + ALIGNMENT_DEFAULT / sizeof(FIXP_DBL)];
523*e5436536SAndroid Build Coastguard Worker FIXP_DBL *tmp = (FIXP_DBL *)ALIGN_PTR(_tmp);
524*e5436536SAndroid Build Coastguard Worker C_ALLOC_ALIGNED_REGISTER(tmp, sizeof(_tmp));
525*e5436536SAndroid Build Coastguard Worker dct_III(pSpec, tmp, tl, &specShiftScale);
526*e5436536SAndroid Build Coastguard Worker C_ALLOC_ALIGNED_UNREGISTER(tmp);
527*e5436536SAndroid Build Coastguard Worker }
528*e5436536SAndroid Build Coastguard Worker } else {
529*e5436536SAndroid Build Coastguard Worker if (hMdct->prevAliasSymmetry == 0) {
530*e5436536SAndroid Build Coastguard Worker FIXP_DBL _tmp[1024 + ALIGNMENT_DEFAULT / sizeof(FIXP_DBL)];
531*e5436536SAndroid Build Coastguard Worker FIXP_DBL *tmp = (FIXP_DBL *)ALIGN_PTR(_tmp);
532*e5436536SAndroid Build Coastguard Worker C_ALLOC_ALIGNED_REGISTER(tmp, sizeof(_tmp));
533*e5436536SAndroid Build Coastguard Worker dst_III(pSpec, tmp, tl, &specShiftScale);
534*e5436536SAndroid Build Coastguard Worker C_ALLOC_ALIGNED_UNREGISTER(tmp);
535*e5436536SAndroid Build Coastguard Worker } else {
536*e5436536SAndroid Build Coastguard Worker dst_IV(pSpec, tl, &specShiftScale);
537*e5436536SAndroid Build Coastguard Worker }
538*e5436536SAndroid Build Coastguard Worker }
539*e5436536SAndroid Build Coastguard Worker
540*e5436536SAndroid Build Coastguard Worker /* Optional scaling of time domain - no yet windowed - of current spectrum
541*e5436536SAndroid Build Coastguard Worker */
542*e5436536SAndroid Build Coastguard Worker /* and de-scale current spectrum signal (time domain, no yet windowed) */
543*e5436536SAndroid Build Coastguard Worker if (gain != (FIXP_DBL)0) {
544*e5436536SAndroid Build Coastguard Worker for (i = 0; i < tl; i++) {
545*e5436536SAndroid Build Coastguard Worker pSpec[i] = fMult(pSpec[i], gain);
546*e5436536SAndroid Build Coastguard Worker }
547*e5436536SAndroid Build Coastguard Worker }
548*e5436536SAndroid Build Coastguard Worker
549*e5436536SAndroid Build Coastguard Worker {
550*e5436536SAndroid Build Coastguard Worker int loc_scale =
551*e5436536SAndroid Build Coastguard Worker fixmin_I(scalefactor[w] + specShiftScale, (INT)DFRACT_BITS - 1);
552*e5436536SAndroid Build Coastguard Worker DWORD_ALIGNED(pSpec);
553*e5436536SAndroid Build Coastguard Worker scaleValuesSaturate(pSpec, tl, loc_scale);
554*e5436536SAndroid Build Coastguard Worker }
555*e5436536SAndroid Build Coastguard Worker
556*e5436536SAndroid Build Coastguard Worker if (noOutSamples <= nrSamples) {
557*e5436536SAndroid Build Coastguard Worker /* Divert output first half to overlap buffer if we already got enough
558*e5436536SAndroid Build Coastguard Worker * output samples. */
559*e5436536SAndroid Build Coastguard Worker pOut0 = hMdct->overlap.time + hMdct->ov_offset;
560*e5436536SAndroid Build Coastguard Worker hMdct->ov_offset += hMdct->prev_nr + fl / 2;
561*e5436536SAndroid Build Coastguard Worker } else {
562*e5436536SAndroid Build Coastguard Worker /* Account output samples */
563*e5436536SAndroid Build Coastguard Worker nrSamples += hMdct->prev_nr + fl / 2;
564*e5436536SAndroid Build Coastguard Worker }
565*e5436536SAndroid Build Coastguard Worker
566*e5436536SAndroid Build Coastguard Worker /* NR output samples 0 .. NR. -overlap[TL/2..TL/2-NR] */
567*e5436536SAndroid Build Coastguard Worker if ((hMdct->pFacZir != 0) && (hMdct->prev_nr == fl / 2)) {
568*e5436536SAndroid Build Coastguard Worker /* In the case of ACELP -> TCX20 -> FD short add FAC ZIR on nr signal part
569*e5436536SAndroid Build Coastguard Worker */
570*e5436536SAndroid Build Coastguard Worker for (i = 0; i < hMdct->prev_nr; i++) {
571*e5436536SAndroid Build Coastguard Worker FIXP_DBL x = -(*pOvl--);
572*e5436536SAndroid Build Coastguard Worker *pOut0 = fAddSaturate(x, IMDCT_SCALE_DBL(hMdct->pFacZir[i]));
573*e5436536SAndroid Build Coastguard Worker pOut0++;
574*e5436536SAndroid Build Coastguard Worker }
575*e5436536SAndroid Build Coastguard Worker hMdct->pFacZir = NULL;
576*e5436536SAndroid Build Coastguard Worker } else {
577*e5436536SAndroid Build Coastguard Worker /* Here we implement a simplified version of what happens after the this
578*e5436536SAndroid Build Coastguard Worker piece of code (see the comments below). We implement the folding of C and
579*e5436536SAndroid Build Coastguard Worker D segments from (-D-Cr) but D is zero, because in this part of the MDCT
580*e5436536SAndroid Build Coastguard Worker sequence the window coefficients with which D must be multiplied are zero.
581*e5436536SAndroid Build Coastguard Worker "pOut0" writes sequentially the C block from left to right. */
582*e5436536SAndroid Build Coastguard Worker if (hMdct->prevPrevAliasSymmetry == 0) {
583*e5436536SAndroid Build Coastguard Worker for (i = 0; i < hMdct->prev_nr; i++) {
584*e5436536SAndroid Build Coastguard Worker FIXP_DBL x = -(*pOvl--);
585*e5436536SAndroid Build Coastguard Worker *pOut0 = IMDCT_SCALE_DBL(x);
586*e5436536SAndroid Build Coastguard Worker pOut0++;
587*e5436536SAndroid Build Coastguard Worker }
588*e5436536SAndroid Build Coastguard Worker } else {
589*e5436536SAndroid Build Coastguard Worker for (i = 0; i < hMdct->prev_nr; i++) {
590*e5436536SAndroid Build Coastguard Worker FIXP_DBL x = *pOvl--;
591*e5436536SAndroid Build Coastguard Worker *pOut0 = IMDCT_SCALE_DBL(x);
592*e5436536SAndroid Build Coastguard Worker pOut0++;
593*e5436536SAndroid Build Coastguard Worker }
594*e5436536SAndroid Build Coastguard Worker }
595*e5436536SAndroid Build Coastguard Worker }
596*e5436536SAndroid Build Coastguard Worker
597*e5436536SAndroid Build Coastguard Worker if (noOutSamples <= nrSamples) {
598*e5436536SAndroid Build Coastguard Worker /* Divert output second half to overlap buffer if we already got enough
599*e5436536SAndroid Build Coastguard Worker * output samples. */
600*e5436536SAndroid Build Coastguard Worker pOut1 = hMdct->overlap.time + hMdct->ov_offset + fl / 2 - 1;
601*e5436536SAndroid Build Coastguard Worker hMdct->ov_offset += fl / 2 + nl;
602*e5436536SAndroid Build Coastguard Worker } else {
603*e5436536SAndroid Build Coastguard Worker pOut1 = pOut0 + (fl - 1);
604*e5436536SAndroid Build Coastguard Worker nrSamples += fl / 2 + nl;
605*e5436536SAndroid Build Coastguard Worker }
606*e5436536SAndroid Build Coastguard Worker
607*e5436536SAndroid Build Coastguard Worker /* output samples before window crossing point NR .. TL/2.
608*e5436536SAndroid Build Coastguard Worker * -overlap[TL/2-NR..TL/2-NR-FL/2] + current[NR..TL/2] */
609*e5436536SAndroid Build Coastguard Worker /* output samples after window crossing point TL/2 .. TL/2+FL/2.
610*e5436536SAndroid Build Coastguard Worker * -overlap[0..FL/2] - current[TL/2..FL/2] */
611*e5436536SAndroid Build Coastguard Worker pCurr = pSpec + tl - fl / 2;
612*e5436536SAndroid Build Coastguard Worker DWORD_ALIGNED(pCurr);
613*e5436536SAndroid Build Coastguard Worker C_ALLOC_ALIGNED_REGISTER(pWindow, fl);
614*e5436536SAndroid Build Coastguard Worker DWORD_ALIGNED(pWindow);
615*e5436536SAndroid Build Coastguard Worker C_ALLOC_ALIGNED_UNREGISTER(pWindow);
616*e5436536SAndroid Build Coastguard Worker
617*e5436536SAndroid Build Coastguard Worker if (hMdct->prevPrevAliasSymmetry == 0) {
618*e5436536SAndroid Build Coastguard Worker if (hMdct->prevAliasSymmetry == 0) {
619*e5436536SAndroid Build Coastguard Worker if (!hMdct->pAsymOvlp) {
620*e5436536SAndroid Build Coastguard Worker for (i = 0; i < fl / 2; i++) {
621*e5436536SAndroid Build Coastguard Worker FIXP_DBL x0, x1;
622*e5436536SAndroid Build Coastguard Worker cplxMultDiv2(&x1, &x0, *pCurr++, -*pOvl--, pWindow[i]);
623*e5436536SAndroid Build Coastguard Worker *pOut0 = IMDCT_SCALE_DBL_LSH1(x0);
624*e5436536SAndroid Build Coastguard Worker *pOut1 = IMDCT_SCALE_DBL_LSH1(-x1);
625*e5436536SAndroid Build Coastguard Worker pOut0++;
626*e5436536SAndroid Build Coastguard Worker pOut1--;
627*e5436536SAndroid Build Coastguard Worker }
628*e5436536SAndroid Build Coastguard Worker } else {
629*e5436536SAndroid Build Coastguard Worker FIXP_DBL *pAsymOvl = hMdct->pAsymOvlp + fl / 2 - 1;
630*e5436536SAndroid Build Coastguard Worker for (i = 0; i < fl / 2; i++) {
631*e5436536SAndroid Build Coastguard Worker FIXP_DBL x0, x1;
632*e5436536SAndroid Build Coastguard Worker x1 = -fMultDiv2(*pCurr, pWindow[i].v.re) +
633*e5436536SAndroid Build Coastguard Worker fMultDiv2(*pAsymOvl, pWindow[i].v.im);
634*e5436536SAndroid Build Coastguard Worker x0 = fMultDiv2(*pCurr, pWindow[i].v.im) -
635*e5436536SAndroid Build Coastguard Worker fMultDiv2(*pOvl, pWindow[i].v.re);
636*e5436536SAndroid Build Coastguard Worker pCurr++;
637*e5436536SAndroid Build Coastguard Worker pOvl--;
638*e5436536SAndroid Build Coastguard Worker pAsymOvl--;
639*e5436536SAndroid Build Coastguard Worker *pOut0++ = IMDCT_SCALE_DBL_LSH1(x0);
640*e5436536SAndroid Build Coastguard Worker *pOut1-- = IMDCT_SCALE_DBL_LSH1(x1);
641*e5436536SAndroid Build Coastguard Worker }
642*e5436536SAndroid Build Coastguard Worker hMdct->pAsymOvlp = NULL;
643*e5436536SAndroid Build Coastguard Worker }
644*e5436536SAndroid Build Coastguard Worker } else { /* prevAliasingSymmetry == 1 */
645*e5436536SAndroid Build Coastguard Worker for (i = 0; i < fl / 2; i++) {
646*e5436536SAndroid Build Coastguard Worker FIXP_DBL x0, x1;
647*e5436536SAndroid Build Coastguard Worker cplxMultDiv2(&x1, &x0, *pCurr++, -*pOvl--, pWindow[i]);
648*e5436536SAndroid Build Coastguard Worker *pOut0 = IMDCT_SCALE_DBL_LSH1(x0);
649*e5436536SAndroid Build Coastguard Worker *pOut1 = IMDCT_SCALE_DBL_LSH1(x1);
650*e5436536SAndroid Build Coastguard Worker pOut0++;
651*e5436536SAndroid Build Coastguard Worker pOut1--;
652*e5436536SAndroid Build Coastguard Worker }
653*e5436536SAndroid Build Coastguard Worker }
654*e5436536SAndroid Build Coastguard Worker } else { /* prevPrevAliasingSymmetry == 1 */
655*e5436536SAndroid Build Coastguard Worker if (hMdct->prevAliasSymmetry == 0) {
656*e5436536SAndroid Build Coastguard Worker for (i = 0; i < fl / 2; i++) {
657*e5436536SAndroid Build Coastguard Worker FIXP_DBL x0, x1;
658*e5436536SAndroid Build Coastguard Worker cplxMultDiv2(&x1, &x0, *pCurr++, *pOvl--, pWindow[i]);
659*e5436536SAndroid Build Coastguard Worker *pOut0 = IMDCT_SCALE_DBL_LSH1(x0);
660*e5436536SAndroid Build Coastguard Worker *pOut1 = IMDCT_SCALE_DBL_LSH1(-x1);
661*e5436536SAndroid Build Coastguard Worker pOut0++;
662*e5436536SAndroid Build Coastguard Worker pOut1--;
663*e5436536SAndroid Build Coastguard Worker }
664*e5436536SAndroid Build Coastguard Worker } else { /* prevAliasingSymmetry == 1 */
665*e5436536SAndroid Build Coastguard Worker for (i = 0; i < fl / 2; i++) {
666*e5436536SAndroid Build Coastguard Worker FIXP_DBL x0, x1;
667*e5436536SAndroid Build Coastguard Worker cplxMultDiv2(&x1, &x0, *pCurr++, *pOvl--, pWindow[i]);
668*e5436536SAndroid Build Coastguard Worker *pOut0 = IMDCT_SCALE_DBL_LSH1(x0);
669*e5436536SAndroid Build Coastguard Worker *pOut1 = IMDCT_SCALE_DBL_LSH1(x1);
670*e5436536SAndroid Build Coastguard Worker pOut0++;
671*e5436536SAndroid Build Coastguard Worker pOut1--;
672*e5436536SAndroid Build Coastguard Worker }
673*e5436536SAndroid Build Coastguard Worker }
674*e5436536SAndroid Build Coastguard Worker }
675*e5436536SAndroid Build Coastguard Worker
676*e5436536SAndroid Build Coastguard Worker if (hMdct->pFacZir != 0) {
677*e5436536SAndroid Build Coastguard Worker /* add FAC ZIR of previous ACELP -> mdct transition */
678*e5436536SAndroid Build Coastguard Worker FIXP_DBL *pOut = pOut0 - fl / 2;
679*e5436536SAndroid Build Coastguard Worker FDK_ASSERT(fl / 2 <= 128);
680*e5436536SAndroid Build Coastguard Worker for (i = 0; i < fl / 2; i++) {
681*e5436536SAndroid Build Coastguard Worker pOut[i] = fAddSaturate(pOut[i], IMDCT_SCALE_DBL(hMdct->pFacZir[i]));
682*e5436536SAndroid Build Coastguard Worker }
683*e5436536SAndroid Build Coastguard Worker hMdct->pFacZir = NULL;
684*e5436536SAndroid Build Coastguard Worker }
685*e5436536SAndroid Build Coastguard Worker pOut0 += (fl / 2) + nl;
686*e5436536SAndroid Build Coastguard Worker
687*e5436536SAndroid Build Coastguard Worker /* NL output samples TL/2+FL/2..TL. - current[FL/2..0] */
688*e5436536SAndroid Build Coastguard Worker pOut1 += (fl / 2) + 1;
689*e5436536SAndroid Build Coastguard Worker pCurr = pSpec + tl - fl / 2 - 1;
690*e5436536SAndroid Build Coastguard Worker /* Here we implement a simplified version of what happens above the this
691*e5436536SAndroid Build Coastguard Worker piece of code (see the comments above). We implement the folding of C and D
692*e5436536SAndroid Build Coastguard Worker segments from (C-Dr) but C is zero, because in this part of the MDCT
693*e5436536SAndroid Build Coastguard Worker sequence the window coefficients with which C must be multiplied are zero.
694*e5436536SAndroid Build Coastguard Worker "pOut1" writes sequentially the D block from left to right. */
695*e5436536SAndroid Build Coastguard Worker if (hMdct->prevAliasSymmetry == 0) {
696*e5436536SAndroid Build Coastguard Worker for (i = 0; i < nl; i++) {
697*e5436536SAndroid Build Coastguard Worker FIXP_DBL x = -(*pCurr--);
698*e5436536SAndroid Build Coastguard Worker *pOut1++ = IMDCT_SCALE_DBL(x);
699*e5436536SAndroid Build Coastguard Worker }
700*e5436536SAndroid Build Coastguard Worker } else {
701*e5436536SAndroid Build Coastguard Worker for (i = 0; i < nl; i++) {
702*e5436536SAndroid Build Coastguard Worker FIXP_DBL x = *pCurr--;
703*e5436536SAndroid Build Coastguard Worker *pOut1++ = IMDCT_SCALE_DBL(x);
704*e5436536SAndroid Build Coastguard Worker }
705*e5436536SAndroid Build Coastguard Worker }
706*e5436536SAndroid Build Coastguard Worker
707*e5436536SAndroid Build Coastguard Worker /* Set overlap source pointer for next window pOvl = pSpec + tl/2 - 1; */
708*e5436536SAndroid Build Coastguard Worker pOvl = pSpec + tl / 2 - 1;
709*e5436536SAndroid Build Coastguard Worker
710*e5436536SAndroid Build Coastguard Worker /* Previous window values. */
711*e5436536SAndroid Build Coastguard Worker hMdct->prev_nr = nr;
712*e5436536SAndroid Build Coastguard Worker hMdct->prev_fr = fr;
713*e5436536SAndroid Build Coastguard Worker hMdct->prev_tl = tl;
714*e5436536SAndroid Build Coastguard Worker hMdct->prev_wrs = wrs;
715*e5436536SAndroid Build Coastguard Worker
716*e5436536SAndroid Build Coastguard Worker /* Previous aliasing symmetry */
717*e5436536SAndroid Build Coastguard Worker hMdct->prevPrevAliasSymmetry = hMdct->prevAliasSymmetry;
718*e5436536SAndroid Build Coastguard Worker hMdct->prevAliasSymmetry = currAliasSymmetry;
719*e5436536SAndroid Build Coastguard Worker }
720*e5436536SAndroid Build Coastguard Worker
721*e5436536SAndroid Build Coastguard Worker /* Save overlap */
722*e5436536SAndroid Build Coastguard Worker
723*e5436536SAndroid Build Coastguard Worker pOvl = hMdct->overlap.freq + hMdct->ov_size - tl / 2;
724*e5436536SAndroid Build Coastguard Worker FDKmemcpy(pOvl, &spectrum[(nSpec - 1) * tl], (tl / 2) * sizeof(FIXP_DBL));
725*e5436536SAndroid Build Coastguard Worker
726*e5436536SAndroid Build Coastguard Worker return nrSamples;
727*e5436536SAndroid Build Coastguard Worker }
728