Coverage Report

Created: 2023-03-26 06:07

/src/aac/libSACdec/src/sac_process.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -----------------------------------------------------------------------------
2
Software License for The Fraunhofer FDK AAC Codec Library for Android
3
4
© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
5
Forschung e.V. All rights reserved.
6
7
 1.    INTRODUCTION
8
The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9
that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10
scheme for digital audio. This FDK AAC Codec software is intended to be used on
11
a wide variety of Android devices.
12
13
AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14
general perceptual audio codecs. AAC-ELD is considered the best-performing
15
full-bandwidth communications codec by independent studies and is widely
16
deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17
specifications.
18
19
Patent licenses for necessary patent claims for the FDK AAC Codec (including
20
those of Fraunhofer) may be obtained through Via Licensing
21
(www.vialicensing.com) or through the respective patent owners individually for
22
the purpose of encoding or decoding bit streams in products that are compliant
23
with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24
Android devices already license these patent claims through Via Licensing or
25
directly from the patent owners, and therefore FDK AAC Codec software may
26
already be covered under those patent licenses when it is used for those
27
licensed purposes only.
28
29
Commercially-licensed AAC software libraries, including floating-point versions
30
with enhanced sound quality, are also available from Fraunhofer. Users are
31
encouraged to check the Fraunhofer website for additional applications
32
information and documentation.
33
34
2.    COPYRIGHT LICENSE
35
36
Redistribution and use in source and binary forms, with or without modification,
37
are permitted without payment of copyright license fees provided that you
38
satisfy the following conditions:
39
40
You must retain the complete text of this software license in redistributions of
41
the FDK AAC Codec or your modifications thereto in source code form.
42
43
You must retain the complete text of this software license in the documentation
44
and/or other materials provided with redistributions of the FDK AAC Codec or
45
your modifications thereto in binary form. You must make available free of
46
charge copies of the complete source code of the FDK AAC Codec and your
47
modifications thereto to recipients of copies in binary form.
48
49
The name of Fraunhofer may not be used to endorse or promote products derived
50
from this library without prior written permission.
51
52
You may not charge copyright license fees for anyone to use, copy or distribute
53
the FDK AAC Codec software or your modifications thereto.
54
55
Your modified versions of the FDK AAC Codec must carry prominent notices stating
56
that you changed the software and the date of any change. For modified versions
57
of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58
must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59
AAC Codec Library for Android."
60
61
3.    NO PATENT LICENSE
62
63
NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64
limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65
Fraunhofer provides no warranty of patent non-infringement with respect to this
66
software.
67
68
You may use this FDK AAC Codec software or modifications thereto only for
69
purposes that are authorized by appropriate patent licenses.
70
71
4.    DISCLAIMER
72
73
This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74
holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75
including but not limited to the implied warranties of merchantability and
76
fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77
CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78
or consequential damages, including but not limited to procurement of substitute
79
goods or services; loss of use, data, or profits, or business interruption,
80
however caused and on any theory of liability, whether in contract, strict
81
liability, or tort (including negligence), arising in any way out of the use of
82
this software, even if advised of the possibility of such damage.
83
84
5.    CONTACT INFORMATION
85
86
Fraunhofer Institute for Integrated Circuits IIS
87
Attention: Audio and Multimedia Departments - FDK AAC LL
88
Am Wolfsmantel 33
89
91058 Erlangen, Germany
90
91
www.iis.fraunhofer.de/amm
92
amm-info@iis.fraunhofer.de
93
----------------------------------------------------------------------------- */
94
95
/*********************** MPEG surround decoder library *************************
96
97
   Author(s):
98
99
   Description: SAC Processing
100
101
*******************************************************************************/
102
103
/* data structures and interfaces for spatial audio reference software */
104
#include "sac_process.h"
105
106
#include "sac_bitdec.h"
107
#include "sac_calcM1andM2.h"
108
#include "sac_smoothing.h"
109
#include "sac_rom.h"
110
111
#include "sac_dec_errorcodes.h"
112
113
#include "FDK_trigFcts.h"
114
#include "FDK_decorrelate.h"
115
116
0
#define SAC_DEC_APPLY_M2_SCALE(spec, s) ((spec) >> (-(s)))
117
118
/**
119
 * \brief  Linear interpolation between two parameter values.
120
 *         a*alpha + b*(1-alpha)
121
 *       = a*alpha + b - b*alpha
122
 *
123
 * \param alpha               Weighting factor.
124
 * \param a                   Parameter a.
125
 * \param b                   Parameter b.
126
 *
127
 * \return Interpolated parameter value.
128
 */
129
FDK_INLINE FIXP_DBL interpolateParameter(const FIXP_SGL alpha, const FIXP_DBL a,
130
0
                                         const FIXP_DBL b) {
131
0
  return (b - fMult(alpha, b) + fMult(alpha, a));
132
0
}
133
134
/**
135
 * \brief Map MPEG Surround channel indices to MPEG 4 PCE like channel indices.
136
 * \param self Spatial decoder handle.
137
 * \param ch MPEG Surround channel index.
138
 * \return MPEG 4 PCE style channel index, corresponding to the given MPEG
139
 * Surround channel index.
140
 */
141
0
static UINT mapChannel(spatialDec *self, UINT ch) {
142
0
  static const UCHAR chanelIdx[][8] = {
143
0
      {0, 1, 2, 3, 4, 5, 6, 7}, /*  binaural, TREE_212, arbitrary tree */
144
0
  };
145
146
0
  int idx = 0;
147
148
0
  return (chanelIdx[idx][ch]);
149
0
}
150
151
0
FIXP_DBL getChGain(spatialDec *self, UINT ch, INT *scale) {
152
  /* init no gain modifier */
153
0
  FIXP_DBL gain = 0x80000000;
154
0
  *scale = 0;
155
156
0
  if ((!isTwoChMode(self->upmixType)) &&
157
0
      (self->upmixType != UPMIXTYPE_BYPASS)) {
158
0
    if ((ch == 0) || (ch == 1) || (ch == 2)) {
159
      /* no modifier */
160
0
    }
161
0
  }
162
163
0
  return gain;
164
0
}
165
166
SACDEC_ERROR SpatialDecQMFAnalysis(spatialDec *self, const PCM_MPS *inData,
167
                                   const INT ts, const INT bypassMode,
168
                                   FIXP_DBL **qmfReal, FIXP_DBL **qmfImag,
169
0
                                   const int numInputChannels) {
170
0
  SACDEC_ERROR err = MPS_OK;
171
0
  int ch, offset;
172
173
0
  offset = self->pQmfDomain->globalConf.nBandsSynthesis *
174
0
           self->pQmfDomain->globalConf.nQmfTimeSlots;
175
176
0
  {
177
0
    for (ch = 0; ch < numInputChannels; ch++) {
178
0
      const PCM_MPS *inSamples =
179
0
          &inData[ts * self->pQmfDomain->globalConf.nBandsAnalysis];
180
0
      FIXP_DBL *pQmfRealAnalysis = qmfReal[ch]; /* no delay in blind mode */
181
0
      FIXP_DBL *pQmfImagAnalysis = qmfImag[ch];
182
183
0
      CalculateSpaceAnalysisQmf(&self->pQmfDomain->QmfDomainIn[ch].fb,
184
0
                                inSamples + (ch * offset), pQmfRealAnalysis,
185
0
                                pQmfImagAnalysis);
186
187
0
      if (!isTwoChMode(self->upmixType) && !bypassMode) {
188
0
        int i;
189
0
        for (i = 0; i < self->qmfBands; i++) {
190
0
          qmfReal[ch][i] = fMult(
191
0
              scaleValueSaturate(qmfReal[ch][i], self->sacInDataHeadroom - (1)),
192
0
              self->clipProtectGain__FDK);
193
0
          qmfImag[ch][i] = fMult(
194
0
              scaleValueSaturate(qmfImag[ch][i], self->sacInDataHeadroom - (1)),
195
0
              self->clipProtectGain__FDK);
196
0
        }
197
0
      }
198
0
    }
199
0
  }
200
201
0
  self->qmfInputDelayBufPos =
202
0
      (self->qmfInputDelayBufPos + 1) % self->pc_filterdelay;
203
204
0
  return err;
205
0
}
206
207
SACDEC_ERROR SpatialDecFeedQMF(spatialDec *self, FIXP_DBL **qmfInDataReal,
208
                               FIXP_DBL **qmfInDataImag, const INT ts,
209
                               const INT bypassMode, FIXP_DBL **qmfReal__FDK,
210
                               FIXP_DBL **qmfImag__FDK,
211
0
                               const INT numInputChannels) {
212
0
  SACDEC_ERROR err = MPS_OK;
213
0
  int ch;
214
215
0
  {
216
0
    for (ch = 0; ch < numInputChannels; ch++) {
217
0
      FIXP_DBL *pQmfRealAnalysis =
218
0
          qmfReal__FDK[ch]; /* no delay in blind mode */
219
0
      FIXP_DBL *pQmfImagAnalysis = qmfImag__FDK[ch];
220
221
      /* Write Input data to pQmfRealAnalysis. */
222
0
      if (self->bShareDelayWithSBR) {
223
0
        FDK_QmfDomain_GetSlot(&self->pQmfDomain->QmfDomainIn[ch],
224
0
                              ts + HYBRID_FILTER_DELAY, 0,
225
0
                              MAX_QMF_BANDS_TO_HYBRID, pQmfRealAnalysis,
226
0
                              pQmfImagAnalysis, 15 + (1));
227
0
        FDK_QmfDomain_GetSlot(&self->pQmfDomain->QmfDomainIn[ch], ts,
228
0
                              MAX_QMF_BANDS_TO_HYBRID, self->qmfBands,
229
0
                              pQmfRealAnalysis, pQmfImagAnalysis, 15 + (1));
230
0
      } else {
231
0
        FDK_QmfDomain_GetSlot(&self->pQmfDomain->QmfDomainIn[ch], ts, 0,
232
0
                              self->qmfBands, pQmfRealAnalysis,
233
0
                              pQmfImagAnalysis, 15 + (1));
234
0
      }
235
0
      if (ts == self->pQmfDomain->globalConf.nQmfTimeSlots - 1) {
236
        /* Is currently also needed in case we dont have any overlap. We need to
237
         * save lb_scale to ov_lb_scale */
238
0
        FDK_QmfDomain_SaveOverlap(&self->pQmfDomain->QmfDomainIn[ch], 0);
239
0
      }
240
241
      /* Apply clip protection to output. */
242
0
      if (!isTwoChMode(self->upmixType) && !bypassMode) {
243
0
        int i;
244
0
        for (i = 0; i < self->qmfBands; i++) {
245
0
          qmfReal__FDK[ch][i] =
246
0
              fMult(qmfReal__FDK[ch][i], self->clipProtectGain__FDK);
247
0
          qmfImag__FDK[ch][i] =
248
0
              fMult(qmfImag__FDK[ch][i], self->clipProtectGain__FDK);
249
0
        }
250
0
      }
251
252
0
    } /* End of loop over numInputChannels */
253
0
  }
254
255
0
  self->qmfInputDelayBufPos =
256
0
      (self->qmfInputDelayBufPos + 1) % self->pc_filterdelay;
257
258
0
  return err;
259
0
}
260
261
/*******************************************************************************
262
 Functionname: SpatialDecHybridAnalysis
263
 *******************************************************************************
264
265
 Description:
266
267
 Arguments:
268
269
 Input:
270
  float** pointers[4] leftReal, leftIm, rightReal, rightIm
271
272
 Output:
273
  float self->qmfInputReal[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_QMF_BANDS];
274
  float self->qmfInputImag[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_QMF_BANDS];
275
276
  float
277
self->hybInputReal[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_HYBRID_BANDS]; float
278
self->hybInputImag[MAX_INPUT_CHANNELS][MAX_TIME_SLOTS][MAX_HYBRID_BANDS];
279
280
281
*******************************************************************************/
282
SACDEC_ERROR SpatialDecHybridAnalysis(spatialDec *self, FIXP_DBL **qmfInputReal,
283
                                      FIXP_DBL **qmfInputImag,
284
                                      FIXP_DBL **hybOutputReal,
285
                                      FIXP_DBL **hybOutputImag, const INT ts,
286
0
                                      const INT numInputChannels) {
287
0
  SACDEC_ERROR err = MPS_OK;
288
0
  int ch;
289
290
0
  for (ch = 0; ch < numInputChannels;
291
0
       ch++) /* hybrid filtering for down-mix signals */
292
0
  {
293
0
    if (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD) {
294
0
      int k;
295
      /* No hybrid filtering. Just copy the QMF data. */
296
0
      for (k = 0; k < self->hybridBands; k += 1) {
297
0
        hybOutputReal[ch][k] = qmfInputReal[ch][k];
298
0
        hybOutputImag[ch][k] = qmfInputImag[ch][k];
299
0
      }
300
0
    } else {
301
0
      self->hybridAnalysis[ch].hfMode = self->bShareDelayWithSBR;
302
303
0
      if (self->stereoConfigIndex == 3)
304
0
        FDK_ASSERT(self->hybridAnalysis[ch].hfMode == 0);
305
0
      FDKhybridAnalysisApply(&self->hybridAnalysis[ch], qmfInputReal[ch],
306
0
                             qmfInputImag[ch], hybOutputReal[ch],
307
0
                             hybOutputImag[ch]);
308
0
    }
309
0
  }
310
311
0
  if ((self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_USAC) &&
312
0
      self->residualCoding) {
313
0
    self->hybridAnalysis[numInputChannels].hfMode = 0;
314
0
    FDKhybridAnalysisApply(
315
0
        &self->hybridAnalysis[numInputChannels],
316
0
        self->qmfResidualReal__FDK[0][0], self->qmfResidualImag__FDK[0][0],
317
0
        self->hybResidualReal__FDK[0], self->hybResidualImag__FDK[0]);
318
0
  }
319
320
0
  return err;
321
0
}
322
323
SACDEC_ERROR SpatialDecCreateX(spatialDec *self, FIXP_DBL **hybInputReal,
324
                               FIXP_DBL **hybInputImag, FIXP_DBL **pxReal,
325
0
                               FIXP_DBL **pxImag) {
326
0
  SACDEC_ERROR err = MPS_OK;
327
0
  int row;
328
329
  /* Creating wDry */
330
0
  for (row = 0; row < self->numInputChannels; row++) {
331
    /* pointer to direct signals */
332
0
    pxReal[row] = hybInputReal[row];
333
0
    pxImag[row] = hybInputImag[row];
334
0
  }
335
336
0
  return err;
337
0
}
338
339
static void M2ParamToKernelMult(FIXP_SGL *RESTRICT pKernel,
340
                                FIXP_DBL *RESTRICT Mparam,
341
                                FIXP_DBL *RESTRICT MparamPrev,
342
                                int *RESTRICT pWidth, FIXP_SGL alpha__FDK,
343
0
                                int nBands) {
344
0
  int pb;
345
346
0
  for (pb = 0; pb < nBands; pb++) {
347
0
    FIXP_SGL tmp = FX_DBL2FX_SGL(
348
0
        interpolateParameter(alpha__FDK, Mparam[pb], MparamPrev[pb]));
349
350
0
    int i = pWidth[pb];
351
0
    if (i & 1) *pKernel++ = tmp;
352
0
    if (i & 2) {
353
0
      *pKernel++ = tmp;
354
0
      *pKernel++ = tmp;
355
0
    }
356
0
    for (i >>= 2; i--;) {
357
0
      *pKernel++ = tmp;
358
0
      *pKernel++ = tmp;
359
0
      *pKernel++ = tmp;
360
0
      *pKernel++ = tmp;
361
0
    }
362
0
  }
363
0
}
364
365
SACDEC_ERROR SpatialDecApplyM1_CreateW_Mode212(
366
    spatialDec *self, const SPATIAL_BS_FRAME *frame, FIXP_DBL **xReal,
367
0
    FIXP_DBL **xImag, FIXP_DBL **vReal, FIXP_DBL **vImag) {
368
0
  SACDEC_ERROR err = MPS_OK;
369
0
  int res;
370
0
  FIXP_DBL *decorrInReal = vReal[0];
371
0
  FIXP_DBL *decorrInImag = vImag[0];
372
373
  /* M1 does not do anything in 212 mode, so use simplified processing */
374
0
  FDK_ASSERT(self->numVChannels == 2);
375
0
  FDK_ASSERT(self->numDirektSignals == 1);
376
0
  FDK_ASSERT(self->numDecorSignals == 1);
377
0
  FDKmemcpy(vReal[0], xReal[0], self->hybridBands * sizeof(FIXP_DBL));
378
0
  FDKmemcpy(vImag[0], xImag[0], self->hybridBands * sizeof(FIXP_DBL));
379
380
0
  if (isTsdActive(frame->TsdData)) {
381
    /* Generate v_{x,nonTr} as input for allpass based decorrelator */
382
0
    TsdGenerateNonTr(self->hybridBands, frame->TsdData, self->TsdTs, vReal[0],
383
0
                     vImag[0], vReal[1], vImag[1], &decorrInReal,
384
0
                     &decorrInImag);
385
0
  }
386
  /* - Decorrelate */
387
0
  res = SpatialDecGetResidualIndex(self, 1);
388
0
  if (FDKdecorrelateApply(&self->apDecor[0], decorrInReal, decorrInImag,
389
0
                          vReal[1], vImag[1],
390
0
                          self->param2hyb[self->residualBands[res]])) {
391
0
    return MPS_NOTOK;
392
0
  }
393
0
  if (isTsdActive(frame->TsdData)) {
394
    /* Generate v_{x,Tr}, apply transient decorrelator and add to allpass based
395
     * decorrelator output */
396
0
    TsdApply(self->hybridBands, frame->TsdData, &self->TsdTs,
397
0
             vReal[0], /* input: v_x */
398
0
             vImag[0],
399
0
             vReal[1], /* input: d_{x,nonTr}; output: d_{x,nonTr} + d_{x,Tr} */
400
0
             vImag[1]);
401
0
  }
402
403
  /* Write residual signal in approriate parameter bands */
404
0
  if (self->residualBands[res] > 0) {
405
0
    int stopBand = self->param2hyb[self->residualBands[res]];
406
0
    FDKmemcpy(vReal[1], self->hybResidualReal__FDK[res],
407
0
              fixMin(stopBand, self->hybridBands) * sizeof(FIXP_DBL));
408
0
    FDKmemcpy(vImag[1], self->hybResidualImag__FDK[res],
409
0
              fixMin(stopBand, self->hybridBands) * sizeof(FIXP_DBL));
410
0
  } /* (self->residualBands[res]>0) */
411
412
0
  return err;
413
0
}
414
415
SACDEC_ERROR SpatialDecApplyM2_Mode212(spatialDec *self, INT ps,
416
                                       const FIXP_SGL alpha, FIXP_DBL **wReal,
417
                                       FIXP_DBL **wImag,
418
                                       FIXP_DBL **hybOutputRealDry,
419
0
                                       FIXP_DBL **hybOutputImagDry) {
420
0
  SACDEC_ERROR err = MPS_OK;
421
0
  INT row;
422
423
0
  INT *pWidth = self->kernels_width;
424
  /* for stereoConfigIndex == 3 case hybridBands is < 71 */
425
0
  INT pb_max = self->kernels[self->hybridBands - 1] + 1;
426
0
  INT max_row = self->numOutputChannels;
427
428
0
  INT M2_exp = 0;
429
0
  if (self->residualCoding) M2_exp = 3;
430
431
0
  for (row = 0; row < max_row; row++)  // 2 times
432
0
  {
433
0
    FIXP_DBL *Mparam0 = self->M2Real__FDK[row][0];
434
0
    FIXP_DBL *Mparam1 = self->M2Real__FDK[row][1];
435
0
    FIXP_DBL *MparamPrev0 = self->M2RealPrev__FDK[row][0];
436
0
    FIXP_DBL *MparamPrev1 = self->M2RealPrev__FDK[row][1];
437
438
0
    FIXP_DBL *RESTRICT pHybOutRealDry = hybOutputRealDry[row];
439
0
    FIXP_DBL *RESTRICT pHybOutImagDry = hybOutputImagDry[row];
440
441
0
    FIXP_DBL *RESTRICT pWReal0 = wReal[0];
442
0
    FIXP_DBL *RESTRICT pWReal1 = wReal[1];
443
0
    FIXP_DBL *RESTRICT pWImag0 = wImag[0];
444
0
    FIXP_DBL *RESTRICT pWImag1 = wImag[1];
445
0
    for (INT pb = 0; pb < pb_max; pb++) {
446
0
      FIXP_DBL tmp0, tmp1;
447
448
0
      tmp0 = interpolateParameter(alpha, Mparam0[pb], MparamPrev0[pb]);
449
0
      tmp1 = interpolateParameter(alpha, Mparam1[pb], MparamPrev1[pb]);
450
451
0
      INT i = pWidth[pb];
452
453
0
      do  // about 3-4 times
454
0
      {
455
0
        FIXP_DBL var0, var1, real, imag;
456
457
0
        var0 = *pWReal0++;
458
0
        var1 = *pWReal1++;
459
0
        real = fMultDiv2(var0, tmp0);
460
0
        var0 = *pWImag0++;
461
0
        real = fMultAddDiv2(real, var1, tmp1);
462
0
        var1 = *pWImag1++;
463
0
        imag = fMultDiv2(var0, tmp0);
464
0
        *pHybOutRealDry++ = real << (1 + M2_exp);
465
0
        imag = fMultAddDiv2(imag, var1, tmp1);
466
0
        *pHybOutImagDry++ = imag << (1 + M2_exp);
467
0
      } while (--i != 0);
468
0
    }
469
0
  }
470
0
  return err;
471
0
}
472
473
SACDEC_ERROR SpatialDecApplyM2_Mode212_ResidualsPlusPhaseCoding(
474
    spatialDec *self, INT ps, const FIXP_SGL alpha, FIXP_DBL **wReal,
475
    FIXP_DBL **wImag, FIXP_DBL **hybOutputRealDry,
476
0
    FIXP_DBL **hybOutputImagDry) {
477
0
  SACDEC_ERROR err = MPS_OK;
478
0
  INT row;
479
0
  INT scale_param_m2;
480
0
  INT *pWidth = self->kernels_width;
481
0
  INT pb_max = self->kernels[self->hybridBands - 1] + 1;
482
483
0
  scale_param_m2 = SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2;
484
485
0
  for (row = 0; row < self->numM2rows; row++) {
486
0
    INT qs, pb;
487
488
0
    FIXP_DBL *RESTRICT pWReal0 = wReal[0];
489
0
    FIXP_DBL *RESTRICT pWImag0 = wImag[0];
490
0
    FIXP_DBL *RESTRICT pWReal1 = wReal[1];
491
0
    FIXP_DBL *RESTRICT pWImag1 = wImag[1];
492
493
0
    FIXP_DBL *MReal0 = self->M2Real__FDK[row][0];
494
0
    FIXP_DBL *MImag0 = self->M2Imag__FDK[row][0];
495
0
    FIXP_DBL *MReal1 = self->M2Real__FDK[row][1];
496
0
    FIXP_DBL *MRealPrev0 = self->M2RealPrev__FDK[row][0];
497
0
    FIXP_DBL *MImagPrev0 = self->M2ImagPrev__FDK[row][0];
498
0
    FIXP_DBL *MRealPrev1 = self->M2RealPrev__FDK[row][1];
499
500
0
    FIXP_DBL *RESTRICT pHybOutRealDry = hybOutputRealDry[row];
501
0
    FIXP_DBL *RESTRICT pHybOutImagDry = hybOutputImagDry[row];
502
503
0
    FDK_ASSERT(!(self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD));
504
0
    FDK_ASSERT((pWidth[0] + pWidth[1]) >= 3);
505
506
0
    for (pb = 0, qs = 3; pb < 2; pb++) {
507
0
      INT s;
508
0
      FIXP_DBL maxVal;
509
0
      FIXP_DBL mReal1;
510
0
      FIXP_DBL mReal0, mImag0;
511
0
      FIXP_DBL iReal0, iImag0, iReal1;
512
513
0
      iReal0 = interpolateParameter(alpha, MReal0[pb], MRealPrev0[pb]);
514
0
      iImag0 = -interpolateParameter(alpha, MImag0[pb], MImagPrev0[pb]);
515
0
      iReal1 = interpolateParameter(alpha, MReal1[pb], MRealPrev1[pb]);
516
517
0
      maxVal = fAbs(iReal0) | fAbs(iImag0);
518
0
      maxVal |= fAbs(iReal1);
519
520
0
      s = fMin(CntLeadingZeros(maxVal) - 2, scale_param_m2);
521
522
0
      mReal0 = scaleValue(iReal0, s);
523
0
      mImag0 = scaleValue(iImag0, s);
524
0
      mReal1 = scaleValue(iReal1, s);
525
526
0
      s = scale_param_m2 - s;
527
528
0
      INT i = pWidth[pb];
529
530
0
      do {
531
0
        FIXP_DBL real, imag, wReal0, wImag0, wReal1, wImag1;
532
533
0
        wReal0 = *pWReal0++;
534
0
        wImag0 = *pWImag0++;
535
0
        wReal1 = *pWReal1++;
536
0
        wImag1 = *pWImag1++;
537
538
0
        cplxMultDiv2(&real, &imag, wReal0, wImag0, mReal0, mImag0);
539
540
0
        *pHybOutRealDry++ = fMultAddDiv2(real, wReal1, mReal1) << s;
541
0
        *pHybOutImagDry++ = fMultAddDiv2(imag, wImag1, mReal1) << s;
542
543
0
        if (qs > 0) {
544
0
          mImag0 = -mImag0;
545
0
          qs--;
546
0
        }
547
0
      } while (--i != 0);
548
0
    }
549
550
0
    for (; pb < pb_max; pb++) {
551
0
      INT s;
552
0
      FIXP_DBL maxVal;
553
0
      FIXP_SGL mReal1;
554
0
      FIXP_SGL mReal0, mImag0;
555
0
      FIXP_DBL iReal0, iImag0, iReal1;
556
557
0
      iReal0 = interpolateParameter(alpha, MReal0[pb], MRealPrev0[pb]);
558
0
      iImag0 = interpolateParameter(alpha, MImag0[pb], MImagPrev0[pb]);
559
0
      iReal1 = interpolateParameter(alpha, MReal1[pb], MRealPrev1[pb]);
560
561
0
      maxVal = fAbs(iReal0) | fAbs(iImag0);
562
0
      maxVal |= fAbs(iReal1);
563
564
0
      s = fMin(CntLeadingZeros(maxVal) - 2, scale_param_m2);
565
566
0
      mReal0 = FX_DBL2FX_SGL(scaleValue(iReal0, s));
567
0
      mImag0 = FX_DBL2FX_SGL(scaleValue(iImag0, s));
568
0
      mReal1 = FX_DBL2FX_SGL(scaleValue(iReal1, s));
569
570
0
      s = scale_param_m2 - s;
571
572
0
      INT i = pWidth[pb];
573
574
0
      do {
575
0
        FIXP_DBL real, imag, wReal0, wImag0, wReal1, wImag1;
576
577
0
        wReal0 = *pWReal0++;
578
0
        wImag0 = *pWImag0++;
579
0
        wReal1 = *pWReal1++;
580
0
        wImag1 = *pWImag1++;
581
582
0
        cplxMultDiv2(&real, &imag, wReal0, wImag0, mReal0, mImag0);
583
584
0
        *pHybOutRealDry++ = fMultAddDiv2(real, wReal1, mReal1) << s;
585
0
        *pHybOutImagDry++ = fMultAddDiv2(imag, wImag1, mReal1) << s;
586
0
      } while (--i != 0);
587
0
    }
588
0
  }
589
590
0
  return err;
591
0
}
592
593
SACDEC_ERROR SpatialDecApplyM2(spatialDec *self, INT ps, const FIXP_SGL alpha,
594
                               FIXP_DBL **wReal, FIXP_DBL **wImag,
595
                               FIXP_DBL **hybOutputRealDry,
596
                               FIXP_DBL **hybOutputImagDry,
597
                               FIXP_DBL **hybOutputRealWet,
598
0
                               FIXP_DBL **hybOutputImagWet) {
599
0
  SACDEC_ERROR err = MPS_OK;
600
601
0
  {
602
0
    int qs, row, col;
603
0
    int complexHybBands;
604
0
    int complexParBands;
605
0
    int scale_param_m2 = 0;
606
0
    int toolsDisabled;
607
608
0
    UCHAR activParamBands;
609
0
    FIXP_DBL *RESTRICT pWReal, *RESTRICT pWImag, *RESTRICT pHybOutRealDry,
610
0
        *RESTRICT pHybOutImagDry, *RESTRICT pHybOutRealWet,
611
0
        *RESTRICT pHybOutImagWet;
612
0
    C_ALLOC_SCRATCH_START(pKernel, FIXP_SGL, MAX_HYBRID_BANDS);
613
614
    /* The wet signal is added to the dry signal directly in applyM2 if GES and
615
     * STP are disabled */
616
0
    toolsDisabled =
617
0
        ((self->tempShapeConfig == 1) || (self->tempShapeConfig == 2)) ? 0 : 1;
618
619
0
    {
620
0
      complexHybBands = self->hybridBands;
621
0
      complexParBands = self->numParameterBands;
622
0
    }
623
624
0
    FDKmemclear(hybOutputImagDry[0],
625
0
                self->createParams.maxNumOutputChannels *
626
0
                    self->createParams.maxNumCmplxHybBands * sizeof(FIXP_DBL));
627
0
    FDKmemclear(hybOutputRealDry[0], self->createParams.maxNumOutputChannels *
628
0
                                         self->createParams.maxNumHybridBands *
629
0
                                         sizeof(FIXP_DBL));
630
631
0
    if (!toolsDisabled) {
632
0
      FDKmemclear(hybOutputRealWet[0],
633
0
                  self->createParams.maxNumOutputChannels *
634
0
                      self->createParams.maxNumHybridBands * sizeof(FIXP_DBL));
635
0
      FDKmemclear(hybOutputImagWet[0],
636
0
                  self->createParams.maxNumOutputChannels *
637
0
                      self->createParams.maxNumCmplxHybBands *
638
0
                      sizeof(FIXP_DBL));
639
0
    }
640
641
0
    if (self->phaseCoding == 3) {
642
0
      scale_param_m2 = -(SCALE_DATA_APPLY_M2_PC - 1);
643
0
    }
644
645
0
    for (row = 0; row < self->numM2rows; row++) {
646
0
      pHybOutRealDry = hybOutputRealDry[row];
647
0
      pHybOutImagDry = hybOutputImagDry[row];
648
649
0
      if (toolsDisabled) {
650
0
        pHybOutRealWet = hybOutputRealDry[row];
651
0
        pHybOutImagWet = hybOutputImagDry[row];
652
0
      } else {
653
0
        pHybOutRealWet = hybOutputRealWet[row];
654
0
        pHybOutImagWet = hybOutputImagWet[row];
655
0
      }
656
657
0
      for (col = 0; col < self->numDirektSignals; col++) {
658
0
        if (self->pActivM2ParamBands ==
659
0
            0) { /* default setting, calculate all rows and columns */
660
0
          activParamBands = 1;
661
0
        } else {
662
0
          if (self->pActivM2ParamBands[MAX_M2_INPUT * row +
663
0
                                       col]) /* table with activ and inactiv
664
                                                bands exists for current
665
                                                configuration */
666
0
            activParamBands = 1;
667
0
          else
668
0
            activParamBands = 0;
669
0
        }
670
0
        if (activParamBands) {
671
0
          pWReal = wReal[col];
672
0
          pWImag = wImag[col];
673
674
0
          M2ParamToKernelMult(pKernel, self->M2Real__FDK[row][col],
675
0
                              self->M2RealPrev__FDK[row][col],
676
0
                              self->kernels_width, alpha,
677
0
                              self->numParameterBands);
678
679
0
          if (1 && (self->phaseCoding != 3)) {
680
            /* direct signals */
681
0
            {
682
              /* only one sample will be assigned to each row, hence
683
               * accumulation is not neccessary; that is valid for all
684
               * configurations */
685
0
              for (qs = 0; qs < complexHybBands; qs++) {
686
0
                pHybOutRealDry[qs] = fMult(pWReal[qs], pKernel[qs]);
687
0
                pHybOutImagDry[qs] = fMult(pWImag[qs], pKernel[qs]);
688
0
              }
689
0
            }
690
0
          } else { /*  isBinauralMode(self->upmixType)  */
691
692
0
            for (qs = 0; qs < complexHybBands; qs++) {
693
0
              pHybOutRealDry[qs] += SAC_DEC_APPLY_M2_SCALE(
694
0
                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
695
0
              pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
696
0
                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
697
0
            }
698
699
0
            M2ParamToKernelMult(pKernel, self->M2Imag__FDK[row][col],
700
0
                                self->M2ImagPrev__FDK[row][col],
701
0
                                self->kernels_width, alpha, complexParBands);
702
703
            /* direct signals sign is -1 for qs = 0,2 */
704
0
            pHybOutRealDry[0] += SAC_DEC_APPLY_M2_SCALE(
705
0
                fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
706
0
            pHybOutImagDry[0] -= SAC_DEC_APPLY_M2_SCALE(
707
0
                fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
708
709
0
            pHybOutRealDry[2] += SAC_DEC_APPLY_M2_SCALE(
710
0
                fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
711
0
            pHybOutImagDry[2] -= SAC_DEC_APPLY_M2_SCALE(
712
0
                fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
713
714
            /* direct signals sign is +1 for qs = 1,3,4,5,...,complexHybBands */
715
0
            pHybOutRealDry[1] -= SAC_DEC_APPLY_M2_SCALE(
716
0
                fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
717
0
            pHybOutImagDry[1] += SAC_DEC_APPLY_M2_SCALE(
718
0
                fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
719
720
0
            for (qs = 3; qs < complexHybBands; qs++) {
721
0
              pHybOutRealDry[qs] -= SAC_DEC_APPLY_M2_SCALE(
722
0
                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
723
0
              pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
724
0
                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
725
0
            }
726
0
          } /* self->upmixType */
727
0
        }   /* if (activParamBands) */
728
0
      }     /* self->numDirektSignals */
729
730
0
      for (; col < self->numVChannels; col++) {
731
0
        if (self->pActivM2ParamBands ==
732
0
            0) { /* default setting, calculate all rows and columns */
733
0
          activParamBands = 1;
734
0
        } else {
735
0
          if (self->pActivM2ParamBands[MAX_M2_INPUT * row +
736
0
                                       col]) /* table with activ and inactiv
737
                                                bands exists for current
738
                                                configuration */
739
0
            activParamBands = 1;
740
0
          else
741
0
            activParamBands = 0;
742
0
        }
743
744
0
        if (activParamBands) {
745
0
          int resBandIndex;
746
0
          int resHybIndex;
747
748
0
          resBandIndex =
749
0
              self->residualBands[SpatialDecGetResidualIndex(self, col)];
750
0
          resHybIndex = self->param2hyb[resBandIndex];
751
752
0
          pWReal = wReal[col];
753
0
          pWImag = wImag[col];
754
755
0
          M2ParamToKernelMult(pKernel, self->M2Real__FDK[row][col],
756
0
                              self->M2RealPrev__FDK[row][col],
757
0
                              self->kernels_width, alpha,
758
0
                              self->numParameterBands);
759
760
0
          if (1 && (self->phaseCoding != 3)) {
761
            /* residual signals */
762
0
            for (qs = 0; qs < resHybIndex; qs++) {
763
0
              pHybOutRealDry[qs] += fMult(pWReal[qs], pKernel[qs]);
764
0
              pHybOutImagDry[qs] += fMult(pWImag[qs], pKernel[qs]);
765
0
            }
766
            /* decor signals */
767
0
            for (; qs < complexHybBands; qs++) {
768
0
              pHybOutRealWet[qs] += fMult(pWReal[qs], pKernel[qs]);
769
0
              pHybOutImagWet[qs] += fMult(pWImag[qs], pKernel[qs]);
770
0
            }
771
0
          } else { /* self->upmixType */
772
            /* residual signals */
773
0
            FIXP_DBL *RESTRICT pHybOutReal;
774
0
            FIXP_DBL *RESTRICT pHybOutImag;
775
776
0
            for (qs = 0; qs < resHybIndex; qs++) {
777
0
              pHybOutRealDry[qs] += SAC_DEC_APPLY_M2_SCALE(
778
0
                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
779
0
              pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
780
0
                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
781
0
            }
782
            /* decor signals */
783
0
            for (; qs < complexHybBands; qs++) {
784
0
              pHybOutRealWet[qs] += SAC_DEC_APPLY_M2_SCALE(
785
0
                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
786
0
              pHybOutImagWet[qs] += SAC_DEC_APPLY_M2_SCALE(
787
0
                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
788
0
            }
789
790
0
            M2ParamToKernelMult(pKernel, self->M2Imag__FDK[row][col],
791
0
                                self->M2ImagPrev__FDK[row][col],
792
0
                                self->kernels_width, alpha, complexParBands);
793
794
            /* direct signals sign is -1 for qs = 0,2 */
795
            /* direct signals sign is +1 for qs = 1,3.. */
796
0
            if (toolsDisabled) {
797
0
              pHybOutRealDry[0] += SAC_DEC_APPLY_M2_SCALE(
798
0
                  fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
799
0
              pHybOutImagDry[0] -= SAC_DEC_APPLY_M2_SCALE(
800
0
                  fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
801
802
0
              pHybOutRealDry[1] -= SAC_DEC_APPLY_M2_SCALE(
803
0
                  fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
804
0
              pHybOutImagDry[1] += SAC_DEC_APPLY_M2_SCALE(
805
0
                  fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
806
807
0
              pHybOutRealDry[2] += SAC_DEC_APPLY_M2_SCALE(
808
0
                  fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
809
0
              pHybOutImagDry[2] -= SAC_DEC_APPLY_M2_SCALE(
810
0
                  fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
811
0
            } else {
812
0
              pHybOutReal = &pHybOutRealDry[0];
813
0
              pHybOutImag = &pHybOutImagDry[0];
814
0
              if (0 == resHybIndex) {
815
0
                pHybOutReal = &pHybOutRealWet[0];
816
0
                pHybOutImag = &pHybOutImagWet[0];
817
0
              }
818
0
              pHybOutReal[0] += SAC_DEC_APPLY_M2_SCALE(
819
0
                  fMultDiv2(pWImag[0], pKernel[0]), scale_param_m2);
820
0
              pHybOutImag[0] -= SAC_DEC_APPLY_M2_SCALE(
821
0
                  fMultDiv2(pWReal[0], pKernel[0]), scale_param_m2);
822
823
0
              if (1 == resHybIndex) {
824
0
                pHybOutReal = &pHybOutRealWet[0];
825
0
                pHybOutImag = &pHybOutImagWet[0];
826
0
              }
827
0
              pHybOutReal[1] -= SAC_DEC_APPLY_M2_SCALE(
828
0
                  fMultDiv2(pWImag[1], pKernel[1]), scale_param_m2);
829
0
              pHybOutImag[1] += SAC_DEC_APPLY_M2_SCALE(
830
0
                  fMultDiv2(pWReal[1], pKernel[1]), scale_param_m2);
831
832
0
              if (2 == resHybIndex) {
833
0
                pHybOutReal = &pHybOutRealWet[0];
834
0
                pHybOutImag = &pHybOutImagWet[0];
835
0
              }
836
0
              pHybOutReal[2] += SAC_DEC_APPLY_M2_SCALE(
837
0
                  fMultDiv2(pWImag[2], pKernel[2]), scale_param_m2);
838
0
              pHybOutImag[2] -= SAC_DEC_APPLY_M2_SCALE(
839
0
                  fMultDiv2(pWReal[2], pKernel[2]), scale_param_m2);
840
0
            }
841
842
0
            for (qs = 3; qs < resHybIndex; qs++) {
843
0
              pHybOutRealDry[qs] -= SAC_DEC_APPLY_M2_SCALE(
844
0
                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
845
0
              pHybOutImagDry[qs] += SAC_DEC_APPLY_M2_SCALE(
846
0
                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
847
0
            }
848
            /* decor signals */
849
0
            for (; qs < complexHybBands; qs++) {
850
0
              pHybOutRealWet[qs] -= SAC_DEC_APPLY_M2_SCALE(
851
0
                  fMultDiv2(pWImag[qs], pKernel[qs]), scale_param_m2);
852
0
              pHybOutImagWet[qs] += SAC_DEC_APPLY_M2_SCALE(
853
0
                  fMultDiv2(pWReal[qs], pKernel[qs]), scale_param_m2);
854
0
            }
855
0
          } /* self->upmixType */
856
0
        }   /* if (activParamBands) { */
857
0
      }     /*  self->numVChannels */
858
859
0
      if (self->phaseCoding == 3) {
860
0
        scaleValuesSaturate(pHybOutRealDry, complexHybBands,
861
0
                            SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
862
0
        scaleValuesSaturate(pHybOutImagDry, complexHybBands,
863
0
                            SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
864
865
0
        if (!toolsDisabled) {
866
0
          scaleValuesSaturate(pHybOutRealWet, complexHybBands,
867
0
                              SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
868
0
          scaleValuesSaturate(pHybOutImagWet, complexHybBands,
869
0
                              SCALE_PARAM_M2_212_PRED + SCALE_DATA_APPLY_M2_PC);
870
0
        }
871
0
      }
872
0
    }
873
874
0
    C_ALLOC_SCRATCH_END(pKernel, FIXP_SGL, MAX_HYBRID_BANDS);
875
0
  }
876
877
0
  return err;
878
0
}
879
880
SACDEC_ERROR SpatialDecSynthesis(spatialDec *self, const INT ts,
881
                                 FIXP_DBL **hybOutputReal,
882
                                 FIXP_DBL **hybOutputImag, PCM_MPS *timeOut,
883
                                 const INT numInputChannels,
884
0
                                 const FDK_channelMapDescr *const mapDescr) {
885
0
  SACDEC_ERROR err = MPS_OK;
886
887
0
  int ch;
888
0
  int stride, offset;
889
890
0
  stride = self->numOutputChannelsAT;
891
0
  offset = 1;
892
893
0
  PCM_MPS *pTimeOut__FDK =
894
0
      &timeOut[stride * self->pQmfDomain->globalConf.nBandsSynthesis * ts];
895
0
  C_ALLOC_SCRATCH_START(pQmfReal, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
896
0
  C_ALLOC_SCRATCH_START(pQmfImag, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
897
898
0
  for (ch = 0; ch < self->numOutputChannelsAT; ch++) {
899
0
    if (self->pConfigCurrent->syntaxFlags & SACDEC_SYNTAX_LD) {
900
0
      int k;
901
      /* No hybrid filtering. Just copy the QMF data. */
902
0
      for (k = 0; k < self->hybridBands; k += 1) {
903
0
        pQmfReal[k] = hybOutputReal[ch][k];
904
0
        pQmfImag[k] = hybOutputImag[ch][k];
905
0
      }
906
0
    } else {
907
0
      FDKhybridSynthesisApply(&self->hybridSynthesis[ch], hybOutputReal[ch],
908
0
                              hybOutputImag[ch], pQmfReal, pQmfImag);
909
0
    }
910
911
    /* Map channel indices from MPEG Surround -> PCE style -> channelMapping[]
912
     */
913
0
    FDK_ASSERT(self->numOutputChannelsAT <= 6);
914
0
    int outCh = FDK_chMapDescr_getMapValue(mapDescr, mapChannel(self, ch),
915
0
                                           self->numOutputChannelsAT);
916
917
0
    {
918
0
      if (self->stereoConfigIndex == 3) {
919
        /* MPS -> SBR */
920
0
        int i;
921
0
        FIXP_DBL *pWorkBufReal, *pWorkBufImag;
922
0
        FDK_ASSERT((self->pQmfDomain->QmfDomainOut[outCh].fb.outGain_m ==
923
0
                    (FIXP_DBL)0x80000000) &&
924
0
                   (self->pQmfDomain->QmfDomainOut[outCh].fb.outGain_e == 0));
925
0
        FDK_QmfDomain_GetWorkBuffer(&self->pQmfDomain->QmfDomainIn[outCh], ts,
926
0
                                    &pWorkBufReal, &pWorkBufImag);
927
0
        FDK_ASSERT(self->qmfBands <=
928
0
                   self->pQmfDomain->QmfDomainIn[outCh].workBuf_nBands);
929
0
        for (i = 0; i < self->qmfBands; i++) {
930
0
          pWorkBufReal[i] = pQmfReal[i];
931
0
          pWorkBufImag[i] = pQmfImag[i];
932
0
        }
933
0
        self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale =
934
0
            -7; /*-ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK;*/
935
0
        self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -=
936
0
            self->pQmfDomain->QmfDomainIn[outCh].fb.filterScale;
937
0
        self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -=
938
0
            self->clipProtectGainSF__FDK;
939
940
0
        self->pQmfDomain->QmfDomainIn[outCh].scaling.lb_scale -= (1);
941
0
      } else {
942
        /* Call the QMF synthesis for dry. */
943
0
        err = CalculateSpaceSynthesisQmf(&self->pQmfDomain->QmfDomainOut[outCh],
944
0
                                         pQmfReal, pQmfImag, stride,
945
0
                                         pTimeOut__FDK + (offset * outCh));
946
0
      }
947
0
      if (err != MPS_OK) goto bail;
948
0
    }
949
0
  } /* ch loop */
950
951
0
bail:
952
0
  C_ALLOC_SCRATCH_END(pQmfImag, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
953
0
  C_ALLOC_SCRATCH_END(pQmfReal, FIXP_DBL, QMF_MAX_SYNTHESIS_BANDS);
954
955
0
  return err;
956
0
}
957
958
0
void SpatialDecBufferMatrices(spatialDec *self) {
959
0
  int row, col;
960
0
  int complexParBands;
961
0
  complexParBands = self->numParameterBands;
962
963
  /*
964
    buffer matrices M2
965
  */
966
0
  for (row = 0; row < self->numM2rows; row++) {
967
0
    for (col = 0; col < self->numVChannels; col++) {
968
0
      FDKmemcpy(self->M2RealPrev__FDK[row][col], self->M2Real__FDK[row][col],
969
0
                self->numParameterBands * sizeof(FIXP_DBL));
970
0
      if (0 || (self->phaseCoding == 3)) {
971
0
        FDKmemcpy(self->M2ImagPrev__FDK[row][col], self->M2Imag__FDK[row][col],
972
0
                  complexParBands * sizeof(FIXP_DBL));
973
0
      }
974
0
    }
975
0
  }
976
977
  /* buffer phase */
978
0
  FDKmemcpy(self->PhasePrevLeft__FDK, self->PhaseLeft__FDK,
979
0
            self->numParameterBands * sizeof(FIXP_DBL));
980
0
  FDKmemcpy(self->PhasePrevRight__FDK, self->PhaseRight__FDK,
981
0
            self->numParameterBands * sizeof(FIXP_DBL));
982
0
}
983
984
0
#define PHASE_SCALE 2
985
986
#ifndef P_PI
987
#define P_PI 3.1415926535897932
988
#endif
989
990
/* For better precision, PI (pi_x2) is already doubled */
991
static FIXP_DBL interp_angle__FDK(FIXP_DBL angle1, FIXP_DBL angle2,
992
0
                                  FIXP_SGL alpha, FIXP_DBL pi_x2) {
993
0
  if (angle2 - angle1 > (pi_x2 >> 1)) angle2 -= pi_x2;
994
995
0
  if (angle1 - angle2 > (pi_x2 >> 1)) angle1 -= pi_x2;
996
997
0
  return interpolateParameter(alpha, angle2, angle1);
998
0
}
999
1000
/*
1001
 *
1002
 */
1003
void SpatialDecApplyPhase(spatialDec *self, FIXP_SGL alpha__FDK,
1004
0
                          int lastSlotOfParamSet) {
1005
0
  int pb, qs;
1006
0
  FIXP_DBL ppb[MAX_PARAMETER_BANDS *
1007
0
               4]; /* left real, imag - right real, imag interleaved */
1008
1009
0
  const FIXP_DBL pi_x2 = PIx2__IPD;
1010
0
  for (pb = 0; pb < self->numParameterBands; pb++) {
1011
0
    FIXP_DBL pl, pr;
1012
1013
0
    pl = interp_angle__FDK(self->PhasePrevLeft__FDK[pb],
1014
0
                           self->PhaseLeft__FDK[pb], alpha__FDK, pi_x2);
1015
0
    pr = interp_angle__FDK(self->PhasePrevRight__FDK[pb],
1016
0
                           self->PhaseRight__FDK[pb], alpha__FDK, pi_x2);
1017
1018
0
    inline_fixp_cos_sin(pl, pr, IPD_SCALE, &ppb[4 * pb]);
1019
0
  }
1020
1021
  /* sign is -1 for qs = 0,2 and +1 for qs = 1 */
1022
1023
0
  const SCHAR *kernels = &self->kernels[0];
1024
1025
0
  FIXP_DBL *Dry_real0 = &self->hybOutputRealDry__FDK[0][0];
1026
0
  FIXP_DBL *Dry_imag0 = &self->hybOutputImagDry__FDK[0][0];
1027
0
  FIXP_DBL *Dry_real1 = &self->hybOutputRealDry__FDK[1][0];
1028
0
  FIXP_DBL *Dry_imag1 = &self->hybOutputImagDry__FDK[1][0];
1029
1030
0
  for (qs = 2; qs >= 0; qs--) {
1031
0
    FIXP_DBL out_re, out_im;
1032
1033
0
    pb = *kernels++;
1034
0
    if (qs == 1) /* sign[qs] >= 0 */
1035
0
    {
1036
0
      cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0],
1037
0
                   ppb[4 * pb + 1]);
1038
0
      out_re <<= PHASE_SCALE - 1;
1039
0
      out_im <<= PHASE_SCALE - 1;
1040
0
      *Dry_real0++ = out_re;
1041
0
      *Dry_imag0++ = out_im;
1042
1043
0
      cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2],
1044
0
                   ppb[4 * pb + 3]);
1045
0
      out_re <<= PHASE_SCALE - 1;
1046
0
      out_im <<= PHASE_SCALE - 1;
1047
0
      *Dry_real1++ = out_re;
1048
0
      *Dry_imag1++ = out_im;
1049
0
    } else {
1050
0
      cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0],
1051
0
                   -ppb[4 * pb + 1]);
1052
0
      out_re <<= PHASE_SCALE - 1;
1053
0
      out_im <<= PHASE_SCALE - 1;
1054
0
      *Dry_real0++ = out_re;
1055
0
      *Dry_imag0++ = out_im;
1056
1057
0
      cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2],
1058
0
                   -ppb[4 * pb + 3]);
1059
0
      out_re <<= PHASE_SCALE - 1;
1060
0
      out_im <<= PHASE_SCALE - 1;
1061
0
      *Dry_real1++ = out_re;
1062
0
      *Dry_imag1++ = out_im;
1063
0
    }
1064
0
  }
1065
1066
  /* sign is +1 for qs >=3 */
1067
0
  for (qs = self->hybridBands - 3; qs--;) {
1068
0
    FIXP_DBL out_re, out_im;
1069
1070
0
    pb = *kernels++;
1071
0
    cplxMultDiv2(&out_re, &out_im, *Dry_real0, *Dry_imag0, ppb[4 * pb + 0],
1072
0
                 ppb[4 * pb + 1]);
1073
0
    out_re <<= PHASE_SCALE - 1;
1074
0
    out_im <<= PHASE_SCALE - 1;
1075
0
    *Dry_real0++ = out_re;
1076
0
    *Dry_imag0++ = out_im;
1077
1078
0
    cplxMultDiv2(&out_re, &out_im, *Dry_real1, *Dry_imag1, ppb[4 * pb + 2],
1079
0
                 ppb[4 * pb + 3]);
1080
0
    out_re <<= PHASE_SCALE - 1;
1081
0
    out_im <<= PHASE_SCALE - 1;
1082
0
    *Dry_real1++ = out_re;
1083
0
    *Dry_imag1++ = out_im;
1084
0
  }
1085
0
}