Coverage Report

Created: 2025-09-05 06:51

/src/aac/libDRCdec/src/drcDec_selectionProcess.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
/************************* MPEG-D DRC decoder library **************************
96
97
   Author(s):   Andreas Hoelzer
98
99
   Description: DRC Set Selection
100
101
*******************************************************************************/
102
103
#include "drcDec_selectionProcess.h"
104
#include "drcDec_tools.h"
105
106
typedef enum {
107
  DETR_NONE = 0,
108
  DETR_NIGHT = 1,
109
  DETR_NOISY = 2,
110
  DETR_LIMITED = 3,
111
  DETR_LOWLEVEL = 4,
112
  DETR_DIALOG = 5,
113
  DETR_GENERAL_COMPR = 6,
114
  DETR_EXPAND = 7,
115
  DETR_ARTISTIC = 8,
116
  DETR_COUNT
117
} DRC_EFFECT_TYPE_REQUEST;
118
119
typedef enum {
120
  DFRT_EFFECT_TYPE,
121
  DFRT_DYNAMIC_RANGE,
122
  DFRT_DRC_CHARACTERISTIC
123
} DRC_FEATURE_REQUEST_TYPE;
124
125
typedef enum {
126
  MDR_DEFAULT = 0,
127
  MDR_PROGRAM_LOUDNESS = 1,
128
  MDR_ANCHOR_LOUDNESS = 2
129
} METHOD_DEFINITION_REQUEST;
130
131
typedef enum {
132
  MSR_DEFAULT = 0,
133
  MSR_BS_1770_4 = 1,
134
  MSR_USER = 2,
135
  MSR_EXPERT_PANEL = 3,
136
  MSR_RESERVED_A = 4,
137
  MSR_RESERVED_B = 5,
138
  MSR_RESERVED_C = 6,
139
  MSR_RESERVED_D = 7,
140
  MSR_RESERVED_E = 8
141
} MEASUREMENT_SYSTEM_REQUEST;
142
143
typedef enum {
144
  LPR_DEFAULT = 0,
145
  LPR_OFF = 1,
146
  LPR_HIGHPASS = 2
147
} LOUDNESS_PREPROCESSING_REQUEST;
148
149
typedef enum {
150
  DRMRT_SHORT_TERM_LOUDNESS_TO_AVG = 0,
151
  DRMRT_MOMENTARY_LOUDNESS_TO_AVG = 1,
152
  DRMRT_TOP_OF_LOUDNESS_RANGE_TO_AVG = 2
153
} DYN_RANGE_MEASUREMENT_REQUEST_TYPE;
154
155
typedef enum {
156
  TCRT_DOWNMIX_ID = 0,
157
  TCRT_TARGET_LAYOUT = 1,
158
  TCRT_TARGET_CHANNEL_COUNT = 2
159
} TARGET_CONFIG_REQUEST_TYPE;
160
161
typedef shouldBeUnion {
162
  struct {
163
    UCHAR numRequests;
164
    UCHAR numRequestsDesired;
165
    DRC_EFFECT_TYPE_REQUEST request[MAX_REQUESTS_DRC_EFFECT_TYPE];
166
  } drcEffectType;
167
  struct {
168
    DYN_RANGE_MEASUREMENT_REQUEST_TYPE measurementRequestType;
169
    UCHAR requestedIsRange;
170
    FIXP_DBL requestValue;    /* e = 7 */
171
    FIXP_DBL requestValueMin; /* e = 7 */
172
    FIXP_DBL requestValueMax; /* e = 7 */
173
  } dynamicRange;
174
  UCHAR drcCharacteristic;
175
}
176
DRC_FEATURE_REQUEST;
177
178
typedef struct {
179
  /* system parameters */
180
  SCHAR baseChannelCount;
181
  SCHAR baseLayout; /* not supported */
182
  TARGET_CONFIG_REQUEST_TYPE targetConfigRequestType;
183
  UCHAR numDownmixIdRequests;
184
  UCHAR downmixIdRequested[MAX_REQUESTS_DOWNMIX_ID];
185
  UCHAR targetLayoutRequested;
186
  UCHAR targetChannelCountRequested;
187
  LONG audioSampleRate; /* needed for complexity estimation, currently not
188
                           supported */
189
190
  /* loudness normalization parameters */
191
  UCHAR loudnessNormalizationOn;
192
  FIXP_DBL targetLoudness; /* e = 7 */
193
  UCHAR albumMode;
194
  UCHAR peakLimiterPresent;
195
  UCHAR loudnessDeviationMax; /* resolution: 1 dB */
196
  METHOD_DEFINITION_REQUEST loudnessMeasurementMethod;
197
  MEASUREMENT_SYSTEM_REQUEST loudnessMeasurementSystem;
198
  LOUDNESS_PREPROCESSING_REQUEST loudnessMeasurementPreProc; /* not supported */
199
  LONG deviceCutOffFrequency;                                /* not supported */
200
  FIXP_DBL loudnessNormalizationGainDbMax;                   /* e = 7 */
201
  FIXP_DBL loudnessNormalizationGainModificationDb;          /* e = 7 */
202
  FIXP_DBL outputPeakLevelMax;                               /* e = 7 */
203
204
  /* dynamic range control parameters */
205
  UCHAR dynamicRangeControlOn;
206
  UCHAR numDrcFeatureRequests;
207
  DRC_FEATURE_REQUEST_TYPE drcFeatureRequestType[MAX_REQUESTS_DRC_FEATURE];
208
  DRC_FEATURE_REQUEST drcFeatureRequest[MAX_REQUESTS_DRC_FEATURE];
209
210
  /* other */
211
  FIXP_SGL boost;                /* e = 1 */
212
  FIXP_SGL compress;             /* e = 1 */
213
  UCHAR drcCharacteristicTarget; /* not supported */
214
} SEL_PROC_INPUT, *HANDLE_SEL_PROC_INPUT;
215
216
/* Table E.1 of ISO/IEC DIS 23003-4: Recommended order of fallback effect type
217
 * requests */
218
static DRC_EFFECT_TYPE_REQUEST fallbackEffectTypeRequests[6][5] = {
219
    /* Night */ {DETR_GENERAL_COMPR, DETR_NOISY, DETR_LIMITED, DETR_LOWLEVEL,
220
                 DETR_DIALOG},
221
    /* Noisy */
222
    {DETR_GENERAL_COMPR, DETR_NIGHT, DETR_LIMITED, DETR_LOWLEVEL, DETR_DIALOG},
223
    /* Limited */
224
    {DETR_GENERAL_COMPR, DETR_NIGHT, DETR_NOISY, DETR_LOWLEVEL, DETR_DIALOG},
225
    /* LowLevel */
226
    {DETR_GENERAL_COMPR, DETR_NOISY, DETR_NIGHT, DETR_LIMITED, DETR_DIALOG},
227
    /* Dialog */
228
    {DETR_GENERAL_COMPR, DETR_NIGHT, DETR_NOISY, DETR_LIMITED, DETR_LOWLEVEL},
229
    /* General */
230
    {DETR_NIGHT, DETR_NOISY, DETR_LIMITED, DETR_LOWLEVEL, DETR_DIALOG}};
231
232
/*******************************************/
233
typedef struct {
234
  UCHAR selectionFlag;
235
  UCHAR downmixIdRequestIndex;
236
  FIXP_DBL outputPeakLevel;                     /* e = 7 */
237
  FIXP_DBL loudnessNormalizationGainDbAdjusted; /* e = 7 */
238
  FIXP_DBL outputLoudness;                      /* e = 7 */
239
  DRC_INSTRUCTIONS_UNI_DRC* pInst;
240
241
} DRCDEC_SELECTION_DATA;
242
243
typedef struct {
244
  UCHAR numData;
245
  DRCDEC_SELECTION_DATA data[(12 + 1 + 6)];
246
247
} DRCDEC_SELECTION;
248
249
/*******************************************/
250
/* helper functions                        */
251
/*******************************************/
252
253
5.25k
static int _isError(int x) {
254
5.25k
  if (x < DRCDEC_SELECTION_PROCESS_WARNING) {
255
166
    return 1;
256
166
  }
257
258
5.09k
  return 0;
259
5.25k
}
260
261
/* compare and assign */
262
0
static inline int _compAssign(UCHAR* dest, const UCHAR src) {
263
0
  int diff = 0;
264
0
  if (*dest != src) diff = 1;
265
0
  *dest = src;
266
0
  return diff;
267
0
}
268
269
2.68k
static inline int _compAssign(SCHAR* dest, const SCHAR src) {
270
2.68k
  int diff = 0;
271
2.68k
  if (*dest != src) diff = 1;
272
2.68k
  *dest = src;
273
2.68k
  return diff;
274
2.68k
}
275
276
2.68k
static inline int _compAssign(FIXP_DBL* dest, const FIXP_DBL src) {
277
2.68k
  int diff = 0;
278
2.68k
  if (*dest != src) diff = 1;
279
2.68k
  *dest = src;
280
2.68k
  return diff;
281
2.68k
}
282
283
0
static inline int _compAssign(FIXP_SGL* dest, const FIXP_SGL src) {
284
0
  int diff = 0;
285
0
  if (*dest != src) diff = 1;
286
0
  *dest = src;
287
0
  return diff;
288
0
}
289
290
0
static inline int _compAssign(TARGET_CONFIG_REQUEST_TYPE* dest, const int src) {
291
0
  int diff = 0;
292
0
  if (*dest != src) diff = 1;
293
0
  *dest = (TARGET_CONFIG_REQUEST_TYPE)src;
294
0
  return diff;
295
0
}
296
297
0
static inline int _compAssign(METHOD_DEFINITION_REQUEST* dest, const int src) {
298
0
  int diff = 0;
299
0
  if (*dest != src) diff = 1;
300
0
  *dest = (METHOD_DEFINITION_REQUEST)src;
301
0
  return diff;
302
0
}
303
304
0
static inline int _compAssign(DRC_FEATURE_REQUEST_TYPE* dest, const int src) {
305
0
  int diff = 0;
306
0
  if (*dest != src) diff = 1;
307
0
  *dest = (DRC_FEATURE_REQUEST_TYPE)src;
308
0
  return diff;
309
0
}
310
311
0
static inline int _compAssign(DRC_EFFECT_TYPE_REQUEST* dest, const int src) {
312
0
  int diff = 0;
313
0
  if (*dest != src) diff = 1;
314
0
  *dest = (DRC_EFFECT_TYPE_REQUEST)src;
315
0
  return diff;
316
0
}
317
318
static DRCDEC_SELECTION_DATA* _drcdec_selection_addNew(
319
    DRCDEC_SELECTION* pSelection);
320
321
static DRCDEC_SELECTION_DATA* _drcdec_selection_add(
322
    DRCDEC_SELECTION* pSelection, DRCDEC_SELECTION_DATA* pDataIn);
323
324
static int _drcdec_selection_clear(DRCDEC_SELECTION* pSelection);
325
326
static int _drcdec_selection_getNumber(DRCDEC_SELECTION* pSelection);
327
328
static int _drcdec_selection_setNumber(DRCDEC_SELECTION* pSelection, int num);
329
330
static DRCDEC_SELECTION_DATA* _drcdec_selection_getAt(
331
    DRCDEC_SELECTION* pSelection, int at);
332
333
static int _swapSelectionAndClear(DRCDEC_SELECTION** ppCandidatesPotential,
334
                                  DRCDEC_SELECTION** ppCandidatesSelected);
335
336
static int _swapSelection(DRCDEC_SELECTION** ppCandidatesPotential,
337
                          DRCDEC_SELECTION** ppCandidatesSelected);
338
339
/*******************************************/
340
/* declarations of static functions        */
341
/*******************************************/
342
343
static DRCDEC_SELECTION_PROCESS_RETURN _initDefaultParams(
344
    HANDLE_SEL_PROC_INPUT hSelProcInput);
345
346
static DRCDEC_SELECTION_PROCESS_RETURN _initCodecModeParams(
347
    HANDLE_SEL_PROC_INPUT hSelProcInput, const SEL_PROC_CODEC_MODE codecMode);
348
349
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetPreSelection(
350
    SEL_PROC_INPUT* hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
351
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
352
    DRCDEC_SELECTION** ppCandidatesPotential,
353
    DRCDEC_SELECTION** ppCandidatesSelected, SEL_PROC_CODEC_MODE codecMode);
354
355
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_peakValue0(
356
    DRCDEC_SELECTION* pCandidatesPotential,
357
    DRCDEC_SELECTION* pCandidatesSelected);
358
359
static DRCDEC_SELECTION_PROCESS_RETURN _dynamicRangeMeasurement(
360
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, DRC_INSTRUCTIONS_UNI_DRC* pInst,
361
    UCHAR downmixIdRequested,
362
    DYN_RANGE_MEASUREMENT_REQUEST_TYPE dynamicRangeMeasurementType,
363
    int albumMode, int* peakToAveragePresent, FIXP_DBL* peakToAverage);
364
365
static DRCDEC_SELECTION_PROCESS_RETURN _channelLayoutToDownmixIdMapping(
366
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig);
367
368
static DRCDEC_SELECTION_PROCESS_RETURN _generateVirtualDrcSets(
369
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
370
    SEL_PROC_CODEC_MODE codecMode);
371
372
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetRequestSelection(
373
    SEL_PROC_INPUT* hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
374
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
375
    DRCDEC_SELECTION** ppCandidatesPotential,
376
    DRCDEC_SELECTION** ppCandidatesSelected);
377
378
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection(
379
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
380
    DRCDEC_SELECTION** ppCandidatesPotential,
381
    DRCDEC_SELECTION** ppCandidatesSelected, SEL_PROC_CODEC_MODE codecMode);
382
383
static DRCDEC_SELECTION_PROCESS_RETURN _generateOutputInfo(
384
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_SEL_PROC_OUTPUT hSelProcOutput,
385
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
386
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
387
    DRCDEC_SELECTION_DATA* pSelectionData, SEL_PROC_CODEC_MODE codecMode);
388
389
static DRCDEC_SELECTION_PROCESS_RETURN _selectDownmixMatrix(
390
    HANDLE_SEL_PROC_OUTPUT hSelProcOutput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig);
391
392
static DRCDEC_SELECTION_PROCESS_RETURN _getLoudness(
393
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int albumMode,
394
    METHOD_DEFINITION_REQUEST measurementMethodRequested,
395
    MEASUREMENT_SYSTEM_REQUEST measurementSystemRequested,
396
    FIXP_DBL targetLoudness, int drcSetId, int downmixIdRequested,
397
    FIXP_DBL* pLoudnessNormalizationGain, FIXP_DBL* pLoudness);
398
399
static DRCDEC_SELECTION_PROCESS_RETURN _getMixingLevel(
400
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int downmixIdRequested,
401
    int drcSetIdRequested, int albumMode, FIXP_DBL* pMixingLevel);
402
403
static DRCDEC_SELECTION_PROCESS_RETURN _getSignalPeakLevel(
404
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
405
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, DRC_INSTRUCTIONS_UNI_DRC* pInst,
406
    int downmixIdRequested, int* explicitPeakInformationPresent,
407
    FIXP_DBL* signalPeakLevelOut, /* e = 7 */
408
    SEL_PROC_CODEC_MODE codecMode);
409
410
static DRCDEC_SELECTION_PROCESS_RETURN _extractLoudnessPeakToAverageValue(
411
    LOUDNESS_INFO* loudnessInfo,
412
    DYN_RANGE_MEASUREMENT_REQUEST_TYPE dynamicRangeMeasurementType,
413
    int* pLoudnessPeakToAverageValuePresent,
414
    FIXP_DBL* pLoudnessPeakToAverageValue);
415
416
static DRCDEC_SELECTION_PROCESS_RETURN _selectAlbumLoudness(
417
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
418
    DRCDEC_SELECTION* pCandidatesPotential,
419
    DRCDEC_SELECTION* pCandidatesSelected);
420
421
static int _findMethodDefinition(LOUDNESS_INFO* pLoudnessInfo,
422
                                 int methodDefinition, int startIndex);
423
424
/*******************************************/
425
/* public functions                        */
426
/*******************************************/
427
428
struct s_drcdec_selection_process {
429
  SEL_PROC_CODEC_MODE codecMode;
430
  SEL_PROC_INPUT selProcInput;
431
  DRCDEC_SELECTION
432
  selectionData[2]; /* 2 instances, one before and one after selection */
433
};
434
435
DRCDEC_SELECTION_PROCESS_RETURN
436
6.93k
drcDec_SelectionProcess_Create(HANDLE_DRC_SELECTION_PROCESS* phInstance) {
437
6.93k
  HANDLE_DRC_SELECTION_PROCESS hInstance;
438
6.93k
  hInstance = (HANDLE_DRC_SELECTION_PROCESS)FDKcalloc(
439
6.93k
      1, sizeof(struct s_drcdec_selection_process));
440
441
6.93k
  if (!hInstance) return DRCDEC_SELECTION_PROCESS_OUTOFMEMORY;
442
443
6.93k
  hInstance->codecMode = SEL_PROC_CODEC_MODE_UNDEFINED;
444
445
6.93k
  *phInstance = hInstance;
446
6.93k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
447
6.93k
}
448
449
DRCDEC_SELECTION_PROCESS_RETURN
450
6.93k
drcDec_SelectionProcess_Init(HANDLE_DRC_SELECTION_PROCESS hInstance) {
451
6.93k
  if (!hInstance) return DRCDEC_SELECTION_PROCESS_NOT_OK;
452
453
6.93k
  _initDefaultParams(&hInstance->selProcInput);
454
6.93k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
455
6.93k
}
456
457
DRCDEC_SELECTION_PROCESS_RETURN
458
drcDec_SelectionProcess_SetCodecMode(HANDLE_DRC_SELECTION_PROCESS hInstance,
459
4.77k
                                     const SEL_PROC_CODEC_MODE codecMode) {
460
4.77k
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
461
462
4.77k
  if (!hInstance) return DRCDEC_SELECTION_PROCESS_NOT_OK;
463
464
4.77k
  switch (codecMode) {
465
0
    case SEL_PROC_MPEG_4_AAC:
466
4.77k
    case SEL_PROC_MPEG_D_USAC:
467
4.77k
    case SEL_PROC_TEST_TIME_DOMAIN:
468
4.77k
    case SEL_PROC_TEST_QMF_DOMAIN:
469
4.77k
    case SEL_PROC_TEST_STFT_DOMAIN:
470
4.77k
      hInstance->codecMode = codecMode;
471
4.77k
      break;
472
473
0
    case SEL_PROC_CODEC_MODE_UNDEFINED:
474
0
    default:
475
0
      return DRCDEC_SELECTION_PROCESS_NOT_OK;
476
4.77k
  }
477
478
4.77k
  retVal = _initCodecModeParams(&(hInstance->selProcInput),
479
4.77k
                                hInstance->codecMode = codecMode);
480
481
4.77k
  return retVal;
482
4.77k
}
483
484
DRCDEC_SELECTION_PROCESS_RETURN
485
drcDec_SelectionProcess_SetParam(HANDLE_DRC_SELECTION_PROCESS hInstance,
486
                                 const SEL_PROC_USER_PARAM requestType,
487
5.37k
                                 FIXP_DBL requestValue, int* pDiff) {
488
5.37k
  INT requestValueInt = (INT)requestValue;
489
5.37k
  int i, diff = 0;
490
5.37k
  SEL_PROC_INPUT* pSelProcInput = &(hInstance->selProcInput);
491
492
5.37k
  switch (requestType) {
493
0
    case SEL_PROC_LOUDNESS_NORMALIZATION_ON:
494
0
      if ((requestValueInt != 0) && (requestValueInt != 1))
495
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
496
0
      diff |=
497
0
          _compAssign(&pSelProcInput->loudnessNormalizationOn, requestValueInt);
498
0
      break;
499
0
    case SEL_PROC_TARGET_LOUDNESS:
500
      /* Lower boundary: drcSetTargetLoudnessValueLower default value.
501
         Upper boundary: drcSetTargetLoudnessValueUpper default value */
502
0
      if ((requestValue < FL2FXCONST_DBL(-63.0f / (float)(1 << 7))) ||
503
0
          (requestValue > (FIXP_DBL)0))
504
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
505
0
      if (requestValue >
506
0
          FL2FXCONST_DBL(-10.0f /
507
0
                         (float)(1 << 7))) /* recommended maximum value */
508
0
        requestValue = FL2FXCONST_DBL(-10.0f / (float)(1 << 7));
509
0
      diff |= _compAssign(&pSelProcInput->targetLoudness, requestValue);
510
0
      break;
511
0
    case SEL_PROC_EFFECT_TYPE:
512
0
      if ((requestValueInt < -1) || (requestValueInt >= DETR_COUNT))
513
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
514
      /* Caution. This overrides all drcFeatureRequests requested so far! */
515
0
      if (requestValueInt == -1) {
516
0
        diff |= _compAssign(&pSelProcInput->dynamicRangeControlOn, 0);
517
0
      } else if (requestValueInt == DETR_NONE) {
518
0
        diff |= _compAssign(&pSelProcInput->dynamicRangeControlOn, 1);
519
0
        diff |= _compAssign(&pSelProcInput->numDrcFeatureRequests, 0);
520
0
      } else {
521
0
        diff |= _compAssign(&pSelProcInput->dynamicRangeControlOn, 1);
522
0
        diff |= _compAssign(&pSelProcInput->numDrcFeatureRequests, 1);
523
0
        diff |= _compAssign(&pSelProcInput->drcFeatureRequestType[0],
524
0
                            DFRT_EFFECT_TYPE);
525
0
        diff |= _compAssign(&pSelProcInput->drcFeatureRequest[0]
526
0
                                 .drcEffectType.numRequestsDesired,
527
0
                            1);
528
0
        diff |= _compAssign(
529
0
            &pSelProcInput->drcFeatureRequest[0].drcEffectType.request[0],
530
0
            requestValueInt);
531
0
        if ((requestValueInt > DETR_NONE) &&
532
0
            (requestValueInt <= DETR_GENERAL_COMPR)) {
533
          /* use fallback effect type requests */
534
0
          for (i = 0; i < 5; i++) {
535
0
            diff |=
536
0
                _compAssign(&pSelProcInput->drcFeatureRequest[0]
537
0
                                 .drcEffectType.request[i + 1],
538
0
                            fallbackEffectTypeRequests[requestValueInt - 1][i]);
539
0
          }
540
0
          diff |= _compAssign(
541
0
              &pSelProcInput->drcFeatureRequest[0].drcEffectType.numRequests,
542
0
              6);
543
0
        } else {
544
0
          diff |= _compAssign(
545
0
              &pSelProcInput->drcFeatureRequest[0].drcEffectType.numRequests,
546
0
              1);
547
0
        }
548
0
      }
549
0
      break;
550
0
    case SEL_PROC_LOUDNESS_MEASUREMENT_METHOD:
551
0
      if ((requestValueInt < 0) || (requestValueInt > 2))
552
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
553
0
      diff |= _compAssign(&pSelProcInput->loudnessMeasurementMethod,
554
0
                          requestValueInt);
555
0
      break;
556
0
    case SEL_PROC_ALBUM_MODE:
557
0
      if ((requestValueInt < 0) || (requestValueInt > 1))
558
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
559
0
      diff |= _compAssign(&pSelProcInput->albumMode, requestValueInt);
560
0
      break;
561
0
    case SEL_PROC_DOWNMIX_ID:
562
0
      diff |=
563
0
          _compAssign(&pSelProcInput->targetConfigRequestType, TCRT_DOWNMIX_ID);
564
0
      if (requestValueInt < 0) { /* negative requests signal no downmixId */
565
0
        diff |= _compAssign(&pSelProcInput->numDownmixIdRequests, 0);
566
0
      } else {
567
0
        diff |= _compAssign(&pSelProcInput->numDownmixIdRequests, 1);
568
0
        diff |=
569
0
            _compAssign(&pSelProcInput->downmixIdRequested[0], requestValueInt);
570
0
      }
571
0
      break;
572
0
    case SEL_PROC_TARGET_LAYOUT:
573
      /* Request target layout according to ChannelConfiguration in ISO/IEC
574
       * 23001-8 (CICP) */
575
0
      if ((requestValueInt < 1) || (requestValueInt > 63))
576
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
577
0
      diff |= _compAssign(&pSelProcInput->targetConfigRequestType,
578
0
                          TCRT_TARGET_LAYOUT);
579
0
      diff |=
580
0
          _compAssign(&pSelProcInput->targetLayoutRequested, requestValueInt);
581
0
      break;
582
0
    case SEL_PROC_TARGET_CHANNEL_COUNT:
583
0
      if ((requestValueInt < 1) || (requestValueInt > 8))
584
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
585
0
      diff |= _compAssign(&pSelProcInput->targetConfigRequestType,
586
0
                          TCRT_TARGET_CHANNEL_COUNT);
587
0
      diff |= _compAssign(&pSelProcInput->targetChannelCountRequested,
588
0
                          requestValueInt);
589
0
      break;
590
2.68k
    case SEL_PROC_BASE_CHANNEL_COUNT:
591
2.68k
      if (requestValueInt < 0)
592
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
593
2.68k
      diff |= _compAssign(&pSelProcInput->baseChannelCount, requestValueInt);
594
2.68k
      break;
595
2.68k
    case SEL_PROC_SAMPLE_RATE:
596
2.68k
      if (requestValueInt < 0)
597
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
598
2.68k
      diff |= _compAssign(&pSelProcInput->audioSampleRate, requestValueInt);
599
2.68k
      break;
600
0
    case SEL_PROC_BOOST:
601
0
      if ((requestValue < (FIXP_DBL)0) ||
602
0
          (requestValue > FL2FXCONST_DBL(1.0f / (float)(1 << 1))))
603
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
604
0
      diff |= _compAssign(
605
0
          &pSelProcInput->boost,
606
0
          FX_DBL2FX_SGL(
607
0
              requestValue +
608
0
              (FIXP_DBL)(1 << 15))); /* convert to FIXP_SGL with rounding */
609
0
      break;
610
0
    case SEL_PROC_COMPRESS:
611
0
      if ((requestValue < (FIXP_DBL)0) ||
612
0
          (requestValue > FL2FXCONST_DBL(1.0f / (float)(1 << 1))))
613
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
614
0
      diff |= _compAssign(
615
0
          &pSelProcInput->compress,
616
0
          FX_DBL2FX_SGL(
617
0
              requestValue +
618
0
              (FIXP_DBL)(1 << 15))); /* convert to FIXP_SGL with rounding */
619
0
      break;
620
0
    default:
621
0
      return DRCDEC_SELECTION_PROCESS_INVALID_PARAM;
622
5.37k
  }
623
624
5.37k
  if (pDiff != NULL) {
625
5.37k
    *pDiff |= diff;
626
5.37k
  }
627
628
5.37k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
629
5.37k
}
630
631
FIXP_DBL
632
drcDec_SelectionProcess_GetParam(HANDLE_DRC_SELECTION_PROCESS hInstance,
633
0
                                 const SEL_PROC_USER_PARAM requestType) {
634
0
  SEL_PROC_INPUT* pSelProcInput = &(hInstance->selProcInput);
635
636
0
  switch (requestType) {
637
0
    case SEL_PROC_LOUDNESS_NORMALIZATION_ON:
638
0
      return (FIXP_DBL)pSelProcInput->loudnessNormalizationOn;
639
0
    case SEL_PROC_DYNAMIC_RANGE_CONTROL_ON:
640
0
      return (FIXP_DBL)pSelProcInput->dynamicRangeControlOn;
641
0
    default:
642
0
      return (FIXP_DBL)0;
643
0
  }
644
0
}
645
646
DRCDEC_SELECTION_PROCESS_RETURN
647
6.93k
drcDec_SelectionProcess_Delete(HANDLE_DRC_SELECTION_PROCESS* phInstance) {
648
6.93k
  if (phInstance == NULL || *phInstance == NULL)
649
0
    return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE;
650
651
6.93k
  FDKfree(*phInstance);
652
6.93k
  *phInstance = NULL;
653
6.93k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
654
6.93k
}
655
656
DRCDEC_SELECTION_PROCESS_RETURN
657
drcDec_SelectionProcess_Process(HANDLE_DRC_SELECTION_PROCESS hInstance,
658
                                HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
659
                                HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
660
2.68k
                                HANDLE_SEL_PROC_OUTPUT hSelProcOutput) {
661
2.68k
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
662
2.68k
  DRCDEC_SELECTION* pCandidatesSelected;
663
2.68k
  DRCDEC_SELECTION* pCandidatesPotential;
664
665
2.68k
  if (hInstance == NULL) return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE;
666
667
2.68k
  pCandidatesSelected = &(hInstance->selectionData[0]);
668
2.68k
  pCandidatesPotential = &(hInstance->selectionData[1]);
669
2.68k
  _drcdec_selection_setNumber(pCandidatesSelected, 0);
670
2.68k
  _drcdec_selection_setNumber(pCandidatesPotential, 0);
671
672
2.68k
  retVal = _generateVirtualDrcSets(&(hInstance->selProcInput), hUniDrcConfig,
673
2.68k
                                   hInstance->codecMode);
674
2.68k
  if (retVal) return (retVal);
675
676
2.68k
  if (hInstance->selProcInput.baseChannelCount !=
677
2.68k
      hUniDrcConfig->channelLayout.baseChannelCount) {
678
2.60k
    hInstance->selProcInput.baseChannelCount =
679
2.60k
        hUniDrcConfig->channelLayout.baseChannelCount;
680
2.60k
  }
681
682
2.68k
  if ((hInstance->selProcInput.targetConfigRequestType != 0) ||
683
2.68k
      (hInstance->selProcInput.targetConfigRequestType == 0 &&
684
2.68k
       hInstance->selProcInput.numDownmixIdRequests == 0)) {
685
2.68k
    retVal = _channelLayoutToDownmixIdMapping(&(hInstance->selProcInput),
686
2.68k
                                              hUniDrcConfig);
687
688
2.68k
    if (_isError(retVal)) return (retVal);
689
2.68k
  }
690
691
2.68k
  retVal = _drcSetPreSelection(&(hInstance->selProcInput), hUniDrcConfig,
692
2.68k
                               hLoudnessInfoSet, &pCandidatesPotential,
693
2.68k
                               &pCandidatesSelected, hInstance->codecMode);
694
2.68k
  if (retVal) return (retVal);
695
696
2.67k
  if (hInstance->selProcInput.albumMode) {
697
0
    _swapSelectionAndClear(&pCandidatesPotential, &pCandidatesSelected);
698
699
0
    retVal = _selectAlbumLoudness(hLoudnessInfoSet, pCandidatesPotential,
700
0
                                  pCandidatesSelected);
701
0
    if (retVal) return (retVal);
702
703
0
    if (_drcdec_selection_getNumber(pCandidatesSelected) == 0) {
704
0
      _swapSelection(&pCandidatesPotential, &pCandidatesSelected);
705
0
    }
706
0
  }
707
708
2.67k
  _swapSelectionAndClear(&pCandidatesPotential, &pCandidatesSelected);
709
710
2.67k
  retVal = _drcSetRequestSelection(&(hInstance->selProcInput), hUniDrcConfig,
711
2.67k
                                   hLoudnessInfoSet, &pCandidatesPotential,
712
2.67k
                                   &pCandidatesSelected);
713
2.67k
  if (retVal) return (retVal);
714
715
2.65k
  retVal = _drcSetFinalSelection(&(hInstance->selProcInput), hUniDrcConfig,
716
2.65k
                                 &pCandidatesPotential, &pCandidatesSelected,
717
2.65k
                                 hInstance->codecMode);
718
2.65k
  if (retVal) return (retVal);
719
720
2.57k
  retVal = _generateOutputInfo(
721
2.57k
      &(hInstance->selProcInput), hSelProcOutput, hUniDrcConfig,
722
2.57k
      hLoudnessInfoSet, &(pCandidatesSelected->data[0]), hInstance->codecMode);
723
724
2.57k
  if (_isError(retVal)) return (retVal);
725
726
2.40k
  retVal = _selectDownmixMatrix(hSelProcOutput, hUniDrcConfig);
727
2.40k
  if (retVal) return (retVal);
728
729
2.40k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
730
2.40k
}
731
732
/*******************************************/
733
/* static functions                        */
734
/*******************************************/
735
736
static DRCDEC_SELECTION_PROCESS_RETURN _initDefaultParams(
737
6.93k
    HANDLE_SEL_PROC_INPUT hSelProcInput) {
738
6.93k
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
739
740
6.93k
  if (hSelProcInput == NULL) return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE;
741
742
  /* system parameters */
743
6.93k
  hSelProcInput->baseChannelCount = -1;
744
6.93k
  hSelProcInput->baseLayout = -1;
745
6.93k
  hSelProcInput->targetConfigRequestType = TCRT_DOWNMIX_ID;
746
6.93k
  hSelProcInput->numDownmixIdRequests = 0;
747
748
  /* loudness normalization parameters */
749
6.93k
  hSelProcInput->albumMode = 0;
750
6.93k
  hSelProcInput->peakLimiterPresent = 0;
751
6.93k
  hSelProcInput->loudnessNormalizationOn = 1;
752
6.93k
  hSelProcInput->targetLoudness = FL2FXCONST_DBL(-24.0f / (float)(1 << 7));
753
6.93k
  hSelProcInput->loudnessDeviationMax = DEFAULT_LOUDNESS_DEVIATION_MAX;
754
6.93k
  hSelProcInput->loudnessMeasurementMethod = MDR_ANCHOR_LOUDNESS;
755
6.93k
  hSelProcInput->loudnessMeasurementSystem = MSR_EXPERT_PANEL;
756
6.93k
  hSelProcInput->loudnessMeasurementPreProc = LPR_DEFAULT;
757
6.93k
  hSelProcInput->deviceCutOffFrequency = 500;
758
6.93k
  hSelProcInput->loudnessNormalizationGainDbMax =
759
6.93k
      (FIXP_DBL)MAXVAL_DBL; /* infinity as default */
760
6.93k
  hSelProcInput->loudnessNormalizationGainModificationDb = (FIXP_DBL)0;
761
6.93k
  hSelProcInput->outputPeakLevelMax = (FIXP_DBL)0;
762
6.93k
  if (hSelProcInput->peakLimiterPresent == 1) {
763
0
    hSelProcInput->outputPeakLevelMax = FL2FXCONST_DBL(6.0f / (float)(1 << 7));
764
0
  }
765
766
  /* dynamic range control parameters */
767
6.93k
  hSelProcInput->dynamicRangeControlOn = 1;
768
769
6.93k
  hSelProcInput->numDrcFeatureRequests = 0;
770
771
  /* other parameters */
772
6.93k
  hSelProcInput->boost = FL2FXCONST_SGL(1.f / (float)(1 << 1));
773
6.93k
  hSelProcInput->compress = FL2FXCONST_SGL(1.f / (float)(1 << 1));
774
6.93k
  hSelProcInput->drcCharacteristicTarget = 0;
775
776
6.93k
  return retVal;
777
6.93k
}
778
779
static DRCDEC_SELECTION_PROCESS_RETURN _initCodecModeParams(
780
4.77k
    HANDLE_SEL_PROC_INPUT hSelProcInput, const SEL_PROC_CODEC_MODE codecMode) {
781
4.77k
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
782
783
4.77k
  if (hSelProcInput == NULL) return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE;
784
785
4.77k
  switch (codecMode) {
786
0
    case SEL_PROC_MPEG_H_3DA:
787
0
      hSelProcInput->loudnessDeviationMax = 0;
788
0
      hSelProcInput->peakLimiterPresent = 1; /* peak limiter is mandatory */
789
      /* The peak limiter also has to catch overshoots due to user
790
      interactivity, downmixing etc. Therefore the maximum output peak level is
791
      reduced to 0 dB. */
792
0
      hSelProcInput->outputPeakLevelMax = (FIXP_DBL)0;
793
0
      break;
794
0
    case SEL_PROC_MPEG_4_AAC:
795
4.77k
    case SEL_PROC_MPEG_D_USAC:
796
4.77k
      hSelProcInput->loudnessDeviationMax = DEFAULT_LOUDNESS_DEVIATION_MAX;
797
4.77k
      hSelProcInput->peakLimiterPresent = 1;
798
      /* A peak limiter is present at the end of the decoder, therefore we can
799
       * allow for a maximum output peak level greater than full scale
800
       */
801
4.77k
      hSelProcInput->outputPeakLevelMax =
802
4.77k
          FL2FXCONST_DBL(6.0f / (float)(1 << 7));
803
4.77k
      break;
804
0
    case SEL_PROC_TEST_TIME_DOMAIN:
805
0
    case SEL_PROC_TEST_QMF_DOMAIN:
806
0
    case SEL_PROC_TEST_STFT_DOMAIN:
807
      /* for testing, adapt to default settings in reference software */
808
0
      hSelProcInput->loudnessNormalizationOn = 0;
809
0
      hSelProcInput->dynamicRangeControlOn = 0;
810
0
      break;
811
0
    case SEL_PROC_CODEC_MODE_UNDEFINED:
812
0
    default:
813
0
      hSelProcInput->loudnessDeviationMax = DEFAULT_LOUDNESS_DEVIATION_MAX;
814
0
      hSelProcInput->peakLimiterPresent = 0;
815
4.77k
  }
816
817
4.77k
  return retVal;
818
4.77k
}
819
820
static DRCDEC_SELECTION_PROCESS_RETURN _channelLayoutToDownmixIdMapping(
821
2.68k
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig) {
822
2.68k
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
823
824
2.68k
  DOWNMIX_INSTRUCTIONS* pDown = NULL;
825
826
2.68k
  int i;
827
828
2.68k
  hSelProcInput->numDownmixIdRequests = 0;
829
830
2.68k
  switch (hSelProcInput->targetConfigRequestType) {
831
2.68k
    case TCRT_DOWNMIX_ID:
832
2.68k
      if (hSelProcInput->numDownmixIdRequests == 0) {
833
2.68k
        hSelProcInput->downmixIdRequested[0] = 0;
834
2.68k
        hSelProcInput->numDownmixIdRequests = 1;
835
2.68k
      }
836
837
2.68k
      break;
838
839
0
    case TCRT_TARGET_LAYOUT:
840
0
      if (hSelProcInput->targetLayoutRequested == hSelProcInput->baseLayout) {
841
0
        hSelProcInput->downmixIdRequested[0] = 0;
842
0
        hSelProcInput->numDownmixIdRequests = 1;
843
0
      }
844
845
0
      if (hSelProcInput->numDownmixIdRequests == 0) {
846
0
        for (i = 0; i < hUniDrcConfig->downmixInstructionsCount; i++) {
847
0
          pDown = &(hUniDrcConfig->downmixInstructions[i]);
848
849
0
          if (hSelProcInput->targetLayoutRequested == pDown->targetLayout) {
850
0
            hSelProcInput
851
0
                ->downmixIdRequested[hSelProcInput->numDownmixIdRequests] =
852
0
                pDown->downmixId;
853
0
            hSelProcInput->numDownmixIdRequests++;
854
0
          }
855
0
        }
856
0
      }
857
858
0
      if (hSelProcInput->baseLayout == -1) {
859
0
        retVal = DRCDEC_SELECTION_PROCESS_WARNING;
860
0
      }
861
862
0
      if (hSelProcInput->numDownmixIdRequests == 0) {
863
0
        hSelProcInput->downmixIdRequested[0] = 0;
864
0
        hSelProcInput->numDownmixIdRequests = 1;
865
0
        retVal = DRCDEC_SELECTION_PROCESS_WARNING;
866
0
      }
867
868
0
      break;
869
870
0
    case TCRT_TARGET_CHANNEL_COUNT:
871
0
      if (hSelProcInput->targetChannelCountRequested ==
872
0
          hSelProcInput->baseChannelCount) {
873
0
        hSelProcInput->downmixIdRequested[0] = 0;
874
0
        hSelProcInput->numDownmixIdRequests = 1;
875
0
      }
876
877
0
      if (hSelProcInput->numDownmixIdRequests == 0) {
878
0
        for (i = 0; i < hUniDrcConfig->downmixInstructionsCount; i++) {
879
0
          pDown = &(hUniDrcConfig->downmixInstructions[i]);
880
881
0
          if (hSelProcInput->targetChannelCountRequested ==
882
0
              pDown->targetChannelCount) {
883
0
            hSelProcInput
884
0
                ->downmixIdRequested[hSelProcInput->numDownmixIdRequests] =
885
0
                pDown->downmixId;
886
0
            hSelProcInput->numDownmixIdRequests++;
887
0
          }
888
0
        }
889
0
      }
890
891
0
      if (hSelProcInput->baseChannelCount == -1) {
892
0
        retVal = DRCDEC_SELECTION_PROCESS_WARNING;
893
0
      }
894
895
0
      if (hSelProcInput->numDownmixIdRequests == 0) {
896
0
        retVal = DRCDEC_SELECTION_PROCESS_WARNING;
897
0
        hSelProcInput->downmixIdRequested[0] = 0;
898
0
        hSelProcInput->numDownmixIdRequests = 1;
899
0
      }
900
901
0
      break;
902
903
0
    default:
904
0
      return DRCDEC_SELECTION_PROCESS_NOT_OK;
905
2.68k
  }
906
907
2.68k
  return retVal;
908
2.68k
}
909
910
/*******************************************/
911
912
/* Note: Numbering of DRC pre-selection steps according to MPEG-D Part-4 DRC
913
 * Amd1 */
914
915
/* #1: DownmixId of DRC set matches the requested downmixId.
916
   #2: Output channel layout of DRC set matches the requested layout.
917
   #3: Channel count of DRC set matches the requested channel count. */
918
static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement123(
919
    int nRequestedDownmixId, DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc,
920
6.16k
    int* pMatchFound) {
921
6.16k
  int i;
922
6.16k
  *pMatchFound = 0;
923
924
6.82k
  for (i = 0; i < pDrcInstructionUniDrc->downmixIdCount; i++) {
925
6.52k
    if ((pDrcInstructionUniDrc->downmixId[i] == nRequestedDownmixId) ||
926
6.52k
        (pDrcInstructionUniDrc->downmixId[i] == DOWNMIX_ID_ANY_DOWNMIX) ||
927
6.52k
        ((pDrcInstructionUniDrc->downmixId[i] == DOWNMIX_ID_BASE_LAYOUT) &&
928
5.86k
         (pDrcInstructionUniDrc->drcSetId > 0))) {
929
5.86k
      *pMatchFound = 1;
930
5.86k
      break;
931
5.86k
    }
932
6.52k
  }
933
934
6.16k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
935
6.16k
}
936
937
/* #4: The DRC set is not a "Fade-" or "Ducking-" only DRC set. */
938
static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement4(
939
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction, int nDynamicRangeControlOn,
940
5.86k
    int* pMatchFound) {
941
5.86k
  *pMatchFound = 0;
942
943
5.86k
  if (nDynamicRangeControlOn == 1) {
944
5.86k
    if ((pDrcInstruction->drcSetEffect != EB_FADE) &&
945
5.86k
        (pDrcInstruction->drcSetEffect != EB_DUCK_OTHER) &&
946
5.86k
        (pDrcInstruction->drcSetEffect != EB_DUCK_SELF) &&
947
5.86k
        (pDrcInstruction->drcSetEffect != 0 || pDrcInstruction->drcSetId < 0)) {
948
5.51k
      *pMatchFound = 1;
949
5.51k
    }
950
5.86k
  } else {
951
0
    *pMatchFound = 1;
952
0
  }
953
954
5.86k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
955
5.86k
}
956
957
/* #5: The number of DRC bands is supported. Moreover, gainSetIndex and
958
 * gainSequenceIndex are within the allowed range. */
959
static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement5(
960
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc,
961
9.91k
    DRC_COEFFICIENTS_UNI_DRC* pCoef, int* pMatchFound) {
962
9.91k
  int b, i;
963
964
9.91k
  *pMatchFound = 1;
965
966
9.91k
  if (pDrcInstructionUniDrc->drcSetId < 0) /* virtual DRC sets are okay */
967
3.88k
  {
968
3.88k
    return DRCDEC_SELECTION_PROCESS_NO_ERROR;
969
3.88k
  }
970
971
6.02k
  if (pCoef == NULL) /* check for parametricDRC */
972
682
  {
973
682
    *pMatchFound = 0; /* parametricDRC not supported */
974
682
    return DRCDEC_SELECTION_PROCESS_NO_ERROR;
975
682
  }
976
977
5.34k
  if (pCoef->drcLocation !=
978
5.34k
      pDrcInstructionUniDrc
979
5.34k
          ->drcLocation) /* drcLocation must be LOCATION_SELECTED */
980
879
  {
981
879
    *pMatchFound = 0;
982
879
    return DRCDEC_SELECTION_PROCESS_NO_ERROR;
983
879
  }
984
985
7.50k
  for (i = 0; i < pDrcInstructionUniDrc->nDrcChannelGroups; i++) {
986
3.34k
    int indexDrcCoeff = pDrcInstructionUniDrc->gainSetIndexForChannelGroup[i];
987
3.34k
    int bandCount = 0;
988
989
3.34k
    if (indexDrcCoeff >= 12) {
990
161
      *pMatchFound = 0;
991
161
      return DRCDEC_SELECTION_PROCESS_NO_ERROR;
992
161
    }
993
994
3.18k
    if (indexDrcCoeff > pCoef->gainSetCount - 1) /* check for parametricDRC */
995
1.74k
    {
996
1.74k
      continue;
997
1.74k
    }
998
999
1.44k
    GAIN_SET* gainSet = &(pCoef->gainSet[indexDrcCoeff]);
1000
1.44k
    bandCount = gainSet->bandCount;
1001
1002
1.44k
    if (bandCount > 4) {
1003
0
      *pMatchFound = 0;
1004
0
    }
1005
1006
2.77k
    for (b = 0; b < bandCount; b++) {
1007
1.47k
      if ((gainSet->gainSequenceIndex[b] >= 12) ||
1008
1.47k
          (gainSet->gainSequenceIndex[b] >= pCoef->gainSequenceCount)) {
1009
144
        *pMatchFound = 0;
1010
144
        return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1011
144
      }
1012
1.47k
    }
1013
1.44k
  }
1014
1015
4.16k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1016
4.46k
}
1017
1018
/* #6: Independent use of DRC set is permitted.*/
1019
static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement6(
1020
5.31k
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, int* pMatchFound) {
1021
5.31k
  *pMatchFound = 0;
1022
1023
5.31k
  if (((pDrcInstructionUniDrc->dependsOnDrcSetPresent == 0) &&
1024
5.31k
       (pDrcInstructionUniDrc->noIndependentUse == 0)) ||
1025
5.31k
      (pDrcInstructionUniDrc->dependsOnDrcSetPresent == 1)) {
1026
5.29k
    *pMatchFound = 1;
1027
5.29k
  }
1028
1029
5.31k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1030
5.31k
}
1031
1032
/* #7: DRC sets that require EQ are only permitted if EQ is supported. */
1033
static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement7(
1034
5.29k
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, int* pMatchFound) {
1035
5.29k
  *pMatchFound = 1;
1036
1037
5.29k
  if (pDrcInstructionUniDrc->requiresEq) {
1038
    /* EQ is not supported */
1039
15
    *pMatchFound = 0;
1040
15
  }
1041
1042
5.29k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1043
5.29k
}
1044
1045
static void _setSelectionDataInfo(
1046
    DRCDEC_SELECTION_DATA* pData, FIXP_DBL loudness, /* e = 7 */
1047
    FIXP_DBL loudnessNormalizationGainDb,            /* e = 7 */
1048
    FIXP_DBL loudnessNormalizationGainDbMax,         /* e = 7 */
1049
    FIXP_DBL loudnessDeviationMax,                   /* e = 7 */
1050
    FIXP_DBL signalPeakLevel,                        /* e = 7 */
1051
    FIXP_DBL outputPeakLevelMax,                     /* e = 7 */
1052
5.20k
    int applyAdjustment) {
1053
5.20k
  FIXP_DBL adjustment = 0; /* e = 8 */
1054
1055
  /* use e = 8 for all function parameters to prevent overflow */
1056
5.20k
  loudness >>= 1;
1057
5.20k
  loudnessNormalizationGainDb >>= 1;
1058
5.20k
  loudnessNormalizationGainDbMax >>= 1;
1059
5.20k
  loudnessDeviationMax >>= 1;
1060
5.20k
  signalPeakLevel >>= 1;
1061
5.20k
  outputPeakLevelMax >>= 1;
1062
1063
5.20k
  if (applyAdjustment) {
1064
0
    adjustment =
1065
0
        fMax((FIXP_DBL)0, signalPeakLevel + loudnessNormalizationGainDb -
1066
0
                              outputPeakLevelMax);
1067
0
    adjustment = fMin(adjustment, fMax((FIXP_DBL)0, loudnessDeviationMax));
1068
0
  }
1069
1070
5.20k
  pData->loudnessNormalizationGainDbAdjusted = fMin(
1071
5.20k
      loudnessNormalizationGainDb - adjustment, loudnessNormalizationGainDbMax);
1072
5.20k
  pData->outputLoudness = loudness + pData->loudnessNormalizationGainDbAdjusted;
1073
5.20k
  pData->outputPeakLevel =
1074
5.20k
      signalPeakLevel + pData->loudnessNormalizationGainDbAdjusted;
1075
1076
  /* shift back to e = 7 using saturation */
1077
5.20k
  pData->loudnessNormalizationGainDbAdjusted = SATURATE_LEFT_SHIFT(
1078
5.20k
      pData->loudnessNormalizationGainDbAdjusted, 1, DFRACT_BITS);
1079
5.20k
  pData->outputLoudness =
1080
5.20k
      SATURATE_LEFT_SHIFT(pData->outputLoudness, 1, DFRACT_BITS);
1081
5.20k
  pData->outputPeakLevel =
1082
5.20k
      SATURATE_LEFT_SHIFT(pData->outputPeakLevel, 1, DFRACT_BITS);
1083
5.20k
}
1084
1085
static int _targetLoudnessInRange(
1086
2.40k
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, FIXP_DBL targetLoudness) {
1087
2.40k
  int retVal = 0;
1088
1089
2.40k
  FIXP_DBL drcSetTargetLoudnessValueUpper =
1090
2.40k
      ((FIXP_DBL)pDrcInstructionUniDrc->drcSetTargetLoudnessValueUpper)
1091
2.40k
      << (DFRACT_BITS - 1 - 7);
1092
2.40k
  FIXP_DBL drcSetTargetLoudnessValueLower =
1093
2.40k
      ((FIXP_DBL)pDrcInstructionUniDrc->drcSetTargetLoudnessValueLower)
1094
2.40k
      << (DFRACT_BITS - 1 - 7);
1095
1096
2.40k
  if (pDrcInstructionUniDrc->drcSetTargetLoudnessPresent &&
1097
2.40k
      drcSetTargetLoudnessValueUpper >= targetLoudness &&
1098
2.40k
      drcSetTargetLoudnessValueLower < targetLoudness) {
1099
302
    retVal = 1;
1100
302
  }
1101
1102
2.40k
  return retVal;
1103
2.40k
}
1104
1105
static int _drcSetIsUsable(HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
1106
9.07k
                           DRC_INSTRUCTIONS_UNI_DRC* pInst) {
1107
9.07k
  int usable = 0;
1108
9.07k
  DRC_COEFFICIENTS_UNI_DRC* pCoef =
1109
9.07k
      selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED);
1110
1111
  /* check if ID is unique */
1112
9.07k
  if (selectDrcInstructions(hUniDrcConfig, pInst->drcSetId) != pInst) return 0;
1113
  /* sanity check on drcInstructions */
1114
4.40k
  _preSelectionRequirement5(pInst, pCoef, &usable);
1115
4.40k
  return usable;
1116
9.07k
}
1117
1118
/* #8: The range of the target loudness specified for a DRC set has to include
1119
 * the requested decoder target loudness. */
1120
static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement8(
1121
    SEL_PROC_INPUT* hSelProcInput, int downmixIdIndex,
1122
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
1123
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
1124
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc,
1125
    DRCDEC_SELECTION* pCandidatesPotential,
1126
5.27k
    DRCDEC_SELECTION* pCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) {
1127
5.27k
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1128
5.27k
  int explicitPeakInformationPresent;
1129
5.27k
  FIXP_DBL signalPeakLevel;
1130
5.27k
  int addToCandidate = 0;
1131
1132
5.27k
  FIXP_DBL loudnessNormalizationGainDb;
1133
5.27k
  FIXP_DBL loudness;
1134
1135
5.27k
  FIXP_DBL loudnessDeviationMax =
1136
5.27k
      ((FIXP_DBL)hSelProcInput->loudnessDeviationMax) << (DFRACT_BITS - 1 - 7);
1137
1138
5.27k
  {
1139
5.27k
    retVal = _getLoudness(hLoudnessInfoSet, hSelProcInput->albumMode,
1140
5.27k
                          hSelProcInput->loudnessMeasurementMethod,
1141
5.27k
                          hSelProcInput->loudnessMeasurementSystem,
1142
5.27k
                          hSelProcInput->targetLoudness,
1143
5.27k
                          pDrcInstructionUniDrc->drcSetId,
1144
5.27k
                          hSelProcInput->downmixIdRequested[downmixIdIndex],
1145
5.27k
                          &loudnessNormalizationGainDb, &loudness);
1146
5.27k
    if (retVal) return (retVal);
1147
5.27k
  }
1148
1149
5.26k
  if (!hSelProcInput->loudnessNormalizationOn) {
1150
0
    loudnessNormalizationGainDb = (FIXP_DBL)0;
1151
0
  }
1152
1153
5.26k
  retVal = _getSignalPeakLevel(
1154
5.26k
      hSelProcInput, hUniDrcConfig, hLoudnessInfoSet, pDrcInstructionUniDrc,
1155
5.26k
      hSelProcInput->downmixIdRequested[downmixIdIndex],
1156
5.26k
      &explicitPeakInformationPresent, &signalPeakLevel, codecMode
1157
1158
5.26k
  );
1159
5.26k
  if (retVal) return (retVal);
1160
1161
5.26k
  if (hSelProcInput->dynamicRangeControlOn) {
1162
5.26k
    if (explicitPeakInformationPresent == 0) {
1163
3.95k
      if (pDrcInstructionUniDrc->drcSetTargetLoudnessPresent &&
1164
3.95k
          ((hSelProcInput->loudnessNormalizationOn &&
1165
179
            _targetLoudnessInRange(pDrcInstructionUniDrc,
1166
179
                                   hSelProcInput->targetLoudness)) ||
1167
179
           !hSelProcInput->loudnessNormalizationOn)) {
1168
127
        DRCDEC_SELECTION_DATA* pData =
1169
127
            _drcdec_selection_addNew(pCandidatesSelected);
1170
127
        if (pData == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1171
1172
127
        _setSelectionDataInfo(pData, loudness, loudnessNormalizationGainDb,
1173
127
                              hSelProcInput->loudnessNormalizationGainDbMax,
1174
127
                              loudnessDeviationMax, signalPeakLevel,
1175
127
                              hSelProcInput->outputPeakLevelMax, 0);
1176
127
        pData->downmixIdRequestIndex = downmixIdIndex;
1177
127
        pData->pInst = pDrcInstructionUniDrc;
1178
127
        pData->selectionFlag =
1179
127
            1; /* signal pre-selection step dealing with drcSetTargetLoudness */
1180
1181
127
        if (hSelProcInput->loudnessNormalizationOn) {
1182
127
          pData->outputPeakLevel =
1183
127
              hSelProcInput->targetLoudness -
1184
127
              (((FIXP_DBL)pData->pInst->drcSetTargetLoudnessValueUpper)
1185
127
               << (DFRACT_BITS - 1 - 7));
1186
127
        } else {
1187
0
          pData->outputPeakLevel = (FIXP_DBL)0;
1188
0
        }
1189
3.83k
      } else {
1190
3.83k
        if ((!hSelProcInput->loudnessNormalizationOn) ||
1191
3.83k
            (!pDrcInstructionUniDrc->drcSetTargetLoudnessPresent) ||
1192
3.83k
            (hSelProcInput->loudnessNormalizationOn &&
1193
52
             _targetLoudnessInRange(pDrcInstructionUniDrc,
1194
3.78k
                                    hSelProcInput->targetLoudness))) {
1195
3.78k
          addToCandidate = 1;
1196
3.78k
        }
1197
3.83k
      }
1198
3.95k
    } else {
1199
1.30k
      addToCandidate = 1;
1200
1.30k
    }
1201
1202
5.26k
    if (addToCandidate) {
1203
5.08k
      DRCDEC_SELECTION_DATA* pData =
1204
5.08k
          _drcdec_selection_addNew(pCandidatesPotential);
1205
5.08k
      if (pData == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1206
1207
5.08k
      _setSelectionDataInfo(pData, loudness, loudnessNormalizationGainDb,
1208
5.08k
                            hSelProcInput->loudnessNormalizationGainDbMax,
1209
5.08k
                            loudnessDeviationMax, signalPeakLevel,
1210
5.08k
                            hSelProcInput->outputPeakLevelMax, 0);
1211
5.08k
      pData->downmixIdRequestIndex = downmixIdIndex;
1212
5.08k
      pData->pInst = pDrcInstructionUniDrc;
1213
5.08k
      pData->selectionFlag = 0;
1214
5.08k
    }
1215
5.26k
  } else {
1216
0
    if (pDrcInstructionUniDrc->drcSetId < 0) {
1217
0
      DRCDEC_SELECTION_DATA* pData =
1218
0
          _drcdec_selection_addNew(pCandidatesSelected);
1219
0
      if (pData == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1220
1221
0
      _setSelectionDataInfo(pData, loudness, loudnessNormalizationGainDb,
1222
0
                            hSelProcInput->loudnessNormalizationGainDbMax,
1223
0
                            loudnessDeviationMax, signalPeakLevel,
1224
0
                            hSelProcInput->outputPeakLevelMax, 1);
1225
1226
0
      pData->downmixIdRequestIndex = downmixIdIndex;
1227
0
      pData->pInst = pDrcInstructionUniDrc;
1228
0
      pData->selectionFlag = 0;
1229
0
    }
1230
0
  }
1231
1232
5.26k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1233
5.26k
}
1234
1235
/* #9: Clipping is minimized. */
1236
static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement9(
1237
    SEL_PROC_INPUT* hSelProcInput, DRCDEC_SELECTION* pCandidatesPotential,
1238
2.67k
    DRCDEC_SELECTION* pCandidatesSelected) {
1239
2.67k
  int i;
1240
1241
7.75k
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1242
5.08k
    DRCDEC_SELECTION_DATA* pCandidate =
1243
5.08k
        _drcdec_selection_getAt(pCandidatesPotential, i);
1244
5.08k
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1245
1246
5.08k
    if (pCandidate->outputPeakLevel <= hSelProcInput->outputPeakLevelMax) {
1247
4.01k
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1248
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1249
4.01k
    }
1250
5.08k
  }
1251
1252
2.67k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1253
2.67k
}
1254
1255
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetPreSelectionSingleInstruction(
1256
    SEL_PROC_INPUT* hSelProcInput, int downmixIdIndex,
1257
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
1258
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
1259
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc,
1260
    DRCDEC_SELECTION* pCandidatesPotential,
1261
6.16k
    DRCDEC_SELECTION* pCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) {
1262
6.16k
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1263
6.16k
  int matchFound = 0;
1264
6.16k
  DRC_COEFFICIENTS_UNI_DRC* pCoef =
1265
6.16k
      selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED);
1266
1267
6.16k
  retVal = _preSelectionRequirement123(
1268
6.16k
      hSelProcInput->downmixIdRequested[downmixIdIndex], pDrcInstructionUniDrc,
1269
6.16k
      &matchFound);
1270
1271
6.16k
  if (!retVal && matchFound)
1272
5.86k
    retVal = _preSelectionRequirement4(pDrcInstructionUniDrc,
1273
5.86k
                                       hSelProcInput->dynamicRangeControlOn,
1274
5.86k
                                       &matchFound);
1275
1276
6.16k
  if (!retVal && matchFound)
1277
5.51k
    retVal =
1278
5.51k
        _preSelectionRequirement5(pDrcInstructionUniDrc, pCoef, &matchFound);
1279
1280
6.16k
  if (!retVal && matchFound)
1281
5.31k
    retVal = _preSelectionRequirement6(pDrcInstructionUniDrc, &matchFound);
1282
1283
6.16k
  if (!retVal && matchFound)
1284
5.29k
    retVal = _preSelectionRequirement7(pDrcInstructionUniDrc, &matchFound);
1285
1286
6.16k
  if (!retVal && matchFound)
1287
5.27k
    retVal = _preSelectionRequirement8(
1288
5.27k
        hSelProcInput, downmixIdIndex, hUniDrcConfig, hLoudnessInfoSet,
1289
5.27k
        pDrcInstructionUniDrc, pCandidatesPotential, pCandidatesSelected,
1290
5.27k
        codecMode);
1291
1292
6.16k
  return retVal;
1293
6.16k
}
1294
1295
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetSelectionAddCandidates(
1296
    SEL_PROC_INPUT* hSelProcInput, DRCDEC_SELECTION* pCandidatesPotential,
1297
207
    DRCDEC_SELECTION* pCandidatesSelected) {
1298
207
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1299
207
  int nHitCount = 0;
1300
207
  int i;
1301
1302
207
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1303
207
  DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc = NULL;
1304
1305
1.06k
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1306
858
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1307
858
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1308
1309
858
    pDrcInstructionUniDrc = pCandidate->pInst;
1310
1311
858
    if (_targetLoudnessInRange(pDrcInstructionUniDrc,
1312
858
                               hSelProcInput->targetLoudness)) {
1313
49
      nHitCount++;
1314
49
    }
1315
858
  }
1316
1317
207
  if (nHitCount != 0) {
1318
247
    for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1319
212
      pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1320
212
      if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1321
1322
212
      pDrcInstructionUniDrc = pCandidate->pInst;
1323
1324
212
      if (_targetLoudnessInRange(pDrcInstructionUniDrc,
1325
212
                                 hSelProcInput->targetLoudness)) {
1326
49
        if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1327
0
          return DRCDEC_SELECTION_PROCESS_NOT_OK;
1328
49
      }
1329
212
    }
1330
172
  } else {
1331
172
    FIXP_DBL lowestPeakLevel = MAXVAL_DBL; /* e = 7 */
1332
172
    FIXP_DBL peakLevel = 0;                /* e = 7 */
1333
1334
818
    for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1335
646
      pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1336
646
      if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1337
1338
646
      peakLevel = pCandidate->outputPeakLevel;
1339
1340
646
      if (peakLevel < lowestPeakLevel) {
1341
189
        lowestPeakLevel = peakLevel;
1342
189
      }
1343
646
    }
1344
1345
    /* add all with lowest peak level or max 1dB above */
1346
818
    for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1347
646
      FIXP_DBL loudnessDeviationMax =
1348
646
          ((FIXP_DBL)hSelProcInput->loudnessDeviationMax)
1349
646
          << (DFRACT_BITS - 1 - 7); /* e = 7 */
1350
1351
646
      pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1352
646
      if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1353
1354
646
      peakLevel = pCandidate->outputPeakLevel;
1355
1356
646
      if (peakLevel == lowestPeakLevel ||
1357
646
          peakLevel <=
1358
558
              lowestPeakLevel + FL2FXCONST_DBL(1.0f / (float)(1 << 7))) {
1359
558
        FIXP_DBL adjustment =
1360
558
            fMax((FIXP_DBL)0, peakLevel - hSelProcInput->outputPeakLevelMax);
1361
558
        adjustment = fMin(adjustment, fMax((FIXP_DBL)0, loudnessDeviationMax));
1362
1363
558
        pCandidate->loudnessNormalizationGainDbAdjusted -= adjustment;
1364
558
        pCandidate->outputPeakLevel -= adjustment;
1365
558
        pCandidate->outputLoudness -= adjustment;
1366
558
        if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1367
0
          return DRCDEC_SELECTION_PROCESS_NOT_OK;
1368
558
      }
1369
646
    }
1370
172
  }
1371
1372
207
  return retVal;
1373
207
}
1374
1375
static DRCDEC_SELECTION_PROCESS_RETURN _dependentDrcInstruction(
1376
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRC_INSTRUCTIONS_UNI_DRC* pInst,
1377
694
    DRC_INSTRUCTIONS_UNI_DRC** ppDrcInstructionsDependent) {
1378
694
  int i;
1379
694
  DRC_INSTRUCTIONS_UNI_DRC* pDependentDrc = NULL;
1380
1381
3.22k
  for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
1382
3.21k
    pDependentDrc =
1383
3.21k
        (DRC_INSTRUCTIONS_UNI_DRC*)&(hUniDrcConfig->drcInstructionsUniDrc[i]);
1384
1385
3.21k
    if (pDependentDrc->drcSetId == pInst->dependsOnDrcSet) {
1386
684
      break;
1387
684
    }
1388
3.21k
  }
1389
1390
694
  if (i == hUniDrcConfig->drcInstructionsUniDrcCount) {
1391
10
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
1392
10
  }
1393
1394
684
  if (pDependentDrc->dependsOnDrcSetPresent == 1) {
1395
5
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
1396
5
  }
1397
1398
679
  *ppDrcInstructionsDependent = pDependentDrc;
1399
1400
679
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1401
684
}
1402
1403
static DRCDEC_SELECTION_PROCESS_RETURN _selectDrcSetEffectNone(
1404
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRCDEC_SELECTION* pCandidatesPotential,
1405
2.67k
    DRCDEC_SELECTION* pCandidatesSelected) {
1406
2.67k
  int i;
1407
1408
7.41k
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1409
4.74k
    DRCDEC_SELECTION_DATA* pCandidate =
1410
4.74k
        _drcdec_selection_getAt(pCandidatesPotential, i);
1411
4.74k
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1412
1413
4.74k
    if ((pCandidate->pInst->drcSetEffect & 0xff) == 0) {
1414
3.80k
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1415
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1416
3.80k
    }
1417
4.74k
  }
1418
1419
2.67k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1420
2.67k
}
1421
1422
static DRCDEC_SELECTION_PROCESS_RETURN _selectSingleEffectType(
1423
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRC_EFFECT_TYPE_REQUEST effectType,
1424
    DRCDEC_SELECTION* pCandidatesPotential,
1425
740
    DRCDEC_SELECTION* pCandidatesSelected) {
1426
740
  int i;
1427
740
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1428
740
  DRC_INSTRUCTIONS_UNI_DRC* pInst;
1429
740
  DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionsDependent;
1430
1431
740
  if (effectType == DETR_NONE) {
1432
0
    retVal = _selectDrcSetEffectNone(hUniDrcConfig, pCandidatesPotential,
1433
0
                                     pCandidatesSelected);
1434
0
    if (retVal) return (retVal);
1435
740
  } else {
1436
740
    int effectBitPosition = 1 << (effectType - 1);
1437
1438
2.43k
    for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1439
1.71k
      DRCDEC_SELECTION_DATA* pCandidate =
1440
1.71k
          _drcdec_selection_getAt(pCandidatesPotential, i);
1441
1.71k
      if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1442
1443
1.71k
      pInst = pCandidate->pInst;
1444
1445
1.71k
      if (!pInst->dependsOnDrcSetPresent) {
1446
1.01k
        if ((pInst->drcSetEffect & effectBitPosition)) {
1447
585
          if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1448
0
            return DRCDEC_SELECTION_PROCESS_NOT_OK;
1449
585
        }
1450
1.01k
      } else {
1451
694
        retVal = _dependentDrcInstruction(hUniDrcConfig, pInst,
1452
694
                                          &pDrcInstructionsDependent);
1453
694
        if (retVal) return (retVal);
1454
1455
679
        if (((pInst->drcSetEffect & effectBitPosition)) ||
1456
679
            ((pDrcInstructionsDependent->drcSetEffect & effectBitPosition))) {
1457
526
          if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1458
0
            return DRCDEC_SELECTION_PROCESS_NOT_OK;
1459
526
        }
1460
679
      }
1461
1.71k
    }
1462
740
  }
1463
1464
725
  return retVal;
1465
740
}
1466
1467
static DRCDEC_SELECTION_PROCESS_RETURN _selectEffectTypeFeature(
1468
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRC_FEATURE_REQUEST drcFeatureRequest,
1469
    DRCDEC_SELECTION** ppCandidatesPotential,
1470
160
    DRCDEC_SELECTION** ppCandidatesSelected) {
1471
160
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1472
160
  int i;
1473
160
  int desiredEffectTypeFound = 0;
1474
1475
885
  for (i = 0; i < drcFeatureRequest.drcEffectType.numRequestsDesired; i++) {
1476
740
    retVal = _selectSingleEffectType(
1477
740
        hUniDrcConfig, drcFeatureRequest.drcEffectType.request[i],
1478
740
        *ppCandidatesPotential, *ppCandidatesSelected);
1479
740
    if (retVal) return (retVal);
1480
1481
725
    if (_drcdec_selection_getNumber(*ppCandidatesSelected)) {
1482
414
      desiredEffectTypeFound = 1;
1483
414
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1484
414
    }
1485
725
  }
1486
1487
145
  if (!desiredEffectTypeFound) {
1488
1
    for (i = drcFeatureRequest.drcEffectType.numRequestsDesired;
1489
1
         i < drcFeatureRequest.drcEffectType.numRequests; i++) {
1490
0
      retVal = _selectSingleEffectType(
1491
0
          hUniDrcConfig, drcFeatureRequest.drcEffectType.request[i],
1492
0
          *ppCandidatesPotential, *ppCandidatesSelected);
1493
0
      if (retVal) return (retVal);
1494
1495
0
      if (_drcdec_selection_getNumber(*ppCandidatesSelected)) {
1496
0
        _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1497
0
        break;
1498
0
      }
1499
0
    }
1500
1
  }
1501
1502
145
  _swapSelection(ppCandidatesPotential, ppCandidatesSelected);
1503
1504
145
  return retVal;
1505
145
}
1506
1507
static DRCDEC_SELECTION_PROCESS_RETURN _selectDynamicRange(
1508
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
1509
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
1510
    DRC_FEATURE_REQUEST drcFeatureRequest, UCHAR* pDownmixIdRequested,
1511
    int albumMode, DRCDEC_SELECTION* pCandidatesPotential,
1512
0
    DRCDEC_SELECTION* ppCandidatesSelected) {
1513
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1514
0
  int i;
1515
0
  int peakToAveragePresent;
1516
0
  FIXP_DBL peakToAverage;
1517
1518
0
  FIXP_DBL minVal = MAXVAL_DBL;
1519
0
  FIXP_DBL val = 0;
1520
1521
0
  int numSelectedCandidates = _drcdec_selection_getNumber(ppCandidatesSelected);
1522
1523
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1524
0
    DRCDEC_SELECTION_DATA* pCandidate =
1525
0
        _drcdec_selection_getAt(pCandidatesPotential, i);
1526
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1527
1528
0
    retVal = _dynamicRangeMeasurement(
1529
0
        hLoudnessInfoSet, pCandidate->pInst,
1530
0
        pDownmixIdRequested[pCandidate->downmixIdRequestIndex],
1531
0
        drcFeatureRequest.dynamicRange.measurementRequestType, albumMode,
1532
0
        &peakToAveragePresent, &peakToAverage);
1533
0
    if (retVal) return (retVal);
1534
1535
0
    if (peakToAveragePresent) {
1536
0
      if (!drcFeatureRequest.dynamicRange.requestedIsRange) {
1537
0
        val = fAbs(drcFeatureRequest.dynamicRange.requestValue - peakToAverage);
1538
1539
0
        if (minVal > val) {
1540
0
          minVal = val;
1541
1542
0
          _drcdec_selection_setNumber(ppCandidatesSelected,
1543
0
                                      numSelectedCandidates);
1544
0
        }
1545
0
        if (_drcdec_selection_add(ppCandidatesSelected, pCandidate) == NULL)
1546
0
          return DRCDEC_SELECTION_PROCESS_NOT_OK;
1547
0
      } else {
1548
0
        if ((peakToAverage >= drcFeatureRequest.dynamicRange.requestValueMin) &&
1549
0
            (peakToAverage <= drcFeatureRequest.dynamicRange.requestValueMax)) {
1550
0
          if (_drcdec_selection_add(ppCandidatesSelected, pCandidate) == NULL)
1551
0
            return DRCDEC_SELECTION_PROCESS_NOT_OK;
1552
0
        }
1553
0
      }
1554
0
    }
1555
0
  }
1556
1557
0
  return retVal;
1558
0
}
1559
1560
static DRCDEC_SELECTION_PROCESS_RETURN _selectSingleDrcCharacteristic(
1561
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig, int requestedDrcCharacteristic,
1562
    DRCDEC_SELECTION** ppCandidatesPotential,
1563
0
    DRCDEC_SELECTION** ppCandidatesSelected) {
1564
0
  int i, j, b;
1565
0
  int hit = 0;
1566
1567
0
  DRC_INSTRUCTIONS_UNI_DRC* pInst = NULL;
1568
0
  DRC_COEFFICIENTS_UNI_DRC* pCoef = NULL;
1569
0
  GAIN_SET* pGainSet = NULL;
1570
1571
0
  if (requestedDrcCharacteristic < 1) {
1572
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
1573
0
  }
1574
1575
0
  pCoef = selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED);
1576
1577
0
  if (pCoef == NULL) /* check for parametricDRC */
1578
0
  {
1579
0
    return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1580
0
  }
1581
1582
0
  for (i = 0; i < _drcdec_selection_getNumber(*ppCandidatesPotential); i++) {
1583
0
    DRCDEC_SELECTION_DATA* pCandidate =
1584
0
        _drcdec_selection_getAt(*ppCandidatesPotential, i);
1585
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1586
1587
0
    pInst = pCandidate->pInst;
1588
1589
0
    hit = 0;
1590
1591
0
    for (j = 0; j < pInst->nDrcChannelGroups; j++) {
1592
0
      int bandCount = 0;
1593
0
      int indexDrcCoeff = pInst->gainSetIndexForChannelGroup[j];
1594
1595
0
      if (indexDrcCoeff > pCoef->gainSetCount - 1) /* check for parametricDRC */
1596
0
      {
1597
0
        return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1598
0
      }
1599
1600
0
      pGainSet = &(pCoef->gainSet[indexDrcCoeff]);
1601
0
      bandCount = pGainSet->bandCount;
1602
1603
0
      for (b = 0; b < bandCount; b++) {
1604
0
        if ((pGainSet->drcCharacteristic[b].isCICP) &&
1605
0
            (pGainSet->drcCharacteristic[b].cicpIndex ==
1606
0
             requestedDrcCharacteristic)) {
1607
0
          hit = 1;
1608
0
          break;
1609
0
        }
1610
0
      }
1611
1612
0
      if (hit) break;
1613
0
    }
1614
1615
0
    if (hit) {
1616
0
      if (_drcdec_selection_add(*ppCandidatesSelected, pCandidate) == NULL)
1617
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1618
0
    }
1619
0
  }
1620
1621
0
  if (_drcdec_selection_getNumber(*ppCandidatesSelected)) {
1622
0
    _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1623
0
  }
1624
1625
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1626
0
}
1627
1628
static DRCDEC_SELECTION_PROCESS_RETURN _selectDrcCharacteristic(
1629
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig, int drcCharacteristicRequested,
1630
    DRCDEC_SELECTION** ppCandidatesPotential,
1631
0
    DRCDEC_SELECTION** ppCandidatesSelected) {
1632
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1633
1634
0
  const int secondTry[12] = {0, 2, 3, 4, 5, 6, 5, 9, 10, 7, 8, 10};
1635
1636
0
  retVal = _selectSingleDrcCharacteristic(
1637
0
      hUniDrcConfig, drcCharacteristicRequested, ppCandidatesPotential,
1638
0
      ppCandidatesSelected);
1639
0
  if (retVal) return (retVal);
1640
1641
0
  if ((drcCharacteristicRequested <= 11) &&
1642
0
      (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0)) {
1643
0
    retVal = _selectSingleDrcCharacteristic(
1644
0
        hUniDrcConfig, secondTry[drcCharacteristicRequested],
1645
0
        ppCandidatesPotential, ppCandidatesSelected);
1646
0
    if (retVal) return (retVal);
1647
0
  }
1648
1649
0
  if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) {
1650
0
    if ((drcCharacteristicRequested >= 2) &&
1651
0
        (drcCharacteristicRequested <= 5)) {
1652
0
      retVal = _selectSingleDrcCharacteristic(
1653
0
          hUniDrcConfig, drcCharacteristicRequested - 1, ppCandidatesPotential,
1654
0
          ppCandidatesSelected);
1655
0
      if (retVal) return (retVal);
1656
0
    } else if (drcCharacteristicRequested == 11) {
1657
0
      retVal = _selectSingleDrcCharacteristic(
1658
0
          hUniDrcConfig, 9, ppCandidatesPotential, ppCandidatesSelected);
1659
0
      if (retVal) return (retVal);
1660
0
    }
1661
0
  }
1662
1663
0
  _swapSelection(ppCandidatesPotential, ppCandidatesSelected);
1664
1665
0
  return retVal;
1666
0
}
1667
1668
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_peakValue0(
1669
    DRCDEC_SELECTION* pCandidatesPotential,
1670
474
    DRCDEC_SELECTION* pCandidatesSelected) {
1671
474
  int i;
1672
1673
2.41k
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1674
1.94k
    DRCDEC_SELECTION_DATA* pCandidate =
1675
1.94k
        _drcdec_selection_getAt(pCandidatesPotential, i);
1676
1.94k
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1677
1678
1.94k
    if (pCandidate->outputPeakLevel <= FIXP_DBL(0)) {
1679
1.51k
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1680
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1681
1.51k
    }
1682
1.94k
  }
1683
1684
474
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1685
474
}
1686
1687
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_downmixId(
1688
    HANDLE_SEL_PROC_INPUT hSelProcInput,
1689
    DRCDEC_SELECTION** ppCandidatesPotential,
1690
376
    DRCDEC_SELECTION** ppCandidatesSelected) {
1691
376
  int i, j;
1692
376
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1693
376
  DRC_INSTRUCTIONS_UNI_DRC* pInst = NULL;
1694
1695
1.87k
  for (i = 0; i < _drcdec_selection_getNumber(*ppCandidatesPotential); i++) {
1696
1.50k
    pCandidate = _drcdec_selection_getAt(*ppCandidatesPotential, i);
1697
1.50k
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1698
1699
1.50k
    pInst = pCandidate->pInst;
1700
1701
3.18k
    for (j = 0; j < pInst->downmixIdCount; j++) {
1702
1.68k
      if (DOWNMIX_ID_BASE_LAYOUT != pInst->downmixId[j] &&
1703
1.68k
          DOWNMIX_ID_ANY_DOWNMIX != pInst->downmixId[j] &&
1704
1.68k
          hSelProcInput
1705
69
                  ->downmixIdRequested[pCandidate->downmixIdRequestIndex] ==
1706
69
              pInst->downmixId[j]) {
1707
0
        if (_drcdec_selection_add(*ppCandidatesSelected, pCandidate) == NULL)
1708
0
          return DRCDEC_SELECTION_PROCESS_NOT_OK;
1709
0
      }
1710
1.68k
    }
1711
1.50k
  }
1712
1713
376
  if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) {
1714
376
    _swapSelection(ppCandidatesPotential, ppCandidatesSelected);
1715
376
  }
1716
1717
376
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1718
376
}
1719
1720
3.00k
static int _crossSum(int value) {
1721
3.00k
  int sum = 0;
1722
1723
16.3k
  while (value != 0) {
1724
13.3k
    if ((value & 1) == 1) {
1725
4.81k
      sum++;
1726
4.81k
    }
1727
1728
13.3k
    value >>= 1;
1729
13.3k
  }
1730
1731
3.00k
  return sum;
1732
3.00k
}
1733
1734
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_effectTypes(
1735
    DRCDEC_SELECTION* pCandidatesPotential,
1736
376
    DRCDEC_SELECTION* pCandidatesSelected) {
1737
376
  int i;
1738
376
  int minNumEffects = 1000;
1739
376
  int numEffects = 0;
1740
376
  int effects = 0;
1741
376
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1742
376
  DRC_INSTRUCTIONS_UNI_DRC* pInst = NULL;
1743
1744
1.87k
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1745
1.50k
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1746
1.50k
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1747
1748
1.50k
    pInst = pCandidate->pInst;
1749
1750
1.50k
    effects = pInst->drcSetEffect;
1751
1.50k
    effects &= 0xffff ^ (EB_GENERAL_COMPR);
1752
1.50k
    numEffects = _crossSum(effects);
1753
1754
1.50k
    if (numEffects < minNumEffects) {
1755
532
      minNumEffects = numEffects;
1756
532
    }
1757
1.50k
  }
1758
1759
  /* add all with minimum number of effects */
1760
1.87k
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1761
1.50k
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1762
1.50k
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1763
1764
1.50k
    pInst = pCandidate->pInst;
1765
1766
1.50k
    effects = pInst->drcSetEffect;
1767
1.50k
    effects &= 0xffff ^ (EB_GENERAL_COMPR);
1768
1.50k
    numEffects = _crossSum(effects);
1769
1770
1.50k
    if (numEffects == minNumEffects) {
1771
1.24k
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1772
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1773
1.24k
    }
1774
1.50k
  }
1775
1776
376
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1777
376
}
1778
1779
static DRCDEC_SELECTION_PROCESS_RETURN _selectSmallestTargetLoudnessValueUpper(
1780
    DRCDEC_SELECTION* pCandidatesPotential,
1781
34
    DRCDEC_SELECTION* pCandidatesSelected) {
1782
34
  int i;
1783
34
  SCHAR minVal = 0x7F;
1784
34
  SCHAR val = 0;
1785
34
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1786
1787
171
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1788
137
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1789
137
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1790
1791
137
    val = pCandidate->pInst->drcSetTargetLoudnessValueUpper;
1792
1793
137
    if (val < minVal) {
1794
50
      minVal = val;
1795
50
    }
1796
137
  }
1797
1798
  /* add all with same smallest drcSetTargetLoudnessValueUpper */
1799
171
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1800
137
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1801
137
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1802
1803
137
    val = pCandidate->pInst->drcSetTargetLoudnessValueUpper;
1804
1805
137
    if (val == minVal) {
1806
78
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1807
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1808
78
    }
1809
137
  }
1810
1811
34
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1812
34
}
1813
1814
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_targetLoudness(
1815
    FIXP_DBL targetLoudness, DRCDEC_SELECTION* pCandidatesPotential,
1816
272
    DRCDEC_SELECTION* pCandidatesSelected) {
1817
272
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1818
272
  int i;
1819
272
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1820
1821
1.41k
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1822
1.14k
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1823
1.14k
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1824
1825
1.14k
    if (pCandidate->selectionFlag == 0) {
1826
1.07k
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1827
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1828
1.07k
    }
1829
1.14k
  }
1830
1831
272
  if (_drcdec_selection_getNumber(pCandidatesSelected) == 0) {
1832
15
    retVal = _selectSmallestTargetLoudnessValueUpper(pCandidatesPotential,
1833
15
                                                     pCandidatesSelected);
1834
15
    if (retVal) return (retVal);
1835
15
  }
1836
1837
272
  if (_drcdec_selection_getNumber(pCandidatesSelected) > 1) {
1838
262
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc = NULL;
1839
1840
262
    _swapSelectionAndClear(&pCandidatesPotential, &pCandidatesSelected);
1841
1842
1.36k
    for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1843
1.10k
      pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1844
1.10k
      if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1845
1846
1.10k
      pDrcInstructionUniDrc = pCandidate->pInst;
1847
1848
1.10k
      if (_targetLoudnessInRange(pDrcInstructionUniDrc, targetLoudness)) {
1849
77
        if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1850
0
          return DRCDEC_SELECTION_PROCESS_NOT_OK;
1851
77
      }
1852
1.10k
    }
1853
1854
262
    if (_drcdec_selection_getNumber(pCandidatesSelected) > 1) {
1855
19
      _swapSelectionAndClear(&pCandidatesPotential, &pCandidatesSelected);
1856
1857
19
      retVal = _selectSmallestTargetLoudnessValueUpper(pCandidatesPotential,
1858
19
                                                       pCandidatesSelected);
1859
19
      if (retVal) return (retVal);
1860
19
    }
1861
262
  }
1862
1863
272
  return retVal;
1864
272
}
1865
1866
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_peakValueLargest(
1867
    DRCDEC_SELECTION* pCandidatesPotential,
1868
250
    DRCDEC_SELECTION* pCandidatesSelected) {
1869
250
  int i;
1870
250
  FIXP_DBL largestPeakLevel = MINVAL_DBL;
1871
250
  FIXP_DBL peakLevel = 0;
1872
250
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1873
1874
1.30k
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1875
1.05k
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1876
1.05k
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1877
1878
1.05k
    peakLevel = pCandidate->outputPeakLevel;
1879
1880
1.05k
    if (peakLevel > largestPeakLevel) {
1881
259
      largestPeakLevel = peakLevel;
1882
259
    }
1883
1.05k
  }
1884
1885
  /* add all with same largest peak level */
1886
1.30k
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1887
1.05k
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1888
1.05k
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1889
1890
1.05k
    peakLevel = pCandidate->outputPeakLevel;
1891
1892
1.05k
    if (peakLevel == largestPeakLevel) {
1893
1.02k
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1894
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1895
1.02k
    }
1896
1.05k
  }
1897
1898
250
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1899
250
}
1900
1901
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_drcSetId(
1902
    DRCDEC_SELECTION* pCandidatesPotential,
1903
238
    DRCDEC_SELECTION* pCandidatesSelected) {
1904
238
  int i;
1905
238
  int largestId = -1000;
1906
238
  int id = 0;
1907
238
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1908
238
  DRCDEC_SELECTION_DATA* pCandidateSelected = NULL;
1909
1910
1.25k
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1911
1.01k
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1912
1.01k
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1913
1914
1.01k
    id = pCandidate->pInst->drcSetId;
1915
1916
1.01k
    if (id > largestId) {
1917
263
      largestId = id;
1918
263
      pCandidateSelected = pCandidate;
1919
263
    }
1920
1.01k
  }
1921
1922
238
  if (pCandidateSelected != NULL) {
1923
238
    if (_drcdec_selection_add(pCandidatesSelected, pCandidateSelected) == NULL)
1924
0
      return DRCDEC_SELECTION_PROCESS_NOT_OK;
1925
238
  } else {
1926
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
1927
0
  }
1928
1929
238
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1930
238
}
1931
1932
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection(
1933
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
1934
    DRCDEC_SELECTION** ppCandidatesPotential,
1935
2.65k
    DRCDEC_SELECTION** ppCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) {
1936
2.65k
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1937
1938
2.65k
  if (_drcdec_selection_getNumber(*ppCandidatesPotential) == 0) {
1939
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
1940
2.65k
  } else if (_drcdec_selection_getNumber(*ppCandidatesPotential) == 1) {
1941
2.18k
    _swapSelection(ppCandidatesPotential, ppCandidatesSelected);
1942
    /* finished */
1943
2.18k
  } else /* > 1 */
1944
474
  {
1945
474
    retVal = _drcSetFinalSelection_peakValue0(*ppCandidatesPotential,
1946
474
                                              *ppCandidatesSelected);
1947
474
    if (retVal) return (retVal);
1948
1949
474
    if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) {
1950
376
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1951
376
      retVal = _drcSetFinalSelection_downmixId(
1952
376
          hSelProcInput, ppCandidatesPotential, ppCandidatesSelected);
1953
376
      if (retVal) return (retVal);
1954
376
    }
1955
1956
474
    if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) {
1957
376
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1958
376
      retVal = _drcSetFinalSelection_effectTypes(*ppCandidatesPotential,
1959
376
                                                 *ppCandidatesSelected);
1960
376
      if (retVal) return (retVal);
1961
376
    }
1962
1963
474
    if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) {
1964
272
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1965
272
      retVal = _drcSetFinalSelection_targetLoudness(
1966
272
          hSelProcInput->targetLoudness, *ppCandidatesPotential,
1967
272
          *ppCandidatesSelected);
1968
272
      if (retVal) return (retVal);
1969
272
    }
1970
1971
474
    if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) {
1972
250
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1973
250
      retVal = _drcSetFinalSelection_peakValueLargest(*ppCandidatesPotential,
1974
250
                                                      *ppCandidatesSelected);
1975
250
      if (retVal) return (retVal);
1976
250
    }
1977
1978
474
    if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) {
1979
238
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1980
238
      retVal = _drcSetFinalSelection_drcSetId(*ppCandidatesPotential,
1981
238
                                              *ppCandidatesSelected);
1982
238
      if (retVal) return (retVal);
1983
238
    }
1984
474
  }
1985
1986
2.65k
  if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) {
1987
84
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
1988
84
  }
1989
1990
2.57k
  return retVal;
1991
2.65k
}
1992
1993
static DRCDEC_SELECTION_PROCESS_RETURN _generateVirtualDrcSets(
1994
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
1995
2.68k
    SEL_PROC_CODEC_MODE codecMode) {
1996
2.68k
  int i;
1997
2.68k
  int nMixes = hUniDrcConfig->downmixInstructionsCount + 1;
1998
2.68k
  int index = hUniDrcConfig->drcInstructionsUniDrcCount;
1999
2.68k
  int indexVirtual = -1;
2000
2.68k
  DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction =
2001
2.68k
      &(hUniDrcConfig->drcInstructionsUniDrc[index]);
2002
2003
2.68k
  if (codecMode == SEL_PROC_MPEG_H_3DA) {
2004
0
    nMixes = 1;
2005
0
  }
2006
2007
2.68k
  if ((index + nMixes) > (12 + 1 + 6)) {
2008
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
2009
0
  }
2010
2011
2.68k
  FDKmemset(pDrcInstruction, 0, sizeof(DRC_INSTRUCTIONS_UNI_DRC));
2012
2013
2.68k
  pDrcInstruction->drcSetId = indexVirtual;
2014
2.68k
  index++;
2015
2.68k
  indexVirtual--;
2016
2.68k
  pDrcInstruction->downmixIdCount = 1;
2017
2018
2.68k
  if ((codecMode == SEL_PROC_MPEG_H_3DA) &&
2019
2.68k
      (hSelProcInput->numDownmixIdRequests)) {
2020
0
    pDrcInstruction->downmixId[0] = hSelProcInput->downmixIdRequested[0];
2021
2.68k
  } else {
2022
2.68k
    pDrcInstruction->downmixId[0] = DOWNMIX_ID_BASE_LAYOUT;
2023
2.68k
  }
2024
2025
3.89k
  for (i = 1; i < nMixes; i++) {
2026
1.20k
    pDrcInstruction = &(hUniDrcConfig->drcInstructionsUniDrc[index]);
2027
1.20k
    FDKmemset(pDrcInstruction, 0, sizeof(DRC_INSTRUCTIONS_UNI_DRC));
2028
1.20k
    pDrcInstruction->drcSetId = indexVirtual;
2029
1.20k
    pDrcInstruction->downmixId[0] =
2030
1.20k
        hUniDrcConfig->downmixInstructions[i - 1].downmixId;
2031
1.20k
    pDrcInstruction->downmixIdCount = 1;
2032
1.20k
    index++;
2033
1.20k
    indexVirtual--;
2034
1.20k
  }
2035
2036
2.68k
  hUniDrcConfig->drcInstructionsCountInclVirtual =
2037
2.68k
      hUniDrcConfig->drcInstructionsUniDrcCount + nMixes;
2038
2039
2.68k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2040
2.68k
}
2041
2042
static DRCDEC_SELECTION_PROCESS_RETURN _generateOutputInfo(
2043
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_SEL_PROC_OUTPUT hSelProcOutput,
2044
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
2045
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
2046
2.57k
    DRCDEC_SELECTION_DATA* pSelectionData, SEL_PROC_CODEC_MODE codecMode) {
2047
2.57k
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
2048
2049
2.57k
  int i, j;
2050
2.57k
  int hasDependend = 0;
2051
2.57k
  int hasFading = 0;
2052
2.57k
  int hasDucking = 0;
2053
2.57k
  int selectedDrcSetIds;
2054
2.57k
  int selectedDownmixIds;
2055
2.57k
  FIXP_DBL mixingLevel = 0;
2056
2.57k
  int albumMode = hSelProcInput->albumMode;
2057
2.57k
  UCHAR* pDownmixIdRequested = hSelProcInput->downmixIdRequested;
2058
2.57k
  FIXP_SGL boost = hSelProcInput->boost;
2059
2.57k
  FIXP_SGL compress = hSelProcInput->compress;
2060
2061
2.57k
  hSelProcOutput->numSelectedDrcSets = 1;
2062
2.57k
  hSelProcOutput->selectedDrcSetIds[0] = pSelectionData->pInst->drcSetId;
2063
2.57k
  hSelProcOutput->selectedDownmixIds[0] =
2064
2.57k
      pSelectionData->pInst->drcApplyToDownmix == 1
2065
2.57k
          ? pSelectionData->pInst->downmixId[0]
2066
2.57k
          : 0;
2067
2.57k
  hSelProcOutput->loudnessNormalizationGainDb =
2068
2.57k
      pSelectionData->loudnessNormalizationGainDbAdjusted +
2069
2.57k
      hSelProcInput->loudnessNormalizationGainModificationDb;
2070
2.57k
  hSelProcOutput->outputPeakLevelDb = pSelectionData->outputPeakLevel;
2071
2.57k
  hSelProcOutput->outputLoudness = pSelectionData->outputLoudness;
2072
2073
2.57k
  hSelProcOutput->boost = boost;
2074
2.57k
  hSelProcOutput->compress = compress;
2075
2.57k
  hSelProcOutput->baseChannelCount =
2076
2.57k
      hUniDrcConfig->channelLayout.baseChannelCount;
2077
2.57k
  hSelProcOutput->targetChannelCount =
2078
2.57k
      hUniDrcConfig->channelLayout.baseChannelCount;
2079
2.57k
  hSelProcOutput->activeDownmixId =
2080
2.57k
      pDownmixIdRequested[pSelectionData->downmixIdRequestIndex];
2081
2082
2.57k
  _getMixingLevel(hLoudnessInfoSet, *pDownmixIdRequested,
2083
2.57k
                  hSelProcOutput->selectedDrcSetIds[0], albumMode,
2084
2.57k
                  &mixingLevel);
2085
2.57k
  hSelProcOutput->mixingLevel = mixingLevel;
2086
2087
  /*dependent*/
2088
2.57k
  if (pSelectionData->pInst->dependsOnDrcSetPresent) {
2089
88
    int dependsOnDrcSetID = pSelectionData->pInst->dependsOnDrcSet;
2090
2091
494
    for (i = 0; i < hUniDrcConfig->drcInstructionsCountInclVirtual; i++) {
2092
445
      DRC_INSTRUCTIONS_UNI_DRC* pInst =
2093
445
          &(hUniDrcConfig->drcInstructionsUniDrc[i]);
2094
445
      if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
2095
2096
340
      if (pInst->drcSetId == dependsOnDrcSetID) {
2097
39
        hSelProcOutput->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] =
2098
39
            hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId;
2099
39
        hSelProcOutput->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] =
2100
39
            hUniDrcConfig->drcInstructionsUniDrc[i].drcApplyToDownmix == 1
2101
39
                ? hUniDrcConfig->drcInstructionsUniDrc[i].downmixId[0]
2102
39
                : 0;
2103
39
        hSelProcOutput->numSelectedDrcSets++;
2104
39
        hasDependend = 1;
2105
39
        break;
2106
39
      }
2107
340
    }
2108
88
  }
2109
2110
  /* fading */
2111
2.57k
  if (hSelProcInput->albumMode == 0) {
2112
5.69k
    for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
2113
3.29k
      DRC_INSTRUCTIONS_UNI_DRC* pInst =
2114
3.29k
          &(hUniDrcConfig->drcInstructionsUniDrc[i]);
2115
3.29k
      if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
2116
2117
1.09k
      if (pInst->drcSetEffect & EB_FADE) {
2118
309
        if (pInst->downmixId[0] == DOWNMIX_ID_ANY_DOWNMIX) {
2119
143
          hSelProcOutput->numSelectedDrcSets = hasDependend + 1;
2120
143
          hSelProcOutput
2121
143
              ->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] =
2122
143
              hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId;
2123
143
          hSelProcOutput
2124
143
              ->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] =
2125
143
              hUniDrcConfig->drcInstructionsUniDrc[i].drcApplyToDownmix == 1
2126
143
                  ? hUniDrcConfig->drcInstructionsUniDrc[i].downmixId[0]
2127
143
                  : 0;
2128
143
          hSelProcOutput->numSelectedDrcSets++;
2129
143
          hasFading = 1;
2130
2131
166
        } else {
2132
166
          retVal = DRCDEC_SELECTION_PROCESS_NOT_OK;
2133
166
          if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2134
166
        }
2135
309
      }
2136
1.09k
    }
2137
2.57k
  }
2138
2139
  /* ducking */
2140
5.36k
  for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
2141
2.96k
    DRC_INSTRUCTIONS_UNI_DRC* pInst =
2142
2.96k
        &(hUniDrcConfig->drcInstructionsUniDrc[i]);
2143
2.96k
    if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
2144
2145
786
    if (pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) {
2146
1.01k
      for (j = 0; j < pInst->downmixIdCount; j++) {
2147
629
        if (pInst->downmixId[j] == hSelProcOutput->activeDownmixId) {
2148
279
          hSelProcOutput->numSelectedDrcSets =
2149
279
              hasDependend + 1; /* ducking overrides fading */
2150
2151
279
          hSelProcOutput
2152
279
              ->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] =
2153
279
              hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId;
2154
          /* force ducking DRC set to be processed on base layout */
2155
279
          hSelProcOutput
2156
279
              ->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] = 0;
2157
279
          hSelProcOutput->numSelectedDrcSets++;
2158
279
          hasDucking = 1;
2159
279
        }
2160
629
      }
2161
381
    }
2162
786
  }
2163
2164
  /* repeat for DOWNMIX_ID_BASE_LAYOUT if no ducking found*/
2165
2166
2.40k
  if (!hasDucking) {
2167
4.65k
    for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
2168
2.37k
      DRC_INSTRUCTIONS_UNI_DRC* pInst =
2169
2.37k
          &(hUniDrcConfig->drcInstructionsUniDrc[i]);
2170
2.37k
      if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
2171
2172
520
      if (pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) {
2173
468
        for (j = 0; j < pInst->downmixIdCount; j++) {
2174
309
          if (pInst->downmixId[j] == DOWNMIX_ID_BASE_LAYOUT) {
2175
0
            hSelProcOutput->numSelectedDrcSets = hasDependend + hasFading + 1;
2176
0
            hSelProcOutput
2177
0
                ->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] =
2178
0
                hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId;
2179
            /* force ducking DRC set to be processed on base layout */
2180
0
            hSelProcOutput
2181
0
                ->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] = 0;
2182
0
            hSelProcOutput->numSelectedDrcSets++;
2183
0
          }
2184
309
        }
2185
159
      }
2186
520
    }
2187
2.28k
  }
2188
2189
2.40k
  if (hSelProcOutput->numSelectedDrcSets > 3) {
2190
    /* maximum permitted number of applied DRC sets is 3, see section 6.3.5 of
2191
     * ISO/IEC 23003-4 */
2192
0
    hSelProcOutput->numSelectedDrcSets = 0;
2193
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
2194
0
  }
2195
2196
  /* sorting: Ducking/Fading -> Dependent -> Selected */
2197
2.40k
  if (hSelProcOutput->numSelectedDrcSets == 3) {
2198
9
    selectedDrcSetIds = hSelProcOutput->selectedDrcSetIds[0];
2199
9
    selectedDownmixIds = hSelProcOutput->selectedDownmixIds[0];
2200
9
    hSelProcOutput->selectedDrcSetIds[0] = hSelProcOutput->selectedDrcSetIds[2];
2201
9
    hSelProcOutput->selectedDownmixIds[0] =
2202
9
        hSelProcOutput->selectedDownmixIds[2];
2203
9
    hSelProcOutput->selectedDrcSetIds[2] = selectedDrcSetIds;
2204
9
    hSelProcOutput->selectedDownmixIds[2] = selectedDownmixIds;
2205
2.39k
  } else if (hSelProcOutput->numSelectedDrcSets == 2) {
2206
194
    selectedDrcSetIds = hSelProcOutput->selectedDrcSetIds[0];
2207
194
    selectedDownmixIds = hSelProcOutput->selectedDownmixIds[0];
2208
194
    hSelProcOutput->selectedDrcSetIds[0] = hSelProcOutput->selectedDrcSetIds[1];
2209
194
    hSelProcOutput->selectedDownmixIds[0] =
2210
194
        hSelProcOutput->selectedDownmixIds[1];
2211
194
    hSelProcOutput->selectedDrcSetIds[1] = selectedDrcSetIds;
2212
194
    hSelProcOutput->selectedDownmixIds[1] = selectedDownmixIds;
2213
194
  }
2214
2215
2.40k
  return retVal;
2216
2.40k
}
2217
2218
static DRCDEC_SELECTION_PROCESS_RETURN _selectDownmixMatrix(
2219
    HANDLE_SEL_PROC_OUTPUT hSelProcOutput,
2220
2.40k
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig) {
2221
2.40k
  int i;
2222
2.40k
  hSelProcOutput->baseChannelCount =
2223
2.40k
      hUniDrcConfig->channelLayout.baseChannelCount;
2224
2.40k
  hSelProcOutput->targetChannelCount =
2225
2.40k
      hUniDrcConfig->channelLayout.baseChannelCount;
2226
2.40k
  hSelProcOutput->targetLayout = -1;
2227
2.40k
  hSelProcOutput->downmixMatrixPresent = 0;
2228
2229
2.40k
  if (hSelProcOutput->activeDownmixId != 0) {
2230
0
    for (i = 0; i < hUniDrcConfig->downmixInstructionsCount; i++) {
2231
0
      DOWNMIX_INSTRUCTIONS* pDown = &(hUniDrcConfig->downmixInstructions[i]);
2232
0
      if (pDown->targetChannelCount > 8) {
2233
0
        continue;
2234
0
      }
2235
2236
0
      if (hSelProcOutput->activeDownmixId == pDown->downmixId) {
2237
0
        hSelProcOutput->targetChannelCount = pDown->targetChannelCount;
2238
0
        hSelProcOutput->targetLayout = pDown->targetLayout;
2239
2240
0
        if (pDown->downmixCoefficientsPresent) {
2241
0
          int j, k;
2242
0
          FIXP_DBL downmixOffset = getDownmixOffset(
2243
0
              pDown, hSelProcOutput->baseChannelCount); /* e = 1 */
2244
2245
0
          for (j = 0; j < hSelProcOutput->baseChannelCount; j++) {
2246
0
            for (k = 0; k < hSelProcOutput->targetChannelCount; k++) {
2247
0
              hSelProcOutput->downmixMatrix[j][k] =
2248
0
                  fMultDiv2(
2249
0
                      downmixOffset,
2250
0
                      pDown->downmixCoefficient[j + k * hSelProcOutput
2251
0
                                                            ->baseChannelCount])
2252
0
                  << 2;
2253
0
            }
2254
0
          }
2255
2256
0
          hSelProcOutput->downmixMatrixPresent = 1;
2257
0
        }
2258
0
        break;
2259
0
      }
2260
0
    }
2261
0
  }
2262
2263
2.40k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2264
2.40k
}
2265
2266
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetPreSelection(
2267
    SEL_PROC_INPUT* hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
2268
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
2269
    DRCDEC_SELECTION** ppCandidatesPotential,
2270
2.68k
    DRCDEC_SELECTION** ppCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) {
2271
2.68k
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
2272
2.68k
  int i, j;
2273
2274
5.35k
  for (i = 0; i < hSelProcInput->numDownmixIdRequests; i++) {
2275
10.6k
    for (j = 0; j < hUniDrcConfig->drcInstructionsCountInclVirtual; j++) {
2276
7.96k
      DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction =
2277
7.96k
          &(hUniDrcConfig->drcInstructionsUniDrc[j]);
2278
      /* check if ID is unique */
2279
7.96k
      if (selectDrcInstructions(hUniDrcConfig, pDrcInstruction->drcSetId) !=
2280
7.96k
          pDrcInstruction)
2281
1.80k
        continue;
2282
2283
6.16k
      retVal = _drcSetPreSelectionSingleInstruction(
2284
6.16k
          hSelProcInput, i, hUniDrcConfig, hLoudnessInfoSet, pDrcInstruction,
2285
6.16k
          *ppCandidatesPotential, *ppCandidatesSelected, codecMode);
2286
6.16k
      if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2287
6.16k
    }
2288
2.68k
  }
2289
2290
2.67k
  retVal = _preSelectionRequirement9(hSelProcInput, *ppCandidatesPotential,
2291
2.67k
                                     *ppCandidatesSelected);
2292
2.67k
  if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2293
2294
2.67k
  if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) {
2295
207
    retVal = _drcSetSelectionAddCandidates(
2296
207
        hSelProcInput, *ppCandidatesPotential, *ppCandidatesSelected);
2297
207
    if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2298
207
  }
2299
2300
2.67k
  return retVal;
2301
2.67k
}
2302
2303
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetRequestSelection(
2304
    SEL_PROC_INPUT* hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
2305
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
2306
    DRCDEC_SELECTION** ppCandidatesPotential,
2307
2.67k
    DRCDEC_SELECTION** ppCandidatesSelected) {
2308
2.67k
  DRCDEC_SELECTION_PROCESS_RETURN retVal;
2309
2.67k
  int i;
2310
2311
2.67k
  if (_drcdec_selection_getNumber(*ppCandidatesPotential) == 0) {
2312
0
    retVal = DRCDEC_SELECTION_PROCESS_NOT_OK;
2313
0
    if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2314
0
  }
2315
2316
2.67k
  if (hSelProcInput->dynamicRangeControlOn) {
2317
2.67k
    if (hSelProcInput->numDrcFeatureRequests == 0) {
2318
2.67k
      retVal = _selectDrcSetEffectNone(hUniDrcConfig, *ppCandidatesPotential,
2319
2.67k
                                       *ppCandidatesSelected);
2320
2.67k
      if (retVal) return (retVal);
2321
2322
2.67k
      if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) {
2323
160
        DRC_FEATURE_REQUEST fallbackRequest;
2324
160
        fallbackRequest.drcEffectType.numRequests = 5;
2325
160
        fallbackRequest.drcEffectType.numRequestsDesired = 5;
2326
160
        fallbackRequest.drcEffectType.request[0] = DETR_GENERAL_COMPR;
2327
160
        fallbackRequest.drcEffectType.request[1] = DETR_NIGHT;
2328
160
        fallbackRequest.drcEffectType.request[2] = DETR_NOISY;
2329
160
        fallbackRequest.drcEffectType.request[3] = DETR_LIMITED;
2330
160
        fallbackRequest.drcEffectType.request[4] = DETR_LOWLEVEL;
2331
2332
160
        retVal = _selectEffectTypeFeature(hUniDrcConfig, fallbackRequest,
2333
160
                                          ppCandidatesPotential,
2334
160
                                          ppCandidatesSelected);
2335
160
        if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2336
160
      }
2337
2338
2.65k
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
2339
2.65k
    } else {
2340
0
      for (i = 0; i < hSelProcInput->numDrcFeatureRequests; i++) {
2341
0
        if (hSelProcInput->drcFeatureRequestType[i] == DFRT_EFFECT_TYPE) {
2342
0
          retVal = _selectEffectTypeFeature(
2343
0
              hUniDrcConfig, hSelProcInput->drcFeatureRequest[i],
2344
0
              ppCandidatesPotential, ppCandidatesSelected);
2345
2346
0
          _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
2347
0
          if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2348
0
        }
2349
2350
0
        else if (hSelProcInput->drcFeatureRequestType[i] ==
2351
0
                 DFRT_DYNAMIC_RANGE) {
2352
0
          retVal = _selectDynamicRange(
2353
0
              hUniDrcConfig, hLoudnessInfoSet,
2354
0
              hSelProcInput->drcFeatureRequest[i],
2355
0
              hSelProcInput->downmixIdRequested, hSelProcInput->albumMode,
2356
0
              *ppCandidatesPotential, *ppCandidatesSelected);
2357
2358
0
          if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 0) {
2359
0
            _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
2360
0
          }
2361
0
          if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2362
0
        } else if (hSelProcInput->drcFeatureRequestType[i] ==
2363
0
                   DFRT_DRC_CHARACTERISTIC) {
2364
0
          retVal = _selectDrcCharacteristic(
2365
0
              hUniDrcConfig,
2366
0
              hSelProcInput->drcFeatureRequest[i].drcCharacteristic,
2367
0
              ppCandidatesPotential, ppCandidatesSelected);
2368
2369
0
          if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 0) {
2370
0
            _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
2371
0
          }
2372
0
          if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2373
0
        }
2374
0
      }
2375
0
    }
2376
2.67k
  }
2377
2378
2.65k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2379
2.67k
}
2380
2381
/*******************************************/
2382
static DRCDEC_SELECTION_PROCESS_RETURN _dynamicRangeMeasurement(
2383
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, DRC_INSTRUCTIONS_UNI_DRC* pInst,
2384
    UCHAR downmixIdRequested,
2385
    DYN_RANGE_MEASUREMENT_REQUEST_TYPE dynamicRangeMeasurementType,
2386
0
    int albumMode, int* pPeakToAveragePresent, FIXP_DBL* pPeakToAverage) {
2387
0
  int i;
2388
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
2389
0
  int drcSetId = fMax(0, pInst->drcSetId);
2390
2391
0
  *pPeakToAveragePresent = 0;
2392
2393
0
  if (albumMode) {
2394
0
    for (i = 0; i < hLoudnessInfoSet->loudnessInfoAlbumCount; i++) {
2395
0
      LOUDNESS_INFO* pLoudnessInfo = &(hLoudnessInfoSet->loudnessInfoAlbum[i]);
2396
2397
0
      if (drcSetId == pLoudnessInfo->drcSetId) {
2398
0
        if (downmixIdRequested == pLoudnessInfo->downmixId) {
2399
0
          retVal = _extractLoudnessPeakToAverageValue(
2400
0
              pLoudnessInfo, dynamicRangeMeasurementType, pPeakToAveragePresent,
2401
0
              pPeakToAverage);
2402
0
          if (retVal) return (retVal);
2403
0
        }
2404
0
      }
2405
0
    }
2406
0
  }
2407
2408
0
  if (*pPeakToAveragePresent == 0) {
2409
0
    for (i = 0; i < hLoudnessInfoSet->loudnessInfoCount; i++) {
2410
0
      LOUDNESS_INFO* pLoudnessInfo = &(hLoudnessInfoSet->loudnessInfo[i]);
2411
2412
0
      if (drcSetId == pLoudnessInfo->drcSetId) {
2413
0
        if (downmixIdRequested == pLoudnessInfo->downmixId) {
2414
0
          retVal = _extractLoudnessPeakToAverageValue(
2415
0
              pLoudnessInfo, dynamicRangeMeasurementType, pPeakToAveragePresent,
2416
0
              pPeakToAverage);
2417
0
          if (retVal) return (retVal);
2418
0
        }
2419
0
      }
2420
0
    }
2421
0
  }
2422
2423
0
  return retVal;
2424
0
}
2425
/*******************************************/
2426
2427
static DRCDEC_SELECTION_DATA* _drcdec_selection_addNew(
2428
5.20k
    DRCDEC_SELECTION* pSelection) {
2429
5.20k
  if (pSelection->numData < (12 + 1 + 6)) {
2430
5.20k
    DRCDEC_SELECTION_DATA* pData = &(pSelection->data[pSelection->numData]);
2431
5.20k
    FDKmemset(pData, 0, sizeof(DRCDEC_SELECTION_DATA));
2432
5.20k
    pSelection->numData++;
2433
2434
5.20k
    return pData;
2435
5.20k
  } else {
2436
0
    return NULL;
2437
0
  }
2438
5.20k
}
2439
2440
static DRCDEC_SELECTION_DATA* _drcdec_selection_add(
2441
14.7k
    DRCDEC_SELECTION* pSelection, DRCDEC_SELECTION_DATA* pDataIn) {
2442
14.7k
  if (pSelection->numData < (12 + 1 + 6)) {
2443
14.7k
    DRCDEC_SELECTION_DATA* pData = &(pSelection->data[pSelection->numData]);
2444
14.7k
    FDKmemcpy(pData, pDataIn, sizeof(DRCDEC_SELECTION_DATA));
2445
14.7k
    pSelection->numData++;
2446
14.7k
    return pData;
2447
14.7k
  } else {
2448
0
    return NULL;
2449
0
  }
2450
14.7k
}
2451
2452
7.53k
static int _drcdec_selection_clear(DRCDEC_SELECTION* pSelection) {
2453
7.53k
  return pSelection->numData = 0;
2454
7.53k
}
2455
2456
55.8k
static int _drcdec_selection_getNumber(DRCDEC_SELECTION* pSelection) {
2457
55.8k
  return pSelection->numData;
2458
55.8k
}
2459
2460
5.37k
static int _drcdec_selection_setNumber(DRCDEC_SELECTION* pSelection, int num) {
2461
5.37k
  if (num >= 0 && num < pSelection->numData) {
2462
0
    return pSelection->numData = num;
2463
5.37k
  } else {
2464
5.37k
    return pSelection->numData;
2465
5.37k
  }
2466
5.37k
}
2467
2468
static DRCDEC_SELECTION_DATA* _drcdec_selection_getAt(
2469
26.0k
    DRCDEC_SELECTION* pSelection, int at) {
2470
26.0k
  if (at >= 0 && at < (12 + 1 + 6)) {
2471
26.0k
    return &(pSelection->data[at]);
2472
26.0k
  } else {
2473
0
    return NULL;
2474
0
  }
2475
26.0k
}
2476
2477
static int _swapSelectionAndClear(DRCDEC_SELECTION** ppCandidatesPotential,
2478
7.53k
                                  DRCDEC_SELECTION** ppCandidatesSelected) {
2479
7.53k
  DRCDEC_SELECTION* pTmp = *ppCandidatesPotential;
2480
7.53k
  *ppCandidatesPotential = *ppCandidatesSelected;
2481
7.53k
  *ppCandidatesSelected = pTmp;
2482
7.53k
  _drcdec_selection_clear(*ppCandidatesSelected);
2483
7.53k
  return 0;
2484
7.53k
}
2485
2486
static int _swapSelection(DRCDEC_SELECTION** ppCandidatesPotential,
2487
2.70k
                          DRCDEC_SELECTION** ppCandidatesSelected) {
2488
2.70k
  DRCDEC_SELECTION* pTmp = *ppCandidatesPotential;
2489
2.70k
  *ppCandidatesPotential = *ppCandidatesSelected;
2490
2.70k
  *ppCandidatesSelected = pTmp;
2491
2.70k
  return 0;
2492
2.70k
}
2493
2494
/*******************************************/
2495
2496
static LOUDNESS_INFO* _getLoudnessInfoStructure(
2497
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int drcSetId, int downmixId,
2498
42.4k
    int albumMode) {
2499
42.4k
  int i, j;
2500
42.4k
  int count;
2501
2502
42.4k
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2503
2504
42.4k
  if (albumMode) {
2505
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
2506
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
2507
42.4k
  } else {
2508
42.4k
    count = hLoudnessInfoSet->loudnessInfoCount;
2509
42.4k
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
2510
42.4k
  }
2511
2512
99.1k
  for (i = 0; i < count; i++) {
2513
57.6k
    if ((pLoudnessInfo[i].drcSetId == drcSetId) &&
2514
57.6k
        (pLoudnessInfo[i].downmixId == downmixId)) {
2515
14.5k
      for (j = 0; j < pLoudnessInfo[i].measurementCount; j++) {
2516
5.24k
        if ((pLoudnessInfo[i].loudnessMeasurement[j].methodDefinition == 1) ||
2517
5.24k
            (pLoudnessInfo[i].loudnessMeasurement[j].methodDefinition == 2)) {
2518
837
          return &pLoudnessInfo[i];
2519
837
        }
2520
5.24k
      }
2521
10.1k
    }
2522
57.6k
  }
2523
2524
41.5k
  return NULL;
2525
42.4k
}
2526
2527
static LOUDNESS_INFO* _getApplicableLoudnessInfoStructure(
2528
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int drcSetId,
2529
5.27k
    int downmixIdRequested, int albumMode) {
2530
5.27k
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2531
2532
  /* default value */
2533
5.27k
  pLoudnessInfo = _getLoudnessInfoStructure(hLoudnessInfoSet, drcSetId,
2534
5.27k
                                            downmixIdRequested, albumMode);
2535
2536
  /* fallback values */
2537
5.27k
  if (pLoudnessInfo == NULL) {
2538
5.00k
    pLoudnessInfo =
2539
5.00k
        _getLoudnessInfoStructure(hLoudnessInfoSet, drcSetId, 0x7F, albumMode);
2540
5.00k
  }
2541
2542
5.27k
  if (pLoudnessInfo == NULL) {
2543
4.91k
    pLoudnessInfo = _getLoudnessInfoStructure(hLoudnessInfoSet, 0x3F,
2544
4.91k
                                              downmixIdRequested, albumMode);
2545
4.91k
  }
2546
2547
5.27k
  if (pLoudnessInfo == NULL) {
2548
4.77k
    pLoudnessInfo = _getLoudnessInfoStructure(hLoudnessInfoSet, 0,
2549
4.77k
                                              downmixIdRequested, albumMode);
2550
4.77k
  }
2551
2552
5.27k
  if (pLoudnessInfo == NULL) {
2553
4.62k
    pLoudnessInfo =
2554
4.62k
        _getLoudnessInfoStructure(hLoudnessInfoSet, 0x3F, 0x7F, albumMode);
2555
4.62k
  }
2556
2557
5.27k
  if (pLoudnessInfo == NULL) {
2558
4.49k
    pLoudnessInfo =
2559
4.49k
        _getLoudnessInfoStructure(hLoudnessInfoSet, 0, 0x7F, albumMode);
2560
4.49k
  }
2561
2562
5.27k
  if (pLoudnessInfo == NULL) {
2563
4.44k
    pLoudnessInfo =
2564
4.44k
        _getLoudnessInfoStructure(hLoudnessInfoSet, drcSetId, 0, albumMode);
2565
4.44k
  }
2566
2567
5.27k
  if (pLoudnessInfo == NULL) {
2568
4.44k
    pLoudnessInfo =
2569
4.44k
        _getLoudnessInfoStructure(hLoudnessInfoSet, 0x3F, 0, albumMode);
2570
4.44k
  }
2571
2572
5.27k
  if (pLoudnessInfo == NULL) {
2573
4.44k
    pLoudnessInfo =
2574
4.44k
        _getLoudnessInfoStructure(hLoudnessInfoSet, 0, 0, albumMode);
2575
4.44k
  }
2576
2577
5.27k
  return pLoudnessInfo;
2578
5.27k
}
2579
2580
/*******************************************/
2581
2582
typedef struct {
2583
  FIXP_DBL value;
2584
  int order;
2585
} VALUE_ORDER;
2586
2587
5.27k
void _initValueOrder(VALUE_ORDER* pValue) {
2588
5.27k
  pValue->value = (FIXP_DBL)0;
2589
5.27k
  pValue->order = -1;
2590
5.27k
}
2591
2592
enum {
2593
  MS_BONUS0 = 0,
2594
  MS_BONUS1770,
2595
  MS_BONUSUSER,
2596
  MS_BONUSEXPERT,
2597
  MS_RESA,
2598
  MS_RESB,
2599
  MS_RESC,
2600
  MS_RESD,
2601
  MS_RESE,
2602
  MS_PROGRAMLOUDNESS,
2603
  MS_PEAKLOUDNESS
2604
};
2605
2606
static DRCDEC_SELECTION_PROCESS_RETURN _getMethodValue(
2607
    VALUE_ORDER* pValueOrder, FIXP_DBL value, int measurementSystem,
2608
1.70k
    int measurementSystemRequested) {
2609
1.70k
  const int rows = 11;
2610
1.70k
  const int columns = 12;
2611
1.70k
  const int pOrdering[rows][columns] = {
2612
1.70k
      {0, 0, 8, 0, 1, 3, 0, 5, 6, 7, 4, 2}, /* default = bonus1770 */
2613
1.70k
      {0, 0, 8, 0, 1, 3, 0, 5, 6, 7, 4, 2}, /* bonus1770 */
2614
1.70k
      {0, 0, 1, 0, 8, 5, 0, 2, 3, 4, 6, 7}, /* bonusUser */
2615
1.70k
      {0, 0, 3, 0, 1, 8, 0, 4, 5, 6, 7, 2}, /* bonusExpert */
2616
1.70k
      {0, 0, 5, 0, 1, 3, 0, 8, 6, 7, 4, 2}, /* ResA */
2617
1.70k
      {0, 0, 5, 0, 1, 3, 0, 6, 8, 7, 4, 2}, /* ResB */
2618
1.70k
      {0, 0, 5, 0, 1, 3, 0, 6, 7, 8, 4, 2}, /* ResC */
2619
1.70k
      {0, 0, 3, 0, 1, 7, 0, 4, 5, 6, 8, 2}, /* ResD */
2620
1.70k
      {0, 0, 1, 0, 7, 5, 0, 2, 3, 4, 6, 8}, /* ResE */
2621
1.70k
      {0, 0, 1, 0, 0, 0, 0, 2, 3, 4, 0, 0}, /* ProgramLoudness */
2622
1.70k
      {0, 7, 0, 0, 0, 0, 6, 5, 4, 3, 2, 1}  /* PeakLoudness */
2623
1.70k
  };
2624
2625
1.70k
  if (measurementSystemRequested < 0 || measurementSystemRequested >= rows ||
2626
1.70k
      measurementSystem < 0 || measurementSystem >= columns) {
2627
276
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
2628
276
  }
2629
2630
1.42k
  if (pOrdering[measurementSystemRequested][measurementSystem] >
2631
1.42k
      pValueOrder->order) {
2632
934
    pValueOrder->order =
2633
934
        pOrdering[measurementSystemRequested][measurementSystem];
2634
934
    pValueOrder->value = value;
2635
934
  }
2636
2637
1.42k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2638
1.70k
}
2639
2640
/*******************************************/
2641
2642
static DRCDEC_SELECTION_PROCESS_RETURN _getLoudness(
2643
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int albumMode,
2644
    METHOD_DEFINITION_REQUEST measurementMethodRequested,
2645
    MEASUREMENT_SYSTEM_REQUEST measurementSystemRequested,
2646
    FIXP_DBL targetLoudness, /* e = 7 */
2647
    int drcSetId, int downmixIdRequested,
2648
    FIXP_DBL* pLoudnessNormalizationGain, /* e = 7 */
2649
    FIXP_DBL* pLoudness)                  /* e = 7 */
2650
5.27k
{
2651
5.27k
  int index;
2652
2653
5.27k
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2654
5.27k
  VALUE_ORDER valueOrder;
2655
2656
  /* map MDR_DEFAULT to MDR_PROGRAM_LOUDNESS */
2657
5.27k
  METHOD_DEFINITION_REQUEST requestedMethodDefinition =
2658
5.27k
      measurementMethodRequested < MDR_ANCHOR_LOUDNESS ? MDR_PROGRAM_LOUDNESS
2659
5.27k
                                                       : MDR_ANCHOR_LOUDNESS;
2660
2661
5.27k
  if (measurementMethodRequested > MDR_ANCHOR_LOUDNESS) {
2662
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
2663
0
  }
2664
2665
5.27k
  _initValueOrder(&valueOrder);
2666
2667
5.27k
  *pLoudness = UNDEFINED_LOUDNESS_VALUE;
2668
5.27k
  *pLoudnessNormalizationGain = (FIXP_DBL)0;
2669
2670
5.27k
  if (drcSetId < 0) {
2671
3.80k
    drcSetId = 0;
2672
3.80k
  }
2673
2674
5.27k
  pLoudnessInfo = _getApplicableLoudnessInfoStructure(
2675
5.27k
      hLoudnessInfoSet, drcSetId, downmixIdRequested, albumMode);
2676
2677
5.27k
  if (albumMode && (pLoudnessInfo == NULL)) {
2678
0
    pLoudnessInfo = _getApplicableLoudnessInfoStructure(
2679
0
        hLoudnessInfoSet, drcSetId, downmixIdRequested, 0);
2680
0
  }
2681
2682
5.27k
  if (pLoudnessInfo == NULL) {
2683
4.44k
    return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2684
4.44k
  }
2685
2686
837
  index = -1;
2687
2688
1.47k
  do {
2689
1.47k
    index = _findMethodDefinition(pLoudnessInfo, requestedMethodDefinition,
2690
1.47k
                                  index + 1);
2691
2692
1.47k
    if (index >= 0) {
2693
638
      _getMethodValue(
2694
638
          &valueOrder, pLoudnessInfo->loudnessMeasurement[index].methodValue,
2695
638
          pLoudnessInfo->loudnessMeasurement[index].measurementSystem,
2696
638
          measurementSystemRequested);
2697
638
    }
2698
1.47k
  } while (index >= 0);
2699
2700
  /* repeat with other method definition */
2701
837
  if (valueOrder.order == -1) {
2702
560
    index = -1;
2703
2704
1.62k
    do {
2705
1.62k
      index = _findMethodDefinition(
2706
1.62k
          pLoudnessInfo,
2707
1.62k
          requestedMethodDefinition == MDR_PROGRAM_LOUDNESS
2708
1.62k
              ? MDR_ANCHOR_LOUDNESS
2709
1.62k
              : MDR_PROGRAM_LOUDNESS,
2710
1.62k
          index + 1);
2711
2712
1.62k
      if (index >= 0) {
2713
1.06k
        _getMethodValue(
2714
1.06k
            &valueOrder, pLoudnessInfo->loudnessMeasurement[index].methodValue,
2715
1.06k
            pLoudnessInfo->loudnessMeasurement[index].measurementSystem,
2716
1.06k
            measurementSystemRequested);
2717
1.06k
      }
2718
1.62k
    } while (index >= 0);
2719
560
  }
2720
2721
837
  if (valueOrder.order == -1) {
2722
16
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
2723
821
  } else {
2724
821
    *pLoudnessNormalizationGain = targetLoudness - valueOrder.value;
2725
821
    *pLoudness = valueOrder.value;
2726
821
  }
2727
2728
821
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2729
837
}
2730
2731
/*******************************************/
2732
2733
static int _truePeakLevelIsPresent(HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
2734
10.0k
                                   int drcSetId, int downmixId, int albumMode) {
2735
10.0k
  int i;
2736
10.0k
  int count;
2737
10.0k
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2738
2739
10.0k
  if (albumMode) {
2740
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
2741
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
2742
10.0k
  } else {
2743
10.0k
    count = hLoudnessInfoSet->loudnessInfoCount;
2744
10.0k
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
2745
10.0k
  }
2746
2747
22.0k
  for (i = 0; i < count; i++) {
2748
12.3k
    if ((pLoudnessInfo[i].drcSetId == drcSetId) &&
2749
12.3k
        (pLoudnessInfo[i].downmixId == downmixId)) {
2750
2.93k
      if (pLoudnessInfo[i].truePeakLevelPresent) return 1;
2751
2.93k
    }
2752
12.3k
  }
2753
2754
9.68k
  return 0;
2755
10.0k
}
2756
2757
static DRCDEC_SELECTION_PROCESS_RETURN _getTruePeakLevel(
2758
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int drcSetId, int downmixId,
2759
359
    int albumMode, FIXP_DBL* pTruePeakLevel) {
2760
359
  int i;
2761
359
  int count;
2762
359
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2763
2764
359
  if (albumMode) {
2765
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
2766
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
2767
359
  } else {
2768
359
    count = hLoudnessInfoSet->loudnessInfoCount;
2769
359
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
2770
359
  }
2771
2772
1.49k
  for (i = 0; i < count; i++) {
2773
1.49k
    if ((pLoudnessInfo[i].drcSetId == drcSetId) &&
2774
1.49k
        (pLoudnessInfo[i].downmixId == downmixId)) {
2775
670
      if (pLoudnessInfo[i].truePeakLevelPresent) {
2776
359
        *pTruePeakLevel = pLoudnessInfo[i].truePeakLevel;
2777
359
        return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2778
359
      }
2779
670
    }
2780
1.49k
  }
2781
2782
0
  return DRCDEC_SELECTION_PROCESS_NOT_OK;
2783
359
}
2784
2785
static int _samplePeakLevelIsPresent(HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
2786
                                     int drcSetId, int downmixId,
2787
9.68k
                                     int albumMode) {
2788
9.68k
  int i;
2789
9.68k
  int count;
2790
9.68k
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2791
2792
9.68k
  if (albumMode) {
2793
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
2794
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
2795
9.68k
  } else {
2796
9.68k
    count = hLoudnessInfoSet->loudnessInfoCount;
2797
9.68k
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
2798
9.68k
  }
2799
2800
19.6k
  for (i = 0; i < count; i++) {
2801
10.7k
    if ((pLoudnessInfo[i].drcSetId == drcSetId) &&
2802
10.7k
        (pLoudnessInfo[i].downmixId == downmixId)) {
2803
2.25k
      if (pLoudnessInfo[i].samplePeakLevelPresent) return 1;
2804
2.25k
    }
2805
10.7k
  }
2806
2807
8.88k
  return 0;
2808
9.68k
}
2809
2810
static DRCDEC_SELECTION_PROCESS_RETURN _getSamplePeakLevel(
2811
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int drcSetId, int downmixId,
2812
    int albumMode, FIXP_DBL* pSamplePeakLevel /* e = 7 */
2813
795
) {
2814
795
  int i;
2815
795
  int count;
2816
795
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2817
2818
795
  if (albumMode) {
2819
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
2820
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
2821
795
  } else {
2822
795
    count = hLoudnessInfoSet->loudnessInfoCount;
2823
795
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
2824
795
  }
2825
2826
2.14k
  for (i = 0; i < count; i++) {
2827
2.14k
    if ((pLoudnessInfo[i].drcSetId == drcSetId) &&
2828
2.14k
        (pLoudnessInfo[i].downmixId == downmixId)) {
2829
1.24k
      if (pLoudnessInfo[i].samplePeakLevelPresent) {
2830
795
        *pSamplePeakLevel = pLoudnessInfo[i].samplePeakLevel;
2831
795
        return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2832
795
      }
2833
1.24k
    }
2834
2.14k
  }
2835
2836
0
  return DRCDEC_SELECTION_PROCESS_NOT_OK;
2837
795
}
2838
2839
static int _limiterPeakTargetIsPresent(
2840
4.10k
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction, int drcSetId, int downmixId) {
2841
4.10k
  int i;
2842
2843
4.10k
  if (pDrcInstruction->limiterPeakTargetPresent) {
2844
160
    if ((pDrcInstruction->downmixId[0] == downmixId) ||
2845
160
        (pDrcInstruction->downmixId[0] == 0x7F)) {
2846
109
      return 1;
2847
109
    }
2848
2849
211
    for (i = 0; i < pDrcInstruction->downmixIdCount; i++) {
2850
199
      if (pDrcInstruction->downmixId[i] == downmixId) {
2851
39
        return 1;
2852
39
      }
2853
199
    }
2854
51
  }
2855
2856
3.95k
  return 0;
2857
4.10k
}
2858
2859
static DRCDEC_SELECTION_PROCESS_RETURN _getLimiterPeakTarget(
2860
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction, int drcSetId, int downmixId,
2861
148
    FIXP_DBL* pLimiterPeakTarget) {
2862
148
  int i;
2863
2864
148
  if (pDrcInstruction->limiterPeakTargetPresent) {
2865
148
    if ((pDrcInstruction->downmixId[0] == downmixId) ||
2866
148
        (pDrcInstruction->downmixId[0] == 0x7F)) {
2867
109
      *pLimiterPeakTarget =
2868
109
          ((FX_SGL2FX_DBL(pDrcInstruction->limiterPeakTarget) >> 2));
2869
109
      return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2870
109
    }
2871
2872
157
    for (i = 0; i < pDrcInstruction->downmixIdCount; i++) {
2873
157
      if (pDrcInstruction->downmixId[i] == downmixId) {
2874
39
        *pLimiterPeakTarget =
2875
39
            ((FX_SGL2FX_DBL(pDrcInstruction->limiterPeakTarget) >> 2));
2876
39
        return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2877
39
      }
2878
157
    }
2879
39
  }
2880
2881
0
  return DRCDEC_SELECTION_PROCESS_NOT_OK;
2882
148
}
2883
2884
static int _downmixCoefficientsArePresent(HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
2885
0
                                          int downmixId, int* pIndex) {
2886
0
  int i;
2887
0
  *pIndex = -1;
2888
2889
0
  for (i = 0; i < hUniDrcConfig->downmixInstructionsCount; i++) {
2890
0
    if (hUniDrcConfig->downmixInstructions[i].downmixId == downmixId) {
2891
0
      if (hUniDrcConfig->downmixInstructions[i].downmixCoefficientsPresent) {
2892
0
        if (hUniDrcConfig->downmixInstructions[i].targetChannelCount > 8)
2893
0
          return 0;
2894
0
        *pIndex = i;
2895
0
        return 1;
2896
0
      }
2897
0
    }
2898
0
  }
2899
2900
0
  return 0;
2901
0
}
2902
2903
static DRCDEC_SELECTION_PROCESS_RETURN _getSignalPeakLevel(
2904
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
2905
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, DRC_INSTRUCTIONS_UNI_DRC* pInst,
2906
    int downmixIdRequested, int* explicitPeakInformationPresent,
2907
    FIXP_DBL* signalPeakLevelOut, /* e = 7 */
2908
    SEL_PROC_CODEC_MODE codecMode
2909
2910
5.26k
) {
2911
5.26k
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
2912
2913
5.26k
  int albumMode = hSelProcInput->albumMode;
2914
2915
5.26k
  FIXP_DBL signalPeakLevelTmp = (FIXP_DBL)0;
2916
5.26k
  FIXP_DBL signalPeakLevel = FIXP_DBL(0);
2917
2918
5.26k
  int dmxId = downmixIdRequested;
2919
2920
5.26k
  int drcSetId = pInst->drcSetId;
2921
2922
5.26k
  if (drcSetId < 0) {
2923
3.79k
    drcSetId = 0;
2924
3.79k
  }
2925
2926
5.26k
  *explicitPeakInformationPresent = 1;
2927
2928
5.26k
  if (_truePeakLevelIsPresent(hLoudnessInfoSet, drcSetId, dmxId, albumMode)) {
2929
121
    retVal = _getTruePeakLevel(hLoudnessInfoSet, drcSetId, dmxId, albumMode,
2930
121
                               &signalPeakLevel);
2931
121
    if (retVal) return (retVal);
2932
5.14k
  } else if (_samplePeakLevelIsPresent(hLoudnessInfoSet, drcSetId, dmxId,
2933
5.14k
                                       albumMode)) {
2934
361
    retVal = _getSamplePeakLevel(hLoudnessInfoSet, drcSetId, dmxId, albumMode,
2935
361
                                 &signalPeakLevel);
2936
361
    if (retVal) return (retVal);
2937
4.77k
  } else if (_truePeakLevelIsPresent(hLoudnessInfoSet, 0x3F, dmxId,
2938
4.77k
                                     albumMode)) {
2939
238
    retVal = _getTruePeakLevel(hLoudnessInfoSet, 0x3F, dmxId, albumMode,
2940
238
                               &signalPeakLevel);
2941
238
    if (retVal) return (retVal);
2942
4.54k
  } else if (_samplePeakLevelIsPresent(hLoudnessInfoSet, 0x3F, dmxId,
2943
4.54k
                                       albumMode)) {
2944
434
    retVal = _getSamplePeakLevel(hLoudnessInfoSet, 0x3F, dmxId, albumMode,
2945
434
                                 &signalPeakLevel);
2946
434
    if (retVal) return (retVal);
2947
4.10k
  } else if (_limiterPeakTargetIsPresent(pInst, drcSetId, dmxId)) {
2948
148
    retVal = _getLimiterPeakTarget(pInst, drcSetId, dmxId, &signalPeakLevel);
2949
148
    if (retVal) return (retVal);
2950
3.95k
  } else if (dmxId != 0) {
2951
0
    int downmixInstructionIndex = 0;
2952
0
    FIXP_DBL downmixPeakLevelDB = 0;
2953
2954
0
    *explicitPeakInformationPresent = 0;
2955
2956
0
    signalPeakLevelTmp = FIXP_DBL(0);
2957
2958
0
    if (_downmixCoefficientsArePresent(hUniDrcConfig, dmxId,
2959
0
                                       &downmixInstructionIndex)) {
2960
0
      FIXP_DBL dB_m;
2961
0
      int dB_e;
2962
0
      FIXP_DBL coeff;
2963
0
      FIXP_DBL sum, maxSum; /* e = 7, so it is possible to sum up up to 32
2964
                               downmix coefficients (with e = 2) */
2965
0
      int i, j;
2966
0
      DOWNMIX_INSTRUCTIONS* pDown =
2967
0
          &(hUniDrcConfig->downmixInstructions[downmixInstructionIndex]);
2968
0
      FIXP_DBL downmixOffset = getDownmixOffset(
2969
0
          pDown, hUniDrcConfig->channelLayout.baseChannelCount); /* e = 1 */
2970
0
      maxSum = (FIXP_DBL)0;
2971
2972
0
      for (i = 0; i < pDown->targetChannelCount; i++) {
2973
0
        sum = (FIXP_DBL)0;
2974
0
        for (j = 0; j < hUniDrcConfig->channelLayout.baseChannelCount; j++) {
2975
0
          coeff = pDown->downmixCoefficient[j + i * hUniDrcConfig->channelLayout
2976
0
                                                        .baseChannelCount];
2977
0
          sum += coeff >> 5;
2978
0
        }
2979
0
        if (maxSum < sum) maxSum = sum;
2980
0
      }
2981
2982
0
      maxSum = fMultDiv2(maxSum, downmixOffset) << 2;
2983
2984
0
      if (maxSum == FL2FXCONST_DBL(1.0f / (float)(1 << 7))) {
2985
0
        downmixPeakLevelDB = (FIXP_DBL)0;
2986
0
      } else {
2987
0
        dB_m = lin2dB(maxSum, 7, &dB_e); /* e_maxSum = 7 */
2988
0
        downmixPeakLevelDB =
2989
0
            scaleValue(dB_m, dB_e - 7); /* e_downmixPeakLevelDB = 7 */
2990
0
      }
2991
0
    }
2992
2993
0
    if (_truePeakLevelIsPresent(hLoudnessInfoSet, drcSetId, 0, albumMode)) {
2994
0
      retVal = _getTruePeakLevel(hLoudnessInfoSet, drcSetId, 0, albumMode,
2995
0
                                 &signalPeakLevelTmp);
2996
0
      if (retVal) return (retVal);
2997
0
    } else if (_samplePeakLevelIsPresent(hLoudnessInfoSet, drcSetId, 0,
2998
0
                                         albumMode)) {
2999
0
      retVal = _getSamplePeakLevel(hLoudnessInfoSet, drcSetId, 0, albumMode,
3000
0
                                   &signalPeakLevelTmp);
3001
0
      if (retVal) return (retVal);
3002
0
    } else if (_truePeakLevelIsPresent(hLoudnessInfoSet, 0x3F, 0, albumMode)) {
3003
0
      retVal = _getTruePeakLevel(hLoudnessInfoSet, 0x3F, 0, albumMode,
3004
0
                                 &signalPeakLevelTmp);
3005
0
      if (retVal) return (retVal);
3006
0
    } else if (_samplePeakLevelIsPresent(hLoudnessInfoSet, 0x3F, 0,
3007
0
                                         albumMode)) {
3008
0
      retVal = _getSamplePeakLevel(hLoudnessInfoSet, 0x3F, 0, albumMode,
3009
0
                                   &signalPeakLevelTmp);
3010
0
      if (retVal) return (retVal);
3011
0
    } else if (_limiterPeakTargetIsPresent(pInst, drcSetId, 0)) {
3012
0
      retVal = _getLimiterPeakTarget(pInst, drcSetId, 0, &signalPeakLevelTmp);
3013
0
      if (retVal) return (retVal);
3014
0
    }
3015
3016
0
    signalPeakLevel = signalPeakLevelTmp + downmixPeakLevelDB;
3017
3.95k
  } else {
3018
3.95k
    signalPeakLevel = FIXP_DBL(0); /* worst case estimate */
3019
3.95k
    *explicitPeakInformationPresent = FIXP_DBL(0);
3020
3.95k
  }
3021
3022
5.26k
  *signalPeakLevelOut = signalPeakLevel;
3023
3024
5.26k
  return retVal;
3025
5.26k
}
3026
3027
static DRCDEC_SELECTION_PROCESS_RETURN _extractLoudnessPeakToAverageValue(
3028
    LOUDNESS_INFO* loudnessInfo,
3029
    DYN_RANGE_MEASUREMENT_REQUEST_TYPE dynamicRangeMeasurementType,
3030
    int* pLoudnessPeakToAverageValuePresent,
3031
0
    FIXP_DBL* pLoudnessPeakToAverageValue) {
3032
0
  int i;
3033
3034
0
  VALUE_ORDER valueOrderLoudness;
3035
0
  VALUE_ORDER valueOrderPeakLoudness;
3036
3037
0
  _initValueOrder(&valueOrderLoudness);
3038
0
  _initValueOrder(&valueOrderPeakLoudness);
3039
3040
0
  LOUDNESS_MEASUREMENT* pLoudnessMeasure = NULL;
3041
3042
0
  *pLoudnessPeakToAverageValuePresent = 0;
3043
3044
0
  for (i = 0; i < loudnessInfo->measurementCount; i++) {
3045
0
    pLoudnessMeasure = &(loudnessInfo->loudnessMeasurement[i]);
3046
3047
0
    if (pLoudnessMeasure->methodDefinition == MD_PROGRAM_LOUDNESS) {
3048
0
      _getMethodValue(&valueOrderLoudness, pLoudnessMeasure->methodValue,
3049
0
                      pLoudnessMeasure->measurementSystem, MS_PROGRAMLOUDNESS);
3050
0
    }
3051
3052
0
    if ((dynamicRangeMeasurementType == DRMRT_SHORT_TERM_LOUDNESS_TO_AVG) &&
3053
0
        (pLoudnessMeasure->methodDefinition == MD_SHORT_TERM_LOUDNESS_MAX)) {
3054
0
      _getMethodValue(&valueOrderPeakLoudness, pLoudnessMeasure->methodValue,
3055
0
                      pLoudnessMeasure->measurementSystem, MS_PEAKLOUDNESS);
3056
0
    }
3057
3058
0
    if ((dynamicRangeMeasurementType == DRMRT_MOMENTARY_LOUDNESS_TO_AVG) &&
3059
0
        (pLoudnessMeasure->methodDefinition == MD_MOMENTARY_LOUDNESS_MAX)) {
3060
0
      _getMethodValue(&valueOrderPeakLoudness, pLoudnessMeasure->methodValue,
3061
0
                      pLoudnessMeasure->measurementSystem, MS_PEAKLOUDNESS);
3062
0
    }
3063
3064
0
    if ((dynamicRangeMeasurementType == DRMRT_TOP_OF_LOUDNESS_RANGE_TO_AVG) &&
3065
0
        (pLoudnessMeasure->methodDefinition == MD_MAX_OF_LOUDNESS_RANGE)) {
3066
0
      _getMethodValue(&valueOrderPeakLoudness, pLoudnessMeasure->methodValue,
3067
0
                      pLoudnessMeasure->measurementSystem, MS_PEAKLOUDNESS);
3068
0
    }
3069
0
  }
3070
3071
0
  if ((valueOrderLoudness.order > -1) && (valueOrderPeakLoudness.order > -1)) {
3072
0
    *pLoudnessPeakToAverageValue =
3073
0
        valueOrderPeakLoudness.value - valueOrderLoudness.value;
3074
0
    *pLoudnessPeakToAverageValuePresent = 1;
3075
0
  }
3076
3077
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
3078
0
}
3079
3080
/*******************************************/
3081
3082
static DRCDEC_SELECTION_PROCESS_RETURN _selectAlbumLoudness(
3083
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
3084
    DRCDEC_SELECTION* pCandidatesPotential,
3085
0
    DRCDEC_SELECTION* pCandidatesSelected) {
3086
0
  int i, j;
3087
3088
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
3089
0
    DRCDEC_SELECTION_DATA* pCandidate =
3090
0
        _drcdec_selection_getAt(pCandidatesPotential, i);
3091
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
3092
3093
0
    for (j = 0; j < hLoudnessInfoSet->loudnessInfoAlbumCount; j++) {
3094
0
      if (pCandidate->pInst->drcSetId ==
3095
0
          hLoudnessInfoSet->loudnessInfoAlbum[j].drcSetId) {
3096
0
        if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
3097
0
          return DRCDEC_SELECTION_PROCESS_NOT_OK;
3098
0
      }
3099
0
    }
3100
0
  }
3101
3102
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
3103
0
}
3104
3105
/*******************************************/
3106
3107
static int _findMethodDefinition(LOUDNESS_INFO* pLoudnessInfo,
3108
3.58k
                                 int methodDefinition, int startIndex) {
3109
3.58k
  int i;
3110
3.58k
  int index = -1;
3111
3112
6.24k
  for (i = startIndex; i < pLoudnessInfo->measurementCount; i++) {
3113
4.37k
    if (pLoudnessInfo->loudnessMeasurement[i].methodDefinition ==
3114
4.37k
        methodDefinition) {
3115
1.72k
      index = i;
3116
1.72k
      break;
3117
1.72k
    }
3118
4.37k
  }
3119
3120
3.58k
  return index;
3121
3.58k
}
3122
3123
/*******************************************/
3124
3125
static DRCDEC_SELECTION_PROCESS_RETURN _getMixingLevel(
3126
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int downmixIdRequested,
3127
2.57k
    int drcSetIdRequested, int albumMode, FIXP_DBL* pMixingLevel) {
3128
2.57k
  const FIXP_DBL mixingLevelDefault = FL2FXCONST_DBL(85.0f / (float)(1 << 7));
3129
3130
2.57k
  int i;
3131
2.57k
  int count;
3132
3133
2.57k
  LOUDNESS_INFO* pLoudnessInfo = NULL;
3134
3135
2.57k
  *pMixingLevel = mixingLevelDefault;
3136
3137
2.57k
  if (drcSetIdRequested < 0) {
3138
2.39k
    drcSetIdRequested = 0;
3139
2.39k
  }
3140
3141
2.57k
  if (albumMode) {
3142
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
3143
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
3144
2.57k
  } else {
3145
2.57k
    count = hLoudnessInfoSet->loudnessInfoCount;
3146
2.57k
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
3147
2.57k
  }
3148
3149
3.93k
  for (i = 0; i < count; i++) {
3150
1.38k
    if ((drcSetIdRequested == pLoudnessInfo[i].drcSetId) &&
3151
1.38k
        ((downmixIdRequested == pLoudnessInfo[i].downmixId) ||
3152
640
         (DOWNMIX_ID_ANY_DOWNMIX == pLoudnessInfo[i].downmixId))) {
3153
485
      int index = _findMethodDefinition(&pLoudnessInfo[i], MD_MIXING_LEVEL, 0);
3154
3155
485
      if (index >= 0) {
3156
18
        *pMixingLevel = pLoudnessInfo[i].loudnessMeasurement[index].methodValue;
3157
18
        break;
3158
18
      }
3159
485
    }
3160
1.38k
  }
3161
3162
2.57k
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
3163
2.57k
}
3164
3165
/*******************************************/