Coverage Report

Created: 2023-03-26 06:07

/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
0
static int _isError(int x) {
254
0
  if (x < DRCDEC_SELECTION_PROCESS_WARNING) {
255
0
    return 1;
256
0
  }
257
258
0
  return 0;
259
0
}
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
0
static inline int _compAssign(SCHAR* dest, const SCHAR src) {
270
0
  int diff = 0;
271
0
  if (*dest != src) diff = 1;
272
0
  *dest = src;
273
0
  return diff;
274
0
}
275
276
0
static inline int _compAssign(FIXP_DBL* dest, const FIXP_DBL src) {
277
0
  int diff = 0;
278
0
  if (*dest != src) diff = 1;
279
0
  *dest = src;
280
0
  return diff;
281
0
}
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
23
drcDec_SelectionProcess_Create(HANDLE_DRC_SELECTION_PROCESS* phInstance) {
437
23
  HANDLE_DRC_SELECTION_PROCESS hInstance;
438
23
  hInstance = (HANDLE_DRC_SELECTION_PROCESS)FDKcalloc(
439
23
      1, sizeof(struct s_drcdec_selection_process));
440
441
23
  if (!hInstance) return DRCDEC_SELECTION_PROCESS_OUTOFMEMORY;
442
443
23
  hInstance->codecMode = SEL_PROC_CODEC_MODE_UNDEFINED;
444
445
23
  *phInstance = hInstance;
446
23
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
447
23
}
448
449
DRCDEC_SELECTION_PROCESS_RETURN
450
23
drcDec_SelectionProcess_Init(HANDLE_DRC_SELECTION_PROCESS hInstance) {
451
23
  if (!hInstance) return DRCDEC_SELECTION_PROCESS_NOT_OK;
452
453
23
  _initDefaultParams(&hInstance->selProcInput);
454
23
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
455
23
}
456
457
DRCDEC_SELECTION_PROCESS_RETURN
458
drcDec_SelectionProcess_SetCodecMode(HANDLE_DRC_SELECTION_PROCESS hInstance,
459
0
                                     const SEL_PROC_CODEC_MODE codecMode) {
460
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
461
462
0
  if (!hInstance) return DRCDEC_SELECTION_PROCESS_NOT_OK;
463
464
0
  switch (codecMode) {
465
0
    case SEL_PROC_MPEG_4_AAC:
466
0
    case SEL_PROC_MPEG_D_USAC:
467
0
    case SEL_PROC_TEST_TIME_DOMAIN:
468
0
    case SEL_PROC_TEST_QMF_DOMAIN:
469
0
    case SEL_PROC_TEST_STFT_DOMAIN:
470
0
      hInstance->codecMode = codecMode;
471
0
      break;
472
473
0
    case SEL_PROC_CODEC_MODE_UNDEFINED:
474
0
    default:
475
0
      return DRCDEC_SELECTION_PROCESS_NOT_OK;
476
0
  }
477
478
0
  retVal = _initCodecModeParams(&(hInstance->selProcInput),
479
0
                                hInstance->codecMode = codecMode);
480
481
0
  return retVal;
482
0
}
483
484
DRCDEC_SELECTION_PROCESS_RETURN
485
drcDec_SelectionProcess_SetParam(HANDLE_DRC_SELECTION_PROCESS hInstance,
486
                                 const SEL_PROC_USER_PARAM requestType,
487
0
                                 FIXP_DBL requestValue, int* pDiff) {
488
0
  INT requestValueInt = (INT)requestValue;
489
0
  int i, diff = 0;
490
0
  SEL_PROC_INPUT* pSelProcInput = &(hInstance->selProcInput);
491
492
0
  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
0
    case SEL_PROC_BASE_CHANNEL_COUNT:
591
0
      if (requestValueInt < 0)
592
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
593
0
      diff |= _compAssign(&pSelProcInput->baseChannelCount, requestValueInt);
594
0
      break;
595
0
    case SEL_PROC_SAMPLE_RATE:
596
0
      if (requestValueInt < 0)
597
0
        return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE;
598
0
      diff |= _compAssign(&pSelProcInput->audioSampleRate, requestValueInt);
599
0
      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
0
  }
623
624
0
  if (pDiff != NULL) {
625
0
    *pDiff |= diff;
626
0
  }
627
628
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
629
0
}
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
23
drcDec_SelectionProcess_Delete(HANDLE_DRC_SELECTION_PROCESS* phInstance) {
648
23
  if (phInstance == NULL || *phInstance == NULL)
649
0
    return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE;
650
651
23
  FDKfree(*phInstance);
652
23
  *phInstance = NULL;
653
23
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
654
23
}
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
0
                                HANDLE_SEL_PROC_OUTPUT hSelProcOutput) {
661
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
662
0
  DRCDEC_SELECTION* pCandidatesSelected;
663
0
  DRCDEC_SELECTION* pCandidatesPotential;
664
665
0
  if (hInstance == NULL) return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE;
666
667
0
  pCandidatesSelected = &(hInstance->selectionData[0]);
668
0
  pCandidatesPotential = &(hInstance->selectionData[1]);
669
0
  _drcdec_selection_setNumber(pCandidatesSelected, 0);
670
0
  _drcdec_selection_setNumber(pCandidatesPotential, 0);
671
672
0
  retVal = _generateVirtualDrcSets(&(hInstance->selProcInput), hUniDrcConfig,
673
0
                                   hInstance->codecMode);
674
0
  if (retVal) return (retVal);
675
676
0
  if (hInstance->selProcInput.baseChannelCount !=
677
0
      hUniDrcConfig->channelLayout.baseChannelCount) {
678
0
    hInstance->selProcInput.baseChannelCount =
679
0
        hUniDrcConfig->channelLayout.baseChannelCount;
680
0
  }
681
682
0
  if ((hInstance->selProcInput.targetConfigRequestType != 0) ||
683
0
      (hInstance->selProcInput.targetConfigRequestType == 0 &&
684
0
       hInstance->selProcInput.numDownmixIdRequests == 0)) {
685
0
    retVal = _channelLayoutToDownmixIdMapping(&(hInstance->selProcInput),
686
0
                                              hUniDrcConfig);
687
688
0
    if (_isError(retVal)) return (retVal);
689
0
  }
690
691
0
  retVal = _drcSetPreSelection(&(hInstance->selProcInput), hUniDrcConfig,
692
0
                               hLoudnessInfoSet, &pCandidatesPotential,
693
0
                               &pCandidatesSelected, hInstance->codecMode);
694
0
  if (retVal) return (retVal);
695
696
0
  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
0
  _swapSelectionAndClear(&pCandidatesPotential, &pCandidatesSelected);
709
710
0
  retVal = _drcSetRequestSelection(&(hInstance->selProcInput), hUniDrcConfig,
711
0
                                   hLoudnessInfoSet, &pCandidatesPotential,
712
0
                                   &pCandidatesSelected);
713
0
  if (retVal) return (retVal);
714
715
0
  retVal = _drcSetFinalSelection(&(hInstance->selProcInput), hUniDrcConfig,
716
0
                                 &pCandidatesPotential, &pCandidatesSelected,
717
0
                                 hInstance->codecMode);
718
0
  if (retVal) return (retVal);
719
720
0
  retVal = _generateOutputInfo(
721
0
      &(hInstance->selProcInput), hSelProcOutput, hUniDrcConfig,
722
0
      hLoudnessInfoSet, &(pCandidatesSelected->data[0]), hInstance->codecMode);
723
724
0
  if (_isError(retVal)) return (retVal);
725
726
0
  retVal = _selectDownmixMatrix(hSelProcOutput, hUniDrcConfig);
727
0
  if (retVal) return (retVal);
728
729
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
730
0
}
731
732
/*******************************************/
733
/* static functions                        */
734
/*******************************************/
735
736
static DRCDEC_SELECTION_PROCESS_RETURN _initDefaultParams(
737
23
    HANDLE_SEL_PROC_INPUT hSelProcInput) {
738
23
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
739
740
23
  if (hSelProcInput == NULL) return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE;
741
742
  /* system parameters */
743
23
  hSelProcInput->baseChannelCount = -1;
744
23
  hSelProcInput->baseLayout = -1;
745
23
  hSelProcInput->targetConfigRequestType = TCRT_DOWNMIX_ID;
746
23
  hSelProcInput->numDownmixIdRequests = 0;
747
748
  /* loudness normalization parameters */
749
23
  hSelProcInput->albumMode = 0;
750
23
  hSelProcInput->peakLimiterPresent = 0;
751
23
  hSelProcInput->loudnessNormalizationOn = 1;
752
23
  hSelProcInput->targetLoudness = FL2FXCONST_DBL(-24.0f / (float)(1 << 7));
753
23
  hSelProcInput->loudnessDeviationMax = DEFAULT_LOUDNESS_DEVIATION_MAX;
754
23
  hSelProcInput->loudnessMeasurementMethod = MDR_ANCHOR_LOUDNESS;
755
23
  hSelProcInput->loudnessMeasurementSystem = MSR_EXPERT_PANEL;
756
23
  hSelProcInput->loudnessMeasurementPreProc = LPR_DEFAULT;
757
23
  hSelProcInput->deviceCutOffFrequency = 500;
758
23
  hSelProcInput->loudnessNormalizationGainDbMax =
759
23
      (FIXP_DBL)MAXVAL_DBL; /* infinity as default */
760
23
  hSelProcInput->loudnessNormalizationGainModificationDb = (FIXP_DBL)0;
761
23
  hSelProcInput->outputPeakLevelMax = (FIXP_DBL)0;
762
23
  if (hSelProcInput->peakLimiterPresent == 1) {
763
0
    hSelProcInput->outputPeakLevelMax = FL2FXCONST_DBL(6.0f / (float)(1 << 7));
764
0
  }
765
766
  /* dynamic range control parameters */
767
23
  hSelProcInput->dynamicRangeControlOn = 1;
768
769
23
  hSelProcInput->numDrcFeatureRequests = 0;
770
771
  /* other parameters */
772
23
  hSelProcInput->boost = FL2FXCONST_SGL(1.f / (float)(1 << 1));
773
23
  hSelProcInput->compress = FL2FXCONST_SGL(1.f / (float)(1 << 1));
774
23
  hSelProcInput->drcCharacteristicTarget = 0;
775
776
23
  return retVal;
777
23
}
778
779
static DRCDEC_SELECTION_PROCESS_RETURN _initCodecModeParams(
780
0
    HANDLE_SEL_PROC_INPUT hSelProcInput, const SEL_PROC_CODEC_MODE codecMode) {
781
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
782
783
0
  if (hSelProcInput == NULL) return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE;
784
785
0
  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
0
    case SEL_PROC_MPEG_D_USAC:
796
0
      hSelProcInput->loudnessDeviationMax = DEFAULT_LOUDNESS_DEVIATION_MAX;
797
0
      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
0
      hSelProcInput->outputPeakLevelMax =
802
0
          FL2FXCONST_DBL(6.0f / (float)(1 << 7));
803
0
      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
0
  }
816
817
0
  return retVal;
818
0
}
819
820
static DRCDEC_SELECTION_PROCESS_RETURN _channelLayoutToDownmixIdMapping(
821
0
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig) {
822
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
823
824
0
  DOWNMIX_INSTRUCTIONS* pDown = NULL;
825
826
0
  int i;
827
828
0
  hSelProcInput->numDownmixIdRequests = 0;
829
830
0
  switch (hSelProcInput->targetConfigRequestType) {
831
0
    case TCRT_DOWNMIX_ID:
832
0
      if (hSelProcInput->numDownmixIdRequests == 0) {
833
0
        hSelProcInput->downmixIdRequested[0] = 0;
834
0
        hSelProcInput->numDownmixIdRequests = 1;
835
0
      }
836
837
0
      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
0
  }
906
907
0
  return retVal;
908
0
}
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
0
    int* pMatchFound) {
921
0
  int i;
922
0
  *pMatchFound = 0;
923
924
0
  for (i = 0; i < pDrcInstructionUniDrc->downmixIdCount; i++) {
925
0
    if ((pDrcInstructionUniDrc->downmixId[i] == nRequestedDownmixId) ||
926
0
        (pDrcInstructionUniDrc->downmixId[i] == DOWNMIX_ID_ANY_DOWNMIX) ||
927
0
        ((pDrcInstructionUniDrc->downmixId[i] == DOWNMIX_ID_BASE_LAYOUT) &&
928
0
         (pDrcInstructionUniDrc->drcSetId > 0))) {
929
0
      *pMatchFound = 1;
930
0
      break;
931
0
    }
932
0
  }
933
934
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
935
0
}
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
0
    int* pMatchFound) {
941
0
  *pMatchFound = 0;
942
943
0
  if (nDynamicRangeControlOn == 1) {
944
0
    if ((pDrcInstruction->drcSetEffect != EB_FADE) &&
945
0
        (pDrcInstruction->drcSetEffect != EB_DUCK_OTHER) &&
946
0
        (pDrcInstruction->drcSetEffect != EB_DUCK_SELF) &&
947
0
        (pDrcInstruction->drcSetEffect != 0 || pDrcInstruction->drcSetId < 0)) {
948
0
      *pMatchFound = 1;
949
0
    }
950
0
  } else {
951
0
    *pMatchFound = 1;
952
0
  }
953
954
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
955
0
}
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
0
    DRC_COEFFICIENTS_UNI_DRC* pCoef, int* pMatchFound) {
962
0
  int b, i;
963
964
0
  *pMatchFound = 1;
965
966
0
  if (pDrcInstructionUniDrc->drcSetId < 0) /* virtual DRC sets are okay */
967
0
  {
968
0
    return DRCDEC_SELECTION_PROCESS_NO_ERROR;
969
0
  }
970
971
0
  if (pCoef == NULL) /* check for parametricDRC */
972
0
  {
973
0
    *pMatchFound = 0; /* parametricDRC not supported */
974
0
    return DRCDEC_SELECTION_PROCESS_NO_ERROR;
975
0
  }
976
977
0
  if (pCoef->drcLocation !=
978
0
      pDrcInstructionUniDrc
979
0
          ->drcLocation) /* drcLocation must be LOCATION_SELECTED */
980
0
  {
981
0
    *pMatchFound = 0;
982
0
    return DRCDEC_SELECTION_PROCESS_NO_ERROR;
983
0
  }
984
985
0
  for (i = 0; i < pDrcInstructionUniDrc->nDrcChannelGroups; i++) {
986
0
    int indexDrcCoeff = pDrcInstructionUniDrc->gainSetIndexForChannelGroup[i];
987
0
    int bandCount = 0;
988
989
0
    if (indexDrcCoeff >= 12) {
990
0
      *pMatchFound = 0;
991
0
      return DRCDEC_SELECTION_PROCESS_NO_ERROR;
992
0
    }
993
994
0
    if (indexDrcCoeff > pCoef->gainSetCount - 1) /* check for parametricDRC */
995
0
    {
996
0
      continue;
997
0
    }
998
999
0
    GAIN_SET* gainSet = &(pCoef->gainSet[indexDrcCoeff]);
1000
0
    bandCount = gainSet->bandCount;
1001
1002
0
    if (bandCount > 4) {
1003
0
      *pMatchFound = 0;
1004
0
    }
1005
1006
0
    for (b = 0; b < bandCount; b++) {
1007
0
      if ((gainSet->gainSequenceIndex[b] >= 12) ||
1008
0
          (gainSet->gainSequenceIndex[b] >= pCoef->gainSequenceCount)) {
1009
0
        *pMatchFound = 0;
1010
0
        return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1011
0
      }
1012
0
    }
1013
0
  }
1014
1015
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1016
0
}
1017
1018
/* #6: Independent use of DRC set is permitted.*/
1019
static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement6(
1020
0
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, int* pMatchFound) {
1021
0
  *pMatchFound = 0;
1022
1023
0
  if (((pDrcInstructionUniDrc->dependsOnDrcSetPresent == 0) &&
1024
0
       (pDrcInstructionUniDrc->noIndependentUse == 0)) ||
1025
0
      (pDrcInstructionUniDrc->dependsOnDrcSetPresent == 1)) {
1026
0
    *pMatchFound = 1;
1027
0
  }
1028
1029
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1030
0
}
1031
1032
/* #7: DRC sets that require EQ are only permitted if EQ is supported. */
1033
static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement7(
1034
0
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, int* pMatchFound) {
1035
0
  *pMatchFound = 1;
1036
1037
0
  if (pDrcInstructionUniDrc->requiresEq) {
1038
    /* EQ is not supported */
1039
0
    *pMatchFound = 0;
1040
0
  }
1041
1042
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1043
0
}
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
0
    int applyAdjustment) {
1053
0
  FIXP_DBL adjustment = 0; /* e = 8 */
1054
1055
  /* use e = 8 for all function parameters to prevent overflow */
1056
0
  loudness >>= 1;
1057
0
  loudnessNormalizationGainDb >>= 1;
1058
0
  loudnessNormalizationGainDbMax >>= 1;
1059
0
  loudnessDeviationMax >>= 1;
1060
0
  signalPeakLevel >>= 1;
1061
0
  outputPeakLevelMax >>= 1;
1062
1063
0
  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
0
  pData->loudnessNormalizationGainDbAdjusted = fMin(
1071
0
      loudnessNormalizationGainDb - adjustment, loudnessNormalizationGainDbMax);
1072
0
  pData->outputLoudness = loudness + pData->loudnessNormalizationGainDbAdjusted;
1073
0
  pData->outputPeakLevel =
1074
0
      signalPeakLevel + pData->loudnessNormalizationGainDbAdjusted;
1075
1076
  /* shift back to e = 7 using saturation */
1077
0
  pData->loudnessNormalizationGainDbAdjusted = SATURATE_LEFT_SHIFT(
1078
0
      pData->loudnessNormalizationGainDbAdjusted, 1, DFRACT_BITS);
1079
0
  pData->outputLoudness =
1080
0
      SATURATE_LEFT_SHIFT(pData->outputLoudness, 1, DFRACT_BITS);
1081
0
  pData->outputPeakLevel =
1082
0
      SATURATE_LEFT_SHIFT(pData->outputPeakLevel, 1, DFRACT_BITS);
1083
0
}
1084
1085
static int _targetLoudnessInRange(
1086
0
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, FIXP_DBL targetLoudness) {
1087
0
  int retVal = 0;
1088
1089
0
  FIXP_DBL drcSetTargetLoudnessValueUpper =
1090
0
      ((FIXP_DBL)pDrcInstructionUniDrc->drcSetTargetLoudnessValueUpper)
1091
0
      << (DFRACT_BITS - 1 - 7);
1092
0
  FIXP_DBL drcSetTargetLoudnessValueLower =
1093
0
      ((FIXP_DBL)pDrcInstructionUniDrc->drcSetTargetLoudnessValueLower)
1094
0
      << (DFRACT_BITS - 1 - 7);
1095
1096
0
  if (pDrcInstructionUniDrc->drcSetTargetLoudnessPresent &&
1097
0
      drcSetTargetLoudnessValueUpper >= targetLoudness &&
1098
0
      drcSetTargetLoudnessValueLower < targetLoudness) {
1099
0
    retVal = 1;
1100
0
  }
1101
1102
0
  return retVal;
1103
0
}
1104
1105
static int _drcSetIsUsable(HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
1106
0
                           DRC_INSTRUCTIONS_UNI_DRC* pInst) {
1107
0
  int usable = 0;
1108
0
  DRC_COEFFICIENTS_UNI_DRC* pCoef =
1109
0
      selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED);
1110
1111
  /* check if ID is unique */
1112
0
  if (selectDrcInstructions(hUniDrcConfig, pInst->drcSetId) != pInst) return 0;
1113
  /* sanity check on drcInstructions */
1114
0
  _preSelectionRequirement5(pInst, pCoef, &usable);
1115
0
  return usable;
1116
0
}
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
0
    DRCDEC_SELECTION* pCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) {
1127
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1128
0
  int explicitPeakInformationPresent;
1129
0
  FIXP_DBL signalPeakLevel;
1130
0
  int addToCandidate = 0;
1131
1132
0
  FIXP_DBL loudnessNormalizationGainDb;
1133
0
  FIXP_DBL loudness;
1134
1135
0
  FIXP_DBL loudnessDeviationMax =
1136
0
      ((FIXP_DBL)hSelProcInput->loudnessDeviationMax) << (DFRACT_BITS - 1 - 7);
1137
1138
0
  {
1139
0
    retVal = _getLoudness(hLoudnessInfoSet, hSelProcInput->albumMode,
1140
0
                          hSelProcInput->loudnessMeasurementMethod,
1141
0
                          hSelProcInput->loudnessMeasurementSystem,
1142
0
                          hSelProcInput->targetLoudness,
1143
0
                          pDrcInstructionUniDrc->drcSetId,
1144
0
                          hSelProcInput->downmixIdRequested[downmixIdIndex],
1145
0
                          &loudnessNormalizationGainDb, &loudness);
1146
0
    if (retVal) return (retVal);
1147
0
  }
1148
1149
0
  if (!hSelProcInput->loudnessNormalizationOn) {
1150
0
    loudnessNormalizationGainDb = (FIXP_DBL)0;
1151
0
  }
1152
1153
0
  retVal = _getSignalPeakLevel(
1154
0
      hSelProcInput, hUniDrcConfig, hLoudnessInfoSet, pDrcInstructionUniDrc,
1155
0
      hSelProcInput->downmixIdRequested[downmixIdIndex],
1156
0
      &explicitPeakInformationPresent, &signalPeakLevel, codecMode
1157
1158
0
  );
1159
0
  if (retVal) return (retVal);
1160
1161
0
  if (hSelProcInput->dynamicRangeControlOn) {
1162
0
    if (explicitPeakInformationPresent == 0) {
1163
0
      if (pDrcInstructionUniDrc->drcSetTargetLoudnessPresent &&
1164
0
          ((hSelProcInput->loudnessNormalizationOn &&
1165
0
            _targetLoudnessInRange(pDrcInstructionUniDrc,
1166
0
                                   hSelProcInput->targetLoudness)) ||
1167
0
           !hSelProcInput->loudnessNormalizationOn)) {
1168
0
        DRCDEC_SELECTION_DATA* pData =
1169
0
            _drcdec_selection_addNew(pCandidatesSelected);
1170
0
        if (pData == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1171
1172
0
        _setSelectionDataInfo(pData, loudness, loudnessNormalizationGainDb,
1173
0
                              hSelProcInput->loudnessNormalizationGainDbMax,
1174
0
                              loudnessDeviationMax, signalPeakLevel,
1175
0
                              hSelProcInput->outputPeakLevelMax, 0);
1176
0
        pData->downmixIdRequestIndex = downmixIdIndex;
1177
0
        pData->pInst = pDrcInstructionUniDrc;
1178
0
        pData->selectionFlag =
1179
0
            1; /* signal pre-selection step dealing with drcSetTargetLoudness */
1180
1181
0
        if (hSelProcInput->loudnessNormalizationOn) {
1182
0
          pData->outputPeakLevel =
1183
0
              hSelProcInput->targetLoudness -
1184
0
              (((FIXP_DBL)pData->pInst->drcSetTargetLoudnessValueUpper)
1185
0
               << (DFRACT_BITS - 1 - 7));
1186
0
        } else {
1187
0
          pData->outputPeakLevel = (FIXP_DBL)0;
1188
0
        }
1189
0
      } else {
1190
0
        if ((!hSelProcInput->loudnessNormalizationOn) ||
1191
0
            (!pDrcInstructionUniDrc->drcSetTargetLoudnessPresent) ||
1192
0
            (hSelProcInput->loudnessNormalizationOn &&
1193
0
             _targetLoudnessInRange(pDrcInstructionUniDrc,
1194
0
                                    hSelProcInput->targetLoudness))) {
1195
0
          addToCandidate = 1;
1196
0
        }
1197
0
      }
1198
0
    } else {
1199
0
      addToCandidate = 1;
1200
0
    }
1201
1202
0
    if (addToCandidate) {
1203
0
      DRCDEC_SELECTION_DATA* pData =
1204
0
          _drcdec_selection_addNew(pCandidatesPotential);
1205
0
      if (pData == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1206
1207
0
      _setSelectionDataInfo(pData, loudness, loudnessNormalizationGainDb,
1208
0
                            hSelProcInput->loudnessNormalizationGainDbMax,
1209
0
                            loudnessDeviationMax, signalPeakLevel,
1210
0
                            hSelProcInput->outputPeakLevelMax, 0);
1211
0
      pData->downmixIdRequestIndex = downmixIdIndex;
1212
0
      pData->pInst = pDrcInstructionUniDrc;
1213
0
      pData->selectionFlag = 0;
1214
0
    }
1215
0
  } 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
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1233
0
}
1234
1235
/* #9: Clipping is minimized. */
1236
static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement9(
1237
    SEL_PROC_INPUT* hSelProcInput, DRCDEC_SELECTION* pCandidatesPotential,
1238
0
    DRCDEC_SELECTION* pCandidatesSelected) {
1239
0
  int i;
1240
1241
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1242
0
    DRCDEC_SELECTION_DATA* pCandidate =
1243
0
        _drcdec_selection_getAt(pCandidatesPotential, i);
1244
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1245
1246
0
    if (pCandidate->outputPeakLevel <= hSelProcInput->outputPeakLevelMax) {
1247
0
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1248
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1249
0
    }
1250
0
  }
1251
1252
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1253
0
}
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
0
    DRCDEC_SELECTION* pCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) {
1262
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1263
0
  int matchFound = 0;
1264
0
  DRC_COEFFICIENTS_UNI_DRC* pCoef =
1265
0
      selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED);
1266
1267
0
  retVal = _preSelectionRequirement123(
1268
0
      hSelProcInput->downmixIdRequested[downmixIdIndex], pDrcInstructionUniDrc,
1269
0
      &matchFound);
1270
1271
0
  if (!retVal && matchFound)
1272
0
    retVal = _preSelectionRequirement4(pDrcInstructionUniDrc,
1273
0
                                       hSelProcInput->dynamicRangeControlOn,
1274
0
                                       &matchFound);
1275
1276
0
  if (!retVal && matchFound)
1277
0
    retVal =
1278
0
        _preSelectionRequirement5(pDrcInstructionUniDrc, pCoef, &matchFound);
1279
1280
0
  if (!retVal && matchFound)
1281
0
    retVal = _preSelectionRequirement6(pDrcInstructionUniDrc, &matchFound);
1282
1283
0
  if (!retVal && matchFound)
1284
0
    retVal = _preSelectionRequirement7(pDrcInstructionUniDrc, &matchFound);
1285
1286
0
  if (!retVal && matchFound)
1287
0
    retVal = _preSelectionRequirement8(
1288
0
        hSelProcInput, downmixIdIndex, hUniDrcConfig, hLoudnessInfoSet,
1289
0
        pDrcInstructionUniDrc, pCandidatesPotential, pCandidatesSelected,
1290
0
        codecMode);
1291
1292
0
  return retVal;
1293
0
}
1294
1295
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetSelectionAddCandidates(
1296
    SEL_PROC_INPUT* hSelProcInput, DRCDEC_SELECTION* pCandidatesPotential,
1297
0
    DRCDEC_SELECTION* pCandidatesSelected) {
1298
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1299
0
  int nHitCount = 0;
1300
0
  int i;
1301
1302
0
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1303
0
  DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc = NULL;
1304
1305
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1306
0
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1307
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1308
1309
0
    pDrcInstructionUniDrc = pCandidate->pInst;
1310
1311
0
    if (_targetLoudnessInRange(pDrcInstructionUniDrc,
1312
0
                               hSelProcInput->targetLoudness)) {
1313
0
      nHitCount++;
1314
0
    }
1315
0
  }
1316
1317
0
  if (nHitCount != 0) {
1318
0
    for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1319
0
      pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1320
0
      if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1321
1322
0
      pDrcInstructionUniDrc = pCandidate->pInst;
1323
1324
0
      if (_targetLoudnessInRange(pDrcInstructionUniDrc,
1325
0
                                 hSelProcInput->targetLoudness)) {
1326
0
        if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1327
0
          return DRCDEC_SELECTION_PROCESS_NOT_OK;
1328
0
      }
1329
0
    }
1330
0
  } else {
1331
0
    FIXP_DBL lowestPeakLevel = MAXVAL_DBL; /* e = 7 */
1332
0
    FIXP_DBL peakLevel = 0;                /* e = 7 */
1333
1334
0
    for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1335
0
      pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1336
0
      if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1337
1338
0
      peakLevel = pCandidate->outputPeakLevel;
1339
1340
0
      if (peakLevel < lowestPeakLevel) {
1341
0
        lowestPeakLevel = peakLevel;
1342
0
      }
1343
0
    }
1344
1345
    /* add all with lowest peak level or max 1dB above */
1346
0
    for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1347
0
      FIXP_DBL loudnessDeviationMax =
1348
0
          ((FIXP_DBL)hSelProcInput->loudnessDeviationMax)
1349
0
          << (DFRACT_BITS - 1 - 7); /* e = 7 */
1350
1351
0
      pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1352
0
      if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1353
1354
0
      peakLevel = pCandidate->outputPeakLevel;
1355
1356
0
      if (peakLevel == lowestPeakLevel ||
1357
0
          peakLevel <=
1358
0
              lowestPeakLevel + FL2FXCONST_DBL(1.0f / (float)(1 << 7))) {
1359
0
        FIXP_DBL adjustment =
1360
0
            fMax((FIXP_DBL)0, peakLevel - hSelProcInput->outputPeakLevelMax);
1361
0
        adjustment = fMin(adjustment, fMax((FIXP_DBL)0, loudnessDeviationMax));
1362
1363
0
        pCandidate->loudnessNormalizationGainDbAdjusted -= adjustment;
1364
0
        pCandidate->outputPeakLevel -= adjustment;
1365
0
        pCandidate->outputLoudness -= adjustment;
1366
0
        if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1367
0
          return DRCDEC_SELECTION_PROCESS_NOT_OK;
1368
0
      }
1369
0
    }
1370
0
  }
1371
1372
0
  return retVal;
1373
0
}
1374
1375
static DRCDEC_SELECTION_PROCESS_RETURN _dependentDrcInstruction(
1376
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRC_INSTRUCTIONS_UNI_DRC* pInst,
1377
0
    DRC_INSTRUCTIONS_UNI_DRC** ppDrcInstructionsDependent) {
1378
0
  int i;
1379
0
  DRC_INSTRUCTIONS_UNI_DRC* pDependentDrc = NULL;
1380
1381
0
  for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
1382
0
    pDependentDrc =
1383
0
        (DRC_INSTRUCTIONS_UNI_DRC*)&(hUniDrcConfig->drcInstructionsUniDrc[i]);
1384
1385
0
    if (pDependentDrc->drcSetId == pInst->dependsOnDrcSet) {
1386
0
      break;
1387
0
    }
1388
0
  }
1389
1390
0
  if (i == hUniDrcConfig->drcInstructionsUniDrcCount) {
1391
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
1392
0
  }
1393
1394
0
  if (pDependentDrc->dependsOnDrcSetPresent == 1) {
1395
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
1396
0
  }
1397
1398
0
  *ppDrcInstructionsDependent = pDependentDrc;
1399
1400
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1401
0
}
1402
1403
static DRCDEC_SELECTION_PROCESS_RETURN _selectDrcSetEffectNone(
1404
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRCDEC_SELECTION* pCandidatesPotential,
1405
0
    DRCDEC_SELECTION* pCandidatesSelected) {
1406
0
  int i;
1407
1408
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1409
0
    DRCDEC_SELECTION_DATA* pCandidate =
1410
0
        _drcdec_selection_getAt(pCandidatesPotential, i);
1411
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1412
1413
0
    if ((pCandidate->pInst->drcSetEffect & 0xff) == 0) {
1414
0
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1415
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1416
0
    }
1417
0
  }
1418
1419
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1420
0
}
1421
1422
static DRCDEC_SELECTION_PROCESS_RETURN _selectSingleEffectType(
1423
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRC_EFFECT_TYPE_REQUEST effectType,
1424
    DRCDEC_SELECTION* pCandidatesPotential,
1425
0
    DRCDEC_SELECTION* pCandidatesSelected) {
1426
0
  int i;
1427
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1428
0
  DRC_INSTRUCTIONS_UNI_DRC* pInst;
1429
0
  DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionsDependent;
1430
1431
0
  if (effectType == DETR_NONE) {
1432
0
    retVal = _selectDrcSetEffectNone(hUniDrcConfig, pCandidatesPotential,
1433
0
                                     pCandidatesSelected);
1434
0
    if (retVal) return (retVal);
1435
0
  } else {
1436
0
    int effectBitPosition = 1 << (effectType - 1);
1437
1438
0
    for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1439
0
      DRCDEC_SELECTION_DATA* pCandidate =
1440
0
          _drcdec_selection_getAt(pCandidatesPotential, i);
1441
0
      if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1442
1443
0
      pInst = pCandidate->pInst;
1444
1445
0
      if (!pInst->dependsOnDrcSetPresent) {
1446
0
        if ((pInst->drcSetEffect & effectBitPosition)) {
1447
0
          if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1448
0
            return DRCDEC_SELECTION_PROCESS_NOT_OK;
1449
0
        }
1450
0
      } else {
1451
0
        retVal = _dependentDrcInstruction(hUniDrcConfig, pInst,
1452
0
                                          &pDrcInstructionsDependent);
1453
0
        if (retVal) return (retVal);
1454
1455
0
        if (((pInst->drcSetEffect & effectBitPosition)) ||
1456
0
            ((pDrcInstructionsDependent->drcSetEffect & effectBitPosition))) {
1457
0
          if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1458
0
            return DRCDEC_SELECTION_PROCESS_NOT_OK;
1459
0
        }
1460
0
      }
1461
0
    }
1462
0
  }
1463
1464
0
  return retVal;
1465
0
}
1466
1467
static DRCDEC_SELECTION_PROCESS_RETURN _selectEffectTypeFeature(
1468
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRC_FEATURE_REQUEST drcFeatureRequest,
1469
    DRCDEC_SELECTION** ppCandidatesPotential,
1470
0
    DRCDEC_SELECTION** ppCandidatesSelected) {
1471
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1472
0
  int i;
1473
0
  int desiredEffectTypeFound = 0;
1474
1475
0
  for (i = 0; i < drcFeatureRequest.drcEffectType.numRequestsDesired; i++) {
1476
0
    retVal = _selectSingleEffectType(
1477
0
        hUniDrcConfig, drcFeatureRequest.drcEffectType.request[i],
1478
0
        *ppCandidatesPotential, *ppCandidatesSelected);
1479
0
    if (retVal) return (retVal);
1480
1481
0
    if (_drcdec_selection_getNumber(*ppCandidatesSelected)) {
1482
0
      desiredEffectTypeFound = 1;
1483
0
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1484
0
    }
1485
0
  }
1486
1487
0
  if (!desiredEffectTypeFound) {
1488
0
    for (i = drcFeatureRequest.drcEffectType.numRequestsDesired;
1489
0
         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
0
  }
1501
1502
0
  _swapSelection(ppCandidatesPotential, ppCandidatesSelected);
1503
1504
0
  return retVal;
1505
0
}
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
0
    DRCDEC_SELECTION* pCandidatesSelected) {
1671
0
  int i;
1672
1673
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1674
0
    DRCDEC_SELECTION_DATA* pCandidate =
1675
0
        _drcdec_selection_getAt(pCandidatesPotential, i);
1676
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1677
1678
0
    if (pCandidate->outputPeakLevel <= FIXP_DBL(0)) {
1679
0
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1680
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1681
0
    }
1682
0
  }
1683
1684
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1685
0
}
1686
1687
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_downmixId(
1688
    HANDLE_SEL_PROC_INPUT hSelProcInput,
1689
    DRCDEC_SELECTION** ppCandidatesPotential,
1690
0
    DRCDEC_SELECTION** ppCandidatesSelected) {
1691
0
  int i, j;
1692
0
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1693
0
  DRC_INSTRUCTIONS_UNI_DRC* pInst = NULL;
1694
1695
0
  for (i = 0; i < _drcdec_selection_getNumber(*ppCandidatesPotential); i++) {
1696
0
    pCandidate = _drcdec_selection_getAt(*ppCandidatesPotential, i);
1697
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1698
1699
0
    pInst = pCandidate->pInst;
1700
1701
0
    for (j = 0; j < pInst->downmixIdCount; j++) {
1702
0
      if (DOWNMIX_ID_BASE_LAYOUT != pInst->downmixId[j] &&
1703
0
          DOWNMIX_ID_ANY_DOWNMIX != pInst->downmixId[j] &&
1704
0
          hSelProcInput
1705
0
                  ->downmixIdRequested[pCandidate->downmixIdRequestIndex] ==
1706
0
              pInst->downmixId[j]) {
1707
0
        if (_drcdec_selection_add(*ppCandidatesSelected, pCandidate) == NULL)
1708
0
          return DRCDEC_SELECTION_PROCESS_NOT_OK;
1709
0
      }
1710
0
    }
1711
0
  }
1712
1713
0
  if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) {
1714
0
    _swapSelection(ppCandidatesPotential, ppCandidatesSelected);
1715
0
  }
1716
1717
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1718
0
}
1719
1720
0
static int _crossSum(int value) {
1721
0
  int sum = 0;
1722
1723
0
  while (value != 0) {
1724
0
    if ((value & 1) == 1) {
1725
0
      sum++;
1726
0
    }
1727
1728
0
    value >>= 1;
1729
0
  }
1730
1731
0
  return sum;
1732
0
}
1733
1734
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_effectTypes(
1735
    DRCDEC_SELECTION* pCandidatesPotential,
1736
0
    DRCDEC_SELECTION* pCandidatesSelected) {
1737
0
  int i;
1738
0
  int minNumEffects = 1000;
1739
0
  int numEffects = 0;
1740
0
  int effects = 0;
1741
0
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1742
0
  DRC_INSTRUCTIONS_UNI_DRC* pInst = NULL;
1743
1744
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1745
0
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1746
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1747
1748
0
    pInst = pCandidate->pInst;
1749
1750
0
    effects = pInst->drcSetEffect;
1751
0
    effects &= 0xffff ^ (EB_GENERAL_COMPR);
1752
0
    numEffects = _crossSum(effects);
1753
1754
0
    if (numEffects < minNumEffects) {
1755
0
      minNumEffects = numEffects;
1756
0
    }
1757
0
  }
1758
1759
  /* add all with minimum number of effects */
1760
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1761
0
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1762
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1763
1764
0
    pInst = pCandidate->pInst;
1765
1766
0
    effects = pInst->drcSetEffect;
1767
0
    effects &= 0xffff ^ (EB_GENERAL_COMPR);
1768
0
    numEffects = _crossSum(effects);
1769
1770
0
    if (numEffects == minNumEffects) {
1771
0
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1772
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1773
0
    }
1774
0
  }
1775
1776
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1777
0
}
1778
1779
static DRCDEC_SELECTION_PROCESS_RETURN _selectSmallestTargetLoudnessValueUpper(
1780
    DRCDEC_SELECTION* pCandidatesPotential,
1781
0
    DRCDEC_SELECTION* pCandidatesSelected) {
1782
0
  int i;
1783
0
  SCHAR minVal = 0x7F;
1784
0
  SCHAR val = 0;
1785
0
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1786
1787
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1788
0
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1789
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1790
1791
0
    val = pCandidate->pInst->drcSetTargetLoudnessValueUpper;
1792
1793
0
    if (val < minVal) {
1794
0
      minVal = val;
1795
0
    }
1796
0
  }
1797
1798
  /* add all with same smallest drcSetTargetLoudnessValueUpper */
1799
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1800
0
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1801
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1802
1803
0
    val = pCandidate->pInst->drcSetTargetLoudnessValueUpper;
1804
1805
0
    if (val == minVal) {
1806
0
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1807
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1808
0
    }
1809
0
  }
1810
1811
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1812
0
}
1813
1814
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_targetLoudness(
1815
    FIXP_DBL targetLoudness, DRCDEC_SELECTION* pCandidatesPotential,
1816
0
    DRCDEC_SELECTION* pCandidatesSelected) {
1817
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1818
0
  int i;
1819
0
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1820
1821
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1822
0
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1823
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1824
1825
0
    if (pCandidate->selectionFlag == 0) {
1826
0
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1827
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1828
0
    }
1829
0
  }
1830
1831
0
  if (_drcdec_selection_getNumber(pCandidatesSelected) == 0) {
1832
0
    retVal = _selectSmallestTargetLoudnessValueUpper(pCandidatesPotential,
1833
0
                                                     pCandidatesSelected);
1834
0
    if (retVal) return (retVal);
1835
0
  }
1836
1837
0
  if (_drcdec_selection_getNumber(pCandidatesSelected) > 1) {
1838
0
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc = NULL;
1839
1840
0
    _swapSelectionAndClear(&pCandidatesPotential, &pCandidatesSelected);
1841
1842
0
    for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1843
0
      pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1844
0
      if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1845
1846
0
      pDrcInstructionUniDrc = pCandidate->pInst;
1847
1848
0
      if (_targetLoudnessInRange(pDrcInstructionUniDrc, targetLoudness)) {
1849
0
        if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1850
0
          return DRCDEC_SELECTION_PROCESS_NOT_OK;
1851
0
      }
1852
0
    }
1853
1854
0
    if (_drcdec_selection_getNumber(pCandidatesSelected) > 1) {
1855
0
      _swapSelectionAndClear(&pCandidatesPotential, &pCandidatesSelected);
1856
1857
0
      retVal = _selectSmallestTargetLoudnessValueUpper(pCandidatesPotential,
1858
0
                                                       pCandidatesSelected);
1859
0
      if (retVal) return (retVal);
1860
0
    }
1861
0
  }
1862
1863
0
  return retVal;
1864
0
}
1865
1866
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_peakValueLargest(
1867
    DRCDEC_SELECTION* pCandidatesPotential,
1868
0
    DRCDEC_SELECTION* pCandidatesSelected) {
1869
0
  int i;
1870
0
  FIXP_DBL largestPeakLevel = MINVAL_DBL;
1871
0
  FIXP_DBL peakLevel = 0;
1872
0
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1873
1874
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1875
0
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1876
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1877
1878
0
    peakLevel = pCandidate->outputPeakLevel;
1879
1880
0
    if (peakLevel > largestPeakLevel) {
1881
0
      largestPeakLevel = peakLevel;
1882
0
    }
1883
0
  }
1884
1885
  /* add all with same largest peak level */
1886
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1887
0
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1888
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1889
1890
0
    peakLevel = pCandidate->outputPeakLevel;
1891
1892
0
    if (peakLevel == largestPeakLevel) {
1893
0
      if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL)
1894
0
        return DRCDEC_SELECTION_PROCESS_NOT_OK;
1895
0
    }
1896
0
  }
1897
1898
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1899
0
}
1900
1901
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_drcSetId(
1902
    DRCDEC_SELECTION* pCandidatesPotential,
1903
0
    DRCDEC_SELECTION* pCandidatesSelected) {
1904
0
  int i;
1905
0
  int largestId = -1000;
1906
0
  int id = 0;
1907
0
  DRCDEC_SELECTION_DATA* pCandidate = NULL;
1908
0
  DRCDEC_SELECTION_DATA* pCandidateSelected = NULL;
1909
1910
0
  for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) {
1911
0
    pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i);
1912
0
    if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK;
1913
1914
0
    id = pCandidate->pInst->drcSetId;
1915
1916
0
    if (id > largestId) {
1917
0
      largestId = id;
1918
0
      pCandidateSelected = pCandidate;
1919
0
    }
1920
0
  }
1921
1922
0
  if (pCandidateSelected != NULL) {
1923
0
    if (_drcdec_selection_add(pCandidatesSelected, pCandidateSelected) == NULL)
1924
0
      return DRCDEC_SELECTION_PROCESS_NOT_OK;
1925
0
  } else {
1926
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
1927
0
  }
1928
1929
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
1930
0
}
1931
1932
static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection(
1933
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
1934
    DRCDEC_SELECTION** ppCandidatesPotential,
1935
0
    DRCDEC_SELECTION** ppCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) {
1936
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
1937
1938
0
  if (_drcdec_selection_getNumber(*ppCandidatesPotential) == 0) {
1939
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
1940
0
  } else if (_drcdec_selection_getNumber(*ppCandidatesPotential) == 1) {
1941
0
    _swapSelection(ppCandidatesPotential, ppCandidatesSelected);
1942
    /* finished */
1943
0
  } else /* > 1 */
1944
0
  {
1945
0
    retVal = _drcSetFinalSelection_peakValue0(*ppCandidatesPotential,
1946
0
                                              *ppCandidatesSelected);
1947
0
    if (retVal) return (retVal);
1948
1949
0
    if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) {
1950
0
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1951
0
      retVal = _drcSetFinalSelection_downmixId(
1952
0
          hSelProcInput, ppCandidatesPotential, ppCandidatesSelected);
1953
0
      if (retVal) return (retVal);
1954
0
    }
1955
1956
0
    if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) {
1957
0
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1958
0
      retVal = _drcSetFinalSelection_effectTypes(*ppCandidatesPotential,
1959
0
                                                 *ppCandidatesSelected);
1960
0
      if (retVal) return (retVal);
1961
0
    }
1962
1963
0
    if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) {
1964
0
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1965
0
      retVal = _drcSetFinalSelection_targetLoudness(
1966
0
          hSelProcInput->targetLoudness, *ppCandidatesPotential,
1967
0
          *ppCandidatesSelected);
1968
0
      if (retVal) return (retVal);
1969
0
    }
1970
1971
0
    if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) {
1972
0
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1973
0
      retVal = _drcSetFinalSelection_peakValueLargest(*ppCandidatesPotential,
1974
0
                                                      *ppCandidatesSelected);
1975
0
      if (retVal) return (retVal);
1976
0
    }
1977
1978
0
    if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) {
1979
0
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
1980
0
      retVal = _drcSetFinalSelection_drcSetId(*ppCandidatesPotential,
1981
0
                                              *ppCandidatesSelected);
1982
0
      if (retVal) return (retVal);
1983
0
    }
1984
0
  }
1985
1986
0
  if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) {
1987
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
1988
0
  }
1989
1990
0
  return retVal;
1991
0
}
1992
1993
static DRCDEC_SELECTION_PROCESS_RETURN _generateVirtualDrcSets(
1994
    HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig,
1995
0
    SEL_PROC_CODEC_MODE codecMode) {
1996
0
  int i;
1997
0
  int nMixes = hUniDrcConfig->downmixInstructionsCount + 1;
1998
0
  int index = hUniDrcConfig->drcInstructionsUniDrcCount;
1999
0
  int indexVirtual = -1;
2000
0
  DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction =
2001
0
      &(hUniDrcConfig->drcInstructionsUniDrc[index]);
2002
2003
0
  if (codecMode == SEL_PROC_MPEG_H_3DA) {
2004
0
    nMixes = 1;
2005
0
  }
2006
2007
0
  if ((index + nMixes) > (12 + 1 + 6)) {
2008
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
2009
0
  }
2010
2011
0
  FDKmemset(pDrcInstruction, 0, sizeof(DRC_INSTRUCTIONS_UNI_DRC));
2012
2013
0
  pDrcInstruction->drcSetId = indexVirtual;
2014
0
  index++;
2015
0
  indexVirtual--;
2016
0
  pDrcInstruction->downmixIdCount = 1;
2017
2018
0
  if ((codecMode == SEL_PROC_MPEG_H_3DA) &&
2019
0
      (hSelProcInput->numDownmixIdRequests)) {
2020
0
    pDrcInstruction->downmixId[0] = hSelProcInput->downmixIdRequested[0];
2021
0
  } else {
2022
0
    pDrcInstruction->downmixId[0] = DOWNMIX_ID_BASE_LAYOUT;
2023
0
  }
2024
2025
0
  for (i = 1; i < nMixes; i++) {
2026
0
    pDrcInstruction = &(hUniDrcConfig->drcInstructionsUniDrc[index]);
2027
0
    FDKmemset(pDrcInstruction, 0, sizeof(DRC_INSTRUCTIONS_UNI_DRC));
2028
0
    pDrcInstruction->drcSetId = indexVirtual;
2029
0
    pDrcInstruction->downmixId[0] =
2030
0
        hUniDrcConfig->downmixInstructions[i - 1].downmixId;
2031
0
    pDrcInstruction->downmixIdCount = 1;
2032
0
    index++;
2033
0
    indexVirtual--;
2034
0
  }
2035
2036
0
  hUniDrcConfig->drcInstructionsCountInclVirtual =
2037
0
      hUniDrcConfig->drcInstructionsUniDrcCount + nMixes;
2038
2039
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2040
0
}
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
0
    DRCDEC_SELECTION_DATA* pSelectionData, SEL_PROC_CODEC_MODE codecMode) {
2047
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
2048
2049
0
  int i, j;
2050
0
  int hasDependend = 0;
2051
0
  int hasFading = 0;
2052
0
  int hasDucking = 0;
2053
0
  int selectedDrcSetIds;
2054
0
  int selectedDownmixIds;
2055
0
  FIXP_DBL mixingLevel = 0;
2056
0
  int albumMode = hSelProcInput->albumMode;
2057
0
  UCHAR* pDownmixIdRequested = hSelProcInput->downmixIdRequested;
2058
0
  FIXP_SGL boost = hSelProcInput->boost;
2059
0
  FIXP_SGL compress = hSelProcInput->compress;
2060
2061
0
  hSelProcOutput->numSelectedDrcSets = 1;
2062
0
  hSelProcOutput->selectedDrcSetIds[0] = pSelectionData->pInst->drcSetId;
2063
0
  hSelProcOutput->selectedDownmixIds[0] =
2064
0
      pSelectionData->pInst->drcApplyToDownmix == 1
2065
0
          ? pSelectionData->pInst->downmixId[0]
2066
0
          : 0;
2067
0
  hSelProcOutput->loudnessNormalizationGainDb =
2068
0
      pSelectionData->loudnessNormalizationGainDbAdjusted +
2069
0
      hSelProcInput->loudnessNormalizationGainModificationDb;
2070
0
  hSelProcOutput->outputPeakLevelDb = pSelectionData->outputPeakLevel;
2071
0
  hSelProcOutput->outputLoudness = pSelectionData->outputLoudness;
2072
2073
0
  hSelProcOutput->boost = boost;
2074
0
  hSelProcOutput->compress = compress;
2075
0
  hSelProcOutput->baseChannelCount =
2076
0
      hUniDrcConfig->channelLayout.baseChannelCount;
2077
0
  hSelProcOutput->targetChannelCount =
2078
0
      hUniDrcConfig->channelLayout.baseChannelCount;
2079
0
  hSelProcOutput->activeDownmixId =
2080
0
      pDownmixIdRequested[pSelectionData->downmixIdRequestIndex];
2081
2082
0
  _getMixingLevel(hLoudnessInfoSet, *pDownmixIdRequested,
2083
0
                  hSelProcOutput->selectedDrcSetIds[0], albumMode,
2084
0
                  &mixingLevel);
2085
0
  hSelProcOutput->mixingLevel = mixingLevel;
2086
2087
  /*dependent*/
2088
0
  if (pSelectionData->pInst->dependsOnDrcSetPresent) {
2089
0
    int dependsOnDrcSetID = pSelectionData->pInst->dependsOnDrcSet;
2090
2091
0
    for (i = 0; i < hUniDrcConfig->drcInstructionsCountInclVirtual; i++) {
2092
0
      DRC_INSTRUCTIONS_UNI_DRC* pInst =
2093
0
          &(hUniDrcConfig->drcInstructionsUniDrc[i]);
2094
0
      if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
2095
2096
0
      if (pInst->drcSetId == dependsOnDrcSetID) {
2097
0
        hSelProcOutput->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] =
2098
0
            hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId;
2099
0
        hSelProcOutput->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] =
2100
0
            hUniDrcConfig->drcInstructionsUniDrc[i].drcApplyToDownmix == 1
2101
0
                ? hUniDrcConfig->drcInstructionsUniDrc[i].downmixId[0]
2102
0
                : 0;
2103
0
        hSelProcOutput->numSelectedDrcSets++;
2104
0
        hasDependend = 1;
2105
0
        break;
2106
0
      }
2107
0
    }
2108
0
  }
2109
2110
  /* fading */
2111
0
  if (hSelProcInput->albumMode == 0) {
2112
0
    for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
2113
0
      DRC_INSTRUCTIONS_UNI_DRC* pInst =
2114
0
          &(hUniDrcConfig->drcInstructionsUniDrc[i]);
2115
0
      if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
2116
2117
0
      if (pInst->drcSetEffect & EB_FADE) {
2118
0
        if (pInst->downmixId[0] == DOWNMIX_ID_ANY_DOWNMIX) {
2119
0
          hSelProcOutput->numSelectedDrcSets = hasDependend + 1;
2120
0
          hSelProcOutput
2121
0
              ->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] =
2122
0
              hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId;
2123
0
          hSelProcOutput
2124
0
              ->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] =
2125
0
              hUniDrcConfig->drcInstructionsUniDrc[i].drcApplyToDownmix == 1
2126
0
                  ? hUniDrcConfig->drcInstructionsUniDrc[i].downmixId[0]
2127
0
                  : 0;
2128
0
          hSelProcOutput->numSelectedDrcSets++;
2129
0
          hasFading = 1;
2130
2131
0
        } else {
2132
0
          retVal = DRCDEC_SELECTION_PROCESS_NOT_OK;
2133
0
          if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2134
0
        }
2135
0
      }
2136
0
    }
2137
0
  }
2138
2139
  /* ducking */
2140
0
  for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
2141
0
    DRC_INSTRUCTIONS_UNI_DRC* pInst =
2142
0
        &(hUniDrcConfig->drcInstructionsUniDrc[i]);
2143
0
    if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
2144
2145
0
    if (pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) {
2146
0
      for (j = 0; j < pInst->downmixIdCount; j++) {
2147
0
        if (pInst->downmixId[j] == hSelProcOutput->activeDownmixId) {
2148
0
          hSelProcOutput->numSelectedDrcSets =
2149
0
              hasDependend + 1; /* ducking overrides fading */
2150
2151
0
          hSelProcOutput
2152
0
              ->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] =
2153
0
              hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId;
2154
          /* force ducking DRC set to be processed on base layout */
2155
0
          hSelProcOutput
2156
0
              ->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] = 0;
2157
0
          hSelProcOutput->numSelectedDrcSets++;
2158
0
          hasDucking = 1;
2159
0
        }
2160
0
      }
2161
0
    }
2162
0
  }
2163
2164
  /* repeat for DOWNMIX_ID_BASE_LAYOUT if no ducking found*/
2165
2166
0
  if (!hasDucking) {
2167
0
    for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) {
2168
0
      DRC_INSTRUCTIONS_UNI_DRC* pInst =
2169
0
          &(hUniDrcConfig->drcInstructionsUniDrc[i]);
2170
0
      if (!_drcSetIsUsable(hUniDrcConfig, pInst)) continue;
2171
2172
0
      if (pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) {
2173
0
        for (j = 0; j < pInst->downmixIdCount; j++) {
2174
0
          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
0
        }
2185
0
      }
2186
0
    }
2187
0
  }
2188
2189
0
  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
0
  if (hSelProcOutput->numSelectedDrcSets == 3) {
2198
0
    selectedDrcSetIds = hSelProcOutput->selectedDrcSetIds[0];
2199
0
    selectedDownmixIds = hSelProcOutput->selectedDownmixIds[0];
2200
0
    hSelProcOutput->selectedDrcSetIds[0] = hSelProcOutput->selectedDrcSetIds[2];
2201
0
    hSelProcOutput->selectedDownmixIds[0] =
2202
0
        hSelProcOutput->selectedDownmixIds[2];
2203
0
    hSelProcOutput->selectedDrcSetIds[2] = selectedDrcSetIds;
2204
0
    hSelProcOutput->selectedDownmixIds[2] = selectedDownmixIds;
2205
0
  } else if (hSelProcOutput->numSelectedDrcSets == 2) {
2206
0
    selectedDrcSetIds = hSelProcOutput->selectedDrcSetIds[0];
2207
0
    selectedDownmixIds = hSelProcOutput->selectedDownmixIds[0];
2208
0
    hSelProcOutput->selectedDrcSetIds[0] = hSelProcOutput->selectedDrcSetIds[1];
2209
0
    hSelProcOutput->selectedDownmixIds[0] =
2210
0
        hSelProcOutput->selectedDownmixIds[1];
2211
0
    hSelProcOutput->selectedDrcSetIds[1] = selectedDrcSetIds;
2212
0
    hSelProcOutput->selectedDownmixIds[1] = selectedDownmixIds;
2213
0
  }
2214
2215
0
  return retVal;
2216
0
}
2217
2218
static DRCDEC_SELECTION_PROCESS_RETURN _selectDownmixMatrix(
2219
    HANDLE_SEL_PROC_OUTPUT hSelProcOutput,
2220
0
    HANDLE_UNI_DRC_CONFIG hUniDrcConfig) {
2221
0
  int i;
2222
0
  hSelProcOutput->baseChannelCount =
2223
0
      hUniDrcConfig->channelLayout.baseChannelCount;
2224
0
  hSelProcOutput->targetChannelCount =
2225
0
      hUniDrcConfig->channelLayout.baseChannelCount;
2226
0
  hSelProcOutput->targetLayout = -1;
2227
0
  hSelProcOutput->downmixMatrixPresent = 0;
2228
2229
0
  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
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2264
0
}
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
0
    DRCDEC_SELECTION** ppCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) {
2271
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
2272
0
  int i, j;
2273
2274
0
  for (i = 0; i < hSelProcInput->numDownmixIdRequests; i++) {
2275
0
    for (j = 0; j < hUniDrcConfig->drcInstructionsCountInclVirtual; j++) {
2276
0
      DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction =
2277
0
          &(hUniDrcConfig->drcInstructionsUniDrc[j]);
2278
      /* check if ID is unique */
2279
0
      if (selectDrcInstructions(hUniDrcConfig, pDrcInstruction->drcSetId) !=
2280
0
          pDrcInstruction)
2281
0
        continue;
2282
2283
0
      retVal = _drcSetPreSelectionSingleInstruction(
2284
0
          hSelProcInput, i, hUniDrcConfig, hLoudnessInfoSet, pDrcInstruction,
2285
0
          *ppCandidatesPotential, *ppCandidatesSelected, codecMode);
2286
0
      if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2287
0
    }
2288
0
  }
2289
2290
0
  retVal = _preSelectionRequirement9(hSelProcInput, *ppCandidatesPotential,
2291
0
                                     *ppCandidatesSelected);
2292
0
  if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2293
2294
0
  if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) {
2295
0
    retVal = _drcSetSelectionAddCandidates(
2296
0
        hSelProcInput, *ppCandidatesPotential, *ppCandidatesSelected);
2297
0
    if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2298
0
  }
2299
2300
0
  return retVal;
2301
0
}
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
0
    DRCDEC_SELECTION** ppCandidatesSelected) {
2308
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal;
2309
0
  int i;
2310
2311
0
  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
0
  if (hSelProcInput->dynamicRangeControlOn) {
2317
0
    if (hSelProcInput->numDrcFeatureRequests == 0) {
2318
0
      retVal = _selectDrcSetEffectNone(hUniDrcConfig, *ppCandidatesPotential,
2319
0
                                       *ppCandidatesSelected);
2320
0
      if (retVal) return (retVal);
2321
2322
0
      if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) {
2323
0
        DRC_FEATURE_REQUEST fallbackRequest;
2324
0
        fallbackRequest.drcEffectType.numRequests = 5;
2325
0
        fallbackRequest.drcEffectType.numRequestsDesired = 5;
2326
0
        fallbackRequest.drcEffectType.request[0] = DETR_GENERAL_COMPR;
2327
0
        fallbackRequest.drcEffectType.request[1] = DETR_NIGHT;
2328
0
        fallbackRequest.drcEffectType.request[2] = DETR_NOISY;
2329
0
        fallbackRequest.drcEffectType.request[3] = DETR_LIMITED;
2330
0
        fallbackRequest.drcEffectType.request[4] = DETR_LOWLEVEL;
2331
2332
0
        retVal = _selectEffectTypeFeature(hUniDrcConfig, fallbackRequest,
2333
0
                                          ppCandidatesPotential,
2334
0
                                          ppCandidatesSelected);
2335
0
        if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK;
2336
0
      }
2337
2338
0
      _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected);
2339
0
    } 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
0
  }
2377
2378
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2379
0
}
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
0
    DRCDEC_SELECTION* pSelection) {
2429
0
  if (pSelection->numData < (12 + 1 + 6)) {
2430
0
    DRCDEC_SELECTION_DATA* pData = &(pSelection->data[pSelection->numData]);
2431
0
    FDKmemset(pData, 0, sizeof(DRCDEC_SELECTION_DATA));
2432
0
    pSelection->numData++;
2433
2434
0
    return pData;
2435
0
  } else {
2436
0
    return NULL;
2437
0
  }
2438
0
}
2439
2440
static DRCDEC_SELECTION_DATA* _drcdec_selection_add(
2441
0
    DRCDEC_SELECTION* pSelection, DRCDEC_SELECTION_DATA* pDataIn) {
2442
0
  if (pSelection->numData < (12 + 1 + 6)) {
2443
0
    DRCDEC_SELECTION_DATA* pData = &(pSelection->data[pSelection->numData]);
2444
0
    FDKmemcpy(pData, pDataIn, sizeof(DRCDEC_SELECTION_DATA));
2445
0
    pSelection->numData++;
2446
0
    return pData;
2447
0
  } else {
2448
0
    return NULL;
2449
0
  }
2450
0
}
2451
2452
0
static int _drcdec_selection_clear(DRCDEC_SELECTION* pSelection) {
2453
0
  return pSelection->numData = 0;
2454
0
}
2455
2456
0
static int _drcdec_selection_getNumber(DRCDEC_SELECTION* pSelection) {
2457
0
  return pSelection->numData;
2458
0
}
2459
2460
0
static int _drcdec_selection_setNumber(DRCDEC_SELECTION* pSelection, int num) {
2461
0
  if (num >= 0 && num < pSelection->numData) {
2462
0
    return pSelection->numData = num;
2463
0
  } else {
2464
0
    return pSelection->numData;
2465
0
  }
2466
0
}
2467
2468
static DRCDEC_SELECTION_DATA* _drcdec_selection_getAt(
2469
0
    DRCDEC_SELECTION* pSelection, int at) {
2470
0
  if (at >= 0 && at < (12 + 1 + 6)) {
2471
0
    return &(pSelection->data[at]);
2472
0
  } else {
2473
0
    return NULL;
2474
0
  }
2475
0
}
2476
2477
static int _swapSelectionAndClear(DRCDEC_SELECTION** ppCandidatesPotential,
2478
0
                                  DRCDEC_SELECTION** ppCandidatesSelected) {
2479
0
  DRCDEC_SELECTION* pTmp = *ppCandidatesPotential;
2480
0
  *ppCandidatesPotential = *ppCandidatesSelected;
2481
0
  *ppCandidatesSelected = pTmp;
2482
0
  _drcdec_selection_clear(*ppCandidatesSelected);
2483
0
  return 0;
2484
0
}
2485
2486
static int _swapSelection(DRCDEC_SELECTION** ppCandidatesPotential,
2487
0
                          DRCDEC_SELECTION** ppCandidatesSelected) {
2488
0
  DRCDEC_SELECTION* pTmp = *ppCandidatesPotential;
2489
0
  *ppCandidatesPotential = *ppCandidatesSelected;
2490
0
  *ppCandidatesSelected = pTmp;
2491
0
  return 0;
2492
0
}
2493
2494
/*******************************************/
2495
2496
static LOUDNESS_INFO* _getLoudnessInfoStructure(
2497
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int drcSetId, int downmixId,
2498
0
    int albumMode) {
2499
0
  int i, j;
2500
0
  int count;
2501
2502
0
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2503
2504
0
  if (albumMode) {
2505
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
2506
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
2507
0
  } else {
2508
0
    count = hLoudnessInfoSet->loudnessInfoCount;
2509
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
2510
0
  }
2511
2512
0
  for (i = 0; i < count; i++) {
2513
0
    if ((pLoudnessInfo[i].drcSetId == drcSetId) &&
2514
0
        (pLoudnessInfo[i].downmixId == downmixId)) {
2515
0
      for (j = 0; j < pLoudnessInfo[i].measurementCount; j++) {
2516
0
        if ((pLoudnessInfo[i].loudnessMeasurement[j].methodDefinition == 1) ||
2517
0
            (pLoudnessInfo[i].loudnessMeasurement[j].methodDefinition == 2)) {
2518
0
          return &pLoudnessInfo[i];
2519
0
        }
2520
0
      }
2521
0
    }
2522
0
  }
2523
2524
0
  return NULL;
2525
0
}
2526
2527
static LOUDNESS_INFO* _getApplicableLoudnessInfoStructure(
2528
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int drcSetId,
2529
0
    int downmixIdRequested, int albumMode) {
2530
0
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2531
2532
  /* default value */
2533
0
  pLoudnessInfo = _getLoudnessInfoStructure(hLoudnessInfoSet, drcSetId,
2534
0
                                            downmixIdRequested, albumMode);
2535
2536
  /* fallback values */
2537
0
  if (pLoudnessInfo == NULL) {
2538
0
    pLoudnessInfo =
2539
0
        _getLoudnessInfoStructure(hLoudnessInfoSet, drcSetId, 0x7F, albumMode);
2540
0
  }
2541
2542
0
  if (pLoudnessInfo == NULL) {
2543
0
    pLoudnessInfo = _getLoudnessInfoStructure(hLoudnessInfoSet, 0x3F,
2544
0
                                              downmixIdRequested, albumMode);
2545
0
  }
2546
2547
0
  if (pLoudnessInfo == NULL) {
2548
0
    pLoudnessInfo = _getLoudnessInfoStructure(hLoudnessInfoSet, 0,
2549
0
                                              downmixIdRequested, albumMode);
2550
0
  }
2551
2552
0
  if (pLoudnessInfo == NULL) {
2553
0
    pLoudnessInfo =
2554
0
        _getLoudnessInfoStructure(hLoudnessInfoSet, 0x3F, 0x7F, albumMode);
2555
0
  }
2556
2557
0
  if (pLoudnessInfo == NULL) {
2558
0
    pLoudnessInfo =
2559
0
        _getLoudnessInfoStructure(hLoudnessInfoSet, 0, 0x7F, albumMode);
2560
0
  }
2561
2562
0
  if (pLoudnessInfo == NULL) {
2563
0
    pLoudnessInfo =
2564
0
        _getLoudnessInfoStructure(hLoudnessInfoSet, drcSetId, 0, albumMode);
2565
0
  }
2566
2567
0
  if (pLoudnessInfo == NULL) {
2568
0
    pLoudnessInfo =
2569
0
        _getLoudnessInfoStructure(hLoudnessInfoSet, 0x3F, 0, albumMode);
2570
0
  }
2571
2572
0
  if (pLoudnessInfo == NULL) {
2573
0
    pLoudnessInfo =
2574
0
        _getLoudnessInfoStructure(hLoudnessInfoSet, 0, 0, albumMode);
2575
0
  }
2576
2577
0
  return pLoudnessInfo;
2578
0
}
2579
2580
/*******************************************/
2581
2582
typedef struct {
2583
  FIXP_DBL value;
2584
  int order;
2585
} VALUE_ORDER;
2586
2587
0
void _initValueOrder(VALUE_ORDER* pValue) {
2588
0
  pValue->value = (FIXP_DBL)0;
2589
0
  pValue->order = -1;
2590
0
}
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
0
    int measurementSystemRequested) {
2609
0
  const int rows = 11;
2610
0
  const int columns = 12;
2611
0
  const int pOrdering[rows][columns] = {
2612
0
      {0, 0, 8, 0, 1, 3, 0, 5, 6, 7, 4, 2}, /* default = bonus1770 */
2613
0
      {0, 0, 8, 0, 1, 3, 0, 5, 6, 7, 4, 2}, /* bonus1770 */
2614
0
      {0, 0, 1, 0, 8, 5, 0, 2, 3, 4, 6, 7}, /* bonusUser */
2615
0
      {0, 0, 3, 0, 1, 8, 0, 4, 5, 6, 7, 2}, /* bonusExpert */
2616
0
      {0, 0, 5, 0, 1, 3, 0, 8, 6, 7, 4, 2}, /* ResA */
2617
0
      {0, 0, 5, 0, 1, 3, 0, 6, 8, 7, 4, 2}, /* ResB */
2618
0
      {0, 0, 5, 0, 1, 3, 0, 6, 7, 8, 4, 2}, /* ResC */
2619
0
      {0, 0, 3, 0, 1, 7, 0, 4, 5, 6, 8, 2}, /* ResD */
2620
0
      {0, 0, 1, 0, 7, 5, 0, 2, 3, 4, 6, 8}, /* ResE */
2621
0
      {0, 0, 1, 0, 0, 0, 0, 2, 3, 4, 0, 0}, /* ProgramLoudness */
2622
0
      {0, 7, 0, 0, 0, 0, 6, 5, 4, 3, 2, 1}  /* PeakLoudness */
2623
0
  };
2624
2625
0
  if (measurementSystemRequested < 0 || measurementSystemRequested >= rows ||
2626
0
      measurementSystem < 0 || measurementSystem >= columns) {
2627
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
2628
0
  }
2629
2630
0
  if (pOrdering[measurementSystemRequested][measurementSystem] >
2631
0
      pValueOrder->order) {
2632
0
    pValueOrder->order =
2633
0
        pOrdering[measurementSystemRequested][measurementSystem];
2634
0
    pValueOrder->value = value;
2635
0
  }
2636
2637
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2638
0
}
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
0
{
2651
0
  int index;
2652
2653
0
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2654
0
  VALUE_ORDER valueOrder;
2655
2656
  /* map MDR_DEFAULT to MDR_PROGRAM_LOUDNESS */
2657
0
  METHOD_DEFINITION_REQUEST requestedMethodDefinition =
2658
0
      measurementMethodRequested < MDR_ANCHOR_LOUDNESS ? MDR_PROGRAM_LOUDNESS
2659
0
                                                       : MDR_ANCHOR_LOUDNESS;
2660
2661
0
  if (measurementMethodRequested > MDR_ANCHOR_LOUDNESS) {
2662
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
2663
0
  }
2664
2665
0
  _initValueOrder(&valueOrder);
2666
2667
0
  *pLoudness = UNDEFINED_LOUDNESS_VALUE;
2668
0
  *pLoudnessNormalizationGain = (FIXP_DBL)0;
2669
2670
0
  if (drcSetId < 0) {
2671
0
    drcSetId = 0;
2672
0
  }
2673
2674
0
  pLoudnessInfo = _getApplicableLoudnessInfoStructure(
2675
0
      hLoudnessInfoSet, drcSetId, downmixIdRequested, albumMode);
2676
2677
0
  if (albumMode && (pLoudnessInfo == NULL)) {
2678
0
    pLoudnessInfo = _getApplicableLoudnessInfoStructure(
2679
0
        hLoudnessInfoSet, drcSetId, downmixIdRequested, 0);
2680
0
  }
2681
2682
0
  if (pLoudnessInfo == NULL) {
2683
0
    return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2684
0
  }
2685
2686
0
  index = -1;
2687
2688
0
  do {
2689
0
    index = _findMethodDefinition(pLoudnessInfo, requestedMethodDefinition,
2690
0
                                  index + 1);
2691
2692
0
    if (index >= 0) {
2693
0
      _getMethodValue(
2694
0
          &valueOrder, pLoudnessInfo->loudnessMeasurement[index].methodValue,
2695
0
          pLoudnessInfo->loudnessMeasurement[index].measurementSystem,
2696
0
          measurementSystemRequested);
2697
0
    }
2698
0
  } while (index >= 0);
2699
2700
  /* repeat with other method definition */
2701
0
  if (valueOrder.order == -1) {
2702
0
    index = -1;
2703
2704
0
    do {
2705
0
      index = _findMethodDefinition(
2706
0
          pLoudnessInfo,
2707
0
          requestedMethodDefinition == MDR_PROGRAM_LOUDNESS
2708
0
              ? MDR_ANCHOR_LOUDNESS
2709
0
              : MDR_PROGRAM_LOUDNESS,
2710
0
          index + 1);
2711
2712
0
      if (index >= 0) {
2713
0
        _getMethodValue(
2714
0
            &valueOrder, pLoudnessInfo->loudnessMeasurement[index].methodValue,
2715
0
            pLoudnessInfo->loudnessMeasurement[index].measurementSystem,
2716
0
            measurementSystemRequested);
2717
0
      }
2718
0
    } while (index >= 0);
2719
0
  }
2720
2721
0
  if (valueOrder.order == -1) {
2722
0
    return DRCDEC_SELECTION_PROCESS_NOT_OK;
2723
0
  } else {
2724
0
    *pLoudnessNormalizationGain = targetLoudness - valueOrder.value;
2725
0
    *pLoudness = valueOrder.value;
2726
0
  }
2727
2728
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2729
0
}
2730
2731
/*******************************************/
2732
2733
static int _truePeakLevelIsPresent(HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
2734
0
                                   int drcSetId, int downmixId, int albumMode) {
2735
0
  int i;
2736
0
  int count;
2737
0
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2738
2739
0
  if (albumMode) {
2740
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
2741
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
2742
0
  } else {
2743
0
    count = hLoudnessInfoSet->loudnessInfoCount;
2744
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
2745
0
  }
2746
2747
0
  for (i = 0; i < count; i++) {
2748
0
    if ((pLoudnessInfo[i].drcSetId == drcSetId) &&
2749
0
        (pLoudnessInfo[i].downmixId == downmixId)) {
2750
0
      if (pLoudnessInfo[i].truePeakLevelPresent) return 1;
2751
0
    }
2752
0
  }
2753
2754
0
  return 0;
2755
0
}
2756
2757
static DRCDEC_SELECTION_PROCESS_RETURN _getTruePeakLevel(
2758
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int drcSetId, int downmixId,
2759
0
    int albumMode, FIXP_DBL* pTruePeakLevel) {
2760
0
  int i;
2761
0
  int count;
2762
0
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2763
2764
0
  if (albumMode) {
2765
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
2766
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
2767
0
  } else {
2768
0
    count = hLoudnessInfoSet->loudnessInfoCount;
2769
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
2770
0
  }
2771
2772
0
  for (i = 0; i < count; i++) {
2773
0
    if ((pLoudnessInfo[i].drcSetId == drcSetId) &&
2774
0
        (pLoudnessInfo[i].downmixId == downmixId)) {
2775
0
      if (pLoudnessInfo[i].truePeakLevelPresent) {
2776
0
        *pTruePeakLevel = pLoudnessInfo[i].truePeakLevel;
2777
0
        return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2778
0
      }
2779
0
    }
2780
0
  }
2781
2782
0
  return DRCDEC_SELECTION_PROCESS_NOT_OK;
2783
0
}
2784
2785
static int _samplePeakLevelIsPresent(HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet,
2786
                                     int drcSetId, int downmixId,
2787
0
                                     int albumMode) {
2788
0
  int i;
2789
0
  int count;
2790
0
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2791
2792
0
  if (albumMode) {
2793
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
2794
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
2795
0
  } else {
2796
0
    count = hLoudnessInfoSet->loudnessInfoCount;
2797
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
2798
0
  }
2799
2800
0
  for (i = 0; i < count; i++) {
2801
0
    if ((pLoudnessInfo[i].drcSetId == drcSetId) &&
2802
0
        (pLoudnessInfo[i].downmixId == downmixId)) {
2803
0
      if (pLoudnessInfo[i].samplePeakLevelPresent) return 1;
2804
0
    }
2805
0
  }
2806
2807
0
  return 0;
2808
0
}
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
0
) {
2814
0
  int i;
2815
0
  int count;
2816
0
  LOUDNESS_INFO* pLoudnessInfo = NULL;
2817
2818
0
  if (albumMode) {
2819
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
2820
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
2821
0
  } else {
2822
0
    count = hLoudnessInfoSet->loudnessInfoCount;
2823
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
2824
0
  }
2825
2826
0
  for (i = 0; i < count; i++) {
2827
0
    if ((pLoudnessInfo[i].drcSetId == drcSetId) &&
2828
0
        (pLoudnessInfo[i].downmixId == downmixId)) {
2829
0
      if (pLoudnessInfo[i].samplePeakLevelPresent) {
2830
0
        *pSamplePeakLevel = pLoudnessInfo[i].samplePeakLevel;
2831
0
        return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2832
0
      }
2833
0
    }
2834
0
  }
2835
2836
0
  return DRCDEC_SELECTION_PROCESS_NOT_OK;
2837
0
}
2838
2839
static int _limiterPeakTargetIsPresent(
2840
0
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction, int drcSetId, int downmixId) {
2841
0
  int i;
2842
2843
0
  if (pDrcInstruction->limiterPeakTargetPresent) {
2844
0
    if ((pDrcInstruction->downmixId[0] == downmixId) ||
2845
0
        (pDrcInstruction->downmixId[0] == 0x7F)) {
2846
0
      return 1;
2847
0
    }
2848
2849
0
    for (i = 0; i < pDrcInstruction->downmixIdCount; i++) {
2850
0
      if (pDrcInstruction->downmixId[i] == downmixId) {
2851
0
        return 1;
2852
0
      }
2853
0
    }
2854
0
  }
2855
2856
0
  return 0;
2857
0
}
2858
2859
static DRCDEC_SELECTION_PROCESS_RETURN _getLimiterPeakTarget(
2860
    DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction, int drcSetId, int downmixId,
2861
0
    FIXP_DBL* pLimiterPeakTarget) {
2862
0
  int i;
2863
2864
0
  if (pDrcInstruction->limiterPeakTargetPresent) {
2865
0
    if ((pDrcInstruction->downmixId[0] == downmixId) ||
2866
0
        (pDrcInstruction->downmixId[0] == 0x7F)) {
2867
0
      *pLimiterPeakTarget =
2868
0
          ((FX_SGL2FX_DBL(pDrcInstruction->limiterPeakTarget) >> 2));
2869
0
      return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2870
0
    }
2871
2872
0
    for (i = 0; i < pDrcInstruction->downmixIdCount; i++) {
2873
0
      if (pDrcInstruction->downmixId[i] == downmixId) {
2874
0
        *pLimiterPeakTarget =
2875
0
            ((FX_SGL2FX_DBL(pDrcInstruction->limiterPeakTarget) >> 2));
2876
0
        return DRCDEC_SELECTION_PROCESS_NO_ERROR;
2877
0
      }
2878
0
    }
2879
0
  }
2880
2881
0
  return DRCDEC_SELECTION_PROCESS_NOT_OK;
2882
0
}
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
0
) {
2911
0
  DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR;
2912
2913
0
  int albumMode = hSelProcInput->albumMode;
2914
2915
0
  FIXP_DBL signalPeakLevelTmp = (FIXP_DBL)0;
2916
0
  FIXP_DBL signalPeakLevel = FIXP_DBL(0);
2917
2918
0
  int dmxId = downmixIdRequested;
2919
2920
0
  int drcSetId = pInst->drcSetId;
2921
2922
0
  if (drcSetId < 0) {
2923
0
    drcSetId = 0;
2924
0
  }
2925
2926
0
  *explicitPeakInformationPresent = 1;
2927
2928
0
  if (_truePeakLevelIsPresent(hLoudnessInfoSet, drcSetId, dmxId, albumMode)) {
2929
0
    retVal = _getTruePeakLevel(hLoudnessInfoSet, drcSetId, dmxId, albumMode,
2930
0
                               &signalPeakLevel);
2931
0
    if (retVal) return (retVal);
2932
0
  } else if (_samplePeakLevelIsPresent(hLoudnessInfoSet, drcSetId, dmxId,
2933
0
                                       albumMode)) {
2934
0
    retVal = _getSamplePeakLevel(hLoudnessInfoSet, drcSetId, dmxId, albumMode,
2935
0
                                 &signalPeakLevel);
2936
0
    if (retVal) return (retVal);
2937
0
  } else if (_truePeakLevelIsPresent(hLoudnessInfoSet, 0x3F, dmxId,
2938
0
                                     albumMode)) {
2939
0
    retVal = _getTruePeakLevel(hLoudnessInfoSet, 0x3F, dmxId, albumMode,
2940
0
                               &signalPeakLevel);
2941
0
    if (retVal) return (retVal);
2942
0
  } else if (_samplePeakLevelIsPresent(hLoudnessInfoSet, 0x3F, dmxId,
2943
0
                                       albumMode)) {
2944
0
    retVal = _getSamplePeakLevel(hLoudnessInfoSet, 0x3F, dmxId, albumMode,
2945
0
                                 &signalPeakLevel);
2946
0
    if (retVal) return (retVal);
2947
0
  } else if (_limiterPeakTargetIsPresent(pInst, drcSetId, dmxId)) {
2948
0
    retVal = _getLimiterPeakTarget(pInst, drcSetId, dmxId, &signalPeakLevel);
2949
0
    if (retVal) return (retVal);
2950
0
  } 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
0
  } else {
3018
0
    signalPeakLevel = FIXP_DBL(0); /* worst case estimate */
3019
0
    *explicitPeakInformationPresent = FIXP_DBL(0);
3020
0
  }
3021
3022
0
  *signalPeakLevelOut = signalPeakLevel;
3023
3024
0
  return retVal;
3025
0
}
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
0
                                 int methodDefinition, int startIndex) {
3109
0
  int i;
3110
0
  int index = -1;
3111
3112
0
  for (i = startIndex; i < pLoudnessInfo->measurementCount; i++) {
3113
0
    if (pLoudnessInfo->loudnessMeasurement[i].methodDefinition ==
3114
0
        methodDefinition) {
3115
0
      index = i;
3116
0
      break;
3117
0
    }
3118
0
  }
3119
3120
0
  return index;
3121
0
}
3122
3123
/*******************************************/
3124
3125
static DRCDEC_SELECTION_PROCESS_RETURN _getMixingLevel(
3126
    HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int downmixIdRequested,
3127
0
    int drcSetIdRequested, int albumMode, FIXP_DBL* pMixingLevel) {
3128
0
  const FIXP_DBL mixingLevelDefault = FL2FXCONST_DBL(85.0f / (float)(1 << 7));
3129
3130
0
  int i;
3131
0
  int count;
3132
3133
0
  LOUDNESS_INFO* pLoudnessInfo = NULL;
3134
3135
0
  *pMixingLevel = mixingLevelDefault;
3136
3137
0
  if (drcSetIdRequested < 0) {
3138
0
    drcSetIdRequested = 0;
3139
0
  }
3140
3141
0
  if (albumMode) {
3142
0
    count = hLoudnessInfoSet->loudnessInfoAlbumCount;
3143
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum;
3144
0
  } else {
3145
0
    count = hLoudnessInfoSet->loudnessInfoCount;
3146
0
    pLoudnessInfo = hLoudnessInfoSet->loudnessInfo;
3147
0
  }
3148
3149
0
  for (i = 0; i < count; i++) {
3150
0
    if ((drcSetIdRequested == pLoudnessInfo[i].drcSetId) &&
3151
0
        ((downmixIdRequested == pLoudnessInfo[i].downmixId) ||
3152
0
         (DOWNMIX_ID_ANY_DOWNMIX == pLoudnessInfo[i].downmixId))) {
3153
0
      int index = _findMethodDefinition(&pLoudnessInfo[i], MD_MIXING_LEVEL, 0);
3154
3155
0
      if (index >= 0) {
3156
0
        *pMixingLevel = pLoudnessInfo[i].loudnessMeasurement[index].methodValue;
3157
0
        break;
3158
0
      }
3159
0
    }
3160
0
  }
3161
3162
0
  return DRCDEC_SELECTION_PROCESS_NO_ERROR;
3163
0
}
3164
3165
/*******************************************/