1 
2 /* -----------------------------------------------------------------------------------------------------------
3 Software License for The Fraunhofer FDK AAC Codec Library for Android
4 
5 � Copyright  1995 - 2013 Fraunhofer-Gesellschaft zur F�rderung der angewandten Forschung e.V.
6   All rights reserved.
7 
8  1.    INTRODUCTION
9 The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
10 the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
11 This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
12 
13 AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
14 audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
15 independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
16 of the MPEG specifications.
17 
18 Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
19 may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
20 individually for the purpose of encoding or decoding bit streams in products that are compliant with
21 the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
22 these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
23 software may already be covered under those patent licenses when it is used for those licensed purposes only.
24 
25 Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
26 are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
27 applications information and documentation.
28 
29 2.    COPYRIGHT LICENSE
30 
31 Redistribution and use in source and binary forms, with or without modification, are permitted without
32 payment of copyright license fees provided that you satisfy the following conditions:
33 
34 You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
35 your modifications thereto in source code form.
36 
37 You must retain the complete text of this software license in the documentation and/or other materials
38 provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
39 You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
40 modifications thereto to recipients of copies in binary form.
41 
42 The name of Fraunhofer may not be used to endorse or promote products derived from this library without
43 prior written permission.
44 
45 You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
46 software or your modifications thereto.
47 
48 Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
49 and the date of any change. For modified versions of the FDK AAC Codec, the term
50 "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
51 "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
52 
53 3.    NO PATENT LICENSE
54 
55 NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
56 ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
57 respect to this software.
58 
59 You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
60 by appropriate patent licenses.
61 
62 4.    DISCLAIMER
63 
64 This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
65 "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
66 of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
67 CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
68 including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
69 or business interruption, however caused and on any theory of liability, whether in contract, strict
70 liability, or tort (including negligence), arising in any way out of the use of this software, even if
71 advised of the possibility of such damage.
72 
73 5.    CONTACT INFORMATION
74 
75 Fraunhofer Institute for Integrated Circuits IIS
76 Attention: Audio and Multimedia Departments - FDK AAC LL
77 Am Wolfsmantel 33
78 91058 Erlangen, Germany
79 
80 www.iis.fraunhofer.de/amm
81 amm-info@iis.fraunhofer.de
82 ----------------------------------------------------------------------------------------------------------- */
83 
84 /******************************** MPEG Audio Encoder **************************
85 
86    Initial author:       M. Lohwasser
87    contents/description: pns.c
88 
89 ******************************************************************************/
90 
91 #include "aacenc_pns.h"
92 #include "psy_data.h"
93 #include "pnsparam.h"
94 #include "noisedet.h"
95 #include "bit_cnt.h"
96 #include "interface.h"
97 
98 
99 /* minCorrelationEnergy = (1.0e-10f)^2 ~ 2^-67 = 2^-47 * 2^-20 */
100 static const FIXP_DBL minCorrelationEnergy = FL2FXCONST_DBL(0.0); /* FL2FXCONST_DBL((float)FDKpow(2.0,-47)); */
101 /* noiseCorrelationThresh = 0.6^2 */
102 static const FIXP_DBL noiseCorrelationThresh = FL2FXCONST_DBL(0.36);
103 
104 static void FDKaacEnc_FDKaacEnc_noiseDetection( PNS_CONFIG  *pnsConf,
105                             PNS_DATA    *pnsData,
106                             const INT   sfbActive,
107                             const INT   *sfbOffset,
108                             INT          tnsOrder,
109                             INT         tnsPredictionGain,
110                             INT         tnsActive,
111                             FIXP_DBL    *mdctSpectrum,
112                             INT         *sfbMaxScaleSpec,
113                             FIXP_SGL    *sfbtonality );
114 
115 static void FDKaacEnc_CalcNoiseNrgs( const INT   sfbActive,
116                            INT         *pnsFlag,
117                            FIXP_DBL    *sfbEnergyLdData,
118                            INT         *noiseNrg );
119 
120 /*****************************************************************************
121 
122     functionname: initPnsConfiguration
123     description:  fill pnsConf with pns parameters
124     returns:      error status
125     input:        PNS Config struct (modified)
126                   bitrate, samplerate, usePns,
127                   number of sfb's, pointer to sfb offset
128     output:       error code
129 
130 *****************************************************************************/
131 
FDKaacEnc_InitPnsConfiguration(PNS_CONFIG * pnsConf,INT bitRate,INT sampleRate,INT usePns,INT sfbCnt,const INT * sfbOffset,const INT numChan,const INT isLC)132 AAC_ENCODER_ERROR FDKaacEnc_InitPnsConfiguration(PNS_CONFIG *pnsConf,
133                                                  INT         bitRate,
134                                                  INT         sampleRate,
135                                                  INT         usePns,
136                                                  INT         sfbCnt,
137                                                  const INT  *sfbOffset,
138                                                  const INT   numChan,
139                                                  const INT   isLC)
140 {
141   AAC_ENCODER_ERROR ErrorStatus;
142 
143   /* init noise detection */
144   ErrorStatus = FDKaacEnc_GetPnsParam(&pnsConf->np,
145                                       bitRate,
146                                       sampleRate,
147                                       sfbCnt,
148                                       sfbOffset,
149                                       &usePns,
150                                       numChan,
151                                       isLC);
152   if (ErrorStatus != AAC_ENC_OK)
153     return ErrorStatus;
154 
155   pnsConf->minCorrelationEnergy = minCorrelationEnergy;
156   pnsConf->noiseCorrelationThresh = noiseCorrelationThresh;
157 
158   pnsConf->usePns = usePns;
159 
160   return AAC_ENC_OK;
161 }
162 
163 
164 
165 /*****************************************************************************
166 
167     functionname: FDKaacEnc_PnsDetect
168     description:  do decision, if PNS shall used or not
169     returns:
170     input:        pns config structure
171                   pns data structure (modified),
172                   lastWindowSequence (long or short blocks)
173                   sfbActive
174                   pointer to Sfb Energy, Threshold, Offset
175                   pointer to mdct Spectrum
176                   length of each group
177                   pointer to tonality calculated in chaosmeasure
178                   tns order and prediction gain
179                   calculated noiseNrg at active PNS
180     output:       pnsFlag in pns data structure
181 
182 *****************************************************************************/
FDKaacEnc_PnsDetect(PNS_CONFIG * pnsConf,PNS_DATA * pnsData,const INT lastWindowSequence,const INT sfbActive,const INT maxSfbPerGroup,FIXP_DBL * sfbThresholdLdData,const INT * sfbOffset,FIXP_DBL * mdctSpectrum,INT * sfbMaxScaleSpec,FIXP_SGL * sfbtonality,INT tnsOrder,INT tnsPredictionGain,INT tnsActive,FIXP_DBL * sfbEnergyLdData,INT * noiseNrg)183 void FDKaacEnc_PnsDetect(PNS_CONFIG  *pnsConf,
184                          PNS_DATA    *pnsData,
185                          const INT    lastWindowSequence,
186                          const INT    sfbActive,
187                          const INT    maxSfbPerGroup,
188                          FIXP_DBL    *sfbThresholdLdData,
189                          const INT   *sfbOffset,
190                          FIXP_DBL    *mdctSpectrum,
191                          INT         *sfbMaxScaleSpec,
192                          FIXP_SGL    *sfbtonality,
193                          INT          tnsOrder,
194                          INT          tnsPredictionGain,
195                          INT          tnsActive,
196                          FIXP_DBL    *sfbEnergyLdData,
197                          INT         *noiseNrg )
198 
199 {
200   int sfb;
201   int startNoiseSfb;
202 
203   if (pnsConf->np.detectionAlgorithmFlags & IS_LOW_COMLEXITY) {
204     if ( (!pnsConf->usePns) ||              /* pns enabled? */
205            (lastWindowSequence == SHORT_WINDOW) ) /* currently only long blocks */
206     {
207       FDKmemclear(pnsData->pnsFlag, MAX_GROUPED_SFB*sizeof(INT)); /* clear all pnsFlags */
208       for (sfb=0; sfb<MAX_GROUPED_SFB; sfb++) {
209           noiseNrg[sfb] = NO_NOISE_PNS;                           /* clear nrg's of previous frame */
210       }
211       return;
212     }
213   }
214   else {
215     if(!pnsConf->usePns)
216       return;
217 
218     /* PNS only for long Windows */
219     if (pnsConf->np.detectionAlgorithmFlags & JUST_LONG_WINDOW) {
220       if(lastWindowSequence != LONG_WINDOW) {
221         for (sfb = 0; sfb < sfbActive; sfb++) {
222           pnsData->pnsFlag[sfb] = 0;    /* clear all pnsFlags */
223         }
224         return;
225       }
226     }
227   }
228   /*
229     call noise detection
230   */
231   FDKaacEnc_FDKaacEnc_noiseDetection( pnsConf,
232                   pnsData,
233                   sfbActive,
234                   sfbOffset,
235                   tnsOrder,
236                   tnsPredictionGain,
237                   tnsActive,
238                   mdctSpectrum,
239                   sfbMaxScaleSpec,
240                   sfbtonality );
241 
242   /* set startNoiseSfb (long) */
243   startNoiseSfb = pnsConf->np.startSfb;
244 
245   /* Set noise substitution status */
246   for(sfb = 0; sfb < sfbActive; sfb++) {
247 
248     /* No PNS below startNoiseSfb */
249     if(sfb < startNoiseSfb){
250       pnsData->pnsFlag[sfb] = 0;
251       continue;
252     }
253 
254     /*
255       do noise substitution if
256       fuzzy measure is high enough
257       sfb freq > minimum sfb freq
258       signal in coder band is not masked
259     */
260 
261     if((pnsData->noiseFuzzyMeasure[sfb] > FL2FXCONST_SGL(0.5)) &&
262        ( (sfbThresholdLdData[sfb] + FL2FXCONST_DBL(0.5849625f/64.0f))  /* thr * 1.5 = thrLd +ld(1.5)/64 */
263          < sfbEnergyLdData[sfb] ) )
264     {
265       /*
266         mark in psyout flag array that we will code
267         this band with PNS
268       */
269       pnsData->pnsFlag[sfb] = 1; /* PNS_ON */
270     }
271     else{
272       pnsData->pnsFlag[sfb] = 0; /* PNS_OFF */
273     }
274 
275     /* no PNS if LTP is active */
276   }
277 
278   /* avoid PNS holes */
279   if((pnsData->noiseFuzzyMeasure[0]>FL2FXCONST_SGL(0.5f)) && (pnsData->pnsFlag[1])) {
280     pnsData->pnsFlag[0] = 1;
281   }
282 
283   for(sfb=1; sfb<maxSfbPerGroup-1; sfb++) {
284     if((pnsData->noiseFuzzyMeasure[sfb]>pnsConf->np.gapFillThr) &&
285        (pnsData->pnsFlag[sfb-1]) && (pnsData->pnsFlag[sfb+1])) {
286       pnsData->pnsFlag[sfb] = 1;
287     }
288   }
289 
290   if(maxSfbPerGroup>0) {
291     /* avoid PNS hole */
292     if((pnsData->noiseFuzzyMeasure[maxSfbPerGroup-1]>pnsConf->np.gapFillThr) && (pnsData->pnsFlag[maxSfbPerGroup-2])) {
293       pnsData->pnsFlag[maxSfbPerGroup-1] = 1;
294     }
295     /* avoid single PNS band */
296     if(pnsData->pnsFlag[maxSfbPerGroup-2]==0) {
297       pnsData->pnsFlag[maxSfbPerGroup-1] = 0;
298     }
299   }
300 
301   /* avoid single PNS bands */
302   if(pnsData->pnsFlag[1]==0) {
303     pnsData->pnsFlag[0] = 0;
304   }
305 
306   for(sfb=1; sfb<maxSfbPerGroup-1; sfb++) {
307     if((pnsData->pnsFlag[sfb-1]==0)&&(pnsData->pnsFlag[sfb+1]==0)) {
308       pnsData->pnsFlag[sfb] = 0;
309     }
310   }
311 
312 
313   /*
314     calculate noiseNrg's
315   */
316   FDKaacEnc_CalcNoiseNrgs( sfbActive,
317                  pnsData->pnsFlag,
318                  sfbEnergyLdData,
319                  noiseNrg );
320 }
321 
322 
323 /*****************************************************************************
324 
325     functionname:FDKaacEnc_FDKaacEnc_noiseDetection
326     description: wrapper for noisedet.c
327     returns:
328     input:       pns config structure
329                  pns data structure (modified),
330                  sfbActive
331                  tns order and prediction gain
332                  pointer to mdct Spectrumand Sfb Energy
333                  pointer to Sfb tonality
334     output:      noiseFuzzyMeasure in structure pnsData
335                  flags tonal / nontonal
336 
337 *****************************************************************************/
FDKaacEnc_FDKaacEnc_noiseDetection(PNS_CONFIG * pnsConf,PNS_DATA * pnsData,const INT sfbActive,const INT * sfbOffset,int tnsOrder,INT tnsPredictionGain,INT tnsActive,FIXP_DBL * mdctSpectrum,INT * sfbMaxScaleSpec,FIXP_SGL * sfbtonality)338 static void FDKaacEnc_FDKaacEnc_noiseDetection( PNS_CONFIG  *pnsConf,
339                             PNS_DATA    *pnsData,
340                             const INT   sfbActive,
341                             const INT   *sfbOffset,
342                             int          tnsOrder,
343                             INT         tnsPredictionGain,
344                             INT         tnsActive,
345                             FIXP_DBL    *mdctSpectrum,
346                             INT         *sfbMaxScaleSpec,
347                             FIXP_SGL    *sfbtonality )
348 {
349     INT condition = TRUE;
350     if ( !(pnsConf->np.detectionAlgorithmFlags & IS_LOW_COMLEXITY) ) {
351       condition = (tnsOrder > 3);
352     }
353     /*
354     no PNS if heavy TNS activity
355     clear pnsData->noiseFuzzyMeasure
356     */
357     if((pnsConf->np.detectionAlgorithmFlags & USE_TNS_GAIN_THR) &&
358       (tnsPredictionGain >= pnsConf->np.tnsGainThreshold) && condition &&
359       !((pnsConf->np.detectionAlgorithmFlags & USE_TNS_PNS) && (tnsPredictionGain >= pnsConf->np.tnsPNSGainThreshold) && (tnsActive)) )
360     {
361         /* clear all noiseFuzzyMeasure */
362         FDKmemclear(pnsData->noiseFuzzyMeasure, sfbActive*sizeof(FIXP_SGL));
363     }
364     else
365     {
366         /*
367         call noise detection, output in pnsData->noiseFuzzyMeasure,
368         use real mdct spectral data
369         */
370         FDKaacEnc_noiseDetect( mdctSpectrum,
371             sfbMaxScaleSpec,
372             sfbActive,
373             sfbOffset,
374             pnsData->noiseFuzzyMeasure,
375             &pnsConf->np,
376             sfbtonality);
377     }
378 }
379 
380 
381 /*****************************************************************************
382 
383     functionname:FDKaacEnc_CalcNoiseNrgs
384     description: Calculate the NoiseNrg's
385     returns:
386     input:       sfbActive
387                  if pnsFlag calculate NoiseNrg
388                  pointer to sfbEnergy and groupLen
389                  pointer to noiseNrg (modified)
390     output:      noiseNrg's in pnsFlaged sfb's
391 
392 *****************************************************************************/
393 
FDKaacEnc_CalcNoiseNrgs(const INT sfbActive,INT * RESTRICT pnsFlag,FIXP_DBL * RESTRICT sfbEnergyLdData,INT * RESTRICT noiseNrg)394 static void FDKaacEnc_CalcNoiseNrgs( const INT    sfbActive,
395                            INT         *RESTRICT pnsFlag,
396                            FIXP_DBL    *RESTRICT sfbEnergyLdData,
397                            INT         *RESTRICT noiseNrg )
398 {
399   int sfb;
400   INT tmp = (-LOG_NORM_PCM)<<2;
401 
402   for(sfb = 0; sfb < sfbActive; sfb++) {
403     if(pnsFlag[sfb]) {
404       INT nrg = (-sfbEnergyLdData[sfb]+FL2FXCONST_DBL(0.5f/64.0f))>>(DFRACT_BITS-1-7);
405       noiseNrg[sfb] = tmp - nrg;
406     }
407   }
408 }
409 
410 
411 /*****************************************************************************
412 
413     functionname:FDKaacEnc_CodePnsChannel
414     description: Execute pns decission
415     returns:
416     input:       sfbActive
417                  pns config structure
418                  use PNS if pnsFlag
419                  pointer to Sfb Energy, noiseNrg, Threshold
420     output:      set sfbThreshold high to code pe with 0,
421                  noiseNrg marks flag for pns coding
422 
423 *****************************************************************************/
424 
FDKaacEnc_CodePnsChannel(const INT sfbActive,PNS_CONFIG * pnsConf,INT * RESTRICT pnsFlag,FIXP_DBL * RESTRICT sfbEnergyLdData,INT * RESTRICT noiseNrg,FIXP_DBL * RESTRICT sfbThresholdLdData)425 void FDKaacEnc_CodePnsChannel(const INT     sfbActive,
426                               PNS_CONFIG    *pnsConf,
427                               INT           *RESTRICT pnsFlag,
428                               FIXP_DBL      *RESTRICT sfbEnergyLdData,
429                               INT           *RESTRICT noiseNrg,
430                               FIXP_DBL      *RESTRICT sfbThresholdLdData)
431 {
432   INT sfb;
433   INT lastiNoiseEnergy = 0;
434   INT firstPNSband = 1; /* TRUE for first PNS-coded band */
435 
436   /* no PNS */
437   if(!pnsConf->usePns) {
438     for(sfb = 0; sfb < sfbActive; sfb++) {
439       /* no PNS coding */
440       noiseNrg[sfb] = NO_NOISE_PNS;
441     }
442     return;
443   }
444 
445   /* code PNS */
446   for(sfb = 0; sfb < sfbActive; sfb++) {
447     if(pnsFlag[sfb]) {
448       /* high sfbThreshold causes pe = 0 */
449       if(noiseNrg[sfb] != NO_NOISE_PNS)
450         sfbThresholdLdData[sfb] = sfbEnergyLdData[sfb] + FL2FXCONST_DBL(1.0f/LD_DATA_SCALING);
451 
452       /* set noiseNrg in valid region */
453       if(!firstPNSband) {
454         INT deltaiNoiseEnergy = noiseNrg[sfb] - lastiNoiseEnergy;
455 
456         if(deltaiNoiseEnergy > CODE_BOOK_PNS_LAV)
457             noiseNrg[sfb] -= deltaiNoiseEnergy - CODE_BOOK_PNS_LAV;
458         else if(deltaiNoiseEnergy < -CODE_BOOK_PNS_LAV)
459             noiseNrg[sfb] -= deltaiNoiseEnergy + CODE_BOOK_PNS_LAV;
460       }
461       else {
462         firstPNSband = 0;
463       }
464       lastiNoiseEnergy = noiseNrg[sfb];
465     }
466     else {
467       /* no PNS coding */
468       noiseNrg[sfb] = NO_NOISE_PNS;
469     }
470   }
471 }
472 
473 
474 /*****************************************************************************
475 
476     functionname:FDKaacEnc_PreProcessPnsChannelPair
477     description: Calculate the correlation of noise in a channel pair
478 
479     returns:
480     input:       sfbActive
481                  pointer to sfb energies left, right and mid channel
482                  pns config structure
483                  pns data structure left and right (modified)
484 
485     output:      noiseEnergyCorrelation in pns data structure
486 
487 *****************************************************************************/
488 
FDKaacEnc_PreProcessPnsChannelPair(const INT sfbActive,FIXP_DBL * RESTRICT sfbEnergyLeft,FIXP_DBL * RESTRICT sfbEnergyRight,FIXP_DBL * RESTRICT sfbEnergyLeftLD,FIXP_DBL * RESTRICT sfbEnergyRightLD,FIXP_DBL * RESTRICT sfbEnergyMid,PNS_CONFIG * RESTRICT pnsConf,PNS_DATA * pnsDataLeft,PNS_DATA * pnsDataRight)489 void FDKaacEnc_PreProcessPnsChannelPair(const INT   sfbActive,
490                                         FIXP_DBL   *RESTRICT sfbEnergyLeft,
491                                         FIXP_DBL   *RESTRICT sfbEnergyRight,
492                                         FIXP_DBL   *RESTRICT sfbEnergyLeftLD,
493                                         FIXP_DBL   *RESTRICT sfbEnergyRightLD,
494                                         FIXP_DBL   *RESTRICT sfbEnergyMid,
495                                         PNS_CONFIG *RESTRICT pnsConf,
496                                         PNS_DATA   *pnsDataLeft,
497                                         PNS_DATA   *pnsDataRight)
498 {
499   INT sfb;
500   FIXP_DBL ccf;
501 
502   if(!pnsConf->usePns)
503     return;
504 
505   FIXP_DBL *RESTRICT pNoiseEnergyCorrelationL = pnsDataLeft->noiseEnergyCorrelation;
506   FIXP_DBL *RESTRICT pNoiseEnergyCorrelationR = pnsDataRight->noiseEnergyCorrelation;
507 
508   for(sfb=0;sfb< sfbActive;sfb++) {
509     FIXP_DBL quot = (sfbEnergyLeftLD[sfb]>>1) + (sfbEnergyRightLD[sfb]>>1);
510 
511     if(quot < FL2FXCONST_DBL(-32.0f/(float)LD_DATA_SCALING))
512       ccf = FL2FXCONST_DBL(0.0f);
513     else {
514       FIXP_DBL accu = sfbEnergyMid[sfb]- (((sfbEnergyLeft[sfb]>>1)+(sfbEnergyRight[sfb]>>1))>>1);
515       INT sign = (accu < FL2FXCONST_DBL(0.0f)) ? 1 : 0 ;
516       accu = fixp_abs(accu);
517 
518       ccf = CalcLdData(accu) + FL2FXCONST_DBL((float)1.0f/(float)LD_DATA_SCALING) - quot;   /* ld(accu*2) = ld(accu) + 1 */
519       ccf = (ccf>=FL2FXCONST_DBL(0.0)) ? ((FIXP_DBL)MAXVAL_DBL) : (sign) ? -CalcInvLdData(ccf) : CalcInvLdData(ccf);
520     }
521 
522     pNoiseEnergyCorrelationL[sfb] = ccf;
523     pNoiseEnergyCorrelationR[sfb] = ccf;
524   }
525 }
526 
527 
528 
529 /*****************************************************************************
530 
531     functionname:FDKaacEnc_PostProcessPnsChannelPair
532     description: if PNS used at left and right channel,
533                  use msMask to flag correlation
534     returns:
535     input:       sfbActive
536                  pns config structure
537                  pns data structure left and right (modified)
538                  pointer to msMask, flags correlation by pns coding (modified)
539                  Digest of MS coding
540     output:      pnsFlag in pns data structure,
541                  msFlag in msMask (flags correlation)
542 
543 *****************************************************************************/
544 
FDKaacEnc_PostProcessPnsChannelPair(const INT sfbActive,PNS_CONFIG * pnsConf,PNS_DATA * pnsDataLeft,PNS_DATA * pnsDataRight,INT * RESTRICT msMask,INT * msDigest)545 void FDKaacEnc_PostProcessPnsChannelPair(const INT   sfbActive,
546                                          PNS_CONFIG  *pnsConf,
547                                          PNS_DATA    *pnsDataLeft,
548                                          PNS_DATA    *pnsDataRight,
549                                          INT         *RESTRICT msMask,
550                                          INT         *msDigest )
551 {
552   INT sfb;
553 
554   if(!pnsConf->usePns)
555     return;
556 
557   for(sfb=0;sfb<sfbActive;sfb++) {
558     /*
559       MS post processing
560     */
561     if( msMask[sfb] ) {
562       if( (pnsDataLeft->pnsFlag[sfb]) &&
563           (pnsDataRight->pnsFlag[sfb]) ) {
564         /* AAC only: Standard */
565         /* do this to avoid ms flags in layers that should not have it */
566         if(pnsDataLeft->noiseEnergyCorrelation[sfb] <= pnsConf->noiseCorrelationThresh){
567           msMask[sfb] = 0;
568           *msDigest = MS_SOME;
569         }
570       }
571       else {
572         /*
573           No PNS coding
574         */
575         pnsDataLeft->pnsFlag[sfb] = 0;
576         pnsDataRight->pnsFlag[sfb] = 0;
577       }
578     }
579 
580     /*
581       Use MS flag to signal noise correlation if
582       pns is active in both channels
583     */
584     if( (pnsDataLeft->pnsFlag[sfb]) && (pnsDataRight->pnsFlag[sfb]) ) {
585       if(pnsDataLeft->noiseEnergyCorrelation[sfb] > pnsConf->noiseCorrelationThresh) {
586         msMask[sfb] = 1;
587         *msDigest = MS_SOME;
588       }
589     }
590   }
591 }
592