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