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