• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /**************************** AAC decoder library ******************************
96 
97    Author(s):   Manuel Jander
98 
99    Description: USAC FAC
100 
101 *******************************************************************************/
102 
103 #include "usacdec_fac.h"
104 
105 #include "usacdec_const.h"
106 #include "usacdec_lpc.h"
107 #include "usacdec_acelp.h"
108 #include "usacdec_rom.h"
109 #include "dct.h"
110 #include "FDK_tools_rom.h"
111 #include "mdct.h"
112 
113 #define SPEC_FAC(ptr, i, gl) ((ptr) + ((i) * (gl)))
114 
CLpd_FAC_GetMemory(CAacDecoderChannelInfo * pAacDecoderChannelInfo,UCHAR mod[NB_DIV],int * pState)115 FIXP_DBL *CLpd_FAC_GetMemory(CAacDecoderChannelInfo *pAacDecoderChannelInfo,
116                              UCHAR mod[NB_DIV], int *pState) {
117   FIXP_DBL *ptr;
118   int i;
119   int k = 0;
120   int max_windows = 8;
121 
122   FDK_ASSERT(*pState >= 0 && *pState < max_windows);
123 
124   /* Look for free space to store FAC data. 2 FAC data blocks fit into each TCX
125    * spectral data block. */
126   for (i = *pState; i < max_windows; i++) {
127     if (mod[i >> 1] == 0) {
128       break;
129     }
130   }
131 
132   *pState = i + 1;
133 
134   if (i == max_windows) {
135     ptr = pAacDecoderChannelInfo->data.usac.fac_data0;
136   } else {
137     FDK_ASSERT(mod[(i >> 1)] == 0);
138     ptr = SPEC_FAC(pAacDecoderChannelInfo->pSpectralCoefficient, i,
139                    pAacDecoderChannelInfo->granuleLength << k);
140   }
141 
142   return ptr;
143 }
144 
CLpd_FAC_Read(HANDLE_FDK_BITSTREAM hBs,FIXP_DBL * pFac,SCHAR * pFacScale,int length,int use_gain,int frame)145 int CLpd_FAC_Read(HANDLE_FDK_BITSTREAM hBs, FIXP_DBL *pFac, SCHAR *pFacScale,
146                   int length, int use_gain, int frame) {
147   FIXP_DBL fac_gain;
148   int fac_gain_e = 0;
149 
150   if (use_gain) {
151     CLpd_DecodeGain(&fac_gain, &fac_gain_e, FDKreadBits(hBs, 7));
152   }
153 
154   if (CLpc_DecodeAVQ(hBs, pFac, 1, 1, length) != 0) {
155     return -1;
156   }
157 
158   {
159     int scale;
160 
161     scale = getScalefactor(pFac, length);
162     scaleValues(pFac, length, scale);
163     pFacScale[frame] = DFRACT_BITS - 1 - scale;
164   }
165 
166   if (use_gain) {
167     int i;
168 
169     pFacScale[frame] += fac_gain_e;
170 
171     for (i = 0; i < length; i++) {
172       pFac[i] = fMult(pFac[i], fac_gain);
173     }
174   }
175   return 0;
176 }
177 
178 /**
179  * \brief Apply synthesis filter with zero input to x. The overall filter gain
180  * is 1.0.
181  * \param a LPC filter coefficients.
182  * \param length length of the input/output data vector x.
183  * \param x input/output vector, where the synthesis filter is applied in place.
184  */
Syn_filt_zero(const FIXP_LPC a[],const INT a_exp,INT length,FIXP_DBL x[])185 static void Syn_filt_zero(const FIXP_LPC a[], const INT a_exp, INT length,
186                           FIXP_DBL x[]) {
187   int i, j;
188   FIXP_DBL L_tmp;
189 
190   for (i = 0; i < length; i++) {
191     L_tmp = (FIXP_DBL)0;
192 
193     for (j = 0; j < fMin(i, M_LP_FILTER_ORDER); j++) {
194       L_tmp -= fMultDiv2(a[j], x[i - (j + 1)]) >> (LP_FILTER_SCALE - 1);
195     }
196 
197     L_tmp = scaleValue(L_tmp, a_exp + LP_FILTER_SCALE);
198     x[i] = fAddSaturate(x[i], L_tmp);
199   }
200 }
201 
202 /* Table is also correct for coreCoderFrameLength = 768. Factor 3/4 is canceled
203    out: gainFac = 0.5 * sqrt(fac_length/lFrame)
204 */
205 static const FIXP_DBL gainFac[4] = {0x40000000, 0x2d413ccd, 0x20000000,
206                                     0x16a09e66};
207 
CFac_ApplyGains(FIXP_DBL fac_data[LFAC],const INT fac_length,const FIXP_DBL tcx_gain,const FIXP_DBL alfd_gains[],const INT mod)208 void CFac_ApplyGains(FIXP_DBL fac_data[LFAC], const INT fac_length,
209                      const FIXP_DBL tcx_gain, const FIXP_DBL alfd_gains[],
210                      const INT mod) {
211   FIXP_DBL facFactor;
212   int i;
213 
214   FDK_ASSERT((fac_length == 128) || (fac_length == 96));
215 
216   /* 2) Apply gain factor to FAC data */
217   facFactor = fMult(gainFac[mod], tcx_gain);
218   for (i = 0; i < fac_length; i++) {
219     fac_data[i] = fMult(fac_data[i], facFactor);
220   }
221 
222   /* 3) Apply spectrum deshaping using alfd_gains */
223   for (i = 0; i < fac_length / 4; i++) {
224     int k;
225 
226     k = i >> (3 - mod);
227     fac_data[i] = fMult(fac_data[i], alfd_gains[k])
228                   << 1; /* alfd_gains is scaled by one bit. */
229   }
230 }
231 
CFac_CalcFacSignal(FIXP_DBL * pOut,FIXP_DBL * pFac,const int fac_scale,const int fac_length,const FIXP_LPC A[M_LP_FILTER_ORDER],const INT A_exp,const int fAddZir,const int isFdFac)232 static void CFac_CalcFacSignal(FIXP_DBL *pOut, FIXP_DBL *pFac,
233                                const int fac_scale, const int fac_length,
234                                const FIXP_LPC A[M_LP_FILTER_ORDER],
235                                const INT A_exp, const int fAddZir,
236                                const int isFdFac) {
237   FIXP_LPC wA[M_LP_FILTER_ORDER];
238   FIXP_DBL tf_gain = (FIXP_DBL)0;
239   int wlength;
240   int scale = fac_scale;
241 
242   /* obtain tranform gain. */
243   imdct_gain(&tf_gain, &scale, isFdFac ? 0 : fac_length);
244 
245   /* 4) Compute inverse DCT-IV of FAC data. Output scale of DCT IV is 16 bits.
246    */
247   dct_IV(pFac, fac_length, &scale);
248   /* dct_IV scale = log2(fac_length). "- 7" is a factor of 2/128 */
249   if (tf_gain != (FIXP_DBL)0) { /* non-radix 2 transform gain */
250     int i;
251 
252     for (i = 0; i < fac_length; i++) {
253       pFac[i] = fMult(tf_gain, pFac[i]);
254     }
255   }
256   scaleValuesSaturate(pOut, pFac, fac_length,
257                       scale); /* Avoid overflow issues and saturate. */
258 
259   E_LPC_a_weight(wA, A, M_LP_FILTER_ORDER);
260 
261   /* We need the output of the IIR filter to be longer than "fac_length".
262   For this reason we run it with zero input appended to the end of the input
263   sequence, i.e. we generate its ZIR and extend the output signal.*/
264   FDKmemclear(pOut + fac_length, fac_length * sizeof(FIXP_DBL));
265   wlength = 2 * fac_length;
266 
267   /* 5) Apply weighted synthesis filter to FAC data, including optional Zir (5.
268    * item 4). */
269   Syn_filt_zero(wA, A_exp, wlength, pOut);
270 }
271 
CLpd_FAC_Mdct2Acelp(H_MDCT hMdct,FIXP_DBL * output,FIXP_DBL * pFac,const int fac_scale,FIXP_LPC * A,INT A_exp,INT nrOutSamples,const INT fac_length,const INT isFdFac,UCHAR prevWindowShape)272 INT CLpd_FAC_Mdct2Acelp(H_MDCT hMdct, FIXP_DBL *output, FIXP_DBL *pFac,
273                         const int fac_scale, FIXP_LPC *A, INT A_exp,
274                         INT nrOutSamples, const INT fac_length,
275                         const INT isFdFac, UCHAR prevWindowShape) {
276   FIXP_DBL *pOvl;
277   FIXP_DBL *pOut0;
278   const FIXP_WTP *pWindow;
279   int i, fl, nrSamples = 0;
280 
281   FDK_ASSERT(fac_length <= 1024 / (4 * 2));
282 
283   fl = fac_length * 2;
284 
285   pWindow = FDKgetWindowSlope(fl, prevWindowShape);
286 
287   /* Adapt window slope length in case of frame loss. */
288   if (hMdct->prev_fr != fl) {
289     int nl = 0;
290     imdct_adapt_parameters(hMdct, &fl, &nl, fac_length, pWindow, nrOutSamples);
291     FDK_ASSERT(nl == 0);
292   }
293 
294   if (nrSamples < nrOutSamples) {
295     pOut0 = output;
296     nrSamples += hMdct->ov_offset;
297     /* Purge buffered output. */
298     FDKmemcpy(pOut0, hMdct->overlap.time, hMdct->ov_offset * sizeof(pOut0[0]));
299     hMdct->ov_offset = 0;
300   }
301 
302   pOvl = hMdct->overlap.freq + hMdct->ov_size - 1;
303 
304   if (nrSamples >= nrOutSamples) {
305     pOut0 = hMdct->overlap.time + hMdct->ov_offset;
306     hMdct->ov_offset += hMdct->prev_nr + fl / 2;
307   } else {
308     pOut0 = output + nrSamples;
309     nrSamples += hMdct->prev_nr + fl / 2;
310   }
311   if (hMdct->prevPrevAliasSymmetry == 0) {
312     for (i = 0; i < hMdct->prev_nr; i++) {
313       FIXP_DBL x = -(*pOvl--);
314       *pOut0 = IMDCT_SCALE_DBL(x);
315       pOut0++;
316     }
317   } else {
318     for (i = 0; i < hMdct->prev_nr; i++) {
319       FIXP_DBL x = (*pOvl--);
320       *pOut0 = IMDCT_SCALE_DBL(x);
321       pOut0++;
322     }
323   }
324   hMdct->prev_nr = 0;
325 
326   {
327     if (pFac != NULL) {
328       /* Note: The FAC gain might have been applied directly after bit stream
329        * parse in this case. */
330       CFac_CalcFacSignal(pOut0, pFac, fac_scale, fac_length, A, A_exp, 0,
331                          isFdFac);
332     } else {
333       /* Clear buffer because of the overlap and ADD! */
334       FDKmemclear(pOut0, fac_length * sizeof(FIXP_DBL));
335     }
336   }
337 
338   i = 0;
339 
340   if (hMdct->prevPrevAliasSymmetry == 0) {
341     for (; i < fl / 2; i++) {
342       FIXP_DBL x0;
343 
344       /* Overlap Add */
345       x0 = -fMult(*pOvl--, pWindow[i].v.re);
346 
347       *pOut0 = fAddSaturate(*pOut0, IMDCT_SCALE_DBL(x0));
348       pOut0++;
349     }
350   } else {
351     for (; i < fl / 2; i++) {
352       FIXP_DBL x0;
353 
354       /* Overlap Add */
355       x0 = fMult(*pOvl--, pWindow[i].v.re);
356 
357       *pOut0 = fAddSaturate(*pOut0, IMDCT_SCALE_DBL(x0));
358       pOut0++;
359     }
360   }
361   if (hMdct->pFacZir !=
362       0) { /* this should only happen for ACELP -> TCX20 -> ACELP transition */
363     FIXP_DBL *pOut = pOut0 - fl / 2; /* fl/2 == fac_length */
364     for (i = 0; i < fl / 2; i++) {
365       pOut[i] = fAddSaturate(pOut[i], IMDCT_SCALE_DBL(hMdct->pFacZir[i]));
366     }
367     hMdct->pFacZir = NULL;
368   }
369 
370   hMdct->prev_fr = 0;
371   hMdct->prev_nr = 0;
372   hMdct->prev_tl = 0;
373   hMdct->prevPrevAliasSymmetry = hMdct->prevAliasSymmetry;
374 
375   return nrSamples;
376 }
377 
CLpd_FAC_Acelp2Mdct(H_MDCT hMdct,FIXP_DBL * output,FIXP_DBL * _pSpec,const SHORT spec_scale[],const int nSpec,FIXP_DBL * pFac,const int fac_scale,const INT fac_length,INT noOutSamples,const INT tl,const FIXP_WTP * wrs,const INT fr,FIXP_LPC A[16],INT A_exp,CAcelpStaticMem * acelp_mem,const FIXP_DBL gain,const int last_frame_lost,const int isFdFac,const UCHAR last_lpd_mode,const int k,int currAliasingSymmetry)378 INT CLpd_FAC_Acelp2Mdct(H_MDCT hMdct, FIXP_DBL *output, FIXP_DBL *_pSpec,
379                         const SHORT spec_scale[], const int nSpec,
380                         FIXP_DBL *pFac, const int fac_scale,
381                         const INT fac_length, INT noOutSamples, const INT tl,
382                         const FIXP_WTP *wrs, const INT fr, FIXP_LPC A[16],
383                         INT A_exp, CAcelpStaticMem *acelp_mem,
384                         const FIXP_DBL gain, const int last_frame_lost,
385                         const int isFdFac, const UCHAR last_lpd_mode,
386                         const int k, int currAliasingSymmetry) {
387   FIXP_DBL *pCurr, *pOvl, *pSpec;
388   const FIXP_WTP *pWindow;
389   const FIXP_WTB *FacWindowZir_conceal;
390   UCHAR doFacZirConceal = 0;
391   int doDeemph = 1;
392   const FIXP_WTB *FacWindowZir, *FacWindowSynth;
393   FIXP_DBL *pOut0 = output, *pOut1;
394   int w, i, fl, nl, nr, f_len, nrSamples = 0, s = 0, scale, total_gain_e;
395   FIXP_DBL *pF, *pFAC_and_FAC_ZIR = NULL;
396   FIXP_DBL total_gain = gain;
397 
398   FDK_ASSERT(fac_length <= 1024 / (4 * 2));
399   switch (fac_length) {
400     /* coreCoderFrameLength = 1024 */
401     case 128:
402       pWindow = SineWindow256;
403       FacWindowZir = FacWindowZir128;
404       FacWindowSynth = FacWindowSynth128;
405       break;
406     case 64:
407       pWindow = SineWindow128;
408       FacWindowZir = FacWindowZir64;
409       FacWindowSynth = FacWindowSynth64;
410       break;
411     case 32:
412       pWindow = SineWindow64;
413       FacWindowZir = FacWindowZir32;
414       FacWindowSynth = FacWindowSynth32;
415       break;
416     /* coreCoderFrameLength = 768 */
417     case 96:
418       pWindow = SineWindow192;
419       FacWindowZir = FacWindowZir96;
420       FacWindowSynth = FacWindowSynth96;
421       break;
422     case 48:
423       pWindow = SineWindow96;
424       FacWindowZir = FacWindowZir48;
425       FacWindowSynth = FacWindowSynth48;
426       break;
427     default:
428       FDK_ASSERT(0);
429       return 0;
430   }
431 
432   FacWindowZir_conceal = FacWindowSynth;
433   /* Derive NR and NL */
434   fl = fac_length * 2;
435   nl = (tl - fl) >> 1;
436   nr = (tl - fr) >> 1;
437 
438   if (noOutSamples > nrSamples) {
439     /* Purge buffered output. */
440     FDKmemcpy(pOut0, hMdct->overlap.time, hMdct->ov_offset * sizeof(pOut0[0]));
441     nrSamples = hMdct->ov_offset;
442     hMdct->ov_offset = 0;
443   }
444 
445   if (nrSamples >= noOutSamples) {
446     pOut1 = hMdct->overlap.time + hMdct->ov_offset;
447     if (hMdct->ov_offset < fac_length) {
448       pOut0 = output + nrSamples;
449     } else {
450       pOut0 = pOut1;
451     }
452     hMdct->ov_offset += fac_length + nl;
453   } else {
454     pOut1 = output + nrSamples;
455     pOut0 = output + nrSamples;
456   }
457 
458   {
459     pFAC_and_FAC_ZIR = CLpd_ACELP_GetFreeExcMem(acelp_mem, 2 * fac_length);
460     {
461       const FIXP_DBL *pTmp1, *pTmp2;
462 
463       doFacZirConceal |= ((last_frame_lost != 0) && (k == 0));
464       doDeemph &= (last_lpd_mode != 4);
465       if (doFacZirConceal) {
466         /* ACELP contribution in concealment case:
467            Use ZIR with a modified ZIR window to preserve some more energy.
468            Dont use FAC, which contains wrong information for concealed frame
469            Dont use last ACELP samples, but double ZIR, instead (afterwards) */
470         FDKmemclear(pFAC_and_FAC_ZIR, 2 * fac_length * sizeof(FIXP_DBL));
471         FacWindowSynth = (FIXP_WTB *)pFAC_and_FAC_ZIR;
472         FacWindowZir = FacWindowZir_conceal;
473       } else {
474         CFac_CalcFacSignal(pFAC_and_FAC_ZIR, pFac, fac_scale + s, fac_length, A,
475                            A_exp, 1, isFdFac);
476       }
477       /* 6) Get windowed past ACELP samples and ACELP ZIR signal */
478 
479       /*
480        * Get ACELP ZIR (pFac[]) and ACELP past samples (pOut0[]) and add them
481        * to the FAC synth signal contribution on pOut1[].
482        */
483       {
484         {
485           CLpd_Acelp_Zir(A, A_exp, acelp_mem, fac_length, pFac, doDeemph);
486 
487           pTmp1 = pOut0;
488           pTmp2 = pFac;
489         }
490 
491         for (i = 0, w = 0; i < fac_length; i++) {
492           FIXP_DBL x;
493           /* Div2 is compensated by table scaling */
494           x = fMultDiv2(pTmp2[i], FacWindowZir[w]);
495           x += fMultDiv2(pTmp1[-i - 1], FacWindowSynth[w]);
496           pOut1[i] = fAddSaturate(x, pFAC_and_FAC_ZIR[i]);
497           w++;
498         }
499       }
500 
501       if (doFacZirConceal) {
502         /* ZIR is the only ACELP contribution, so double it */
503         scaleValues(pOut1, fac_length, 1);
504       }
505     }
506   }
507 
508   if (nrSamples < noOutSamples) {
509     nrSamples += fac_length + nl;
510   }
511 
512   /* Obtain transform gain */
513   total_gain = gain;
514   total_gain_e = 0;
515   imdct_gain(&total_gain, &total_gain_e, tl);
516 
517   /* IMDCT overlap add */
518   scale = total_gain_e;
519   pSpec = _pSpec;
520 
521   /* Note:when comming from an LPD frame (TCX/ACELP) the previous alisaing
522    * symmetry must always be 0 */
523   if (currAliasingSymmetry == 0) {
524     dct_IV(pSpec, tl, &scale);
525   } else {
526     FIXP_DBL _tmp[1024 + ALIGNMENT_DEFAULT / sizeof(FIXP_DBL)];
527     FIXP_DBL *tmp = (FIXP_DBL *)ALIGN_PTR(_tmp);
528     C_ALLOC_ALIGNED_REGISTER(tmp, sizeof(_tmp));
529     dst_III(pSpec, tmp, tl, &scale);
530     C_ALLOC_ALIGNED_UNREGISTER(tmp);
531   }
532 
533   /* Optional scaling of time domain - no yet windowed - of current spectrum */
534   if (total_gain != (FIXP_DBL)0) {
535     for (i = 0; i < tl; i++) {
536       pSpec[i] = fMult(pSpec[i], total_gain);
537     }
538   }
539   int loc_scale = fixmin_I(spec_scale[0] + scale, (INT)DFRACT_BITS - 1);
540   scaleValuesSaturate(pSpec, tl, loc_scale);
541 
542   pOut1 += fl / 2 - 1;
543   pCurr = pSpec + tl - fl / 2;
544 
545   for (i = 0; i < fl / 2; i++) {
546     FIXP_DBL x1;
547 
548     /* FAC signal is already on pOut1, because of that the += operator. */
549     x1 = fMult(*pCurr++, pWindow[i].v.re);
550     FDK_ASSERT((pOut1 >= hMdct->overlap.time &&
551                 pOut1 < hMdct->overlap.time + hMdct->ov_size) ||
552                (pOut1 >= output && pOut1 < output + 1024));
553     *pOut1 = fAddSaturate(*pOut1, IMDCT_SCALE_DBL(-x1));
554     pOut1--;
555   }
556 
557   /* NL output samples TL/2+FL/2..TL. - current[FL/2..0] */
558   pOut1 += (fl / 2) + 1;
559 
560   pFAC_and_FAC_ZIR += fac_length; /* set pointer to beginning of FAC ZIR */
561 
562   if (nl == 0) {
563     /* save pointer to write FAC ZIR data later */
564     hMdct->pFacZir = pFAC_and_FAC_ZIR;
565   } else {
566     FDK_ASSERT(nl >= fac_length);
567     /* FAC ZIR will be added now ... */
568     hMdct->pFacZir = NULL;
569   }
570 
571   pF = pFAC_and_FAC_ZIR;
572   f_len = fac_length;
573 
574   pCurr = pSpec + tl - fl / 2 - 1;
575   for (i = 0; i < nl; i++) {
576     FIXP_DBL x = -(*pCurr--);
577     /* 5) (item 4) Synthesis filter Zir component, FAC ZIR (another one). */
578     if (i < f_len) {
579       x = fAddSaturate(x, *pF++);
580     }
581 
582     FDK_ASSERT((pOut1 >= hMdct->overlap.time &&
583                 pOut1 < hMdct->overlap.time + hMdct->ov_size) ||
584                (pOut1 >= output && pOut1 < output + 1024));
585     *pOut1 = IMDCT_SCALE_DBL(x);
586     pOut1++;
587   }
588 
589   hMdct->prev_nr = nr;
590   hMdct->prev_fr = fr;
591   hMdct->prev_wrs = wrs;
592   hMdct->prev_tl = tl;
593   hMdct->prevPrevAliasSymmetry = hMdct->prevAliasSymmetry;
594   hMdct->prevAliasSymmetry = currAliasingSymmetry;
595   fl = fr;
596   nl = nr;
597 
598   pOvl = pSpec + tl / 2 - 1;
599   pOut0 = pOut1;
600 
601   for (w = 1; w < nSpec; w++) /* for ACELP -> FD short */
602   {
603     const FIXP_WTP *pWindow_prev;
604 
605     /* Setup window pointers */
606     pWindow_prev = hMdct->prev_wrs;
607 
608     /* Current spectrum */
609     pSpec = _pSpec + w * tl;
610 
611     scale = total_gain_e;
612 
613     /* For the second, third, etc. short frames the alisaing symmetry is equal,
614      * either (0,0) or (1,1) */
615     if (currAliasingSymmetry == 0) {
616       /* DCT IV of current spectrum */
617       dct_IV(pSpec, tl, &scale);
618     } else {
619       dst_IV(pSpec, tl, &scale);
620     }
621 
622     /* Optional scaling of time domain - no yet windowed - of current spectrum
623      */
624     /* and de-scale current spectrum signal (time domain, no yet windowed) */
625     if (total_gain != (FIXP_DBL)0) {
626       for (i = 0; i < tl; i++) {
627         pSpec[i] = fMult(pSpec[i], total_gain);
628       }
629     }
630     loc_scale = fixmin_I(spec_scale[w] + scale, (INT)DFRACT_BITS - 1);
631     scaleValuesSaturate(pSpec, tl, loc_scale);
632 
633     if (noOutSamples <= nrSamples) {
634       /* Divert output first half to overlap buffer if we already got enough
635        * output samples. */
636       pOut0 = hMdct->overlap.time + hMdct->ov_offset;
637       hMdct->ov_offset += hMdct->prev_nr + fl / 2;
638     } else {
639       /* Account output samples */
640       nrSamples += hMdct->prev_nr + fl / 2;
641     }
642 
643     /* NR output samples 0 .. NR. -overlap[TL/2..TL/2-NR] */
644     for (i = 0; i < hMdct->prev_nr; i++) {
645       FIXP_DBL x = -(*pOvl--);
646       *pOut0 = IMDCT_SCALE_DBL(x);
647       pOut0++;
648     }
649 
650     if (noOutSamples <= nrSamples) {
651       /* Divert output second half to overlap buffer if we already got enough
652        * output samples. */
653       pOut1 = hMdct->overlap.time + hMdct->ov_offset + fl / 2 - 1;
654       hMdct->ov_offset += fl / 2 + nl;
655     } else {
656       pOut1 = pOut0 + (fl - 1);
657       nrSamples += fl / 2 + nl;
658     }
659 
660     /* output samples before window crossing point NR .. TL/2.
661      * -overlap[TL/2-NR..TL/2-NR-FL/2] + current[NR..TL/2] */
662     /* output samples after window crossing point TL/2 .. TL/2+FL/2.
663      * -overlap[0..FL/2] - current[TL/2..FL/2] */
664     pCurr = pSpec + tl - fl / 2;
665     if (currAliasingSymmetry == 0) {
666       for (i = 0; i < fl / 2; i++) {
667         FIXP_DBL x0, x1;
668 
669         cplxMultDiv2(&x1, &x0, *pCurr++, -*pOvl--, pWindow_prev[i]);
670         *pOut0 = IMDCT_SCALE_DBL_LSH1(x0);
671         *pOut1 = IMDCT_SCALE_DBL_LSH1(-x1);
672         pOut0++;
673         pOut1--;
674       }
675     } else {
676       if (hMdct->prevPrevAliasSymmetry == 0) {
677         /* Jump DST II -> DST IV for the second window */
678         for (i = 0; i < fl / 2; i++) {
679           FIXP_DBL x0, x1;
680 
681           cplxMultDiv2(&x1, &x0, *pCurr++, -*pOvl--, pWindow_prev[i]);
682           *pOut0 = IMDCT_SCALE_DBL_LSH1(x0);
683           *pOut1 = IMDCT_SCALE_DBL_LSH1(x1);
684           pOut0++;
685           pOut1--;
686         }
687       } else {
688         /* Jump DST IV -> DST IV from the second window on */
689         for (i = 0; i < fl / 2; i++) {
690           FIXP_DBL x0, x1;
691 
692           cplxMultDiv2(&x1, &x0, *pCurr++, *pOvl--, pWindow_prev[i]);
693           *pOut0 = IMDCT_SCALE_DBL_LSH1(x0);
694           *pOut1 = IMDCT_SCALE_DBL_LSH1(x1);
695           pOut0++;
696           pOut1--;
697         }
698       }
699     }
700 
701     if (hMdct->pFacZir != 0) {
702       /* add FAC ZIR of previous ACELP -> mdct transition */
703       FIXP_DBL *pOut = pOut0 - fl / 2;
704       FDK_ASSERT(fl / 2 <= 128);
705       for (i = 0; i < fl / 2; i++) {
706         pOut[i] = fAddSaturate(pOut[i], IMDCT_SCALE_DBL(hMdct->pFacZir[i]));
707       }
708       hMdct->pFacZir = NULL;
709     }
710     pOut0 += (fl / 2);
711 
712     /* NL output samples TL/2+FL/2..TL. - current[FL/2..0] */
713     pOut1 += (fl / 2) + 1;
714     pCurr = pSpec + tl - fl / 2 - 1;
715     for (i = 0; i < nl; i++) {
716       FIXP_DBL x = -(*pCurr--);
717       *pOut1 = IMDCT_SCALE_DBL(x);
718       pOut1++;
719     }
720 
721     /* Set overlap source pointer for next window pOvl = pSpec + tl/2 - 1; */
722     pOvl = pSpec + tl / 2 - 1;
723 
724     /* Previous window values. */
725     hMdct->prev_nr = nr;
726     hMdct->prev_fr = fr;
727     hMdct->prev_tl = tl;
728     hMdct->prev_wrs = pWindow_prev;
729     hMdct->prevPrevAliasSymmetry = hMdct->prevAliasSymmetry;
730     hMdct->prevAliasSymmetry = currAliasingSymmetry;
731   }
732 
733   /* Save overlap */
734 
735   pOvl = hMdct->overlap.freq + hMdct->ov_size - tl / 2;
736   FDK_ASSERT(pOvl >= hMdct->overlap.time + hMdct->ov_offset);
737   FDK_ASSERT(tl / 2 <= hMdct->ov_size);
738   for (i = 0; i < tl / 2; i++) {
739     pOvl[i] = _pSpec[i + (w - 1) * tl];
740   }
741 
742   return nrSamples;
743 }
744