/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 | } |