• 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 /*********************** MPEG surround decoder library *************************
96 
97    Author(s):
98 
99    Description: SAC Processing
100 
101 *******************************************************************************/
102 
103 /* data structures and interfaces for spatial audio reference software */
104 #include "sac_process.h"
105 
106 #include "sac_bitdec.h"
107 #include "sac_calcM1andM2.h"
108 #include "sac_smoothing.h"
109 #include "sac_rom.h"
110 
111 #include "sac_dec_errorcodes.h"
112 
113 #include "FDK_trigFcts.h"
114 #include "FDK_decorrelate.h"
115 
116 #define SAC_DEC_APPLY_M2_SCALE(spec, s) ((spec) >> (-(s)))
117 
118 /**
119  * \brief  Linear interpolation between two parameter values.
120  *         a*alpha + b*(1-alpha)
121  *       = a*alpha + b - b*alpha
122  *
123  * \param alpha               Weighting factor.
124  * \param a                   Parameter a.
125  * \param b                   Parameter b.
126  *
127  * \return Interpolated parameter value.
128  */
interpolateParameter(const FIXP_SGL alpha,const FIXP_DBL a,const FIXP_DBL b)129 FDK_INLINE FIXP_DBL interpolateParameter(const FIXP_SGL alpha, const FIXP_DBL a,
130                                          const FIXP_DBL b) {
131   return (b - fMult(alpha, b) + fMult(alpha, a));
132 }
133 
134 /**
135  * \brief Map MPEG Surround channel indices to MPEG 4 PCE like channel indices.
136  * \param self Spatial decoder handle.
137  * \param ch MPEG Surround channel index.
138  * \return MPEG 4 PCE style channel index, corresponding to the given MPEG
139  * Surround channel index.
140  */
mapChannel(spatialDec * self,UINT ch)141 static UINT mapChannel(spatialDec *self, UINT ch) {
142   static const UCHAR chanelIdx[][8] = {
143       {0, 1, 2, 3, 4, 5, 6, 7}, /*  binaural, TREE_212, arbitrary tree */
144   };
145 
146   int idx = 0;
147 
148   return (chanelIdx[idx][ch]);
149 }
150 
getChGain(spatialDec * self,UINT ch,INT * scale)151 FIXP_DBL getChGain(spatialDec *self, UINT ch, INT *scale) {
152   /* init no gain modifier */
153   FIXP_DBL gain = 0x80000000;
154   *scale = 0;
155 
156   if ((!isTwoChMode(self->upmixType)) &&
157       (self->upmixType != UPMIXTYPE_BYPASS)) {
158     if ((ch == 0) || (ch == 1) || (ch == 2)) {
159       /* no modifier */
160     }
161   }
162 
163   return gain;
164 }
165 
SpatialDecQMFAnalysis(spatialDec * self,const PCM_MPS * inData,const INT ts,const INT bypassMode,FIXP_DBL ** qmfReal,FIXP_DBL ** qmfImag,const int numInputChannels)166 SACDEC_ERROR SpatialDecQMFAnalysis(spatialDec *self, const PCM_MPS *inData,
167                                    const INT ts, const INT bypassMode,
168                                    FIXP_DBL **qmfReal, FIXP_DBL **qmfImag,
169                                    const int numInputChannels) {
170   SACDEC_ERROR err = MPS_OK;
171   int ch, offset;
172 
173   offset = self->pQmfDomain->globalConf.nBandsSynthesis *
174            self->pQmfDomain->globalConf.nQmfTimeSlots;
175 
176   {
177     for (ch = 0; ch < numInputChannels; ch++) {
178       const PCM_MPS *inSamples =
179           &inData[ts * self->pQmfDomain->globalConf.nBandsAnalysis];
180       FIXP_DBL *pQmfRealAnalysis = qmfReal[ch]; /* no delay in blind mode */
181       FIXP_DBL *pQmfImagAnalysis = qmfImag[ch];
182 
183       CalculateSpaceAnalysisQmf(&self->pQmfDomain->QmfDomainIn[ch].fb,
184                                 inSamples + (ch * offset), pQmfRealAnalysis,
185                                 pQmfImagAnalysis);
186 
187       if (!isTwoChMode(self->upmixType) && !bypassMode) {
188         int i;
189         for (i = 0; i < self->qmfBands; i++) {
190           qmfReal[ch][i] = fMult(
191               scaleValueSaturate(qmfReal[ch][i], self->sacInDataHeadroom - (1)),
192               self->clipProtectGain__FDK);
193           qmfImag[ch][i] = fMult(
194               scaleValueSaturate(qmfImag[ch][i], self->sacInDataHeadroom - (1)),
195               self->clipProtectGain__FDK);
196         }
197       }
198     }
199   }
200 
201   self->qmfInputDelayBufPos =
202       (self->qmfInputDelayBufPos + 1) % self->pc_filterdelay;
203 
204   return err;
205 }
206 
SpatialDecFeedQMF(spatialDec * self,FIXP_DBL ** qmfInDataReal,FIXP_DBL ** qmfInDataImag,const INT ts,const INT bypassMode,FIXP_DBL ** qmfReal__FDK,FIXP_DBL ** qmfImag__FDK,const INT numInputChannels)207 SACDEC_ERROR SpatialDecFeedQMF(spatialDec *self, FIXP_DBL **qmfInDataReal,
208                                FIXP_DBL **qmfInDataImag, const INT ts,
209                                const INT bypassMode, FIXP_DBL **qmfReal__FDK,
210                                FIXP_DBL **qmfImag__FDK,
211                                const INT numInputChannels) {
212   SACDEC_ERROR err = MPS_OK;
213   int ch;
214 
215   {
216     for (ch = 0; ch < numInputChannels; ch++) {
217       FIXP_DBL *pQmfRealAnalysis =
218           qmfReal__FDK[ch]; /* no delay in blind mode */
219       FIXP_DBL *pQmfImagAnalysis = qmfImag__FDK[ch];
220 
221       /* Write Input data to pQmfRealAnalysis. */
222       if (self->bShareDelayWithSBR) {
223         FDK_QmfDomain_GetSlot(&self->pQmfDomain->QmfDomainIn[ch],
224                               ts + HYBRID_FILTER_DELAY, 0,
225                               MAX_QMF_BANDS_TO_HYBRID, pQmfRealAnalysis,
226                               pQmfImagAnalysis, 15 + (1));
227         FDK_QmfDomain_GetSlot(&self->pQmfDomain->QmfDomainIn[ch], ts,
228                               MAX_QMF_BANDS_TO_HYBRID, self->qmfBands,
229                               pQmfRealAnalysis, pQmfImagAnalysis, 15 + (1));
230       } else {
231         FDK_QmfDomain_GetSlot(&self->pQmfDomain->QmfDomainIn[ch], ts, 0,
232                               self->qmfBands, pQmfRealAnalysis,
233                               pQmfImagAnalysis, 15 + (1));
234       }
235       if (ts == self->pQmfDomain->globalConf.nQmfTimeSlots - 1) {
236         /* Is currently also needed in case we dont have any overlap. We need to
237          * save lb_scale to ov_lb_scale */
238         FDK_QmfDomain_SaveOverlap(&self->pQmfDomain->QmfDomainIn[ch], 0);
239       }
240 
241       /* Apply clip protection to output. */
242       if (!isTwoChMode(self->upmixType) && !bypassMode) {
243         int i;
244         for (i = 0; i < self->qmfBands; i++) {
245           qmfReal__FDK[ch][i] =
246               fMult(qmfReal__FDK[ch][i], self->clipProtectGain__FDK);
247           qmfImag__FDK[ch][i] =
248               fMult(qmfImag__FDK[ch][i], self->clipProtectGain__FDK);
249         }
250       }
251 
252     } /* End of loop over numInputChannels */
253   }
254 
255   self->qmfInputDelayBufPos =
256       (self->qmfInputDelayBufPos + 1) % self->pc_filterdelay;
257 
258   return err;
259 }
260 
261 /*******************************************************************************
262  Functionname: SpatialDecHybridAnalysis
263  *******************************************************************************
264 
265  Description:
266 
267  Arguments:
268 
269  Input:
270   float** pointers[4] leftReal, leftIm, rightReal, rightIm
271 
272  Output:
273   float self->qmfInputReal[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_QMF_BANDS];
274   float self->qmfInputImag[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_QMF_BANDS];
275 
276   float
277 self->hybInputReal[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_HYBRID_BANDS]; float
278 self->hybInputImag[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_HYBRID_BANDS];
279 
280 
281 *******************************************************************************/
SpatialDecHybridAnalysis(spatialDec * self,FIXP_DBL ** qmfInputReal,FIXP_DBL ** qmfInputImag,FIXP_DBL ** hybOutputReal,FIXP_DBL ** hybOutputImag,const INT ts,const INT numInputChannels)282 SACDEC_ERROR SpatialDecHybridAnalysis(spatialDec *self, FIXP_DBL **qmfInputReal,
283                                       FIXP_DBL **qmfInputImag,
284                                       FIXP_DBL **hybOutputReal,
285                                       FIXP_DBL **hybOutputImag, const INT ts,
286                                       const INT numInputChannels) {
287   SACDEC_ERROR err = MPS_OK;
288   int ch;
289 
290   for (ch = 0; ch < numInputChannels;
291        ch++) /* hybrid filtering for down-mix signals */
292   {
293     if (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD) {
294       int k;
295       /* No hybrid filtering. Just copy the QMF data. */
296       for (k = 0; k < self->hybridBands; k += 1) {
297         hybOutputReal[ch][k] = qmfInputReal[ch][k];
298         hybOutputImag[ch][k] = qmfInputImag[ch][k];
299       }
300     } else {
301       self->hybridAnalysis[ch].hfMode = self->bShareDelayWithSBR;
302 
303       if (self->stereoConfigIndex == 3)
304         FDK_ASSERT(self->hybridAnalysis[ch].hfMode == 0);
305       FDKhybridAnalysisApply(&self->hybridAnalysis[ch], qmfInputReal[ch],
306                              qmfInputImag[ch], hybOutputReal[ch],
307                              hybOutputImag[ch]);
308     }
309   }
310 
311   if ((self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_USAC) &&
312       self->residualCoding) {
313     self->hybridAnalysis[numInputChannels].hfMode = 0;
314     FDKhybridAnalysisApply(
315         &self->hybridAnalysis[numInputChannels],
316         self->qmfResidualReal__FDK[0][0], self->qmfResidualImag__FDK[0][0],
317         self->hybResidualReal__FDK[0], self->hybResidualImag__FDK[0]);
318   }
319 
320   return err;
321 }
322 
SpatialDecCreateX(spatialDec * self,FIXP_DBL ** hybInputReal,FIXP_DBL ** hybInputImag,FIXP_DBL ** pxReal,FIXP_DBL ** pxImag)323 SACDEC_ERROR SpatialDecCreateX(spatialDec *self, FIXP_DBL **hybInputReal,
324                                FIXP_DBL **hybInputImag, FIXP_DBL **pxReal,
325                                FIXP_DBL **pxImag) {
326   SACDEC_ERROR err = MPS_OK;
327   int row;
328 
329   /* Creating wDry */
330   for (row = 0; row < self->numInputChannels; row++) {
331     /* pointer to direct signals */
332     pxReal[row] = hybInputReal[row];
333     pxImag[row] = hybInputImag[row];
334   }
335 
336   return err;
337 }
338 
M2ParamToKernelMult(FIXP_SGL * RESTRICT pKernel,FIXP_DBL * RESTRICT Mparam,FIXP_DBL * RESTRICT MparamPrev,int * RESTRICT pWidth,FIXP_SGL alpha__FDK,int nBands)339 static void M2ParamToKernelMult(FIXP_SGL *RESTRICT pKernel,
340                                 FIXP_DBL *RESTRICT Mparam,
341                                 FIXP_DBL *RESTRICT MparamPrev,
342                                 int *RESTRICT pWidth, FIXP_SGL alpha__FDK,
343                                 int nBands) {
344   int pb;
345 
346   for (pb = 0; pb < nBands; pb++) {
347     FIXP_SGL tmp = FX_DBL2FX_SGL(
348         interpolateParameter(alpha__FDK, Mparam[pb], MparamPrev[pb]));
349 
350     int i = pWidth[pb];
351     if (i & 1) *pKernel++ = tmp;
352     if (i & 2) {
353       *pKernel++ = tmp;
354       *pKernel++ = tmp;
355     }
356     for (i >>= 2; i--;) {
357       *pKernel++ = tmp;
358       *pKernel++ = tmp;
359       *pKernel++ = tmp;
360       *pKernel++ = tmp;
361     }
362   }
363 }
364 
SpatialDecApplyM1_CreateW_Mode212(spatialDec * self,const SPATIAL_BS_FRAME * frame,FIXP_DBL ** xReal,FIXP_DBL ** xImag,FIXP_DBL ** vReal,FIXP_DBL ** vImag)365 SACDEC_ERROR SpatialDecApplyM1_CreateW_Mode212(
366     spatialDec *self, const SPATIAL_BS_FRAME *frame, FIXP_DBL **xReal,
367     FIXP_DBL **xImag, FIXP_DBL **vReal, FIXP_DBL **vImag) {
368   SACDEC_ERROR err = MPS_OK;
369   int res;
370   FIXP_DBL *decorrInReal = vReal[0];
371   FIXP_DBL *decorrInImag = vImag[0];
372 
373   /* M1 does not do anything in 212 mode, so use simplified processing */
374   FDK_ASSERT(self->numVChannels == 2);
375   FDK_ASSERT(self->numDirektSignals == 1);
376   FDK_ASSERT(self->numDecorSignals == 1);
377   FDKmemcpy(vReal[0], xReal[0], self->hybridBands * sizeof(FIXP_DBL));
378   FDKmemcpy(vImag[0], xImag[0], self->hybridBands * sizeof(FIXP_DBL));
379 
380   if (isTsdActive(frame->TsdData)) {
381     /* Generate v_{x,nonTr} as input for allpass based decorrelator */
382     TsdGenerateNonTr(self->hybridBands, frame->TsdData, self->TsdTs, vReal[0],
383                      vImag[0], vReal[1], vImag[1], &decorrInReal,
384                      &decorrInImag);
385   }
386   /* - Decorrelate */
387   res = SpatialDecGetResidualIndex(self, 1);
388   if (FDKdecorrelateApply(&self->apDecor[0], decorrInReal, decorrInImag,
389                           vReal[1], vImag[1],
390                           self->param2hyb[self->residualBands[res]])) {
391     return MPS_NOTOK;
392   }
393   if (isTsdActive(frame->TsdData)) {
394     /* Generate v_{x,Tr}, apply transient decorrelator and add to allpass based
395      * decorrelator output */
396     TsdApply(self->hybridBands, frame->TsdData, &self->TsdTs,
397              vReal[0], /* input: v_x */
398              vImag[0],
399              vReal[1], /* input: d_{x,nonTr}; output: d_{x,nonTr} + d_{x,Tr} */
400              vImag[1]);
401   }
402 
403   /* Write residual signal in approriate parameter bands */
404   if (self->residualBands[res] > 0) {
405     int stopBand = self->param2hyb[self->residualBands[res]];
406     FDKmemcpy(vReal[1], self->hybResidualReal__FDK[res],
407               fixMin(stopBand, self->hybridBands) * sizeof(FIXP_DBL));
408     FDKmemcpy(vImag[1], self->hybResidualImag__FDK[res],
409               fixMin(stopBand, self->hybridBands) * sizeof(FIXP_DBL));
410   } /* (self->residualBands[res]>0) */
411 
412   return err;
413 }
414 
SpatialDecApplyM2_Mode212(spatialDec * self,INT ps,const FIXP_SGL alpha,FIXP_DBL ** wReal,FIXP_DBL ** wImag,FIXP_DBL ** hybOutputRealDry,FIXP_DBL ** hybOutputImagDry)415 SACDEC_ERROR SpatialDecApplyM2_Mode212(spatialDec *self, INT ps,
416                                        const FIXP_SGL alpha, FIXP_DBL **wReal,
417                                        FIXP_DBL **wImag,
418                                        FIXP_DBL **hybOutputRealDry,
419                                        FIXP_DBL **hybOutputImagDry) {
420   SACDEC_ERROR err = MPS_OK;
421   INT row;
422 
423   INT *pWidth = self->kernels_width;
424   /* for stereoConfigIndex == 3 case hybridBands is < 71 */
425   INT pb_max = self->kernels[self->hybridBands - 1] + 1;
426   INT max_row = self->numOutputChannels;
427 
428   INT M2_exp = 0;
429   if (self->residualCoding) M2_exp = 3;
430 
431   for (row = 0; row < max_row; row++)  // 2 times
432   {
433     FIXP_DBL *Mparam0 = self->M2Real__FDK[row][0];
434     FIXP_DBL *Mparam1 = self->M2Real__FDK[row][1];
435     FIXP_DBL *MparamPrev0 = self->M2RealPrev__FDK[row][0];
436     FIXP_DBL *MparamPrev1 = self->M2RealPrev__FDK[row][1];
437 
438     FIXP_DBL *RESTRICT pHybOutRealDry = hybOutputRealDry[row];
439     FIXP_DBL *RESTRICT pHybOutImagDry = hybOutputImagDry[row];
440 
441     FIXP_DBL *RESTRICT pWReal0 = wReal[0];
442     FIXP_DBL *RESTRICT pWReal1 = wReal[1];
443     FIXP_DBL *RESTRICT pWImag0 = wImag[0];
444     FIXP_DBL *RESTRICT pWImag1 = wImag[1];
445     for (INT pb = 0; pb < pb_max; pb++) {
446       FIXP_DBL tmp0, tmp1;
447 
448       tmp0 = interpolateParameter(alpha, Mparam0[pb], MparamPrev0[pb]);
449       tmp1 = interpolateParameter(alpha, Mparam1[pb], MparamPrev1[pb]);
450 
451       INT i = pWidth[pb];
452 
453       do  // about 3-4 times
454       {
455         FIXP_DBL var0, var1, real, imag;
456 
457         var0 = *pWReal0++;
458         var1 = *pWReal1++;
459         real = fMultDiv2(var0, tmp0);
460         var0 = *pWImag0++;
461         real = fMultAddDiv2(real, var1, tmp1);
462         var1 = *pWImag1++;
463         imag = fMultDiv2(var0, tmp0);
464         *pHybOutRealDry++ = real << (1 + M2_exp);
465         imag = fMultAddDiv2(imag, var1, tmp1);
466         *pHybOutImagDry++ = imag << (1 + M2_exp);
467       } while (--i != 0);
468     }
469   }
470   return err;
471 }
472 
SpatialDecApplyM2_Mode212_ResidualsPlusPhaseCoding(spatialDec * self,INT ps,const FIXP_SGL alpha,FIXP_DBL ** wReal,FIXP_DBL ** wImag,FIXP_DBL ** hybOutputRealDry,FIXP_DBL ** hybOutputImagDry)473 SACDEC_ERROR SpatialDecApplyM2_Mode212_ResidualsPlusPhaseCoding(
474     spatialDec *self, INT ps, const FIXP_SGL alpha, FIXP_DBL **wReal,
475     FIXP_DBL **wImag, FIXP_DBL **hybOutputRealDry,
476     FIXP_DBL **hybOutputImagDry) {
477   SACDEC_ERROR err = MPS_OK;
478   INT row;
479   INT scale_param_m2;
480   INT *pWidth = self->kernels_width;
481   INT pb_max = self->kernels[self->hybridBands - 1] + 1;
482 
483   scale_param_m2 = SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2;
484 
485   for (row = 0; row < self->numM2rows; row++) {
486     INT qs, pb;
487 
488     FIXP_DBL *RESTRICT pWReal0 = wReal[0];
489     FIXP_DBL *RESTRICT pWImag0 = wImag[0];
490     FIXP_DBL *RESTRICT pWReal1 = wReal[1];
491     FIXP_DBL *RESTRICT pWImag1 = wImag[1];
492 
493     FIXP_DBL *MReal0 = self->M2Real__FDK[row][0];
494     FIXP_DBL *MImag0 = self->M2Imag__FDK[row][0];
495     FIXP_DBL *MReal1 = self->M2Real__FDK[row][1];
496     FIXP_DBL *MRealPrev0 = self->M2RealPrev__FDK[row][0];
497     FIXP_DBL *MImagPrev0 = self->M2ImagPrev__FDK[row][0];
498     FIXP_DBL *MRealPrev1 = self->M2RealPrev__FDK[row][1];
499 
500     FIXP_DBL *RESTRICT pHybOutRealDry = hybOutputRealDry[row];
501     FIXP_DBL *RESTRICT pHybOutImagDry = hybOutputImagDry[row];
502 
503     FDK_ASSERT(!(self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD));
504     FDK_ASSERT((pWidth[0] + pWidth[1]) >= 3);
505 
506     for (pb = 0, qs = 3; pb < 2; pb++) {
507       INT s;
508       FIXP_DBL maxVal;
509       FIXP_DBL mReal1;
510       FIXP_DBL mReal0, mImag0;
511       FIXP_DBL iReal0, iImag0, iReal1;
512 
513       iReal0 = interpolateParameter(alpha, MReal0[pb], MRealPrev0[pb]);
514       iImag0 = -interpolateParameter(alpha, MImag0[pb], MImagPrev0[pb]);
515       iReal1 = interpolateParameter(alpha, MReal1[pb], MRealPrev1[pb]);
516 
517       maxVal = fAbs(iReal0) | fAbs(iImag0);
518       maxVal |= fAbs(iReal1);
519 
520       s = fMax(CntLeadingZeros(maxVal) - 1, 0);
521       s = fMin(s, scale_param_m2);
522 
523       mReal0 = iReal0 << s;
524       mImag0 = iImag0 << s;
525       mReal1 = iReal1 << s;
526 
527       s = scale_param_m2 - s;
528 
529       INT i = pWidth[pb];
530 
531       do {
532         FIXP_DBL real, imag, wReal0, wImag0, wReal1, wImag1;
533 
534         wReal0 = *pWReal0++;
535         wImag0 = *pWImag0++;
536         wReal1 = *pWReal1++;
537         wImag1 = *pWImag1++;
538 
539         cplxMultDiv2(&real, &imag, wReal0, wImag0, mReal0, mImag0);
540 
541         *pHybOutRealDry++ = fMultAddDiv2(real, wReal1, mReal1) << s;
542         *pHybOutImagDry++ = fMultAddDiv2(imag, wImag1, mReal1) << s;
543 
544         if (qs > 0) {
545           mImag0 = -mImag0;
546           qs--;
547         }
548       } while (--i != 0);
549     }
550 
551     for (; pb < pb_max; pb++) {
552       INT s;
553       FIXP_DBL maxVal;
554       FIXP_SGL mReal1;
555       FIXP_SGL mReal0, mImag0;
556       FIXP_DBL iReal0, iImag0, iReal1;
557 
558       iReal0 = interpolateParameter(alpha, MReal0[pb], MRealPrev0[pb]);
559       iImag0 = interpolateParameter(alpha, MImag0[pb], MImagPrev0[pb]);
560       iReal1 = interpolateParameter(alpha, MReal1[pb], MRealPrev1[pb]);
561 
562       maxVal = fAbs(iReal0) | fAbs(iImag0);
563       maxVal |= fAbs(iReal1);
564 
565       s = fMax(CntLeadingZeros(maxVal) - 1, 0);
566       s = fMin(s, scale_param_m2);
567 
568       mReal0 = FX_DBL2FX_SGL(iReal0 << s);
569       mImag0 = FX_DBL2FX_SGL(iImag0 << s);
570       mReal1 = FX_DBL2FX_SGL(iReal1 << s);
571 
572       s = scale_param_m2 - s;
573 
574       INT i = pWidth[pb];
575 
576       do {
577         FIXP_DBL real, imag, wReal0, wImag0, wReal1, wImag1;
578 
579         wReal0 = *pWReal0++;
580         wImag0 = *pWImag0++;
581         wReal1 = *pWReal1++;
582         wImag1 = *pWImag1++;
583 
584         cplxMultDiv2(&real, &imag, wReal0, wImag0, mReal0, mImag0);
585 
586         *pHybOutRealDry++ = fMultAddDiv2(real, wReal1, mReal1) << s;
587         *pHybOutImagDry++ = fMultAddDiv2(imag, wImag1, mReal1) << s;
588       } while (--i != 0);
589     }
590   }
591 
592   return err;
593 }
594 
SpatialDecApplyM2(spatialDec * self,INT ps,const FIXP_SGL alpha,FIXP_DBL ** wReal,FIXP_DBL ** wImag,FIXP_DBL ** hybOutputRealDry,FIXP_DBL ** hybOutputImagDry,FIXP_DBL ** hybOutputRealWet,FIXP_DBL ** hybOutputImagWet)595 SACDEC_ERROR SpatialDecApplyM2(spatialDec *self, INT ps, const FIXP_SGL alpha,
596                                FIXP_DBL **wReal, FIXP_DBL **wImag,
597                                FIXP_DBL **hybOutputRealDry,
598                                FIXP_DBL **hybOutputImagDry,
599                                FIXP_DBL **hybOutputRealWet,
600                                FIXP_DBL **hybOutputImagWet) {
601   SACDEC_ERROR err = MPS_OK;
602 
603   {
604     int qs, row, col;
605     int complexHybBands;
606     int complexParBands;
607     int scale_param_m2 = 0;
608     int toolsDisabled;
609 
610     UCHAR activParamBands;
611     FIXP_DBL *RESTRICT pWReal, *RESTRICT pWImag, *RESTRICT pHybOutRealDry,
612         *RESTRICT pHybOutImagDry, *RESTRICT pHybOutRealWet,
613         *RESTRICT pHybOutImagWet;
614     C_ALLOC_SCRATCH_START(pKernel, FIXP_SGL, MAX_HYBRID_BANDS);
615 
616     /* The wet signal is added to the dry signal directly in applyM2 if GES and
617      * STP are disabled */
618     toolsDisabled =
619         ((self->tempShapeConfig == 1) || (self->tempShapeConfig == 2)) ? 0 : 1;
620 
621     {
622       complexHybBands = self->hybridBands;
623       complexParBands = self->numParameterBands;
624     }
625 
626     FDKmemclear(hybOutputImagDry[0],
627                 self->createParams.maxNumOutputChannels *
628                     self->createParams.maxNumCmplxHybBands * sizeof(FIXP_DBL));
629     FDKmemclear(hybOutputRealDry[0], self->createParams.maxNumOutputChannels *
630                                          self->createParams.maxNumHybridBands *
631                                          sizeof(FIXP_DBL));
632 
633     if (!toolsDisabled) {
634       FDKmemclear(hybOutputRealWet[0],
635                   self->createParams.maxNumOutputChannels *
636                       self->createParams.maxNumHybridBands * sizeof(FIXP_DBL));
637       FDKmemclear(hybOutputImagWet[0],
638                   self->createParams.maxNumOutputChannels *
639                       self->createParams.maxNumCmplxHybBands *
640                       sizeof(FIXP_DBL));
641     }
642 
643     if (self->phaseCoding == 3) {
644       scale_param_m2 = -(SCALE_DATA_APPLY_M2_PC - 1);
645     }
646 
647     for (row = 0; row < self->numM2rows; row++) {
648       pHybOutRealDry = hybOutputRealDry[row];
649       pHybOutImagDry = hybOutputImagDry[row];
650 
651       if (toolsDisabled) {
652         pHybOutRealWet = hybOutputRealDry[row];
653         pHybOutImagWet = hybOutputImagDry[row];
654       } else {
655         pHybOutRealWet = hybOutputRealWet[row];
656         pHybOutImagWet = hybOutputImagWet[row];
657       }
658 
659       for (col = 0; col < self->numDirektSignals; col++) {
660         if (self->pActivM2ParamBands ==
661             0) { /* default setting, calculate all rows and columns */
662           activParamBands = 1;
663         } else {
664           if (self->pActivM2ParamBands[MAX_M2_INPUT * row +
665                                        col]) /* table with activ and inactiv
666                                                 bands exists for current
667                                                 configuration */
668             activParamBands = 1;
669           else
670             activParamBands = 0;
671         }
672         if (activParamBands) {
673           pWReal = wReal[col];
674           pWImag = wImag[col];
675 
676           M2ParamToKernelMult(pKernel, self->M2Real__FDK[row][col],
677                               self->M2RealPrev__FDK[row][col],
678                               self->kernels_width, alpha,
679                               self->numParameterBands);
680 
681           if (1 && (self->phaseCoding != 3)) {
682             /* direct signals */
683             {
684               /* only one sample will be assigned to each row, hence
685                * accumulation is not neccessary; that is valid for all
686                * configurations */
687               for (qs = 0; qs < complexHybBands; qs++) {
688                 pHybOutRealDry[qs] = fMult(pWReal[qs], pKernel[qs]);
689                 pHybOutImagDry[qs] = fMult(pWImag[qs], pKernel[qs]);
690               }
691             }
692           } else { /*  isBinauralMode(self->upmixType)  */
693 
694             for (qs = 0; qs < complexHybBands; qs++) {
695               pHybOutRealDry[qs] += SAC_DEC_APPLY_M2_SCALE(
696                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
697               pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
698                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
699             }
700 
701             M2ParamToKernelMult(pKernel, self->M2Imag__FDK[row][col],
702                                 self->M2ImagPrev__FDK[row][col],
703                                 self->kernels_width, alpha, complexParBands);
704 
705             /* direct signals sign is -1 for qs = 0,2 */
706             pHybOutRealDry[0] += SAC_DEC_APPLY_M2_SCALE(
707                 fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
708             pHybOutImagDry[0] -= SAC_DEC_APPLY_M2_SCALE(
709                 fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
710 
711             pHybOutRealDry[2] += SAC_DEC_APPLY_M2_SCALE(
712                 fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
713             pHybOutImagDry[2] -= SAC_DEC_APPLY_M2_SCALE(
714                 fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
715 
716             /* direct signals sign is +1 for qs = 1,3,4,5,...,complexHybBands */
717             pHybOutRealDry[1] -= SAC_DEC_APPLY_M2_SCALE(
718                 fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
719             pHybOutImagDry[1] += SAC_DEC_APPLY_M2_SCALE(
720                 fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
721 
722             for (qs = 3; qs < complexHybBands; qs++) {
723               pHybOutRealDry[qs] -= SAC_DEC_APPLY_M2_SCALE(
724                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
725               pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
726                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
727             }
728           } /* self->upmixType */
729         }   /* if (activParamBands) */
730       }     /* self->numDirektSignals */
731 
732       for (; col < self->numVChannels; col++) {
733         if (self->pActivM2ParamBands ==
734             0) { /* default setting, calculate all rows and columns */
735           activParamBands = 1;
736         } else {
737           if (self->pActivM2ParamBands[MAX_M2_INPUT * row +
738                                        col]) /* table with activ and inactiv
739                                                 bands exists for current
740                                                 configuration */
741             activParamBands = 1;
742           else
743             activParamBands = 0;
744         }
745 
746         if (activParamBands) {
747           int resBandIndex;
748           int resHybIndex;
749 
750           resBandIndex =
751               self->residualBands[SpatialDecGetResidualIndex(self, col)];
752           resHybIndex = self->param2hyb[resBandIndex];
753 
754           pWReal = wReal[col];
755           pWImag = wImag[col];
756 
757           M2ParamToKernelMult(pKernel, self->M2Real__FDK[row][col],
758                               self->M2RealPrev__FDK[row][col],
759                               self->kernels_width, alpha,
760                               self->numParameterBands);
761 
762           if (1 && (self->phaseCoding != 3)) {
763             /* residual signals */
764             for (qs = 0; qs < resHybIndex; qs++) {
765               pHybOutRealDry[qs] += fMult(pWReal[qs], pKernel[qs]);
766               pHybOutImagDry[qs] += fMult(pWImag[qs], pKernel[qs]);
767             }
768             /* decor signals */
769             for (; qs < complexHybBands; qs++) {
770               pHybOutRealWet[qs] += fMult(pWReal[qs], pKernel[qs]);
771               pHybOutImagWet[qs] += fMult(pWImag[qs], pKernel[qs]);
772             }
773           } else { /* self->upmixType */
774             /* residual signals */
775             FIXP_DBL *RESTRICT pHybOutReal;
776             FIXP_DBL *RESTRICT pHybOutImag;
777 
778             for (qs = 0; qs < resHybIndex; qs++) {
779               pHybOutRealDry[qs] += SAC_DEC_APPLY_M2_SCALE(
780                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
781               pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
782                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
783             }
784             /* decor signals */
785             for (; qs < complexHybBands; qs++) {
786               pHybOutRealWet[qs] += SAC_DEC_APPLY_M2_SCALE(
787                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
788               pHybOutImagWet[qs] += SAC_DEC_APPLY_M2_SCALE(
789                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
790             }
791 
792             M2ParamToKernelMult(pKernel, self->M2Imag__FDK[row][col],
793                                 self->M2ImagPrev__FDK[row][col],
794                                 self->kernels_width, alpha, complexParBands);
795 
796             /* direct signals sign is -1 for qs = 0,2 */
797             /* direct signals sign is +1 for qs = 1,3.. */
798             if (toolsDisabled) {
799               pHybOutRealDry[0] += SAC_DEC_APPLY_M2_SCALE(
800                   fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
801               pHybOutImagDry[0] -= SAC_DEC_APPLY_M2_SCALE(
802                   fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
803 
804               pHybOutRealDry[1] -= SAC_DEC_APPLY_M2_SCALE(
805                   fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
806               pHybOutImagDry[1] += SAC_DEC_APPLY_M2_SCALE(
807                   fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
808 
809               pHybOutRealDry[2] += SAC_DEC_APPLY_M2_SCALE(
810                   fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
811               pHybOutImagDry[2] -= SAC_DEC_APPLY_M2_SCALE(
812                   fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
813             } else {
814               pHybOutReal = &pHybOutRealDry[0];
815               pHybOutImag = &pHybOutImagDry[0];
816               if (0 == resHybIndex) {
817                 pHybOutReal = &pHybOutRealWet[0];
818                 pHybOutImag = &pHybOutImagWet[0];
819               }
820               pHybOutReal[0] += SAC_DEC_APPLY_M2_SCALE(
821                   fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
822               pHybOutImag[0] -= SAC_DEC_APPLY_M2_SCALE(
823                   fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
824 
825               if (1 == resHybIndex) {
826                 pHybOutReal = &pHybOutRealWet[0];
827                 pHybOutImag = &pHybOutImagWet[0];
828               }
829               pHybOutReal[1] -= SAC_DEC_APPLY_M2_SCALE(
830                   fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
831               pHybOutImag[1] += SAC_DEC_APPLY_M2_SCALE(
832                   fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
833 
834               if (2 == resHybIndex) {
835                 pHybOutReal = &pHybOutRealWet[0];
836                 pHybOutImag = &pHybOutImagWet[0];
837               }
838               pHybOutReal[2] += SAC_DEC_APPLY_M2_SCALE(
839                   fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
840               pHybOutImag[2] -= SAC_DEC_APPLY_M2_SCALE(
841                   fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
842             }
843 
844             for (qs = 3; qs < resHybIndex; qs++) {
845               pHybOutRealDry[qs] -= SAC_DEC_APPLY_M2_SCALE(
846                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
847               pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
848                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
849             }
850             /* decor signals */
851             for (; qs < complexHybBands; qs++) {
852               pHybOutRealWet[qs] -= SAC_DEC_APPLY_M2_SCALE(
853                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
854               pHybOutImagWet[qs] += SAC_DEC_APPLY_M2_SCALE(
855                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
856             }
857           } /* self->upmixType */
858         }   /* if (activParamBands) { */
859       }     /*  self->numVChannels */
860 
861       if (self->phaseCoding == 3) {
862         scaleValuesSaturate(pHybOutRealDry, complexHybBands,
863                             SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
864         scaleValuesSaturate(pHybOutImagDry, complexHybBands,
865                             SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
866 
867         if (!toolsDisabled) {
868           scaleValuesSaturate(pHybOutRealWet, complexHybBands,
869                               SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
870           scaleValuesSaturate(pHybOutImagWet, complexHybBands,
871                               SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
872         }
873       }
874     }
875 
876     C_ALLOC_SCRATCH_END(pKernel, FIXP_SGL, MAX_HYBRID_BANDS);
877   }
878 
879   return err;
880 }
881 
SpatialDecSynthesis(spatialDec * self,const INT ts,FIXP_DBL ** hybOutputReal,FIXP_DBL ** hybOutputImag,PCM_MPS * timeOut,const INT numInputChannels,const FDK_channelMapDescr * const mapDescr)882 SACDEC_ERROR SpatialDecSynthesis(spatialDec *self, const INT ts,
883                                  FIXP_DBL **hybOutputReal,
884                                  FIXP_DBL **hybOutputImag, PCM_MPS *timeOut,
885                                  const INT numInputChannels,
886                                  const FDK_channelMapDescr *const mapDescr) {
887   SACDEC_ERROR err = MPS_OK;
888 
889   int ch;
890   int stride, offset;
891 
892   stride = self->numOutputChannelsAT;
893   offset = 1;
894 
895   PCM_MPS *pTimeOut__FDK =
896       &timeOut[stride * self->pQmfDomain->globalConf.nBandsSynthesis * ts];
897   C_ALLOC_SCRATCH_START(pQmfReal, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
898   C_ALLOC_SCRATCH_START(pQmfImag, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
899 
900   for (ch = 0; ch < self->numOutputChannelsAT; ch++) {
901     if (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD) {
902       int k;
903       /* No hybrid filtering. Just copy the QMF data. */
904       for (k = 0; k < self->hybridBands; k += 1) {
905         pQmfReal[k] = hybOutputReal[ch][k];
906         pQmfImag[k] = hybOutputImag[ch][k];
907       }
908     } else {
909       FDKhybridSynthesisApply(&self->hybridSynthesis[ch], hybOutputReal[ch],
910                               hybOutputImag[ch], pQmfReal, pQmfImag);
911     }
912 
913     /* Map channel indices from MPEG Surround -> PCE style -> channelMapping[]
914      */
915     FDK_ASSERT(self->numOutputChannelsAT <= 6);
916     int outCh = FDK_chMapDescr_getMapValue(mapDescr, mapChannel(self, ch),
917                                            self->numOutputChannelsAT);
918 
919     {
920       if (self->stereoConfigIndex == 3) {
921         /* MPS -> SBR */
922         int i;
923         FIXP_DBL *pWorkBufReal, *pWorkBufImag;
924         FDK_ASSERT((self->pQmfDomain->QmfDomainOut[outCh].fb.outGain_m ==
925                     (FIXP_DBL)0x80000000) &&
926                    (self->pQmfDomain->QmfDomainOut[outCh].fb.outGain_e == 0));
927         FDK_QmfDomain_GetWorkBuffer(&self->pQmfDomain->QmfDomainIn[outCh], ts,
928                                     &pWorkBufReal, &pWorkBufImag);
929         FDK_ASSERT(self->qmfBands <=
930                    self->pQmfDomain->QmfDomainIn[outCh].workBuf_nBands);
931         for (i = 0; i < self->qmfBands; i++) {
932           pWorkBufReal[i] = pQmfReal[i];
933           pWorkBufImag[i] = pQmfImag[i];
934         }
935         self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale =
936             -7; /*-ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK;*/
937         self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -=
938             self->pQmfDomain->QmfDomainIn[outCh].fb.filterScale;
939         self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -=
940             self->clipProtectGainSF__FDK;
941 
942         self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -= (1);
943       } else {
944         /* Call the QMF synthesis for dry. */
945         err = CalculateSpaceSynthesisQmf(&self->pQmfDomain->QmfDomainOut[outCh],
946                                          pQmfReal, pQmfImag, stride,
947                                          pTimeOut__FDK + (offset * outCh));
948       }
949       if (err != MPS_OK) goto bail;
950     }
951   } /* ch loop */
952 
953 bail:
954   C_ALLOC_SCRATCH_END(pQmfImag, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
955   C_ALLOC_SCRATCH_END(pQmfReal, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
956 
957   return err;
958 }
959 
SpatialDecBufferMatrices(spatialDec * self)960 void SpatialDecBufferMatrices(spatialDec *self) {
961   int row, col;
962   int complexParBands;
963   complexParBands = self->numParameterBands;
964 
965   /*
966     buffer matrices M2
967   */
968   for (row = 0; row < self->numM2rows; row++) {
969     for (col = 0; col < self->numVChannels; col++) {
970       FDKmemcpy(self->M2RealPrev__FDK[row][col], self->M2Real__FDK[row][col],
971                 self->numParameterBands * sizeof(FIXP_DBL));
972       if (0 || (self->phaseCoding == 3)) {
973         FDKmemcpy(self->M2ImagPrev__FDK[row][col], self->M2Imag__FDK[row][col],
974                   complexParBands * sizeof(FIXP_DBL));
975       }
976     }
977   }
978 
979   /* buffer phase */
980   FDKmemcpy(self->PhasePrevLeft__FDK, self->PhaseLeft__FDK,
981             self->numParameterBands * sizeof(FIXP_DBL));
982   FDKmemcpy(self->PhasePrevRight__FDK, self->PhaseRight__FDK,
983             self->numParameterBands * sizeof(FIXP_DBL));
984 }
985 
986 #define PHASE_SCALE 2
987 
988 #ifndef P_PI
989 #define P_PI 3.1415926535897932
990 #endif
991 
992 /* For better precision, PI (pi_x2) is already doubled */
interp_angle__FDK(FIXP_DBL angle1,FIXP_DBL angle2,FIXP_SGL alpha,FIXP_DBL pi_x2)993 static FIXP_DBL interp_angle__FDK(FIXP_DBL angle1, FIXP_DBL angle2,
994                                   FIXP_SGL alpha, FIXP_DBL pi_x2) {
995   if (angle2 - angle1 > (pi_x2 >> 1)) angle2 -= pi_x2;
996 
997   if (angle1 - angle2 > (pi_x2 >> 1)) angle1 -= pi_x2;
998 
999   return interpolateParameter(alpha, angle2, angle1);
1000 }
1001 
1002 /*
1003  *
1004  */
SpatialDecApplyPhase(spatialDec * self,FIXP_SGL alpha__FDK,int lastSlotOfParamSet)1005 void SpatialDecApplyPhase(spatialDec *self, FIXP_SGL alpha__FDK,
1006                           int lastSlotOfParamSet) {
1007   int pb, qs;
1008   FIXP_DBL ppb[MAX_PARAMETER_BANDS *
1009                4]; /* left real, imag - right real, imag interleaved */
1010 
1011   const FIXP_DBL pi_x2 = PIx2__IPD;
1012   for (pb = 0; pb < self->numParameterBands; pb++) {
1013     FIXP_DBL pl, pr;
1014 
1015     pl = interp_angle__FDK(self->PhasePrevLeft__FDK[pb],
1016                            self->PhaseLeft__FDK[pb], alpha__FDK, pi_x2);
1017     pr = interp_angle__FDK(self->PhasePrevRight__FDK[pb],
1018                            self->PhaseRight__FDK[pb], alpha__FDK, pi_x2);
1019 
1020     inline_fixp_cos_sin(pl, pr, IPD_SCALE, &ppb[4 * pb]);
1021   }
1022 
1023   /* sign is -1 for qs = 0,2 and +1 for qs = 1 */
1024 
1025   const SCHAR *kernels = &self->kernels[0];
1026 
1027   FIXP_DBL *Dry_real0 = &self->hybOutputRealDry__FDK[0][0];
1028   FIXP_DBL *Dry_imag0 = &self->hybOutputImagDry__FDK[0][0];
1029   FIXP_DBL *Dry_real1 = &self->hybOutputRealDry__FDK[1][0];
1030   FIXP_DBL *Dry_imag1 = &self->hybOutputImagDry__FDK[1][0];
1031 
1032   for (qs = 2; qs >= 0; qs--) {
1033     FIXP_DBL out_re, out_im;
1034 
1035     pb = *kernels++;
1036     if (qs == 1) /* sign[qs] >= 0 */
1037     {
1038       cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0],
1039                    ppb[4 * pb + 1]);
1040       out_re <<= PHASE_SCALE - 1;
1041       out_im <<= PHASE_SCALE - 1;
1042       *Dry_real0++ = out_re;
1043       *Dry_imag0++ = out_im;
1044 
1045       cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2],
1046                    ppb[4 * pb + 3]);
1047       out_re <<= PHASE_SCALE - 1;
1048       out_im <<= PHASE_SCALE - 1;
1049       *Dry_real1++ = out_re;
1050       *Dry_imag1++ = out_im;
1051     } else {
1052       cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0],
1053                    -ppb[4 * pb + 1]);
1054       out_re <<= PHASE_SCALE - 1;
1055       out_im <<= PHASE_SCALE - 1;
1056       *Dry_real0++ = out_re;
1057       *Dry_imag0++ = out_im;
1058 
1059       cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2],
1060                    -ppb[4 * pb + 3]);
1061       out_re <<= PHASE_SCALE - 1;
1062       out_im <<= PHASE_SCALE - 1;
1063       *Dry_real1++ = out_re;
1064       *Dry_imag1++ = out_im;
1065     }
1066   }
1067 
1068   /* sign is +1 for qs >=3 */
1069   for (qs = self->hybridBands - 3; qs--;) {
1070     FIXP_DBL out_re, out_im;
1071 
1072     pb = *kernels++;
1073     cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0],
1074                  ppb[4 * pb + 1]);
1075     out_re <<= PHASE_SCALE - 1;
1076     out_im <<= PHASE_SCALE - 1;
1077     *Dry_real0++ = out_re;
1078     *Dry_imag0++ = out_im;
1079 
1080     cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2],
1081                  ppb[4 * pb + 3]);
1082     out_re <<= PHASE_SCALE - 1;
1083     out_im <<= PHASE_SCALE - 1;
1084     *Dry_real1++ = out_re;
1085     *Dry_imag1++ = out_im;
1086   }
1087 }
1088