2 /* -----------------------------------------------------------------------------------------------------------
3 Software License for The Fraunhofer FDK AAC Codec Library for Android
5 © Copyright 1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
9 The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
10 the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
11 This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
13 AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
14 audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
15 independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
16 of the MPEG specifications.
18 Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
19 may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
20 individually for the purpose of encoding or decoding bit streams in products that are compliant with
21 the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
22 these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
23 software may already be covered under those patent licenses when it is used for those licensed purposes only.
25 Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
26 are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
27 applications information and documentation.
31 Redistribution and use in source and binary forms, with or without modification, are permitted without
32 payment of copyright license fees provided that you satisfy the following conditions:
34 You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
35 your modifications thereto in source code form.
37 You must retain the complete text of this software license in the documentation and/or other materials
38 provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
39 You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
40 modifications thereto to recipients of copies in binary form.
42 The name of Fraunhofer may not be used to endorse or promote products derived from this library without
43 prior written permission.
45 You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
46 software or your modifications thereto.
48 Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
49 and the date of any change. For modified versions of the FDK AAC Codec, the term
50 "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
51 "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
55 NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
56 ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
57 respect to this software.
59 You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
60 by appropriate patent licenses.
64 This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
65 "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
66 of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
67 CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
68 including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
69 or business interruption, however caused and on any theory of liability, whether in contract, strict
70 liability, or tort (including negligence), arising in any way out of the use of this software, even if
71 advised of the possibility of such damage.
73 5. CONTACT INFORMATION
75 Fraunhofer Institute for Integrated Circuits IIS
76 Attention: Audio and Multimedia Departments - FDK AAC LL
78 91058 Erlangen, Germany
80 www.iis.fraunhofer.de/amm
81 amm-info@iis.fraunhofer.de
82 ----------------------------------------------------------------------------------------------------------- */
84 /******************************** MPEG Audio Encoder **************************
86 Initial author: M.Werner
87 contents/description: Psychoaccoustic major function block
89 ******************************************************************************/
91 #include "psy_const.h"
93 #include "block_switch.h"
94 #include "transform.h"
95 #include "spreading.h"
96 #include "pre_echo_control.h"
98 #include "psy_configuration.h"
100 #include "ms_stereo.h"
101 #include "interface.h"
102 #include "psy_main.h"
103 #include "grp_data.h"
104 #include "tns_func.h"
105 #include "pns_func.h"
106 #include "tonality.h"
107 #include "aacEnc_ram.h"
108 #include "intensity.h"
112 /* blending to reduce gibbs artifacts */
113 #define FADE_OUT_LEN 6
114 static const FIXP_DBL fadeOutFactor
[FADE_OUT_LEN
] = {1840644096, 1533870080, 1227096064, 920322048, 613548032, 306774016};
116 /* forward definitions */
119 /*****************************************************************************
121 functionname: FDKaacEnc_PsyNew
122 description: allocates memory for psychoacoustic
123 returns: an error code
124 input: pointer to a psych handle
126 *****************************************************************************/
127 AAC_ENCODER_ERROR
FDKaacEnc_PsyNew(PSY_INTERNAL
**phpsy
,
133 AAC_ENCODER_ERROR ErrorStatus
;
137 hPsy
= GetRam_aacEnc_PsyInternal();
140 ErrorStatus
= AAC_ENC_NO_MEMORY
;
144 for (i
=0; i
<nElements
; i
++) {
146 hPsy
->psyElement
[i
] = GetRam_aacEnc_PsyElement(i
);
147 if (hPsy
->psyElement
[i
] == NULL
) {
148 ErrorStatus
= AAC_ENC_NO_MEMORY
;
153 for (i
=0; i
<nChannels
; i
++) {
155 hPsy
->pStaticChannels
[i
] = GetRam_aacEnc_PsyStatic(i
);
156 if (hPsy
->pStaticChannels
[i
]==NULL
) {
157 ErrorStatus
= AAC_ENC_NO_MEMORY
;
160 /* AUDIO INPUT BUFFER */
161 hPsy
->pStaticChannels
[i
]->psyInputBuffer
= GetRam_aacEnc_PsyInputBuffer(i
);
162 if (hPsy
->pStaticChannels
[i
]->psyInputBuffer
==NULL
) {
163 ErrorStatus
= AAC_ENC_NO_MEMORY
;
168 /* reusable psych memory */
169 hPsy
->psyDynamic
= GetRam_aacEnc_PsyDynamic(0, dynamic_RAM
);
174 FDKaacEnc_PsyClose(phpsy
, NULL
);
179 /*****************************************************************************
181 functionname: FDKaacEnc_PsyOutNew
182 description: allocates memory for psyOut struc
183 returns: an error code
184 input: pointer to a psych handle
186 *****************************************************************************/
187 AAC_ENCODER_ERROR
FDKaacEnc_PsyOutNew(PSY_OUT
**phpsyOut
,
194 AAC_ENCODER_ERROR ErrorStatus
;
196 int elInc
= 0, chInc
= 0;
198 for (n
=0; n
<nSubFrames
; n
++) {
199 phpsyOut
[n
] = GetRam_aacEnc_PsyOut(n
);
201 if (phpsyOut
[n
] == NULL
) {
202 ErrorStatus
= AAC_ENC_NO_MEMORY
;
206 for (i
=0; i
<nChannels
; i
++) {
207 phpsyOut
[n
]->pPsyOutChannels
[i
] = GetRam_aacEnc_PsyOutChannel(chInc
++);
210 for (i
=0; i
<nElements
; i
++) {
211 phpsyOut
[n
]->psyOutElement
[i
] = GetRam_aacEnc_PsyOutElements(elInc
++);
212 if (phpsyOut
[n
]->psyOutElement
[i
] == NULL
) {
213 ErrorStatus
= AAC_ENC_NO_MEMORY
;
222 FDKaacEnc_PsyClose(NULL
, phpsyOut
);
227 AAC_ENCODER_ERROR
FDKaacEnc_psyInitStates(PSY_INTERNAL
*hPsy
,
228 PSY_STATIC
* psyStatic
,
229 AUDIO_OBJECT_TYPE audioObjectType
)
231 /* init input buffer */
232 FDKmemclear(psyStatic
->psyInputBuffer
, MAX_INPUT_BUFFER_SIZE
*sizeof(INT_PCM
));
234 FDKaacEnc_InitBlockSwitching(&psyStatic
->blockSwitchingControl
,
235 isLowDelay(audioObjectType
)
242 AAC_ENCODER_ERROR
FDKaacEnc_psyInit(PSY_INTERNAL
*hPsy
,
244 const INT nSubFrames
,
245 const INT nMaxChannels
,
246 const AUDIO_OBJECT_TYPE audioObjectType
,
249 AAC_ENCODER_ERROR ErrorStatus
= AAC_ENC_OK
;
250 int i
, ch
, n
, chInc
= 0, resetChannels
= 3;
252 if ( (nMaxChannels
>2) && (cm
->nChannels
==2) ) {
254 FDKaacEnc_psyInitStates(hPsy
, hPsy
->pStaticChannels
[0], audioObjectType
);
257 if ( (nMaxChannels
==2) ) {
261 for (i
=0; i
<cm
->nElements
; i
++) {
262 for (ch
=0; ch
<cm
->elInfo
[i
].nChannelsInEl
; ch
++) {
263 if (cm
->elInfo
[i
].elType
!=ID_LFE
) {
264 hPsy
->psyElement
[i
]->psyStatic
[ch
] = hPsy
->pStaticChannels
[chInc
];
265 if (chInc
>=resetChannels
) {
266 FDKaacEnc_psyInitStates(hPsy
, hPsy
->psyElement
[i
]->psyStatic
[ch
], audioObjectType
);
268 hPsy
->psyElement
[i
]->psyStatic
[ch
]->isLFE
= 0;
271 hPsy
->psyElement
[i
]->psyStatic
[ch
] = hPsy
->pStaticChannels
[nMaxChannels
-1];
272 hPsy
->psyElement
[i
]->psyStatic
[ch
]->isLFE
= 1;
278 for (n
=0; n
<nSubFrames
; n
++) {
280 for (i
=0; i
<cm
->nElements
; i
++) {
281 for (ch
=0; ch
<cm
->elInfo
[i
].nChannelsInEl
; ch
++) {
282 phpsyOut
[n
]->psyOutElement
[i
]->psyOutChannel
[ch
] = phpsyOut
[n
]->pPsyOutChannels
[chInc
++];
291 /*****************************************************************************
293 functionname: FDKaacEnc_psyMainInit
294 description: initializes psychoacoustic
295 returns: an error code
297 *****************************************************************************/
299 AAC_ENCODER_ERROR
FDKaacEnc_psyMainInit(PSY_INTERNAL
*hPsy
,
300 AUDIO_OBJECT_TYPE audioObjectType
,
312 AAC_ENCODER_ERROR ErrorStatus
;
314 int channelsEff
= cm
->nChannelsEff
;
319 switch(FDKaacEnc_GetMonoStereoMode(cm
->encMode
)) {
320 /* ... and map to tnsChannels */
321 case EL_MODE_MONO
: tnsChannels
= 1; break;
322 case EL_MODE_STEREO
: tnsChannels
= 2; break;
323 default: tnsChannels
= 0;
326 switch (audioObjectType
)
328 default: filterBank
= FB_LC
; break;
329 case AOT_ER_AAC_LD
: filterBank
= FB_LD
; break;
330 case AOT_ER_AAC_ELD
: filterBank
= FB_ELD
; break;
333 hPsy
->granuleLength
= granuleLength
;
335 ErrorStatus
= FDKaacEnc_InitPsyConfiguration(bitRate
/channelsEff
, sampleRate
, bandwidth
, LONG_WINDOW
, hPsy
->granuleLength
, useIS
, &(hPsy
->psyConf
[0]), filterBank
);
336 if (ErrorStatus
!= AAC_ENC_OK
)
339 ErrorStatus
= FDKaacEnc_InitTnsConfiguration(
340 (bitRate
*tnsChannels
)/channelsEff
,
345 (syntaxFlags
&AC_SBR_PRESENT
)?1:0,
346 &(hPsy
->psyConf
[0].tnsConf
),
351 if (ErrorStatus
!= AAC_ENC_OK
)
354 if (granuleLength
> 512) {
355 ErrorStatus
= FDKaacEnc_InitPsyConfiguration(bitRate
/channelsEff
, sampleRate
, bandwidth
, SHORT_WINDOW
, hPsy
->granuleLength
, useIS
, &hPsy
->psyConf
[1], filterBank
);
356 if (ErrorStatus
!= AAC_ENC_OK
)
359 ErrorStatus
= FDKaacEnc_InitTnsConfiguration(
360 (bitRate
*tnsChannels
)/channelsEff
,
365 (syntaxFlags
&AC_SBR_PRESENT
)?1:0,
366 &hPsy
->psyConf
[1].tnsConf
,
371 if (ErrorStatus
!= AAC_ENC_OK
)
377 for (i
=0; i
<cm
->nElements
; i
++) {
378 for (ch
=0; ch
<cm
->elInfo
[i
].nChannelsInEl
; ch
++) {
381 FDKaacEnc_psyInitStates(hPsy
, hPsy
->psyElement
[i
]->psyStatic
[ch
], audioObjectType
);
384 FDKaacEnc_InitPreEchoControl(hPsy
->psyElement
[i
]->psyStatic
[ch
]->sfbThresholdnm1
,
385 &hPsy
->psyElement
[i
]->psyStatic
[ch
]->calcPreEcho
,
386 hPsy
->psyConf
[0].sfbCnt
,
387 hPsy
->psyConf
[0].sfbPcmQuantThreshold
,
388 &hPsy
->psyElement
[i
]->psyStatic
[ch
]->mdctScalenm1
);
392 ErrorStatus
= FDKaacEnc_InitPnsConfiguration(&hPsy
->psyConf
[0].pnsConf
,
396 hPsy
->psyConf
[0].sfbCnt
,
397 hPsy
->psyConf
[0].sfbOffset
,
398 cm
->elInfo
[0].nChannelsInEl
,
399 (hPsy
->psyConf
[0].filterbank
== FB_LC
));
400 if (ErrorStatus
!= AAC_ENC_OK
)
403 ErrorStatus
= FDKaacEnc_InitPnsConfiguration(&hPsy
->psyConf
[1].pnsConf
,
407 hPsy
->psyConf
[1].sfbCnt
,
408 hPsy
->psyConf
[1].sfbOffset
,
409 cm
->elInfo
[1].nChannelsInEl
,
410 (hPsy
->psyConf
[1].filterbank
== FB_LC
));
416 void FDKaacEnc_deinterleaveInputBuffer(INT_PCM
*pOutputSamples
,
417 INT_PCM
*pInputSamples
,
422 /* deinterlave input samples and write to output buffer */
423 for (k
=0; k
<nSamples
; k
++) {
424 pOutputSamples
[k
] = pInputSamples
[k
*nChannels
];
430 /*****************************************************************************
432 functionname: FDKaacEnc_psyMain
433 description: psychoacoustic
434 returns: an error code
436 This function assumes that enough input data is in the modulo buffer.
438 *****************************************************************************/
440 AAC_ENCODER_ERROR
FDKaacEnc_psyMain(INT channels
,
441 PSY_ELEMENT
*psyElement
,
442 PSY_DYNAMIC
*psyDynamic
,
443 PSY_CONFIGURATION
*psyConf
,
444 PSY_OUT_ELEMENT
*RESTRICT psyOutElement
,
450 INT commonWindow
= 1;
451 INT maxSfbPerGroup
[(2)];
453 INT ch
; /* counts through channels */
454 INT w
; /* counts through windows */
455 INT sfb
; /* counts through scalefactor bands */
456 INT line
; /* counts through lines */
458 PSY_CONFIGURATION
*RESTRICT hPsyConfLong
= &psyConf
[0];
459 PSY_CONFIGURATION
*RESTRICT hPsyConfShort
= &psyConf
[1];
460 PSY_OUT_CHANNEL
**RESTRICT psyOutChannel
= psyOutElement
->psyOutChannel
;
461 FIXP_SGL sfbTonality
[(2)][MAX_SFB_LONG
];
463 PSY_STATIC
**RESTRICT psyStatic
= psyElement
->psyStatic
;
465 PSY_DATA
*RESTRICT psyData
[(2)];
466 TNS_DATA
*RESTRICT tnsData
[(2)];
467 PNS_DATA
*RESTRICT pnsData
[(2)];
469 INT zeroSpec
= TRUE
; /* means all spectral lines are zero */
471 INT blockSwitchingOffset
;
473 PSY_CONFIGURATION
*RESTRICT hThisPsyConf
[(2)];
474 INT windowLength
[(2)];
479 INT
*pSfbMaxScaleSpec
[(2)];
480 FIXP_DBL
*pSfbEnergy
[(2)];
481 FIXP_DBL
*pSfbSpreadEnergy
[(2)];
482 FIXP_DBL
*pSfbEnergyLdData
[(2)];
483 FIXP_DBL
*pSfbEnergyMS
[(2)];
484 FIXP_DBL
*pSfbThreshold
[(2)];
486 INT isShortWindow
[(2)];
489 if (hPsyConfLong
->filterbank
== FB_LC
) {
490 blockSwitchingOffset
= psyConf
->granuleLength
+ (9*psyConf
->granuleLength
/(2*TRANS_FAC
));
492 blockSwitchingOffset
= psyConf
->granuleLength
;
495 for(ch
= 0; ch
< channels
; ch
++)
497 psyData
[ch
] = &psyDynamic
->psyData
[ch
];
498 tnsData
[ch
] = &psyDynamic
->tnsData
[ch
];
499 pnsData
[ch
] = &psyDynamic
->pnsData
[ch
];
501 psyData
[ch
]->mdctSpectrum
= psyOutChannel
[ch
]->mdctSpectrum
;
504 /* block switching */
505 if (hPsyConfLong
->filterbank
!= FB_ELD
)
509 for(ch
= 0; ch
< channels
; ch
++)
511 C_ALLOC_SCRATCH_START(pTimeSignal
, INT_PCM
, (1024))
513 /* deinterleave input data and use for block switching */
514 FDKaacEnc_deinterleaveInputBuffer( pTimeSignal
,
516 psyConf
->granuleLength
,
520 FDKaacEnc_BlockSwitching (&psyStatic
[ch
]->blockSwitchingControl
,
521 psyConf
->granuleLength
,
522 psyStatic
[ch
]->isLFE
,
527 /* fill up internal input buffer, to 2xframelength samples */
528 FDKmemcpy(psyStatic
[ch
]->psyInputBuffer
+blockSwitchingOffset
,
530 (2*psyConf
->granuleLength
-blockSwitchingOffset
)*sizeof(INT_PCM
));
532 C_ALLOC_SCRATCH_END(pTimeSignal
, INT_PCM
, (1024))
535 /* synch left and right block type */
536 err
= FDKaacEnc_SyncBlockSwitching(&psyStatic
[0]->blockSwitchingControl
,
537 &psyStatic
[1]->blockSwitchingControl
,
542 return AAC_ENC_UNSUPPORTED_AOT
; /* mixed up LC and LD */
547 for(ch
= 0; ch
< channels
; ch
++)
549 /* deinterleave input data and use for block switching */
550 FDKaacEnc_deinterleaveInputBuffer( psyStatic
[ch
]->psyInputBuffer
+ blockSwitchingOffset
,
552 psyConf
->granuleLength
,
557 for(ch
= 0; ch
< channels
; ch
++)
558 isShortWindow
[ch
]=(psyStatic
[ch
]->blockSwitchingControl
.lastWindowSequence
== SHORT_WINDOW
);
560 /* set parameters according to window length */
561 for(ch
= 0; ch
< channels
; ch
++)
563 if(isShortWindow
[ch
]) {
564 hThisPsyConf
[ch
] = hPsyConfShort
;
565 windowLength
[ch
] = psyConf
->granuleLength
/TRANS_FAC
;
566 nWindows
[ch
] = TRANS_FAC
;
567 maxSfb
[ch
] = MAX_SFB_SHORT
;
569 pSfbMaxScaleSpec
[ch
] = psyData
[ch
]->sfbMaxScaleSpec
.Short
[0];
570 pSfbEnergy
[ch
] = psyData
[ch
]->sfbEnergy
.Short
[0];
571 pSfbSpreadEnergy
[ch
] = psyData
[ch
]->sfbSpreadEnergy
.Short
[0];
572 pSfbEnergyLdData
[ch
] = psyData
[ch
]->sfbEnergyLdData
.Short
[0];
573 pSfbEnergyMS
[ch
] = psyData
[ch
]->sfbEnergyMS
.Short
[0];
574 pSfbThreshold
[ch
] = psyData
[ch
]->sfbThreshold
.Short
[0];
578 hThisPsyConf
[ch
] = hPsyConfLong
;
579 windowLength
[ch
] = psyConf
->granuleLength
;
581 maxSfb
[ch
] = MAX_GROUPED_SFB
;
583 pSfbMaxScaleSpec
[ch
] = psyData
[ch
]->sfbMaxScaleSpec
.Long
;
584 pSfbEnergy
[ch
] = psyData
[ch
]->sfbEnergy
.Long
;
585 pSfbSpreadEnergy
[ch
] = psyData
[ch
]->sfbSpreadEnergy
.Long
;
586 pSfbEnergyLdData
[ch
] = psyData
[ch
]->sfbEnergyLdData
.Long
;
587 pSfbEnergyMS
[ch
] = psyData
[ch
]->sfbEnergyMS
.Long
;
588 pSfbThreshold
[ch
] = psyData
[ch
]->sfbThreshold
.Long
;
592 /* Transform and get mdctScaling for all channels and windows. */
593 for(ch
= 0; ch
< channels
; ch
++)
595 /* update number of active bands */
596 if (psyStatic
[ch
]->isLFE
) {
597 psyData
[ch
]->sfbActive
= hThisPsyConf
[ch
]->sfbActiveLFE
;
598 psyData
[ch
]->lowpassLine
= hThisPsyConf
[ch
]->lowpassLineLFE
;
601 psyData
[ch
]->sfbActive
= hThisPsyConf
[ch
]->sfbActive
;
602 psyData
[ch
]->lowpassLine
= hThisPsyConf
[ch
]->lowpassLine
;
605 for(w
= 0; w
< nWindows
[ch
]; w
++) {
607 wOffset
= w
*windowLength
[ch
];
609 FDKaacEnc_Transform_Real( psyStatic
[ch
]->psyInputBuffer
+ wOffset
,
610 psyData
[ch
]->mdctSpectrum
+wOffset
,
611 psyStatic
[ch
]->blockSwitchingControl
.lastWindowSequence
,
612 psyStatic
[ch
]->blockSwitchingControl
.windowShape
,
613 &psyStatic
[ch
]->blockSwitchingControl
.lastWindowShape
,
614 psyConf
->granuleLength
,
616 hThisPsyConf
[ch
]->filterbank
617 ,psyStatic
[ch
]->overlapAddBuffer
620 /* Low pass / highest sfb */
621 FDKmemclear(&psyData
[ch
]->mdctSpectrum
[psyData
[ch
]->lowpassLine
+wOffset
],
622 (windowLength
[ch
]-psyData
[ch
]->lowpassLine
)*sizeof(FIXP_DBL
));
624 if (hPsyConfLong
->filterbank
!= FB_LC
) {
625 /* Do blending to reduce gibbs artifacts */
626 for (int i
=0; i
<FADE_OUT_LEN
; i
++) {
627 psyData
[ch
]->mdctSpectrum
[psyData
[ch
]->lowpassLine
+wOffset
- FADE_OUT_LEN
+ i
] = fMult(psyData
[ch
]->mdctSpectrum
[psyData
[ch
]->lowpassLine
+wOffset
- FADE_OUT_LEN
+ i
], fadeOutFactor
[i
]);
632 /* Check for zero spectrum. These loops will usually terminate very, very early. */
633 for(line
=0; (line
<psyData
[ch
]->lowpassLine
) && (zeroSpec
==TRUE
); line
++) {
634 if (psyData
[ch
]->mdctSpectrum
[line
+wOffset
] != (FIXP_DBL
)0) {
642 psyData
[ch
]->mdctScale
= mdctSpectrum_e
;
644 /* rotate internal time samples */
645 FDKmemmove(psyStatic
[ch
]->psyInputBuffer
,
646 psyStatic
[ch
]->psyInputBuffer
+psyConf
->granuleLength
,
647 psyConf
->granuleLength
*sizeof(INT_PCM
));
650 /* ... and get remaining samples from input buffer */
651 FDKaacEnc_deinterleaveInputBuffer( psyStatic
[ch
]->psyInputBuffer
+psyConf
->granuleLength
,
652 &pInput
[ (2*psyConf
->granuleLength
-blockSwitchingOffset
)*totalChannels
+ chIdx
[ch
] ],
653 blockSwitchingOffset
-psyConf
->granuleLength
,
658 /* Do some rescaling to get maximum possible accuracy for energies */
659 if ( zeroSpec
== FALSE
) {
661 /* Calc possible spectrum leftshift for each sfb (1 means: 1 bit left shift is possible without overflow) */
662 INT minSpecShift
= MAX_SHIFT_DBL
;
663 INT nrgShift
= MAX_SHIFT_DBL
;
664 INT finalShift
= MAX_SHIFT_DBL
;
665 FIXP_DBL currNrg
= 0;
668 for(ch
= 0; ch
< channels
; ch
++) {
669 for(w
= 0; w
< nWindows
[ch
]; w
++) {
670 wOffset
= w
*windowLength
[ch
];
671 FDKaacEnc_CalcSfbMaxScaleSpec(psyData
[ch
]->mdctSpectrum
+wOffset
,
672 hThisPsyConf
[ch
]->sfbOffset
,
673 pSfbMaxScaleSpec
[ch
]+w
*maxSfb
[ch
],
674 psyData
[ch
]->sfbActive
);
676 for (sfb
= 0; sfb
<psyData
[ch
]->sfbActive
; sfb
++)
677 minSpecShift
= fixMin(minSpecShift
, (pSfbMaxScaleSpec
[ch
]+w
*maxSfb
[ch
])[sfb
]);
682 /* Calc possible energy leftshift for each sfb (1 means: 1 bit left shift is possible without overflow) */
683 for(ch
= 0; ch
< channels
; ch
++) {
684 for(w
= 0; w
< nWindows
[ch
]; w
++) {
685 wOffset
= w
*windowLength
[ch
];
686 currNrg
= FDKaacEnc_CheckBandEnergyOptim(psyData
[ch
]->mdctSpectrum
+wOffset
,
687 pSfbMaxScaleSpec
[ch
]+w
*maxSfb
[ch
],
688 hThisPsyConf
[ch
]->sfbOffset
,
689 psyData
[ch
]->sfbActive
,
690 pSfbEnergy
[ch
]+w
*maxSfb
[ch
],
691 pSfbEnergyLdData
[ch
]+w
*maxSfb
[ch
],
694 maxNrg
= fixMax(maxNrg
, currNrg
);
698 if ( maxNrg
!= (FIXP_DBL
)0 ) {
699 nrgShift
= (CountLeadingBits(maxNrg
)>>1) + (minSpecShift
-4);
702 /* 2check: Hasn't this decision to be made for both channels? */
703 /* For short windows 1 additional bit headroom is necessary to prevent overflows when summing up energies in FDKaacEnc_groupShortData() */
704 if(isShortWindow
[0]) nrgShift
--;
706 /* both spectrum and energies mustn't overflow */
707 finalShift
= fixMin(minSpecShift
, nrgShift
);
709 /* do not shift more than 3 bits more to the left than signal without blockfloating point
710 * would be to avoid overflow of scaled PCM quantization thresholds */
711 if (finalShift
> psyData
[0]->mdctScale
+ 3 )
712 finalShift
= psyData
[0]->mdctScale
+ 3;
714 FDK_ASSERT(finalShift
>= 0); /* right shift is not allowed */
716 /* correct sfbEnergy and sfbEnergyLdData with new finalShift */
717 FIXP_DBL ldShift
= finalShift
* FL2FXCONST_DBL(2.0/64);
718 for(ch
= 0; ch
< channels
; ch
++) {
719 for(w
= 0; w
< nWindows
[ch
]; w
++) {
720 for(sfb
=0; sfb
<psyData
[ch
]->sfbActive
; sfb
++) {
721 INT scale
= fixMax(0, (pSfbMaxScaleSpec
[ch
]+w
*maxSfb
[ch
])[sfb
]-4);
722 scale
= fixMin((scale
-finalShift
)<<1, DFRACT_BITS
-1);
723 if (scale
>= 0) (pSfbEnergy
[ch
]+w
*maxSfb
[ch
])[sfb
] >>= (scale
);
724 else (pSfbEnergy
[ch
]+w
*maxSfb
[ch
])[sfb
] <<= (-scale
);
725 (pSfbThreshold
[ch
]+w
*maxSfb
[ch
])[sfb
] = fMult((pSfbEnergy
[ch
]+w
*maxSfb
[ch
])[sfb
], C_RATIO
);
726 (pSfbEnergyLdData
[ch
]+w
*maxSfb
[ch
])[sfb
] += ldShift
;
731 if ( finalShift
!= 0 ) {
732 for (ch
= 0; ch
< channels
; ch
++) {
733 for(w
= 0; w
< nWindows
[ch
]; w
++) {
734 wOffset
= w
*windowLength
[ch
];
735 for(line
=0; line
<psyData
[ch
]->lowpassLine
; line
++) {
736 psyData
[ch
]->mdctSpectrum
[line
+wOffset
] <<= finalShift
;
738 /* update sfbMaxScaleSpec */
739 for (sfb
= 0; sfb
<psyData
[ch
]->sfbActive
; sfb
++)
740 (pSfbMaxScaleSpec
[ch
]+w
*maxSfb
[ch
])[sfb
] -= finalShift
;
742 /* update mdctScale */
743 psyData
[ch
]->mdctScale
-= finalShift
;
748 /* all spectral lines are zero */
749 for (ch
= 0; ch
< channels
; ch
++) {
750 psyData
[ch
]->mdctScale
= 0; /* otherwise mdctScale would be for example 7 and PCM quantization thresholds would be shifted
751 * 14 bits to the right causing some of them to become 0 (which causes problems later) */
752 /* clear sfbMaxScaleSpec */
753 for(w
= 0; w
< nWindows
[ch
]; w
++) {
754 for (sfb
= 0; sfb
<psyData
[ch
]->sfbActive
; sfb
++) {
755 (pSfbMaxScaleSpec
[ch
]+w
*maxSfb
[ch
])[sfb
] = 0;
756 (pSfbEnergy
[ch
]+w
*maxSfb
[ch
])[sfb
] = (FIXP_DBL
)0;
757 (pSfbEnergyLdData
[ch
]+w
*maxSfb
[ch
])[sfb
] = FL2FXCONST_DBL(-1.0f
);
758 (pSfbThreshold
[ch
]+w
*maxSfb
[ch
])[sfb
] = (FIXP_DBL
)0;
764 /* Advance psychoacoustics: Tonality and TNS */
765 if (psyStatic
[0]->isLFE
) {
766 tnsData
[0]->dataRaw
.Long
.subBlockInfo
.tnsActive
= 0;
771 for(ch
= 0; ch
< channels
; ch
++) {
772 if (!isShortWindow
[ch
]) {
774 FDKaacEnc_CalculateFullTonality( psyData
[ch
]->mdctSpectrum
,
775 pSfbMaxScaleSpec
[ch
],
776 pSfbEnergyLdData
[ch
],
778 psyData
[ch
]->sfbActive
,
779 hThisPsyConf
[ch
]->sfbOffset
,
780 hThisPsyConf
[ch
]->pnsConf
.usePns
);
784 if (hPsyConfLong
->tnsConf
.tnsActive
|| hPsyConfShort
->tnsConf
.tnsActive
) {
785 INT tnsActive
[TRANS_FAC
];
786 INT nrgScaling
[2] = {0,0};
787 INT tnsSpecShift
= 0;
789 for(ch
= 0; ch
< channels
; ch
++) {
790 for(w
= 0; w
< nWindows
[ch
]; w
++) {
792 wOffset
= w
*windowLength
[ch
];
796 &hThisPsyConf
[ch
]->tnsConf
,
797 &psyOutChannel
[ch
]->tnsInfo
,
798 hThisPsyConf
[ch
]->sfbCnt
,
799 psyData
[ch
]->mdctSpectrum
+wOffset
,
801 psyStatic
[ch
]->blockSwitchingControl
.lastWindowSequence
810 &psyOutChannel
[1]->tnsInfo
,
811 &psyOutChannel
[0]->tnsInfo
,
813 psyStatic
[1]->blockSwitchingControl
.lastWindowSequence
,
814 psyStatic
[0]->blockSwitchingControl
.lastWindowSequence
,
815 &hThisPsyConf
[1]->tnsConf
);
818 FDK_ASSERT(commonWindow
=1); /* all checks for TNS do only work for common windows (which is always set)*/
819 for(w
= 0; w
< nWindows
[0]; w
++)
821 if (isShortWindow
[0])
822 tnsActive
[w
] = tnsData
[0]->dataRaw
.Short
.subBlockInfo
[w
].tnsActive
||
823 ((channels
== 2) ? tnsData
[1]->dataRaw
.Short
.subBlockInfo
[w
].tnsActive
: 0);
825 tnsActive
[w
] = tnsData
[0]->dataRaw
.Long
.subBlockInfo
.tnsActive
||
826 ((channels
== 2) ? tnsData
[1]->dataRaw
.Long
.subBlockInfo
.tnsActive
: 0);
829 for(ch
= 0; ch
< channels
; ch
++) {
830 if (tnsActive
[0] && !isShortWindow
[ch
]) {
831 /* Scale down spectrum if tns is active in one of the two channels with same lastWindowSequence */
832 /* first part of threshold calculation; it's not necessary to update sfbMaxScaleSpec */
834 for(sfb
=0; sfb
<hThisPsyConf
[ch
]->lowpassLine
; sfb
++) {
835 psyData
[ch
]->mdctSpectrum
[sfb
] = psyData
[ch
]->mdctSpectrum
[sfb
] >> shift
;
838 /* update thresholds */
839 for (sfb
=0; sfb
<psyData
[ch
]->sfbActive
; sfb
++) {
840 pSfbThreshold
[ch
][sfb
] >>= (2*shift
);
843 psyData
[ch
]->mdctScale
+= shift
; /* update mdctScale */
845 /* calc sfbEnergies after tnsEncode again ! */
850 for(ch
= 0; ch
< channels
; ch
++) {
851 for(w
= 0; w
< nWindows
[ch
]; w
++)
853 wOffset
= w
*windowLength
[ch
];
855 &psyOutChannel
[ch
]->tnsInfo
,
857 hThisPsyConf
[ch
]->sfbCnt
,
858 &hThisPsyConf
[ch
]->tnsConf
,
859 hThisPsyConf
[ch
]->sfbOffset
[psyData
[ch
]->sfbActive
],/*hThisPsyConf[ch]->lowpassLine*/ /* filter stops before that line ! */
860 psyData
[ch
]->mdctSpectrum
+wOffset
,
862 psyStatic
[ch
]->blockSwitchingControl
.lastWindowSequence
);
865 /* Calc sfb-bandwise mdct-energies for left and right channel again, */
866 /* if tns active in current channel or in one channel with same lastWindowSequence left and right */
867 FDKaacEnc_CalcSfbMaxScaleSpec(psyData
[ch
]->mdctSpectrum
+wOffset
,
868 hThisPsyConf
[ch
]->sfbOffset
,
869 pSfbMaxScaleSpec
[ch
]+w
*maxSfb
[ch
],
870 psyData
[ch
]->sfbActive
);
875 for(ch
= 0; ch
< channels
; ch
++) {
876 for(w
= 0; w
< nWindows
[ch
]; w
++) {
880 if (isShortWindow
[ch
]) {
881 FDKaacEnc_CalcBandEnergyOptimShort(psyData
[ch
]->mdctSpectrum
+w
*windowLength
[ch
],
882 pSfbMaxScaleSpec
[ch
]+w
*maxSfb
[ch
],
883 hThisPsyConf
[ch
]->sfbOffset
,
884 psyData
[ch
]->sfbActive
,
885 pSfbEnergy
[ch
]+w
*maxSfb
[ch
]);
888 nrgScaling
[ch
] = /* with tns, energy calculation can overflow; -> scaling */
889 FDKaacEnc_CalcBandEnergyOptimLong(psyData
[ch
]->mdctSpectrum
,
890 pSfbMaxScaleSpec
[ch
],
891 hThisPsyConf
[ch
]->sfbOffset
,
892 psyData
[ch
]->sfbActive
,
894 pSfbEnergyLdData
[ch
]);
895 tnsSpecShift
= fixMax(tnsSpecShift
, nrgScaling
[ch
]); /* nrgScaling is set only if nrg would have an overflow */
899 } /* end channel loop */
901 /* adapt scaling to prevent nrg overflow, only for long blocks */
902 for(ch
= 0; ch
< channels
; ch
++) {
903 if ( (tnsSpecShift
!=0) && !isShortWindow
[ch
] ) {
904 /* scale down spectrum, nrg's and thresholds, if there was an overflow in sfbNrg calculation after tns */
905 for(line
=0; line
<hThisPsyConf
[ch
]->lowpassLine
; line
++) {
906 psyData
[ch
]->mdctSpectrum
[line
] >>= tnsSpecShift
;
908 INT scale
= (tnsSpecShift
-nrgScaling
[ch
])<<1;
909 for(sfb
=0; sfb
<psyData
[ch
]->sfbActive
; sfb
++) {
910 pSfbEnergyLdData
[ch
][sfb
] -= scale
*FL2FXCONST_DBL(1.0/LD_DATA_SCALING
);
911 pSfbEnergy
[ch
][sfb
] >>= scale
;
912 pSfbThreshold
[ch
][sfb
] >>= (tnsSpecShift
<<1);
914 psyData
[ch
]->mdctScale
+= tnsSpecShift
; /* update mdctScale; not necessary to update sfbMaxScaleSpec */
917 } /* end channel loop */
927 /* Advance thresholds */
928 for(ch
= 0; ch
< channels
; ch
++) {
932 INT energyShift
= psyData
[ch
]->mdctScale
*2 ;
933 INT clipNrgShift
= energyShift
- THR_SHIFTBITS
;
935 if(isShortWindow
[ch
])
940 if (clipNrgShift
>= 0)
941 clipEnergy
= hThisPsyConf
[ch
]->clipEnergy
>> clipNrgShift
;
942 else if (clipNrgShift
>=-headroom
)
943 clipEnergy
= hThisPsyConf
[ch
]->clipEnergy
<< -clipNrgShift
;
945 clipEnergy
= (FIXP_DBL
)MAXVAL_DBL
;
947 for(w
= 0; w
< nWindows
[ch
]; w
++)
950 /* limit threshold to avoid clipping */
951 for (i
=0; i
<psyData
[ch
]->sfbActive
; i
++) {
952 *(pSfbThreshold
[ch
]+w
*maxSfb
[ch
]+i
) = fixMin(*(pSfbThreshold
[ch
]+w
*maxSfb
[ch
]+i
), clipEnergy
);
956 FDKaacEnc_SpreadingMax(psyData
[ch
]->sfbActive
,
957 hThisPsyConf
[ch
]->sfbMaskLowFactor
,
958 hThisPsyConf
[ch
]->sfbMaskHighFactor
,
959 pSfbThreshold
[ch
]+w
*maxSfb
[ch
]);
962 /* PCM quantization threshold */
963 energyShift
+= PCM_QUANT_THR_SCALE
;
964 if (energyShift
>=0) {
965 energyShift
= fixMin(DFRACT_BITS
-1,energyShift
);
966 for (i
=0; i
<psyData
[ch
]->sfbActive
;i
++) {
967 *(pSfbThreshold
[ch
]+w
*maxSfb
[ch
]+i
) = fixMax(*(pSfbThreshold
[ch
]+w
*maxSfb
[ch
]+i
) >> THR_SHIFTBITS
,
968 (hThisPsyConf
[ch
]->sfbPcmQuantThreshold
[i
] >> energyShift
));
971 energyShift
= fixMin(DFRACT_BITS
-1,-energyShift
);
972 for (i
=0; i
<psyData
[ch
]->sfbActive
;i
++) {
973 *(pSfbThreshold
[ch
]+w
*maxSfb
[ch
]+i
) = fixMax(*(pSfbThreshold
[ch
]+w
*maxSfb
[ch
]+i
) >> THR_SHIFTBITS
,
974 (hThisPsyConf
[ch
]->sfbPcmQuantThreshold
[i
] << energyShift
));
978 if (!psyStatic
[ch
]->isLFE
)
980 /* preecho control */
981 if(psyStatic
[ch
]->blockSwitchingControl
.lastWindowSequence
== STOP_WINDOW
) {
982 /* prevent FDKaacEnc_PreEchoControl from comparing stop
983 thresholds with short thresholds */
984 for (i
=0; i
<psyData
[ch
]->sfbActive
;i
++) {
985 psyStatic
[ch
]->sfbThresholdnm1
[i
] = (FIXP_DBL
)MAXVAL_DBL
;
988 psyStatic
[ch
]->mdctScalenm1
= 0;
989 psyStatic
[ch
]->calcPreEcho
= 0;
992 FDKaacEnc_PreEchoControl( psyStatic
[ch
]->sfbThresholdnm1
,
993 psyStatic
[ch
]->calcPreEcho
,
994 psyData
[ch
]->sfbActive
,
995 hThisPsyConf
[ch
]->maxAllowedIncreaseFactor
,
996 hThisPsyConf
[ch
]->minRemainingThresholdFactor
,
997 pSfbThreshold
[ch
]+w
*maxSfb
[ch
],
998 psyData
[ch
]->mdctScale
,
999 &psyStatic
[ch
]->mdctScalenm1
);
1001 psyStatic
[ch
]->calcPreEcho
= 1;
1003 if(psyStatic
[ch
]->blockSwitchingControl
.lastWindowSequence
== START_WINDOW
)
1005 /* prevent FDKaacEnc_PreEchoControl in next frame to compare start
1006 thresholds with short thresholds */
1007 for (i
=0; i
<psyData
[ch
]->sfbActive
;i
++) {
1008 psyStatic
[ch
]->sfbThresholdnm1
[i
] = (FIXP_DBL
)MAXVAL_DBL
;
1011 psyStatic
[ch
]->mdctScalenm1
= 0;
1012 psyStatic
[ch
]->calcPreEcho
= 0;
1017 /* spread energy to avoid hole detection */
1018 FDKmemcpy(pSfbSpreadEnergy
[ch
]+w
*maxSfb
[ch
], pSfbEnergy
[ch
]+w
*maxSfb
[ch
], psyData
[ch
]->sfbActive
*sizeof(FIXP_DBL
));
1020 FDKaacEnc_SpreadingMax(psyData
[ch
]->sfbActive
,
1021 hThisPsyConf
[ch
]->sfbMaskLowFactorSprEn
,
1022 hThisPsyConf
[ch
]->sfbMaskHighFactorSprEn
,
1023 pSfbSpreadEnergy
[ch
]+w
*maxSfb
[ch
]);
1027 /* Calc bandwise energies for mid and side channel. Do it only if 2 channels exist */
1029 for(w
= 0; w
< nWindows
[1]; w
++) {
1030 wOffset
= w
*windowLength
[1];
1031 FDKaacEnc_CalcBandNrgMSOpt(psyData
[0]->mdctSpectrum
+wOffset
,
1032 psyData
[1]->mdctSpectrum
+wOffset
,
1033 pSfbMaxScaleSpec
[0]+w
*maxSfb
[0],
1034 pSfbMaxScaleSpec
[1]+w
*maxSfb
[1],
1035 hThisPsyConf
[1]->sfbOffset
,
1036 psyData
[0]->sfbActive
,
1037 pSfbEnergyMS
[0]+w
*maxSfb
[0],
1038 pSfbEnergyMS
[1]+w
*maxSfb
[1],
1039 (psyStatic
[1]->blockSwitchingControl
.lastWindowSequence
!= SHORT_WINDOW
),
1040 psyData
[0]->sfbEnergyMSLdData
,
1041 psyData
[1]->sfbEnergyMSLdData
);
1045 /* group short data (maxSfb[ch] for short blocks is determined here) */
1046 for(ch
=0;ch
<channels
;ch
++)
1049 if(isShortWindow
[ch
])
1052 noSfb
= psyStatic
[ch
]->blockSwitchingControl
.noOfGroups
* hPsyConfShort
->sfbCnt
;
1053 /* At this point, energies and thresholds are copied/regrouped from the ".Short" to the ".Long" arrays */
1054 FDKaacEnc_groupShortData( psyData
[ch
]->mdctSpectrum
,
1055 &psyData
[ch
]->sfbThreshold
,
1056 &psyData
[ch
]->sfbEnergy
,
1057 &psyData
[ch
]->sfbEnergyMS
,
1058 &psyData
[ch
]->sfbSpreadEnergy
,
1059 hPsyConfShort
->sfbCnt
,
1060 psyData
[ch
]->sfbActive
,
1061 hPsyConfShort
->sfbOffset
,
1062 hPsyConfShort
->sfbMinSnrLdData
,
1063 psyData
[ch
]->groupedSfbOffset
,
1064 &maxSfbPerGroup
[ch
],
1065 psyOutChannel
[ch
]->sfbMinSnrLdData
,
1066 psyStatic
[ch
]->blockSwitchingControl
.noOfGroups
,
1067 psyStatic
[ch
]->blockSwitchingControl
.groupLen
,
1068 psyConf
[1].granuleLength
);
1071 /* calculate ldData arrays (short values are in .Long-arrays after FDKaacEnc_groupShortData) */
1072 for (sfbGrp
= 0; sfbGrp
< noSfb
; sfbGrp
+= hPsyConfShort
->sfbCnt
) {
1073 LdDataVector(&psyData
[ch
]->sfbEnergy
.Long
[sfbGrp
], &psyOutChannel
[ch
]->sfbEnergyLdData
[sfbGrp
], psyData
[ch
]->sfbActive
);
1076 /* calc sfbThrld and set Values smaller 2^-31 to 2^-33*/
1077 for (sfbGrp
= 0; sfbGrp
< noSfb
; sfbGrp
+= hPsyConfShort
->sfbCnt
) {
1078 LdDataVector(&psyData
[ch
]->sfbThreshold
.Long
[sfbGrp
], &psyOutChannel
[ch
]->sfbThresholdLdData
[sfbGrp
], psyData
[ch
]->sfbActive
);
1079 for (sfb
=0;sfb
<psyData
[ch
]->sfbActive
;sfb
++) {
1080 psyOutChannel
[ch
]->sfbThresholdLdData
[sfbGrp
+sfb
] =
1081 fixMax(psyOutChannel
[ch
]->sfbThresholdLdData
[sfbGrp
+sfb
], FL2FXCONST_DBL(-0.515625f
));
1085 if ( channels
==2 ) {
1086 for (sfbGrp
= 0; sfbGrp
< noSfb
; sfbGrp
+= hPsyConfShort
->sfbCnt
) {
1087 LdDataVector(&psyData
[ch
]->sfbEnergyMS
.Long
[sfbGrp
], &psyData
[ch
]->sfbEnergyMSLdData
[sfbGrp
], psyData
[ch
]->sfbActive
);
1091 FDKmemcpy(psyOutChannel
[ch
]->sfbOffsets
, psyData
[ch
]->groupedSfbOffset
, (MAX_GROUPED_SFB
+1)*sizeof(INT
));
1094 /* maxSfb[ch] for long blocks */
1095 for (sfb
= psyData
[ch
]->sfbActive
-1; sfb
>= 0; sfb
--) {
1096 for (line
= hPsyConfLong
->sfbOffset
[sfb
+1]-1; line
>= hPsyConfLong
->sfbOffset
[sfb
]; line
--) {
1097 if (psyData
[ch
]->mdctSpectrum
[line
] != FL2FXCONST_SGL(0.0f
)) break;
1099 if (line
> hPsyConfLong
->sfbOffset
[sfb
]) break;
1101 maxSfbPerGroup
[ch
] = sfb
+ 1;
1102 /* ensure at least one section in ICS; workaround for existing decoder crc implementation */
1103 maxSfbPerGroup
[ch
] = fixMax(fixMin(5,psyData
[ch
]->sfbActive
),maxSfbPerGroup
[ch
]);
1105 /* sfbNrgLdData is calculated in FDKaacEnc_advancePsychLong, copy in psyOut structure */
1106 FDKmemcpy(psyOutChannel
[ch
]->sfbEnergyLdData
, psyData
[ch
]->sfbEnergyLdData
.Long
, psyData
[ch
]->sfbActive
*sizeof(FIXP_DBL
));
1108 FDKmemcpy(psyOutChannel
[ch
]->sfbOffsets
, hPsyConfLong
->sfbOffset
, (MAX_GROUPED_SFB
+1)*sizeof(INT
));
1110 /* sfbMinSnrLdData modified in adjust threshold, copy necessary */
1111 FDKmemcpy(psyOutChannel
[ch
]->sfbMinSnrLdData
, hPsyConfLong
->sfbMinSnrLdData
, psyData
[ch
]->sfbActive
*sizeof(FIXP_DBL
));
1113 /* sfbEnergyMSLdData ist already calculated in FDKaacEnc_CalcBandNrgMSOpt; only in long case */
1115 /* calc sfbThrld and set Values smaller 2^-31 to 2^-33*/
1116 LdDataVector(psyData
[ch
]->sfbThreshold
.Long
, psyOutChannel
[ch
]->sfbThresholdLdData
, psyData
[ch
]->sfbActive
);
1117 for (i
=0;i
<psyData
[ch
]->sfbActive
;i
++) {
1118 psyOutChannel
[ch
]->sfbThresholdLdData
[i
] =
1119 fixMax(psyOutChannel
[ch
]->sfbThresholdLdData
[i
], FL2FXCONST_DBL(-0.515625f
));
1130 Intensity parameter intialization.
1132 for(ch
=0;ch
<channels
;ch
++) {
1133 FDKmemclear(psyOutChannel
[ch
]->isBook
, MAX_GROUPED_SFB
*sizeof(INT
));
1134 FDKmemclear(psyOutChannel
[ch
]->isScale
, MAX_GROUPED_SFB
*sizeof(INT
));
1137 for(ch
=0;ch
<channels
;ch
++) {
1138 INT win
= (isShortWindow
[ch
]?1:0);
1139 if (!psyStatic
[ch
]->isLFE
)
1142 FDKaacEnc_PnsDetect( &(psyConf
[0].pnsConf
),
1144 psyStatic
[ch
]->blockSwitchingControl
.lastWindowSequence
,
1145 psyData
[ch
]->sfbActive
,
1146 maxSfbPerGroup
[ch
], /* count of Sfb which are not zero. */
1147 psyOutChannel
[ch
]->sfbThresholdLdData
,
1148 psyConf
[win
].sfbOffset
,
1149 psyData
[ch
]->mdctSpectrum
,
1150 psyData
[ch
]->sfbMaxScaleSpec
.Long
,
1152 psyOutChannel
[ch
]->tnsInfo
.order
[0][0],
1153 tnsData
[ch
]->dataRaw
.Long
.subBlockInfo
.predictionGain
,
1154 tnsData
[ch
]->dataRaw
.Long
.subBlockInfo
.tnsActive
,
1155 psyOutChannel
[ch
]->sfbEnergyLdData
,
1156 psyOutChannel
[ch
]->noiseNrg
);
1165 psyOutElement
->toolsInfo
.msDigest
= MS_NONE
;
1166 psyOutElement
->commonWindow
= commonWindow
;
1167 if (psyOutElement
->commonWindow
)
1168 maxSfbPerGroup
[0] = maxSfbPerGroup
[1] =
1169 fixMax(maxSfbPerGroup
[0], maxSfbPerGroup
[1]);
1171 if(psyStatic
[0]->blockSwitchingControl
.lastWindowSequence
!= SHORT_WINDOW
)
1173 /* PNS preprocessing depending on ms processing: PNS not in Short Window! */
1174 FDKaacEnc_PreProcessPnsChannelPair(
1175 psyData
[0]->sfbActive
,
1176 (&psyData
[0]->sfbEnergy
)->Long
,
1177 (&psyData
[1]->sfbEnergy
)->Long
,
1178 psyOutChannel
[0]->sfbEnergyLdData
,
1179 psyOutChannel
[1]->sfbEnergyLdData
,
1180 psyData
[0]->sfbEnergyMS
.Long
,
1181 &(psyConf
[0].pnsConf
),
1185 FDKaacEnc_IntensityStereoProcessing(
1186 psyData
[0]->sfbEnergy
.Long
,
1187 psyData
[1]->sfbEnergy
.Long
,
1188 psyData
[0]->mdctSpectrum
,
1189 psyData
[1]->mdctSpectrum
,
1190 psyData
[0]->sfbThreshold
.Long
,
1191 psyData
[1]->sfbThreshold
.Long
,
1192 psyOutChannel
[1]->sfbThresholdLdData
,
1193 psyData
[0]->sfbSpreadEnergy
.Long
,
1194 psyData
[1]->sfbSpreadEnergy
.Long
,
1195 psyOutChannel
[0]->sfbEnergyLdData
,
1196 psyOutChannel
[1]->sfbEnergyLdData
,
1197 &psyOutElement
->toolsInfo
.msDigest
,
1198 psyOutElement
->toolsInfo
.msMask
,
1202 psyConf
[0].sfbOffset
,
1203 psyConf
[0].allowIS
&& commonWindow
,
1204 psyOutChannel
[1]->isBook
,
1205 psyOutChannel
[1]->isScale
,
1208 FDKaacEnc_MsStereoProcessing(
1211 psyOutChannel
[1]->isBook
,
1212 &psyOutElement
->toolsInfo
.msDigest
,
1213 psyOutElement
->toolsInfo
.msMask
,
1214 psyData
[0]->sfbActive
,
1215 psyData
[0]->sfbActive
,
1217 psyOutChannel
[0]->sfbOffsets
);
1219 /* PNS postprocessing */
1220 FDKaacEnc_PostProcessPnsChannelPair(psyData
[0]->sfbActive
,
1221 &(psyConf
[0].pnsConf
),
1224 psyOutElement
->toolsInfo
.msMask
,
1225 &psyOutElement
->toolsInfo
.msDigest
);
1228 FDKaacEnc_IntensityStereoProcessing(
1229 psyData
[0]->sfbEnergy
.Long
,
1230 psyData
[1]->sfbEnergy
.Long
,
1231 psyData
[0]->mdctSpectrum
,
1232 psyData
[1]->mdctSpectrum
,
1233 psyData
[0]->sfbThreshold
.Long
,
1234 psyData
[1]->sfbThreshold
.Long
,
1235 psyOutChannel
[1]->sfbThresholdLdData
,
1236 psyData
[0]->sfbSpreadEnergy
.Long
,
1237 psyData
[1]->sfbSpreadEnergy
.Long
,
1238 psyOutChannel
[0]->sfbEnergyLdData
,
1239 psyOutChannel
[1]->sfbEnergyLdData
,
1240 &psyOutElement
->toolsInfo
.msDigest
,
1241 psyOutElement
->toolsInfo
.msMask
,
1242 psyStatic
[0]->blockSwitchingControl
.noOfGroups
*hPsyConfShort
->sfbCnt
,
1245 psyData
[0]->groupedSfbOffset
,
1246 psyConf
[0].allowIS
&& commonWindow
,
1247 psyOutChannel
[1]->isBook
,
1248 psyOutChannel
[1]->isScale
,
1251 /* it's OK to pass the ".Long" arrays here. They contain grouped short data since FDKaacEnc_groupShortData() */
1252 FDKaacEnc_MsStereoProcessing( psyData
,
1254 psyOutChannel
[1]->isBook
,
1255 &psyOutElement
->toolsInfo
.msDigest
,
1256 psyOutElement
->toolsInfo
.msMask
,
1257 psyStatic
[0]->blockSwitchingControl
.noOfGroups
*hPsyConfShort
->sfbCnt
,
1258 hPsyConfShort
->sfbCnt
,
1260 psyOutChannel
[0]->sfbOffsets
);
1267 for(ch
=0;ch
<channels
;ch
++) {
1268 if (psyStatic
[ch
]->isLFE
) {
1270 for(sfb
= 0; sfb
< psyData
[ch
]->sfbActive
; sfb
++) {
1271 psyOutChannel
[ch
]->noiseNrg
[sfb
] = NO_NOISE_PNS
;
1275 FDKaacEnc_CodePnsChannel(psyData
[ch
]->sfbActive
,
1276 &(psyConf
[ch
].pnsConf
),
1277 pnsData
[ch
]->pnsFlag
,
1278 psyData
[ch
]->sfbEnergyLdData
.Long
,
1279 psyOutChannel
[ch
]->noiseNrg
, /* this is the energy that will be written to the bitstream */
1280 psyOutChannel
[ch
]->sfbThresholdLdData
);
1287 for(ch
=0;ch
<channels
;ch
++)
1291 psyOutChannel
[ch
]->maxSfbPerGroup
= maxSfbPerGroup
[ch
];
1292 psyOutChannel
[ch
]->mdctScale
= psyData
[ch
]->mdctScale
;
1294 if(isShortWindow
[ch
]==0) {
1296 psyOutChannel
[ch
]->sfbCnt
= hPsyConfLong
->sfbActive
;
1297 psyOutChannel
[ch
]->sfbPerGroup
= hPsyConfLong
->sfbActive
;
1298 psyOutChannel
[ch
]->lastWindowSequence
= psyStatic
[ch
]->blockSwitchingControl
.lastWindowSequence
;
1299 psyOutChannel
[ch
]->windowShape
= psyStatic
[ch
]->blockSwitchingControl
.windowShape
;
1302 INT sfbCnt
= psyStatic
[ch
]->blockSwitchingControl
.noOfGroups
*hPsyConfShort
->sfbCnt
;
1304 psyOutChannel
[ch
]->sfbCnt
= sfbCnt
;
1305 psyOutChannel
[ch
]->sfbPerGroup
= hPsyConfShort
->sfbCnt
;
1306 psyOutChannel
[ch
]->lastWindowSequence
= SHORT_WINDOW
;
1307 psyOutChannel
[ch
]->windowShape
= SINE_WINDOW
;
1310 /* generate grouping mask */
1312 for (grp
= 0; grp
< psyStatic
[ch
]->blockSwitchingControl
.noOfGroups
; grp
++)
1315 for (j
=1; j
<psyStatic
[ch
]->blockSwitchingControl
.groupLen
[grp
]; j
++) {
1316 mask
= (mask
<<1) | 1 ;
1319 psyOutChannel
[ch
]->groupingMask
= mask
;
1321 /* build interface */
1322 FDKmemcpy(psyOutChannel
[ch
]->groupLen
,psyStatic
[ch
]->blockSwitchingControl
.groupLen
,MAX_NO_OF_GROUPS
*sizeof(INT
));
1323 FDKmemcpy(psyOutChannel
[ch
]->sfbEnergy
,(&psyData
[ch
]->sfbEnergy
)->Long
, MAX_GROUPED_SFB
*sizeof(FIXP_DBL
));
1324 FDKmemcpy(psyOutChannel
[ch
]->sfbSpreadEnergy
,(&psyData
[ch
]->sfbSpreadEnergy
)->Long
, MAX_GROUPED_SFB
*sizeof(FIXP_DBL
));
1325 // FDKmemcpy(psyOutChannel[ch]->mdctSpectrum, psyData[ch]->mdctSpectrum, (1024)*sizeof(FIXP_DBL));
1332 void FDKaacEnc_PsyClose(PSY_INTERNAL
**phPsyInternal
,
1338 if(phPsyInternal
!=NULL
) {
1339 PSY_INTERNAL
*hPsyInternal
= *phPsyInternal
;
1343 for (i
=0; i
<(8); i
++) {
1344 if (hPsyInternal
->pStaticChannels
[i
]) {
1345 if (hPsyInternal
->pStaticChannels
[i
]->psyInputBuffer
)
1346 FreeRam_aacEnc_PsyInputBuffer(&hPsyInternal
->pStaticChannels
[i
]->psyInputBuffer
); /* AUDIO INPUT BUFFER */
1348 FreeRam_aacEnc_PsyStatic(&hPsyInternal
->pStaticChannels
[i
]); /* PSY_STATIC */
1352 for (i
=0; i
<(8); i
++) {
1353 if (hPsyInternal
->psyElement
[i
])
1354 FreeRam_aacEnc_PsyElement(&hPsyInternal
->psyElement
[i
]); /* PSY_ELEMENT */
1358 FreeRam_aacEnc_PsyInternal(phPsyInternal
);
1362 if (phPsyOut
!=NULL
) {
1363 for (n
=0; n
<(1); n
++) {
1366 for (i
=0; i
<(8); i
++) {
1367 if (phPsyOut
[n
]->pPsyOutChannels
[i
])
1368 FreeRam_aacEnc_PsyOutChannel(&phPsyOut
[n
]->pPsyOutChannels
[i
]); /* PSY_OUT_CHANNEL */
1371 for (i
=0; i
<(8); i
++) {
1372 if (phPsyOut
[n
]->psyOutElement
[i
])
1373 FreeRam_aacEnc_PsyOutElements(&phPsyOut
[n
]->psyOutElement
[i
]); /* PSY_OUT_ELEMENTS */
1376 FreeRam_aacEnc_PsyOut(&phPsyOut
[n
]);