Coverage Report

Created: 2025-07-18 06:08

/src/aac/libAACenc/src/intensity.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -----------------------------------------------------------------------------
2
Software License for The Fraunhofer FDK AAC Codec Library for Android
3
4
© Copyright  1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
5
Forschung e.V. All rights reserved.
6
7
 1.    INTRODUCTION
8
The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9
that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10
scheme for digital audio. This FDK AAC Codec software is intended to be used on
11
a wide variety of Android devices.
12
13
AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14
general perceptual audio codecs. AAC-ELD is considered the best-performing
15
full-bandwidth communications codec by independent studies and is widely
16
deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17
specifications.
18
19
Patent licenses for necessary patent claims for the FDK AAC Codec (including
20
those of Fraunhofer) may be obtained through Via Licensing
21
(www.vialicensing.com) or through the respective patent owners individually for
22
the purpose of encoding or decoding bit streams in products that are compliant
23
with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24
Android devices already license these patent claims through Via Licensing or
25
directly from the patent owners, and therefore FDK AAC Codec software may
26
already be covered under those patent licenses when it is used for those
27
licensed purposes only.
28
29
Commercially-licensed AAC software libraries, including floating-point versions
30
with enhanced sound quality, are also available from Fraunhofer. Users are
31
encouraged to check the Fraunhofer website for additional applications
32
information and documentation.
33
34
2.    COPYRIGHT LICENSE
35
36
Redistribution and use in source and binary forms, with or without modification,
37
are permitted without payment of copyright license fees provided that you
38
satisfy the following conditions:
39
40
You must retain the complete text of this software license in redistributions of
41
the FDK AAC Codec or your modifications thereto in source code form.
42
43
You must retain the complete text of this software license in the documentation
44
and/or other materials provided with redistributions of the FDK AAC Codec or
45
your modifications thereto in binary form. You must make available free of
46
charge copies of the complete source code of the FDK AAC Codec and your
47
modifications thereto to recipients of copies in binary form.
48
49
The name of Fraunhofer may not be used to endorse or promote products derived
50
from this library without prior written permission.
51
52
You may not charge copyright license fees for anyone to use, copy or distribute
53
the FDK AAC Codec software or your modifications thereto.
54
55
Your modified versions of the FDK AAC Codec must carry prominent notices stating
56
that you changed the software and the date of any change. For modified versions
57
of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58
must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59
AAC Codec Library for Android."
60
61
3.    NO PATENT LICENSE
62
63
NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64
limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65
Fraunhofer provides no warranty of patent non-infringement with respect to this
66
software.
67
68
You may use this FDK AAC Codec software or modifications thereto only for
69
purposes that are authorized by appropriate patent licenses.
70
71
4.    DISCLAIMER
72
73
This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74
holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75
including but not limited to the implied warranties of merchantability and
76
fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77
CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78
or consequential damages, including but not limited to procurement of substitute
79
goods or services; loss of use, data, or profits, or business interruption,
80
however caused and on any theory of liability, whether in contract, strict
81
liability, or tort (including negligence), arising in any way out of the use of
82
this software, even if advised of the possibility of such damage.
83
84
5.    CONTACT INFORMATION
85
86
Fraunhofer Institute for Integrated Circuits IIS
87
Attention: Audio and Multimedia Departments - FDK AAC LL
88
Am Wolfsmantel 33
89
91058 Erlangen, Germany
90
91
www.iis.fraunhofer.de/amm
92
amm-info@iis.fraunhofer.de
93
----------------------------------------------------------------------------- */
94
95
/**************************** AAC encoder library ******************************
96
97
   Author(s):   A. Horndasch (code originally from lwr) / Josef Hoepfl (FDK)
98
99
   Description: intensity stereo processing
100
101
*******************************************************************************/
102
103
#include "intensity.h"
104
105
#include "interface.h"
106
#include "psy_configuration.h"
107
#include "psy_const.h"
108
#include "qc_main.h"
109
#include "bit_cnt.h"
110
111
/* only set an IS seed it left/right channel correlation is above IS_CORR_THRESH
112
 */
113
0
#define IS_CORR_THRESH FL2FXCONST_DBL(0.95f)
114
115
/* when expanding the IS region to more SFBs only accept an error that is
116
 * not more than IS_TOTAL_ERROR_THRESH overall and
117
 * not more than IS_LOCAL_ERROR_THRESH for the current SFB */
118
0
#define IS_TOTAL_ERROR_THRESH FL2FXCONST_DBL(0.04f)
119
0
#define IS_LOCAL_ERROR_THRESH FL2FXCONST_DBL(0.01f)
120
121
/* the maximum allowed change of the intensity direction (unit: IS scale) -
122
 * scaled with factor 0.25 - */
123
0
#define IS_DIRECTION_DEVIATION_THRESH_SF 2
124
#define IS_DIRECTION_DEVIATION_THRESH \
125
0
  FL2FXCONST_DBL(2.0f / (1 << IS_DIRECTION_DEVIATION_THRESH_SF))
126
127
/* IS regions need to have a minimal percentage of the overall loudness, e.g.
128
 * 0.06 == 6% */
129
0
#define IS_REGION_MIN_LOUDNESS FL2FXCONST_DBL(0.1f)
130
131
/* only perform IS if IS_MIN_SFBS neighboring SFBs can be processed */
132
0
#define IS_MIN_SFBS 6
133
134
/* only do IS if
135
 * if IS_LEFT_RIGHT_RATIO_THRESH < sfbEnergyLeft[sfb]/sfbEnergyRight[sfb] < 1 /
136
 * IS_LEFT_RIGHT_RATIO_THRESH
137
 * -> no IS if the panning angle is not far from the middle, MS will do */
138
/* this is equivalent to a scale of +/-1.02914634566 */
139
0
#define IS_LEFT_RIGHT_RATIO_THRESH FL2FXCONST_DBL(0.7f)
140
141
/* scalefactor of realScale */
142
0
#define REAL_SCALE_SF 1
143
144
/* scalefactor overallLoudness */
145
0
#define OVERALL_LOUDNESS_SF 6
146
147
/* scalefactor for sum over max samples per goup */
148
0
#define MAX_SFB_PER_GROUP_SF 6
149
150
/* scalefactor for sum of mdct spectrum */
151
0
#define MDCT_SPEC_SF 6
152
153
typedef struct {
154
  FIXP_DBL corr_thresh; /*!< Only set an IS seed it left/right channel
155
                           correlation is above corr_thresh */
156
157
  FIXP_DBL total_error_thresh; /*!< When expanding the IS region to more SFBs
158
                                  only accept an error that is not more than
159
                                  'total_error_thresh' overall. */
160
161
  FIXP_DBL local_error_thresh; /*!< When expanding the IS region to more SFBs
162
                                  only accept an error that is not more than
163
                                  'local_error_thresh' for the current SFB. */
164
165
  FIXP_DBL direction_deviation_thresh; /*!< The maximum allowed change of the
166
                                          intensity direction (unit: IS scale)
167
                                        */
168
169
  FIXP_DBL is_region_min_loudness; /*!< IS regions need to have a minimal
170
                                      percentage of the overall loudness, e.g.
171
                                      0.06 == 6% */
172
173
  INT min_is_sfbs; /*!< Only perform IS if 'min_is_sfbs' neighboring SFBs can be
174
                      processed */
175
176
  FIXP_DBL left_right_ratio_threshold; /*!< No IS if the panning angle is not
177
                                          far from the middle, MS will do */
178
179
} INTENSITY_PARAMETERS;
180
181
/*****************************************************************************
182
183
    functionname: calcSfbMaxScale
184
185
    description:  Calc max value in scalefactor band
186
187
    input:        *mdctSpectrum
188
                   l1
189
                   l2
190
191
    output:       none
192
193
    returns:      scalefactor
194
195
*****************************************************************************/
196
static INT calcSfbMaxScale(const FIXP_DBL *mdctSpectrum, const INT l1,
197
0
                           const INT l2) {
198
0
  INT i;
199
0
  INT sfbMaxScale;
200
0
  FIXP_DBL maxSpc;
201
202
0
  maxSpc = FL2FXCONST_DBL(0.0);
203
0
  for (i = l1; i < l2; i++) {
204
0
    FIXP_DBL tmp = fixp_abs((FIXP_DBL)mdctSpectrum[i]);
205
0
    maxSpc = fixMax(maxSpc, tmp);
206
0
  }
207
0
  sfbMaxScale = (maxSpc == FL2FXCONST_DBL(0.0)) ? (DFRACT_BITS - 2)
208
0
                                                : CntLeadingZeros(maxSpc) - 1;
209
210
0
  return sfbMaxScale;
211
0
}
212
213
/*****************************************************************************
214
215
    functionname: FDKaacEnc_initIsParams
216
217
    description:  Initialization of intensity parameters
218
219
    input:        isParams
220
221
    output:       isParams
222
223
    returns:      none
224
225
*****************************************************************************/
226
0
static void FDKaacEnc_initIsParams(INTENSITY_PARAMETERS *isParams) {
227
0
  isParams->corr_thresh = IS_CORR_THRESH;
228
0
  isParams->total_error_thresh = IS_TOTAL_ERROR_THRESH;
229
0
  isParams->local_error_thresh = IS_LOCAL_ERROR_THRESH;
230
0
  isParams->direction_deviation_thresh = IS_DIRECTION_DEVIATION_THRESH;
231
0
  isParams->is_region_min_loudness = IS_REGION_MIN_LOUDNESS;
232
0
  isParams->min_is_sfbs = IS_MIN_SFBS;
233
0
  isParams->left_right_ratio_threshold = IS_LEFT_RIGHT_RATIO_THRESH;
234
0
}
235
236
/*****************************************************************************
237
238
    functionname: FDKaacEnc_prepareIntensityDecision
239
240
    description:  Prepares intensity decision
241
242
    input:        sfbEnergyLeft
243
                  sfbEnergyRight
244
                  sfbEnergyLdDataLeft
245
                  sfbEnergyLdDataRight
246
                  mdctSpectrumLeft
247
                  sfbEnergyLdDataRight
248
                  isParams
249
250
    output:       hrrErr            scale: none
251
                  isMask            scale: none
252
                  realScale         scale: LD_DATA_SHIFT + REAL_SCALE_SF
253
                  normSfbLoudness   scale: none
254
255
    returns:      none
256
257
*****************************************************************************/
258
static void FDKaacEnc_prepareIntensityDecision(
259
    const FIXP_DBL *sfbEnergyLeft, const FIXP_DBL *sfbEnergyRight,
260
    const FIXP_DBL *sfbEnergyLdDataLeft, const FIXP_DBL *sfbEnergyLdDataRight,
261
    const FIXP_DBL *mdctSpectrumLeft, const FIXP_DBL *mdctSpectrumRight,
262
    const INTENSITY_PARAMETERS *isParams, FIXP_DBL *hrrErr, INT *isMask,
263
    FIXP_DBL *realScale, FIXP_DBL *normSfbLoudness, const INT sfbCnt,
264
0
    const INT sfbPerGroup, const INT maxSfbPerGroup, const INT *sfbOffset) {
265
0
  INT j, sfb, sfboffs;
266
0
  INT grpCounter;
267
268
  /* temporary variables to compute loudness */
269
0
  FIXP_DBL overallLoudness[MAX_NO_OF_GROUPS];
270
271
  /* temporary variables to compute correlation */
272
0
  FIXP_DBL channelCorr[MAX_GROUPED_SFB];
273
0
  FIXP_DBL ml, mr;
274
0
  FIXP_DBL prod_lr;
275
0
  FIXP_DBL square_l, square_r;
276
0
  FIXP_DBL tmp_l, tmp_r;
277
0
  FIXP_DBL inv_n;
278
279
0
  FDKmemclear(channelCorr, MAX_GROUPED_SFB * sizeof(FIXP_DBL));
280
0
  FDKmemclear(normSfbLoudness, MAX_GROUPED_SFB * sizeof(FIXP_DBL));
281
0
  FDKmemclear(overallLoudness, MAX_NO_OF_GROUPS * sizeof(FIXP_DBL));
282
0
  FDKmemclear(realScale, MAX_GROUPED_SFB * sizeof(FIXP_DBL));
283
284
0
  for (grpCounter = 0, sfboffs = 0; sfboffs < sfbCnt;
285
0
       sfboffs += sfbPerGroup, grpCounter++) {
286
0
    overallLoudness[grpCounter] = FL2FXCONST_DBL(0.0f);
287
0
    for (sfb = 0; sfb < maxSfbPerGroup; sfb++) {
288
0
      INT sL, sR, s;
289
0
      FIXP_DBL isValue = sfbEnergyLdDataLeft[sfb + sfboffs] -
290
0
                         sfbEnergyLdDataRight[sfb + sfboffs];
291
292
      /* delimitate intensity scale value to representable range */
293
0
      realScale[sfb + sfboffs] = fixMin(
294
0
          FL2FXCONST_DBL(60.f / (1 << (REAL_SCALE_SF + LD_DATA_SHIFT))),
295
0
          fixMax(FL2FXCONST_DBL(-60.f / (1 << (REAL_SCALE_SF + LD_DATA_SHIFT))),
296
0
                 isValue));
297
298
0
      sL = fixMax(0, (CntLeadingZeros(sfbEnergyLeft[sfb + sfboffs]) - 1));
299
0
      sR = fixMax(0, (CntLeadingZeros(sfbEnergyRight[sfb + sfboffs]) - 1));
300
0
      s = (fixMin(sL, sR) >> 2) << 2;
301
0
      normSfbLoudness[sfb + sfboffs] =
302
0
          sqrtFixp(sqrtFixp(((sfbEnergyLeft[sfb + sfboffs] << s) >> 1) +
303
0
                            ((sfbEnergyRight[sfb + sfboffs] << s) >> 1))) >>
304
0
          (s >> 2);
305
306
0
      overallLoudness[grpCounter] +=
307
0
          normSfbLoudness[sfb + sfboffs] >> OVERALL_LOUDNESS_SF;
308
      /* don't do intensity if
309
       * - panning angle is too close to the middle or
310
       * - one channel is non-existent or
311
       * - if it is dual mono */
312
0
      if ((sfbEnergyLeft[sfb + sfboffs] >=
313
0
           fMult(isParams->left_right_ratio_threshold,
314
0
                 sfbEnergyRight[sfb + sfboffs])) &&
315
0
          (fMult(isParams->left_right_ratio_threshold,
316
0
                 sfbEnergyLeft[sfb + sfboffs]) <=
317
0
           sfbEnergyRight[sfb + sfboffs])) {
318
        /* this will prevent post processing from considering this SFB for
319
         * merging */
320
0
        hrrErr[sfb + sfboffs] = FL2FXCONST_DBL(1.0 / 8.0);
321
0
      }
322
0
    }
323
0
  }
324
325
0
  for (grpCounter = 0, sfboffs = 0; sfboffs < sfbCnt;
326
0
       sfboffs += sfbPerGroup, grpCounter++) {
327
0
    INT invOverallLoudnessSF;
328
0
    FIXP_DBL invOverallLoudness;
329
330
0
    if (overallLoudness[grpCounter] == FL2FXCONST_DBL(0.0)) {
331
0
      invOverallLoudness = FL2FXCONST_DBL(0.0);
332
0
      invOverallLoudnessSF = 0;
333
0
    } else {
334
0
      invOverallLoudness =
335
0
          fDivNorm((FIXP_DBL)MAXVAL_DBL, overallLoudness[grpCounter],
336
0
                   &invOverallLoudnessSF);
337
0
      invOverallLoudnessSF =
338
0
          invOverallLoudnessSF - OVERALL_LOUDNESS_SF +
339
0
          1; /* +1: compensate fMultDiv2() in subsequent loop */
340
0
    }
341
0
    invOverallLoudnessSF = fixMin(
342
0
        fixMax(invOverallLoudnessSF, -(DFRACT_BITS - 1)), DFRACT_BITS - 1);
343
344
0
    for (sfb = 0; sfb < maxSfbPerGroup; sfb++) {
345
0
      FIXP_DBL tmp;
346
347
0
      tmp = fMultDiv2((normSfbLoudness[sfb + sfboffs] >> OVERALL_LOUDNESS_SF)
348
0
                          << OVERALL_LOUDNESS_SF,
349
0
                      invOverallLoudness);
350
351
0
      normSfbLoudness[sfb + sfboffs] = scaleValue(tmp, invOverallLoudnessSF);
352
353
0
      channelCorr[sfb + sfboffs] = FL2FXCONST_DBL(0.0f);
354
355
      /* max width of scalefactorband is 96; width's are always even */
356
      /* inv_n is scaled with factor 2 to compensate fMultDiv2() in subsequent
357
       * loops */
358
0
      inv_n = GetInvInt(
359
0
          (sfbOffset[sfb + sfboffs + 1] - sfbOffset[sfb + sfboffs]) >> 1);
360
361
0
      if (inv_n > FL2FXCONST_DBL(0.0f)) {
362
0
        INT s, sL, sR;
363
364
        /* correlation := Pearson's product-moment coefficient */
365
        /* compute correlation between channels and check if it is over
366
         * threshold */
367
0
        ml = FL2FXCONST_DBL(0.0f);
368
0
        mr = FL2FXCONST_DBL(0.0f);
369
0
        prod_lr = FL2FXCONST_DBL(0.0f);
370
0
        square_l = FL2FXCONST_DBL(0.0f);
371
0
        square_r = FL2FXCONST_DBL(0.0f);
372
373
0
        sL = calcSfbMaxScale(mdctSpectrumLeft, sfbOffset[sfb + sfboffs],
374
0
                             sfbOffset[sfb + sfboffs + 1]);
375
0
        sR = calcSfbMaxScale(mdctSpectrumRight, sfbOffset[sfb + sfboffs],
376
0
                             sfbOffset[sfb + sfboffs + 1]);
377
0
        s = fixMin(sL, sR);
378
379
0
        for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1];
380
0
             j++) {
381
0
          ml += fMultDiv2((mdctSpectrumLeft[j] << s),
382
0
                          inv_n);  // scaled with mdctScale - s + inv_n
383
0
          mr += fMultDiv2((mdctSpectrumRight[j] << s),
384
0
                          inv_n);  // scaled with mdctScale - s + inv_n
385
0
        }
386
0
        ml = fMultDiv2(ml, inv_n);  // scaled with mdctScale - s + inv_n
387
0
        mr = fMultDiv2(mr, inv_n);  // scaled with mdctScale - s + inv_n
388
389
0
        for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1];
390
0
             j++) {
391
0
          tmp_l = fMultDiv2((mdctSpectrumLeft[j] << s), inv_n) -
392
0
                  ml;  // scaled with mdctScale - s + inv_n
393
0
          tmp_r = fMultDiv2((mdctSpectrumRight[j] << s), inv_n) -
394
0
                  mr;  // scaled with mdctScale - s + inv_n
395
396
0
          prod_lr += fMultDiv2(
397
0
              tmp_l, tmp_r);  // scaled with 2*(mdctScale - s + inv_n) + 1
398
0
          square_l +=
399
0
              fPow2Div2(tmp_l);  // scaled with 2*(mdctScale - s + inv_n) + 1
400
0
          square_r +=
401
0
              fPow2Div2(tmp_r);  // scaled with 2*(mdctScale - s + inv_n) + 1
402
0
        }
403
0
        prod_lr = prod_lr << 1;    // scaled with 2*(mdctScale - s + inv_n)
404
0
        square_l = square_l << 1;  // scaled with 2*(mdctScale - s + inv_n)
405
0
        square_r = square_r << 1;  // scaled with 2*(mdctScale - s + inv_n)
406
407
0
        if (square_l > FL2FXCONST_DBL(0.0f) &&
408
0
            square_r > FL2FXCONST_DBL(0.0f)) {
409
0
          INT channelCorrSF = 0;
410
411
          /* local scaling of square_l and square_r is compensated after sqrt
412
           * calculation */
413
0
          sL = fixMax(0, (CntLeadingZeros(square_l) - 1));
414
0
          sR = fixMax(0, (CntLeadingZeros(square_r) - 1));
415
0
          s = ((sL + sR) >> 1) << 1;
416
0
          sL = fixMin(sL, s);
417
0
          sR = s - sL;
418
0
          tmp = fMult(square_l << sL, square_r << sR);
419
0
          tmp = sqrtFixp(tmp);
420
421
0
          FDK_ASSERT(tmp > FL2FXCONST_DBL(0.0f));
422
423
          /* numerator and denominator have the same scaling */
424
0
          if (prod_lr < FL2FXCONST_DBL(0.0f)) {
425
0
            channelCorr[sfb + sfboffs] =
426
0
                -(fDivNorm(-prod_lr, tmp, &channelCorrSF));
427
428
0
          } else {
429
0
            channelCorr[sfb + sfboffs] =
430
0
                (fDivNorm(prod_lr, tmp, &channelCorrSF));
431
0
          }
432
0
          channelCorrSF = fixMin(
433
0
              fixMax((channelCorrSF + ((sL + sR) >> 1)), -(DFRACT_BITS - 1)),
434
0
              DFRACT_BITS - 1);
435
436
0
          if (channelCorrSF < 0) {
437
0
            channelCorr[sfb + sfboffs] =
438
0
                channelCorr[sfb + sfboffs] >> (-channelCorrSF);
439
0
          } else {
440
            /* avoid overflows due to limited computational accuracy */
441
0
            if (fAbs(channelCorr[sfb + sfboffs]) >
442
0
                (((FIXP_DBL)MAXVAL_DBL) >> channelCorrSF)) {
443
0
              if (channelCorr[sfb + sfboffs] < FL2FXCONST_DBL(0.0f))
444
0
                channelCorr[sfb + sfboffs] = -(FIXP_DBL)MAXVAL_DBL;
445
0
              else
446
0
                channelCorr[sfb + sfboffs] = (FIXP_DBL)MAXVAL_DBL;
447
0
            } else {
448
0
              channelCorr[sfb + sfboffs] = channelCorr[sfb + sfboffs]
449
0
                                           << channelCorrSF;
450
0
            }
451
0
          }
452
0
        }
453
0
      }
454
455
      /* for post processing: hrrErr is the error in terms of (too little)
456
       * correlation weighted with the loudness of the SFB; SFBs with small
457
       * hrrErr can be merged */
458
0
      if (hrrErr[sfb + sfboffs] == FL2FXCONST_DBL(1.0 / 8.0)) {
459
0
        continue;
460
0
      }
461
462
0
      hrrErr[sfb + sfboffs] =
463
0
          fMultDiv2((FL2FXCONST_DBL(0.25f) - (channelCorr[sfb + sfboffs] >> 2)),
464
0
                    normSfbLoudness[sfb + sfboffs]);
465
466
      /* set IS mask/vector to 1, if correlation is high enough */
467
0
      if (fAbs(channelCorr[sfb + sfboffs]) >= isParams->corr_thresh) {
468
0
        isMask[sfb + sfboffs] = 1;
469
0
      }
470
0
    }
471
0
  }
472
0
}
473
474
/*****************************************************************************
475
476
    functionname: FDKaacEnc_finalizeIntensityDecision
477
478
    description:  Finalizes intensity decision
479
480
    input:        isParams          scale: none
481
                  hrrErr            scale: none
482
                  realIsScale       scale: LD_DATA_SHIFT + REAL_SCALE_SF
483
                  normSfbLoudness   scale: none
484
485
    output:       isMask            scale: none
486
487
    returns:      none
488
489
*****************************************************************************/
490
static void FDKaacEnc_finalizeIntensityDecision(
491
    const FIXP_DBL *hrrErr, INT *isMask, const FIXP_DBL *realIsScale,
492
    const FIXP_DBL *normSfbLoudness, const INTENSITY_PARAMETERS *isParams,
493
0
    const INT sfbCnt, const INT sfbPerGroup, const INT maxSfbPerGroup) {
494
0
  INT sfb, sfboffs, j;
495
0
  FIXP_DBL isScaleLast = FL2FXCONST_DBL(0.0f);
496
0
  INT isStartValueFound = 0;
497
498
0
  for (sfboffs = 0; sfboffs < sfbCnt; sfboffs += sfbPerGroup) {
499
0
    INT startIsSfb = 0;
500
0
    INT inIsBlock = 0;
501
0
    INT currentIsSfbCount = 0;
502
0
    FIXP_DBL overallHrrError = FL2FXCONST_DBL(0.0f);
503
0
    FIXP_DBL isRegionLoudness = FL2FXCONST_DBL(0.0f);
504
505
0
    for (sfb = 0; sfb < maxSfbPerGroup; sfb++) {
506
0
      if (isMask[sfboffs + sfb] == 1) {
507
0
        if (currentIsSfbCount == 0) {
508
0
          startIsSfb = sfboffs + sfb;
509
0
        }
510
0
        if (isStartValueFound == 0) {
511
0
          isScaleLast = realIsScale[sfboffs + sfb];
512
0
          isStartValueFound = 1;
513
0
        }
514
0
        inIsBlock = 1;
515
0
        currentIsSfbCount++;
516
0
        overallHrrError += hrrErr[sfboffs + sfb] >> (MAX_SFB_PER_GROUP_SF - 3);
517
0
        isRegionLoudness +=
518
0
            normSfbLoudness[sfboffs + sfb] >> MAX_SFB_PER_GROUP_SF;
519
0
      } else {
520
        /* based on correlation, IS should not be used
521
         * -> use it anyway, if overall error is below threshold
522
         *    and if local error does not exceed threshold
523
         * otherwise: check if there are enough IS SFBs
524
         */
525
0
        if (inIsBlock) {
526
0
          overallHrrError +=
527
0
              hrrErr[sfboffs + sfb] >> (MAX_SFB_PER_GROUP_SF - 3);
528
0
          isRegionLoudness +=
529
0
              normSfbLoudness[sfboffs + sfb] >> MAX_SFB_PER_GROUP_SF;
530
531
0
          if ((hrrErr[sfboffs + sfb] < (isParams->local_error_thresh >> 3)) &&
532
0
              (overallHrrError <
533
0
               (isParams->total_error_thresh >> MAX_SFB_PER_GROUP_SF))) {
534
0
            currentIsSfbCount++;
535
            /* overwrite correlation based decision */
536
0
            isMask[sfboffs + sfb] = 1;
537
0
          } else {
538
0
            inIsBlock = 0;
539
0
          }
540
0
        }
541
0
      }
542
      /* check for large direction deviation */
543
0
      if (inIsBlock) {
544
0
        if (fAbs(isScaleLast - realIsScale[sfboffs + sfb]) <
545
0
            (isParams->direction_deviation_thresh >>
546
0
             (REAL_SCALE_SF + LD_DATA_SHIFT -
547
0
              IS_DIRECTION_DEVIATION_THRESH_SF))) {
548
0
          isScaleLast = realIsScale[sfboffs + sfb];
549
0
        } else {
550
0
          isMask[sfboffs + sfb] = 0;
551
0
          inIsBlock = 0;
552
0
          currentIsSfbCount--;
553
0
        }
554
0
      }
555
556
0
      if (currentIsSfbCount > 0 && (!inIsBlock || sfb == maxSfbPerGroup - 1)) {
557
        /* not enough SFBs -> do not use IS */
558
0
        if (currentIsSfbCount < isParams->min_is_sfbs ||
559
0
            (isRegionLoudness<isParams->is_region_min_loudness>>
560
0
             MAX_SFB_PER_GROUP_SF)) {
561
0
          for (j = startIsSfb; j <= sfboffs + sfb; j++) {
562
0
            isMask[j] = 0;
563
0
          }
564
0
          isScaleLast = FL2FXCONST_DBL(0.0f);
565
0
          isStartValueFound = 0;
566
0
          for (j = 0; j < startIsSfb; j++) {
567
0
            if (isMask[j] != 0) {
568
0
              isScaleLast = realIsScale[j];
569
0
              isStartValueFound = 1;
570
0
            }
571
0
          }
572
0
        }
573
0
        currentIsSfbCount = 0;
574
0
        overallHrrError = FL2FXCONST_DBL(0.0f);
575
0
        isRegionLoudness = FL2FXCONST_DBL(0.0f);
576
0
      }
577
0
    }
578
0
  }
579
0
}
580
581
/*****************************************************************************
582
583
    functionname: FDKaacEnc_IntensityStereoProcessing
584
585
    description:  Intensity stereo processing tool
586
587
    input:        sfbEnergyLeft
588
                  sfbEnergyRight
589
                  mdctSpectrumLeft
590
                  mdctSpectrumRight
591
                  sfbThresholdLeft
592
                  sfbThresholdRight
593
                  sfbSpreadEnLeft
594
                  sfbSpreadEnRight
595
                  sfbEnergyLdDataLeft
596
                  sfbEnergyLdDataRight
597
598
    output:       isBook
599
                  isScale
600
                  pnsData->pnsFlag
601
                  msDigest                 zeroed from start to sfbCnt
602
                  msMask                   zeroed from start to sfbCnt
603
                  mdctSpectrumRight        zeroed where isBook!=0
604
                  sfbEnergyRight           zeroed where isBook!=0
605
                  sfbSpreadEnRight       zeroed where isBook!=0
606
                  sfbThresholdRight        zeroed where isBook!=0
607
                  sfbEnergyLdDataRight     FL2FXCONST_DBL(-1.0) where isBook!=0
608
                  sfbThresholdLdDataRight  FL2FXCONST_DBL(-0.515625f) where
609
isBook!=0
610
611
    returns:      none
612
613
*****************************************************************************/
614
void FDKaacEnc_IntensityStereoProcessing(
615
    FIXP_DBL *sfbEnergyLeft, FIXP_DBL *sfbEnergyRight,
616
    FIXP_DBL *mdctSpectrumLeft, FIXP_DBL *mdctSpectrumRight,
617
    FIXP_DBL *sfbThresholdLeft, FIXP_DBL *sfbThresholdRight,
618
    FIXP_DBL *sfbThresholdLdDataRight, FIXP_DBL *sfbSpreadEnLeft,
619
    FIXP_DBL *sfbSpreadEnRight, FIXP_DBL *sfbEnergyLdDataLeft,
620
    FIXP_DBL *sfbEnergyLdDataRight, INT *msDigest, INT *msMask,
621
    const INT sfbCnt, const INT sfbPerGroup, const INT maxSfbPerGroup,
622
    const INT *sfbOffset, const INT allowIS, INT *isBook, INT *isScale,
623
0
    PNS_DATA *RESTRICT pnsData[2]) {
624
0
  INT sfb, sfboffs, j;
625
0
  FIXP_DBL scale;
626
0
  FIXP_DBL lr;
627
0
  FIXP_DBL hrrErr[MAX_GROUPED_SFB];
628
0
  FIXP_DBL normSfbLoudness[MAX_GROUPED_SFB];
629
0
  FIXP_DBL realIsScale[MAX_GROUPED_SFB];
630
0
  INTENSITY_PARAMETERS isParams;
631
0
  INT isMask[MAX_GROUPED_SFB];
632
633
0
  FDKmemclear((void *)isBook, sfbCnt * sizeof(INT));
634
0
  FDKmemclear((void *)isMask, sfbCnt * sizeof(INT));
635
0
  FDKmemclear((void *)realIsScale, sfbCnt * sizeof(FIXP_DBL));
636
0
  FDKmemclear((void *)isScale, sfbCnt * sizeof(INT));
637
0
  FDKmemclear((void *)hrrErr, sfbCnt * sizeof(FIXP_DBL));
638
639
0
  if (!allowIS) return;
640
641
0
  FDKaacEnc_initIsParams(&isParams);
642
643
  /* compute / set the following values per SFB:
644
   * - left/right ratio between channels
645
   * - normalized loudness
646
   *   + loudness == average of energy in channels to 0.25
647
   *   + normalization: division by sum of all SFB loudnesses
648
   * - isMask (is set to 0 if channels are the same or one is 0)
649
   */
650
0
  FDKaacEnc_prepareIntensityDecision(
651
0
      sfbEnergyLeft, sfbEnergyRight, sfbEnergyLdDataLeft, sfbEnergyLdDataRight,
652
0
      mdctSpectrumLeft, mdctSpectrumRight, &isParams, hrrErr, isMask,
653
0
      realIsScale, normSfbLoudness, sfbCnt, sfbPerGroup, maxSfbPerGroup,
654
0
      sfbOffset);
655
656
0
  FDKaacEnc_finalizeIntensityDecision(hrrErr, isMask, realIsScale,
657
0
                                      normSfbLoudness, &isParams, sfbCnt,
658
0
                                      sfbPerGroup, maxSfbPerGroup);
659
660
0
  for (sfb = 0; sfb < sfbCnt; sfb += sfbPerGroup) {
661
0
    for (sfboffs = 0; sfboffs < maxSfbPerGroup; sfboffs++) {
662
0
      INT sL, sR;
663
0
      FIXP_DBL inv_n;
664
0
      INT mdct_spec_sf = MDCT_SPEC_SF;
665
666
0
      msMask[sfb + sfboffs] = 0;
667
0
      if (isMask[sfb + sfboffs] == 0) {
668
0
        continue;
669
0
      }
670
671
0
      if ((sfbEnergyLeft[sfb + sfboffs] < sfbThresholdLeft[sfb + sfboffs]) &&
672
0
          (fMult(FL2FXCONST_DBL(1.0f / 1.5f), sfbEnergyRight[sfb + sfboffs]) >
673
0
           sfbThresholdRight[sfb + sfboffs])) {
674
0
        continue;
675
0
      }
676
      /* NEW: if there is a big-enough IS region, switch off PNS */
677
0
      if (pnsData[0]) {
678
0
        if (pnsData[0]->pnsFlag[sfb + sfboffs]) {
679
0
          pnsData[0]->pnsFlag[sfb + sfboffs] = 0;
680
0
        }
681
0
        if (pnsData[1]->pnsFlag[sfb + sfboffs]) {
682
0
          pnsData[1]->pnsFlag[sfb + sfboffs] = 0;
683
0
        }
684
0
      }
685
686
0
      if (sfbOffset[sfb + sfboffs + 1] - sfbOffset[sfb + sfboffs] >
687
0
          1 << mdct_spec_sf) {
688
0
        mdct_spec_sf++; /* This is for rare cases where the number of bins in a
689
                           scale factor band is > 64 */
690
0
      }
691
692
0
      inv_n = GetInvInt(
693
0
          (sfbOffset[sfb + sfboffs + 1] - sfbOffset[sfb + sfboffs]) >>
694
0
          1);  // scaled with 2 to compensate fMultDiv2() in subsequent loop
695
0
      sL = calcSfbMaxScale(mdctSpectrumLeft, sfbOffset[sfb + sfboffs],
696
0
                           sfbOffset[sfb + sfboffs + 1]);
697
0
      sR = calcSfbMaxScale(mdctSpectrumRight, sfbOffset[sfb + sfboffs],
698
0
                           sfbOffset[sfb + sfboffs + 1]);
699
700
0
      lr = FL2FXCONST_DBL(0.0f);
701
0
      for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1]; j++)
702
0
        lr += fMultDiv2(
703
0
            fMultDiv2(mdctSpectrumLeft[j] << sL, mdctSpectrumRight[j] << sR),
704
0
            inv_n);
705
0
      lr = lr << 1;
706
707
0
      if (lr < FL2FXCONST_DBL(0.0f)) {
708
        /* This means OUT OF phase intensity stereo, cf. standard */
709
0
        INT s0, s1, s2;
710
0
        FIXP_DBL tmp, d, ed = FL2FXCONST_DBL(0.0f);
711
712
0
        s0 = fixMin(sL, sR);
713
0
        for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1];
714
0
             j++) {
715
0
          d = ((mdctSpectrumLeft[j] << s0) >> 1) -
716
0
              ((mdctSpectrumRight[j] << s0) >> 1);
717
0
          ed += fMultDiv2(d, d) >> (mdct_spec_sf - 1);
718
0
        }
719
0
        msMask[sfb + sfboffs] = 1;
720
0
        tmp = fDivNorm(sfbEnergyLeft[sfb + sfboffs], ed, &s1);
721
0
        s2 = (s1) + (2 * s0) - 2 - mdct_spec_sf;
722
0
        if (s2 & 1) {
723
0
          tmp = tmp >> 1;
724
0
          s2 = s2 + 1;
725
0
        }
726
0
        s2 = (s2 >> 1) + 1;  // +1 compensate fMultDiv2() in subsequent loop
727
0
        s2 = fixMin(fixMax(s2, -(DFRACT_BITS - 1)), (DFRACT_BITS - 1));
728
0
        scale = sqrtFixp(tmp);
729
0
        if (s2 < 0) {
730
0
          s2 = -s2;
731
0
          for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1];
732
0
               j++) {
733
0
            mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j], scale) -
734
0
                                   fMultDiv2(mdctSpectrumRight[j], scale)) >>
735
0
                                  s2;
736
0
            mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f);
737
0
          }
738
0
        } else {
739
0
          for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1];
740
0
               j++) {
741
0
            mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j], scale) -
742
0
                                   fMultDiv2(mdctSpectrumRight[j], scale))
743
0
                                  << s2;
744
0
            mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f);
745
0
          }
746
0
        }
747
0
      } else {
748
        /* This means IN phase intensity stereo, cf. standard */
749
0
        INT s0, s1, s2;
750
0
        FIXP_DBL tmp, s, es = FL2FXCONST_DBL(0.0f);
751
752
0
        s0 = fixMin(sL, sR);
753
0
        for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1];
754
0
             j++) {
755
0
          s = ((mdctSpectrumLeft[j] << s0) >> 1) +
756
0
              ((mdctSpectrumRight[j] << s0) >> 1);
757
0
          es += fMultDiv2(s, s) >>
758
0
                (mdct_spec_sf -
759
0
                 1);  // scaled 2*(mdctScale - s0 + 1) + mdct_spec_sf
760
0
        }
761
0
        msMask[sfb + sfboffs] = 0;
762
0
        tmp = fDivNorm(sfbEnergyLeft[sfb + sfboffs], es, &s1);
763
0
        s2 = (s1) + (2 * s0) - 2 - mdct_spec_sf;
764
0
        if (s2 & 1) {
765
0
          tmp = tmp >> 1;
766
0
          s2 = s2 + 1;
767
0
        }
768
0
        s2 = (s2 >> 1) + 1;  // +1 compensate fMultDiv2() in subsequent loop
769
0
        s2 = fixMin(fixMax(s2, -(DFRACT_BITS - 1)), (DFRACT_BITS - 1));
770
0
        scale = sqrtFixp(tmp);
771
0
        if (s2 < 0) {
772
0
          s2 = -s2;
773
0
          for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1];
774
0
               j++) {
775
0
            mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j], scale) +
776
0
                                   fMultDiv2(mdctSpectrumRight[j], scale)) >>
777
0
                                  s2;
778
0
            mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f);
779
0
          }
780
0
        } else {
781
0
          for (j = sfbOffset[sfb + sfboffs]; j < sfbOffset[sfb + sfboffs + 1];
782
0
               j++) {
783
0
            mdctSpectrumLeft[j] = (fMultDiv2(mdctSpectrumLeft[j], scale) +
784
0
                                   fMultDiv2(mdctSpectrumRight[j], scale))
785
0
                                  << s2;
786
0
            mdctSpectrumRight[j] = FL2FXCONST_DBL(0.0f);
787
0
          }
788
0
        }
789
0
      }
790
791
0
      isBook[sfb + sfboffs] = CODE_BOOK_IS_IN_PHASE_NO;
792
793
0
      if (realIsScale[sfb + sfboffs] < FL2FXCONST_DBL(0.0f)) {
794
0
        isScale[sfb + sfboffs] =
795
0
            (INT)(((realIsScale[sfb + sfboffs] >> 1) -
796
0
                   FL2FXCONST_DBL(
797
0
                       0.5f / (1 << (REAL_SCALE_SF + LD_DATA_SHIFT + 1)))) >>
798
0
                  (DFRACT_BITS - 1 - REAL_SCALE_SF - LD_DATA_SHIFT - 1)) +
799
0
            1;
800
0
      } else {
801
0
        isScale[sfb + sfboffs] =
802
0
            (INT)(((realIsScale[sfb + sfboffs] >> 1) +
803
0
                   FL2FXCONST_DBL(
804
0
                       0.5f / (1 << (REAL_SCALE_SF + LD_DATA_SHIFT + 1)))) >>
805
0
                  (DFRACT_BITS - 1 - REAL_SCALE_SF - LD_DATA_SHIFT - 1));
806
0
      }
807
808
0
      sfbEnergyRight[sfb + sfboffs] = FL2FXCONST_DBL(0.0f);
809
0
      sfbEnergyLdDataRight[sfb + sfboffs] = FL2FXCONST_DBL(-1.0f);
810
0
      sfbThresholdRight[sfb + sfboffs] = FL2FXCONST_DBL(0.0f);
811
0
      sfbThresholdLdDataRight[sfb + sfboffs] = FL2FXCONST_DBL(-0.515625f);
812
0
      sfbSpreadEnRight[sfb + sfboffs] = FL2FXCONST_DBL(0.0f);
813
814
0
      *msDigest = MS_SOME;
815
0
    }
816
0
  }
817
0
}