/src/aac/libAACenc/src/psy_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 | | /**************************** AAC encoder library ****************************** |
96 | | |
97 | | Author(s): M.Werner |
98 | | |
99 | | Description: Psychoaccoustic major function block |
100 | | |
101 | | *******************************************************************************/ |
102 | | |
103 | | #include "psy_const.h" |
104 | | |
105 | | #include "block_switch.h" |
106 | | #include "transform.h" |
107 | | #include "spreading.h" |
108 | | #include "pre_echo_control.h" |
109 | | #include "band_nrg.h" |
110 | | #include "psy_configuration.h" |
111 | | #include "psy_data.h" |
112 | | #include "ms_stereo.h" |
113 | | #include "interface.h" |
114 | | #include "psy_main.h" |
115 | | #include "grp_data.h" |
116 | | #include "tns_func.h" |
117 | | #include "pns_func.h" |
118 | | #include "tonality.h" |
119 | | #include "aacEnc_ram.h" |
120 | | #include "intensity.h" |
121 | | |
122 | | /* blending to reduce gibbs artifacts */ |
123 | 0 | #define FADE_OUT_LEN 6 |
124 | | static const FIXP_DBL fadeOutFactor[FADE_OUT_LEN] = { |
125 | | 1840644096, 1533870080, 1227096064, 920322048, 613548032, 306774016}; |
126 | | |
127 | | /* forward definitions */ |
128 | | |
129 | | /***************************************************************************** |
130 | | |
131 | | functionname: FDKaacEnc_PsyNew |
132 | | description: allocates memory for psychoacoustic |
133 | | returns: an error code |
134 | | input: pointer to a psych handle |
135 | | |
136 | | *****************************************************************************/ |
137 | | AAC_ENCODER_ERROR FDKaacEnc_PsyNew(PSY_INTERNAL **phpsy, const INT nElements, |
138 | 0 | const INT nChannels, UCHAR *dynamic_RAM) { |
139 | 0 | AAC_ENCODER_ERROR ErrorStatus; |
140 | 0 | PSY_INTERNAL *hPsy; |
141 | 0 | INT i; |
142 | |
|
143 | 0 | hPsy = GetRam_aacEnc_PsyInternal(); |
144 | 0 | *phpsy = hPsy; |
145 | 0 | if (hPsy == NULL) { |
146 | 0 | ErrorStatus = AAC_ENC_NO_MEMORY; |
147 | 0 | goto bail; |
148 | 0 | } |
149 | | |
150 | 0 | for (i = 0; i < nElements; i++) { |
151 | | /* PSY_ELEMENT */ |
152 | 0 | hPsy->psyElement[i] = GetRam_aacEnc_PsyElement(i); |
153 | 0 | if (hPsy->psyElement[i] == NULL) { |
154 | 0 | ErrorStatus = AAC_ENC_NO_MEMORY; |
155 | 0 | goto bail; |
156 | 0 | } |
157 | 0 | } |
158 | | |
159 | 0 | for (i = 0; i < nChannels; i++) { |
160 | | /* PSY_STATIC */ |
161 | 0 | hPsy->pStaticChannels[i] = GetRam_aacEnc_PsyStatic(i); |
162 | 0 | if (hPsy->pStaticChannels[i] == NULL) { |
163 | 0 | ErrorStatus = AAC_ENC_NO_MEMORY; |
164 | 0 | goto bail; |
165 | 0 | } |
166 | | /* AUDIO INPUT BUFFER */ |
167 | 0 | hPsy->pStaticChannels[i]->psyInputBuffer = GetRam_aacEnc_PsyInputBuffer(i); |
168 | 0 | if (hPsy->pStaticChannels[i]->psyInputBuffer == NULL) { |
169 | 0 | ErrorStatus = AAC_ENC_NO_MEMORY; |
170 | 0 | goto bail; |
171 | 0 | } |
172 | 0 | } |
173 | | |
174 | | /* reusable psych memory */ |
175 | 0 | hPsy->psyDynamic = GetRam_aacEnc_PsyDynamic(0, dynamic_RAM); |
176 | |
|
177 | 0 | return AAC_ENC_OK; |
178 | | |
179 | 0 | bail: |
180 | 0 | FDKaacEnc_PsyClose(phpsy, NULL); |
181 | |
|
182 | 0 | return ErrorStatus; |
183 | 0 | } |
184 | | |
185 | | /***************************************************************************** |
186 | | |
187 | | functionname: FDKaacEnc_PsyOutNew |
188 | | description: allocates memory for psyOut struc |
189 | | returns: an error code |
190 | | input: pointer to a psych handle |
191 | | |
192 | | *****************************************************************************/ |
193 | | AAC_ENCODER_ERROR FDKaacEnc_PsyOutNew(PSY_OUT **phpsyOut, const INT nElements, |
194 | | const INT nChannels, const INT nSubFrames, |
195 | 0 | UCHAR *dynamic_RAM) { |
196 | 0 | AAC_ENCODER_ERROR ErrorStatus; |
197 | 0 | int n, i; |
198 | 0 | int elInc = 0, chInc = 0; |
199 | |
|
200 | 0 | for (n = 0; n < nSubFrames; n++) { |
201 | 0 | phpsyOut[n] = GetRam_aacEnc_PsyOut(n); |
202 | |
|
203 | 0 | if (phpsyOut[n] == NULL) { |
204 | 0 | ErrorStatus = AAC_ENC_NO_MEMORY; |
205 | 0 | goto bail; |
206 | 0 | } |
207 | | |
208 | 0 | for (i = 0; i < nChannels; i++) { |
209 | 0 | phpsyOut[n]->pPsyOutChannels[i] = GetRam_aacEnc_PsyOutChannel(chInc++); |
210 | 0 | if (NULL == phpsyOut[n]->pPsyOutChannels[i]) { |
211 | 0 | ErrorStatus = AAC_ENC_NO_MEMORY; |
212 | 0 | goto bail; |
213 | 0 | } |
214 | 0 | } |
215 | | |
216 | 0 | for (i = 0; i < nElements; i++) { |
217 | 0 | phpsyOut[n]->psyOutElement[i] = GetRam_aacEnc_PsyOutElements(elInc++); |
218 | 0 | if (phpsyOut[n]->psyOutElement[i] == NULL) { |
219 | 0 | ErrorStatus = AAC_ENC_NO_MEMORY; |
220 | 0 | goto bail; |
221 | 0 | } |
222 | 0 | } |
223 | 0 | } /* nSubFrames */ |
224 | | |
225 | 0 | return AAC_ENC_OK; |
226 | | |
227 | 0 | bail: |
228 | 0 | FDKaacEnc_PsyClose(NULL, phpsyOut); |
229 | 0 | return ErrorStatus; |
230 | 0 | } |
231 | | |
232 | | AAC_ENCODER_ERROR FDKaacEnc_psyInitStates(PSY_INTERNAL *hPsy, |
233 | | PSY_STATIC *psyStatic, |
234 | 0 | AUDIO_OBJECT_TYPE audioObjectType) { |
235 | | /* init input buffer */ |
236 | 0 | FDKmemclear(psyStatic->psyInputBuffer, |
237 | 0 | MAX_INPUT_BUFFER_SIZE * sizeof(INT_PCM)); |
238 | |
|
239 | 0 | FDKaacEnc_InitBlockSwitching(&psyStatic->blockSwitchingControl, |
240 | 0 | isLowDelay(audioObjectType)); |
241 | |
|
242 | 0 | return AAC_ENC_OK; |
243 | 0 | } |
244 | | |
245 | | AAC_ENCODER_ERROR FDKaacEnc_psyInit(PSY_INTERNAL *hPsy, PSY_OUT **phpsyOut, |
246 | | const INT nSubFrames, |
247 | | const INT nMaxChannels, |
248 | | const AUDIO_OBJECT_TYPE audioObjectType, |
249 | 0 | CHANNEL_MAPPING *cm) { |
250 | 0 | AAC_ENCODER_ERROR ErrorStatus = AAC_ENC_OK; |
251 | 0 | int i, ch, n, chInc = 0, resetChannels = 3; |
252 | |
|
253 | 0 | if ((nMaxChannels > 2) && (cm->nChannels == 2)) { |
254 | 0 | chInc = 1; |
255 | 0 | FDKaacEnc_psyInitStates(hPsy, hPsy->pStaticChannels[0], audioObjectType); |
256 | 0 | } |
257 | |
|
258 | 0 | if ((nMaxChannels == 2)) { |
259 | 0 | resetChannels = 0; |
260 | 0 | } |
261 | |
|
262 | 0 | for (i = 0; i < cm->nElements; i++) { |
263 | 0 | for (ch = 0; ch < cm->elInfo[i].nChannelsInEl; ch++) { |
264 | 0 | hPsy->psyElement[i]->psyStatic[ch] = hPsy->pStaticChannels[chInc]; |
265 | 0 | if (cm->elInfo[i].elType != ID_LFE) { |
266 | 0 | if (chInc >= resetChannels) { |
267 | 0 | FDKaacEnc_psyInitStates(hPsy, hPsy->psyElement[i]->psyStatic[ch], |
268 | 0 | audioObjectType); |
269 | 0 | } |
270 | 0 | mdct_init(&(hPsy->psyElement[i]->psyStatic[ch]->mdctPers), NULL, 0); |
271 | 0 | hPsy->psyElement[i]->psyStatic[ch]->isLFE = 0; |
272 | 0 | } else { |
273 | 0 | hPsy->psyElement[i]->psyStatic[ch]->isLFE = 1; |
274 | 0 | } |
275 | 0 | chInc++; |
276 | 0 | } |
277 | 0 | } |
278 | |
|
279 | 0 | for (n = 0; n < nSubFrames; n++) { |
280 | 0 | chInc = 0; |
281 | 0 | for (i = 0; i < cm->nElements; i++) { |
282 | 0 | for (ch = 0; ch < cm->elInfo[i].nChannelsInEl; ch++) { |
283 | 0 | phpsyOut[n]->psyOutElement[i]->psyOutChannel[ch] = |
284 | 0 | phpsyOut[n]->pPsyOutChannels[chInc++]; |
285 | 0 | } |
286 | 0 | } |
287 | 0 | } |
288 | |
|
289 | 0 | return ErrorStatus; |
290 | 0 | } |
291 | | |
292 | | /***************************************************************************** |
293 | | |
294 | | functionname: FDKaacEnc_psyMainInit |
295 | | description: initializes psychoacoustic |
296 | | returns: an error code |
297 | | |
298 | | *****************************************************************************/ |
299 | | |
300 | | AAC_ENCODER_ERROR FDKaacEnc_psyMainInit( |
301 | | PSY_INTERNAL *hPsy, AUDIO_OBJECT_TYPE audioObjectType, CHANNEL_MAPPING *cm, |
302 | | INT sampleRate, INT granuleLength, INT bitRate, INT tnsMask, INT bandwidth, |
303 | 0 | INT usePns, INT useIS, INT useMS, UINT syntaxFlags, ULONG initFlags) { |
304 | 0 | AAC_ENCODER_ERROR ErrorStatus; |
305 | 0 | int i, ch; |
306 | 0 | int channelsEff = cm->nChannelsEff; |
307 | 0 | int tnsChannels = 0; |
308 | 0 | FB_TYPE filterBank; |
309 | |
|
310 | 0 | switch (FDKaacEnc_GetMonoStereoMode(cm->encMode)) { |
311 | | /* ... and map to tnsChannels */ |
312 | 0 | case EL_MODE_MONO: |
313 | 0 | tnsChannels = 1; |
314 | 0 | break; |
315 | 0 | case EL_MODE_STEREO: |
316 | 0 | tnsChannels = 2; |
317 | 0 | break; |
318 | 0 | default: |
319 | 0 | tnsChannels = 0; |
320 | 0 | } |
321 | | |
322 | 0 | switch (audioObjectType) { |
323 | 0 | default: |
324 | 0 | filterBank = FB_LC; |
325 | 0 | break; |
326 | 0 | case AOT_ER_AAC_LD: |
327 | 0 | filterBank = FB_LD; |
328 | 0 | break; |
329 | 0 | case AOT_ER_AAC_ELD: |
330 | 0 | filterBank = FB_ELD; |
331 | 0 | break; |
332 | 0 | } |
333 | | |
334 | 0 | hPsy->granuleLength = granuleLength; |
335 | |
|
336 | 0 | ErrorStatus = FDKaacEnc_InitPsyConfiguration( |
337 | 0 | bitRate / channelsEff, sampleRate, bandwidth, LONG_WINDOW, |
338 | 0 | hPsy->granuleLength, useIS, useMS, &(hPsy->psyConf[0]), filterBank); |
339 | 0 | if (ErrorStatus != AAC_ENC_OK) return ErrorStatus; |
340 | | |
341 | 0 | ErrorStatus = FDKaacEnc_InitTnsConfiguration( |
342 | 0 | (bitRate * tnsChannels) / channelsEff, sampleRate, tnsChannels, |
343 | 0 | LONG_WINDOW, hPsy->granuleLength, isLowDelay(audioObjectType), |
344 | 0 | (syntaxFlags & AC_SBR_PRESENT) ? 1 : 0, &(hPsy->psyConf[0].tnsConf), |
345 | 0 | &hPsy->psyConf[0], (INT)(tnsMask & 2), (INT)(tnsMask & 8)); |
346 | |
|
347 | 0 | if (ErrorStatus != AAC_ENC_OK) return ErrorStatus; |
348 | | |
349 | 0 | if (granuleLength > 512) { |
350 | 0 | ErrorStatus = FDKaacEnc_InitPsyConfiguration( |
351 | 0 | bitRate / channelsEff, sampleRate, bandwidth, SHORT_WINDOW, |
352 | 0 | hPsy->granuleLength, useIS, useMS, &hPsy->psyConf[1], filterBank); |
353 | |
|
354 | 0 | if (ErrorStatus != AAC_ENC_OK) return ErrorStatus; |
355 | | |
356 | 0 | ErrorStatus = FDKaacEnc_InitTnsConfiguration( |
357 | 0 | (bitRate * tnsChannels) / channelsEff, sampleRate, tnsChannels, |
358 | 0 | SHORT_WINDOW, hPsy->granuleLength, isLowDelay(audioObjectType), |
359 | 0 | (syntaxFlags & AC_SBR_PRESENT) ? 1 : 0, &hPsy->psyConf[1].tnsConf, |
360 | 0 | &hPsy->psyConf[1], (INT)(tnsMask & 1), (INT)(tnsMask & 4)); |
361 | |
|
362 | 0 | if (ErrorStatus != AAC_ENC_OK) return ErrorStatus; |
363 | 0 | } |
364 | | |
365 | 0 | for (i = 0; i < cm->nElements; i++) { |
366 | 0 | for (ch = 0; ch < cm->elInfo[i].nChannelsInEl; ch++) { |
367 | 0 | if (initFlags) { |
368 | | /* reset states */ |
369 | 0 | FDKaacEnc_psyInitStates(hPsy, hPsy->psyElement[i]->psyStatic[ch], |
370 | 0 | audioObjectType); |
371 | 0 | } |
372 | |
|
373 | 0 | FDKaacEnc_InitPreEchoControl( |
374 | 0 | hPsy->psyElement[i]->psyStatic[ch]->sfbThresholdnm1, |
375 | 0 | &hPsy->psyElement[i]->psyStatic[ch]->calcPreEcho, |
376 | 0 | hPsy->psyConf[0].sfbCnt, hPsy->psyConf[0].sfbPcmQuantThreshold, |
377 | 0 | &hPsy->psyElement[i]->psyStatic[ch]->mdctScalenm1); |
378 | 0 | } |
379 | 0 | } |
380 | |
|
381 | 0 | ErrorStatus = FDKaacEnc_InitPnsConfiguration( |
382 | 0 | &hPsy->psyConf[0].pnsConf, bitRate / channelsEff, sampleRate, usePns, |
383 | 0 | hPsy->psyConf[0].sfbCnt, hPsy->psyConf[0].sfbOffset, |
384 | 0 | cm->elInfo[0].nChannelsInEl, (hPsy->psyConf[0].filterbank == FB_LC)); |
385 | 0 | if (ErrorStatus != AAC_ENC_OK) return ErrorStatus; |
386 | | |
387 | 0 | if (granuleLength > 512) { |
388 | 0 | ErrorStatus = FDKaacEnc_InitPnsConfiguration( |
389 | 0 | &hPsy->psyConf[1].pnsConf, bitRate / channelsEff, sampleRate, usePns, |
390 | 0 | hPsy->psyConf[1].sfbCnt, hPsy->psyConf[1].sfbOffset, |
391 | 0 | cm->elInfo[1].nChannelsInEl, (hPsy->psyConf[1].filterbank == FB_LC)); |
392 | 0 | if (ErrorStatus != AAC_ENC_OK) return ErrorStatus; |
393 | 0 | } |
394 | | |
395 | 0 | return ErrorStatus; |
396 | 0 | } |
397 | | |
398 | | /***************************************************************************** |
399 | | |
400 | | functionname: FDKaacEnc_psyMain |
401 | | description: psychoacoustic |
402 | | returns: an error code |
403 | | |
404 | | This function assumes that enough input data is in the modulo buffer. |
405 | | |
406 | | *****************************************************************************/ |
407 | | AAC_ENCODER_ERROR FDKaacEnc_psyMain(INT channels, PSY_ELEMENT *psyElement, |
408 | | PSY_DYNAMIC *psyDynamic, |
409 | | PSY_CONFIGURATION *psyConf, |
410 | | PSY_OUT_ELEMENT *RESTRICT psyOutElement, |
411 | | INT_PCM *pInput, const UINT inputBufSize, |
412 | 0 | INT *chIdx, INT totalChannels) { |
413 | 0 | const INT commonWindow = 1; |
414 | 0 | INT maxSfbPerGroup[(2)]; |
415 | 0 | INT mdctSpectrum_e; |
416 | 0 | INT ch; /* counts through channels */ |
417 | 0 | INT w; /* counts through windows */ |
418 | 0 | INT sfb; /* counts through scalefactor bands */ |
419 | 0 | INT line; /* counts through lines */ |
420 | |
|
421 | 0 | PSY_CONFIGURATION *RESTRICT hPsyConfLong = &psyConf[0]; |
422 | 0 | PSY_CONFIGURATION *RESTRICT hPsyConfShort = &psyConf[1]; |
423 | 0 | PSY_OUT_CHANNEL **RESTRICT psyOutChannel = psyOutElement->psyOutChannel; |
424 | 0 | FIXP_SGL sfbTonality[(2)][MAX_SFB_LONG]; |
425 | |
|
426 | 0 | PSY_STATIC **RESTRICT psyStatic = psyElement->psyStatic; |
427 | |
|
428 | 0 | PSY_DATA *RESTRICT psyData[(2)]; |
429 | 0 | TNS_DATA *RESTRICT tnsData[(2)]; |
430 | 0 | PNS_DATA *RESTRICT pnsData[(2)]; |
431 | |
|
432 | 0 | INT zeroSpec = TRUE; /* means all spectral lines are zero */ |
433 | |
|
434 | 0 | INT blockSwitchingOffset; |
435 | |
|
436 | 0 | PSY_CONFIGURATION *RESTRICT hThisPsyConf[(2)]; |
437 | 0 | INT windowLength[(2)]; |
438 | 0 | INT nWindows[(2)]; |
439 | 0 | INT wOffset; |
440 | |
|
441 | 0 | INT maxSfb[(2)]; |
442 | 0 | INT *pSfbMaxScaleSpec[(2)]; |
443 | 0 | FIXP_DBL *pSfbEnergy[(2)]; |
444 | 0 | FIXP_DBL *pSfbSpreadEnergy[(2)]; |
445 | 0 | FIXP_DBL *pSfbEnergyLdData[(2)]; |
446 | 0 | FIXP_DBL *pSfbEnergyMS[(2)]; |
447 | 0 | FIXP_DBL *pSfbThreshold[(2)]; |
448 | |
|
449 | 0 | INT isShortWindow[(2)]; |
450 | | |
451 | | /* number of incoming time samples to be processed */ |
452 | 0 | const INT nTimeSamples = psyConf->granuleLength; |
453 | |
|
454 | 0 | switch (hPsyConfLong->filterbank) { |
455 | 0 | case FB_LC: |
456 | 0 | blockSwitchingOffset = |
457 | 0 | nTimeSamples + (9 * nTimeSamples / (2 * TRANS_FAC)); |
458 | 0 | break; |
459 | 0 | case FB_LD: |
460 | 0 | case FB_ELD: |
461 | 0 | blockSwitchingOffset = nTimeSamples; |
462 | 0 | break; |
463 | 0 | default: |
464 | 0 | return AAC_ENC_UNSUPPORTED_FILTERBANK; |
465 | 0 | } |
466 | | |
467 | 0 | for (ch = 0; ch < channels; ch++) { |
468 | 0 | psyData[ch] = &psyDynamic->psyData[ch]; |
469 | 0 | tnsData[ch] = &psyDynamic->tnsData[ch]; |
470 | 0 | pnsData[ch] = &psyDynamic->pnsData[ch]; |
471 | |
|
472 | 0 | psyData[ch]->mdctSpectrum = psyOutChannel[ch]->mdctSpectrum; |
473 | 0 | } |
474 | | |
475 | | /* block switching */ |
476 | 0 | if (hPsyConfLong->filterbank != FB_ELD) { |
477 | 0 | int err; |
478 | |
|
479 | 0 | for (ch = 0; ch < channels; ch++) { |
480 | 0 | C_ALLOC_SCRATCH_START(pTimeSignal, INT_PCM, (1024)) |
481 | | |
482 | | /* copy input data and use for block switching */ |
483 | 0 | FDKmemcpy(pTimeSignal, pInput + chIdx[ch] * inputBufSize, |
484 | 0 | nTimeSamples * sizeof(INT_PCM)); |
485 | |
|
486 | 0 | FDKaacEnc_BlockSwitching(&psyStatic[ch]->blockSwitchingControl, |
487 | 0 | nTimeSamples, psyStatic[ch]->isLFE, pTimeSignal); |
488 | | |
489 | | /* fill up internal input buffer, to 2xframelength samples */ |
490 | 0 | FDKmemcpy(psyStatic[ch]->psyInputBuffer + blockSwitchingOffset, |
491 | 0 | pTimeSignal, |
492 | 0 | (2 * nTimeSamples - blockSwitchingOffset) * sizeof(INT_PCM)); |
493 | |
|
494 | 0 | C_ALLOC_SCRATCH_END(pTimeSignal, INT_PCM, (1024)) |
495 | 0 | } |
496 | | |
497 | | /* synch left and right block type */ |
498 | 0 | err = FDKaacEnc_SyncBlockSwitching( |
499 | 0 | &psyStatic[0]->blockSwitchingControl, |
500 | 0 | (channels > 1) ? &psyStatic[1]->blockSwitchingControl : NULL, channels, |
501 | 0 | commonWindow); |
502 | |
|
503 | 0 | if (err) { |
504 | 0 | return AAC_ENC_UNSUPPORTED_AOT; /* mixed up LC and LD */ |
505 | 0 | } |
506 | |
|
507 | 0 | } else { |
508 | 0 | for (ch = 0; ch < channels; ch++) { |
509 | | /* copy input data and use for block switching */ |
510 | 0 | FDKmemcpy(psyStatic[ch]->psyInputBuffer + blockSwitchingOffset, |
511 | 0 | pInput + chIdx[ch] * inputBufSize, |
512 | 0 | nTimeSamples * sizeof(INT_PCM)); |
513 | 0 | } |
514 | 0 | } |
515 | | |
516 | 0 | for (ch = 0; ch < channels; ch++) |
517 | 0 | isShortWindow[ch] = |
518 | 0 | (psyStatic[ch]->blockSwitchingControl.lastWindowSequence == |
519 | 0 | SHORT_WINDOW); |
520 | | |
521 | | /* set parameters according to window length */ |
522 | 0 | for (ch = 0; ch < channels; ch++) { |
523 | 0 | if (isShortWindow[ch]) { |
524 | 0 | hThisPsyConf[ch] = hPsyConfShort; |
525 | 0 | windowLength[ch] = psyConf->granuleLength / TRANS_FAC; |
526 | 0 | nWindows[ch] = TRANS_FAC; |
527 | 0 | maxSfb[ch] = MAX_SFB_SHORT; |
528 | |
|
529 | 0 | pSfbMaxScaleSpec[ch] = psyData[ch]->sfbMaxScaleSpec.Short[0]; |
530 | 0 | pSfbEnergy[ch] = psyData[ch]->sfbEnergy.Short[0]; |
531 | 0 | pSfbSpreadEnergy[ch] = psyData[ch]->sfbSpreadEnergy.Short[0]; |
532 | 0 | pSfbEnergyLdData[ch] = psyData[ch]->sfbEnergyLdData.Short[0]; |
533 | 0 | pSfbEnergyMS[ch] = psyData[ch]->sfbEnergyMS.Short[0]; |
534 | 0 | pSfbThreshold[ch] = psyData[ch]->sfbThreshold.Short[0]; |
535 | |
|
536 | 0 | } else { |
537 | 0 | hThisPsyConf[ch] = hPsyConfLong; |
538 | 0 | windowLength[ch] = psyConf->granuleLength; |
539 | 0 | nWindows[ch] = 1; |
540 | 0 | maxSfb[ch] = MAX_GROUPED_SFB; |
541 | |
|
542 | 0 | pSfbMaxScaleSpec[ch] = psyData[ch]->sfbMaxScaleSpec.Long; |
543 | 0 | pSfbEnergy[ch] = psyData[ch]->sfbEnergy.Long; |
544 | 0 | pSfbSpreadEnergy[ch] = psyData[ch]->sfbSpreadEnergy.Long; |
545 | 0 | pSfbEnergyLdData[ch] = psyData[ch]->sfbEnergyLdData.Long; |
546 | 0 | pSfbEnergyMS[ch] = psyData[ch]->sfbEnergyMS.Long; |
547 | 0 | pSfbThreshold[ch] = psyData[ch]->sfbThreshold.Long; |
548 | 0 | } |
549 | 0 | } |
550 | | |
551 | | /* Transform and get mdctScaling for all channels and windows. */ |
552 | 0 | for (ch = 0; ch < channels; ch++) { |
553 | | /* update number of active bands */ |
554 | 0 | if (psyStatic[ch]->isLFE) { |
555 | 0 | psyData[ch]->sfbActive = hThisPsyConf[ch]->sfbActiveLFE; |
556 | 0 | psyData[ch]->lowpassLine = hThisPsyConf[ch]->lowpassLineLFE; |
557 | 0 | } else { |
558 | 0 | psyData[ch]->sfbActive = hThisPsyConf[ch]->sfbActive; |
559 | 0 | psyData[ch]->lowpassLine = hThisPsyConf[ch]->lowpassLine; |
560 | 0 | } |
561 | |
|
562 | 0 | if (hThisPsyConf[ch]->filterbank == FB_ELD) { |
563 | 0 | if (FDKaacEnc_Transform_Real_Eld( |
564 | 0 | psyStatic[ch]->psyInputBuffer, psyData[ch]->mdctSpectrum, |
565 | 0 | psyStatic[ch]->blockSwitchingControl.lastWindowSequence, |
566 | 0 | psyStatic[ch]->blockSwitchingControl.windowShape, |
567 | 0 | &psyStatic[ch]->blockSwitchingControl.lastWindowShape, |
568 | 0 | nTimeSamples, &mdctSpectrum_e, hThisPsyConf[ch]->filterbank, |
569 | 0 | psyStatic[ch]->overlapAddBuffer) != 0) { |
570 | 0 | return AAC_ENC_UNSUPPORTED_FILTERBANK; |
571 | 0 | } |
572 | 0 | } else { |
573 | 0 | if (FDKaacEnc_Transform_Real( |
574 | 0 | psyStatic[ch]->psyInputBuffer, psyData[ch]->mdctSpectrum, |
575 | 0 | psyStatic[ch]->blockSwitchingControl.lastWindowSequence, |
576 | 0 | psyStatic[ch]->blockSwitchingControl.windowShape, |
577 | 0 | &psyStatic[ch]->blockSwitchingControl.lastWindowShape, |
578 | 0 | &psyStatic[ch]->mdctPers, nTimeSamples, &mdctSpectrum_e, |
579 | 0 | hThisPsyConf[ch]->filterbank) != 0) { |
580 | 0 | return AAC_ENC_UNSUPPORTED_FILTERBANK; |
581 | 0 | } |
582 | 0 | } |
583 | | |
584 | 0 | for (w = 0; w < nWindows[ch]; w++) { |
585 | 0 | wOffset = w * windowLength[ch]; |
586 | | |
587 | | /* Low pass / highest sfb */ |
588 | 0 | FDKmemclear( |
589 | 0 | &psyData[ch]->mdctSpectrum[psyData[ch]->lowpassLine + wOffset], |
590 | 0 | (windowLength[ch] - psyData[ch]->lowpassLine) * sizeof(FIXP_DBL)); |
591 | |
|
592 | 0 | if ((hPsyConfLong->filterbank != FB_LC) && |
593 | 0 | (psyData[ch]->lowpassLine >= FADE_OUT_LEN)) { |
594 | | /* Do blending to reduce gibbs artifacts */ |
595 | 0 | for (int i = 0; i < FADE_OUT_LEN; i++) { |
596 | 0 | psyData[ch]->mdctSpectrum[psyData[ch]->lowpassLine + wOffset - |
597 | 0 | FADE_OUT_LEN + i] = |
598 | 0 | fMult(psyData[ch]->mdctSpectrum[psyData[ch]->lowpassLine + |
599 | 0 | wOffset - FADE_OUT_LEN + i], |
600 | 0 | fadeOutFactor[i]); |
601 | 0 | } |
602 | 0 | } |
603 | | |
604 | | /* Check for zero spectrum. These loops will usually terminate very, very |
605 | | * early. */ |
606 | 0 | for (line = 0; (line < psyData[ch]->lowpassLine) && (zeroSpec == TRUE); |
607 | 0 | line++) { |
608 | 0 | if (psyData[ch]->mdctSpectrum[line + wOffset] != (FIXP_DBL)0) { |
609 | 0 | zeroSpec = FALSE; |
610 | 0 | break; |
611 | 0 | } |
612 | 0 | } |
613 | |
|
614 | 0 | } /* w loop */ |
615 | |
|
616 | 0 | psyData[ch]->mdctScale = mdctSpectrum_e; |
617 | | |
618 | | /* rotate internal time samples */ |
619 | 0 | FDKmemmove(psyStatic[ch]->psyInputBuffer, |
620 | 0 | psyStatic[ch]->psyInputBuffer + nTimeSamples, |
621 | 0 | nTimeSamples * sizeof(INT_PCM)); |
622 | | |
623 | | /* ... and get remaining samples from input buffer */ |
624 | 0 | FDKmemcpy(psyStatic[ch]->psyInputBuffer + nTimeSamples, |
625 | 0 | pInput + (2 * nTimeSamples - blockSwitchingOffset) + |
626 | 0 | chIdx[ch] * inputBufSize, |
627 | 0 | (blockSwitchingOffset - nTimeSamples) * sizeof(INT_PCM)); |
628 | |
|
629 | 0 | } /* ch */ |
630 | | |
631 | | /* Do some rescaling to get maximum possible accuracy for energies */ |
632 | 0 | if (zeroSpec == FALSE) { |
633 | | /* Calc possible spectrum leftshift for each sfb (1 means: 1 bit left shift |
634 | | * is possible without overflow) */ |
635 | 0 | INT minSpecShift = MAX_SHIFT_DBL; |
636 | 0 | INT nrgShift = MAX_SHIFT_DBL; |
637 | 0 | INT finalShift = MAX_SHIFT_DBL; |
638 | 0 | FIXP_DBL currNrg = 0; |
639 | 0 | FIXP_DBL maxNrg = 0; |
640 | |
|
641 | 0 | for (ch = 0; ch < channels; ch++) { |
642 | 0 | for (w = 0; w < nWindows[ch]; w++) { |
643 | 0 | wOffset = w * windowLength[ch]; |
644 | 0 | FDKaacEnc_CalcSfbMaxScaleSpec( |
645 | 0 | psyData[ch]->mdctSpectrum + wOffset, hThisPsyConf[ch]->sfbOffset, |
646 | 0 | pSfbMaxScaleSpec[ch] + w * maxSfb[ch], psyData[ch]->sfbActive); |
647 | |
|
648 | 0 | for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) |
649 | 0 | minSpecShift = fixMin(minSpecShift, |
650 | 0 | (pSfbMaxScaleSpec[ch] + w * maxSfb[ch])[sfb]); |
651 | 0 | } |
652 | 0 | } |
653 | | |
654 | | /* Calc possible energy leftshift for each sfb (1 means: 1 bit left shift is |
655 | | * possible without overflow) */ |
656 | 0 | for (ch = 0; ch < channels; ch++) { |
657 | 0 | for (w = 0; w < nWindows[ch]; w++) { |
658 | 0 | wOffset = w * windowLength[ch]; |
659 | 0 | currNrg = FDKaacEnc_CheckBandEnergyOptim( |
660 | 0 | psyData[ch]->mdctSpectrum + wOffset, |
661 | 0 | pSfbMaxScaleSpec[ch] + w * maxSfb[ch], hThisPsyConf[ch]->sfbOffset, |
662 | 0 | psyData[ch]->sfbActive, pSfbEnergy[ch] + w * maxSfb[ch], |
663 | 0 | pSfbEnergyLdData[ch] + w * maxSfb[ch], minSpecShift - 4); |
664 | |
|
665 | 0 | maxNrg = fixMax(maxNrg, currNrg); |
666 | 0 | } |
667 | 0 | } |
668 | |
|
669 | 0 | if (maxNrg != (FIXP_DBL)0) { |
670 | 0 | nrgShift = (CountLeadingBits(maxNrg) >> 1) + (minSpecShift - 4); |
671 | 0 | } |
672 | | |
673 | | /* 2check: Hasn't this decision to be made for both channels? */ |
674 | | /* For short windows 1 additional bit headroom is necessary to prevent |
675 | | * overflows when summing up energies in FDKaacEnc_groupShortData() */ |
676 | 0 | if (isShortWindow[0]) nrgShift--; |
677 | | |
678 | | /* both spectrum and energies mustn't overflow */ |
679 | 0 | finalShift = fixMin(minSpecShift, nrgShift); |
680 | | |
681 | | /* do not shift more than 3 bits more to the left than signal without |
682 | | * blockfloating point would be to avoid overflow of scaled PCM quantization |
683 | | * thresholds */ |
684 | 0 | if (finalShift > psyData[0]->mdctScale + 3) |
685 | 0 | finalShift = psyData[0]->mdctScale + 3; |
686 | |
|
687 | 0 | FDK_ASSERT(finalShift >= 0); /* right shift is not allowed */ |
688 | | |
689 | | /* correct sfbEnergy and sfbEnergyLdData with new finalShift */ |
690 | 0 | FIXP_DBL ldShift = finalShift * FL2FXCONST_DBL(2.0 / 64); |
691 | 0 | for (ch = 0; ch < channels; ch++) { |
692 | 0 | INT maxSfb_ch = maxSfb[ch]; |
693 | 0 | INT w_maxSfb_ch = 0; |
694 | 0 | for (w = 0; w < nWindows[ch]; w++) { |
695 | 0 | for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) { |
696 | 0 | INT scale = fixMax(0, (pSfbMaxScaleSpec[ch] + w_maxSfb_ch)[sfb] - 4); |
697 | 0 | scale = fixMin((scale - finalShift) << 1, DFRACT_BITS - 1); |
698 | 0 | if (scale >= 0) |
699 | 0 | (pSfbEnergy[ch] + w_maxSfb_ch)[sfb] >>= (scale); |
700 | 0 | else |
701 | 0 | (pSfbEnergy[ch] + w_maxSfb_ch)[sfb] <<= (-scale); |
702 | 0 | (pSfbThreshold[ch] + w_maxSfb_ch)[sfb] = |
703 | 0 | fMult((pSfbEnergy[ch] + w_maxSfb_ch)[sfb], C_RATIO); |
704 | 0 | (pSfbEnergyLdData[ch] + w_maxSfb_ch)[sfb] += ldShift; |
705 | 0 | } |
706 | 0 | w_maxSfb_ch += maxSfb_ch; |
707 | 0 | } |
708 | 0 | } |
709 | |
|
710 | 0 | if (finalShift != 0) { |
711 | 0 | for (ch = 0; ch < channels; ch++) { |
712 | 0 | INT wLen = windowLength[ch]; |
713 | 0 | INT lowpassLine = psyData[ch]->lowpassLine; |
714 | 0 | wOffset = 0; |
715 | 0 | FIXP_DBL *mdctSpectrum = &psyData[ch]->mdctSpectrum[0]; |
716 | 0 | for (w = 0; w < nWindows[ch]; w++) { |
717 | 0 | FIXP_DBL *spectrum = &mdctSpectrum[wOffset]; |
718 | 0 | for (line = 0; line < lowpassLine; line++) { |
719 | 0 | spectrum[line] <<= finalShift; |
720 | 0 | } |
721 | 0 | wOffset += wLen; |
722 | | |
723 | | /* update sfbMaxScaleSpec */ |
724 | 0 | for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) |
725 | 0 | (pSfbMaxScaleSpec[ch] + w * maxSfb[ch])[sfb] -= finalShift; |
726 | 0 | } |
727 | | /* update mdctScale */ |
728 | 0 | psyData[ch]->mdctScale -= finalShift; |
729 | 0 | } |
730 | 0 | } |
731 | |
|
732 | 0 | } else { |
733 | | /* all spectral lines are zero */ |
734 | 0 | for (ch = 0; ch < channels; ch++) { |
735 | 0 | psyData[ch]->mdctScale = |
736 | 0 | 0; /* otherwise mdctScale would be for example 7 and PCM quantization |
737 | | * thresholds would be shifted 14 bits to the right causing some of |
738 | | * them to become 0 (which causes problems later) */ |
739 | | /* clear sfbMaxScaleSpec */ |
740 | 0 | for (w = 0; w < nWindows[ch]; w++) { |
741 | 0 | for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) { |
742 | 0 | (pSfbMaxScaleSpec[ch] + w * maxSfb[ch])[sfb] = 0; |
743 | 0 | (pSfbEnergy[ch] + w * maxSfb[ch])[sfb] = (FIXP_DBL)0; |
744 | 0 | (pSfbEnergyLdData[ch] + w * maxSfb[ch])[sfb] = FL2FXCONST_DBL(-1.0f); |
745 | 0 | (pSfbThreshold[ch] + w * maxSfb[ch])[sfb] = (FIXP_DBL)0; |
746 | 0 | } |
747 | 0 | } |
748 | 0 | } |
749 | 0 | } |
750 | | |
751 | | /* Advance psychoacoustics: Tonality and TNS */ |
752 | 0 | if ((channels >= 1) && (psyStatic[0]->isLFE)) { |
753 | 0 | tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive[HIFILT] = 0; |
754 | 0 | tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive[LOFILT] = 0; |
755 | 0 | } else { |
756 | 0 | for (ch = 0; ch < channels; ch++) { |
757 | 0 | if (!isShortWindow[ch]) { |
758 | | /* tonality */ |
759 | 0 | FDKaacEnc_CalculateFullTonality( |
760 | 0 | psyData[ch]->mdctSpectrum, pSfbMaxScaleSpec[ch], |
761 | 0 | pSfbEnergyLdData[ch], sfbTonality[ch], psyData[ch]->sfbActive, |
762 | 0 | hThisPsyConf[ch]->sfbOffset, hThisPsyConf[ch]->pnsConf.usePns); |
763 | 0 | } |
764 | 0 | } /* ch */ |
765 | |
|
766 | 0 | if (hPsyConfLong->tnsConf.tnsActive || hPsyConfShort->tnsConf.tnsActive) { |
767 | 0 | INT tnsActive[TRANS_FAC] = {0}; |
768 | 0 | INT nrgScaling[2] = {0, 0}; |
769 | 0 | INT tnsSpecShift = 0; |
770 | |
|
771 | 0 | for (ch = 0; ch < channels; ch++) { |
772 | 0 | for (w = 0; w < nWindows[ch]; w++) { |
773 | 0 | wOffset = w * windowLength[ch]; |
774 | | /* TNS */ |
775 | 0 | FDKaacEnc_TnsDetect( |
776 | 0 | tnsData[ch], &hThisPsyConf[ch]->tnsConf, |
777 | 0 | &psyOutChannel[ch]->tnsInfo, hThisPsyConf[ch]->sfbCnt, |
778 | 0 | psyData[ch]->mdctSpectrum + wOffset, w, |
779 | 0 | psyStatic[ch]->blockSwitchingControl.lastWindowSequence); |
780 | 0 | } |
781 | 0 | } |
782 | |
|
783 | 0 | if (channels == 2) { |
784 | 0 | FDKaacEnc_TnsSync( |
785 | 0 | tnsData[1], tnsData[0], &psyOutChannel[1]->tnsInfo, |
786 | 0 | &psyOutChannel[0]->tnsInfo, |
787 | |
|
788 | 0 | psyStatic[1]->blockSwitchingControl.lastWindowSequence, |
789 | 0 | psyStatic[0]->blockSwitchingControl.lastWindowSequence, |
790 | 0 | &hThisPsyConf[1]->tnsConf); |
791 | 0 | } |
792 | |
|
793 | 0 | if (channels >= 1) { |
794 | 0 | FDK_ASSERT(1 == commonWindow); /* all checks for TNS do only work for |
795 | | common windows (which is always set)*/ |
796 | 0 | for (w = 0; w < nWindows[0]; w++) { |
797 | 0 | if (isShortWindow[0]) |
798 | 0 | tnsActive[w] = |
799 | 0 | tnsData[0]->dataRaw.Short.subBlockInfo[w].tnsActive[HIFILT] || |
800 | 0 | tnsData[0]->dataRaw.Short.subBlockInfo[w].tnsActive[LOFILT] || |
801 | 0 | tnsData[channels - 1] |
802 | 0 | ->dataRaw.Short.subBlockInfo[w] |
803 | 0 | .tnsActive[HIFILT] || |
804 | 0 | tnsData[channels - 1] |
805 | 0 | ->dataRaw.Short.subBlockInfo[w] |
806 | 0 | .tnsActive[LOFILT]; |
807 | 0 | else |
808 | 0 | tnsActive[w] = |
809 | 0 | tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive[HIFILT] || |
810 | 0 | tnsData[0]->dataRaw.Long.subBlockInfo.tnsActive[LOFILT] || |
811 | 0 | tnsData[channels - 1] |
812 | 0 | ->dataRaw.Long.subBlockInfo.tnsActive[HIFILT] || |
813 | 0 | tnsData[channels - 1] |
814 | 0 | ->dataRaw.Long.subBlockInfo.tnsActive[LOFILT]; |
815 | 0 | } |
816 | 0 | } |
817 | | |
818 | 0 | for (ch = 0; ch < channels; ch++) { |
819 | 0 | if (tnsActive[0] && !isShortWindow[ch]) { |
820 | | /* Scale down spectrum if tns is active in one of the two channels |
821 | | * with same lastWindowSequence */ |
822 | | /* first part of threshold calculation; it's not necessary to update |
823 | | * sfbMaxScaleSpec */ |
824 | 0 | INT shift = 1; |
825 | 0 | for (sfb = 0; sfb < hThisPsyConf[ch]->lowpassLine; sfb++) { |
826 | 0 | psyData[ch]->mdctSpectrum[sfb] = |
827 | 0 | psyData[ch]->mdctSpectrum[sfb] >> shift; |
828 | 0 | } |
829 | | |
830 | | /* update thresholds */ |
831 | 0 | for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) { |
832 | 0 | pSfbThreshold[ch][sfb] >>= (2 * shift); |
833 | 0 | } |
834 | |
|
835 | 0 | psyData[ch]->mdctScale += shift; /* update mdctScale */ |
836 | | |
837 | | /* calc sfbEnergies after tnsEncode again ! */ |
838 | 0 | } |
839 | 0 | } |
840 | |
|
841 | 0 | for (ch = 0; ch < channels; ch++) { |
842 | 0 | for (w = 0; w < nWindows[ch]; w++) { |
843 | 0 | wOffset = w * windowLength[ch]; |
844 | 0 | FDKaacEnc_TnsEncode( |
845 | 0 | &psyOutChannel[ch]->tnsInfo, tnsData[ch], |
846 | 0 | hThisPsyConf[ch]->sfbCnt, &hThisPsyConf[ch]->tnsConf, |
847 | 0 | hThisPsyConf[ch]->sfbOffset[psyData[ch]->sfbActive], |
848 | | /*hThisPsyConf[ch]->lowpassLine*/ /* filter stops |
849 | | before that |
850 | | line ! */ |
851 | 0 | psyData[ch]->mdctSpectrum + |
852 | 0 | wOffset, |
853 | 0 | w, psyStatic[ch]->blockSwitchingControl.lastWindowSequence); |
854 | |
|
855 | 0 | if (tnsActive[w]) { |
856 | | /* Calc sfb-bandwise mdct-energies for left and right channel again, |
857 | | */ |
858 | | /* if tns active in current channel or in one channel with same |
859 | | * lastWindowSequence left and right */ |
860 | 0 | FDKaacEnc_CalcSfbMaxScaleSpec(psyData[ch]->mdctSpectrum + wOffset, |
861 | 0 | hThisPsyConf[ch]->sfbOffset, |
862 | 0 | pSfbMaxScaleSpec[ch] + w * maxSfb[ch], |
863 | 0 | psyData[ch]->sfbActive); |
864 | 0 | } |
865 | 0 | } |
866 | 0 | } |
867 | |
|
868 | 0 | for (ch = 0; ch < channels; ch++) { |
869 | 0 | for (w = 0; w < nWindows[ch]; w++) { |
870 | 0 | if (tnsActive[w]) { |
871 | 0 | if (isShortWindow[ch]) { |
872 | 0 | FDKaacEnc_CalcBandEnergyOptimShort( |
873 | 0 | psyData[ch]->mdctSpectrum + w * windowLength[ch], |
874 | 0 | pSfbMaxScaleSpec[ch] + w * maxSfb[ch], |
875 | 0 | hThisPsyConf[ch]->sfbOffset, psyData[ch]->sfbActive, |
876 | 0 | pSfbEnergy[ch] + w * maxSfb[ch]); |
877 | 0 | } else { |
878 | 0 | nrgScaling[ch] = /* with tns, energy calculation can overflow; -> |
879 | | scaling */ |
880 | 0 | FDKaacEnc_CalcBandEnergyOptimLong( |
881 | 0 | psyData[ch]->mdctSpectrum, pSfbMaxScaleSpec[ch], |
882 | 0 | hThisPsyConf[ch]->sfbOffset, psyData[ch]->sfbActive, |
883 | 0 | pSfbEnergy[ch], pSfbEnergyLdData[ch]); |
884 | 0 | tnsSpecShift = |
885 | 0 | fixMax(tnsSpecShift, nrgScaling[ch]); /* nrgScaling is set |
886 | | only if nrg would |
887 | | have an overflow */ |
888 | 0 | } |
889 | 0 | } /* if tnsActive */ |
890 | 0 | } |
891 | 0 | } /* end channel loop */ |
892 | | |
893 | | /* adapt scaling to prevent nrg overflow, only for long blocks */ |
894 | 0 | for (ch = 0; ch < channels; ch++) { |
895 | 0 | if ((tnsSpecShift != 0) && !isShortWindow[ch]) { |
896 | | /* scale down spectrum, nrg's and thresholds, if there was an overflow |
897 | | * in sfbNrg calculation after tns */ |
898 | 0 | for (line = 0; line < hThisPsyConf[ch]->lowpassLine; line++) { |
899 | 0 | psyData[ch]->mdctSpectrum[line] >>= tnsSpecShift; |
900 | 0 | } |
901 | 0 | INT scale = (tnsSpecShift - nrgScaling[ch]) << 1; |
902 | 0 | for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) { |
903 | 0 | pSfbEnergyLdData[ch][sfb] -= |
904 | 0 | scale * FL2FXCONST_DBL(1.0 / LD_DATA_SCALING); |
905 | 0 | pSfbEnergy[ch][sfb] >>= scale; |
906 | 0 | pSfbThreshold[ch][sfb] >>= (tnsSpecShift << 1); |
907 | 0 | } |
908 | 0 | psyData[ch]->mdctScale += tnsSpecShift; /* update mdctScale; not |
909 | | necessary to update |
910 | | sfbMaxScaleSpec */ |
911 | 0 | } |
912 | 0 | } /* end channel loop */ |
913 | |
|
914 | 0 | } /* TNS active */ |
915 | 0 | else { |
916 | | /* In case of disable TNS, reset its dynamic data. Some of its elements is |
917 | | * required in PNS detection below. */ |
918 | 0 | FDKmemclear(psyDynamic->tnsData, sizeof(psyDynamic->tnsData)); |
919 | 0 | } |
920 | 0 | } /* !isLFE */ |
921 | | |
922 | | /* Advance thresholds */ |
923 | 0 | for (ch = 0; ch < channels; ch++) { |
924 | 0 | INT headroom; |
925 | |
|
926 | 0 | FIXP_DBL clipEnergy; |
927 | 0 | INT energyShift = psyData[ch]->mdctScale * 2; |
928 | 0 | INT clipNrgShift = energyShift - THR_SHIFTBITS; |
929 | 0 | if (isShortWindow[ch]) |
930 | 0 | headroom = 6; |
931 | 0 | else |
932 | 0 | headroom = 0; |
933 | |
|
934 | 0 | if (clipNrgShift >= 0) |
935 | 0 | clipEnergy = hThisPsyConf[ch]->clipEnergy >> clipNrgShift; |
936 | 0 | else if (clipNrgShift >= -headroom) |
937 | 0 | clipEnergy = hThisPsyConf[ch]->clipEnergy << -clipNrgShift; |
938 | 0 | else |
939 | 0 | clipEnergy = (FIXP_DBL)MAXVAL_DBL; |
940 | |
|
941 | 0 | for (w = 0; w < nWindows[ch]; w++) { |
942 | 0 | INT i; |
943 | | /* limit threshold to avoid clipping */ |
944 | 0 | for (i = 0; i < psyData[ch]->sfbActive; i++) { |
945 | 0 | *(pSfbThreshold[ch] + w * maxSfb[ch] + i) = |
946 | 0 | fixMin(*(pSfbThreshold[ch] + w * maxSfb[ch] + i), clipEnergy); |
947 | 0 | } |
948 | | |
949 | | /* spreading */ |
950 | 0 | FDKaacEnc_SpreadingMax(psyData[ch]->sfbActive, |
951 | 0 | hThisPsyConf[ch]->sfbMaskLowFactor, |
952 | 0 | hThisPsyConf[ch]->sfbMaskHighFactor, |
953 | 0 | pSfbThreshold[ch] + w * maxSfb[ch]); |
954 | | |
955 | | /* PCM quantization threshold */ |
956 | 0 | energyShift += PCM_QUANT_THR_SCALE; |
957 | 0 | if (energyShift >= 0) { |
958 | 0 | energyShift = fixMin(DFRACT_BITS - 1, energyShift); |
959 | 0 | for (i = 0; i < psyData[ch]->sfbActive; i++) { |
960 | 0 | *(pSfbThreshold[ch] + w * maxSfb[ch] + i) = fixMax( |
961 | 0 | *(pSfbThreshold[ch] + w * maxSfb[ch] + i) >> THR_SHIFTBITS, |
962 | 0 | (hThisPsyConf[ch]->sfbPcmQuantThreshold[i] >> energyShift)); |
963 | 0 | } |
964 | 0 | } else { |
965 | 0 | energyShift = fixMin(DFRACT_BITS - 1, -energyShift); |
966 | 0 | for (i = 0; i < psyData[ch]->sfbActive; i++) { |
967 | 0 | *(pSfbThreshold[ch] + w * maxSfb[ch] + i) = fixMax( |
968 | 0 | *(pSfbThreshold[ch] + w * maxSfb[ch] + i) >> THR_SHIFTBITS, |
969 | 0 | (hThisPsyConf[ch]->sfbPcmQuantThreshold[i] << energyShift)); |
970 | 0 | } |
971 | 0 | } |
972 | |
|
973 | 0 | if (!psyStatic[ch]->isLFE) { |
974 | | /* preecho control */ |
975 | 0 | if (psyStatic[ch]->blockSwitchingControl.lastWindowSequence == |
976 | 0 | STOP_WINDOW) { |
977 | | /* prevent FDKaacEnc_PreEchoControl from comparing stop |
978 | | thresholds with short thresholds */ |
979 | 0 | for (i = 0; i < psyData[ch]->sfbActive; i++) { |
980 | 0 | psyStatic[ch]->sfbThresholdnm1[i] = (FIXP_DBL)MAXVAL_DBL; |
981 | 0 | } |
982 | |
|
983 | 0 | psyStatic[ch]->mdctScalenm1 = 0; |
984 | 0 | psyStatic[ch]->calcPreEcho = 0; |
985 | 0 | } |
986 | |
|
987 | 0 | FDKaacEnc_PreEchoControl( |
988 | 0 | psyStatic[ch]->sfbThresholdnm1, psyStatic[ch]->calcPreEcho, |
989 | 0 | psyData[ch]->sfbActive, hThisPsyConf[ch]->maxAllowedIncreaseFactor, |
990 | 0 | hThisPsyConf[ch]->minRemainingThresholdFactor, |
991 | 0 | pSfbThreshold[ch] + w * maxSfb[ch], psyData[ch]->mdctScale, |
992 | 0 | &psyStatic[ch]->mdctScalenm1); |
993 | |
|
994 | 0 | psyStatic[ch]->calcPreEcho = 1; |
995 | |
|
996 | 0 | if (psyStatic[ch]->blockSwitchingControl.lastWindowSequence == |
997 | 0 | START_WINDOW) { |
998 | | /* prevent FDKaacEnc_PreEchoControl in next frame to compare start |
999 | | thresholds with short thresholds */ |
1000 | 0 | for (i = 0; i < psyData[ch]->sfbActive; i++) { |
1001 | 0 | psyStatic[ch]->sfbThresholdnm1[i] = (FIXP_DBL)MAXVAL_DBL; |
1002 | 0 | } |
1003 | |
|
1004 | 0 | psyStatic[ch]->mdctScalenm1 = 0; |
1005 | 0 | psyStatic[ch]->calcPreEcho = 0; |
1006 | 0 | } |
1007 | 0 | } |
1008 | | |
1009 | | /* spread energy to avoid hole detection */ |
1010 | 0 | FDKmemcpy(pSfbSpreadEnergy[ch] + w * maxSfb[ch], |
1011 | 0 | pSfbEnergy[ch] + w * maxSfb[ch], |
1012 | 0 | psyData[ch]->sfbActive * sizeof(FIXP_DBL)); |
1013 | |
|
1014 | 0 | FDKaacEnc_SpreadingMax(psyData[ch]->sfbActive, |
1015 | 0 | hThisPsyConf[ch]->sfbMaskLowFactorSprEn, |
1016 | 0 | hThisPsyConf[ch]->sfbMaskHighFactorSprEn, |
1017 | 0 | pSfbSpreadEnergy[ch] + w * maxSfb[ch]); |
1018 | 0 | } |
1019 | 0 | } |
1020 | | |
1021 | | /* Calc bandwise energies for mid and side channel. Do it only if 2 channels |
1022 | | * exist */ |
1023 | 0 | if (channels == 2) { |
1024 | 0 | for (w = 0; w < nWindows[1]; w++) { |
1025 | 0 | wOffset = w * windowLength[1]; |
1026 | 0 | FDKaacEnc_CalcBandNrgMSOpt( |
1027 | 0 | psyData[0]->mdctSpectrum + wOffset, |
1028 | 0 | psyData[1]->mdctSpectrum + wOffset, |
1029 | 0 | pSfbMaxScaleSpec[0] + w * maxSfb[0], |
1030 | 0 | pSfbMaxScaleSpec[1] + w * maxSfb[1], hThisPsyConf[1]->sfbOffset, |
1031 | 0 | psyData[0]->sfbActive, pSfbEnergyMS[0] + w * maxSfb[0], |
1032 | 0 | pSfbEnergyMS[1] + w * maxSfb[1], |
1033 | 0 | (psyStatic[1]->blockSwitchingControl.lastWindowSequence != |
1034 | 0 | SHORT_WINDOW), |
1035 | 0 | psyData[0]->sfbEnergyMSLdData, psyData[1]->sfbEnergyMSLdData); |
1036 | 0 | } |
1037 | 0 | } |
1038 | | |
1039 | | /* group short data (maxSfb[ch] for short blocks is determined here) */ |
1040 | 0 | for (ch = 0; ch < channels; ch++) { |
1041 | 0 | if (isShortWindow[ch]) { |
1042 | 0 | int sfbGrp; |
1043 | 0 | int noSfb = psyStatic[ch]->blockSwitchingControl.noOfGroups * |
1044 | 0 | hPsyConfShort->sfbCnt; |
1045 | | /* At this point, energies and thresholds are copied/regrouped from the |
1046 | | * ".Short" to the ".Long" arrays */ |
1047 | 0 | FDKaacEnc_groupShortData( |
1048 | 0 | psyData[ch]->mdctSpectrum, &psyData[ch]->sfbThreshold, |
1049 | 0 | &psyData[ch]->sfbEnergy, &psyData[ch]->sfbEnergyMS, |
1050 | 0 | &psyData[ch]->sfbSpreadEnergy, hPsyConfShort->sfbCnt, |
1051 | 0 | psyData[ch]->sfbActive, hPsyConfShort->sfbOffset, |
1052 | 0 | hPsyConfShort->sfbMinSnrLdData, psyData[ch]->groupedSfbOffset, |
1053 | 0 | &maxSfbPerGroup[ch], psyOutChannel[ch]->sfbMinSnrLdData, |
1054 | 0 | psyStatic[ch]->blockSwitchingControl.noOfGroups, |
1055 | 0 | psyStatic[ch]->blockSwitchingControl.groupLen, |
1056 | 0 | psyConf[1].granuleLength); |
1057 | | |
1058 | | /* calculate ldData arrays (short values are in .Long-arrays after |
1059 | | * FDKaacEnc_groupShortData) */ |
1060 | 0 | for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) { |
1061 | 0 | LdDataVector(&psyData[ch]->sfbEnergy.Long[sfbGrp], |
1062 | 0 | &psyOutChannel[ch]->sfbEnergyLdData[sfbGrp], |
1063 | 0 | psyData[ch]->sfbActive); |
1064 | 0 | } |
1065 | | |
1066 | | /* calc sfbThrld and set Values smaller 2^-31 to 2^-33*/ |
1067 | 0 | for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) { |
1068 | 0 | LdDataVector(&psyData[ch]->sfbThreshold.Long[sfbGrp], |
1069 | 0 | &psyOutChannel[ch]->sfbThresholdLdData[sfbGrp], |
1070 | 0 | psyData[ch]->sfbActive); |
1071 | 0 | for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) { |
1072 | 0 | psyOutChannel[ch]->sfbThresholdLdData[sfbGrp + sfb] = |
1073 | 0 | fixMax(psyOutChannel[ch]->sfbThresholdLdData[sfbGrp + sfb], |
1074 | 0 | FL2FXCONST_DBL(-0.515625f)); |
1075 | 0 | } |
1076 | 0 | } |
1077 | |
|
1078 | 0 | if (channels == 2) { |
1079 | 0 | for (sfbGrp = 0; sfbGrp < noSfb; sfbGrp += hPsyConfShort->sfbCnt) { |
1080 | 0 | LdDataVector(&psyData[ch]->sfbEnergyMS.Long[sfbGrp], |
1081 | 0 | &psyData[ch]->sfbEnergyMSLdData[sfbGrp], |
1082 | 0 | psyData[ch]->sfbActive); |
1083 | 0 | } |
1084 | 0 | } |
1085 | |
|
1086 | 0 | FDKmemcpy(psyOutChannel[ch]->sfbOffsets, psyData[ch]->groupedSfbOffset, |
1087 | 0 | (MAX_GROUPED_SFB + 1) * sizeof(INT)); |
1088 | |
|
1089 | 0 | } else { |
1090 | 0 | int i; |
1091 | | /* maxSfb[ch] for long blocks */ |
1092 | 0 | for (sfb = psyData[ch]->sfbActive - 1; sfb >= 0; sfb--) { |
1093 | 0 | for (line = hPsyConfLong->sfbOffset[sfb + 1] - 1; |
1094 | 0 | line >= hPsyConfLong->sfbOffset[sfb]; line--) { |
1095 | 0 | if (psyData[ch]->mdctSpectrum[line] != FL2FXCONST_SGL(0.0f)) break; |
1096 | 0 | } |
1097 | 0 | if (line > hPsyConfLong->sfbOffset[sfb]) break; |
1098 | 0 | } |
1099 | 0 | maxSfbPerGroup[ch] = sfb + 1; |
1100 | 0 | maxSfbPerGroup[ch] = |
1101 | 0 | fixMax(fixMin(5, psyData[ch]->sfbActive), maxSfbPerGroup[ch]); |
1102 | | |
1103 | | /* sfbNrgLdData is calculated in FDKaacEnc_advancePsychLong, copy in |
1104 | | * psyOut structure */ |
1105 | 0 | FDKmemcpy(psyOutChannel[ch]->sfbEnergyLdData, |
1106 | 0 | psyData[ch]->sfbEnergyLdData.Long, |
1107 | 0 | psyData[ch]->sfbActive * sizeof(FIXP_DBL)); |
1108 | |
|
1109 | 0 | FDKmemcpy(psyOutChannel[ch]->sfbOffsets, hPsyConfLong->sfbOffset, |
1110 | 0 | (MAX_GROUPED_SFB + 1) * sizeof(INT)); |
1111 | | |
1112 | | /* sfbMinSnrLdData modified in adjust threshold, copy necessary */ |
1113 | 0 | FDKmemcpy(psyOutChannel[ch]->sfbMinSnrLdData, |
1114 | 0 | hPsyConfLong->sfbMinSnrLdData, |
1115 | 0 | psyData[ch]->sfbActive * sizeof(FIXP_DBL)); |
1116 | | |
1117 | | /* sfbEnergyMSLdData ist already calculated in FDKaacEnc_CalcBandNrgMSOpt; |
1118 | | * only in long case */ |
1119 | | |
1120 | | /* calc sfbThrld and set Values smaller 2^-31 to 2^-33*/ |
1121 | 0 | LdDataVector(psyData[ch]->sfbThreshold.Long, |
1122 | 0 | psyOutChannel[ch]->sfbThresholdLdData, |
1123 | 0 | psyData[ch]->sfbActive); |
1124 | 0 | for (i = 0; i < psyData[ch]->sfbActive; i++) { |
1125 | 0 | psyOutChannel[ch]->sfbThresholdLdData[i] = |
1126 | 0 | fixMax(psyOutChannel[ch]->sfbThresholdLdData[i], |
1127 | 0 | FL2FXCONST_DBL(-0.515625f)); |
1128 | 0 | } |
1129 | 0 | } |
1130 | 0 | } |
1131 | | |
1132 | | /* |
1133 | | Intensity parameter intialization. |
1134 | | */ |
1135 | 0 | for (ch = 0; ch < channels; ch++) { |
1136 | 0 | FDKmemclear(psyOutChannel[ch]->isBook, MAX_GROUPED_SFB * sizeof(INT)); |
1137 | 0 | FDKmemclear(psyOutChannel[ch]->isScale, MAX_GROUPED_SFB * sizeof(INT)); |
1138 | 0 | } |
1139 | |
|
1140 | 0 | for (ch = 0; ch < channels; ch++) { |
1141 | 0 | INT win = (isShortWindow[ch] ? 1 : 0); |
1142 | 0 | if (!psyStatic[ch]->isLFE) { |
1143 | | /* PNS Decision */ |
1144 | 0 | FDKaacEnc_PnsDetect( |
1145 | 0 | &(psyConf[0].pnsConf), pnsData[ch], |
1146 | 0 | psyStatic[ch]->blockSwitchingControl.lastWindowSequence, |
1147 | 0 | psyData[ch]->sfbActive, |
1148 | 0 | maxSfbPerGroup[ch], /* count of Sfb which are not zero. */ |
1149 | 0 | psyOutChannel[ch]->sfbThresholdLdData, psyConf[win].sfbOffset, |
1150 | 0 | psyData[ch]->mdctSpectrum, psyData[ch]->sfbMaxScaleSpec.Long, |
1151 | 0 | sfbTonality[ch], psyOutChannel[ch]->tnsInfo.order[0][0], |
1152 | 0 | tnsData[ch]->dataRaw.Long.subBlockInfo.predictionGain[HIFILT], |
1153 | 0 | tnsData[ch]->dataRaw.Long.subBlockInfo.tnsActive[HIFILT], |
1154 | 0 | psyOutChannel[ch]->sfbEnergyLdData, psyOutChannel[ch]->noiseNrg); |
1155 | 0 | } /* !isLFE */ |
1156 | 0 | } /* ch */ |
1157 | | |
1158 | | /* |
1159 | | stereo Processing |
1160 | | */ |
1161 | 0 | if (channels == 2) { |
1162 | 0 | psyOutElement->toolsInfo.msDigest = MS_NONE; |
1163 | 0 | psyOutElement->commonWindow = commonWindow; |
1164 | 0 | if (psyOutElement->commonWindow) |
1165 | 0 | maxSfbPerGroup[0] = maxSfbPerGroup[1] = |
1166 | 0 | fixMax(maxSfbPerGroup[0], maxSfbPerGroup[1]); |
1167 | 0 | if (psyStatic[0]->blockSwitchingControl.lastWindowSequence != |
1168 | 0 | SHORT_WINDOW) { |
1169 | | /* PNS preprocessing depending on ms processing: PNS not in Short Window! |
1170 | | */ |
1171 | 0 | FDKaacEnc_PreProcessPnsChannelPair( |
1172 | 0 | psyData[0]->sfbActive, (&psyData[0]->sfbEnergy)->Long, |
1173 | 0 | (&psyData[1]->sfbEnergy)->Long, psyOutChannel[0]->sfbEnergyLdData, |
1174 | 0 | psyOutChannel[1]->sfbEnergyLdData, psyData[0]->sfbEnergyMS.Long, |
1175 | 0 | &(psyConf[0].pnsConf), pnsData[0], pnsData[1]); |
1176 | |
|
1177 | 0 | FDKaacEnc_IntensityStereoProcessing( |
1178 | 0 | psyData[0]->sfbEnergy.Long, psyData[1]->sfbEnergy.Long, |
1179 | 0 | psyData[0]->mdctSpectrum, psyData[1]->mdctSpectrum, |
1180 | 0 | psyData[0]->sfbThreshold.Long, psyData[1]->sfbThreshold.Long, |
1181 | 0 | psyOutChannel[1]->sfbThresholdLdData, |
1182 | 0 | psyData[0]->sfbSpreadEnergy.Long, psyData[1]->sfbSpreadEnergy.Long, |
1183 | 0 | psyOutChannel[0]->sfbEnergyLdData, psyOutChannel[1]->sfbEnergyLdData, |
1184 | 0 | &psyOutElement->toolsInfo.msDigest, psyOutElement->toolsInfo.msMask, |
1185 | 0 | psyConf[0].sfbCnt, psyConf[0].sfbCnt, maxSfbPerGroup[0], |
1186 | 0 | psyConf[0].sfbOffset, |
1187 | 0 | psyConf[0].allowIS && psyOutElement->commonWindow, |
1188 | 0 | psyOutChannel[1]->isBook, psyOutChannel[1]->isScale, pnsData); |
1189 | |
|
1190 | 0 | FDKaacEnc_MsStereoProcessing( |
1191 | 0 | psyData, psyOutChannel, psyOutChannel[1]->isBook, |
1192 | 0 | &psyOutElement->toolsInfo.msDigest, psyOutElement->toolsInfo.msMask, |
1193 | 0 | psyConf[0].allowMS, psyData[0]->sfbActive, psyData[0]->sfbActive, |
1194 | 0 | maxSfbPerGroup[0], psyOutChannel[0]->sfbOffsets); |
1195 | | |
1196 | | /* PNS postprocessing */ |
1197 | 0 | FDKaacEnc_PostProcessPnsChannelPair( |
1198 | 0 | psyData[0]->sfbActive, &(psyConf[0].pnsConf), pnsData[0], pnsData[1], |
1199 | 0 | psyOutElement->toolsInfo.msMask, &psyOutElement->toolsInfo.msDigest); |
1200 | |
|
1201 | 0 | } else { |
1202 | 0 | FDKaacEnc_IntensityStereoProcessing( |
1203 | 0 | psyData[0]->sfbEnergy.Long, psyData[1]->sfbEnergy.Long, |
1204 | 0 | psyData[0]->mdctSpectrum, psyData[1]->mdctSpectrum, |
1205 | 0 | psyData[0]->sfbThreshold.Long, psyData[1]->sfbThreshold.Long, |
1206 | 0 | psyOutChannel[1]->sfbThresholdLdData, |
1207 | 0 | psyData[0]->sfbSpreadEnergy.Long, psyData[1]->sfbSpreadEnergy.Long, |
1208 | 0 | psyOutChannel[0]->sfbEnergyLdData, psyOutChannel[1]->sfbEnergyLdData, |
1209 | 0 | &psyOutElement->toolsInfo.msDigest, psyOutElement->toolsInfo.msMask, |
1210 | 0 | psyStatic[0]->blockSwitchingControl.noOfGroups * |
1211 | 0 | hPsyConfShort->sfbCnt, |
1212 | 0 | psyConf[1].sfbCnt, maxSfbPerGroup[0], psyData[0]->groupedSfbOffset, |
1213 | 0 | psyConf[0].allowIS && psyOutElement->commonWindow, |
1214 | 0 | psyOutChannel[1]->isBook, psyOutChannel[1]->isScale, pnsData); |
1215 | | |
1216 | | /* it's OK to pass the ".Long" arrays here. They contain grouped short |
1217 | | * data since FDKaacEnc_groupShortData() */ |
1218 | 0 | FDKaacEnc_MsStereoProcessing( |
1219 | 0 | psyData, psyOutChannel, psyOutChannel[1]->isBook, |
1220 | 0 | &psyOutElement->toolsInfo.msDigest, psyOutElement->toolsInfo.msMask, |
1221 | 0 | psyConf[1].allowMS, |
1222 | 0 | psyStatic[0]->blockSwitchingControl.noOfGroups * |
1223 | 0 | hPsyConfShort->sfbCnt, |
1224 | 0 | hPsyConfShort->sfbCnt, maxSfbPerGroup[0], |
1225 | 0 | psyOutChannel[0]->sfbOffsets); |
1226 | 0 | } |
1227 | 0 | } /* (channels == 2) */ |
1228 | | |
1229 | | /* |
1230 | | PNS Coding |
1231 | | */ |
1232 | 0 | for (ch = 0; ch < channels; ch++) { |
1233 | 0 | if (psyStatic[ch]->isLFE) { |
1234 | | /* no PNS coding */ |
1235 | 0 | for (sfb = 0; sfb < psyData[ch]->sfbActive; sfb++) { |
1236 | 0 | psyOutChannel[ch]->noiseNrg[sfb] = NO_NOISE_PNS; |
1237 | 0 | } |
1238 | 0 | } else { |
1239 | 0 | FDKaacEnc_CodePnsChannel( |
1240 | 0 | psyData[ch]->sfbActive, &(hThisPsyConf[ch]->pnsConf), |
1241 | 0 | pnsData[ch]->pnsFlag, psyData[ch]->sfbEnergyLdData.Long, |
1242 | 0 | psyOutChannel[ch]->noiseNrg, /* this is the energy that will be |
1243 | | written to the bitstream */ |
1244 | 0 | psyOutChannel[ch]->sfbThresholdLdData); |
1245 | 0 | } |
1246 | 0 | } |
1247 | | |
1248 | | /* |
1249 | | build output |
1250 | | */ |
1251 | 0 | for (ch = 0; ch < channels; ch++) { |
1252 | 0 | INT mask; |
1253 | 0 | int grp; |
1254 | 0 | psyOutChannel[ch]->maxSfbPerGroup = maxSfbPerGroup[ch]; |
1255 | 0 | psyOutChannel[ch]->mdctScale = psyData[ch]->mdctScale; |
1256 | 0 | if (isShortWindow[ch] == 0) { |
1257 | 0 | psyOutChannel[ch]->sfbCnt = hPsyConfLong->sfbActive; |
1258 | 0 | psyOutChannel[ch]->sfbPerGroup = hPsyConfLong->sfbActive; |
1259 | 0 | psyOutChannel[ch]->lastWindowSequence = |
1260 | 0 | psyStatic[ch]->blockSwitchingControl.lastWindowSequence; |
1261 | 0 | psyOutChannel[ch]->windowShape = |
1262 | 0 | psyStatic[ch]->blockSwitchingControl.windowShape; |
1263 | 0 | } else { |
1264 | 0 | INT sfbCnt = psyStatic[ch]->blockSwitchingControl.noOfGroups * |
1265 | 0 | hPsyConfShort->sfbCnt; |
1266 | |
|
1267 | 0 | psyOutChannel[ch]->sfbCnt = sfbCnt; |
1268 | 0 | psyOutChannel[ch]->sfbPerGroup = hPsyConfShort->sfbCnt; |
1269 | 0 | psyOutChannel[ch]->lastWindowSequence = SHORT_WINDOW; |
1270 | 0 | psyOutChannel[ch]->windowShape = SINE_WINDOW; |
1271 | 0 | } |
1272 | | /* generate grouping mask */ |
1273 | 0 | mask = 0; |
1274 | 0 | for (grp = 0; grp < psyStatic[ch]->blockSwitchingControl.noOfGroups; |
1275 | 0 | grp++) { |
1276 | 0 | int j; |
1277 | 0 | mask <<= 1; |
1278 | 0 | for (j = 1; j < psyStatic[ch]->blockSwitchingControl.groupLen[grp]; j++) { |
1279 | 0 | mask = (mask << 1) | 1; |
1280 | 0 | } |
1281 | 0 | } |
1282 | 0 | psyOutChannel[ch]->groupingMask = mask; |
1283 | | |
1284 | | /* build interface */ |
1285 | 0 | FDKmemcpy(psyOutChannel[ch]->groupLen, |
1286 | 0 | psyStatic[ch]->blockSwitchingControl.groupLen, |
1287 | 0 | MAX_NO_OF_GROUPS * sizeof(INT)); |
1288 | 0 | FDKmemcpy(psyOutChannel[ch]->sfbEnergy, (&psyData[ch]->sfbEnergy)->Long, |
1289 | 0 | MAX_GROUPED_SFB * sizeof(FIXP_DBL)); |
1290 | 0 | FDKmemcpy(psyOutChannel[ch]->sfbSpreadEnergy, |
1291 | 0 | (&psyData[ch]->sfbSpreadEnergy)->Long, |
1292 | 0 | MAX_GROUPED_SFB * sizeof(FIXP_DBL)); |
1293 | | // FDKmemcpy(psyOutChannel[ch]->mdctSpectrum, |
1294 | | // psyData[ch]->mdctSpectrum, (1024)*sizeof(FIXP_DBL)); |
1295 | 0 | } |
1296 | |
|
1297 | 0 | return AAC_ENC_OK; |
1298 | 0 | } |
1299 | | |
1300 | 0 | void FDKaacEnc_PsyClose(PSY_INTERNAL **phPsyInternal, PSY_OUT **phPsyOut) { |
1301 | 0 | int n, i; |
1302 | |
|
1303 | 0 | if (phPsyInternal != NULL) { |
1304 | 0 | PSY_INTERNAL *hPsyInternal = *phPsyInternal; |
1305 | |
|
1306 | 0 | if (hPsyInternal) { |
1307 | 0 | for (i = 0; i < (8); i++) { |
1308 | 0 | if (hPsyInternal->pStaticChannels[i]) { |
1309 | 0 | if (hPsyInternal->pStaticChannels[i]->psyInputBuffer) |
1310 | 0 | FreeRam_aacEnc_PsyInputBuffer( |
1311 | 0 | &hPsyInternal->pStaticChannels[i] |
1312 | 0 | ->psyInputBuffer); /* AUDIO INPUT BUFFER */ |
1313 | |
|
1314 | 0 | FreeRam_aacEnc_PsyStatic( |
1315 | 0 | &hPsyInternal->pStaticChannels[i]); /* PSY_STATIC */ |
1316 | 0 | } |
1317 | 0 | } |
1318 | |
|
1319 | 0 | for (i = 0; i < ((8)); i++) { |
1320 | 0 | if (hPsyInternal->psyElement[i]) |
1321 | 0 | FreeRam_aacEnc_PsyElement( |
1322 | 0 | &hPsyInternal->psyElement[i]); /* PSY_ELEMENT */ |
1323 | 0 | } |
1324 | |
|
1325 | 0 | FreeRam_aacEnc_PsyInternal(phPsyInternal); |
1326 | 0 | } |
1327 | 0 | } |
1328 | |
|
1329 | 0 | if (phPsyOut != NULL) { |
1330 | 0 | for (n = 0; n < (1); n++) { |
1331 | 0 | if (phPsyOut[n]) { |
1332 | 0 | for (i = 0; i < (8); i++) { |
1333 | 0 | if (phPsyOut[n]->pPsyOutChannels[i]) |
1334 | 0 | FreeRam_aacEnc_PsyOutChannel( |
1335 | 0 | &phPsyOut[n]->pPsyOutChannels[i]); /* PSY_OUT_CHANNEL */ |
1336 | 0 | } |
1337 | |
|
1338 | 0 | for (i = 0; i < ((8)); i++) { |
1339 | 0 | if (phPsyOut[n]->psyOutElement[i]) |
1340 | 0 | FreeRam_aacEnc_PsyOutElements( |
1341 | 0 | &phPsyOut[n]->psyOutElement[i]); /* PSY_OUT_ELEMENTS */ |
1342 | 0 | } |
1343 | |
|
1344 | 0 | FreeRam_aacEnc_PsyOut(&phPsyOut[n]); |
1345 | 0 | } |
1346 | 0 | } |
1347 | 0 | } |
1348 | 0 | } |