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