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