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. 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 */
100static const FIXP_DBL minCorrelationEnergy = FL2FXCONST_DBL(0.0); /* FL2FXCONST_DBL((float)FDKpow(2.0,-47)); */
101/* noiseCorrelationThresh = 0.6^2 */
102static const FIXP_DBL noiseCorrelationThresh = FL2FXCONST_DBL(0.36);
103
104static 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
115static 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
132AAC_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*****************************************************************************/
183void 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*****************************************************************************/
338static 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
394static 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
425void 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
489void 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
545void 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