Home | History | Annotate | Download | only in src
      1 /* -----------------------------------------------------------------------------
      2 Software License for The Fraunhofer FDK AAC Codec Library for Android
      3 
      4  Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Frderung 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 (at) 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  */
    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  */
    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 
    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 
    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 
    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 *******************************************************************************/
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 */
    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  */
    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