adj_thr.cpp revision 2228e360595641dd906bf1773307f43d304f5b2e
1
2/* -----------------------------------------------------------------------------------------------------------
3Software License for The Fraunhofer FDK AAC Codec Library for Android
4
5� Copyright  1995 - 2012 Fraunhofer-Gesellschaft zur F�rderung der angewandten Forschung e.V.
6  All rights reserved.
7
8 1.    INTRODUCTION
9The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
10the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
11This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
12
13AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
14audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
15independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
16of the MPEG specifications.
17
18Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
19may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
20individually for the purpose of encoding or decoding bit streams in products that are compliant with
21the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
22these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
23software may already be covered under those patent licenses when it is used for those licensed purposes only.
24
25Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
26are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
27applications information and documentation.
28
292.    COPYRIGHT LICENSE
30
31Redistribution and use in source and binary forms, with or without modification, are permitted without
32payment of copyright license fees provided that you satisfy the following conditions:
33
34You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
35your modifications thereto in source code form.
36
37You must retain the complete text of this software license in the documentation and/or other materials
38provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
39You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
40modifications thereto to recipients of copies in binary form.
41
42The name of Fraunhofer may not be used to endorse or promote products derived from this library without
43prior written permission.
44
45You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
46software or your modifications thereto.
47
48Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
49and 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."
52
533.    NO PATENT LICENSE
54
55NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
56ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
57respect to this software.
58
59You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
60by appropriate patent licenses.
61
624.    DISCLAIMER
63
64This 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
66of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
67CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
68including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
69or business interruption, however caused and on any theory of liability, whether in contract, strict
70liability, or tort (including negligence), arising in any way out of the use of this software, even if
71advised of the possibility of such damage.
72
735.    CONTACT INFORMATION
74
75Fraunhofer Institute for Integrated Circuits IIS
76Attention: Audio and Multimedia Departments - FDK AAC LL
77Am Wolfsmantel 33
7891058 Erlangen, Germany
79
80www.iis.fraunhofer.de/amm
81amm-info@iis.fraunhofer.de
82----------------------------------------------------------------------------------------------------------- */
83
84/******************************** MPEG Audio Encoder **************************
85
86    Initial author:       M. Werner
87    contents/description: Threshold compensation
88
89******************************************************************************/
90
91#include "common_fix.h"
92
93#include "adj_thr_data.h"
94#include "adj_thr.h"
95#include "qc_data.h"
96#include "sf_estim.h"
97#include "aacEnc_ram.h"
98
99
100
101
102#define INV_INT_TAB_SIZE  (8)
103static const FIXP_DBL invInt[INV_INT_TAB_SIZE] =
104{
105  0x7fffffff, 0x7fffffff, 0x40000000, 0x2aaaaaaa, 0x20000000, 0x19999999, 0x15555555, 0x12492492
106};
107
108
109#define INV_SQRT4_TAB_SIZE  (8)
110static const FIXP_DBL invSqrt4[INV_SQRT4_TAB_SIZE] =
111{
112  0x7fffffff, 0x7fffffff, 0x6ba27e65, 0x61424bb5, 0x5a827999, 0x55994845, 0x51c8e33c, 0x4eb160d1
113};
114
115
116/*static const INT      invRedExp = 4;*/
117static const FIXP_DBL  SnrLdMin1 = (FIXP_DBL)0xfcad0ddf; /*FL2FXCONST_DBL(FDKlog(0.316)/FDKlog(2.0)/LD_DATA_SCALING);*/
118static const FIXP_DBL  SnrLdMin2 = (FIXP_DBL)0x0351e1a2; /*FL2FXCONST_DBL(FDKlog(3.16) /FDKlog(2.0)/LD_DATA_SCALING);*/
119static const FIXP_DBL  SnrLdFac  = (FIXP_DBL)0xff5b2c3e; /*FL2FXCONST_DBL(FDKlog(0.8)  /FDKlog(2.0)/LD_DATA_SCALING);*/
120
121static const FIXP_DBL  SnrLdMin3 = (FIXP_DBL)0xfe000000; /*FL2FXCONST_DBL(FDKlog(0.5)  /FDKlog(2.0)/LD_DATA_SCALING);*/
122static const FIXP_DBL  SnrLdMin4 = (FIXP_DBL)0x02000000; /*FL2FXCONST_DBL(FDKlog(2.0)  /FDKlog(2.0)/LD_DATA_SCALING);*/
123static const FIXP_DBL  SnrLdMin5 = (FIXP_DBL)0xfc000000; /*FL2FXCONST_DBL(FDKlog(0.25) /FDKlog(2.0)/LD_DATA_SCALING);*/
124
125
126/* values for avoid hole flag */
127enum _avoid_hole_state {
128    NO_AH              =0,
129    AH_INACTIVE        =1,
130    AH_ACTIVE          =2
131};
132
133
134/*  Q format definitions */
135#define Q_BITFAC    (24)   /* Q scaling used in FDKaacEnc_bitresCalcBitFac() calculation */
136#define Q_AVGBITS   (17)   /* scale bit values */
137
138static INT FDKaacEnc_bits2pe2(
139        const INT                 bits,
140        const FIXP_DBL            factor_m,
141        const INT                 factor_e
142        )
143{
144   return (INT)(fMult(factor_m, (FIXP_DBL)(bits<<Q_AVGBITS)) >> (Q_AVGBITS-factor_e));
145}
146
147/*****************************************************************************
148functionname: FDKaacEnc_calcThreshExp
149description:  loudness calculation (threshold to the power of redExp)
150*****************************************************************************/
151static void FDKaacEnc_calcThreshExp(FIXP_DBL thrExp[(2)][MAX_GROUPED_SFB],
152                          QC_OUT_CHANNEL*  qcOutChannel[(2)],
153                          PSY_OUT_CHANNEL*  psyOutChannel[(2)],
154                          const INT nChannels)
155{
156   INT ch, sfb, sfbGrp;
157   FIXP_DBL thrExpLdData;
158
159   for (ch=0; ch<nChannels; ch++) {
160     for(sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup) {
161       for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
162         thrExpLdData = psyOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb]>>2 ;
163         thrExp[ch][sfbGrp+sfb] = CalcInvLdData(thrExpLdData);
164       }
165     }
166   }
167}
168
169
170/*****************************************************************************
171    functionname: FDKaacEnc_adaptMinSnr
172    description:  reduce minSnr requirements for bands with relative low energies
173*****************************************************************************/
174static void FDKaacEnc_adaptMinSnr(QC_OUT_CHANNEL     *qcOutChannel[(2)],
175                                  PSY_OUT_CHANNEL    *psyOutChannel[(2)],
176                                  MINSNR_ADAPT_PARAM *msaParam,
177                                  const INT           nChannels)
178{
179  INT ch, sfb, sfbGrp, nSfb;
180  FIXP_DBL avgEnLD64, dbRatio, minSnrRed;
181  FIXP_DBL minSnrLimitLD64 = FL2FXCONST_DBL(-0.00503012648262f); /* ld64(0.8f) */
182  FIXP_DBL nSfbLD64;
183  FIXP_DBL accu;
184
185  for (ch=0; ch<nChannels; ch++) {
186    /* calc average energy per scalefactor band */
187    nSfb = 0;
188    accu = FL2FXCONST_DBL(0.0f);
189
190    for (sfbGrp=0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) {
191      for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
192        accu += psyOutChannel[ch]->sfbEnergy[sfbGrp+sfb]>>6;
193				 nSfb++;
194			 }
195    }
196
197    if ((accu == FL2FXCONST_DBL(0.0f)) || (nSfb == 0)) {
198      avgEnLD64 = FL2FXCONST_DBL(-1.0f);
199    }
200    else {
201      nSfbLD64  = CalcLdInt(nSfb);
202      avgEnLD64 = CalcLdData(accu);
203      avgEnLD64 = avgEnLD64 + FL2FXCONST_DBL(0.09375f) - nSfbLD64;  /* 0.09375f: compensate shift with 6 */
204    }
205
206    /* reduce minSnr requirement by minSnr^minSnrRed dependent on avgEn/sfbEn */
207    for (sfbGrp=0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) {
208      for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
209        if ( (msaParam->startRatio + qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb]) < avgEnLD64 ) {
210          dbRatio = fMult((avgEnLD64 - qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb]),FL2FXCONST_DBL(0.3010299956f)); /* scaled by (1.0f/(10.0f*64.0f)) */
211          minSnrRed = msaParam->redOffs + fMult(msaParam->redRatioFac,dbRatio); /* scaled by 1.0f/64.0f*/
212          minSnrRed = fixMax(minSnrRed, msaParam->maxRed); /* scaled by 1.0f/64.0f*/
213          qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb] = (fMult(qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb],minSnrRed)) << 6;
214          qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(minSnrLimitLD64, qcOutChannel[ch]->sfbMinSnrLdData[sfbGrp+sfb]);
215        }
216      }
217    }
218  }
219}
220
221
222/*****************************************************************************
223functionname: FDKaacEnc_initAvoidHoleFlag
224description:  determine bands where avoid hole is not necessary resp. possible
225*****************************************************************************/
226static void FDKaacEnc_initAvoidHoleFlag(QC_OUT_CHANNEL  *qcOutChannel[(2)],
227                              PSY_OUT_CHANNEL *psyOutChannel[(2)],
228                              UCHAR ahFlag[(2)][MAX_GROUPED_SFB],
229                              struct TOOLSINFO *toolsInfo,
230                              const INT nChannels,
231                              const PE_DATA *peData,
232                              AH_PARAM *ahParam)
233{
234   INT ch, sfb, sfbGrp;
235   FIXP_DBL sfbEn, sfbEnm1;
236   FIXP_DBL sfbEnLdData;
237   FIXP_DBL avgEnLdData;
238
239   /* decrease spread energy by 3dB for long blocks, resp. 2dB for shorts
240      (avoid more holes in long blocks) */
241   for (ch=0; ch<nChannels; ch++) {
242      INT sfbGrp, sfb;
243      QC_OUT_CHANNEL*  qcOutChan  = qcOutChannel[ch];
244
245      if (psyOutChannel[ch]->lastWindowSequence != SHORT_WINDOW) {
246         for (sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup)
247           for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++)
248              qcOutChan->sfbSpreadEnergy[sfbGrp+sfb] >>= 1 ;
249      }
250      else {
251         for (sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup)
252           for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++)
253              qcOutChan->sfbSpreadEnergy[sfbGrp+sfb] =
254                   fMult(FL2FXCONST_DBL(0.63f),
255                         qcOutChan->sfbSpreadEnergy[sfbGrp+sfb]) ;
256      }
257   }
258
259   /* increase minSnr for local peaks, decrease it for valleys */
260   if (ahParam->modifyMinSnr) {
261      for(ch=0; ch<nChannels; ch++) {
262         QC_OUT_CHANNEL*  qcOutChan  = qcOutChannel[ch];
263         for(sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup){
264            for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
265               FIXP_DBL sfbEnp1, avgEn;
266               if (sfb > 0)
267                  sfbEnm1 = qcOutChan->sfbEnergy[sfbGrp+sfb-1];
268               else
269                  sfbEnm1 = qcOutChan->sfbEnergy[sfbGrp+sfb];
270
271               if (sfb < psyOutChannel[ch]->maxSfbPerGroup-1)
272                  sfbEnp1 = qcOutChan->sfbEnergy[sfbGrp+sfb+1];
273               else
274                  sfbEnp1 = qcOutChan->sfbEnergy[sfbGrp+sfb];
275
276               avgEn = (sfbEnm1>>1) + (sfbEnp1>>1);
277               avgEnLdData = CalcLdData(avgEn);
278               sfbEn = qcOutChan->sfbEnergy[sfbGrp+sfb];
279               sfbEnLdData = qcOutChan->sfbEnergyLdData[sfbGrp+sfb];
280               /* peak ? */
281               if (sfbEn > avgEn) {
282                  FIXP_DBL tmpMinSnrLdData;
283                  if (psyOutChannel[ch]->lastWindowSequence==LONG_WINDOW)
284                     tmpMinSnrLdData = fixMax( SnrLdFac + (FIXP_DBL)(avgEnLdData - sfbEnLdData), (FIXP_DBL)SnrLdMin1 ) ;
285                  else
286                     tmpMinSnrLdData = fixMax( SnrLdFac + (FIXP_DBL)(avgEnLdData - sfbEnLdData), (FIXP_DBL)SnrLdMin3 ) ;
287
288                  qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] =
289                     fixMin(qcOutChan->sfbMinSnrLdData[sfbGrp+sfb], tmpMinSnrLdData);
290               }
291               /* valley ? */
292               if ( ((sfbEnLdData+(FIXP_DBL)SnrLdMin4) < (FIXP_DBL)avgEnLdData) && (sfbEn > FL2FXCONST_DBL(0.0)) ) {
293                  FIXP_DBL tmpMinSnrLdData = avgEnLdData - sfbEnLdData -(FIXP_DBL)SnrLdMin4 + qcOutChan->sfbMinSnrLdData[sfbGrp+sfb];
294                  tmpMinSnrLdData = fixMin((FIXP_DBL)SnrLdFac, tmpMinSnrLdData);
295                  qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(tmpMinSnrLdData,
296                        (FIXP_DBL)(qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + SnrLdMin2 ));
297               }
298            }
299         }
300      }
301   }
302
303   /* stereo: adapt the minimum requirements sfbMinSnr of mid and
304      side channels to avoid spending unnoticable bits */
305   if (nChannels == 2) {
306      QC_OUT_CHANNEL*  qcOutChanM  = qcOutChannel[0];
307      QC_OUT_CHANNEL*  qcOutChanS  = qcOutChannel[1];
308      PSY_OUT_CHANNEL*  psyOutChanM  = psyOutChannel[0];
309      for(sfbGrp = 0;sfbGrp < psyOutChanM->sfbCnt;sfbGrp+= psyOutChanM->sfbPerGroup){
310        for (sfb=0; sfb<psyOutChanM->maxSfbPerGroup; sfb++) {
311          if (toolsInfo->msMask[sfbGrp+sfb]) {
312             FIXP_DBL maxSfbEnLd = fixMax(qcOutChanM->sfbEnergyLdData[sfbGrp+sfb],qcOutChanS->sfbEnergyLdData[sfbGrp+sfb]);
313             FIXP_DBL maxThrLd, sfbMinSnrTmpLd;
314
315             if ( ((SnrLdMin5>>1) + (maxSfbEnLd>>1) + (qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb]>>1)) <= FL2FXCONST_DBL(-0.5f))
316               maxThrLd = FL2FXCONST_DBL(-1.0f) ;
317             else
318               maxThrLd = SnrLdMin5 + maxSfbEnLd + qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb];
319
320             if (qcOutChanM->sfbEnergy[sfbGrp+sfb] > FL2FXCONST_DBL(0.0f))
321               sfbMinSnrTmpLd = maxThrLd - qcOutChanM->sfbEnergyLdData[sfbGrp+sfb];
322             else
323               sfbMinSnrTmpLd = FL2FXCONST_DBL(0.0f);
324
325             qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb] = fixMax(qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb],sfbMinSnrTmpLd);
326
327             if (qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb] <= FL2FXCONST_DBL(0.0f))
328                qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(qcOutChanM->sfbMinSnrLdData[sfbGrp+sfb], (FIXP_DBL)SnrLdFac);
329
330             if (qcOutChanS->sfbEnergy[sfbGrp+sfb] > FL2FXCONST_DBL(0.0f))
331               sfbMinSnrTmpLd = maxThrLd - qcOutChanS->sfbEnergyLdData[sfbGrp+sfb];
332             else
333               sfbMinSnrTmpLd = FL2FXCONST_DBL(0.0f);
334
335             qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb] = fixMax(qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb],sfbMinSnrTmpLd);
336
337             if (qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb] <= FL2FXCONST_DBL(0.0f))
338                qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb] = fixMin(qcOutChanS->sfbMinSnrLdData[sfbGrp+sfb],(FIXP_DBL)SnrLdFac);
339
340             if (qcOutChanM->sfbEnergy[sfbGrp+sfb]>qcOutChanM->sfbSpreadEnergy[sfbGrp+sfb])
341                qcOutChanS->sfbSpreadEnergy[sfbGrp+sfb] =
342                   fMult(qcOutChanS->sfbEnergy[sfbGrp+sfb], FL2FXCONST_DBL(0.9f));
343
344             if (qcOutChanS->sfbEnergy[sfbGrp+sfb]>qcOutChanS->sfbSpreadEnergy[sfbGrp+sfb])
345                qcOutChanM->sfbSpreadEnergy[sfbGrp+sfb] =
346                   fMult(qcOutChanM->sfbEnergy[sfbGrp+sfb], FL2FXCONST_DBL(0.9f));
347          }
348        }
349      }
350   }
351
352   /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
353   for(ch=0; ch<nChannels; ch++) {
354      QC_OUT_CHANNEL  *qcOutChan  = qcOutChannel[ch];
355      PSY_OUT_CHANNEL  *psyOutChan  = psyOutChannel[ch];
356      for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
357        for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
358          if ((qcOutChan->sfbSpreadEnergy[sfbGrp+sfb] > qcOutChan->sfbEnergy[sfbGrp+sfb])
359              || (qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] > FL2FXCONST_DBL(0.0f))) {
360             ahFlag[ch][sfbGrp+sfb] = NO_AH;
361          }
362          else {
363             ahFlag[ch][sfbGrp+sfb] = AH_INACTIVE;
364          }
365        }
366      }
367   }
368}
369
370
371
372/**
373 * \brief  Calculate constants that do not change during successive pe calculations.
374 *
375 * \param peData                Pointer to structure containing PE data of current element.
376 * \param psyOutChannel         Pointer to PSY_OUT_CHANNEL struct holding nChannels elements.
377 * \param qcOutChannel          Pointer to QC_OUT_CHANNEL struct holding nChannels elements.
378 * \param nChannels             Number of channels in element.
379 * \param peOffset              Fixed PE offset defined while FDKaacEnc_AdjThrInit() depending on bitrate.
380 *
381 * \return  void
382 */
383static
384void FDKaacEnc_preparePe(PE_DATA *peData,
385               PSY_OUT_CHANNEL* psyOutChannel[(2)],
386               QC_OUT_CHANNEL* qcOutChannel[(2)],
387               const INT nChannels,
388               const INT peOffset)
389{
390    INT ch;
391
392    for(ch=0; ch<nChannels; ch++) {
393        PSY_OUT_CHANNEL *psyOutChan = psyOutChannel[ch];
394        FDKaacEnc_prepareSfbPe(&peData->peChannelData[ch],
395            psyOutChan->sfbEnergyLdData,
396            psyOutChan->sfbThresholdLdData,
397            qcOutChannel[ch]->sfbFormFactorLdData,
398            psyOutChan->sfbOffsets,
399            psyOutChan->sfbCnt,
400            psyOutChan->sfbPerGroup,
401            psyOutChan->maxSfbPerGroup);
402    }
403    peData->offset = peOffset;
404}
405
406/**
407 * \brief  Calculate weighting factor for threshold adjustment.
408 *
409 * Calculate weighting factor to be applied at energies and thresholds in ld64 format.
410 *
411 * \param peData,               Pointer to PE data in current element.
412 * \param psyOutChannel         Pointer to PSY_OUT_CHANNEL struct holding nChannels elements.
413 * \param qcOutChannel          Pointer to QC_OUT_CHANNEL struct holding nChannels elements.
414 * \param toolsInfo             Pointer to tools info struct of current element.
415 * \param adjThrStateElement    Pointer to ATS_ELEMENT holding enFacPatch states.
416 * \param nChannels             Number of channels in element.
417 * \param usePatchTool          Apply the weighting tool 0 (no) else (yes).
418 *
419 * \return  void
420 */
421static
422void FDKaacEnc_calcWeighting(PE_DATA *peData,
423               PSY_OUT_CHANNEL* psyOutChannel[(2)],
424               QC_OUT_CHANNEL* qcOutChannel[(2)],
425               struct TOOLSINFO *toolsInfo,
426               ATS_ELEMENT* adjThrStateElement,
427               const INT nChannels,
428               const INT usePatchTool)
429{
430    int ch, noShortWindowInFrame = TRUE;
431    INT exePatchM = 0;
432
433    for (ch=0; ch<nChannels; ch++) {
434        if (psyOutChannel[ch]->lastWindowSequence == SHORT_WINDOW) {
435            noShortWindowInFrame = FALSE;
436        }
437        FDKmemclear(qcOutChannel[ch]->sfbEnFacLd, MAX_GROUPED_SFB*sizeof(FIXP_DBL));
438    }
439
440    if (usePatchTool==0) {
441        return; /* tool is disabled */
442    }
443
444    for (ch=0; ch<nChannels; ch++) {
445
446        PSY_OUT_CHANNEL *psyOutChan = psyOutChannel[ch];
447
448        if (noShortWindowInFrame) { /* retain energy ratio between blocks of different length */
449
450            FIXP_DBL nrgSum14, nrgSum12, nrgSum34, nrgTotal;
451            FIXP_DBL nrgFacLd_14, nrgFacLd_12, nrgFacLd_34;
452            INT usePatch, exePatch;
453            int sfb, nLinesSum = 0;
454
455            nrgSum14 = nrgSum12 = nrgSum34 = nrgTotal = FL2FXCONST_DBL(0.f);
456
457            /* calculate flatness of audible spectrum, i.e. spectrum above masking threshold. */
458            for (sfb = 0; sfb < psyOutChan->sfbCnt; sfb++) {
459
460                FIXP_DBL nrgFac12 = CalcInvLdData(psyOutChan->sfbEnergyLdData[sfb]>>1);   /* nrg^(1/2) */
461                FIXP_DBL nrgFac14 = CalcInvLdData(psyOutChan->sfbEnergyLdData[sfb]>>2);   /* nrg^(1/4) */
462
463                /* maximal number of bands is 64, results scaling factor 6 */
464                nLinesSum += peData->peChannelData[ch].sfbNLines[sfb];                    /* relevant lines */
465                nrgTotal  += ( psyOutChan->sfbEnergy[sfb] >> 6 );                         /* sum up nrg */
466                nrgSum12  += ( nrgFac12 >> 6 );                                           /* sum up nrg^(2/4) */
467                nrgSum14  += ( nrgFac14 >> 6 );                                           /* sum up nrg^(1/4) */
468                nrgSum34  += ( fMult(nrgFac14, nrgFac12) >> 6 );                          /* sum up nrg^(3/4) */
469            }
470
471            nrgTotal = CalcLdData(nrgTotal);                                              /* get ld64 of total nrg */
472
473            nrgFacLd_14 = CalcLdData(nrgSum14) - nrgTotal;                                /* ld64(nrgSum14/nrgTotal) */
474            nrgFacLd_12 = CalcLdData(nrgSum12) - nrgTotal;                                /* ld64(nrgSum12/nrgTotal) */
475            nrgFacLd_34 = CalcLdData(nrgSum34) - nrgTotal;                                /* ld64(nrgSum34/nrgTotal) */
476
477            adjThrStateElement->chaosMeasureEnFac[ch] = FDKmax( FL2FXCONST_DBL(0.1875f), fDivNorm(nLinesSum,psyOutChan->sfbOffsets[psyOutChan->sfbCnt]) );
478
479            usePatch = (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.78125f));
480            exePatch = ((usePatch) && (adjThrStateElement->lastEnFacPatch[ch]));
481
482            for (sfb = 0; sfb < psyOutChan->sfbCnt; sfb++) {
483                INT sfbExePatch;
484
485                /* for MS coupled SFBs, also execute patch in side channel if done in mid channel */
486                if ((ch == 1) && (toolsInfo->msMask[sfb])) {
487                    sfbExePatch = exePatchM;
488                }
489                else {
490                    sfbExePatch = exePatch;
491                }
492
493                if ( (sfbExePatch) && (psyOutChan->sfbEnergy[sfb]>FL2FXCONST_DBL(0.f)) )
494                {
495                    /* execute patch based on spectral flatness calculated above */
496                    if (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.8125f)) {
497                        qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_14 + (psyOutChan->sfbEnergyLdData[sfb]+(psyOutChan->sfbEnergyLdData[sfb]>>1)))>>1 ); /* sfbEnergy^(3/4) */
498                    }
499                    else if (adjThrStateElement->chaosMeasureEnFac[ch] > FL2FXCONST_DBL(0.796875f)) {
500                        qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_12 + psyOutChan->sfbEnergyLdData[sfb])>>1 );          /* sfbEnergy^(2/4) */
501                    }
502                    else {
503                        qcOutChannel[ch]->sfbEnFacLd[sfb] = ( (nrgFacLd_34 + (psyOutChan->sfbEnergyLdData[sfb]>>1))>>1 );     /* sfbEnergy^(1/4) */
504                    }
505                    qcOutChannel[ch]->sfbEnFacLd[sfb] = fixMin(qcOutChannel[ch]->sfbEnFacLd[sfb],(FIXP_DBL)0);
506
507                }
508            } /* sfb loop */
509
510            adjThrStateElement->lastEnFacPatch[ch] = usePatch;
511            exePatchM = exePatch;
512        }
513        else {
514            /* !noShortWindowInFrame */
515            adjThrStateElement->chaosMeasureEnFac[ch] = FL2FXCONST_DBL(0.75f);
516            adjThrStateElement->lastEnFacPatch[ch] = TRUE; /* allow use of sfbEnFac patch in upcoming frame */
517        }
518
519    } /* ch loop */
520
521}
522
523
524
525
526/*****************************************************************************
527functionname: FDKaacEnc_calcPe
528description:  calculate pe for both channels
529*****************************************************************************/
530static
531void FDKaacEnc_calcPe(PSY_OUT_CHANNEL* psyOutChannel[(2)],
532            QC_OUT_CHANNEL* qcOutChannel[(2)],
533            PE_DATA *peData,
534            const INT nChannels)
535{
536   INT ch;
537
538   peData->pe = peData->offset;
539   peData->constPart = 0;
540   peData->nActiveLines = 0;
541   for(ch=0; ch<nChannels; ch++) {
542      PE_CHANNEL_DATA *peChanData = &peData->peChannelData[ch];
543      FDKaacEnc_calcSfbPe(&peData->peChannelData[ch],
544                qcOutChannel[ch]->sfbWeightedEnergyLdData,
545                qcOutChannel[ch]->sfbThresholdLdData,
546                psyOutChannel[ch]->sfbCnt,
547                psyOutChannel[ch]->sfbPerGroup,
548                psyOutChannel[ch]->maxSfbPerGroup,
549                psyOutChannel[ch]->isBook,
550                psyOutChannel[ch]->isScale);
551
552      peData->pe += peChanData->pe;
553      peData->constPart += peChanData->constPart;
554      peData->nActiveLines += peChanData->nActiveLines;
555   }
556}
557
558void FDKaacEnc_peCalculation(PE_DATA *peData,
559                             PSY_OUT_CHANNEL* psyOutChannel[(2)],
560                             QC_OUT_CHANNEL* qcOutChannel[(2)],
561                             struct TOOLSINFO *toolsInfo,
562                             ATS_ELEMENT* adjThrStateElement,
563                             const INT nChannels)
564{
565  /* constants that will not change during successive pe calculations */
566  FDKaacEnc_preparePe(peData, psyOutChannel, qcOutChannel, nChannels, adjThrStateElement->peOffset);
567
568  /* calculate weighting factor for threshold adjustment */
569  FDKaacEnc_calcWeighting(peData, psyOutChannel, qcOutChannel, toolsInfo, adjThrStateElement, nChannels, 1);
570{
571    /* no weighting of threholds and energies for mlout */
572    /* weight energies and thresholds */
573    int ch;
574    for (ch=0; ch<nChannels; ch++) {
575
576        int sfb, sfbGrp;
577        QC_OUT_CHANNEL* pQcOutCh = qcOutChannel[ch];
578
579        for (sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) {
580          for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
581            pQcOutCh->sfbWeightedEnergyLdData[sfb+sfbGrp] = pQcOutCh->sfbEnergyLdData[sfb+sfbGrp] - pQcOutCh->sfbEnFacLd[sfb+sfbGrp];
582            pQcOutCh->sfbThresholdLdData[sfb+sfbGrp]     -= pQcOutCh->sfbEnFacLd[sfb+sfbGrp];
583          }
584        }
585    }
586}
587
588  /* pe without reduction */
589  FDKaacEnc_calcPe(psyOutChannel, qcOutChannel, peData, nChannels);
590}
591
592
593
594/*****************************************************************************
595functionname: FDKaacEnc_FDKaacEnc_calcPeNoAH
596description:  sum the pe data only for bands where avoid hole is inactive
597*****************************************************************************/
598static void FDKaacEnc_FDKaacEnc_calcPeNoAH(INT *pe,
599                       INT *constPart,
600                       INT    *nActiveLines,
601                       PE_DATA *peData,
602                       UCHAR ahFlag[(2)][MAX_GROUPED_SFB],
603                       PSY_OUT_CHANNEL* psyOutChannel[(2)],
604                       const INT nChannels)
605{
606    INT ch, sfb,sfbGrp;
607
608    INT pe_tmp = peData->offset;
609    INT constPart_tmp = 0;
610    INT nActiveLines_tmp = 0;
611    for(ch=0; ch<nChannels; ch++) {
612        PE_CHANNEL_DATA *peChanData = &peData->peChannelData[ch];
613        for(sfbGrp = 0;sfbGrp < psyOutChannel[ch]->sfbCnt;sfbGrp+= psyOutChannel[ch]->sfbPerGroup){
614            for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
615                if(ahFlag[ch][sfbGrp+sfb] < AH_ACTIVE) {
616                    pe_tmp += peChanData->sfbPe[sfbGrp+sfb];
617                    constPart_tmp += peChanData->sfbConstPart[sfbGrp+sfb];
618                    nActiveLines_tmp += peChanData->sfbNActiveLines[sfbGrp+sfb];
619                }
620            }
621        }
622    }
623    /* correct scaled pe and constPart values */
624    *pe = pe_tmp >> PE_CONSTPART_SHIFT;
625    *constPart = constPart_tmp >> PE_CONSTPART_SHIFT;
626
627	*nActiveLines = nActiveLines_tmp;
628}
629
630
631/*****************************************************************************
632functionname: FDKaacEnc_reduceThresholdsCBR
633description:  apply reduction formula
634*****************************************************************************/
635static const FIXP_DBL limitThrReducedLdData = (FIXP_DBL)0x00008000; /*FL2FXCONST_DBL(FDKpow(2.0,-LD_DATA_SCALING/4.0));*/
636
637static void FDKaacEnc_reduceThresholdsCBR(QC_OUT_CHANNEL*  qcOutChannel[(2)],
638                                PSY_OUT_CHANNEL* psyOutChannel[(2)],
639                                UCHAR ahFlag[(2)][MAX_GROUPED_SFB],
640                                FIXP_DBL thrExp[(2)][MAX_GROUPED_SFB],
641                                const INT nChannels,
642                                const FIXP_DBL redVal,
643                                const SCHAR redValScaling)
644{
645   INT ch, sfb, sfbGrp;
646   FIXP_DBL sfbEnLdData, sfbThrLdData, sfbThrReducedLdData;
647   FIXP_DBL sfbThrExp;
648
649    for(ch=0; ch<nChannels; ch++) {
650      QC_OUT_CHANNEL *qcOutChan = qcOutChannel[ch];
651      for(sfbGrp = 0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+= psyOutChannel[ch]->sfbPerGroup){
652        for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
653         sfbEnLdData  = qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb];
654         sfbThrLdData = qcOutChan->sfbThresholdLdData[sfbGrp+sfb];
655         sfbThrExp    = thrExp[ch][sfbGrp+sfb];
656         if ((sfbEnLdData > sfbThrLdData) && (ahFlag[ch][sfbGrp+sfb] != AH_ACTIVE)) {
657
658            /* threshold reduction formula:
659             float tmp = thrExp[ch][sfb]+redVal;
660             tmp *= tmp;
661             sfbThrReduced = tmp*tmp;
662            */
663            int minScale = fixMin(CountLeadingBits(sfbThrExp), CountLeadingBits(redVal) - (DFRACT_BITS-1-redValScaling) )-1;
664
665            /* 4*log( sfbThrExp + redVal ) */
666            sfbThrReducedLdData = CalcLdData(fAbs(scaleValue(sfbThrExp, minScale) + scaleValue(redVal,(DFRACT_BITS-1-redValScaling)+minScale)))
667                                             - (FIXP_DBL)(minScale<<(DFRACT_BITS-1-LD_DATA_SHIFT));
668            sfbThrReducedLdData <<= 2;
669
670            /* avoid holes */
671            if ( ((sfbThrReducedLdData - sfbEnLdData) > qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] )
672                    && (ahFlag[ch][sfbGrp+sfb] != NO_AH) )
673            {
674              if (qcOutChan->sfbMinSnrLdData[sfbGrp+sfb]  > (FL2FXCONST_DBL(-1.0f) - sfbEnLdData) ){
675                   sfbThrReducedLdData = fixMax((qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + sfbEnLdData), sfbThrLdData);
676              }
677              else sfbThrReducedLdData = sfbThrLdData;
678              ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE;
679            }
680
681            /* minimum of 29 dB Ratio for Thresholds */
682            if ((sfbEnLdData+(FIXP_DBL)MAXVAL_DBL) > FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING)){
683                sfbThrReducedLdData = fixMax(sfbThrReducedLdData, (sfbEnLdData - FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING)));
684            }
685
686            qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = sfbThrReducedLdData;
687         }
688        }
689      }
690   }
691}
692
693/* similar to prepareSfbPe1() */
694static FIXP_DBL FDKaacEnc_calcChaosMeasure(PSY_OUT_CHANNEL *psyOutChannel,
695                                 const FIXP_DBL  *sfbFormFactorLdData)
696{
697  #define SCALE_FORM_FAC     (4)    /* (SCALE_FORM_FAC+FORM_FAC_SHIFT) >= ld(FRAME_LENGTH)*/
698  #define SCALE_NRGS         (8)
699  #define SCALE_NLINES      (16)
700  #define SCALE_NRGS_SQRT4   (2)    /* 0.25 * SCALE_NRGS */
701  #define SCALE_NLINES_P34  (12)    /* 0.75 * SCALE_NLINES */
702
703  INT   sfbGrp, sfb;
704  FIXP_DBL chaosMeasure;
705  INT frameNLines = 0;
706  FIXP_DBL frameFormFactor = FL2FXCONST_DBL(0.f);
707  FIXP_DBL frameEnergy = FL2FXCONST_DBL(0.f);
708
709  for (sfbGrp=0; sfbGrp<psyOutChannel->sfbCnt; sfbGrp+=psyOutChannel->sfbPerGroup) {
710    for (sfb=0; sfb<psyOutChannel->maxSfbPerGroup; sfb++){
711      if (psyOutChannel->sfbEnergyLdData[sfbGrp+sfb] > psyOutChannel->sfbThresholdLdData[sfbGrp+sfb]) {
712        frameFormFactor += (CalcInvLdData(sfbFormFactorLdData[sfbGrp+sfb])>>SCALE_FORM_FAC);
713        frameNLines     += (psyOutChannel->sfbOffsets[sfbGrp+sfb+1] - psyOutChannel->sfbOffsets[sfbGrp+sfb]);
714        frameEnergy     += (psyOutChannel->sfbEnergy[sfbGrp+sfb]>>SCALE_NRGS);
715      }
716    }
717  }
718
719  if(frameNLines > 0){
720
721    /*  frameNActiveLines = frameFormFactor*2^FORM_FAC_SHIFT * ((frameEnergy *2^SCALE_NRGS)/frameNLines)^-0.25
722        chaosMeasure      = frameNActiveLines / frameNLines */
723    chaosMeasure =
724           CalcInvLdData( (((CalcLdData(frameFormFactor)>>1) -
725                            (CalcLdData(frameEnergy)>>(2+1))) -
726                           (fMultDiv2(FL2FXCONST_DBL(0.75f),CalcLdData((FIXP_DBL)frameNLines<<(DFRACT_BITS-1-SCALE_NLINES))) -
727                            (((FIXP_DBL)(SCALE_FORM_FAC-SCALE_NRGS_SQRT4+FORM_FAC_SHIFT-(SCALE_NLINES_P34))<<(DFRACT_BITS-1-LD_DATA_SHIFT))>>1))
728                          )<<1 );
729  } else {
730
731    /* assuming total chaos, if no sfb is above thresholds */
732    chaosMeasure = FL2FXCONST_DBL(1.f);
733  }
734
735  return chaosMeasure;
736}
737
738
739/* apply reduction formula for VBR-mode */
740static void FDKaacEnc_reduceThresholdsVBR(QC_OUT_CHANNEL* qcOutChannel[(2)],
741                                PSY_OUT_CHANNEL* psyOutChannel[(2)],
742                                UCHAR ahFlag[(2)][MAX_GROUPED_SFB],
743                                FIXP_DBL thrExp[(2)][MAX_GROUPED_SFB],
744                                const INT nChannels,
745                                const FIXP_DBL  vbrQualFactor,
746                                FIXP_DBL* chaosMeasureOld)
747{
748  INT ch, sfbGrp, sfb;
749  FIXP_DBL chGroupEnergy[TRANS_FAC][2];/*energy for each group and channel*/
750  FIXP_DBL chChaosMeasure[2];
751  FIXP_DBL frameEnergy = FL2FXCONST_DBL(1e-10f);
752  FIXP_DBL chaosMeasure = FL2FXCONST_DBL(0.f);
753  FIXP_DBL sfbEnLdData, sfbThrLdData, sfbThrExp;
754  FIXP_DBL sfbThrReducedLdData;
755  FIXP_DBL chaosMeasureAvg;
756  INT groupCnt; /* loop counter */
757  FIXP_DBL redVal[TRANS_FAC]; /* reduction values; in short-block case one redVal for each group */
758  QC_OUT_CHANNEL  *qcOutChan  = NULL;
759  PSY_OUT_CHANNEL  *psyOutChan  = NULL;
760
761#define SCALE_GROUP_ENERGY   (8)
762
763#define CONST_CHAOS_MEAS_AVG_FAC_0  (FL2FXCONST_DBL(0.25f))
764#define CONST_CHAOS_MEAS_AVG_FAC_1  (FL2FXCONST_DBL(1.f-0.25f))
765
766#define MIN_LDTHRESH                (FL2FXCONST_DBL(-0.515625f))
767
768
769  for(ch=0; ch<nChannels; ch++){
770    qcOutChan  = qcOutChannel[ch];
771    psyOutChan  = psyOutChannel[ch];
772
773    /* adding up energy for each channel and each group separately */
774    FIXP_DBL chEnergy = FL2FXCONST_DBL(0.f);
775    groupCnt=0;
776
777    for (sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup, groupCnt++) {
778      chGroupEnergy[groupCnt][ch] = FL2FXCONST_DBL(0.f);
779      for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++){
780        chGroupEnergy[groupCnt][ch] += (psyOutChan->sfbEnergy[sfbGrp+sfb]>>SCALE_GROUP_ENERGY);
781      }
782      chEnergy += chGroupEnergy[groupCnt][ch];
783    }
784    frameEnergy += chEnergy;
785
786    /* chaosMeasure */
787    if (psyOutChannel[0]->lastWindowSequence == SHORT_WINDOW) {
788      chChaosMeasure[ch] = FL2FXCONST_DBL(0.5f); /* assume a constant chaos measure of 0.5f for short blocks */
789    } else {
790      chChaosMeasure[ch] = FDKaacEnc_calcChaosMeasure(psyOutChannel[ch], qcOutChannel[ch]->sfbFormFactorLdData);
791    }
792    chaosMeasure += fMult(chChaosMeasure[ch], chEnergy);
793  }
794
795  if(frameEnergy > chaosMeasure) {
796    INT scale = CntLeadingZeros(frameEnergy) - 1;
797    FIXP_DBL num   = chaosMeasure<<scale;
798    FIXP_DBL denum = frameEnergy<<scale;
799    chaosMeasure   = schur_div(num,denum,16);
800  }
801  else {
802    chaosMeasure = FL2FXCONST_DBL(1.f);
803  }
804
805  chaosMeasureAvg = fMult(CONST_CHAOS_MEAS_AVG_FAC_0, chaosMeasure) +
806                    fMult(CONST_CHAOS_MEAS_AVG_FAC_1, *chaosMeasureOld);      /* averaging chaos measure */
807  *chaosMeasureOld = chaosMeasure = (fixMin(chaosMeasure, chaosMeasureAvg));  /* use min-value, safe for next frame */
808
809  /* characteristic curve
810     chaosMeasure = 0.2f + 0.7f/0.3f * (chaosMeasure - 0.2f);
811     chaosMeasure = fixMin(1.0f, fixMax(0.1f, chaosMeasure));
812     constants scaled by 4.f
813  */
814  chaosMeasure = ((FL2FXCONST_DBL(0.2f)>>2) + fMult(FL2FXCONST_DBL(0.7f/(4.f*0.3f)), (chaosMeasure - FL2FXCONST_DBL(0.2f))));
815  chaosMeasure = (fixMin((FIXP_DBL)(FL2FXCONST_DBL(1.0f)>>2), fixMax((FIXP_DBL)(FL2FXCONST_DBL(0.1f)>>2), chaosMeasure)))<<2;
816
817  /* calculation of reduction value */
818  if (psyOutChannel[0]->lastWindowSequence == SHORT_WINDOW){ /* short-blocks */
819    FDK_ASSERT(TRANS_FAC==8);
820    #define   WIN_TYPE_SCALE   (3)
821
822    INT sfbGrp, groupCnt=0;
823    for (sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup,groupCnt++) {
824
825      FIXP_DBL groupEnergy = FL2FXCONST_DBL(0.f);
826
827      for(ch=0;ch<nChannels;ch++){
828        groupEnergy += chGroupEnergy[groupCnt][ch];   /* adding up the channels groupEnergy */
829      }
830
831      FDK_ASSERT(psyOutChannel[0]->groupLen[groupCnt]<=INV_INT_TAB_SIZE);
832      groupEnergy = fMult(groupEnergy,invInt[psyOutChannel[0]->groupLen[groupCnt]]);  /* correction of group energy */
833      groupEnergy = fixMin(groupEnergy, frameEnergy>>WIN_TYPE_SCALE);                 /* do not allow an higher redVal as calculated framewise */
834
835      groupEnergy>>=2; /* 2*WIN_TYPE_SCALE = 6 => 6+2 = 8 ==> 8/4 = int number */
836
837      redVal[groupCnt] = fMult(fMult(vbrQualFactor,chaosMeasure),
838                               CalcInvLdData(CalcLdData(groupEnergy)>>2) )
839                         << (int)( ( 2 + (2*WIN_TYPE_SCALE) + SCALE_GROUP_ENERGY )>>2 ) ;
840
841    }
842  } else { /* long-block */
843
844    redVal[0] = fMult( fMult(vbrQualFactor,chaosMeasure),
845                       CalcInvLdData(CalcLdData(frameEnergy)>>2) )
846                << (int)( SCALE_GROUP_ENERGY>>2 ) ;
847  }
848
849  for(ch=0; ch<nChannels; ch++) {
850    qcOutChan  = qcOutChannel[ch];
851    psyOutChan  = psyOutChannel[ch];
852
853    for (sfbGrp=0; sfbGrp<psyOutChan->sfbCnt; sfbGrp+=psyOutChan->sfbPerGroup) {
854      for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++){
855
856        sfbEnLdData  = (qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb]);
857        sfbThrLdData = (qcOutChan->sfbThresholdLdData[sfbGrp+sfb]);
858        sfbThrExp    = thrExp[ch][sfbGrp+sfb];
859
860        if ( (sfbThrLdData>=MIN_LDTHRESH) && (sfbEnLdData > sfbThrLdData) && (ahFlag[ch][sfbGrp+sfb] != AH_ACTIVE)) {
861
862          /* Short-Window */
863          if (psyOutChannel[ch]->lastWindowSequence == SHORT_WINDOW) {
864            const int groupNumber = (int) sfb/psyOutChan->sfbPerGroup;
865
866            FDK_ASSERT(INV_SQRT4_TAB_SIZE>psyOutChan->groupLen[groupNumber]);
867
868            sfbThrExp = fMult(sfbThrExp, fMult( FL2FXCONST_DBL(2.82f/4.f), invSqrt4[psyOutChan->groupLen[groupNumber]]))<<2 ;
869
870            if ( sfbThrExp <= (limitThrReducedLdData-redVal[groupNumber]) ) {
871                sfbThrReducedLdData = FL2FXCONST_DBL(-1.0f);
872            }
873            else {
874                if ((FIXP_DBL)redVal[groupNumber] >= FL2FXCONST_DBL(1.0f)-sfbThrExp)
875                    sfbThrReducedLdData = FL2FXCONST_DBL(0.0f);
876                else {
877                    /* threshold reduction formula */
878                    sfbThrReducedLdData = CalcLdData(sfbThrExp + redVal[groupNumber]);
879                    sfbThrReducedLdData <<= 2;
880                }
881            }
882            sfbThrReducedLdData += ( CalcLdInt(psyOutChan->groupLen[groupNumber]) -
883                                     ((FIXP_DBL)6<<(DFRACT_BITS-1-LD_DATA_SHIFT)) );
884          }
885
886          /* Long-Window */
887          else {
888            if ((FIXP_DBL)redVal[0] >= FL2FXCONST_DBL(1.0f)-sfbThrExp) {
889              sfbThrReducedLdData = FL2FXCONST_DBL(0.0f);
890            }
891            else {
892              /* threshold reduction formula */
893              sfbThrReducedLdData = CalcLdData(sfbThrExp + redVal[0]);
894              sfbThrReducedLdData <<= 2;
895            }
896          }
897
898          /* avoid holes */
899          if ( ((sfbThrReducedLdData - sfbEnLdData) > qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] )
900                  && (ahFlag[ch][sfbGrp+sfb] != NO_AH) )
901          {
902            if (qcOutChan->sfbMinSnrLdData[sfbGrp+sfb]  > (FL2FXCONST_DBL(-1.0f) - sfbEnLdData) ){
903                 sfbThrReducedLdData = fixMax((qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + sfbEnLdData), sfbThrLdData);
904            }
905            else sfbThrReducedLdData = sfbThrLdData;
906            ahFlag[ch][sfbGrp+sfb] = AH_ACTIVE;
907          }
908
909          if (sfbThrReducedLdData<FL2FXCONST_DBL(-0.5f))
910               sfbThrReducedLdData = FL2FXCONST_DBL(-1.f);
911
912          /* minimum of 29 dB Ratio for Thresholds */
913          if ((sfbEnLdData+FL2FXCONST_DBL(1.0f)) > FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING)){
914            sfbThrReducedLdData = fixMax(sfbThrReducedLdData, sfbEnLdData - FL2FXCONST_DBL(9.6336206/LD_DATA_SCALING));
915          }
916
917          sfbThrReducedLdData = fixMax(MIN_LDTHRESH,sfbThrReducedLdData);
918
919          qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = sfbThrReducedLdData;
920        }
921      }
922    }
923  }
924}
925
926
927/*****************************************************************************
928functionname: FDKaacEnc_correctThresh
929description:  if pe difference deltaPe between desired pe and real pe is small enough,
930the difference can be distributed among the scale factor bands.
931New thresholds can be derived from this pe-difference
932*****************************************************************************/
933static void FDKaacEnc_correctThresh(CHANNEL_MAPPING* cm,
934                          QC_OUT_ELEMENT*  qcElement[(6)],
935                          PSY_OUT_ELEMENT* psyOutElement[(6)],
936                          UCHAR            ahFlag[(6)][(2)][MAX_GROUPED_SFB],
937                          FIXP_DBL         thrExp[(6)][(2)][MAX_GROUPED_SFB],
938                          const            FIXP_DBL redVal[(6)],
939                          const            SCHAR redValScaling[(6)],
940                          const            INT deltaPe,
941                          const            INT processElements,
942                          const            INT elementOffset)
943{
944   INT ch, sfb, sfbGrp;
945   QC_OUT_CHANNEL *qcOutChan;
946   PSY_OUT_CHANNEL *psyOutChan;
947   PE_CHANNEL_DATA *peChanData;
948   FIXP_DBL thrFactorLdData;
949   FIXP_DBL sfbEnLdData, sfbThrLdData, sfbThrReducedLdData;
950   FIXP_DBL *sfbPeFactorsLdData[(6)][(2)];
951   FIXP_DBL sfbNActiveLinesLdData[(2)][MAX_GROUPED_SFB];
952   INT      normFactorInt;
953   FIXP_DBL normFactorLdData;
954
955   INT nElements = elementOffset+processElements;
956   INT elementId;
957
958   /* scratch is empty; use temporal memory from quantSpec in QC_OUT_CHANNEL */
959   for(elementId=elementOffset;elementId<nElements;elementId++) {
960     for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
961       SHORT* ptr = qcElement[elementId]->qcOutChannel[ch]->quantSpec;
962       sfbPeFactorsLdData[elementId][ch] = (FIXP_DBL*)ptr;
963     }
964   }
965
966   /* for each sfb calc relative factors for pe changes */
967   normFactorInt = 0;
968
969   for(elementId=elementOffset;elementId<nElements;elementId++) {
970     if (cm->elInfo[elementId].elType != ID_DSE) {
971
972       for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
973
974          qcOutChan = qcElement[elementId]->qcOutChannel[ch];
975          psyOutChan = psyOutElement[elementId]->psyOutChannel[ch];
976          peChanData = &qcElement[elementId]->peData.peChannelData[ch];
977
978          for(sfbGrp = 0; sfbGrp < psyOutChan->sfbCnt; sfbGrp+= psyOutChan->sfbPerGroup){
979            for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
980
981             if ( peChanData->sfbNActiveLines[sfbGrp+sfb] == 0 ) {
982                sfbNActiveLinesLdData[ch][sfbGrp+sfb] = FL2FXCONST_DBL(-1.0f);
983             }
984             else {
985                /* Both CalcLdInt and CalcLdData can be used!
986                 * No offset has to be subtracted, because sfbNActiveLinesLdData
987                 * is shorted while thrFactor calculation */
988                sfbNActiveLinesLdData[ch][sfbGrp+sfb] = CalcLdInt(peChanData->sfbNActiveLines[sfbGrp+sfb]);
989             }
990             if ( ((ahFlag[elementId][ch][sfbGrp+sfb] < AH_ACTIVE) || (deltaPe > 0)) &&
991                   peChanData->sfbNActiveLines[sfbGrp+sfb] != 0 )
992             {
993                if (thrExp[elementId][ch][sfbGrp+sfb] > -redVal[elementId]) {
994
995                   /* sfbPeFactors[ch][sfbGrp+sfb] = peChanData->sfbNActiveLines[sfbGrp+sfb] /
996                                     (thrExp[elementId][ch][sfbGrp+sfb] + redVal[elementId]); */
997
998                   int minScale = fixMin(CountLeadingBits(thrExp[elementId][ch][sfbGrp+sfb]), CountLeadingBits(redVal[elementId]) - (DFRACT_BITS-1-redValScaling[elementId]) ) - 1;
999
1000                   /* sumld = ld64( sfbThrExp + redVal ) */
1001                   FIXP_DBL sumLd = CalcLdData(scaleValue(thrExp[elementId][ch][sfbGrp+sfb], minScale) + scaleValue(redVal[elementId], (DFRACT_BITS-1-redValScaling[elementId])+minScale))
1002                                               - (FIXP_DBL)(minScale<<(DFRACT_BITS-1-LD_DATA_SHIFT));
1003
1004                   if (sumLd < FL2FXCONST_DBL(0.f)) {
1005                      sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb] - sumLd;
1006                   }
1007                   else {
1008                     if ( sfbNActiveLinesLdData[ch][sfbGrp+sfb] > (FL2FXCONST_DBL(-1.f) + sumLd) ) {
1009                       sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb] - sumLd;
1010                     }
1011                     else {
1012                      sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = sfbNActiveLinesLdData[ch][sfbGrp+sfb];
1013                     }
1014                   }
1015
1016                   normFactorInt += (INT)CalcInvLdData(sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb]);
1017                }
1018                else sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = FL2FXCONST_DBL(1.0f);
1019             }
1020             else sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] = FL2FXCONST_DBL(-1.0f);
1021            }
1022          }
1023       }
1024     }
1025   }
1026
1027   /* normFactorLdData = ld64(deltaPe/normFactorInt) */
1028   normFactorLdData = CalcLdData((FIXP_DBL)((deltaPe<0) ? (-deltaPe) : (deltaPe))) - CalcLdData((FIXP_DBL)normFactorInt);
1029
1030   /* distribute the pe difference to the scalefactors
1031      and calculate the according thresholds */
1032   for(elementId=elementOffset;elementId<nElements;elementId++) {
1033     if (cm->elInfo[elementId].elType != ID_DSE) {
1034
1035       for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
1036          qcOutChan = qcElement[elementId]->qcOutChannel[ch];
1037          psyOutChan = psyOutElement[elementId]->psyOutChannel[ch];
1038          peChanData = &qcElement[elementId]->peData.peChannelData[ch];
1039
1040          for(sfbGrp = 0;sfbGrp < psyOutChan->sfbCnt;sfbGrp+= psyOutChan->sfbPerGroup){
1041            for (sfb=0; sfb<psyOutChan->maxSfbPerGroup; sfb++) {
1042
1043              if (peChanData->sfbNActiveLines[sfbGrp+sfb] > 0) {
1044
1045                 /* pe difference for this sfb */
1046                 if ( (sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb]==FL2FXCONST_DBL(-1.0f)) ||
1047                      (deltaPe==0) )
1048                 {
1049                   thrFactorLdData = FL2FXCONST_DBL(0.f);
1050                 }
1051                 else {
1052                   /* new threshold */
1053                   FIXP_DBL tmp = CalcInvLdData(sfbPeFactorsLdData[elementId][ch][sfbGrp+sfb] + normFactorLdData - sfbNActiveLinesLdData[ch][sfbGrp+sfb] - FL2FXCONST_DBL((float)LD_DATA_SHIFT/LD_DATA_SCALING));
1054
1055                   /* limit thrFactor to 60dB */
1056                   tmp = (deltaPe<0) ? tmp : (-tmp);
1057                   thrFactorLdData = FDKmin(tmp, FL2FXCONST_DBL(20.f/LD_DATA_SCALING));
1058                 }
1059
1060                 /* new threshold */
1061                 sfbThrLdData = qcOutChan->sfbThresholdLdData[sfbGrp+sfb];
1062                 sfbEnLdData  = qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb];
1063
1064                 if (thrFactorLdData < FL2FXCONST_DBL(0.f)) {
1065                   if( sfbThrLdData > (FL2FXCONST_DBL(-1.f)-thrFactorLdData) ) {
1066                     sfbThrReducedLdData = sfbThrLdData + thrFactorLdData;
1067                   }
1068                   else {
1069                     sfbThrReducedLdData = FL2FXCONST_DBL(-1.f);
1070                   }
1071                 }
1072                 else{
1073                    sfbThrReducedLdData = sfbThrLdData + thrFactorLdData;
1074                 }
1075
1076                 /* avoid hole */
1077                 if ( (sfbThrReducedLdData - sfbEnLdData > qcOutChan->sfbMinSnrLdData[sfbGrp+sfb]) &&
1078                      (ahFlag[elementId][ch][sfbGrp+sfb] == AH_INACTIVE) )
1079                 {
1080                    /* sfbThrReduced = max(psyOutChan[ch]->sfbMinSnr[i] * sfbEn, sfbThr); */
1081                    if ( sfbEnLdData > (sfbThrLdData-qcOutChan->sfbMinSnrLdData[sfbGrp+sfb]) ) {
1082                        sfbThrReducedLdData = qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] + sfbEnLdData;
1083                    }
1084                    else {
1085                        sfbThrReducedLdData = sfbThrLdData;
1086                    }
1087                    ahFlag[elementId][ch][sfbGrp+sfb] = AH_ACTIVE;
1088                 }
1089
1090                 qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = sfbThrReducedLdData;
1091              }
1092            }
1093          }
1094       }
1095     }
1096   }
1097}
1098
1099/*****************************************************************************
1100    functionname: FDKaacEnc_reduceMinSnr
1101    description:  if the desired pe can not be reached, reduce pe by
1102                  reducing minSnr
1103*****************************************************************************/
1104void FDKaacEnc_reduceMinSnr(CHANNEL_MAPPING* cm,
1105                            QC_OUT_ELEMENT*  qcElement[(6)],
1106                            PSY_OUT_ELEMENT* psyOutElement[(6)],
1107                            UCHAR            ahFlag[(6)][(2)][MAX_GROUPED_SFB],
1108                            const            INT desiredPe,
1109                            INT*             redPeGlobal,
1110                            const            INT processElements,
1111                            const            INT elementOffset)
1112
1113{
1114   INT elementId;
1115   INT nElements = elementOffset+processElements;
1116
1117   INT newGlobalPe = *redPeGlobal;
1118
1119   for(elementId=elementOffset;elementId<nElements;elementId++) {
1120     if (cm->elInfo[elementId].elType != ID_DSE) {
1121       INT ch;
1122       INT maxSfbPerGroup[2];
1123       INT sfbCnt[2];
1124       INT sfbPerGroup[2];
1125
1126       for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
1127         maxSfbPerGroup[ch] = psyOutElement[elementId]->psyOutChannel[ch]->maxSfbPerGroup-1;
1128         sfbCnt[ch]         = psyOutElement[elementId]->psyOutChannel[ch]->sfbCnt;
1129         sfbPerGroup[ch]    = psyOutElement[elementId]->psyOutChannel[ch]->sfbPerGroup;
1130       }
1131
1132       PE_DATA *peData = &qcElement[elementId]->peData;
1133
1134       do
1135       {
1136         for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
1137
1138            INT sfb, sfbGrp;
1139            QC_OUT_CHANNEL  *qcOutChan = qcElement[elementId]->qcOutChannel[ch];
1140            INT noReduction = 1;
1141
1142            if (maxSfbPerGroup[ch]>=0) {  /* sfb in next channel */
1143              INT deltaPe = 0;
1144              sfb = maxSfbPerGroup[ch]--;
1145              noReduction = 0;
1146
1147              for (sfbGrp = 0; sfbGrp < sfbCnt[ch]; sfbGrp += sfbPerGroup[ch]) {
1148
1149                if (ahFlag[elementId][ch][sfbGrp+sfb] != NO_AH &&
1150                    qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] < SnrLdFac)
1151                {
1152                  /* increase threshold to new minSnr of 1dB */
1153                  qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] = SnrLdFac;
1154
1155                  /* sfbThrReduced = max(psyOutChan[ch]->sfbMinSnr[i] * sfbEn, sfbThr); */
1156                  if ( qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb] >= qcOutChan->sfbThresholdLdData[sfbGrp+sfb] - qcOutChan->sfbMinSnrLdData[sfbGrp+sfb] ) {
1157
1158                     qcOutChan->sfbThresholdLdData[sfbGrp+sfb] = qcOutChan->sfbWeightedEnergyLdData[sfbGrp+sfb] + qcOutChan->sfbMinSnrLdData[sfbGrp+sfb];
1159
1160                     /* calc new pe */
1161                     /* C2 + C3*ld(1/0.8) = 1.5 */
1162                     deltaPe -= (peData->peChannelData[ch].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT);
1163
1164                     /* sfbPe = 1.5 * sfbNLines */
1165                     peData->peChannelData[ch].sfbPe[sfbGrp+sfb] = (3*peData->peChannelData[ch].sfbNLines[sfbGrp+sfb]) << (PE_CONSTPART_SHIFT-1);
1166                     deltaPe += (peData->peChannelData[ch].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT);
1167                   }
1168                }
1169
1170              } /* sfbGrp loop */
1171
1172              peData->pe += deltaPe;
1173              peData->peChannelData[ch].pe += deltaPe;
1174              newGlobalPe += deltaPe;
1175
1176              /* stop if enough has been saved */
1177              if (peData->pe <= desiredPe) {
1178                goto bail;
1179              }
1180
1181            } /* sfb > 0 */
1182
1183            if ( (ch==(cm->elInfo[elementId].nChannelsInEl-1)) && noReduction ) {
1184              goto bail;
1185            }
1186
1187         } /* ch loop */
1188
1189       } while ( peData->pe > desiredPe);
1190
1191     } /* != ID_DSE */
1192   } /* element loop */
1193
1194
1195bail:
1196   /* update global PE */
1197   *redPeGlobal = newGlobalPe;
1198}
1199
1200
1201/*****************************************************************************
1202    functionname: FDKaacEnc_allowMoreHoles
1203    description:  if the desired pe can not be reached, some more scalefactor
1204                  bands have to be quantized to zero
1205*****************************************************************************/
1206static void FDKaacEnc_allowMoreHoles(CHANNEL_MAPPING* cm,
1207                           QC_OUT_ELEMENT*  qcElement[(6)],
1208                           PSY_OUT_ELEMENT* psyOutElement[(6)],
1209                           ATS_ELEMENT*     AdjThrStateElement[(6)],
1210                           UCHAR            ahFlag[(6)][(2)][MAX_GROUPED_SFB],
1211                           const INT        desiredPe,
1212                           const INT        currentPe,
1213                           const int        processElements,
1214                           const int        elementOffset)
1215{
1216  INT elementId;
1217  INT nElements = elementOffset+processElements;
1218  INT actPe = currentPe;
1219
1220  if (actPe <= desiredPe) {
1221    return; /* nothing to do */
1222  }
1223
1224  for (elementId = elementOffset;elementId<nElements;elementId++) {
1225    if (cm->elInfo[elementId].elType != ID_DSE) {
1226
1227      INT ch, sfb, sfbGrp;
1228
1229      PE_DATA *peData = &qcElement[elementId]->peData;
1230      const INT nChannels = cm->elInfo[elementId].nChannelsInEl;
1231
1232      QC_OUT_CHANNEL*  qcOutChannel[(2)] = {NULL};
1233      PSY_OUT_CHANNEL* psyOutChannel[(2)] = {NULL};
1234
1235      for (ch=0; ch<nChannels; ch++) {
1236
1237        /* init pointers */
1238        qcOutChannel[ch] = qcElement[elementId]->qcOutChannel[ch];
1239        psyOutChannel[ch] = psyOutElement[elementId]->psyOutChannel[ch];
1240
1241        for(sfbGrp=0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+= psyOutChannel[ch]->sfbPerGroup) {
1242          for (sfb=psyOutChannel[ch]->maxSfbPerGroup; sfb<psyOutChannel[ch]->sfbPerGroup; sfb++) {
1243            peData->peChannelData[ch].sfbPe[sfbGrp+sfb] = 0;
1244          }
1245        }
1246      }
1247
1248      /* for MS allow hole in the channel with less energy */
1249      if ( nChannels==2 && psyOutChannel[0]->lastWindowSequence==psyOutChannel[1]->lastWindowSequence ) {
1250
1251        for (sfb=0; sfb<psyOutChannel[0]->maxSfbPerGroup; sfb++) {
1252          for(sfbGrp=0; sfbGrp < psyOutChannel[0]->sfbCnt; sfbGrp+=psyOutChannel[0]->sfbPerGroup) {
1253            if (psyOutElement[elementId]->toolsInfo.msMask[sfbGrp+sfb]) {
1254              FIXP_DBL EnergyLd_L = qcOutChannel[0]->sfbWeightedEnergyLdData[sfbGrp+sfb];
1255              FIXP_DBL EnergyLd_R = qcOutChannel[1]->sfbWeightedEnergyLdData[sfbGrp+sfb];
1256
1257              /* allow hole in side channel ? */
1258              if ( (ahFlag[elementId][1][sfbGrp+sfb] != NO_AH) &&
1259                   (((FL2FXCONST_DBL(-0.02065512648f)>>1) + (qcOutChannel[0]->sfbMinSnrLdData[sfbGrp+sfb]>>1))
1260                        > ((EnergyLd_R>>1) - (EnergyLd_L>>1))) )
1261              {
1262                  ahFlag[elementId][1][sfbGrp+sfb] = NO_AH;
1263                  qcOutChannel[1]->sfbThresholdLdData[sfbGrp+sfb] = FL2FXCONST_DBL(0.015625f) + EnergyLd_R;
1264                  actPe -= peData->peChannelData[1].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT;
1265              }
1266              /* allow hole in mid channel ? */
1267              else if ( (ahFlag[elementId][0][sfbGrp+sfb] != NO_AH) &&
1268                        (((FL2FXCONST_DBL(-0.02065512648f)>>1) + (qcOutChannel[1]->sfbMinSnrLdData[sfbGrp+sfb]>>1))
1269                             > ((EnergyLd_L>>1) - (EnergyLd_R>>1))) )
1270              {
1271                  ahFlag[elementId][0][sfbGrp+sfb] = NO_AH;
1272                  qcOutChannel[0]->sfbThresholdLdData[sfbGrp+sfb] = FL2FXCONST_DBL(0.015625f) + EnergyLd_L;
1273                  actPe -= peData->peChannelData[0].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT;
1274              } /* if (ahFlag) */
1275            } /* if MS */
1276          } /* sfbGrp */
1277          if (actPe <= desiredPe) {
1278            return; /* stop if enough has been saved */
1279          }
1280        } /* sfb */
1281      } /* MS possible ? */
1282
1283      /* more holes necessary? subsequently erase bands
1284         starting with low energies */
1285      INT startSfb[2];
1286      FIXP_DBL avgEnLD64,minEnLD64;
1287      INT ahCnt;
1288      FIXP_DBL ahCntLD64;
1289      INT enIdx;
1290      FIXP_DBL enLD64[4];
1291      FIXP_DBL avgEn;
1292
1293      /* do not go below startSfb */
1294      for (ch=0; ch<nChannels; ch++) {
1295        if (psyOutChannel[ch]->lastWindowSequence != SHORT_WINDOW)
1296          startSfb[ch] = AdjThrStateElement[elementId]->ahParam.startSfbL;
1297        else
1298          startSfb[ch] = AdjThrStateElement[elementId]->ahParam.startSfbS;
1299      }
1300
1301      /* calc avg and min energies of bands that avoid holes */
1302      avgEn = FL2FXCONST_DBL(0.0f);
1303      minEnLD64 = FL2FXCONST_DBL(0.0f);
1304      ahCnt = 0;
1305
1306      for (ch=0; ch<nChannels; ch++) {
1307
1308        sfbGrp=0;
1309        sfb=startSfb[ch];
1310
1311        do {
1312          for (; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
1313            if ((ahFlag[elementId][ch][sfbGrp+sfb]!=NO_AH) &&
1314                (qcOutChannel[ch]->sfbWeightedEnergyLdData[sfbGrp+sfb] > qcOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb])){
1315              minEnLD64 = fixMin(minEnLD64,qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb]);
1316              avgEn += qcOutChannel[ch]->sfbEnergy[sfbGrp+sfb] >> 6;
1317              ahCnt++;
1318            }
1319          }
1320
1321          sfbGrp += psyOutChannel[ch]->sfbPerGroup;
1322          sfb=0;
1323
1324        } while (sfbGrp < psyOutChannel[ch]->sfbCnt);
1325      }
1326
1327      if ( (avgEn == FL2FXCONST_DBL(0.0f)) || (ahCnt == 0) ) {
1328        avgEnLD64 = FL2FXCONST_DBL(0.0f);
1329      }
1330      else {
1331        avgEnLD64 = CalcLdData(avgEn);
1332        ahCntLD64 = CalcLdInt(ahCnt);
1333        avgEnLD64 = avgEnLD64 + FL2FXCONST_DBL(0.09375f) - ahCntLD64; /* compensate shift with 6 */
1334      }
1335
1336      /* calc some energy borders between minEn and avgEn */
1337      /* for (enIdx=0; enIdx<4; enIdx++) */
1338        /* en[enIdx] = minEn * (float)FDKpow(avgEn/(minEn+FLT_MIN), (2*enIdx+1)/7.0f); */
1339      enLD64[0] = minEnLD64 + fMult((avgEnLD64-minEnLD64),FL2FXCONST_DBL(0.14285714285f));
1340      enLD64[1] = minEnLD64 + fMult((avgEnLD64-minEnLD64),FL2FXCONST_DBL(0.42857142857f));
1341      enLD64[2] = minEnLD64 + fMult((avgEnLD64-minEnLD64),FL2FXCONST_DBL(0.71428571428f));
1342      enLD64[3] = minEnLD64 + (avgEnLD64-minEnLD64);
1343
1344      for (enIdx=0; enIdx<4; enIdx++) {
1345        INT noReduction = 1;
1346
1347        INT maxSfbPerGroup[2];
1348        INT sfbCnt[2];
1349        INT sfbPerGroup[2];
1350
1351        for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
1352          maxSfbPerGroup[ch] = psyOutElement[elementId]->psyOutChannel[ch]->maxSfbPerGroup-1;
1353          sfbCnt[ch]         = psyOutElement[elementId]->psyOutChannel[ch]->sfbCnt;
1354          sfbPerGroup[ch]    = psyOutElement[elementId]->psyOutChannel[ch]->sfbPerGroup;
1355        }
1356
1357        do {
1358
1359          noReduction = 1;
1360
1361          for(ch=0; ch<cm->elInfo[elementId].nChannelsInEl; ch++) {
1362
1363            INT sfb, sfbGrp;
1364
1365            /* start with lowest energy border at highest sfb */
1366            if (maxSfbPerGroup[ch]>=startSfb[ch]) {  /* sfb in next channel */
1367              sfb = maxSfbPerGroup[ch]--;
1368              noReduction = 0;
1369
1370              for (sfbGrp = 0; sfbGrp < sfbCnt[ch]; sfbGrp += sfbPerGroup[ch]) {
1371                /* sfb energy below border ? */
1372                if (ahFlag[elementId][ch][sfbGrp+sfb] != NO_AH && qcOutChannel[ch]->sfbEnergyLdData[sfbGrp+sfb] < enLD64[enIdx]) {
1373                  /* allow hole */
1374                  ahFlag[elementId][ch][sfbGrp+sfb] = NO_AH;
1375                  qcOutChannel[ch]->sfbThresholdLdData[sfbGrp+sfb] = FL2FXCONST_DBL(0.015625f) + qcOutChannel[ch]->sfbWeightedEnergyLdData[sfbGrp+sfb];
1376                  actPe -= peData->peChannelData[ch].sfbPe[sfbGrp+sfb]>>PE_CONSTPART_SHIFT;
1377                }
1378              } /* sfbGrp  */
1379
1380              if (actPe <= desiredPe) {
1381                return; /* stop if enough has been saved */
1382              }
1383            } /* sfb > 0 */
1384          } /* ch loop */
1385
1386        } while( (noReduction == 0) && (actPe > desiredPe) );
1387
1388        if (actPe <= desiredPe) {
1389          return; /* stop if enough has been saved */
1390        }
1391
1392      } /* enIdx loop */
1393
1394    } /* EOF DSE-suppression */
1395  } /* EOF for all elements... */
1396
1397}
1398
1399/* reset avoid hole flags from AH_ACTIVE to AH_INACTIVE  */
1400static void FDKaacEnc_resetAHFlags( UCHAR ahFlag[(2)][MAX_GROUPED_SFB],
1401                          const int nChannels,
1402                          PSY_OUT_CHANNEL  *psyOutChannel[(2)])
1403{
1404  int ch, sfb, sfbGrp;
1405
1406  for(ch=0; ch<nChannels; ch++) {
1407    for (sfbGrp=0; sfbGrp < psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutChannel[ch]->sfbPerGroup) {
1408      for (sfb=0; sfb<psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
1409        if ( ahFlag[ch][sfbGrp+sfb] == AH_ACTIVE) {
1410          ahFlag[ch][sfbGrp+sfb] = AH_INACTIVE;
1411        }
1412      }
1413    }
1414  }
1415}
1416
1417
1418static FIXP_DBL CalcRedValPower(FIXP_DBL num,
1419                                FIXP_DBL denum,
1420                                INT*     scaling )
1421{
1422    FIXP_DBL value = FL2FXCONST_DBL(0.f);
1423
1424    if (num>=FL2FXCONST_DBL(0.f)) {
1425      value = fDivNorm( num, denum, scaling);
1426    }
1427    else {
1428      value = -fDivNorm( -num, denum, scaling);
1429    }
1430    value = f2Pow(value, *scaling, scaling);
1431    *scaling = DFRACT_BITS-1-*scaling;
1432
1433    return value;
1434}
1435
1436
1437/*****************************************************************************
1438functionname: FDKaacEnc_adaptThresholdsToPe
1439description:  two guesses for the reduction value and one final correction of the thresholds
1440*****************************************************************************/
1441static void FDKaacEnc_adaptThresholdsToPe(CHANNEL_MAPPING*  cm,
1442                                ATS_ELEMENT*      AdjThrStateElement[(6)],
1443                                QC_OUT_ELEMENT*   qcElement[(6)],
1444                                PSY_OUT_ELEMENT*  psyOutElement[(6)],
1445                                const INT         desiredPe,
1446                                const INT         processElements,
1447                                const INT         elementOffset)
1448{
1449   FIXP_DBL redValue[(6)];
1450   SCHAR    redValScaling[(6)];
1451   UCHAR    pAhFlag[(6)][(2)][MAX_GROUPED_SFB];
1452   FIXP_DBL pThrExp[(6)][(2)][MAX_GROUPED_SFB];
1453   int iter;
1454
1455   INT constPartGlobal, noRedPeGlobal, nActiveLinesGlobal, redPeGlobal;
1456   constPartGlobal = noRedPeGlobal = nActiveLinesGlobal = redPeGlobal = 0;
1457
1458   int elementId;
1459
1460   int nElements = elementOffset+processElements;
1461   if(nElements > cm->nElements) {
1462     nElements = cm->nElements;
1463   }
1464
1465   /* ------------------------------------------------------- */
1466   /* Part I: Initialize data structures and variables... */
1467   /* ------------------------------------------------------- */
1468   for (elementId = elementOffset;elementId<nElements;elementId++) {
1469     if (cm->elInfo[elementId].elType != ID_DSE) {
1470
1471       INT nChannels = cm->elInfo[elementId].nChannelsInEl;
1472       PE_DATA *peData    = &qcElement[elementId]->peData;
1473
1474       /* thresholds to the power of redExp */
1475       FDKaacEnc_calcThreshExp(pThrExp[elementId], qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, nChannels);
1476
1477       /* lower the minSnr requirements for low energies compared to the average
1478          energy in this frame */
1479       FDKaacEnc_adaptMinSnr(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, &AdjThrStateElement[elementId]->minSnrAdaptParam, nChannels);
1480
1481       /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
1482       FDKaacEnc_initAvoidHoleFlag(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, pAhFlag[elementId], &psyOutElement[elementId]->toolsInfo, nChannels, peData, &AdjThrStateElement[elementId]->ahParam);
1483
1484       /* sum up */
1485       constPartGlobal    += peData->constPart;
1486       noRedPeGlobal      += peData->pe;
1487       nActiveLinesGlobal += fixMax((INT)peData->nActiveLines, 1);
1488
1489     } /* EOF DSE-suppression */
1490   } /* EOF for all elements... */
1491
1492   /* ----------------------------------------------------------------------- */
1493   /* Part II: Calculate bit consumption of initial bit constraints setup */
1494   /* ----------------------------------------------------------------------- */
1495   for (elementId = elementOffset;elementId<nElements;elementId++) {
1496     if (cm->elInfo[elementId].elType != ID_DSE) {
1497       /*
1498       redVal = ( 2 ^ ( (constPartGlobal-desiredPe) / (invRedExp*nActiveLinesGlobal) )
1499                - 2 ^ ( (constPartGlobal-noRedPeGlobal) / (invRedExp*nActiveLinesGlobal) ) )
1500       */
1501
1502
1503       INT nChannels = cm->elInfo[elementId].nChannelsInEl;
1504       PE_DATA *peData    = &qcElement[elementId]->peData;
1505
1506       /* first guess of reduction value */
1507       int scale0=0, scale1=0;
1508       FIXP_DBL tmp0 = CalcRedValPower( constPartGlobal-desiredPe, 4*nActiveLinesGlobal, &scale0 );
1509       FIXP_DBL tmp1 = CalcRedValPower( constPartGlobal-noRedPeGlobal, 4*nActiveLinesGlobal, &scale1 );
1510
1511       int scalMin = FDKmin(scale0, scale1)-1;
1512
1513       redValue[elementId]  = scaleValue(tmp0,(scalMin-scale0)) - scaleValue(tmp1,(scalMin-scale1));
1514       redValScaling[elementId] = scalMin;
1515
1516       /* reduce thresholds */
1517       FDKaacEnc_reduceThresholdsCBR(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, pAhFlag[elementId], pThrExp[elementId], nChannels, redValue[elementId], redValScaling[elementId]);
1518
1519       /* pe after first guess */
1520       FDKaacEnc_calcPe(psyOutElement[elementId]->psyOutChannel, qcElement[elementId]->qcOutChannel, peData, nChannels);
1521
1522       redPeGlobal += peData->pe;
1523     } /* EOF DSE-suppression */
1524   } /* EOF for all elements... */
1525
1526   /* -------------------------------------------------- */
1527   /* Part III: Iterate until bit constraints are met */
1528   /* -------------------------------------------------- */
1529   iter = 0;
1530   while ((fixp_abs(redPeGlobal - desiredPe) > fMultI(FL2FXCONST_DBL(0.05f),desiredPe)) && (iter < 1)) {
1531
1532     INT desiredPeNoAHGlobal;
1533     INT redPeNoAHGlobal = 0;
1534     INT constPartNoAHGlobal = 0;
1535     INT nActiveLinesNoAHGlobal = 0;
1536
1537     for (elementId = elementOffset;elementId<nElements;elementId++) {
1538       if (cm->elInfo[elementId].elType != ID_DSE) {
1539
1540         INT redPeNoAH, constPartNoAH, nActiveLinesNoAH;
1541         INT nChannels = cm->elInfo[elementId].nChannelsInEl;
1542         PE_DATA *peData    = &qcElement[elementId]->peData;
1543
1544         /* pe for bands where avoid hole is inactive */
1545         FDKaacEnc_FDKaacEnc_calcPeNoAH(&redPeNoAH, &constPartNoAH, &nActiveLinesNoAH,
1546                    peData, pAhFlag[elementId], psyOutElement[elementId]->psyOutChannel, nChannels);
1547
1548         redPeNoAHGlobal += redPeNoAH;
1549         constPartNoAHGlobal += constPartNoAH;
1550         nActiveLinesNoAHGlobal += nActiveLinesNoAH;
1551       } /* EOF DSE-suppression */
1552     } /* EOF for all elements... */
1553
1554     /* Calculate new redVal ... */
1555     if(desiredPe < redPeGlobal) {
1556
1557       /* new desired pe without bands where avoid hole is active */
1558       desiredPeNoAHGlobal = desiredPe - (redPeGlobal - redPeNoAHGlobal);
1559
1560       /* limit desiredPeNoAH to positive values, as the PE can not become negative */
1561       desiredPeNoAHGlobal = FDKmax(0,desiredPeNoAHGlobal);
1562
1563       /* second guess (only if there are bands left where avoid hole is inactive)*/
1564       if (nActiveLinesNoAHGlobal > 0) {
1565         for (elementId = elementOffset;elementId<nElements;elementId++) {
1566           if (cm->elInfo[elementId].elType != ID_DSE) {
1567             /*
1568             redVal += ( 2 ^ ( (constPartNoAHGlobal-desiredPeNoAHGlobal) / (invRedExp*nActiveLinesNoAHGlobal) )
1569                       - 2 ^ ( (constPartNoAHGlobal-redPeNoAHGlobal) / (invRedExp*nActiveLinesNoAHGlobal) ) )
1570             */
1571             int scale0 = 0;
1572             int scale1 = 0;
1573
1574             FIXP_DBL tmp0 = CalcRedValPower( constPartNoAHGlobal-desiredPeNoAHGlobal, 4*nActiveLinesNoAHGlobal, &scale0 );
1575             FIXP_DBL tmp1 = CalcRedValPower( constPartNoAHGlobal-redPeNoAHGlobal, 4*nActiveLinesNoAHGlobal, &scale1 );
1576
1577             int scalMin = FDKmin(scale0, scale1)-1;
1578
1579             tmp0 = scaleValue(tmp0,(scalMin-scale0)) - scaleValue(tmp1,(scalMin-scale1));
1580             scale0 = scalMin;
1581
1582             /* old reduction value */
1583             tmp1 = redValue[elementId];
1584             scale1 = redValScaling[elementId];
1585
1586             scalMin = fixMin(scale0,scale1)-1;
1587
1588             /* sum up old and new reduction value */
1589             redValue[elementId] = scaleValue(tmp0,(scalMin-scale0)) + scaleValue(tmp1,(scalMin-scale1));
1590             redValScaling[elementId] = scalMin;
1591
1592           } /* EOF DSE-suppression */
1593         } /* EOF for all elements... */
1594       } /* nActiveLinesNoAHGlobal > 0 */
1595     }
1596     else {
1597        /* desiredPe >= redPeGlobal */
1598        for (elementId = elementOffset;elementId<nElements;elementId++) {
1599          if (cm->elInfo[elementId].elType != ID_DSE) {
1600
1601            INT redVal_scale = 0;
1602            FIXP_DBL tmp = fDivNorm((FIXP_DBL)redPeGlobal, (FIXP_DBL)desiredPe, &redVal_scale);
1603
1604            /* redVal *= redPeGlobal/desiredPe; */
1605            redValue[elementId] = fMult(redValue[elementId], tmp);
1606            redValScaling[elementId] -= redVal_scale;
1607
1608            FDKaacEnc_resetAHFlags(pAhFlag[elementId], cm->elInfo[elementId].nChannelsInEl, psyOutElement[elementId]->psyOutChannel);
1609          } /* EOF DSE-suppression */
1610        } /* EOF for all elements... */
1611     }
1612
1613     redPeGlobal = 0;
1614     /* Calculate new redVal's PE... */
1615     for (elementId = elementOffset;elementId<nElements;elementId++) {
1616       if (cm->elInfo[elementId].elType != ID_DSE) {
1617
1618         INT nChannels = cm->elInfo[elementId].nChannelsInEl;
1619         PE_DATA *peData    = &qcElement[elementId]->peData;
1620
1621         /* reduce thresholds */
1622         FDKaacEnc_reduceThresholdsCBR(qcElement[elementId]->qcOutChannel, psyOutElement[elementId]->psyOutChannel, pAhFlag[elementId], pThrExp[elementId], nChannels, redValue[elementId], redValScaling[elementId]);
1623
1624         /* pe after second guess */
1625         FDKaacEnc_calcPe(psyOutElement[elementId]->psyOutChannel, qcElement[elementId]->qcOutChannel, peData, nChannels);
1626         redPeGlobal += peData->pe;
1627
1628       } /* EOF DSE-suppression */
1629     } /* EOF for all elements... */
1630
1631     iter++;
1632   } /* EOF while */
1633
1634
1635   /* ------------------------------------------------------- */
1636   /* Part IV: if still required, further reduce constraints  */
1637   /* ------------------------------------------------------- */
1638   /*                  1.0*        1.15*       1.20*
1639    *               desiredPe   desiredPe   desiredPe
1640    *                   |           |           |
1641    * ...XXXXXXXXXXXXXXXXXXXXXXXXXXX|           |
1642    *                   |           |           |XXXXXXXXXXX...
1643    *                   |           |XXXXXXXXXXX|
1644    *            --- A ---          | --- B --- | --- C ---
1645    *
1646    * (X): redPeGlobal
1647    * (A): FDKaacEnc_correctThresh()
1648    * (B): FDKaacEnc_allowMoreHoles()
1649    * (C): FDKaacEnc_reduceMinSnr()
1650   */
1651
1652   /* correct thresholds to get closer to the desired pe */
1653   if ( redPeGlobal > desiredPe ) {
1654     FDKaacEnc_correctThresh(cm, qcElement, psyOutElement, pAhFlag, pThrExp, redValue, redValScaling,
1655                   desiredPe - redPeGlobal, processElements, elementOffset);
1656
1657     /* update PE */
1658     redPeGlobal = 0;
1659     for(elementId=elementOffset;elementId<nElements;elementId++) {
1660       if (cm->elInfo[elementId].elType != ID_DSE) {
1661
1662         INT nChannels = cm->elInfo[elementId].nChannelsInEl;
1663         PE_DATA *peData    = &qcElement[elementId]->peData;
1664
1665         /* pe after correctThresh */
1666         FDKaacEnc_calcPe(psyOutElement[elementId]->psyOutChannel, qcElement[elementId]->qcOutChannel, peData, nChannels);
1667         redPeGlobal += peData->pe;
1668
1669       } /* EOF DSE-suppression */
1670     } /* EOF for all elements... */
1671   }
1672
1673   if ( redPeGlobal > desiredPe ) {
1674     /* reduce pe by reducing minSnr requirements */
1675     FDKaacEnc_reduceMinSnr(cm, qcElement, psyOutElement, pAhFlag,
1676                            (fMultI(FL2FXCONST_DBL(0.15f),desiredPe) + desiredPe),
1677                            &redPeGlobal, processElements, elementOffset);
1678
1679     /* reduce pe by allowing additional spectral holes */
1680     FDKaacEnc_allowMoreHoles(cm, qcElement, psyOutElement, AdjThrStateElement, pAhFlag,
1681                    desiredPe, redPeGlobal, processElements, elementOffset);
1682   }
1683
1684}
1685
1686
1687/* similar to FDKaacEnc_adaptThresholdsToPe(), for  VBR-mode */
1688void FDKaacEnc_AdaptThresholdsVBR(QC_OUT_CHANNEL* qcOutChannel[(2)],
1689                               PSY_OUT_CHANNEL* psyOutChannel[(2)],
1690                               ATS_ELEMENT* AdjThrStateElement,
1691                               struct TOOLSINFO *toolsInfo,
1692                               PE_DATA *peData,
1693                               const INT nChannels)
1694{
1695   UCHAR    pAhFlag[(2)][MAX_GROUPED_SFB];
1696   FIXP_DBL pThrExp[(2)][MAX_GROUPED_SFB];
1697
1698   /* thresholds to the power of redExp */
1699   FDKaacEnc_calcThreshExp(pThrExp, qcOutChannel, psyOutChannel, nChannels);
1700
1701   /* lower the minSnr requirements for low energies compared to the average
1702      energy in this frame */
1703   FDKaacEnc_adaptMinSnr(qcOutChannel, psyOutChannel, &AdjThrStateElement->minSnrAdaptParam, nChannels);
1704
1705   /* init ahFlag (0: no ah necessary, 1: ah possible, 2: ah active */
1706   FDKaacEnc_initAvoidHoleFlag(qcOutChannel, psyOutChannel, pAhFlag, toolsInfo,
1707                     nChannels, peData, &AdjThrStateElement->ahParam);
1708
1709   /* reduce thresholds */
1710   FDKaacEnc_reduceThresholdsVBR(qcOutChannel, psyOutChannel, pAhFlag, pThrExp, nChannels,
1711                       AdjThrStateElement->vbrQualFactor,
1712                       &AdjThrStateElement->chaosMeasureOld);
1713
1714}
1715
1716
1717/*****************************************************************************
1718
1719  functionname: FDKaacEnc_calcBitSave
1720  description:  Calculates percentage of bit save, see figure below
1721  returns:
1722  input:        parameters and bitres-fullness
1723  output:       percentage of bit save
1724
1725*****************************************************************************/
1726/*
1727        bitsave
1728                    maxBitSave(%)|   clipLow
1729                                 |---\
1730                                 |    \
1731                                 |     \
1732                                 |      \
1733                                 |       \
1734                                 |--------\--------------> bitres
1735                                 |         \
1736                    minBitSave(%)|          \------------
1737                                          clipHigh      maxBitres
1738*/
1739static FIXP_DBL FDKaacEnc_calcBitSave(FIXP_DBL fillLevel,
1740    const FIXP_DBL clipLow,
1741    const FIXP_DBL clipHigh,
1742    const FIXP_DBL minBitSave,
1743    const FIXP_DBL maxBitSave,
1744    const FIXP_DBL bitsave_slope)
1745{
1746    FIXP_DBL bitsave;
1747
1748    fillLevel = fixMax(fillLevel, clipLow);
1749    fillLevel = fixMin(fillLevel, clipHigh);
1750
1751    bitsave = maxBitSave - fMult((fillLevel-clipLow), bitsave_slope);
1752
1753    return (bitsave);
1754}
1755
1756/*****************************************************************************
1757
1758  functionname: FDKaacEnc_calcBitSpend
1759  description:  Calculates percentage of bit spend, see figure below
1760  returns:
1761  input:        parameters and bitres-fullness
1762  output:       percentage of bit spend
1763
1764*****************************************************************************/
1765/*
1766                              bitspend      clipHigh
1767                   maxBitSpend(%)|          /-----------maxBitres
1768                                 |         /
1769                                 |        /
1770                                 |       /
1771                                 |      /
1772                                 |     /
1773                                 |----/-----------------> bitres
1774                                 |   /
1775                   minBitSpend(%)|--/
1776                                   clipLow
1777*/
1778static FIXP_DBL FDKaacEnc_calcBitSpend(FIXP_DBL fillLevel,
1779    const FIXP_DBL clipLow,
1780    const FIXP_DBL clipHigh,
1781    const FIXP_DBL minBitSpend,
1782    const FIXP_DBL maxBitSpend,
1783    const FIXP_DBL bitspend_slope)
1784{
1785    FIXP_DBL bitspend;
1786
1787    fillLevel = fixMax(fillLevel, clipLow);
1788    fillLevel = fixMin(fillLevel, clipHigh);
1789
1790    bitspend = minBitSpend + fMult(fillLevel-clipLow, bitspend_slope);
1791
1792    return (bitspend);
1793}
1794
1795
1796/*****************************************************************************
1797
1798  functionname: FDKaacEnc_adjustPeMinMax()
1799  description:  adjusts peMin and peMax parameters over time
1800  returns:
1801  input:        current pe, peMin, peMax, bitres size
1802  output:       adjusted peMin/peMax
1803
1804*****************************************************************************/
1805static void FDKaacEnc_adjustPeMinMax(const INT currPe,
1806    INT      *peMin,
1807    INT      *peMax)
1808{
1809  FIXP_DBL minFacHi = FL2FXCONST_DBL(0.3f), maxFacHi = (FIXP_DBL)MAXVAL_DBL, minFacLo = FL2FXCONST_DBL(0.14f), maxFacLo = FL2FXCONST_DBL(0.07f);
1810    INT diff;
1811
1812    INT minDiff_fix = fMultI(FL2FXCONST_DBL(0.1666666667f), currPe);
1813
1814    if (currPe > *peMax)
1815    {
1816        diff = (currPe-*peMax) ;
1817        *peMin += fMultI(minFacHi,diff);
1818        *peMax += fMultI(maxFacHi,diff);
1819    }
1820    else if (currPe < *peMin)
1821    {
1822        diff = (*peMin-currPe) ;
1823        *peMin -= fMultI(minFacLo,diff);
1824        *peMax -= fMultI(maxFacLo,diff);
1825    }
1826    else
1827    {
1828        *peMin += fMultI(minFacHi, (currPe - *peMin));
1829        *peMax -= fMultI(maxFacLo, (*peMax - currPe));
1830    }
1831
1832    if ((*peMax - *peMin) < minDiff_fix)
1833    {
1834        INT peMax_fix = *peMax, peMin_fix = *peMin;
1835        FIXP_DBL partLo_fix, partHi_fix;
1836
1837        partLo_fix = (FIXP_DBL)fixMax(0, currPe - peMin_fix);
1838        partHi_fix = (FIXP_DBL)fixMax(0, peMax_fix - currPe);
1839
1840        peMax_fix = (INT)(currPe + fMultI(fDivNorm(partHi_fix, (partLo_fix+partHi_fix)), minDiff_fix));
1841        peMin_fix = (INT)(currPe - fMultI(fDivNorm(partLo_fix, (partLo_fix+partHi_fix)), minDiff_fix));
1842        peMin_fix = fixMax(0, peMin_fix);
1843
1844        *peMax = peMax_fix;
1845        *peMin = peMin_fix;
1846    }
1847}
1848
1849
1850
1851/*****************************************************************************
1852
1853  functionname: BitresCalcBitFac
1854  description:  calculates factor of spending bits for one frame
1855  1.0 : take all frame dynpart bits
1856  >1.0 : take all frame dynpart bits + bitres
1857  <1.0 : put bits in bitreservoir
1858  returns:      BitFac
1859  input:        bitres-fullness, pe, blockType, parameter-settings
1860  output:
1861
1862*****************************************************************************/
1863/*
1864                     bitfac(%)            pemax
1865                   bitspend(%)   |          /-----------maxBitres
1866                                 |         /
1867                                 |        /
1868                                 |       /
1869                                 |      /
1870                                 |     /
1871                                 |----/-----------------> pe
1872                                 |   /
1873                   bitsave(%)    |--/
1874                                    pemin
1875*/
1876
1877static FIXP_DBL FDKaacEnc_bitresCalcBitFac(const INT       bitresBits,
1878    const INT        maxBitresBits,
1879    const INT        pe,
1880    const INT        lastWindowSequence,
1881    const INT        avgBits,
1882    const FIXP_DBL   maxBitFac,
1883    ADJ_THR_STATE   *AdjThr,
1884    ATS_ELEMENT     *adjThrChan)
1885{
1886    BRES_PARAM *bresParam;
1887    INT pex;
1888
1889    INT qmin, qbr, qbres, qmbr;
1890    FIXP_DBL bitSave, bitSpend;
1891
1892    FIXP_DBL bitresFac_fix, tmp_cst, tmp_fix;
1893    FIXP_DBL pe_pers, bits_ratio, maxBrVal;
1894    FIXP_DBL bitsave_slope, bitspend_slope, maxBitFac_tmp;
1895    FIXP_DBL fillLevel_fix = (FIXP_DBL)0x7fffffff;
1896    FIXP_DBL UNITY = (FIXP_DBL)0x7fffffff;
1897    FIXP_DBL POINT7 = (FIXP_DBL)0x5999999A;
1898
1899    if (maxBitresBits > bitresBits) {
1900      fillLevel_fix = fDivNorm(bitresBits, maxBitresBits);
1901    }
1902
1903    if (lastWindowSequence != SHORT_WINDOW)
1904    {
1905        bresParam = &(AdjThr->bresParamLong);
1906        bitsave_slope = (FIXP_DBL)0x3BBBBBBC;
1907        bitspend_slope = (FIXP_DBL)0x55555555;
1908    }
1909    else
1910    {
1911        bresParam = &(AdjThr->bresParamShort);
1912        bitsave_slope = (FIXP_DBL)0x2E8BA2E9;
1913        bitspend_slope = (FIXP_DBL)0x7fffffff;
1914    }
1915
1916    pex = fixMax(pe, adjThrChan->peMin);
1917    pex = fixMin(pex, adjThrChan->peMax);
1918
1919    bitSave = FDKaacEnc_calcBitSave(fillLevel_fix,
1920        bresParam->clipSaveLow, bresParam->clipSaveHigh,
1921        bresParam->minBitSave, bresParam->maxBitSave, bitsave_slope);
1922
1923    bitSpend = FDKaacEnc_calcBitSpend(fillLevel_fix,
1924        bresParam->clipSpendLow, bresParam->clipSpendHigh,
1925        bresParam->minBitSpend, bresParam->maxBitSpend, bitspend_slope);
1926
1927    pe_pers = fDivNorm(pex - adjThrChan->peMin, adjThrChan->peMax - adjThrChan->peMin);
1928    tmp_fix = fMult(((FIXP_DBL)bitSpend + (FIXP_DBL)bitSave), pe_pers);
1929    bitresFac_fix = (UNITY>>1) - ((FIXP_DBL)bitSave>>1) + (tmp_fix>>1); qbres = (DFRACT_BITS-2);
1930
1931    /* (float)bitresBits/(float)avgBits */
1932    bits_ratio = fDivNorm(bitresBits, avgBits, &qbr);
1933    qbr = DFRACT_BITS-1-qbr;
1934
1935    /* Add 0.7 in q31 to bits_ratio in qbr */
1936    /* 0.7f + (float)bitresBits/(float)avgBits */
1937    qmin = fixMin(qbr, (DFRACT_BITS-1));
1938    bits_ratio = bits_ratio >> (qbr - qmin);
1939    tmp_cst = POINT7 >> ((DFRACT_BITS-1) - qmin);
1940    maxBrVal = (bits_ratio>>1) + (tmp_cst>>1); qmbr = qmin - 1;
1941
1942    /* bitresFac_fix = fixMin(bitresFac_fix, 0.7 + bitresBits/avgBits); */
1943    bitresFac_fix = bitresFac_fix >> (qbres - qmbr); qbres = qmbr;
1944    bitresFac_fix = fixMin(bitresFac_fix, maxBrVal);
1945
1946    /* Compare with maxBitFac */
1947    qmin = fixMin(Q_BITFAC, qbres);
1948    bitresFac_fix = bitresFac_fix >> (qbres - qmin);
1949    maxBitFac_tmp = maxBitFac >> (Q_BITFAC - qmin);
1950    if(maxBitFac_tmp < bitresFac_fix)
1951    {
1952        bitresFac_fix = maxBitFac;
1953    }
1954    else
1955    {
1956        if(qmin < Q_BITFAC)
1957        {
1958            bitresFac_fix = bitresFac_fix << (Q_BITFAC-qmin);
1959        }
1960        else
1961        {
1962            bitresFac_fix = bitresFac_fix >> (qmin-Q_BITFAC);
1963        }
1964    }
1965
1966    FDKaacEnc_adjustPeMinMax(pe, &adjThrChan->peMin, &adjThrChan->peMax);
1967
1968    return bitresFac_fix;
1969}
1970
1971
1972/*****************************************************************************
1973functionname: FDKaacEnc_AdjThrNew
1974description:  allocate ADJ_THR_STATE
1975*****************************************************************************/
1976INT FDKaacEnc_AdjThrNew(ADJ_THR_STATE** phAdjThr,
1977                        INT             nElements)
1978{
1979    INT err = 0;
1980    INT i;
1981    ADJ_THR_STATE* hAdjThr = GetRam_aacEnc_AdjustThreshold();
1982    if (hAdjThr==NULL) {
1983        err = 1;
1984        goto bail;
1985    }
1986
1987    for (i=0; i<nElements; i++) {
1988        hAdjThr->adjThrStateElem[i] =  GetRam_aacEnc_AdjThrStateElement(i);
1989        if (hAdjThr->adjThrStateElem[i]==NULL) {
1990          err = 1;
1991          goto bail;
1992        }
1993    }
1994
1995bail:
1996    *phAdjThr = hAdjThr;
1997    return err;
1998}
1999
2000
2001/*****************************************************************************
2002functionname: FDKaacEnc_AdjThrInit
2003description:  initialize ADJ_THR_STATE
2004*****************************************************************************/
2005void FDKaacEnc_AdjThrInit(ADJ_THR_STATE   *hAdjThr,
2006    const INT       meanPe,
2007    ELEMENT_BITS    *elBits[(6)],
2008    INT             nElements,
2009    FIXP_DBL        vbrQualFactor)
2010{
2011    INT i;
2012
2013    FIXP_DBL POINT8 = FL2FXCONST_DBL(0.8f);
2014    FIXP_DBL POINT6 = FL2FXCONST_DBL(0.6f);
2015
2016    /* common for all elements: */
2017    /* parameters for bitres control */
2018    hAdjThr->bresParamLong.clipSaveLow   = (FIXP_DBL)0x1999999a; /* FL2FXCONST_DBL(0.2f); */
2019    hAdjThr->bresParamLong.clipSaveHigh  = (FIXP_DBL)0x7999999a; /* FL2FXCONST_DBL(0.95f); */
2020    hAdjThr->bresParamLong.minBitSave    = (FIXP_DBL)0xf999999a; /* FL2FXCONST_DBL(-0.05f); */
2021    hAdjThr->bresParamLong.maxBitSave    = (FIXP_DBL)0x26666666; /* FL2FXCONST_DBL(0.3f); */
2022    hAdjThr->bresParamLong.clipSpendLow  = (FIXP_DBL)0x1999999a; /* FL2FXCONST_DBL(0.2f); */
2023    hAdjThr->bresParamLong.clipSpendHigh = (FIXP_DBL)0x7999999a; /* FL2FXCONST_DBL(0.95f); */
2024    hAdjThr->bresParamLong.minBitSpend   = (FIXP_DBL)0xf3333333; /* FL2FXCONST_DBL(-0.10f); */
2025    hAdjThr->bresParamLong.maxBitSpend   = (FIXP_DBL)0x33333333; /* FL2FXCONST_DBL(0.4f); */
2026
2027    hAdjThr->bresParamShort.clipSaveLow   = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
2028    hAdjThr->bresParamShort.clipSaveHigh  = (FIXP_DBL)0x5fffffff; /* FL2FXCONST_DBL(0.75f); */
2029    hAdjThr->bresParamShort.minBitSave    = (FIXP_DBL)0x00000000; /* FL2FXCONST_DBL(0.0f); */
2030    hAdjThr->bresParamShort.maxBitSave    = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
2031    hAdjThr->bresParamShort.clipSpendLow  = (FIXP_DBL)0x199999a0; /* FL2FXCONST_DBL(0.2f); */
2032    hAdjThr->bresParamShort.clipSpendHigh = (FIXP_DBL)0x5fffffff; /* FL2FXCONST_DBL(0.75f); */
2033    hAdjThr->bresParamShort.minBitSpend   = (FIXP_DBL)0xf9999998; /* FL2FXCONST_DBL(-0.05f); */
2034    hAdjThr->bresParamShort.maxBitSpend   = (FIXP_DBL)0x40000000; /* FL2FXCONST_DBL(0.5f); */
2035
2036    /* specific for each element: */
2037    for (i=0; i<nElements; i++) {
2038        ATS_ELEMENT* atsElem = hAdjThr->adjThrStateElem[i];
2039        MINSNR_ADAPT_PARAM *msaParam = &atsElem->minSnrAdaptParam;
2040        INT chBitrate = elBits[i]->chBitrateEl;
2041
2042        /* parameters for bitres control */
2043        atsElem->peMin = fMultI(POINT8, meanPe) >> 1;
2044        atsElem->peMax = fMultI(POINT6, meanPe);
2045
2046        /* for use in FDKaacEnc_reduceThresholdsVBR */
2047        atsElem->chaosMeasureOld = FL2FXCONST_DBL(0.3f);
2048
2049        /* additional pe offset to correct pe2bits for low bitrates */
2050        atsElem->peOffset = 0;
2051
2052        /* vbr initialisation */
2053        atsElem->vbrQualFactor = vbrQualFactor;
2054        if (chBitrate < 32000)
2055        {
2056            atsElem->peOffset = fixMax(50, 100-fMultI((FIXP_DBL)0x666667, chBitrate));
2057        }
2058
2059        /* avoid hole parameters */
2060        if (chBitrate > 20000) {
2061            atsElem->ahParam.modifyMinSnr = TRUE;
2062            atsElem->ahParam.startSfbL = 15;
2063            atsElem->ahParam.startSfbS = 3;
2064        }
2065        else {
2066            atsElem->ahParam.modifyMinSnr = FALSE;
2067            atsElem->ahParam.startSfbL = 0;
2068            atsElem->ahParam.startSfbS = 0;
2069        }
2070
2071    		  /* minSnr adaptation */
2072        msaParam->maxRed = FL2FXCONST_DBL(0.00390625f); /* 0.25f/64.0f */
2073        /* start adaptation of minSnr for avgEn/sfbEn > startRatio */
2074        msaParam->startRatio = FL2FXCONST_DBL(0.05190512648f); /* ld64(10.0f) */
2075        /* maximum minSnr reduction to minSnr^maxRed is reached for
2076           avgEn/sfbEn >= maxRatio */
2077        /* msaParam->maxRatio = 1000.0f; */
2078        /*msaParam->redRatioFac = ((float)1.0f - msaParam->maxRed) / ((float)10.0f*log10(msaParam->startRatio/msaParam->maxRatio)/log10(2.0f)*(float)0.3010299956f);*/
2079        msaParam->redRatioFac = FL2FXCONST_DBL(-0.375f); /* -0.0375f * 10.0f */
2080        /*msaParam->redOffs = (float)1.0f - msaParam->redRatioFac * (float)10.0f * log10(msaParam->startRatio)/log10(2.0f) * (float)0.3010299956f;*/
2081        msaParam->redOffs = FL2FXCONST_DBL(0.021484375); /* 1.375f/64.0f */
2082
2083        /* init pe correction */
2084        atsElem->peCorrectionFactor_m = FL2FXCONST_DBL(0.5f); /* 1.0 */
2085        atsElem->peCorrectionFactor_e = 1;
2086
2087        atsElem->dynBitsLast = -1;
2088        atsElem->peLast = 0;
2089
2090        /* init bits to pe factor */
2091        atsElem->bits2PeFactor_m = FL2FXCONST_DBL(1.18f/(1<<(1)));
2092        atsElem->bits2PeFactor_e = 1;
2093    }
2094}
2095
2096
2097/*****************************************************************************
2098    functionname: FDKaacEnc_FDKaacEnc_calcPeCorrection
2099    description:  calc desired pe
2100*****************************************************************************/
2101static void FDKaacEnc_FDKaacEnc_calcPeCorrection(
2102        FIXP_DBL *const           correctionFac_m,
2103        INT *const                correctionFac_e,
2104        const INT                 peAct,
2105        const INT                 peLast,
2106        const INT                 bitsLast,
2107        const FIXP_DBL            bits2PeFactor_m,
2108        const INT                 bits2PeFactor_e
2109        )
2110{
2111  if ( (bitsLast > 0) && (peAct < 1.5f*peLast) && (peAct > 0.7f*peLast) &&
2112       (FDKaacEnc_bits2pe2(bitsLast, fMult(FL2FXCONST_DBL(1.2f/2.f), bits2PeFactor_m), bits2PeFactor_e+1) > peLast) &&
2113       (FDKaacEnc_bits2pe2(bitsLast, fMult(FL2FXCONST_DBL(0.65f),    bits2PeFactor_m), bits2PeFactor_e  ) < peLast) )
2114  {
2115    FIXP_DBL corrFac = *correctionFac_m;
2116
2117    int scaling = 0;
2118    FIXP_DBL denum = (FIXP_DBL)FDKaacEnc_bits2pe2(bitsLast, bits2PeFactor_m, bits2PeFactor_e);
2119    FIXP_DBL newFac = fDivNorm((FIXP_DBL)peLast, denum, &scaling);
2120
2121    /* dead zone, newFac and corrFac are scaled by 0.5 */
2122    if ((FIXP_DBL)peLast <= denum) { /* ratio <= 1.f */
2123      newFac = fixMax(scaleValue(fixMin( fMult(FL2FXCONST_DBL(1.1f/2.f), newFac), scaleValue(FL2FXCONST_DBL(  1.f/2.f), -scaling)), scaling), FL2FXCONST_DBL(0.85f/2.f) );
2124    }
2125    else { /* ratio < 1.f */
2126     newFac = fixMax( fixMin( scaleValue(fMult(FL2FXCONST_DBL(0.9f/2.f), newFac), scaling), FL2FXCONST_DBL(1.15f/2.f) ), FL2FXCONST_DBL(   1.f/2.f) );
2127    }
2128
2129    if (   ((newFac > FL2FXCONST_DBL(1.f/2.f)) && (corrFac < FL2FXCONST_DBL(1.f/2.f)))
2130        || ((newFac < FL2FXCONST_DBL(1.f/2.f)) && (corrFac > FL2FXCONST_DBL(1.f/2.f))))
2131    {
2132      corrFac = FL2FXCONST_DBL(1.f/2.f);
2133    }
2134
2135    /* faster adaptation towards 1.0, slower in the other direction */
2136    if ( (corrFac < FL2FXCONST_DBL(1.f/2.f) && newFac < corrFac)
2137      || (corrFac > FL2FXCONST_DBL(1.f/2.f) && newFac > corrFac) )
2138    {
2139      corrFac = fMult(FL2FXCONST_DBL(0.85f), corrFac) + fMult(FL2FXCONST_DBL(0.15f), newFac);
2140    }
2141    else {
2142      corrFac = fMult(FL2FXCONST_DBL(0.7f), corrFac) + fMult(FL2FXCONST_DBL(0.3f), newFac);
2143    }
2144
2145    corrFac = fixMax( fixMin( corrFac, FL2FXCONST_DBL(1.15f/2.f) ), FL2FXCONST_DBL(0.85/2.f) );
2146
2147    *correctionFac_m = corrFac;
2148    *correctionFac_e = 1;
2149  }
2150  else {
2151    *correctionFac_m = FL2FXCONST_DBL(1.f/2.f);
2152    *correctionFac_e = 1;
2153  }
2154}
2155
2156
2157void FDKaacEnc_DistributeBits(ADJ_THR_STATE *adjThrState,
2158    ATS_ELEMENT       *AdjThrStateElement,
2159    PSY_OUT_CHANNEL   *psyOutChannel[(2)],
2160    PE_DATA           *peData,
2161    INT               *grantedPe,
2162    INT               *grantedPeCorr,
2163    const INT         nChannels,
2164    const INT         commonWindow,
2165    const INT         grantedDynBits,
2166    const INT         bitresBits,
2167    const INT         maxBitresBits,
2168    const FIXP_DBL    maxBitFac,
2169    const INT         bitDistributenMode)
2170{
2171  FIXP_DBL bitFactor;
2172  INT noRedPe = peData->pe;
2173
2174  /* prefer short windows for calculation of bitFactor */
2175  INT curWindowSequence = LONG_WINDOW;
2176  if (nChannels==2) {
2177    if ((psyOutChannel[0]->lastWindowSequence == SHORT_WINDOW) ||
2178        (psyOutChannel[1]->lastWindowSequence == SHORT_WINDOW)) {
2179        curWindowSequence = SHORT_WINDOW;
2180    }
2181  }
2182  else {
2183    curWindowSequence = psyOutChannel[0]->lastWindowSequence;
2184  }
2185
2186  if (grantedDynBits >= 1) {
2187    if (bitDistributenMode!=0) {
2188      *grantedPe = FDKaacEnc_bits2pe2(grantedDynBits, AdjThrStateElement->bits2PeFactor_m, AdjThrStateElement->bits2PeFactor_e);
2189    }
2190    else
2191    {
2192    /* factor dependend on current fill level and pe */
2193    bitFactor = FDKaacEnc_bitresCalcBitFac(bitresBits, maxBitresBits, noRedPe,
2194                                 curWindowSequence, grantedDynBits, maxBitFac,
2195                                 adjThrState,
2196                                 AdjThrStateElement
2197                                 );
2198
2199    /* desired pe for actual frame */
2200    /* Worst case max of grantedDynBits is = 1024 * 5.27 * 2 */
2201    *grantedPe = FDKaacEnc_bits2pe2(grantedDynBits,
2202                     fMult(bitFactor, AdjThrStateElement->bits2PeFactor_m), AdjThrStateElement->bits2PeFactor_e+(DFRACT_BITS-1-Q_BITFAC)
2203                     );
2204    }
2205  }
2206  else {
2207    *grantedPe = 0; /* prevent divsion by 0 */
2208  }
2209
2210  /* correction of pe value */
2211  {
2212    FDKaacEnc_FDKaacEnc_calcPeCorrection(
2213       &AdjThrStateElement->peCorrectionFactor_m,
2214       &AdjThrStateElement->peCorrectionFactor_e,
2215        fixMin(*grantedPe, noRedPe),
2216        AdjThrStateElement->peLast,
2217        AdjThrStateElement->dynBitsLast,
2218        AdjThrStateElement->bits2PeFactor_m,
2219        AdjThrStateElement->bits2PeFactor_e
2220        );
2221  }
2222
2223  *grantedPeCorr = (INT)(fMult((FIXP_DBL)(*grantedPe<<Q_AVGBITS), AdjThrStateElement->peCorrectionFactor_m) >> (Q_AVGBITS-AdjThrStateElement->peCorrectionFactor_e));
2224
2225  /* update last pe */
2226  AdjThrStateElement->peLast = *grantedPe;
2227  AdjThrStateElement->dynBitsLast = -1;
2228
2229}
2230
2231/*****************************************************************************
2232functionname: FDKaacEnc_AdjustThresholds
2233description:  adjust thresholds
2234*****************************************************************************/
2235void FDKaacEnc_AdjustThresholds(ATS_ELEMENT*        AdjThrStateElement[(6)],
2236                                QC_OUT_ELEMENT*     qcElement[(6)],
2237                                QC_OUT*             qcOut,
2238                                PSY_OUT_ELEMENT*    psyOutElement[(6)],
2239                                INT                 CBRbitrateMode,
2240                                CHANNEL_MAPPING*    cm)
2241{
2242    int i;
2243    if (CBRbitrateMode)
2244    {
2245        /* In case, no bits must be shifted between different elements, */
2246        /* an element-wise execution of the pe-dependent threshold- */
2247        /* adaption becomes necessary... */
2248            for (i=0; i<cm->nElements; i++)
2249            {
2250                ELEMENT_INFO elInfo = cm->elInfo[i];
2251
2252                if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) ||
2253                    (elInfo.elType == ID_LFE))
2254                {
2255                    /* qcElement[i]->grantedPe = 2000; */  /* Use this only for debugging */
2256                    //if (totalGrantedPeCorr < totalNoRedPe) {
2257                    if (qcElement[i]->grantedPe < qcElement[i]->peData.pe)
2258                    {
2259                        /* calc threshold necessary for desired pe */
2260                        FDKaacEnc_adaptThresholdsToPe(cm,
2261                                            AdjThrStateElement,
2262                                            qcElement,
2263                                            psyOutElement,
2264                                            qcElement[i]->grantedPeCorr,
2265                                            1,         /* Process only 1 element */
2266                                            i);        /* Process exactly THIS element */
2267
2268                    }
2269
2270                }  /*  -end- if(ID_SCE || ID_CPE || ID_LFE) */
2271
2272            }  /* -end- element loop */
2273    }
2274    else {
2275        for (i=0; i<cm->nElements; i++)
2276        {
2277            ELEMENT_INFO elInfo = cm->elInfo[i];
2278
2279            if ((elInfo.elType == ID_SCE) || (elInfo.elType == ID_CPE) ||
2280                (elInfo.elType == ID_LFE))
2281            {
2282                  /* for VBR-mode */
2283                  FDKaacEnc_AdaptThresholdsVBR(qcElement[i]->qcOutChannel,
2284                                            psyOutElement[i]->psyOutChannel,
2285                                            AdjThrStateElement[i],
2286                                            &psyOutElement[i]->toolsInfo,
2287                                            &qcElement[i]->peData,
2288                                            cm->elInfo[i].nChannelsInEl);
2289            }  /*  -end- if(ID_SCE || ID_CPE || ID_LFE) */
2290
2291        }  /* -end- element loop */
2292
2293    }
2294        for (i=0; i<cm->nElements; i++) {
2295            int ch,sfb,sfbGrp;
2296            /* no weighting of threholds and energies for mlout */
2297            /* weight energies and thresholds */
2298            for (ch=0; ch<cm->elInfo[i].nChannelsInEl; ch++) {
2299                QC_OUT_CHANNEL* pQcOutCh = qcElement[i]->qcOutChannel[ch];
2300                for (sfbGrp = 0;sfbGrp < psyOutElement[i]->psyOutChannel[ch]->sfbCnt; sfbGrp+=psyOutElement[i]->psyOutChannel[ch]->sfbPerGroup) {
2301                    for (sfb=0; sfb<psyOutElement[i]->psyOutChannel[ch]->maxSfbPerGroup; sfb++) {
2302                        pQcOutCh->sfbThresholdLdData[sfb+sfbGrp] += pQcOutCh->sfbEnFacLd[sfb+sfbGrp];
2303                    }
2304                }
2305            }
2306        }
2307
2308}
2309
2310void FDKaacEnc_AdjThrClose(ADJ_THR_STATE** phAdjThr)
2311{
2312    INT i;
2313    ADJ_THR_STATE* hAdjThr = *phAdjThr;
2314
2315    if (hAdjThr!=NULL) {
2316      for (i=0; i<(6); i++) {
2317        if (hAdjThr->adjThrStateElem[i]!=NULL) {
2318          FreeRam_aacEnc_AdjThrStateElement(&hAdjThr->adjThrStateElem[i]);
2319        }
2320      }
2321      FreeRam_aacEnc_AdjustThreshold(phAdjThr);
2322    }
2323}
2324
2325