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