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