• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -----------------------------------------------------------------------------
2 Software License for The Fraunhofer FDK AAC Codec Library for Android
3 
4 © Copyright  1995 - 2021 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 = fMin(CntLeadingZeros(maxVal) - 2, scale_param_m2);
521 
522       mReal0 = scaleValue(iReal0, s);
523       mImag0 = scaleValue(iImag0, s);
524       mReal1 = scaleValue(iReal1, s);
525 
526       s = scale_param_m2 - s;
527 
528       INT i = pWidth[pb];
529 
530       do {
531         FIXP_DBL real, imag, wReal0, wImag0, wReal1, wImag1;
532 
533         wReal0 = *pWReal0++;
534         wImag0 = *pWImag0++;
535         wReal1 = *pWReal1++;
536         wImag1 = *pWImag1++;
537 
538         cplxMultDiv2(&real, &imag, wReal0, wImag0, mReal0, mImag0);
539 
540         *pHybOutRealDry++ = fMultAddDiv2(real, wReal1, mReal1) << s;
541         *pHybOutImagDry++ = fMultAddDiv2(imag, wImag1, mReal1) << s;
542 
543         if (qs > 0) {
544           mImag0 = -mImag0;
545           qs--;
546         }
547       } while (--i != 0);
548     }
549 
550     for (; pb < pb_max; pb++) {
551       INT s;
552       FIXP_DBL maxVal;
553       FIXP_SGL mReal1;
554       FIXP_SGL mReal0, mImag0;
555       FIXP_DBL iReal0, iImag0, iReal1;
556 
557       iReal0 = interpolateParameter(alpha, MReal0[pb], MRealPrev0[pb]);
558       iImag0 = interpolateParameter(alpha, MImag0[pb], MImagPrev0[pb]);
559       iReal1 = interpolateParameter(alpha, MReal1[pb], MRealPrev1[pb]);
560 
561       maxVal = fAbs(iReal0) | fAbs(iImag0);
562       maxVal |= fAbs(iReal1);
563 
564       s = fMin(CntLeadingZeros(maxVal) - 2, scale_param_m2);
565 
566       mReal0 = FX_DBL2FX_SGL(scaleValue(iReal0, s));
567       mImag0 = FX_DBL2FX_SGL(scaleValue(iImag0, s));
568       mReal1 = FX_DBL2FX_SGL(scaleValue(iReal1, s));
569 
570       s = scale_param_m2 - s;
571 
572       INT i = pWidth[pb];
573 
574       do {
575         FIXP_DBL real, imag, wReal0, wImag0, wReal1, wImag1;
576 
577         wReal0 = *pWReal0++;
578         wImag0 = *pWImag0++;
579         wReal1 = *pWReal1++;
580         wImag1 = *pWImag1++;
581 
582         cplxMultDiv2(&real, &imag, wReal0, wImag0, mReal0, mImag0);
583 
584         *pHybOutRealDry++ = fMultAddDiv2(real, wReal1, mReal1) << s;
585         *pHybOutImagDry++ = fMultAddDiv2(imag, wImag1, mReal1) << s;
586       } while (--i != 0);
587     }
588   }
589 
590   return err;
591 }
592 
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)593 SACDEC_ERROR SpatialDecApplyM2(spatialDec *self, INT ps, const FIXP_SGL alpha,
594                                FIXP_DBL **wReal, FIXP_DBL **wImag,
595                                FIXP_DBL **hybOutputRealDry,
596                                FIXP_DBL **hybOutputImagDry,
597                                FIXP_DBL **hybOutputRealWet,
598                                FIXP_DBL **hybOutputImagWet) {
599   SACDEC_ERROR err = MPS_OK;
600 
601   {
602     int qs, row, col;
603     int complexHybBands;
604     int complexParBands;
605     int scale_param_m2 = 0;
606     int toolsDisabled;
607 
608     UCHAR activParamBands;
609     FIXP_DBL *RESTRICT pWReal, *RESTRICT pWImag, *RESTRICT pHybOutRealDry,
610         *RESTRICT pHybOutImagDry, *RESTRICT pHybOutRealWet,
611         *RESTRICT pHybOutImagWet;
612     C_ALLOC_SCRATCH_START(pKernel, FIXP_SGL, MAX_HYBRID_BANDS);
613 
614     /* The wet signal is added to the dry signal directly in applyM2 if GES and
615      * STP are disabled */
616     toolsDisabled =
617         ((self->tempShapeConfig == 1) || (self->tempShapeConfig == 2)) ? 0 : 1;
618 
619     {
620       complexHybBands = self->hybridBands;
621       complexParBands = self->numParameterBands;
622     }
623 
624     FDKmemclear(hybOutputImagDry[0],
625                 self->createParams.maxNumOutputChannels *
626                     self->createParams.maxNumCmplxHybBands * sizeof(FIXP_DBL));
627     FDKmemclear(hybOutputRealDry[0], self->createParams.maxNumOutputChannels *
628                                          self->createParams.maxNumHybridBands *
629                                          sizeof(FIXP_DBL));
630 
631     if (!toolsDisabled) {
632       FDKmemclear(hybOutputRealWet[0],
633                   self->createParams.maxNumOutputChannels *
634                       self->createParams.maxNumHybridBands * sizeof(FIXP_DBL));
635       FDKmemclear(hybOutputImagWet[0],
636                   self->createParams.maxNumOutputChannels *
637                       self->createParams.maxNumCmplxHybBands *
638                       sizeof(FIXP_DBL));
639     }
640 
641     if (self->phaseCoding == 3) {
642       scale_param_m2 = -(SCALE_DATA_APPLY_M2_PC - 1);
643     }
644 
645     for (row = 0; row < self->numM2rows; row++) {
646       pHybOutRealDry = hybOutputRealDry[row];
647       pHybOutImagDry = hybOutputImagDry[row];
648 
649       if (toolsDisabled) {
650         pHybOutRealWet = hybOutputRealDry[row];
651         pHybOutImagWet = hybOutputImagDry[row];
652       } else {
653         pHybOutRealWet = hybOutputRealWet[row];
654         pHybOutImagWet = hybOutputImagWet[row];
655       }
656 
657       for (col = 0; col < self->numDirektSignals; col++) {
658         if (self->pActivM2ParamBands ==
659             0) { /* default setting, calculate all rows and columns */
660           activParamBands = 1;
661         } else {
662           if (self->pActivM2ParamBands[MAX_M2_INPUT * row +
663                                        col]) /* table with activ and inactiv
664                                                 bands exists for current
665                                                 configuration */
666             activParamBands = 1;
667           else
668             activParamBands = 0;
669         }
670         if (activParamBands) {
671           pWReal = wReal[col];
672           pWImag = wImag[col];
673 
674           M2ParamToKernelMult(pKernel, self->M2Real__FDK[row][col],
675                               self->M2RealPrev__FDK[row][col],
676                               self->kernels_width, alpha,
677                               self->numParameterBands);
678 
679           if (1 && (self->phaseCoding != 3)) {
680             /* direct signals */
681             {
682               /* only one sample will be assigned to each row, hence
683                * accumulation is not neccessary; that is valid for all
684                * configurations */
685               for (qs = 0; qs < complexHybBands; qs++) {
686                 pHybOutRealDry[qs] = fMult(pWReal[qs], pKernel[qs]);
687                 pHybOutImagDry[qs] = fMult(pWImag[qs], pKernel[qs]);
688               }
689             }
690           } else { /*  isBinauralMode(self->upmixType)  */
691 
692             for (qs = 0; qs < complexHybBands; qs++) {
693               pHybOutRealDry[qs] += SAC_DEC_APPLY_M2_SCALE(
694                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
695               pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
696                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
697             }
698 
699             M2ParamToKernelMult(pKernel, self->M2Imag__FDK[row][col],
700                                 self->M2ImagPrev__FDK[row][col],
701                                 self->kernels_width, alpha, complexParBands);
702 
703             /* direct signals sign is -1 for qs = 0,2 */
704             pHybOutRealDry[0] += SAC_DEC_APPLY_M2_SCALE(
705                 fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
706             pHybOutImagDry[0] -= SAC_DEC_APPLY_M2_SCALE(
707                 fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
708 
709             pHybOutRealDry[2] += SAC_DEC_APPLY_M2_SCALE(
710                 fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
711             pHybOutImagDry[2] -= SAC_DEC_APPLY_M2_SCALE(
712                 fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
713 
714             /* direct signals sign is +1 for qs = 1,3,4,5,...,complexHybBands */
715             pHybOutRealDry[1] -= SAC_DEC_APPLY_M2_SCALE(
716                 fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
717             pHybOutImagDry[1] += SAC_DEC_APPLY_M2_SCALE(
718                 fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
719 
720             for (qs = 3; qs < complexHybBands; qs++) {
721               pHybOutRealDry[qs] -= SAC_DEC_APPLY_M2_SCALE(
722                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
723               pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
724                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
725             }
726           } /* self->upmixType */
727         }   /* if (activParamBands) */
728       }     /* self->numDirektSignals */
729 
730       for (; col < self->numVChannels; col++) {
731         if (self->pActivM2ParamBands ==
732             0) { /* default setting, calculate all rows and columns */
733           activParamBands = 1;
734         } else {
735           if (self->pActivM2ParamBands[MAX_M2_INPUT * row +
736                                        col]) /* table with activ and inactiv
737                                                 bands exists for current
738                                                 configuration */
739             activParamBands = 1;
740           else
741             activParamBands = 0;
742         }
743 
744         if (activParamBands) {
745           int resBandIndex;
746           int resHybIndex;
747 
748           resBandIndex =
749               self->residualBands[SpatialDecGetResidualIndex(self, col)];
750           resHybIndex = self->param2hyb[resBandIndex];
751 
752           pWReal = wReal[col];
753           pWImag = wImag[col];
754 
755           M2ParamToKernelMult(pKernel, self->M2Real__FDK[row][col],
756                               self->M2RealPrev__FDK[row][col],
757                               self->kernels_width, alpha,
758                               self->numParameterBands);
759 
760           if (1 && (self->phaseCoding != 3)) {
761             /* residual signals */
762             for (qs = 0; qs < resHybIndex; qs++) {
763               pHybOutRealDry[qs] += fMult(pWReal[qs], pKernel[qs]);
764               pHybOutImagDry[qs] += fMult(pWImag[qs], pKernel[qs]);
765             }
766             /* decor signals */
767             for (; qs < complexHybBands; qs++) {
768               pHybOutRealWet[qs] += fMult(pWReal[qs], pKernel[qs]);
769               pHybOutImagWet[qs] += fMult(pWImag[qs], pKernel[qs]);
770             }
771           } else { /* self->upmixType */
772             /* residual signals */
773             FIXP_DBL *RESTRICT pHybOutReal;
774             FIXP_DBL *RESTRICT pHybOutImag;
775 
776             for (qs = 0; qs < resHybIndex; qs++) {
777               pHybOutRealDry[qs] += SAC_DEC_APPLY_M2_SCALE(
778                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
779               pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
780                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
781             }
782             /* decor signals */
783             for (; qs < complexHybBands; qs++) {
784               pHybOutRealWet[qs] += SAC_DEC_APPLY_M2_SCALE(
785                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
786               pHybOutImagWet[qs] += SAC_DEC_APPLY_M2_SCALE(
787                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
788             }
789 
790             M2ParamToKernelMult(pKernel, self->M2Imag__FDK[row][col],
791                                 self->M2ImagPrev__FDK[row][col],
792                                 self->kernels_width, alpha, complexParBands);
793 
794             /* direct signals sign is -1 for qs = 0,2 */
795             /* direct signals sign is +1 for qs = 1,3.. */
796             if (toolsDisabled) {
797               pHybOutRealDry[0] += SAC_DEC_APPLY_M2_SCALE(
798                   fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
799               pHybOutImagDry[0] -= SAC_DEC_APPLY_M2_SCALE(
800                   fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
801 
802               pHybOutRealDry[1] -= SAC_DEC_APPLY_M2_SCALE(
803                   fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
804               pHybOutImagDry[1] += SAC_DEC_APPLY_M2_SCALE(
805                   fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
806 
807               pHybOutRealDry[2] += SAC_DEC_APPLY_M2_SCALE(
808                   fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
809               pHybOutImagDry[2] -= SAC_DEC_APPLY_M2_SCALE(
810                   fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
811             } else {
812               pHybOutReal = &pHybOutRealDry[0];
813               pHybOutImag = &pHybOutImagDry[0];
814               if (0 == resHybIndex) {
815                 pHybOutReal = &pHybOutRealWet[0];
816                 pHybOutImag = &pHybOutImagWet[0];
817               }
818               pHybOutReal[0] += SAC_DEC_APPLY_M2_SCALE(
819                   fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
820               pHybOutImag[0] -= SAC_DEC_APPLY_M2_SCALE(
821                   fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
822 
823               if (1 == resHybIndex) {
824                 pHybOutReal = &pHybOutRealWet[0];
825                 pHybOutImag = &pHybOutImagWet[0];
826               }
827               pHybOutReal[1] -= SAC_DEC_APPLY_M2_SCALE(
828                   fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
829               pHybOutImag[1] += SAC_DEC_APPLY_M2_SCALE(
830                   fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
831 
832               if (2 == resHybIndex) {
833                 pHybOutReal = &pHybOutRealWet[0];
834                 pHybOutImag = &pHybOutImagWet[0];
835               }
836               pHybOutReal[2] += SAC_DEC_APPLY_M2_SCALE(
837                   fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
838               pHybOutImag[2] -= SAC_DEC_APPLY_M2_SCALE(
839                   fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
840             }
841 
842             for (qs = 3; qs < resHybIndex; qs++) {
843               pHybOutRealDry[qs] -= SAC_DEC_APPLY_M2_SCALE(
844                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
845               pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
846                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
847             }
848             /* decor signals */
849             for (; qs < complexHybBands; qs++) {
850               pHybOutRealWet[qs] -= SAC_DEC_APPLY_M2_SCALE(
851                   fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
852               pHybOutImagWet[qs] += SAC_DEC_APPLY_M2_SCALE(
853                   fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
854             }
855           } /* self->upmixType */
856         }   /* if (activParamBands) { */
857       }     /*  self->numVChannels */
858 
859       if (self->phaseCoding == 3) {
860         scaleValuesSaturate(pHybOutRealDry, complexHybBands,
861                             SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
862         scaleValuesSaturate(pHybOutImagDry, complexHybBands,
863                             SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
864 
865         if (!toolsDisabled) {
866           scaleValuesSaturate(pHybOutRealWet, complexHybBands,
867                               SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
868           scaleValuesSaturate(pHybOutImagWet, complexHybBands,
869                               SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
870         }
871       }
872     }
873 
874     C_ALLOC_SCRATCH_END(pKernel, FIXP_SGL, MAX_HYBRID_BANDS);
875   }
876 
877   return err;
878 }
879 
SpatialDecSynthesis(spatialDec * self,const INT ts,FIXP_DBL ** hybOutputReal,FIXP_DBL ** hybOutputImag,PCM_MPS * timeOut,const INT numInputChannels,const FDK_channelMapDescr * const mapDescr)880 SACDEC_ERROR SpatialDecSynthesis(spatialDec *self, const INT ts,
881                                  FIXP_DBL **hybOutputReal,
882                                  FIXP_DBL **hybOutputImag, PCM_MPS *timeOut,
883                                  const INT numInputChannels,
884                                  const FDK_channelMapDescr *const mapDescr) {
885   SACDEC_ERROR err = MPS_OK;
886 
887   int ch;
888   int stride, offset;
889 
890   stride = self->numOutputChannelsAT;
891   offset = 1;
892 
893   PCM_MPS *pTimeOut__FDK =
894       &timeOut[stride * self->pQmfDomain->globalConf.nBandsSynthesis * ts];
895   C_ALLOC_SCRATCH_START(pQmfReal, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
896   C_ALLOC_SCRATCH_START(pQmfImag, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
897 
898   for (ch = 0; ch < self->numOutputChannelsAT; ch++) {
899     if (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD) {
900       int k;
901       /* No hybrid filtering. Just copy the QMF data. */
902       for (k = 0; k < self->hybridBands; k += 1) {
903         pQmfReal[k] = hybOutputReal[ch][k];
904         pQmfImag[k] = hybOutputImag[ch][k];
905       }
906     } else {
907       FDKhybridSynthesisApply(&self->hybridSynthesis[ch], hybOutputReal[ch],
908                               hybOutputImag[ch], pQmfReal, pQmfImag);
909     }
910 
911     /* Map channel indices from MPEG Surround -> PCE style -> channelMapping[]
912      */
913     FDK_ASSERT(self->numOutputChannelsAT <= 6);
914     int outCh = FDK_chMapDescr_getMapValue(mapDescr, mapChannel(self, ch),
915                                            self->numOutputChannelsAT);
916 
917     {
918       if (self->stereoConfigIndex == 3) {
919         /* MPS -> SBR */
920         int i;
921         FIXP_DBL *pWorkBufReal, *pWorkBufImag;
922         FDK_ASSERT((self->pQmfDomain->QmfDomainOut[outCh].fb.outGain_m ==
923                     (FIXP_DBL)0x80000000) &&
924                    (self->pQmfDomain->QmfDomainOut[outCh].fb.outGain_e == 0));
925         FDK_QmfDomain_GetWorkBuffer(&self->pQmfDomain->QmfDomainIn[outCh], ts,
926                                     &pWorkBufReal, &pWorkBufImag);
927         FDK_ASSERT(self->qmfBands <=
928                    self->pQmfDomain->QmfDomainIn[outCh].workBuf_nBands);
929         for (i = 0; i < self->qmfBands; i++) {
930           pWorkBufReal[i] = pQmfReal[i];
931           pWorkBufImag[i] = pQmfImag[i];
932         }
933         self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale =
934             -7; /*-ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK;*/
935         self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -=
936             self->pQmfDomain->QmfDomainIn[outCh].fb.filterScale;
937         self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -=
938             self->clipProtectGainSF__FDK;
939 
940         self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -= (1);
941       } else {
942         /* Call the QMF synthesis for dry. */
943         err = CalculateSpaceSynthesisQmf(&self->pQmfDomain->QmfDomainOut[outCh],
944                                          pQmfReal, pQmfImag, stride,
945                                          pTimeOut__FDK + (offset * outCh));
946       }
947       if (err != MPS_OK) goto bail;
948     }
949   } /* ch loop */
950 
951 bail:
952   C_ALLOC_SCRATCH_END(pQmfImag, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
953   C_ALLOC_SCRATCH_END(pQmfReal, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
954 
955   return err;
956 }
957 
SpatialDecBufferMatrices(spatialDec * self)958 void SpatialDecBufferMatrices(spatialDec *self) {
959   int row, col;
960   int complexParBands;
961   complexParBands = self->numParameterBands;
962 
963   /*
964     buffer matrices M2
965   */
966   for (row = 0; row < self->numM2rows; row++) {
967     for (col = 0; col < self->numVChannels; col++) {
968       FDKmemcpy(self->M2RealPrev__FDK[row][col], self->M2Real__FDK[row][col],
969                 self->numParameterBands * sizeof(FIXP_DBL));
970       if (0 || (self->phaseCoding == 3)) {
971         FDKmemcpy(self->M2ImagPrev__FDK[row][col], self->M2Imag__FDK[row][col],
972                   complexParBands * sizeof(FIXP_DBL));
973       }
974     }
975   }
976 
977   /* buffer phase */
978   FDKmemcpy(self->PhasePrevLeft__FDK, self->PhaseLeft__FDK,
979             self->numParameterBands * sizeof(FIXP_DBL));
980   FDKmemcpy(self->PhasePrevRight__FDK, self->PhaseRight__FDK,
981             self->numParameterBands * sizeof(FIXP_DBL));
982 }
983 
984 #define PHASE_SCALE 2
985 
986 #ifndef P_PI
987 #define P_PI 3.1415926535897932
988 #endif
989 
990 /* 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)991 static FIXP_DBL interp_angle__FDK(FIXP_DBL angle1, FIXP_DBL angle2,
992                                   FIXP_SGL alpha, FIXP_DBL pi_x2) {
993   if (angle2 - angle1 > (pi_x2 >> 1)) angle2 -= pi_x2;
994 
995   if (angle1 - angle2 > (pi_x2 >> 1)) angle1 -= pi_x2;
996 
997   return interpolateParameter(alpha, angle2, angle1);
998 }
999 
1000 /*
1001  *
1002  */
SpatialDecApplyPhase(spatialDec * self,FIXP_SGL alpha__FDK,int lastSlotOfParamSet)1003 void SpatialDecApplyPhase(spatialDec *self, FIXP_SGL alpha__FDK,
1004                           int lastSlotOfParamSet) {
1005   int pb, qs;
1006   FIXP_DBL ppb[MAX_PARAMETER_BANDS *
1007                4]; /* left real, imag - right real, imag interleaved */
1008 
1009   const FIXP_DBL pi_x2 = PIx2__IPD;
1010   for (pb = 0; pb < self->numParameterBands; pb++) {
1011     FIXP_DBL pl, pr;
1012 
1013     pl = interp_angle__FDK(self->PhasePrevLeft__FDK[pb],
1014                            self->PhaseLeft__FDK[pb], alpha__FDK, pi_x2);
1015     pr = interp_angle__FDK(self->PhasePrevRight__FDK[pb],
1016                            self->PhaseRight__FDK[pb], alpha__FDK, pi_x2);
1017 
1018     inline_fixp_cos_sin(pl, pr, IPD_SCALE, &ppb[4 * pb]);
1019   }
1020 
1021   /* sign is -1 for qs = 0,2 and +1 for qs = 1 */
1022 
1023   const SCHAR *kernels = &self->kernels[0];
1024 
1025   FIXP_DBL *Dry_real0 = &self->hybOutputRealDry__FDK[0][0];
1026   FIXP_DBL *Dry_imag0 = &self->hybOutputImagDry__FDK[0][0];
1027   FIXP_DBL *Dry_real1 = &self->hybOutputRealDry__FDK[1][0];
1028   FIXP_DBL *Dry_imag1 = &self->hybOutputImagDry__FDK[1][0];
1029 
1030   for (qs = 2; qs >= 0; qs--) {
1031     FIXP_DBL out_re, out_im;
1032 
1033     pb = *kernels++;
1034     if (qs == 1) /* sign[qs] >= 0 */
1035     {
1036       cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0],
1037                    ppb[4 * pb + 1]);
1038       out_re <<= PHASE_SCALE - 1;
1039       out_im <<= PHASE_SCALE - 1;
1040       *Dry_real0++ = out_re;
1041       *Dry_imag0++ = out_im;
1042 
1043       cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2],
1044                    ppb[4 * pb + 3]);
1045       out_re <<= PHASE_SCALE - 1;
1046       out_im <<= PHASE_SCALE - 1;
1047       *Dry_real1++ = out_re;
1048       *Dry_imag1++ = out_im;
1049     } else {
1050       cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0],
1051                    -ppb[4 * pb + 1]);
1052       out_re <<= PHASE_SCALE - 1;
1053       out_im <<= PHASE_SCALE - 1;
1054       *Dry_real0++ = out_re;
1055       *Dry_imag0++ = out_im;
1056 
1057       cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2],
1058                    -ppb[4 * pb + 3]);
1059       out_re <<= PHASE_SCALE - 1;
1060       out_im <<= PHASE_SCALE - 1;
1061       *Dry_real1++ = out_re;
1062       *Dry_imag1++ = out_im;
1063     }
1064   }
1065 
1066   /* sign is +1 for qs >=3 */
1067   for (qs = self->hybridBands - 3; qs--;) {
1068     FIXP_DBL out_re, out_im;
1069 
1070     pb = *kernels++;
1071     cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0],
1072                  ppb[4 * pb + 1]);
1073     out_re <<= PHASE_SCALE - 1;
1074     out_im <<= PHASE_SCALE - 1;
1075     *Dry_real0++ = out_re;
1076     *Dry_imag0++ = out_im;
1077 
1078     cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2],
1079                  ppb[4 * pb + 3]);
1080     out_re <<= PHASE_SCALE - 1;
1081     out_im <<= PHASE_SCALE - 1;
1082     *Dry_real1++ = out_re;
1083     *Dry_imag1++ = out_im;
1084   }
1085 }
1086