/src/aac/libSBRenc/src/ps_main.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 - 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 | | /**************************** SBR encoder library ****************************** |
96 | | |
97 | | Author(s): M. Multrus |
98 | | |
99 | | Description: PS Wrapper, Downmix |
100 | | |
101 | | *******************************************************************************/ |
102 | | |
103 | | #include "ps_main.h" |
104 | | |
105 | | /* Includes ******************************************************************/ |
106 | | #include "ps_bitenc.h" |
107 | | #include "sbrenc_ram.h" |
108 | | |
109 | | /*--------------- function declarations --------------------*/ |
110 | | static void psFindBestScaling( |
111 | | HANDLE_PARAMETRIC_STEREO hParametricStereo, |
112 | | FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], |
113 | | UCHAR *dynBandScale, FIXP_DBL *maxBandValue, SCHAR *dmxScale); |
114 | | |
115 | | /*------------- function definitions ----------------*/ |
116 | 0 | FDK_PSENC_ERROR PSEnc_Create(HANDLE_PARAMETRIC_STEREO *phParametricStereo) { |
117 | 0 | FDK_PSENC_ERROR error = PSENC_OK; |
118 | 0 | HANDLE_PARAMETRIC_STEREO hParametricStereo = NULL; |
119 | |
|
120 | 0 | if (phParametricStereo == NULL) { |
121 | 0 | error = PSENC_INVALID_HANDLE; |
122 | 0 | } else { |
123 | 0 | int i; |
124 | |
|
125 | 0 | if (NULL == (hParametricStereo = GetRam_ParamStereo())) { |
126 | 0 | error = PSENC_MEMORY_ERROR; |
127 | 0 | goto bail; |
128 | 0 | } |
129 | 0 | FDKmemclear(hParametricStereo, sizeof(PARAMETRIC_STEREO)); |
130 | |
|
131 | 0 | if (PSENC_OK != |
132 | 0 | (error = FDKsbrEnc_CreatePSEncode(&hParametricStereo->hPsEncode))) { |
133 | 0 | error = PSENC_MEMORY_ERROR; |
134 | 0 | goto bail; |
135 | 0 | } |
136 | | |
137 | 0 | for (i = 0; i < MAX_PS_CHANNELS; i++) { |
138 | 0 | if (FDKhybridAnalysisOpen( |
139 | 0 | &hParametricStereo->fdkHybAnaFilter[i], |
140 | 0 | hParametricStereo->__staticHybAnaStatesLF[i], |
141 | 0 | sizeof(hParametricStereo->__staticHybAnaStatesLF[i]), |
142 | 0 | hParametricStereo->__staticHybAnaStatesHF[i], |
143 | 0 | sizeof(hParametricStereo->__staticHybAnaStatesHF[i])) != 0) { |
144 | 0 | error = PSENC_MEMORY_ERROR; |
145 | 0 | goto bail; |
146 | 0 | } |
147 | 0 | } |
148 | 0 | } |
149 | | |
150 | 0 | bail: |
151 | 0 | if (phParametricStereo != NULL) { |
152 | 0 | *phParametricStereo = hParametricStereo; /* return allocated handle */ |
153 | 0 | } |
154 | |
|
155 | 0 | if (error != PSENC_OK) { |
156 | 0 | PSEnc_Destroy(phParametricStereo); |
157 | 0 | } |
158 | 0 | return error; |
159 | 0 | } |
160 | | |
161 | | FDK_PSENC_ERROR PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo, |
162 | | const HANDLE_PSENC_CONFIG hPsEncConfig, |
163 | 0 | INT noQmfSlots, INT noQmfBands, UCHAR *dynamic_RAM) { |
164 | 0 | FDK_PSENC_ERROR error = PSENC_OK; |
165 | |
|
166 | 0 | if ((NULL == hParametricStereo) || (NULL == hPsEncConfig)) { |
167 | 0 | error = PSENC_INVALID_HANDLE; |
168 | 0 | } else { |
169 | 0 | int ch, i; |
170 | |
|
171 | 0 | hParametricStereo->initPS = 1; |
172 | 0 | hParametricStereo->noQmfSlots = noQmfSlots; |
173 | 0 | hParametricStereo->noQmfBands = noQmfBands; |
174 | | |
175 | | /* clear delay lines */ |
176 | 0 | FDKmemclear(hParametricStereo->qmfDelayLines, |
177 | 0 | sizeof(hParametricStereo->qmfDelayLines)); |
178 | |
|
179 | 0 | hParametricStereo->qmfDelayScale = FRACT_BITS - 1; |
180 | | |
181 | | /* create configuration for hybrid filter bank */ |
182 | 0 | for (ch = 0; ch < MAX_PS_CHANNELS; ch++) { |
183 | 0 | FDKhybridAnalysisInit(&hParametricStereo->fdkHybAnaFilter[ch], |
184 | 0 | THREE_TO_TEN, 64, 64, 1); |
185 | 0 | } /* ch */ |
186 | |
|
187 | 0 | FDKhybridSynthesisInit(&hParametricStereo->fdkHybSynFilter, THREE_TO_TEN, |
188 | 0 | 64, 64); |
189 | | |
190 | | /* determine average delay */ |
191 | 0 | hParametricStereo->psDelay = |
192 | 0 | (HYBRID_FILTER_DELAY * hParametricStereo->noQmfBands); |
193 | |
|
194 | 0 | if ((hPsEncConfig->maxEnvelopes < PSENC_NENV_1) || |
195 | 0 | (hPsEncConfig->maxEnvelopes > PSENC_NENV_MAX)) { |
196 | 0 | hPsEncConfig->maxEnvelopes = PSENC_NENV_DEFAULT; |
197 | 0 | } |
198 | 0 | hParametricStereo->maxEnvelopes = hPsEncConfig->maxEnvelopes; |
199 | |
|
200 | 0 | if (PSENC_OK != |
201 | 0 | (error = FDKsbrEnc_InitPSEncode( |
202 | 0 | hParametricStereo->hPsEncode, (PS_BANDS)hPsEncConfig->nStereoBands, |
203 | 0 | hPsEncConfig->iidQuantErrorThreshold))) { |
204 | 0 | goto bail; |
205 | 0 | } |
206 | | |
207 | 0 | for (ch = 0; ch < MAX_PS_CHANNELS; ch++) { |
208 | 0 | FIXP_DBL *pDynReal = GetRam_Sbr_envRBuffer(ch, dynamic_RAM); |
209 | 0 | FIXP_DBL *pDynImag = GetRam_Sbr_envIBuffer(ch, dynamic_RAM); |
210 | |
|
211 | 0 | for (i = 0; i < HYBRID_FRAMESIZE; i++) { |
212 | 0 | hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][ch][0] = |
213 | 0 | &pDynReal[i * MAX_HYBRID_BANDS]; |
214 | 0 | hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][ch][1] = |
215 | 0 | &pDynImag[i * MAX_HYBRID_BANDS]; |
216 | 0 | ; |
217 | 0 | } |
218 | |
|
219 | 0 | for (i = 0; i < HYBRID_READ_OFFSET; i++) { |
220 | 0 | hParametricStereo->pHybridData[i][ch][0] = |
221 | 0 | hParametricStereo->__staticHybridData[i][ch][0]; |
222 | 0 | hParametricStereo->pHybridData[i][ch][1] = |
223 | 0 | hParametricStereo->__staticHybridData[i][ch][1]; |
224 | 0 | } |
225 | 0 | } /* ch */ |
226 | | |
227 | | /* clear static hybrid buffer */ |
228 | 0 | FDKmemclear(hParametricStereo->__staticHybridData, |
229 | 0 | sizeof(hParametricStereo->__staticHybridData)); |
230 | | |
231 | | /* clear bs buffer */ |
232 | 0 | FDKmemclear(hParametricStereo->psOut, sizeof(hParametricStereo->psOut)); |
233 | |
|
234 | 0 | hParametricStereo->psOut[0].enablePSHeader = |
235 | 0 | 1; /* write ps header in first frame */ |
236 | | |
237 | | /* clear scaling buffer */ |
238 | 0 | FDKmemclear(hParametricStereo->dynBandScale, sizeof(UCHAR) * PS_MAX_BANDS); |
239 | 0 | FDKmemclear(hParametricStereo->maxBandValue, |
240 | 0 | sizeof(FIXP_DBL) * PS_MAX_BANDS); |
241 | |
|
242 | 0 | } /* valid handle */ |
243 | 0 | bail: |
244 | 0 | return error; |
245 | 0 | } |
246 | | |
247 | 0 | FDK_PSENC_ERROR PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO *phParametricStereo) { |
248 | 0 | FDK_PSENC_ERROR error = PSENC_OK; |
249 | |
|
250 | 0 | if (NULL != phParametricStereo) { |
251 | 0 | HANDLE_PARAMETRIC_STEREO hParametricStereo = *phParametricStereo; |
252 | 0 | if (hParametricStereo != NULL) { |
253 | 0 | FDKsbrEnc_DestroyPSEncode(&hParametricStereo->hPsEncode); |
254 | 0 | FreeRam_ParamStereo(phParametricStereo); |
255 | 0 | } |
256 | 0 | } |
257 | |
|
258 | 0 | return error; |
259 | 0 | } |
260 | | |
261 | | static FDK_PSENC_ERROR ExtractPSParameters( |
262 | | HANDLE_PARAMETRIC_STEREO hParametricStereo, const int sendHeader, |
263 | 0 | FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2]) { |
264 | 0 | FDK_PSENC_ERROR error = PSENC_OK; |
265 | |
|
266 | 0 | if (hParametricStereo == NULL) { |
267 | 0 | error = PSENC_INVALID_HANDLE; |
268 | 0 | } else { |
269 | | /* call ps encode function */ |
270 | 0 | if (hParametricStereo->initPS) { |
271 | 0 | hParametricStereo->psOut[1] = hParametricStereo->psOut[0]; |
272 | 0 | } |
273 | 0 | hParametricStereo->psOut[0] = hParametricStereo->psOut[1]; |
274 | |
|
275 | 0 | if (PSENC_OK != |
276 | 0 | (error = FDKsbrEnc_PSEncode( |
277 | 0 | hParametricStereo->hPsEncode, &hParametricStereo->psOut[1], |
278 | 0 | hParametricStereo->dynBandScale, hParametricStereo->maxEnvelopes, |
279 | 0 | hybridData, hParametricStereo->noQmfSlots, sendHeader))) { |
280 | 0 | goto bail; |
281 | 0 | } |
282 | | |
283 | 0 | if (hParametricStereo->initPS) { |
284 | 0 | hParametricStereo->psOut[0] = hParametricStereo->psOut[1]; |
285 | 0 | hParametricStereo->initPS = 0; |
286 | 0 | } |
287 | 0 | } |
288 | 0 | bail: |
289 | 0 | return error; |
290 | 0 | } |
291 | | |
292 | | static FDK_PSENC_ERROR DownmixPSQmfData( |
293 | | HANDLE_PARAMETRIC_STEREO hParametricStereo, |
294 | | HANDLE_QMF_FILTER_BANK sbrSynthQmf, FIXP_DBL **RESTRICT mixRealQmfData, |
295 | | FIXP_DBL **RESTRICT mixImagQmfData, INT_PCM *downsampledOutSignal, |
296 | | const UINT downsampledOutSignalBufSize, |
297 | | FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], |
298 | | const INT noQmfSlots, const INT psQmfScale[MAX_PS_CHANNELS], |
299 | 0 | SCHAR *qmfScale) { |
300 | 0 | FDK_PSENC_ERROR error = PSENC_OK; |
301 | |
|
302 | 0 | if (hParametricStereo == NULL) { |
303 | 0 | error = PSENC_INVALID_HANDLE; |
304 | 0 | } else { |
305 | 0 | int n, k; |
306 | 0 | C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 2 * 64) |
307 | | |
308 | | /* define scalings */ |
309 | 0 | int dynQmfScale = fixMax( |
310 | 0 | 0, hParametricStereo->dmxScale - |
311 | 0 | 1); /* scale one bit more for addition of left and right */ |
312 | 0 | int downmixScale = psQmfScale[0] - dynQmfScale; |
313 | 0 | const FIXP_DBL maxStereoScaleFactor = MAXVAL_DBL; /* 2.f/2.f */ |
314 | |
|
315 | 0 | for (n = 0; n < noQmfSlots; n++) { |
316 | 0 | FIXP_DBL tmpHybrid[2][MAX_HYBRID_BANDS]; |
317 | |
|
318 | 0 | for (k = 0; k < 71; k++) { |
319 | 0 | int dynScale, sc; /* scaling */ |
320 | 0 | FIXP_DBL tmpLeftReal, tmpRightReal, tmpLeftImag, tmpRightImag; |
321 | 0 | FIXP_DBL tmpScaleFactor, stereoScaleFactor; |
322 | |
|
323 | 0 | tmpLeftReal = hybridData[n][0][0][k]; |
324 | 0 | tmpLeftImag = hybridData[n][0][1][k]; |
325 | 0 | tmpRightReal = hybridData[n][1][0][k]; |
326 | 0 | tmpRightImag = hybridData[n][1][1][k]; |
327 | |
|
328 | 0 | sc = fixMax( |
329 | 0 | 0, CntLeadingZeros(fixMax( |
330 | 0 | fixMax(fixp_abs(tmpLeftReal), fixp_abs(tmpLeftImag)), |
331 | 0 | fixMax(fixp_abs(tmpRightReal), fixp_abs(tmpRightImag)))) - |
332 | 0 | 2); |
333 | |
|
334 | 0 | tmpLeftReal <<= sc; |
335 | 0 | tmpLeftImag <<= sc; |
336 | 0 | tmpRightReal <<= sc; |
337 | 0 | tmpRightImag <<= sc; |
338 | 0 | dynScale = fixMin(sc - dynQmfScale, DFRACT_BITS - 1); |
339 | | |
340 | | /* calc stereo scale factor to avoid loss of energy in bands */ |
341 | | /* stereo scale factor = min(2.0f, sqrt( (abs(l(k, n)^2 + abs(r(k, n)^2 |
342 | | * )))/(0.5f*abs(l(k, n) + r(k, n))) )) */ |
343 | 0 | stereoScaleFactor = fPow2Div2(tmpLeftReal) + fPow2Div2(tmpLeftImag) + |
344 | 0 | fPow2Div2(tmpRightReal) + fPow2Div2(tmpRightImag); |
345 | | |
346 | | /* might be that tmpScaleFactor becomes negative, so fabs(.) */ |
347 | 0 | tmpScaleFactor = |
348 | 0 | fixp_abs(stereoScaleFactor + fMult(tmpLeftReal, tmpRightReal) + |
349 | 0 | fMult(tmpLeftImag, tmpRightImag)); |
350 | | |
351 | | /* min(2.0f, sqrt(stereoScaleFactor/(0.5f*tmpScaleFactor))) */ |
352 | 0 | if ((stereoScaleFactor >> 1) < |
353 | 0 | fMult(maxStereoScaleFactor, tmpScaleFactor)) { |
354 | 0 | int sc_num = CountLeadingBits(stereoScaleFactor); |
355 | 0 | int sc_denum = CountLeadingBits(tmpScaleFactor); |
356 | 0 | sc = -(sc_num - sc_denum); |
357 | |
|
358 | 0 | tmpScaleFactor = schur_div((stereoScaleFactor << (sc_num)) >> 1, |
359 | 0 | tmpScaleFactor << sc_denum, 16); |
360 | | |
361 | | /* prevent odd scaling for next sqrt calculation */ |
362 | 0 | if (sc & 0x1) { |
363 | 0 | sc++; |
364 | 0 | tmpScaleFactor >>= 1; |
365 | 0 | } |
366 | 0 | stereoScaleFactor = sqrtFixp(tmpScaleFactor); |
367 | 0 | stereoScaleFactor <<= (sc >> 1); |
368 | 0 | } else { |
369 | 0 | stereoScaleFactor = maxStereoScaleFactor; |
370 | 0 | } |
371 | | |
372 | | /* write data to hybrid output */ |
373 | 0 | tmpHybrid[0][k] = fMultDiv2(stereoScaleFactor, |
374 | 0 | (FIXP_DBL)(tmpLeftReal + tmpRightReal)) >> |
375 | 0 | dynScale; |
376 | 0 | tmpHybrid[1][k] = fMultDiv2(stereoScaleFactor, |
377 | 0 | (FIXP_DBL)(tmpLeftImag + tmpRightImag)) >> |
378 | 0 | dynScale; |
379 | |
|
380 | 0 | } /* hybrid bands - k */ |
381 | |
|
382 | 0 | FDKhybridSynthesisApply(&hParametricStereo->fdkHybSynFilter, tmpHybrid[0], |
383 | 0 | tmpHybrid[1], mixRealQmfData[n], |
384 | 0 | mixImagQmfData[n]); |
385 | |
|
386 | 0 | qmfSynthesisFilteringSlot( |
387 | 0 | sbrSynthQmf, mixRealQmfData[n], mixImagQmfData[n], downmixScale - 7, |
388 | 0 | downmixScale - 7, |
389 | 0 | downsampledOutSignal + (n * sbrSynthQmf->no_channels), 1, |
390 | 0 | pWorkBuffer); |
391 | |
|
392 | 0 | } /* slots */ |
393 | |
|
394 | 0 | *qmfScale = -downmixScale + 7; |
395 | |
|
396 | 0 | C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 2 * 64) |
397 | |
|
398 | 0 | { |
399 | 0 | const INT noQmfSlots2 = hParametricStereo->noQmfSlots >> 1; |
400 | 0 | const int noQmfBands = hParametricStereo->noQmfBands; |
401 | |
|
402 | 0 | INT scale, i, j, slotOffset; |
403 | |
|
404 | 0 | FIXP_DBL tmp[2][64]; |
405 | |
|
406 | 0 | for (i = 0; i < noQmfSlots2; i++) { |
407 | 0 | FDKmemcpy(tmp[0], hParametricStereo->qmfDelayLines[0][i], |
408 | 0 | noQmfBands * sizeof(FIXP_DBL)); |
409 | 0 | FDKmemcpy(tmp[1], hParametricStereo->qmfDelayLines[1][i], |
410 | 0 | noQmfBands * sizeof(FIXP_DBL)); |
411 | |
|
412 | 0 | FDKmemcpy(hParametricStereo->qmfDelayLines[0][i], |
413 | 0 | mixRealQmfData[i + noQmfSlots2], |
414 | 0 | noQmfBands * sizeof(FIXP_DBL)); |
415 | 0 | FDKmemcpy(hParametricStereo->qmfDelayLines[1][i], |
416 | 0 | mixImagQmfData[i + noQmfSlots2], |
417 | 0 | noQmfBands * sizeof(FIXP_DBL)); |
418 | |
|
419 | 0 | FDKmemcpy(mixRealQmfData[i + noQmfSlots2], mixRealQmfData[i], |
420 | 0 | noQmfBands * sizeof(FIXP_DBL)); |
421 | 0 | FDKmemcpy(mixImagQmfData[i + noQmfSlots2], mixImagQmfData[i], |
422 | 0 | noQmfBands * sizeof(FIXP_DBL)); |
423 | |
|
424 | 0 | FDKmemcpy(mixRealQmfData[i], tmp[0], noQmfBands * sizeof(FIXP_DBL)); |
425 | 0 | FDKmemcpy(mixImagQmfData[i], tmp[1], noQmfBands * sizeof(FIXP_DBL)); |
426 | 0 | } |
427 | |
|
428 | 0 | if (hParametricStereo->qmfDelayScale > *qmfScale) { |
429 | 0 | scale = hParametricStereo->qmfDelayScale - *qmfScale; |
430 | 0 | slotOffset = 0; |
431 | 0 | } else { |
432 | 0 | scale = *qmfScale - hParametricStereo->qmfDelayScale; |
433 | 0 | slotOffset = noQmfSlots2; |
434 | 0 | } |
435 | |
|
436 | 0 | for (i = 0; i < noQmfSlots2; i++) { |
437 | 0 | for (j = 0; j < noQmfBands; j++) { |
438 | 0 | mixRealQmfData[i + slotOffset][j] >>= scale; |
439 | 0 | mixImagQmfData[i + slotOffset][j] >>= scale; |
440 | 0 | } |
441 | 0 | } |
442 | |
|
443 | 0 | scale = *qmfScale; |
444 | 0 | *qmfScale = fMin(*qmfScale, hParametricStereo->qmfDelayScale); |
445 | 0 | hParametricStereo->qmfDelayScale = scale; |
446 | 0 | } |
447 | |
|
448 | 0 | } /* valid handle */ |
449 | |
|
450 | 0 | return error; |
451 | 0 | } |
452 | | |
453 | | INT FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo, |
454 | 0 | HANDLE_FDK_BITSTREAM hBitstream) { |
455 | 0 | return ( |
456 | 0 | (hParametricStereo != NULL) |
457 | 0 | ? FDKsbrEnc_WritePSBitstream(&hParametricStereo->psOut[0], hBitstream) |
458 | 0 | : 0); |
459 | 0 | } |
460 | | |
461 | | FDK_PSENC_ERROR FDKsbrEnc_PSEnc_ParametricStereoProcessing( |
462 | | HANDLE_PARAMETRIC_STEREO hParametricStereo, INT_PCM *samples[2], |
463 | | UINT samplesBufSize, QMF_FILTER_BANK **hQmfAnalysis, |
464 | | FIXP_DBL **RESTRICT downmixedRealQmfData, |
465 | | FIXP_DBL **RESTRICT downmixedImagQmfData, INT_PCM *downsampledOutSignal, |
466 | 0 | HANDLE_QMF_FILTER_BANK sbrSynthQmf, SCHAR *qmfScale, const int sendHeader) { |
467 | 0 | FDK_PSENC_ERROR error = PSENC_OK; |
468 | 0 | INT psQmfScale[MAX_PS_CHANNELS] = {0}; |
469 | 0 | int psCh, i; |
470 | 0 | C_AALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, 4 * 64) |
471 | |
|
472 | 0 | for (psCh = 0; psCh < MAX_PS_CHANNELS; psCh++) { |
473 | 0 | for (i = 0; i < hQmfAnalysis[psCh]->no_col; i++) { |
474 | 0 | qmfAnalysisFilteringSlot( |
475 | 0 | hQmfAnalysis[psCh], &pWorkBuffer[2 * 64], /* qmfReal[64] */ |
476 | 0 | &pWorkBuffer[3 * 64], /* qmfImag[64] */ |
477 | 0 | samples[psCh] + i * hQmfAnalysis[psCh]->no_channels, 1, |
478 | 0 | &pWorkBuffer[0 * 64] /* qmf workbuffer 2*64 */ |
479 | 0 | ); |
480 | |
|
481 | 0 | FDKhybridAnalysisApply( |
482 | 0 | &hParametricStereo->fdkHybAnaFilter[psCh], |
483 | 0 | &pWorkBuffer[2 * 64], /* qmfReal[64] */ |
484 | 0 | &pWorkBuffer[3 * 64], /* qmfImag[64] */ |
485 | 0 | hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][psCh][0], |
486 | 0 | hParametricStereo->pHybridData[i + HYBRID_READ_OFFSET][psCh][1]); |
487 | |
|
488 | 0 | } /* no_col loop i */ |
489 | |
|
490 | 0 | psQmfScale[psCh] = hQmfAnalysis[psCh]->outScalefactor; |
491 | |
|
492 | 0 | } /* for psCh */ |
493 | |
|
494 | 0 | C_AALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, 4 * 64) |
495 | | |
496 | | /* find best scaling in new QMF and Hybrid data */ |
497 | 0 | psFindBestScaling( |
498 | 0 | hParametricStereo, &hParametricStereo->pHybridData[HYBRID_READ_OFFSET], |
499 | 0 | hParametricStereo->dynBandScale, hParametricStereo->maxBandValue, |
500 | 0 | &hParametricStereo->dmxScale); |
501 | | |
502 | | /* extract the ps parameters */ |
503 | 0 | if (PSENC_OK != |
504 | 0 | (error = ExtractPSParameters(hParametricStereo, sendHeader, |
505 | 0 | &hParametricStereo->pHybridData[0]))) { |
506 | 0 | goto bail; |
507 | 0 | } |
508 | | |
509 | | /* save hybrid date for next frame */ |
510 | 0 | for (i = 0; i < HYBRID_READ_OFFSET; i++) { |
511 | 0 | FDKmemcpy( |
512 | 0 | hParametricStereo->pHybridData[i][0][0], |
513 | 0 | hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][0][0], |
514 | 0 | MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* left, real */ |
515 | 0 | FDKmemcpy( |
516 | 0 | hParametricStereo->pHybridData[i][0][1], |
517 | 0 | hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][0][1], |
518 | 0 | MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* left, imag */ |
519 | 0 | FDKmemcpy( |
520 | 0 | hParametricStereo->pHybridData[i][1][0], |
521 | 0 | hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][1][0], |
522 | 0 | MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* right, real */ |
523 | 0 | FDKmemcpy( |
524 | 0 | hParametricStereo->pHybridData[i][1][1], |
525 | 0 | hParametricStereo->pHybridData[hParametricStereo->noQmfSlots + i][1][1], |
526 | 0 | MAX_HYBRID_BANDS * sizeof(FIXP_DBL)); /* right, imag */ |
527 | 0 | } |
528 | | |
529 | | /* downmix and hybrid synthesis */ |
530 | 0 | if (PSENC_OK != |
531 | 0 | (error = DownmixPSQmfData( |
532 | 0 | hParametricStereo, sbrSynthQmf, downmixedRealQmfData, |
533 | 0 | downmixedImagQmfData, downsampledOutSignal, samplesBufSize, |
534 | 0 | &hParametricStereo->pHybridData[HYBRID_READ_OFFSET], |
535 | 0 | hParametricStereo->noQmfSlots, psQmfScale, qmfScale))) { |
536 | 0 | goto bail; |
537 | 0 | } |
538 | | |
539 | 0 | bail: |
540 | |
|
541 | 0 | return error; |
542 | 0 | } |
543 | | |
544 | | static void psFindBestScaling( |
545 | | HANDLE_PARAMETRIC_STEREO hParametricStereo, |
546 | | FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], |
547 | 0 | UCHAR *dynBandScale, FIXP_DBL *maxBandValue, SCHAR *dmxScale) { |
548 | 0 | HANDLE_PS_ENCODE hPsEncode = hParametricStereo->hPsEncode; |
549 | |
|
550 | 0 | INT group, bin, col, band; |
551 | 0 | const INT frameSize = hParametricStereo->noQmfSlots; |
552 | 0 | const INT psBands = (INT)hPsEncode->psEncMode; |
553 | 0 | const INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; |
554 | | |
555 | | /* group wise scaling */ |
556 | 0 | FIXP_DBL maxVal[2][PS_MAX_BANDS]; |
557 | 0 | FIXP_DBL maxValue = FL2FXCONST_DBL(0.f); |
558 | |
|
559 | 0 | FDKmemclear(maxVal, sizeof(maxVal)); |
560 | | |
561 | | /* start with hybrid data */ |
562 | 0 | for (group = 0; group < nIidGroups; group++) { |
563 | | /* Translate group to bin */ |
564 | 0 | bin = hPsEncode->subband2parameterIndex[group]; |
565 | | |
566 | | /* Translate from 20 bins to 10 bins */ |
567 | 0 | if (hPsEncode->psEncMode == PS_BANDS_COARSE) { |
568 | 0 | bin >>= 1; |
569 | 0 | } |
570 | | |
571 | | /* QMF downmix scaling */ |
572 | 0 | for (col = 0; col < frameSize; col++) { |
573 | 0 | int i, section = (col < frameSize - HYBRID_READ_OFFSET) ? 0 : 1; |
574 | 0 | FIXP_DBL tmp = maxVal[section][bin]; |
575 | 0 | for (i = hPsEncode->iidGroupBorders[group]; |
576 | 0 | i < hPsEncode->iidGroupBorders[group + 1]; i++) { |
577 | 0 | tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][0][0][i])); |
578 | 0 | tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][0][1][i])); |
579 | 0 | tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][1][0][i])); |
580 | 0 | tmp = fixMax(tmp, (FIXP_DBL)fixp_abs(hybridData[col][1][1][i])); |
581 | 0 | } |
582 | 0 | maxVal[section][bin] = tmp; |
583 | 0 | } |
584 | 0 | } /* nIidGroups */ |
585 | | |
586 | | /* convert maxSpec to maxScaling, find scaling space */ |
587 | 0 | for (band = 0; band < psBands; band++) { |
588 | 0 | #ifndef MULT_16x16 |
589 | 0 | dynBandScale[band] = |
590 | 0 | CountLeadingBits(fixMax(maxVal[0][band], maxBandValue[band])); |
591 | | #else |
592 | | dynBandScale[band] = fixMax( |
593 | | 0, CountLeadingBits(fixMax(maxVal[0][band], maxBandValue[band])) - |
594 | | FRACT_BITS); |
595 | | #endif |
596 | 0 | maxValue = fixMax(maxValue, fixMax(maxVal[0][band], maxVal[1][band])); |
597 | 0 | maxBandValue[band] = fixMax(maxVal[0][band], maxVal[1][band]); |
598 | 0 | } |
599 | | |
600 | | /* calculate maximal scaling for QMF downmix */ |
601 | 0 | #ifndef MULT_16x16 |
602 | 0 | *dmxScale = fixMin(DFRACT_BITS, CountLeadingBits(maxValue)); |
603 | | #else |
604 | | *dmxScale = fixMax(0, fixMin(FRACT_BITS, CountLeadingBits((maxValue)))); |
605 | | #endif |
606 | 0 | } |