diff options
Diffstat (limited to 'libDRCdec/src')
-rw-r--r-- | libDRCdec/src/FDK_drcDecLib.cpp | 891 | ||||
-rw-r--r-- | libDRCdec/src/drcDec_gainDecoder.cpp | 445 | ||||
-rw-r--r-- | libDRCdec/src/drcDec_gainDecoder.h | 264 | ||||
-rw-r--r-- | libDRCdec/src/drcDec_reader.cpp | 2027 | ||||
-rw-r--r-- | libDRCdec/src/drcDec_reader.h | 130 | ||||
-rw-r--r-- | libDRCdec/src/drcDec_rom.cpp | 323 | ||||
-rw-r--r-- | libDRCdec/src/drcDec_rom.h | 120 | ||||
-rw-r--r-- | libDRCdec/src/drcDec_selectionProcess.cpp | 3083 | ||||
-rw-r--r-- | libDRCdec/src/drcDec_selectionProcess.h | 217 | ||||
-rw-r--r-- | libDRCdec/src/drcDec_tools.cpp | 371 | ||||
-rw-r--r-- | libDRCdec/src/drcDec_tools.h | 146 | ||||
-rw-r--r-- | libDRCdec/src/drcDec_types.h | 428 | ||||
-rw-r--r-- | libDRCdec/src/drcDecoder.h | 142 | ||||
-rw-r--r-- | libDRCdec/src/drcGainDec_init.cpp | 344 | ||||
-rw-r--r-- | libDRCdec/src/drcGainDec_init.h | 120 | ||||
-rw-r--r-- | libDRCdec/src/drcGainDec_preprocess.cpp | 714 | ||||
-rw-r--r-- | libDRCdec/src/drcGainDec_preprocess.h | 111 | ||||
-rw-r--r-- | libDRCdec/src/drcGainDec_process.cpp | 532 | ||||
-rw-r--r-- | libDRCdec/src/drcGainDec_process.h | 119 |
19 files changed, 10527 insertions, 0 deletions
diff --git a/libDRCdec/src/FDK_drcDecLib.cpp b/libDRCdec/src/FDK_drcDecLib.cpp new file mode 100644 index 0000000..b29b79d --- /dev/null +++ b/libDRCdec/src/FDK_drcDecLib.cpp @@ -0,0 +1,891 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): Bernhard Neugebauer + + Description: MPEG-D DRC Decoder + +*******************************************************************************/ + +#include "drcDec_reader.h" +#include "drcDec_gainDecoder.h" +#include "FDK_drcDecLib.h" + +#include "drcDec_selectionProcess.h" +#include "drcDec_tools.h" + +/* Decoder library info */ +#define DRCDEC_LIB_VL0 2 +#define DRCDEC_LIB_VL1 1 +#define DRCDEC_LIB_VL2 0 +#define DRCDEC_LIB_TITLE "MPEG-D DRC Decoder Lib" +#ifdef __ANDROID__ +#define DRCDEC_LIB_BUILD_DATE "" +#define DRCDEC_LIB_BUILD_TIME "" +#else +#define DRCDEC_LIB_BUILD_DATE __DATE__ +#define DRCDEC_LIB_BUILD_TIME __TIME__ +#endif + +typedef enum { + DRC_DEC_NOT_INITIALIZED = 0, + DRC_DEC_INITIALIZED, + DRC_DEC_NEW_GAIN_PAYLOAD, + DRC_DEC_INTERPOLATION_PREPARED +} DRC_DEC_STATUS; + +struct s_drc_decoder { + DRC_DEC_CODEC_MODE codecMode; + DRC_DEC_FUNCTIONAL_RANGE functionalRange; + DRC_DEC_STATUS status; + + /* handles of submodules */ + HANDLE_DRC_GAIN_DECODER hGainDec; + HANDLE_DRC_SELECTION_PROCESS hSelectionProc; + int selProcInputDiff; + + /* data structs */ + UNI_DRC_CONFIG uniDrcConfig; + LOUDNESS_INFO_SET loudnessInfoSet; + UNI_DRC_GAIN uniDrcGain; + + SEL_PROC_OUTPUT selProcOutput; +} DRC_DECODER; + +static int isResetNeeded(HANDLE_DRC_DECODER hDrcDec, + const SEL_PROC_OUTPUT oldSelProcOutput) { + int i, resetNeeded = 0; + + if (hDrcDec->selProcOutput.numSelectedDrcSets != + oldSelProcOutput.numSelectedDrcSets) { + resetNeeded = 1; + } else { + for (i = 0; i < hDrcDec->selProcOutput.numSelectedDrcSets; i++) { + if (hDrcDec->selProcOutput.selectedDrcSetIds[i] != + oldSelProcOutput.selectedDrcSetIds[i]) + resetNeeded = 1; + if (hDrcDec->selProcOutput.selectedDownmixIds[i] != + oldSelProcOutput.selectedDownmixIds[i]) + resetNeeded = 1; + } + } + + if (hDrcDec->selProcOutput.boost != oldSelProcOutput.boost) resetNeeded = 1; + if (hDrcDec->selProcOutput.compress != oldSelProcOutput.compress) + resetNeeded = 1; + + /* Note: Changes in downmix matrix are not caught, as they don't affect the + * DRC gain decoder */ + + return resetNeeded; +} + +static DRC_DEC_ERROR startSelectionProcess(HANDLE_DRC_DECODER hDrcDec) { + DRC_ERROR dErr = DE_OK; + DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR; + int uniDrcConfigHasChanged = 0; + SEL_PROC_OUTPUT oldSelProcOutput = hDrcDec->selProcOutput; + + if (!hDrcDec->status) return DRC_DEC_NOT_READY; + + if (hDrcDec->functionalRange & DRC_DEC_SELECTION) { + uniDrcConfigHasChanged = hDrcDec->uniDrcConfig.diff; + if (hDrcDec->uniDrcConfig.diff || hDrcDec->loudnessInfoSet.diff || + hDrcDec->selProcInputDiff) { + /* in case of an error, signal that selection process was not successful + */ + hDrcDec->selProcOutput.numSelectedDrcSets = 0; + + sErr = drcDec_SelectionProcess_Process( + hDrcDec->hSelectionProc, &(hDrcDec->uniDrcConfig), + &(hDrcDec->loudnessInfoSet), &(hDrcDec->selProcOutput)); + if (sErr) return DRC_DEC_OK; + + hDrcDec->selProcInputDiff = 0; + hDrcDec->uniDrcConfig.diff = 0; + hDrcDec->loudnessInfoSet.diff = 0; + } + } + + if (hDrcDec->functionalRange & DRC_DEC_GAIN) { + if (isResetNeeded(hDrcDec, oldSelProcOutput) || uniDrcConfigHasChanged) { + dErr = + drcDec_GainDecoder_Config(hDrcDec->hGainDec, &(hDrcDec->uniDrcConfig), + hDrcDec->selProcOutput.numSelectedDrcSets, + hDrcDec->selProcOutput.selectedDrcSetIds, + hDrcDec->selProcOutput.selectedDownmixIds); + if (dErr) return DRC_DEC_OK; + } + } + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_Open(HANDLE_DRC_DECODER* phDrcDec, + const DRC_DEC_FUNCTIONAL_RANGE functionalRange) { + DRC_ERROR dErr = DE_OK; + DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR; + HANDLE_DRC_DECODER hDrcDec; + + *phDrcDec = (HANDLE_DRC_DECODER)FDKcalloc(1, sizeof(DRC_DECODER)); + if (!*phDrcDec) return DRC_DEC_OUT_OF_MEMORY; + hDrcDec = *phDrcDec; + + hDrcDec->functionalRange = functionalRange; + + hDrcDec->status = DRC_DEC_NOT_INITIALIZED; + hDrcDec->codecMode = DRC_DEC_CODEC_MODE_UNDEFINED; + + if (hDrcDec->functionalRange & DRC_DEC_SELECTION) { + sErr = drcDec_SelectionProcess_Create(&(hDrcDec->hSelectionProc)); + if (sErr) return DRC_DEC_OUT_OF_MEMORY; + sErr = drcDec_SelectionProcess_Init(hDrcDec->hSelectionProc); + if (sErr) return DRC_DEC_NOT_OK; + hDrcDec->selProcInputDiff = 1; + } + + if (hDrcDec->functionalRange & DRC_DEC_GAIN) { + dErr = drcDec_GainDecoder_Open(&(hDrcDec->hGainDec)); + if (dErr) return DRC_DEC_OUT_OF_MEMORY; + } + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_SetCodecMode(HANDLE_DRC_DECODER hDrcDec, + const DRC_DEC_CODEC_MODE codecMode) { + DRC_ERROR dErr = DE_OK; + DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + + if (hDrcDec->codecMode == + DRC_DEC_CODEC_MODE_UNDEFINED) { /* Set codec mode, if it is set for the + first time */ + hDrcDec->codecMode = codecMode; + + if (hDrcDec->functionalRange & DRC_DEC_SELECTION) { + sErr = drcDec_SelectionProcess_SetCodecMode( + hDrcDec->hSelectionProc, (SEL_PROC_CODEC_MODE)codecMode); + if (sErr) return DRC_DEC_NOT_OK; + hDrcDec->selProcInputDiff = 1; + } + + if (hDrcDec->functionalRange & DRC_DEC_GAIN) { + DELAY_MODE delayMode; + int timeDomainSupported; + SUBBAND_DOMAIN_MODE subbandDomainSupported; + + switch (hDrcDec->codecMode) { + case DRC_DEC_MPEG_4_AAC: + case DRC_DEC_MPEG_D_USAC: + case DRC_DEC_MPEG_H_3DA: + default: + delayMode = DM_REGULAR_DELAY; + } + + switch (hDrcDec->codecMode) { + case DRC_DEC_MPEG_4_AAC: + case DRC_DEC_MPEG_D_USAC: + timeDomainSupported = 1; + subbandDomainSupported = SDM_OFF; + break; + case DRC_DEC_MPEG_H_3DA: + timeDomainSupported = 1; + subbandDomainSupported = SDM_STFT256; + break; + + case DRC_DEC_TEST_TIME_DOMAIN: + timeDomainSupported = 1; + subbandDomainSupported = SDM_OFF; + break; + case DRC_DEC_TEST_QMF_DOMAIN: + timeDomainSupported = 0; + subbandDomainSupported = SDM_QMF64; + break; + case DRC_DEC_TEST_STFT_DOMAIN: + timeDomainSupported = 0; + subbandDomainSupported = SDM_STFT256; + break; + + default: + timeDomainSupported = 0; + subbandDomainSupported = SDM_OFF; + } + + dErr = drcDec_GainDecoder_SetCodecDependentParameters( + hDrcDec->hGainDec, delayMode, timeDomainSupported, + subbandDomainSupported); + if (dErr) return DRC_DEC_NOT_OK; + } + } + + /* Don't allow changing codecMode if it has already been set. */ + if (hDrcDec->codecMode != codecMode) return DRC_DEC_NOT_OK; + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_Init(HANDLE_DRC_DECODER hDrcDec, const int frameSize, + const int sampleRate, const int baseChannelCount) { + DRC_ERROR dErr = DE_OK; + DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + if (hDrcDec == NULL || frameSize == 0 || sampleRate == 0 || + baseChannelCount == 0) + return DRC_DEC_OK; /* return without doing anything */ + + if (hDrcDec->functionalRange & DRC_DEC_SELECTION) { + sErr = drcDec_SelectionProcess_SetParam( + hDrcDec->hSelectionProc, SEL_PROC_BASE_CHANNEL_COUNT, + (FIXP_DBL)baseChannelCount, &(hDrcDec->selProcInputDiff)); + if (sErr) return DRC_DEC_NOT_OK; + sErr = drcDec_SelectionProcess_SetParam( + hDrcDec->hSelectionProc, SEL_PROC_SAMPLE_RATE, (FIXP_DBL)sampleRate, + &(hDrcDec->selProcInputDiff)); + if (sErr) return DRC_DEC_NOT_OK; + } + + if (hDrcDec->functionalRange & DRC_DEC_GAIN) { + dErr = drcDec_GainDecoder_Init(hDrcDec->hGainDec, frameSize, sampleRate); + if (dErr) return DRC_DEC_NOT_OK; + } + + hDrcDec->status = DRC_DEC_INITIALIZED; + + startSelectionProcess(hDrcDec); + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_Close(HANDLE_DRC_DECODER* phDrcDec) { + HANDLE_DRC_DECODER hDrcDec; + + if (phDrcDec == NULL) { + return DRC_DEC_OK; + } + + hDrcDec = *phDrcDec; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + + if (hDrcDec->functionalRange & DRC_DEC_GAIN) { + drcDec_GainDecoder_Close(&(hDrcDec->hGainDec)); + } + + if (hDrcDec->functionalRange & DRC_DEC_SELECTION) { + drcDec_SelectionProcess_Delete(&(hDrcDec->hSelectionProc)); + } + + FDKfree(*phDrcDec); + *phDrcDec = NULL; + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_SetParam(HANDLE_DRC_DECODER hDrcDec, + const DRC_DEC_USERPARAM requestType, + const FIXP_DBL requestValue) { + DRCDEC_SELECTION_PROCESS_RETURN sErr = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + + if (hDrcDec->functionalRange == DRC_DEC_GAIN) + return DRC_DEC_NOT_OK; /* not supported for DRC_DEC_GAIN. All parameters are + handed over to selection process lib. */ + + switch (requestType) { + case DRC_DEC_BOOST: + sErr = drcDec_SelectionProcess_SetParam(hDrcDec->hSelectionProc, + SEL_PROC_BOOST, requestValue, + &(hDrcDec->selProcInputDiff)); + if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE; + break; + case DRC_DEC_COMPRESS: + sErr = drcDec_SelectionProcess_SetParam(hDrcDec->hSelectionProc, + SEL_PROC_COMPRESS, requestValue, + &(hDrcDec->selProcInputDiff)); + if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE; + break; + case DRC_DEC_LOUDNESS_NORMALIZATION_ON: + sErr = drcDec_SelectionProcess_SetParam( + hDrcDec->hSelectionProc, SEL_PROC_LOUDNESS_NORMALIZATION_ON, + requestValue, &(hDrcDec->selProcInputDiff)); + if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE; + break; + case DRC_DEC_TARGET_LOUDNESS: + sErr = drcDec_SelectionProcess_SetParam( + hDrcDec->hSelectionProc, SEL_PROC_TARGET_LOUDNESS, requestValue, + &(hDrcDec->selProcInputDiff)); + if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE; + break; + case DRC_DEC_EFFECT_TYPE: + sErr = drcDec_SelectionProcess_SetParam( + hDrcDec->hSelectionProc, SEL_PROC_EFFECT_TYPE, requestValue, + &(hDrcDec->selProcInputDiff)); + if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE; + break; + case DRC_DEC_DOWNMIX_ID: + sErr = drcDec_SelectionProcess_SetParam(hDrcDec->hSelectionProc, + SEL_PROC_DOWNMIX_ID, requestValue, + &(hDrcDec->selProcInputDiff)); + if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE; + break; + case DRC_DEC_TARGET_CHANNEL_COUNT_REQUESTED: + sErr = drcDec_SelectionProcess_SetParam( + hDrcDec->hSelectionProc, SEL_PROC_TARGET_CHANNEL_COUNT, requestValue, + &(hDrcDec->selProcInputDiff)); + if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE; + break; + case DRC_DEC_BASE_CHANNEL_COUNT: + sErr = drcDec_SelectionProcess_SetParam( + hDrcDec->hSelectionProc, SEL_PROC_BASE_CHANNEL_COUNT, requestValue, + &(hDrcDec->selProcInputDiff)); + if (sErr) return DRC_DEC_NOT_OK; + break; + case DRC_DEC_LOUDNESS_MEASUREMENT_METHOD: + sErr = drcDec_SelectionProcess_SetParam( + hDrcDec->hSelectionProc, SEL_PROC_LOUDNESS_MEASUREMENT_METHOD, + requestValue, &(hDrcDec->selProcInputDiff)); + if (sErr) return DRC_DEC_PARAM_OUT_OF_RANGE; + break; + default: + return DRC_DEC_INVALID_PARAM; + } + + /* All parameters need a new start of the selection process */ + startSelectionProcess(hDrcDec); + + return DRC_DEC_OK; +} + +LONG FDK_drcDec_GetParam(HANDLE_DRC_DECODER hDrcDec, + const DRC_DEC_USERPARAM requestType) { + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + + switch (requestType) { + case DRC_DEC_BOOST: + return (LONG)hDrcDec->selProcOutput.boost; + case DRC_DEC_COMPRESS: + return (LONG)hDrcDec->selProcOutput.compress; + case DRC_DEC_IS_MULTIBAND_DRC_1: + return (LONG)bitstreamContainsMultibandDrc(&hDrcDec->uniDrcConfig, 0); + case DRC_DEC_IS_MULTIBAND_DRC_2: + return (LONG)bitstreamContainsMultibandDrc(&hDrcDec->uniDrcConfig, 0x7F); + case DRC_DEC_IS_ACTIVE: { + /* MPEG-D DRC is considered active (and overrides MPEG-4 DRC), if + * uniDrc payload is present (loudnessInfoSet and/or uniDrcConfig) + * at least one of DRC and Loudness Control is switched on */ + int drcOn = drcDec_SelectionProcess_GetParam( + hDrcDec->hSelectionProc, SEL_PROC_DYNAMIC_RANGE_CONTROL_ON); + int lnOn = drcDec_SelectionProcess_GetParam( + hDrcDec->hSelectionProc, SEL_PROC_LOUDNESS_NORMALIZATION_ON); + int uniDrcPayloadPresent = + (hDrcDec->loudnessInfoSet.loudnessInfoCount > 0); + uniDrcPayloadPresent |= + (hDrcDec->loudnessInfoSet.loudnessInfoAlbumCount > 0); + uniDrcPayloadPresent |= + (hDrcDec->uniDrcConfig.drcInstructionsUniDrcCount > 0); + uniDrcPayloadPresent |= + (hDrcDec->uniDrcConfig.downmixInstructionsCount > 0); + return (LONG)(uniDrcPayloadPresent && (drcOn || lnOn)); + } + case DRC_DEC_TARGET_CHANNEL_COUNT_SELECTED: + return (LONG)hDrcDec->selProcOutput.targetChannelCount; + default: + return 0; + } +} + +DRC_DEC_ERROR +FDK_drcDec_SetInterfaceParameters(HANDLE_DRC_DECODER hDrcDec, + HANDLE_UNI_DRC_INTERFACE hUniDrcInterface) { + return DRC_DEC_UNSUPPORTED_FUNCTION; +} + +DRC_DEC_ERROR +FDK_drcDec_SetSelectionProcessMpeghParameters_simple( + HANDLE_DRC_DECODER hDrcDec, const int groupPresetIdRequested, + const int numGroupIdsRequested, const int* groupIdsRequested) { + return DRC_DEC_UNSUPPORTED_FUNCTION; +} + +DRC_DEC_ERROR +FDK_drcDec_SetDownmixInstructions(HANDLE_DRC_DECODER hDrcDec, + const int numDownmixId, const int* downmixId, + const int* targetLayout, + const int* targetChannelCount) { + return DRC_DEC_UNSUPPORTED_FUNCTION; +} + +void FDK_drcDec_SetSelectionProcessOutput( + HANDLE_DRC_DECODER hDrcDec, HANDLE_SEL_PROC_OUTPUT hSelProcOutput) {} + +HANDLE_SEL_PROC_OUTPUT +FDK_drcDec_GetSelectionProcessOutput(HANDLE_DRC_DECODER hDrcDec) { + if (hDrcDec == NULL) return NULL; + + return &(hDrcDec->selProcOutput); +} + +LONG /* FIXP_DBL, e = 7 */ +FDK_drcDec_GetGroupLoudness(HANDLE_SEL_PROC_OUTPUT hSelProcOutput, + const int groupID, int* groupLoudnessAvailable) { + return (LONG)0; +} + +void FDK_drcDec_SetChannelGains(HANDLE_DRC_DECODER hDrcDec, + const int numChannels, const int frameSize, + FIXP_DBL* channelGainDb, FIXP_DBL* audioBuffer, + const int audioBufferChannelOffset) { + int err; + + if (hDrcDec == NULL) return; + + err = drcDec_GainDecoder_SetLoudnessNormalizationGainDb( + hDrcDec->hGainDec, hDrcDec->selProcOutput.loudnessNormalizationGainDb); + if (err) return; + + drcDec_GainDecoder_SetChannelGains(hDrcDec->hGainDec, numChannels, frameSize, + channelGainDb, audioBufferChannelOffset, + audioBuffer); +} + +DRC_DEC_ERROR +FDK_drcDec_ReadUniDrcConfig(HANDLE_DRC_DECODER hDrcDec, + HANDLE_FDK_BITSTREAM hBitstream) { + DRC_ERROR dErr = DE_OK; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + + if (hDrcDec->codecMode == DRC_DEC_MPEG_D_USAC) { + dErr = drcDec_readUniDrcConfig(hBitstream, &(hDrcDec->uniDrcConfig)); + } else + return DRC_DEC_NOT_OK; + + if (dErr) { + /* clear config, if parsing error occured */ + FDKmemclear(&hDrcDec->uniDrcConfig, sizeof(hDrcDec->uniDrcConfig)); + hDrcDec->uniDrcConfig.diff = 1; + } + + startSelectionProcess(hDrcDec); + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_ReadDownmixInstructions_Box(HANDLE_DRC_DECODER hDrcDec, + HANDLE_FDK_BITSTREAM hBitstream) { + DRC_ERROR dErr = DE_OK; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + + return DRC_DEC_NOT_OK; + + if (dErr) { + /* clear config, if parsing error occurred */ + FDKmemclear(&hDrcDec->uniDrcConfig.downmixInstructions, + sizeof(hDrcDec->uniDrcConfig.downmixInstructions)); + hDrcDec->uniDrcConfig.downmixInstructionsCount = 0; + hDrcDec->uniDrcConfig.downmixInstructionsCountV0 = 0; + hDrcDec->uniDrcConfig.downmixInstructionsCountV1 = 0; + hDrcDec->uniDrcConfig.diff = 1; + } + + startSelectionProcess(hDrcDec); + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_ReadUniDrcInstructions_Box(HANDLE_DRC_DECODER hDrcDec, + HANDLE_FDK_BITSTREAM hBitstream) { + DRC_ERROR dErr = DE_OK; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + + return DRC_DEC_NOT_OK; + + if (dErr) { + /* clear config, if parsing error occurred */ + FDKmemclear(&hDrcDec->uniDrcConfig.drcInstructionsUniDrc, + sizeof(hDrcDec->uniDrcConfig.drcInstructionsUniDrc)); + hDrcDec->uniDrcConfig.drcInstructionsUniDrcCount = 0; + hDrcDec->uniDrcConfig.drcInstructionsUniDrcCountV0 = 0; + hDrcDec->uniDrcConfig.drcInstructionsUniDrcCountV1 = 0; + hDrcDec->uniDrcConfig.diff = 1; + } + + startSelectionProcess(hDrcDec); + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_ReadUniDrcCoefficients_Box(HANDLE_DRC_DECODER hDrcDec, + HANDLE_FDK_BITSTREAM hBitstream) { + DRC_ERROR dErr = DE_OK; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + + return DRC_DEC_NOT_OK; + + if (dErr) { + /* clear config, if parsing error occurred */ + FDKmemclear(&hDrcDec->uniDrcConfig.drcCoefficientsUniDrc, + sizeof(hDrcDec->uniDrcConfig.drcCoefficientsUniDrc)); + hDrcDec->uniDrcConfig.drcCoefficientsUniDrcCount = 0; + hDrcDec->uniDrcConfig.drcCoefficientsUniDrcCountV0 = 0; + hDrcDec->uniDrcConfig.drcCoefficientsUniDrcCountV1 = 0; + hDrcDec->uniDrcConfig.diff = 1; + } + + startSelectionProcess(hDrcDec); + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_ReadLoudnessInfoSet(HANDLE_DRC_DECODER hDrcDec, + HANDLE_FDK_BITSTREAM hBitstream) { + DRC_ERROR dErr = DE_OK; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + + if (hDrcDec->codecMode == DRC_DEC_MPEG_D_USAC) { + dErr = drcDec_readLoudnessInfoSet(hBitstream, &(hDrcDec->loudnessInfoSet)); + } else + return DRC_DEC_NOT_OK; + + if (dErr) { + /* clear config, if parsing error occurred */ + FDKmemclear(&hDrcDec->loudnessInfoSet, sizeof(hDrcDec->loudnessInfoSet)); + hDrcDec->loudnessInfoSet.diff = 1; + } + + startSelectionProcess(hDrcDec); + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_ReadLoudnessBox(HANDLE_DRC_DECODER hDrcDec, + HANDLE_FDK_BITSTREAM hBitstream) { + DRC_ERROR dErr = DE_OK; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + + return DRC_DEC_NOT_OK; + + if (dErr) { + /* clear config, if parsing error occurred */ + FDKmemclear(&hDrcDec->loudnessInfoSet, sizeof(hDrcDec->loudnessInfoSet)); + hDrcDec->loudnessInfoSet.diff = 1; + } + + startSelectionProcess(hDrcDec); + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_ReadUniDrcGain(HANDLE_DRC_DECODER hDrcDec, + HANDLE_FDK_BITSTREAM hBitstream) { + DRC_ERROR dErr = DE_OK; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + if (!hDrcDec->status) { + return DRC_DEC_OK; + } + + dErr = drcDec_readUniDrcGain( + hBitstream, &(hDrcDec->uniDrcConfig), + drcDec_GainDecoder_GetFrameSize(hDrcDec->hGainDec), + drcDec_GainDecoder_GetDeltaTminDefault(hDrcDec->hGainDec), + &(hDrcDec->uniDrcGain)); + if (dErr) return DRC_DEC_NOT_OK; + + hDrcDec->status = DRC_DEC_NEW_GAIN_PAYLOAD; + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_ReadUniDrc(HANDLE_DRC_DECODER hDrcDec, + HANDLE_FDK_BITSTREAM hBitstream) { + DRC_ERROR dErr = DE_OK; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + if (!hDrcDec->status) return DRC_DEC_NOT_READY; + + dErr = drcDec_readUniDrc( + hBitstream, &(hDrcDec->uniDrcConfig), &(hDrcDec->loudnessInfoSet), + drcDec_GainDecoder_GetFrameSize(hDrcDec->hGainDec), + drcDec_GainDecoder_GetDeltaTminDefault(hDrcDec->hGainDec), + &(hDrcDec->uniDrcGain)); + if (dErr) return DRC_DEC_NOT_OK; + + startSelectionProcess(hDrcDec); + + hDrcDec->status = DRC_DEC_NEW_GAIN_PAYLOAD; + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_Preprocess(HANDLE_DRC_DECODER hDrcDec) { + DRC_ERROR dErr = DE_OK; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + if (!hDrcDec->status) return DRC_DEC_NOT_READY; + if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK; + + if (hDrcDec->status != DRC_DEC_NEW_GAIN_PAYLOAD) { + /* no new gain payload was read, e.g. during concalment or flushing. + Generate DRC gains based on the stored DRC gains of last frames */ + drcDec_GainDecoder_Conceal(hDrcDec->hGainDec, &(hDrcDec->uniDrcConfig), + &(hDrcDec->uniDrcGain)); + } + + dErr = drcDec_GainDecoder_Preprocess( + hDrcDec->hGainDec, &(hDrcDec->uniDrcGain), + hDrcDec->selProcOutput.loudnessNormalizationGainDb, + hDrcDec->selProcOutput.boost, hDrcDec->selProcOutput.compress); + if (dErr) return DRC_DEC_NOT_OK; + hDrcDec->status = DRC_DEC_INTERPOLATION_PREPARED; + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_ProcessTime(HANDLE_DRC_DECODER hDrcDec, const int delaySamples, + const DRC_DEC_LOCATION drcLocation, + const int channelOffset, const int drcChannelOffset, + const int numChannelsProcessed, FIXP_DBL* realBuffer, + const int timeDataChannelOffset) { + DRC_ERROR dErr = DE_OK; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK; + if (hDrcDec->status != DRC_DEC_INTERPOLATION_PREPARED) + return DRC_DEC_NOT_READY; + + dErr = drcDec_GainDecoder_ProcessTimeDomain( + hDrcDec->hGainDec, delaySamples, (GAIN_DEC_LOCATION)drcLocation, + channelOffset, drcChannelOffset, numChannelsProcessed, + timeDataChannelOffset, realBuffer); + if (dErr) return DRC_DEC_NOT_OK; + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_ProcessFreq(HANDLE_DRC_DECODER hDrcDec, const int delaySamples, + const DRC_DEC_LOCATION drcLocation, + const int channelOffset, const int drcChannelOffset, + const int numChannelsProcessed, + const int processSingleTimeslot, FIXP_DBL** realBuffer, + FIXP_DBL** imagBuffer) { + DRC_ERROR dErr = DE_OK; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK; + if (hDrcDec->status != DRC_DEC_INTERPOLATION_PREPARED) + return DRC_DEC_NOT_READY; + + dErr = drcDec_GainDecoder_ProcessSubbandDomain( + hDrcDec->hGainDec, delaySamples, (GAIN_DEC_LOCATION)drcLocation, + channelOffset, drcChannelOffset, numChannelsProcessed, + processSingleTimeslot, realBuffer, imagBuffer); + if (dErr) return DRC_DEC_NOT_OK; + + return DRC_DEC_OK; +} + +DRC_DEC_ERROR +FDK_drcDec_ApplyDownmix(HANDLE_DRC_DECODER hDrcDec, int* reverseInChannelMap, + int* reverseOutChannelMap, FIXP_DBL* realBuffer, + int* pNChannels) { + SEL_PROC_OUTPUT* pSelProcOutput = &(hDrcDec->selProcOutput); + int baseChCnt = pSelProcOutput->baseChannelCount; + int targetChCnt = pSelProcOutput->targetChannelCount; + int frameSize, n, ic, oc; + FIXP_DBL tmp_out[8]; + FIXP_DBL* audioChannels[8]; + + if (hDrcDec == NULL) return DRC_DEC_NOT_OPENED; + if (!(hDrcDec->functionalRange & DRC_DEC_GAIN)) return DRC_DEC_NOT_OK; + + /* only downmix is performed here, no upmix. + Downmix is only performed if downmix coefficients are provided. + All other cases of downmix and upmix are treated by pcmDmx library. */ + if (pSelProcOutput->downmixMatrixPresent == 0) + return DRC_DEC_OK; /* no downmix */ + if (targetChCnt >= baseChCnt) return DRC_DEC_OK; /* downmix only */ + + /* sanity checks */ + if (realBuffer == NULL) return DRC_DEC_NOT_OK; + if (reverseInChannelMap == NULL) return DRC_DEC_NOT_OK; + if (reverseOutChannelMap == NULL) return DRC_DEC_NOT_OK; + if (baseChCnt > 8) return DRC_DEC_NOT_OK; + if (baseChCnt != *pNChannels) return DRC_DEC_NOT_OK; + if (targetChCnt > 8) return DRC_DEC_NOT_OK; + + frameSize = drcDec_GainDecoder_GetFrameSize(hDrcDec->hGainDec); + + for (ic = 0; ic < baseChCnt; ic++) { + audioChannels[ic] = &(realBuffer[ic * frameSize]); + } + + /* in-place downmix */ + for (n = 0; n < frameSize; n++) { + for (oc = 0; oc < targetChCnt; oc++) { + tmp_out[oc] = (FIXP_DBL)0; + for (ic = 0; ic < baseChCnt; ic++) { + tmp_out[oc] += + fMultDiv2(audioChannels[ic][n], + pSelProcOutput->downmixMatrix[reverseInChannelMap[ic]] + [reverseOutChannelMap[oc]]) + << 3; + } + } + for (oc = 0; oc < targetChCnt; oc++) { + if (oc >= baseChCnt) break; + audioChannels[oc][n] = tmp_out[oc]; + } + } + + for (oc = targetChCnt; oc < baseChCnt; oc++) { + FDKmemset(audioChannels[oc], 0, frameSize * sizeof(FIXP_DBL)); + } + + *pNChannels = targetChCnt; + + return DRC_DEC_OK; +} + +/* Get library info for this module. */ +DRC_DEC_ERROR +FDK_drcDec_GetLibInfo(LIB_INFO* info) { + int i; + + if (info == NULL) { + return DRC_DEC_INVALID_PARAM; + } + + /* Search for next free tab */ + for (i = 0; i < FDK_MODULE_LAST; i++) { + if (info[i].module_id == FDK_NONE) break; + } + if (i == FDK_MODULE_LAST) { + return DRC_DEC_NOT_OK; + } + + /* Add the library info */ + info[i].module_id = FDK_UNIDRCDEC; + info[i].version = LIB_VERSION(DRCDEC_LIB_VL0, DRCDEC_LIB_VL1, DRCDEC_LIB_VL2); + LIB_VERSION_STRING(info + i); + info[i].build_date = DRCDEC_LIB_BUILD_DATE; + info[i].build_time = DRCDEC_LIB_BUILD_TIME; + info[i].title = DRCDEC_LIB_TITLE; + + return DRC_DEC_OK; +} diff --git a/libDRCdec/src/drcDec_gainDecoder.cpp b/libDRCdec/src/drcDec_gainDecoder.cpp new file mode 100644 index 0000000..ca81fad --- /dev/null +++ b/libDRCdec/src/drcDec_gainDecoder.cpp @@ -0,0 +1,445 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "drcDec_types.h" +#include "drcDec_gainDecoder.h" +#include "drcGainDec_preprocess.h" +#include "drcGainDec_init.h" +#include "drcGainDec_process.h" +#include "drcDec_tools.h" + +/*******************************************/ +/* static functions */ +/*******************************************/ + +static int _fitsLocation(DRC_INSTRUCTIONS_UNI_DRC* pInst, + const GAIN_DEC_LOCATION drcLocation) { + int downmixId = pInst->drcApplyToDownmix ? pInst->downmixId[0] : 0; + switch (drcLocation) { + case GAIN_DEC_DRC1: + return (downmixId == 0); + case GAIN_DEC_DRC1_DRC2: + return ((downmixId == 0) || (downmixId == DOWNMIX_ID_ANY_DOWNMIX)); + case GAIN_DEC_DRC2: + return (downmixId == DOWNMIX_ID_ANY_DOWNMIX); + case GAIN_DEC_DRC3: + return ((downmixId != 0) && (downmixId != DOWNMIX_ID_ANY_DOWNMIX)); + case GAIN_DEC_DRC2_DRC3: + return (downmixId != 0); + } + return 0; +} + +static void _setChannelGains(HANDLE_DRC_GAIN_DECODER hGainDec, + const int numChannelGains, + const FIXP_DBL* channelGainDb) { + int i, channelGain_e; + FIXP_DBL channelGain; + FDK_ASSERT(numChannelGains <= 8); + for (i = 0; i < numChannelGains; i++) { + if (channelGainDb[i] == (FIXP_DBL)MINVAL_DBL) { + hGainDec->channelGain[i] = (FIXP_DBL)0; + } else { + /* add loudness normalisation gain (dB) to channel gain (dB) */ + FIXP_DBL tmp_channelGainDb = (channelGainDb[i] >> 1) + + (hGainDec->loudnessNormalisationGainDb >> 2); + tmp_channelGainDb = + SATURATE_LEFT_SHIFT(tmp_channelGainDb, 1, DFRACT_BITS); + channelGain = dB2lin(tmp_channelGainDb, 8, &channelGain_e); + hGainDec->channelGain[i] = scaleValue(channelGain, channelGain_e - 8); + } + } +} + +/*******************************************/ +/* public functions */ +/*******************************************/ + +DRC_ERROR +drcDec_GainDecoder_Open(HANDLE_DRC_GAIN_DECODER* phGainDec) { + DRC_GAIN_DECODER* hGainDec = NULL; + + hGainDec = (DRC_GAIN_DECODER*)FDKcalloc(1, sizeof(DRC_GAIN_DECODER)); + if (hGainDec == NULL) return DE_MEMORY_ERROR; + + hGainDec->multiBandActiveDrcIndex = -1; + hGainDec->channelGainActiveDrcIndex = -1; + + *phGainDec = hGainDec; + + return DE_OK; +} + +DRC_ERROR +drcDec_GainDecoder_Init(HANDLE_DRC_GAIN_DECODER hGainDec, const int frameSize, + const int sampleRate) { + DRC_ERROR err = DE_OK; + + err = initGainDec(hGainDec, frameSize, sampleRate); + if (err) return err; + + initDrcGainBuffers(hGainDec->frameSize, &hGainDec->drcGainBuffers); + + return err; +} + +DRC_ERROR +drcDec_GainDecoder_SetCodecDependentParameters( + HANDLE_DRC_GAIN_DECODER hGainDec, const DELAY_MODE delayMode, + const int timeDomainSupported, + const SUBBAND_DOMAIN_MODE subbandDomainSupported) { + if ((delayMode != DM_REGULAR_DELAY) && (delayMode != DM_LOW_DELAY)) { + return DE_NOT_OK; + } + hGainDec->delayMode = delayMode; + hGainDec->timeDomainSupported = timeDomainSupported; + hGainDec->subbandDomainSupported = subbandDomainSupported; + + return DE_OK; +} + +DRC_ERROR +drcDec_GainDecoder_Config(HANDLE_DRC_GAIN_DECODER hGainDec, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + const UCHAR numSelectedDrcSets, + const SCHAR* selectedDrcSetIds, + const UCHAR* selectedDownmixIds) { + DRC_ERROR err = DE_OK; + int a; + + hGainDec->nActiveDrcs = 0; + hGainDec->multiBandActiveDrcIndex = -1; + hGainDec->channelGainActiveDrcIndex = -1; + for (a = 0; a < numSelectedDrcSets; a++) { + err = initActiveDrc(hGainDec, hUniDrcConfig, selectedDrcSetIds[a], + selectedDownmixIds[a]); + if (err) return err; + } + + err = initActiveDrcOffset(hGainDec); + if (err) return err; + + return err; +} + +DRC_ERROR +drcDec_GainDecoder_Close(HANDLE_DRC_GAIN_DECODER* phGainDec) { + if (*phGainDec != NULL) { + FDKfree(*phGainDec); + *phGainDec = NULL; + } + + return DE_OK; +} + +DRC_ERROR +drcDec_GainDecoder_Preprocess(HANDLE_DRC_GAIN_DECODER hGainDec, + HANDLE_UNI_DRC_GAIN hUniDrcGain, + const FIXP_DBL loudnessNormalizationGainDb, + const FIXP_SGL boost, const FIXP_SGL compress) { + DRC_ERROR err = DE_OK; + int a, c; + + /* lnbPointer is the index on the most recent node buffer */ + hGainDec->drcGainBuffers.lnbPointer++; + if (hGainDec->drcGainBuffers.lnbPointer >= NUM_LNB_FRAMES) + hGainDec->drcGainBuffers.lnbPointer = 0; + + for (a = 0; a < hGainDec->nActiveDrcs; a++) { + /* prepare gain interpolation of sequences used by copying and modifying + * nodes in node buffers */ + err = prepareDrcGain(hGainDec, hUniDrcGain, compress, boost, + loudnessNormalizationGainDb, a); + if (err) return err; + } + + for (a = 0; a < MAX_ACTIVE_DRCS; a++) { + for (c = 0; c < 8; c++) { + hGainDec->activeDrc[a] + .lnbIndexForChannel[c][hGainDec->drcGainBuffers.lnbPointer] = + -1; /* "no DRC processing" */ + } + hGainDec->activeDrc[a].subbandGainsReady = 0; + } + + for (c = 0; c < 8; c++) { + hGainDec->drcGainBuffers + .channelGain[c][hGainDec->drcGainBuffers.lnbPointer] = + FL2FXCONST_DBL(1.0f / (float)(1 << 8)); + } + + return err; +} + +/* create gain sequence out of gain sequences of last frame for concealment and + * flushing */ +DRC_ERROR +drcDec_GainDecoder_Conceal(HANDLE_DRC_GAIN_DECODER hGainDec, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_UNI_DRC_GAIN hUniDrcGain) { + int seq, gainSequenceCount; + DRC_COEFFICIENTS_UNI_DRC* pCoef = + selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED); + if (pCoef == NULL) return DE_OK; + + gainSequenceCount = fMin(pCoef->gainSequenceCount, (UCHAR)12); + + for (seq = 0; seq < gainSequenceCount; seq++) { + int lastNodeIndex = 0; + FIXP_SGL lastGainDb = (FIXP_SGL)0; + + lastNodeIndex = hUniDrcGain->nNodes[seq] - 1; + if ((lastNodeIndex >= 0) && (lastNodeIndex < 16)) { + lastGainDb = hUniDrcGain->gainNode[seq][lastNodeIndex].gainDb; + } + + hUniDrcGain->nNodes[seq] = 1; + if (lastGainDb > (FIXP_SGL)0) { + hUniDrcGain->gainNode[seq][0].gainDb = + FX_DBL2FX_SGL(fMult(FL2FXCONST_SGL(0.9f), lastGainDb)); + } else { + hUniDrcGain->gainNode[seq][0].gainDb = + FX_DBL2FX_SGL(fMult(FL2FXCONST_SGL(0.98f), lastGainDb)); + } + hUniDrcGain->gainNode[seq][0].time = hGainDec->frameSize - 1; + } + return DE_OK; +} + +void drcDec_GainDecoder_SetChannelGains(HANDLE_DRC_GAIN_DECODER hGainDec, + const int numChannels, + const int frameSize, + const FIXP_DBL* channelGainDb, + const int audioBufferChannelOffset, + FIXP_DBL* audioBuffer) { + int c, i; + + if (hGainDec->channelGainActiveDrcIndex >= 0) { + /* channel gains will be applied in drcDec_GainDecoder_ProcessTimeDomain or + * drcDec_GainDecoder_ProcessSubbandDomain, respectively. */ + _setChannelGains(hGainDec, numChannels, channelGainDb); + + if (!hGainDec->status) { /* overwrite previous channel gains at startup */ + DRC_GAIN_BUFFERS* pDrcGainBuffers = &hGainDec->drcGainBuffers; + for (c = 0; c < numChannels; c++) { + for (i = 0; i < NUM_LNB_FRAMES; i++) { + pDrcGainBuffers->channelGain[c][i] = hGainDec->channelGain[c]; + } + } + hGainDec->status = 1; + } + } else { + /* smooth and apply channel gains */ + FIXP_DBL prevChannelGain[8]; + for (c = 0; c < numChannels; c++) { + prevChannelGain[c] = hGainDec->channelGain[c]; + } + + _setChannelGains(hGainDec, numChannels, channelGainDb); + + if (!hGainDec->status) { /* overwrite previous channel gains at startup */ + for (c = 0; c < numChannels; c++) + prevChannelGain[c] = hGainDec->channelGain[c]; + hGainDec->status = 1; + } + + for (c = 0; c < numChannels; c++) { + INT n_min = fMin(fMin(CntLeadingZeros(prevChannelGain[c]), + CntLeadingZeros(hGainDec->channelGain[c])) - + 1, + 9); + FIXP_DBL gain = prevChannelGain[c] << n_min; + FIXP_DBL stepsize = ((hGainDec->channelGain[c] << n_min) - gain); + if (stepsize != (FIXP_DBL)0) { + if (frameSize == 1024) + stepsize = stepsize >> 10; + else + stepsize = (LONG)stepsize / frameSize; + } + n_min = 9 - n_min; +#ifdef FUNCTION_drcDec_GainDecoder_SetChannelGains_func1 + drcDec_GainDecoder_SetChannelGains_func1(audioBuffer, gain, stepsize, + n_min, frameSize); +#else + for (i = 0; i < frameSize; i++) { + audioBuffer[i] = fMultDiv2(audioBuffer[i], gain) << n_min; + gain += stepsize; + } +#endif + audioBuffer += audioBufferChannelOffset; + } + } +} + +DRC_ERROR +drcDec_GainDecoder_ProcessTimeDomain( + HANDLE_DRC_GAIN_DECODER hGainDec, const int delaySamples, + const GAIN_DEC_LOCATION drcLocation, const int channelOffset, + const int drcChannelOffset, const int numChannelsProcessed, + const int timeDataChannelOffset, FIXP_DBL* audioIOBuffer) { + DRC_ERROR err = DE_OK; + int a; + + if (!hGainDec->timeDomainSupported) { + return DE_NOT_OK; + } + + for (a = 0; a < hGainDec->nActiveDrcs; a++) { + if (!_fitsLocation(hGainDec->activeDrc[a].pInst, drcLocation)) continue; + + /* Apply DRC */ + err = processDrcTime(hGainDec, a, delaySamples, channelOffset, + drcChannelOffset, numChannelsProcessed, + timeDataChannelOffset, audioIOBuffer); + if (err) return err; + } + + return err; +} + +DRC_ERROR +drcDec_GainDecoder_ProcessSubbandDomain( + HANDLE_DRC_GAIN_DECODER hGainDec, const int delaySamples, + const GAIN_DEC_LOCATION drcLocation, const int channelOffset, + const int drcChannelOffset, const int numChannelsProcessed, + const int processSingleTimeslot, FIXP_DBL* audioIOBufferReal[], + FIXP_DBL* audioIOBufferImag[]) { + DRC_ERROR err = DE_OK; + int a; + + if (hGainDec->subbandDomainSupported == SDM_OFF) { + return DE_NOT_OK; + } + + for (a = 0; a < hGainDec->nActiveDrcs; a++) { + if (!_fitsLocation(hGainDec->activeDrc[a].pInst, drcLocation)) continue; + + /* Apply DRC */ + err = processDrcSubband(hGainDec, a, delaySamples, channelOffset, + drcChannelOffset, numChannelsProcessed, + processSingleTimeslot, audioIOBufferReal, + audioIOBufferImag); + if (err) return err; + } + + return err; +} + +DRC_ERROR +drcDec_GainDecoder_SetLoudnessNormalizationGainDb( + HANDLE_DRC_GAIN_DECODER hGainDec, FIXP_DBL loudnessNormalizationGainDb) { + hGainDec->loudnessNormalisationGainDb = loudnessNormalizationGainDb; + + return DE_OK; +} + +int drcDec_GainDecoder_GetFrameSize(HANDLE_DRC_GAIN_DECODER hGainDec) { + if (hGainDec == NULL) return -1; + + return hGainDec->frameSize; +} + +int drcDec_GainDecoder_GetDeltaTminDefault(HANDLE_DRC_GAIN_DECODER hGainDec) { + if (hGainDec == NULL) return -1; + + return hGainDec->deltaTminDefault; +} diff --git a/libDRCdec/src/drcDec_gainDecoder.h b/libDRCdec/src/drcDec_gainDecoder.h new file mode 100644 index 0000000..2f4df4c --- /dev/null +++ b/libDRCdec/src/drcDec_gainDecoder.h @@ -0,0 +1,264 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#ifndef DRCDEC_GAINDECODER_H +#define DRCDEC_GAINDECODER_H + +#include "drcDecoder.h" + +/* Definitions common to gainDecoder submodule */ + +#define NUM_LNB_FRAMES \ + 5 /* previous frame + this frame + one frame for DM_REGULAR_DELAY + (maximum \ + delaySamples)/frameSize */ + +/* QMF64 */ +#define SUBBAND_NUM_BANDS_QMF64 64 +#define SUBBAND_DOWNSAMPLING_FACTOR_QMF64 64 +#define SUBBAND_ANALYSIS_DELAY_QMF64 320 + +/* QMF71 (according to ISO/IEC 23003-1:2007) */ +#define SUBBAND_NUM_BANDS_QMF71 71 +#define SUBBAND_DOWNSAMPLING_FACTOR_QMF71 64 +#define SUBBAND_ANALYSIS_DELAY_QMF71 320 + 384 + +/* STFT256 (according to ISO/IEC 23008-3:2015/AMD3) */ +#define SUBBAND_NUM_BANDS_STFT256 256 +#define SUBBAND_DOWNSAMPLING_FACTOR_STFT256 256 +#define SUBBAND_ANALYSIS_DELAY_STFT256 256 + +typedef enum { + GAIN_DEC_DRC1, + GAIN_DEC_DRC1_DRC2, + GAIN_DEC_DRC2, + GAIN_DEC_DRC3, + GAIN_DEC_DRC2_DRC3 +} GAIN_DEC_LOCATION; + +typedef struct { + FIXP_DBL gainLin; /* e = 7 */ + SHORT time; +} NODE_LIN; + +typedef struct { + GAIN_INTERPOLATION_TYPE gainInterpolationType; + int nNodes[NUM_LNB_FRAMES]; /* number of nodes, saturated to 16 */ + NODE_LIN linearNode[NUM_LNB_FRAMES][16]; +} LINEAR_NODE_BUFFER; + +typedef struct { + int lnbPointer; + LINEAR_NODE_BUFFER linearNodeBuffer[12]; + LINEAR_NODE_BUFFER dummyLnb; + FIXP_DBL channelGain[8][NUM_LNB_FRAMES]; /* e = 8 */ +} DRC_GAIN_BUFFERS; + +typedef struct { + int activeDrcOffset; + DRC_INSTRUCTIONS_UNI_DRC* pInst; + DRC_COEFFICIENTS_UNI_DRC* pCoef; + + DUCKING_MODIFICATION duckingModificationForChannelGroup[8]; + SCHAR channelGroupForChannel[8]; + + UCHAR bandCountForChannelGroup[8]; + UCHAR gainElementForGroup[8]; + UCHAR channelGroupIsParametricDrc[8]; + UCHAR gainElementCount; /* number of different DRC gains inluding all DRC + bands */ + int lnbIndexForChannel[8][NUM_LNB_FRAMES]; + int subbandGainsReady; +} ACTIVE_DRC; + +typedef struct { + int deltaTminDefault; + INT frameSize; + FIXP_DBL loudnessNormalisationGainDb; + DELAY_MODE delayMode; + + int nActiveDrcs; + ACTIVE_DRC activeDrc[MAX_ACTIVE_DRCS]; + int multiBandActiveDrcIndex; + int channelGainActiveDrcIndex; + FIXP_DBL channelGain[8]; /* e = 8 */ + + DRC_GAIN_BUFFERS drcGainBuffers; + FIXP_DBL subbandGains[12][4 * 1024 / 256]; + FIXP_DBL dummySubbandGains[4 * 1024 / 256]; + + int status; + int timeDomainSupported; + SUBBAND_DOMAIN_MODE subbandDomainSupported; +} DRC_GAIN_DECODER, *HANDLE_DRC_GAIN_DECODER; + +/* init functions */ +DRC_ERROR +drcDec_GainDecoder_Open(HANDLE_DRC_GAIN_DECODER* phGainDec); + +DRC_ERROR +drcDec_GainDecoder_Init(HANDLE_DRC_GAIN_DECODER hGainDec, const int frameSize, + const int sampleRate); + +DRC_ERROR +drcDec_GainDecoder_SetCodecDependentParameters( + HANDLE_DRC_GAIN_DECODER hGainDec, const DELAY_MODE delayMode, + const int timeDomainSupported, + const SUBBAND_DOMAIN_MODE subbandDomainSupported); + +DRC_ERROR +drcDec_GainDecoder_Config(HANDLE_DRC_GAIN_DECODER hGainDec, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + const UCHAR numSelectedDrcSets, + const SCHAR* selectedDrcSetIds, + const UCHAR* selectedDownmixIds); + +/* close functions */ +DRC_ERROR +drcDec_GainDecoder_Close(HANDLE_DRC_GAIN_DECODER* phGainDec); + +/* process functions */ + +/* call drcDec_GainDecoder_Preprocess first */ +DRC_ERROR +drcDec_GainDecoder_Preprocess(HANDLE_DRC_GAIN_DECODER hGainDec, + HANDLE_UNI_DRC_GAIN hUniDrcGain, + const FIXP_DBL loudnessNormalizationGainDb, + const FIXP_SGL boost, const FIXP_SGL compress); + +/* Then call one of drcDec_GainDecoder_ProcessTimeDomain or + * drcDec_GainDecoder_ProcessSubbandDomain */ +DRC_ERROR +drcDec_GainDecoder_ProcessTimeDomain( + HANDLE_DRC_GAIN_DECODER hGainDec, const int delaySamples, + const GAIN_DEC_LOCATION drcLocation, const int channelOffset, + const int drcChannelOffset, const int numChannelsProcessed, + const int timeDataChannelOffset, FIXP_DBL* audioIOBuffer); + +DRC_ERROR +drcDec_GainDecoder_ProcessSubbandDomain( + HANDLE_DRC_GAIN_DECODER hGainDec, const int delaySamples, + GAIN_DEC_LOCATION drcLocation, const int channelOffset, + const int drcChannelOffset, const int numChannelsProcessed, + const int processSingleTimeslot, FIXP_DBL* audioIOBufferReal[], + FIXP_DBL* audioIOBufferImag[]); + +DRC_ERROR +drcDec_GainDecoder_Conceal(HANDLE_DRC_GAIN_DECODER hGainDec, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_UNI_DRC_GAIN hUniDrcGain); + +DRC_ERROR +drcDec_GainDecoder_SetLoudnessNormalizationGainDb( + HANDLE_DRC_GAIN_DECODER hGainDec, FIXP_DBL loudnessNormalizationGainDb); + +int drcDec_GainDecoder_GetFrameSize(HANDLE_DRC_GAIN_DECODER hGainDec); + +int drcDec_GainDecoder_GetDeltaTminDefault(HANDLE_DRC_GAIN_DECODER hGainDec); + +void drcDec_GainDecoder_SetChannelGains(HANDLE_DRC_GAIN_DECODER hGainDec, + const int numChannels, + const int frameSize, + const FIXP_DBL* channelGainDb, + const int audioBufferChannelOffset, + FIXP_DBL* audioBuffer); + +#endif diff --git a/libDRCdec/src/drcDec_reader.cpp b/libDRCdec/src/drcDec_reader.cpp new file mode 100644 index 0000000..db5fab7 --- /dev/null +++ b/libDRCdec/src/drcDec_reader.cpp @@ -0,0 +1,2027 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "fixpoint_math.h" +#include "drcDec_reader.h" +#include "drcDec_tools.h" +#include "drcDec_rom.h" +#include "drcDecoder.h" + +/* MPEG-D DRC AMD 1 */ + +#define UNIDRCCONFEXT_PARAM_DRC 0x1 +#define UNIDRCCONFEXT_V1 0x2 +#define UNIDRCLOUDEXT_EQ 0x1 + +#define UNIDRCGAINEXT_TERM 0x0 +#define UNIDRCLOUDEXT_TERM 0x0 +#define UNIDRCCONFEXT_TERM 0x0 + +static int _getZ(const int nNodesMax) { + /* Z is the minimum codeword length that is needed to encode all possible + * timeDelta values */ + /* Z = ceil(log2(2*nNodesMax)) */ + int Z = 1; + while ((1 << Z) < (2 * nNodesMax)) { + Z++; + } + return Z; +} + +static int _getTimeDeltaMin(const GAIN_SET* pGset, const int deltaTminDefault) { + if (pGset->timeDeltaMinPresent) { + return pGset->timeDeltaMin; + } else { + return deltaTminDefault; + } +} + +/* compare and assign */ +static inline int _compAssign(UCHAR* dest, const UCHAR src) { + int diff = 0; + if (*dest != src) diff = 1; + *dest = src; + return diff; +} + +static inline int _compAssign(ULONG* dest, const ULONG src) { + int diff = 0; + if (*dest != src) diff = 1; + *dest = src; + return diff; +} + +typedef const SCHAR (*Huffman)[2]; + +int _decodeHuffmanCW(Huffman h, /*!< pointer to huffman codebook table */ + HANDLE_FDK_BITSTREAM hBs) /*!< Handle to bitbuffer */ +{ + SCHAR index = 0; + int value, bit; + + while (index >= 0) { + bit = FDKreadBits(hBs, 1); + index = h[index][bit]; + } + + value = index + 64; /* Add offset */ + + return value; +} + +/**********/ +/* uniDrc */ +/**********/ + +DRC_ERROR +drcDec_readUniDrc(HANDLE_FDK_BITSTREAM hBs, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + const int frameSize, const int deltaTminDefault, + HANDLE_UNI_DRC_GAIN hUniDrcGain) { + DRC_ERROR err = DE_OK; + int loudnessInfoSetPresent, uniDrcConfigPresent; + + loudnessInfoSetPresent = FDKreadBits(hBs, 1); + if (loudnessInfoSetPresent) { + uniDrcConfigPresent = FDKreadBits(hBs, 1); + if (uniDrcConfigPresent) { + err = drcDec_readUniDrcConfig(hBs, hUniDrcConfig); + if (err) return err; + } + err = drcDec_readLoudnessInfoSet(hBs, hLoudnessInfoSet); + if (err) return err; + } + + if (hUniDrcGain != NULL) { + err = drcDec_readUniDrcGain(hBs, hUniDrcConfig, frameSize, deltaTminDefault, + hUniDrcGain); + if (err) return err; + } + + return err; +} + +/**************/ +/* uniDrcGain */ +/**************/ + +static FIXP_SGL _decodeGainInitial( + HANDLE_FDK_BITSTREAM hBs, const GAIN_CODING_PROFILE gainCodingProfile) { + int sign, magn; + FIXP_SGL gainInitial = (FIXP_SGL)0; + switch (gainCodingProfile) { + case GCP_REGULAR: + sign = FDKreadBits(hBs, 1); + magn = FDKreadBits(hBs, 8); + + gainInitial = + (FIXP_SGL)(magn << (FRACT_BITS - 1 - 3 - 7)); /* magn * 0.125; */ + if (sign) gainInitial = -gainInitial; + break; + case GCP_FADING: + sign = FDKreadBits(hBs, 1); + if (sign == 0) + gainInitial = (FIXP_SGL)0; + else { + magn = FDKreadBits(hBs, 10); + gainInitial = -(FIXP_SGL)( + (magn + 1) << (FRACT_BITS - 1 - 3 - 7)); /* - (magn + 1) * 0.125; */ + } + break; + case GCP_CLIPPING_DUCKING: + sign = FDKreadBits(hBs, 1); + if (sign == 0) + gainInitial = (FIXP_SGL)0; + else { + magn = FDKreadBits(hBs, 8); + gainInitial = -(FIXP_SGL)( + (magn + 1) << (FRACT_BITS - 1 - 3 - 7)); /* - (magn + 1) * 0.125; */ + } + break; + case GCP_CONSTANT: + break; + } + return gainInitial; +} + +static int _decodeNNodes(HANDLE_FDK_BITSTREAM hBs) { + int nNodes = 0, endMarker = 0; + + /* decode number of nodes */ + while (endMarker != 1) { + nNodes++; + if (nNodes >= 128) break; + endMarker = FDKreadBits(hBs, 1); + } + return nNodes; +} + +static void _decodeGains(HANDLE_FDK_BITSTREAM hBs, + const GAIN_CODING_PROFILE gainCodingProfile, + const int nNodes, GAIN_NODE* pNodes) { + int k, deltaGain; + Huffman deltaGainCodebook; + + pNodes[0].gainDb = _decodeGainInitial(hBs, gainCodingProfile); + + if (gainCodingProfile == GCP_CLIPPING_DUCKING) { + deltaGainCodebook = (Huffman)&deltaGain_codingProfile_2_huffman; + } else { + deltaGainCodebook = (Huffman)&deltaGain_codingProfile_0_1_huffman; + } + + for (k = 1; k < nNodes; k++) { + deltaGain = _decodeHuffmanCW(deltaGainCodebook, hBs); + if (k >= 16) continue; + /* gain_dB_e = 7 */ + pNodes[k].gainDb = + pNodes[k - 1].gainDb + + (FIXP_SGL)(deltaGain << (FRACT_BITS - 1 - 7 - + 3)); /* pNodes[k-1].gainDb + 0.125*deltaGain */ + } +} + +static void _decodeSlopes(HANDLE_FDK_BITSTREAM hBs, + const GAIN_INTERPOLATION_TYPE gainInterpolationType, + const int nNodes, GAIN_NODE* pNodes) { + int k = 0; + + if (gainInterpolationType == GIT_SPLINE) { + /* decode slope steepness */ + for (k = 0; k < nNodes; k++) { + _decodeHuffmanCW((Huffman)&slopeSteepness_huffman, hBs); + } + } +} + +static int _decodeTimeDelta(HANDLE_FDK_BITSTREAM hBs, const int Z) { + int prefix, mu; + + prefix = FDKreadBits(hBs, 2); + switch (prefix) { + case 0x0: + return 1; + case 0x1: + mu = FDKreadBits(hBs, 2); + return mu + 2; + case 0x2: + mu = FDKreadBits(hBs, 3); + return mu + 6; + case 0x3: + mu = FDKreadBits(hBs, Z); + return mu + 14; + default: + return 0; + } +} + +static void _decodeTimes(HANDLE_FDK_BITSTREAM hBs, const int deltaTmin, + const int frameSize, const int fullFrame, + const int timeOffset, const int Z, const int nNodes, + GAIN_NODE* pNodes) { + int timeDelta, k; + int timeOffs = timeOffset; + int frameEndFlag, nodeTimeTmp, nodeResFlag; + + if (fullFrame == 0) { + frameEndFlag = FDKreadBits(hBs, 1); + } else { + frameEndFlag = 1; + } + + if (frameEndFlag == + 1) { /* frameEndFlag == 1 signals that the last node is at the end of the + DRC frame */ + nodeResFlag = 0; + for (k = 0; k < nNodes - 1; k++) { + /* decode a delta time value */ + timeDelta = _decodeTimeDelta(hBs, Z); + if (k >= (16 - 1)) continue; + /* frameEndFlag == 1 needs special handling for last node with node + * reservoir */ + nodeTimeTmp = timeOffs + timeDelta * deltaTmin; + if (nodeTimeTmp > frameSize + timeOffset) { + if (nodeResFlag == 0) { + pNodes[k].time = frameSize + timeOffset; + nodeResFlag = 1; + } + pNodes[k + 1].time = nodeTimeTmp; + } else { + pNodes[k].time = nodeTimeTmp; + } + timeOffs = nodeTimeTmp; + } + if (nodeResFlag == 0) { + k = fMin(k, 16 - 1); + pNodes[k].time = frameSize + timeOffset; + } + } else { + for (k = 0; k < nNodes; k++) { + /* decode a delta time value */ + timeDelta = _decodeTimeDelta(hBs, Z); + if (k >= 16) continue; + pNodes[k].time = timeOffs + timeDelta * deltaTmin; + timeOffs = pNodes[k].time; + } + } +} + +static void _readNodes(HANDLE_FDK_BITSTREAM hBs, GAIN_SET* gainSet, + const int frameSize, const int timeDeltaMin, + UCHAR* pNNodes, GAIN_NODE* pNodes) { + int timeOffset, drcGainCodingMode, nNodes; + int Z = _getZ(frameSize / timeDeltaMin); + if (gainSet->timeAlignment == 0) { + timeOffset = -1; + } else { + timeOffset = -timeDeltaMin + + (timeDeltaMin - 1) / + 2; /* timeOffset = - deltaTmin + floor((deltaTmin-1)/2); */ + } + + drcGainCodingMode = FDKreadBits(hBs, 1); + if (drcGainCodingMode == 0) { + /* "simple" mode: only one node at the end of the frame with slope = 0 */ + nNodes = 1; + pNodes[0].gainDb = _decodeGainInitial( + hBs, (GAIN_CODING_PROFILE)gainSet->gainCodingProfile); + pNodes[0].time = frameSize + timeOffset; + } else { + nNodes = _decodeNNodes(hBs); + + _decodeSlopes(hBs, (GAIN_INTERPOLATION_TYPE)gainSet->gainInterpolationType, + nNodes, pNodes); + + _decodeTimes(hBs, timeDeltaMin, frameSize, gainSet->fullFrame, timeOffset, + Z, nNodes, pNodes); + + _decodeGains(hBs, (GAIN_CODING_PROFILE)gainSet->gainCodingProfile, nNodes, + pNodes); + } + *pNNodes = (UCHAR)nNodes; +} + +static void _readDrcGainSequence(HANDLE_FDK_BITSTREAM hBs, GAIN_SET* gainSet, + const int frameSize, const int timeDeltaMin, + UCHAR* pNNodes, GAIN_NODE pNodes[16]) { + SHORT timeBufPrevFrame[16], timeBufCurFrame[16]; + int nNodesNodeRes, nNodesCur, k, m; + + if (gainSet->gainCodingProfile == GCP_CONSTANT) { + *pNNodes = 1; + pNodes[0].time = frameSize - 1; + pNodes[0].gainDb = (FIXP_SGL)0; + } else { + _readNodes(hBs, gainSet, frameSize, timeDeltaMin, pNNodes, pNodes); + + /* count number of nodes in node reservoir */ + nNodesNodeRes = 0; + nNodesCur = 0; + /* count and buffer nodes from node reservoir */ + for (k = 0; k < *pNNodes; k++) { + if (k >= 16) continue; + if (pNodes[k].time >= frameSize) { + /* write node reservoir times into buffer */ + timeBufPrevFrame[nNodesNodeRes] = pNodes[k].time; + nNodesNodeRes++; + } else { /* times from current frame */ + timeBufCurFrame[nNodesCur] = pNodes[k].time; + nNodesCur++; + } + } + /* compose right time order (bit reservoir first) */ + for (k = 0; k < nNodesNodeRes; k++) { + /* subtract two time frameSize: one to remove node reservoir offset and + * one to get the negative index relative to the current frame + */ + pNodes[k].time = timeBufPrevFrame[k] - 2 * frameSize; + } + /* ...and times from current frame */ + for (m = 0; m < nNodesCur; m++, k++) { + pNodes[k].time = timeBufCurFrame[m]; + } + } +} + +static DRC_ERROR _readUniDrcGainExtension(HANDLE_FDK_BITSTREAM hBs, + UNI_DRC_GAIN_EXTENSION* pExt) { + DRC_ERROR err = DE_OK; + int k, bitSizeLen, extSizeBits, bitSize; + + k = 0; + pExt->uniDrcGainExtType[k] = FDKreadBits(hBs, 4); + while (pExt->uniDrcGainExtType[k] != UNIDRCGAINEXT_TERM) { + if (k >= (8 - 1)) return DE_MEMORY_ERROR; + bitSizeLen = FDKreadBits(hBs, 3); + extSizeBits = bitSizeLen + 4; + + bitSize = FDKreadBits(hBs, extSizeBits); + pExt->extBitSize[k] = bitSize + 1; + + switch (pExt->uniDrcGainExtType[k]) { + /* add future extensions here */ + default: + FDKpushFor(hBs, pExt->extBitSize[k]); + break; + } + k++; + pExt->uniDrcGainExtType[k] = FDKreadBits(hBs, 4); + } + + return err; +} + +DRC_ERROR +drcDec_readUniDrcGain(HANDLE_FDK_BITSTREAM hBs, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, const int frameSize, + const int deltaTminDefault, + HANDLE_UNI_DRC_GAIN hUniDrcGain) { + DRC_ERROR err = DE_OK; + int seq, gainSequenceCount; + DRC_COEFFICIENTS_UNI_DRC* pCoef = + selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED); + if (pCoef == NULL) return DE_OK; + if (hUniDrcGain == NULL) return DE_OK; /* hUniDrcGain not initialized yet */ + + gainSequenceCount = fMin(pCoef->gainSequenceCount, (UCHAR)12); + + for (seq = 0; seq < gainSequenceCount; seq++) { + UCHAR index = pCoef->gainSetIndexForGainSequence[seq]; + GAIN_SET* gainSet; + int timeDeltaMin; + UCHAR tmpNNodes = 0; + GAIN_NODE tmpNodes[16]; + + if ((index >= pCoef->gainSetCount) || (index >= 12)) return DE_NOT_OK; + gainSet = &(pCoef->gainSet[index]); + + timeDeltaMin = _getTimeDeltaMin(gainSet, deltaTminDefault); + + _readDrcGainSequence(hBs, gainSet, frameSize, timeDeltaMin, &tmpNNodes, + tmpNodes); + + hUniDrcGain->nNodes[seq] = tmpNNodes; + FDKmemcpy(hUniDrcGain->gainNode[seq], tmpNodes, + fMin(tmpNNodes, (UCHAR)16) * sizeof(GAIN_NODE)); + } + + hUniDrcGain->uniDrcGainExtPresent = FDKreadBits(hBs, 1); + if (hUniDrcGain->uniDrcGainExtPresent == 1) { + err = _readUniDrcGainExtension(hBs, &(hUniDrcGain->uniDrcGainExtension)); + if (err) return err; + } + + return err; +} + +/****************/ +/* uniDrcConfig */ +/****************/ + +static void _decodeDuckingModification(HANDLE_FDK_BITSTREAM hBs, + DUCKING_MODIFICATION* pDMod, int isBox) { + int bsDuckingScaling, sigma, mu; + + if (isBox) FDKpushFor(hBs, 7); /* reserved */ + pDMod->duckingScalingPresent = FDKreadBits(hBs, 1); + + if (pDMod->duckingScalingPresent) { + if (isBox) FDKpushFor(hBs, 4); /* reserved */ + bsDuckingScaling = FDKreadBits(hBs, 4); + sigma = bsDuckingScaling >> 3; + mu = bsDuckingScaling & 0x7; + + if (sigma) { + pDMod->duckingScaling = (FIXP_SGL)( + (7 - mu) << (FRACT_BITS - 1 - 3 - 2)); /* 1.0 - 0.125 * (1 + mu); */ + } else { + pDMod->duckingScaling = (FIXP_SGL)( + (9 + mu) << (FRACT_BITS - 1 - 3 - 2)); /* 1.0 + 0.125 * (1 + mu); */ + } + } else { + pDMod->duckingScaling = (FIXP_SGL)(1 << (FRACT_BITS - 1 - 2)); /* 1.0 */ + } +} + +static void _decodeGainModification(HANDLE_FDK_BITSTREAM hBs, const int version, + int bandCount, GAIN_MODIFICATION* pGMod, + int isBox) { + int sign, bsGainOffset, bsAttenuationScaling, bsAmplificationScaling; + + if (version > 0) { + int b, shapeFilterPresent; + + if (isBox) { + FDKpushFor(hBs, 4); /* reserved */ + bandCount = FDKreadBits(hBs, 4); + } + + for (b = 0; b < bandCount; b++) { + if (isBox) { + FDKpushFor(hBs, 4); /* reserved */ + pGMod[b].targetCharacteristicLeftPresent = FDKreadBits(hBs, 1); + pGMod[b].targetCharacteristicRightPresent = FDKreadBits(hBs, 1); + pGMod[b].gainScalingPresent = FDKreadBits(hBs, 1); + pGMod[b].gainOffsetPresent = FDKreadBits(hBs, 1); + } + + if (!isBox) + pGMod[b].targetCharacteristicLeftPresent = FDKreadBits(hBs, 1); + if (pGMod[b].targetCharacteristicLeftPresent) { + if (isBox) FDKpushFor(hBs, 4); /* reserved */ + pGMod[b].targetCharacteristicLeftIndex = FDKreadBits(hBs, 4); + } + if (!isBox) + pGMod[b].targetCharacteristicRightPresent = FDKreadBits(hBs, 1); + if (pGMod[b].targetCharacteristicRightPresent) { + if (isBox) FDKpushFor(hBs, 4); /* reserved */ + pGMod[b].targetCharacteristicRightIndex = FDKreadBits(hBs, 4); + } + if (!isBox) pGMod[b].gainScalingPresent = FDKreadBits(hBs, 1); + if (pGMod[b].gainScalingPresent) { + bsAttenuationScaling = FDKreadBits(hBs, 4); + pGMod[b].attenuationScaling = (FIXP_SGL)( + bsAttenuationScaling + << (FRACT_BITS - 1 - 3 - 2)); /* bsAttenuationScaling * 0.125; */ + bsAmplificationScaling = FDKreadBits(hBs, 4); + pGMod[b].amplificationScaling = (FIXP_SGL)( + bsAmplificationScaling + << (FRACT_BITS - 1 - 3 - 2)); /* bsAmplificationScaling * 0.125; */ + } + if (!isBox) pGMod[b].gainOffsetPresent = FDKreadBits(hBs, 1); + if (pGMod[b].gainOffsetPresent) { + if (isBox) FDKpushFor(hBs, 2); /* reserved */ + sign = FDKreadBits(hBs, 1); + bsGainOffset = FDKreadBits(hBs, 5); + pGMod[b].gainOffset = (FIXP_SGL)( + (1 + bsGainOffset) + << (FRACT_BITS - 1 - 2 - 4)); /* (1+bsGainOffset) * 0.25; */ + if (sign) { + pGMod[b].gainOffset = -pGMod[b].gainOffset; + } + } + } + if (bandCount == 1) { + shapeFilterPresent = FDKreadBits(hBs, 1); + if (shapeFilterPresent) { + if (isBox) FDKpushFor(hBs, 3); /* reserved */ + FDKpushFor(hBs, 4); /* pGMod->shapeFilterIndex */ + } else { + if (isBox) FDKpushFor(hBs, 7); /* reserved */ + } + } + } else { + int b, gainScalingPresent, gainOffsetPresent; + FIXP_SGL attenuationScaling = FL2FXCONST_SGL(1.0f / (float)(1 << 2)), + amplificationScaling = FL2FXCONST_SGL(1.0f / (float)(1 << 2)), + gainOffset = (FIXP_SGL)0; + if (isBox) FDKpushFor(hBs, 7); /* reserved */ + gainScalingPresent = FDKreadBits(hBs, 1); + if (gainScalingPresent) { + bsAttenuationScaling = FDKreadBits(hBs, 4); + attenuationScaling = (FIXP_SGL)( + bsAttenuationScaling + << (FRACT_BITS - 1 - 3 - 2)); /* bsAttenuationScaling * 0.125; */ + bsAmplificationScaling = FDKreadBits(hBs, 4); + amplificationScaling = (FIXP_SGL)( + bsAmplificationScaling + << (FRACT_BITS - 1 - 3 - 2)); /* bsAmplificationScaling * 0.125; */ + } + if (isBox) FDKpushFor(hBs, 7); /* reserved */ + gainOffsetPresent = FDKreadBits(hBs, 1); + if (gainOffsetPresent) { + if (isBox) FDKpushFor(hBs, 2); /* reserved */ + sign = FDKreadBits(hBs, 1); + bsGainOffset = FDKreadBits(hBs, 5); + gainOffset = + (FIXP_SGL)((1 + bsGainOffset) << (FRACT_BITS - 1 - 2 - + 4)); /* (1+bsGainOffset) * 0.25; */ + if (sign) { + gainOffset = -gainOffset; + } + } + for (b = 0; b < 4; b++) { + pGMod[b].targetCharacteristicLeftPresent = 0; + pGMod[b].targetCharacteristicRightPresent = 0; + pGMod[b].gainScalingPresent = gainScalingPresent; + pGMod[b].attenuationScaling = attenuationScaling; + pGMod[b].amplificationScaling = amplificationScaling; + pGMod[b].gainOffsetPresent = gainOffsetPresent; + pGMod[b].gainOffset = gainOffset; + } + } +} + +static void _readDrcCharacteristic(HANDLE_FDK_BITSTREAM hBs, const int version, + DRC_CHARACTERISTIC* pDChar, int isBox) { + if (version == 0) { + if (isBox) FDKpushFor(hBs, 1); /* reserved */ + pDChar->cicpIndex = FDKreadBits(hBs, 7); + if (pDChar->cicpIndex > 0) { + pDChar->present = 1; + pDChar->isCICP = 1; + } else { + pDChar->present = 0; + } + } else { + pDChar->present = FDKreadBits(hBs, 1); + if (isBox) pDChar->isCICP = FDKreadBits(hBs, 1); + if (pDChar->present) { + if (!isBox) pDChar->isCICP = FDKreadBits(hBs, 1); + if (pDChar->isCICP) { + if (isBox) FDKpushFor(hBs, 1); /* reserved */ + pDChar->cicpIndex = FDKreadBits(hBs, 7); + } else { + pDChar->custom.left = FDKreadBits(hBs, 4); + pDChar->custom.right = FDKreadBits(hBs, 4); + } + } + } +} + +static void _readBandBorder(HANDLE_FDK_BITSTREAM hBs, BAND_BORDER* pBBord, + int drcBandType, int isBox) { + if (drcBandType) { + if (isBox) FDKpushFor(hBs, 4); /* reserved */ + pBBord->crossoverFreqIndex = FDKreadBits(hBs, 4); + } else { + if (isBox) FDKpushFor(hBs, 6); /* reserved */ + pBBord->startSubBandIndex = FDKreadBits(hBs, 10); + } +} + +static DRC_ERROR _readGainSet(HANDLE_FDK_BITSTREAM hBs, const int version, + int* gainSequenceIndex, GAIN_SET* pGSet, + int isBox) { + if (isBox) FDKpushFor(hBs, 2); /* reserved */ + pGSet->gainCodingProfile = FDKreadBits(hBs, 2); + pGSet->gainInterpolationType = FDKreadBits(hBs, 1); + pGSet->fullFrame = FDKreadBits(hBs, 1); + pGSet->timeAlignment = FDKreadBits(hBs, 1); + pGSet->timeDeltaMinPresent = FDKreadBits(hBs, 1); + + if (pGSet->timeDeltaMinPresent) { + int bsTimeDeltaMin; + if (isBox) FDKpushFor(hBs, 5); /* reserved */ + bsTimeDeltaMin = FDKreadBits(hBs, 11); + pGSet->timeDeltaMin = bsTimeDeltaMin + 1; + } + + if (pGSet->gainCodingProfile != GCP_CONSTANT) { + int i; + if (isBox) FDKpushFor(hBs, 3); /* reserved */ + pGSet->bandCount = FDKreadBits(hBs, 4); + if (pGSet->bandCount > 4) return DE_MEMORY_ERROR; + + if ((pGSet->bandCount > 1) || isBox) { + pGSet->drcBandType = FDKreadBits(hBs, 1); + } + + for (i = 0; i < pGSet->bandCount; i++) { + if (version == 0) { + *gainSequenceIndex = (*gainSequenceIndex) + 1; + } else { + int indexPresent; + indexPresent = (isBox) ? 1 : FDKreadBits(hBs, 1); + if (indexPresent) { + int bsIndex; + bsIndex = FDKreadBits(hBs, 6); + *gainSequenceIndex = bsIndex; + } else { + *gainSequenceIndex = (*gainSequenceIndex) + 1; + } + } + pGSet->gainSequenceIndex[i] = *gainSequenceIndex; + _readDrcCharacteristic(hBs, version, &(pGSet->drcCharacteristic[i]), + isBox); + } + for (i = 1; i < pGSet->bandCount; i++) { + _readBandBorder(hBs, &(pGSet->bandBorder[i]), pGSet->drcBandType, isBox); + } + } else { + pGSet->bandCount = 1; + *gainSequenceIndex = (*gainSequenceIndex) + 1; + pGSet->gainSequenceIndex[0] = *gainSequenceIndex; + } + + return DE_OK; +} + +static DRC_ERROR _readCustomDrcCharacteristic(HANDLE_FDK_BITSTREAM hBs, + const CHARACTERISTIC_SIDE side, + UCHAR* pCharacteristicFormat, + CUSTOM_DRC_CHAR* pCChar, + int isBox) { + if (isBox) FDKpushFor(hBs, 7); /* reserved */ + *pCharacteristicFormat = FDKreadBits(hBs, 1); + if (*pCharacteristicFormat == CF_SIGMOID) { + int bsGain, bsIoRatio, bsExp; + if (isBox) FDKpushFor(hBs, 1); /* reserved */ + bsGain = FDKreadBits(hBs, 6); + if (side == CS_LEFT) { + pCChar->sigmoid.gain = (FIXP_SGL)(bsGain << (FRACT_BITS - 1 - 6)); + } else { + pCChar->sigmoid.gain = (FIXP_SGL)(-bsGain << (FRACT_BITS - 1 - 6)); + } + bsIoRatio = FDKreadBits(hBs, 4); + /* pCChar->sigmoid.ioRatio = 0.05 + 0.15 * bsIoRatio; */ + pCChar->sigmoid.ioRatio = + FL2FXCONST_SGL(0.05f / (float)(1 << 2)) + + (FIXP_SGL)((((3 * bsIoRatio) << (FRACT_BITS - 1)) / 5) >> 4); + bsExp = FDKreadBits(hBs, 4); + if (bsExp < 15) { + pCChar->sigmoid.exp = (FIXP_SGL)((1 + 2 * bsExp) << (FRACT_BITS - 1 - 5)); + } else { + pCChar->sigmoid.exp = (FIXP_SGL)MAXVAL_SGL; /* represents infinity */ + } + pCChar->sigmoid.flipSign = FDKreadBits(hBs, 1); + } else { /* CF_NODES */ + int i, bsCharacteristicNodeCount, bsNodeLevelDelta, bsNodeGain; + if (isBox) FDKpushFor(hBs, 6); /* reserved */ + bsCharacteristicNodeCount = FDKreadBits(hBs, 2); + pCChar->nodes.characteristicNodeCount = bsCharacteristicNodeCount + 1; + if (pCChar->nodes.characteristicNodeCount > 4) return DE_MEMORY_ERROR; + pCChar->nodes.nodeLevel[0] = DRC_INPUT_LOUDNESS_TARGET_SGL; + pCChar->nodes.nodeGain[0] = (FIXP_SGL)0; + for (i = 0; i < pCChar->nodes.characteristicNodeCount; i++) { + if (isBox) FDKpushFor(hBs, 3); /* reserved */ + bsNodeLevelDelta = FDKreadBits(hBs, 5); + if (side == CS_LEFT) { + pCChar->nodes.nodeLevel[i + 1] = + pCChar->nodes.nodeLevel[i] - + (FIXP_SGL)((1 + bsNodeLevelDelta) << (FRACT_BITS - 1 - 7)); + } else { + pCChar->nodes.nodeLevel[i + 1] = + pCChar->nodes.nodeLevel[i] + + (FIXP_SGL)((1 + bsNodeLevelDelta) << (FRACT_BITS - 1 - 7)); + } + bsNodeGain = FDKreadBits(hBs, 8); + pCChar->nodes.nodeGain[i + 1] = (FIXP_SGL)( + (bsNodeGain - 128) + << (FRACT_BITS - 1 - 1 - 7)); /* 0.5f * bsNodeGain - 64.0f; */ + } + } + return DE_OK; +} + +static void _skipLoudEqInstructions(HANDLE_FDK_BITSTREAM hBs) { + int i; + int downmixIdPresent, additionalDownmixIdPresent, + additionalDownmixIdCount = 0; + int drcSetIdPresent, additionalDrcSetIdPresent, additionalDrcSetIdCount = 0; + int eqSetIdPresent, additionalEqSetIdPresent, additionalEqSetIdCount = 0; + int loudEqGainSequenceCount, drcCharacteristicFormatIsCICP; + + FDKpushFor(hBs, 4); /* loudEqSetId */ + FDKpushFor(hBs, 4); /* drcLocation */ + downmixIdPresent = FDKreadBits(hBs, 1); + if (downmixIdPresent) { + FDKpushFor(hBs, 7); /* downmixId */ + additionalDownmixIdPresent = FDKreadBits(hBs, 1); + if (additionalDownmixIdPresent) { + additionalDownmixIdCount = FDKreadBits(hBs, 7); + for (i = 0; i < additionalDownmixIdCount; i++) { + FDKpushFor(hBs, 7); /* additionalDownmixId */ + } + } + } + + drcSetIdPresent = FDKreadBits(hBs, 1); + if (drcSetIdPresent) { + FDKpushFor(hBs, 6); /* drcSetId */ + additionalDrcSetIdPresent = FDKreadBits(hBs, 1); + if (additionalDrcSetIdPresent) { + additionalDrcSetIdCount = FDKreadBits(hBs, 6); + for (i = 0; i < additionalDrcSetIdCount; i++) { + FDKpushFor(hBs, 6); /* additionalDrcSetId; */ + } + } + } + + eqSetIdPresent = FDKreadBits(hBs, 1); + if (eqSetIdPresent) { + FDKpushFor(hBs, 6); /* eqSetId */ + additionalEqSetIdPresent = FDKreadBits(hBs, 1); + if (additionalEqSetIdPresent) { + additionalEqSetIdCount = FDKreadBits(hBs, 6); + for (i = 0; i < additionalEqSetIdCount; i++) { + FDKpushFor(hBs, 6); /* additionalEqSetId; */ + } + } + } + + FDKpushFor(hBs, 1); /* loudnessAfterDrc */ + FDKpushFor(hBs, 1); /* loudnessAfterEq */ + loudEqGainSequenceCount = FDKreadBits(hBs, 6); + for (i = 0; i < loudEqGainSequenceCount; i++) { + FDKpushFor(hBs, 6); /* gainSequenceIndex */ + drcCharacteristicFormatIsCICP = FDKreadBits(hBs, 1); + if (drcCharacteristicFormatIsCICP) { + FDKpushFor(hBs, 7); /* drcCharacteristic */ + } else { + FDKpushFor(hBs, 4); /* drcCharacteristicLeftIndex */ + FDKpushFor(hBs, 4); /* drcCharacteristicRightIndex */ + } + FDKpushFor(hBs, 6); /* frequencyRangeIndex */ + FDKpushFor(hBs, 3); /* bsLoudEqScaling */ + FDKpushFor(hBs, 5); /* bsLoudEqOffset */ + } +} + +static void _skipEqSubbandGainSpline(HANDLE_FDK_BITSTREAM hBs) { + int nEqNodes, k, bits; + nEqNodes = FDKreadBits(hBs, 5); + nEqNodes += 2; + for (k = 0; k < nEqNodes; k++) { + bits = FDKreadBits(hBs, 1); + if (!bits) { + FDKpushFor(hBs, 4); + } + } + FDKpushFor(hBs, 4 * (nEqNodes - 1)); + bits = FDKreadBits(hBs, 2); + switch (bits) { + case 0: + FDKpushFor(hBs, 5); + break; + case 1: + case 2: + FDKpushFor(hBs, 4); + break; + case 3: + FDKpushFor(hBs, 3); + break; + } + FDKpushFor(hBs, 5 * (nEqNodes - 1)); +} + +static void _skipEqCoefficients(HANDLE_FDK_BITSTREAM hBs) { + int j, k; + int eqDelayMaxPresent; + int uniqueFilterBlockCount, filterElementCount, filterElementGainPresent; + int uniqueTdFilterElementCount, eqFilterFormat, bsRealZeroRadiusOneCount, + realZeroCount, genericZeroCount, realPoleCount, complexPoleCount, + firFilterOrder; + int uniqueEqSubbandGainsCount, eqSubbandGainRepresentation, + eqSubbandGainCount; + EQ_SUBBAND_GAIN_FORMAT eqSubbandGainFormat; + + eqDelayMaxPresent = FDKreadBits(hBs, 1); + if (eqDelayMaxPresent) { + FDKpushFor(hBs, 8); /* bsEqDelayMax */ + } + + uniqueFilterBlockCount = FDKreadBits(hBs, 6); + for (j = 0; j < uniqueFilterBlockCount; j++) { + filterElementCount = FDKreadBits(hBs, 6); + for (k = 0; k < filterElementCount; k++) { + FDKpushFor(hBs, 6); /* filterElementIndex */ + filterElementGainPresent = FDKreadBits(hBs, 1); + if (filterElementGainPresent) { + FDKpushFor(hBs, 10); /* bsFilterElementGain */ + } + } + } + uniqueTdFilterElementCount = FDKreadBits(hBs, 6); + for (j = 0; j < uniqueTdFilterElementCount; j++) { + eqFilterFormat = FDKreadBits(hBs, 1); + if (eqFilterFormat == 0) { /* pole/zero */ + bsRealZeroRadiusOneCount = FDKreadBits(hBs, 3); + realZeroCount = FDKreadBits(hBs, 6); + genericZeroCount = FDKreadBits(hBs, 6); + realPoleCount = FDKreadBits(hBs, 4); + complexPoleCount = FDKreadBits(hBs, 4); + FDKpushFor(hBs, 2 * bsRealZeroRadiusOneCount * 1); + FDKpushFor(hBs, realZeroCount * 8); + FDKpushFor(hBs, genericZeroCount * 14); + FDKpushFor(hBs, realPoleCount * 8); + FDKpushFor(hBs, complexPoleCount * 14); + } else { /* FIR coefficients */ + firFilterOrder = FDKreadBits(hBs, 7); + FDKpushFor(hBs, 1); + FDKpushFor(hBs, (firFilterOrder / 2 + 1) * 11); + } + } + uniqueEqSubbandGainsCount = FDKreadBits(hBs, 6); + if (uniqueEqSubbandGainsCount > 0) { + eqSubbandGainRepresentation = FDKreadBits(hBs, 1); + eqSubbandGainFormat = (EQ_SUBBAND_GAIN_FORMAT)FDKreadBits(hBs, 4); + switch (eqSubbandGainFormat) { + case GF_QMF32: + eqSubbandGainCount = 32; + break; + case GF_QMFHYBRID39: + eqSubbandGainCount = 39; + break; + case GF_QMF64: + eqSubbandGainCount = 64; + break; + case GF_QMFHYBRID71: + eqSubbandGainCount = 71; + break; + case GF_QMF128: + eqSubbandGainCount = 128; + break; + case GF_QMFHYBRID135: + eqSubbandGainCount = 135; + break; + case GF_UNIFORM: + default: + eqSubbandGainCount = FDKreadBits(hBs, 8); + eqSubbandGainCount++; + break; + } + for (k = 0; k < uniqueEqSubbandGainsCount; k++) { + if (eqSubbandGainRepresentation == 1) { + _skipEqSubbandGainSpline(hBs); + } else { + FDKpushFor(hBs, eqSubbandGainCount * 9); + } + } + } +} + +static void _skipTdFilterCascade(HANDLE_FDK_BITSTREAM hBs, + const int eqChannelGroupCount) { + int i, eqCascadeGainPresent, filterBlockCount, eqPhaseAlignmentPresent; + for (i = 0; i < eqChannelGroupCount; i++) { + eqCascadeGainPresent = FDKreadBits(hBs, 1); + if (eqCascadeGainPresent) { + FDKpushFor(hBs, 10); /* bsEqCascadeGain */ + } + filterBlockCount = FDKreadBits(hBs, 4); + FDKpushFor(hBs, filterBlockCount * 7); /* filterBlockIndex */ + } + eqPhaseAlignmentPresent = FDKreadBits(hBs, 1); + { + if (eqPhaseAlignmentPresent) { + for (i = 0; i < eqChannelGroupCount; i++) { + FDKpushFor(hBs, (eqChannelGroupCount - i - 1) * 1); + } + } + } +} + +static DRC_ERROR _skipEqInstructions(HANDLE_FDK_BITSTREAM hBs, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig) { + DRC_ERROR err = DE_OK; + int c, i, k, channelCount; + int downmixIdPresent, downmixId, eqApplyToDownmix, additionalDownmixIdPresent, + additionalDownmixIdCount = 0; + int additionalDrcSetIdPresent, additionalDrcSetIdCount; + int dependsOnEqSetPresent, eqChannelGroupCount, tdFilterCascadePresent, + subbandGainsPresent, eqTransitionDurationPresent; + + FDKpushFor(hBs, 6); /* eqSetId */ + FDKpushFor(hBs, 4); /* eqSetComplexityLevel */ + downmixIdPresent = FDKreadBits(hBs, 1); + if (downmixIdPresent) { + downmixId = FDKreadBits(hBs, 7); + eqApplyToDownmix = FDKreadBits(hBs, 1); + additionalDownmixIdPresent = FDKreadBits(hBs, 1); + if (additionalDownmixIdPresent) { + additionalDownmixIdCount = FDKreadBits(hBs, 7); + FDKpushFor(hBs, additionalDownmixIdCount * 7); /* additionalDownmixId */ + } + } else { + downmixId = 0; + eqApplyToDownmix = 0; + } + FDKpushFor(hBs, 6); /* drcSetId */ + additionalDrcSetIdPresent = FDKreadBits(hBs, 1); + if (additionalDrcSetIdPresent) { + additionalDrcSetIdCount = FDKreadBits(hBs, 6); + for (i = 0; i < additionalDrcSetIdCount; i++) { + FDKpushFor(hBs, 6); /* additionalDrcSetId */ + } + } + FDKpushFor(hBs, 16); /* eqSetPurpose */ + dependsOnEqSetPresent = FDKreadBits(hBs, 1); + if (dependsOnEqSetPresent) { + FDKpushFor(hBs, 6); /* dependsOnEqSet */ + } else { + FDKpushFor(hBs, 1); /* noIndependentEqUse */ + } + + channelCount = hUniDrcConfig->channelLayout.baseChannelCount; + if ((downmixIdPresent == 1) && (eqApplyToDownmix == 1) && (downmixId != 0) && + (downmixId != DOWNMIX_ID_ANY_DOWNMIX) && + (additionalDownmixIdCount == 0)) { + DOWNMIX_INSTRUCTIONS* pDown = + selectDownmixInstructions(hUniDrcConfig, downmixId); + if (pDown == NULL) return DE_NOT_OK; + + channelCount = + pDown->targetChannelCount; /* targetChannelCountFromDownmixId*/ + } else if ((downmixId == DOWNMIX_ID_ANY_DOWNMIX) || + (additionalDownmixIdCount > 1)) { + channelCount = 1; + } + + eqChannelGroupCount = 0; + for (c = 0; c < channelCount; c++) { + UCHAR eqChannelGroupForChannel[8]; + int newGroup = 1; + if (c >= 8) return DE_MEMORY_ERROR; + eqChannelGroupForChannel[c] = FDKreadBits(hBs, 7); + for (k = 0; k < c; k++) { + if (eqChannelGroupForChannel[c] == eqChannelGroupForChannel[k]) { + newGroup = 0; + } + } + if (newGroup == 1) { + eqChannelGroupCount += 1; + } + } + tdFilterCascadePresent = FDKreadBits(hBs, 1); + if (tdFilterCascadePresent) { + _skipTdFilterCascade(hBs, eqChannelGroupCount); + } + subbandGainsPresent = FDKreadBits(hBs, 1); + if (subbandGainsPresent) { + FDKpushFor(hBs, eqChannelGroupCount * 6); /* subbandGainsIndex */ + } + eqTransitionDurationPresent = FDKreadBits(hBs, 1); + if (eqTransitionDurationPresent) { + FDKpushFor(hBs, 5); /* bsEqTransitionDuration */ + } + return err; +} + +static void _skipDrcCoefficientsBasic(HANDLE_FDK_BITSTREAM hBs) { + FDKpushFor(hBs, 4); /* drcLocation */ + FDKpushFor(hBs, 7); /* drcCharacteristic */ +} + +static DRC_ERROR _readDrcCoefficientsUniDrc(HANDLE_FDK_BITSTREAM hBs, + const int version, + DRC_COEFFICIENTS_UNI_DRC* pCoef) { + DRC_ERROR err = DE_OK; + int i, bsDrcFrameSize; + int gainSequenceIndex = -1; + + pCoef->drcLocation = FDKreadBits(hBs, 4); + pCoef->drcFrameSizePresent = FDKreadBits(hBs, 1); + + if (pCoef->drcFrameSizePresent == 1) { + bsDrcFrameSize = FDKreadBits(hBs, 15); + pCoef->drcFrameSize = bsDrcFrameSize + 1; + } + if (version == 0) { + int gainSequenceCount = 0, gainSetCount; + pCoef->characteristicLeftCount = 0; + pCoef->characteristicRightCount = 0; + gainSetCount = FDKreadBits(hBs, 6); + pCoef->gainSetCount = fMin(gainSetCount, 12); + for (i = 0; i < gainSetCount; i++) { + GAIN_SET tmpGset; + FDKmemclear(&tmpGset, sizeof(GAIN_SET)); + err = _readGainSet(hBs, version, &gainSequenceIndex, &tmpGset, 0); + if (err) return err; + gainSequenceCount += tmpGset.bandCount; + + if (i >= 12) continue; + pCoef->gainSet[i] = tmpGset; + } + pCoef->gainSequenceCount = gainSequenceCount; + } else { /* (version == 1) */ + UCHAR drcCharacteristicLeftPresent, drcCharacteristicRightPresent; + UCHAR shapeFiltersPresent, shapeFilterCount, tmpPresent; + int gainSetCount; + drcCharacteristicLeftPresent = FDKreadBits(hBs, 1); + if (drcCharacteristicLeftPresent) { + pCoef->characteristicLeftCount = FDKreadBits(hBs, 4); + if ((pCoef->characteristicLeftCount + 1) > 8) return DE_MEMORY_ERROR; + for (i = 0; i < pCoef->characteristicLeftCount; i++) { + err = _readCustomDrcCharacteristic( + hBs, CS_LEFT, &(pCoef->characteristicLeftFormat[i + 1]), + &(pCoef->customCharacteristicLeft[i + 1]), 0); + if (err) return err; + } + } + drcCharacteristicRightPresent = FDKreadBits(hBs, 1); + if (drcCharacteristicRightPresent) { + pCoef->characteristicRightCount = FDKreadBits(hBs, 4); + if ((pCoef->characteristicRightCount + 1) > 8) return DE_MEMORY_ERROR; + for (i = 0; i < pCoef->characteristicRightCount; i++) { + err = _readCustomDrcCharacteristic( + hBs, CS_RIGHT, &(pCoef->characteristicRightFormat[i + 1]), + &(pCoef->customCharacteristicRight[i + 1]), 0); + if (err) return err; + } + } + shapeFiltersPresent = FDKreadBits(hBs, 1); + if (shapeFiltersPresent) { + shapeFilterCount = FDKreadBits(hBs, 4); + for (i = 0; i < shapeFilterCount; i++) { + tmpPresent = FDKreadBits(hBs, 1); + if (tmpPresent) /* lfCutParams */ + FDKpushFor(hBs, 5); + + tmpPresent = FDKreadBits(hBs, 1); + if (tmpPresent) /* lfBoostParams */ + FDKpushFor(hBs, 5); + + tmpPresent = FDKreadBits(hBs, 1); + if (tmpPresent) /* hfCutParams */ + FDKpushFor(hBs, 5); + + tmpPresent = FDKreadBits(hBs, 1); + if (tmpPresent) /* hfBoostParams */ + FDKpushFor(hBs, 5); + } + } + pCoef->gainSequenceCount = FDKreadBits(hBs, 6); + gainSetCount = FDKreadBits(hBs, 6); + pCoef->gainSetCount = fMin(gainSetCount, 12); + for (i = 0; i < gainSetCount; i++) { + GAIN_SET tmpGset; + FDKmemclear(&tmpGset, sizeof(GAIN_SET)); + err = _readGainSet(hBs, version, &gainSequenceIndex, &tmpGset, 0); + if (err) return err; + + if (i >= 12) continue; + pCoef->gainSet[i] = tmpGset; + } + } + for (i = 0; i < 12; i++) { + pCoef->gainSetIndexForGainSequence[i] = 255; + } + for (i = 0; i < pCoef->gainSetCount; i++) { + int b; + for (b = 0; b < pCoef->gainSet[i].bandCount; b++) { + if (pCoef->gainSet[i].gainSequenceIndex[b] >= 12) continue; + pCoef->gainSetIndexForGainSequence[pCoef->gainSet[i] + .gainSequenceIndex[b]] = i; + } + } + + return err; +} + +static void _skipDrcInstructionsBasic(HANDLE_FDK_BITSTREAM hBs) { + int drcSetEffect; + int additionalDownmixIdPresent, additionalDownmixIdCount, + limiterPeakTargetPresent; + int drcSetTargetLoudnessPresent, drcSetTargetLoudnessValueLowerPresent; + + FDKpushFor(hBs, 6); /* drcSetId */ + FDKpushFor(hBs, 4); /* drcLocation */ + FDKpushFor(hBs, 7); /* downmixId */ + additionalDownmixIdPresent = FDKreadBits(hBs, 1); + if (additionalDownmixIdPresent) { + additionalDownmixIdCount = FDKreadBits(hBs, 3); + FDKpushFor(hBs, 7 * additionalDownmixIdCount); /* additionalDownmixId */ + } + + drcSetEffect = FDKreadBits(hBs, 16); + if (!(drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF))) { + limiterPeakTargetPresent = FDKreadBits(hBs, 1); + if (limiterPeakTargetPresent) { + FDKpushFor(hBs, 8); /* bsLimiterPeakTarget */ + } + } + + drcSetTargetLoudnessPresent = FDKreadBits(hBs, 1); + if (drcSetTargetLoudnessPresent) { + FDKpushFor(hBs, 6); /* bsDrcSetTargetLoudnessValueUpper */ + drcSetTargetLoudnessValueLowerPresent = FDKreadBits(hBs, 1); + if (drcSetTargetLoudnessValueLowerPresent) { + FDKpushFor(hBs, 6); /* bsDrcSetTargetLoudnessValueLower */ + } + } +} + +static DRC_ERROR _readDrcInstructionsUniDrc(HANDLE_FDK_BITSTREAM hBs, + const int version, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + DRC_INSTRUCTIONS_UNI_DRC* pInst) { + DRC_ERROR err = DE_OK; + int i, g, c; + int downmixIdPresent, additionalDownmixIdPresent, additionalDownmixIdCount; + int bsLimiterPeakTarget, channelCount; + DRC_COEFFICIENTS_UNI_DRC* pCoef = NULL; + int repeatParameters, bsRepeatParametersCount; + int repeatSequenceIndex, bsRepeatSequenceCount; + SCHAR* gainSetIndex = pInst->gainSetIndex; + SCHAR channelGroupForChannel[8]; + DUCKING_MODIFICATION duckingModificationForChannelGroup[8]; + + pInst->drcSetId = FDKreadBits(hBs, 6); + if (version == 0) { + /* Assume all v0 DRC sets to be manageable in terms of complexity */ + pInst->drcSetComplexityLevel = 2; + } else { + pInst->drcSetComplexityLevel = FDKreadBits(hBs, 4); + } + pInst->drcLocation = FDKreadBits(hBs, 4); + if (version == 0) { + downmixIdPresent = 1; + } else { + downmixIdPresent = FDKreadBits(hBs, 1); + } + if (downmixIdPresent) { + pInst->downmixId[0] = FDKreadBits(hBs, 7); + if (version == 0) { + if (pInst->downmixId[0] == 0) + pInst->drcApplyToDownmix = 0; + else + pInst->drcApplyToDownmix = 1; + } else { + pInst->drcApplyToDownmix = FDKreadBits(hBs, 1); + } + + additionalDownmixIdPresent = FDKreadBits(hBs, 1); + if (additionalDownmixIdPresent) { + additionalDownmixIdCount = FDKreadBits(hBs, 3); + if ((1 + additionalDownmixIdCount) > 8) return DE_MEMORY_ERROR; + for (i = 0; i < additionalDownmixIdCount; i++) { + pInst->downmixId[i + 1] = FDKreadBits(hBs, 7); + } + pInst->downmixIdCount = 1 + additionalDownmixIdCount; + } else { + pInst->downmixIdCount = 1; + } + } else { + pInst->downmixId[0] = 0; + pInst->downmixIdCount = 1; + } + + pInst->drcSetEffect = FDKreadBits(hBs, 16); + + if ((pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) == 0) { + pInst->limiterPeakTargetPresent = FDKreadBits(hBs, 1); + if (pInst->limiterPeakTargetPresent) { + bsLimiterPeakTarget = FDKreadBits(hBs, 8); + pInst->limiterPeakTarget = -(FIXP_SGL)( + bsLimiterPeakTarget + << (FRACT_BITS - 1 - 3 - 5)); /* - bsLimiterPeakTarget * 0.125; */ + } + } + + pInst->drcSetTargetLoudnessPresent = FDKreadBits(hBs, 1); + + /* set default values */ + pInst->drcSetTargetLoudnessValueUpper = 0; + pInst->drcSetTargetLoudnessValueLower = -63; + + if (pInst->drcSetTargetLoudnessPresent == 1) { + int bsDrcSetTargetLoudnessValueUpper, bsDrcSetTargetLoudnessValueLower; + int drcSetTargetLoudnessValueLowerPresent; + bsDrcSetTargetLoudnessValueUpper = FDKreadBits(hBs, 6); + pInst->drcSetTargetLoudnessValueUpper = + bsDrcSetTargetLoudnessValueUpper - 63; + drcSetTargetLoudnessValueLowerPresent = FDKreadBits(hBs, 1); + if (drcSetTargetLoudnessValueLowerPresent == 1) { + bsDrcSetTargetLoudnessValueLower = FDKreadBits(hBs, 6); + pInst->drcSetTargetLoudnessValueLower = + bsDrcSetTargetLoudnessValueLower - 63; + } + } + + pInst->dependsOnDrcSetPresent = FDKreadBits(hBs, 1); + + pInst->noIndependentUse = 0; + if (pInst->dependsOnDrcSetPresent) { + pInst->dependsOnDrcSet = FDKreadBits(hBs, 6); + } else { + pInst->noIndependentUse = FDKreadBits(hBs, 1); + } + + if (version == 0) { + pInst->requiresEq = 0; + } else { + pInst->requiresEq = FDKreadBits(hBs, 1); + } + + pCoef = selectDrcCoefficients(hUniDrcConfig, pInst->drcLocation); + + pInst->drcChannelCount = channelCount = + hUniDrcConfig->channelLayout.baseChannelCount; + + if (pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) { + DUCKING_MODIFICATION* pDModForChannel = + pInst->duckingModificationForChannel; + c = 0; + while (c < channelCount) { + int bsGainSetIndex; + bsGainSetIndex = FDKreadBits(hBs, 6); + if (c >= 8) return DE_MEMORY_ERROR; + gainSetIndex[c] = bsGainSetIndex - 1; + _decodeDuckingModification(hBs, &(pDModForChannel[c]), 0); + + c++; + repeatParameters = FDKreadBits(hBs, 1); + if (repeatParameters == 1) { + bsRepeatParametersCount = FDKreadBits(hBs, 5); + bsRepeatParametersCount += 1; + for (i = 0; i < bsRepeatParametersCount; i++) { + if (c >= 8) return DE_MEMORY_ERROR; + gainSetIndex[c] = gainSetIndex[c - 1]; + pDModForChannel[c] = pDModForChannel[c - 1]; + c++; + } + } + } + if (c > channelCount) { + return DE_NOT_OK; + } + + err = deriveDrcChannelGroups( + pInst->drcSetEffect, pInst->drcChannelCount, gainSetIndex, + pDModForChannel, &pInst->nDrcChannelGroups, + pInst->gainSetIndexForChannelGroup, channelGroupForChannel, + duckingModificationForChannelGroup); + if (err) return (err); + } else { + int deriveChannelCount = 0; + if (((version == 0) || (pInst->drcApplyToDownmix != 0)) && + (pInst->downmixId[0] != DOWNMIX_ID_BASE_LAYOUT) && + (pInst->downmixId[0] != DOWNMIX_ID_ANY_DOWNMIX) && + (pInst->downmixIdCount == 1)) { + if (hUniDrcConfig->downmixInstructionsCount != 0) { + DOWNMIX_INSTRUCTIONS* pDown = + selectDownmixInstructions(hUniDrcConfig, pInst->downmixId[0]); + if (pDown == NULL) return DE_NOT_OK; + pInst->drcChannelCount = channelCount = + pDown->targetChannelCount; /* targetChannelCountFromDownmixId*/ + } else { + deriveChannelCount = 1; + channelCount = 1; + } + } else if (((version == 0) || (pInst->drcApplyToDownmix != 0)) && + ((pInst->downmixId[0] == DOWNMIX_ID_ANY_DOWNMIX) || + (pInst->downmixIdCount > 1))) { + /* Set maximum channel count as upper border. The effective channel count + * is set at the process function. */ + pInst->drcChannelCount = 8; + channelCount = 1; + } + + c = 0; + while (c < channelCount) { + int bsGainSetIndex; + bsGainSetIndex = FDKreadBits(hBs, 6); + if (c >= 8) return DE_MEMORY_ERROR; + gainSetIndex[c] = bsGainSetIndex - 1; + c++; + repeatSequenceIndex = FDKreadBits(hBs, 1); + + if (repeatSequenceIndex == 1) { + bsRepeatSequenceCount = FDKreadBits(hBs, 5); + bsRepeatSequenceCount += 1; + if (deriveChannelCount) { + channelCount = 1 + bsRepeatSequenceCount; + } + for (i = 0; i < bsRepeatSequenceCount; i++) { + if (c >= 8) return DE_MEMORY_ERROR; + gainSetIndex[c] = bsGainSetIndex - 1; + c++; + } + } + } + if (c > channelCount) { + return DE_NOT_OK; + } + if (deriveChannelCount) { + pInst->drcChannelCount = channelCount; + } + + /* DOWNMIX_ID_ANY_DOWNMIX: channelCount is 1. Distribute gainSetIndex to all + * channels. */ + if ((pInst->downmixId[0] == DOWNMIX_ID_ANY_DOWNMIX) || + (pInst->downmixIdCount > 1)) { + for (c = 1; c < pInst->drcChannelCount; c++) { + gainSetIndex[c] = gainSetIndex[0]; + } + } + + err = deriveDrcChannelGroups(pInst->drcSetEffect, pInst->drcChannelCount, + gainSetIndex, NULL, &pInst->nDrcChannelGroups, + pInst->gainSetIndexForChannelGroup, + channelGroupForChannel, NULL); + if (err) return (err); + + for (g = 0; g < pInst->nDrcChannelGroups; g++) { + int set, bandCount; + set = pInst->gainSetIndexForChannelGroup[g]; + + /* get bandCount */ + if (pCoef != NULL && set < pCoef->gainSetCount) { + bandCount = pCoef->gainSet[set].bandCount; + } else { + bandCount = 1; + } + + _decodeGainModification(hBs, version, bandCount, + pInst->gainModificationForChannelGroup[g], 0); + } + } + + return err; +} + +static DRC_ERROR _readChannelLayout(HANDLE_FDK_BITSTREAM hBs, + CHANNEL_LAYOUT* pChan) { + DRC_ERROR err = DE_OK; + + pChan->baseChannelCount = FDKreadBits(hBs, 7); + + if (pChan->baseChannelCount > 8) return DE_NOT_OK; + + pChan->layoutSignalingPresent = FDKreadBits(hBs, 1); + + if (pChan->layoutSignalingPresent) { + pChan->definedLayout = FDKreadBits(hBs, 8); + + if (pChan->definedLayout == 0) { + int i; + for (i = 0; i < pChan->baseChannelCount; i++) { + if (i < 8) { + pChan->speakerPosition[i] = FDKreadBits(hBs, 7); + } else { + FDKpushFor(hBs, 7); + } + } + } + } + return err; +} + +static DRC_ERROR _readDownmixInstructions(HANDLE_FDK_BITSTREAM hBs, + const int version, + CHANNEL_LAYOUT* pChan, + DOWNMIX_INSTRUCTIONS* pDown) { + DRC_ERROR err = DE_OK; + + pDown->downmixId = FDKreadBits(hBs, 7); + pDown->targetChannelCount = FDKreadBits(hBs, 7); + pDown->targetLayout = FDKreadBits(hBs, 8); + pDown->downmixCoefficientsPresent = FDKreadBits(hBs, 1); + + if (pDown->downmixCoefficientsPresent) { + int nDownmixCoeffs = pDown->targetChannelCount * pChan->baseChannelCount; + int i; + if (nDownmixCoeffs > 8 * 8) return DE_NOT_OK; + if (version == 0) { + pDown->bsDownmixOffset = 0; + for (i = 0; i < nDownmixCoeffs; i++) { + /* LFE downmix coefficients are not supported. */ + pDown->downmixCoefficient[i] = downmixCoeff[FDKreadBits(hBs, 4)]; + } + } else { + pDown->bsDownmixOffset = FDKreadBits(hBs, 4); + for (i = 0; i < nDownmixCoeffs; i++) { + pDown->downmixCoefficient[i] = downmixCoeffV1[FDKreadBits(hBs, 5)]; + } + } + } + return err; +} + +static DRC_ERROR _readDrcExtensionV1(HANDLE_FDK_BITSTREAM hBs, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig) { + DRC_ERROR err = DE_OK; + int downmixInstructionsV1Present; + int drcCoeffsAndInstructionsUniDrcV1Present; + int loudEqInstructionsPresent, loudEqInstructionsCount; + int eqPresent, eqInstructionsCount; + int i, offset; + int diff = hUniDrcConfig->diff; + + downmixInstructionsV1Present = FDKreadBits(hBs, 1); + if (downmixInstructionsV1Present == 1) { + diff |= _compAssign(&hUniDrcConfig->downmixInstructionsCountV1, + FDKreadBits(hBs, 7)); + offset = hUniDrcConfig->downmixInstructionsCountV0; + hUniDrcConfig->downmixInstructionsCount = fMin( + (UCHAR)(offset + hUniDrcConfig->downmixInstructionsCountV1), (UCHAR)6); + for (i = 0; i < hUniDrcConfig->downmixInstructionsCountV1; i++) { + DOWNMIX_INSTRUCTIONS tmpDown; + FDKmemclear(&tmpDown, sizeof(DOWNMIX_INSTRUCTIONS)); + err = _readDownmixInstructions(hBs, 1, &hUniDrcConfig->channelLayout, + &tmpDown); + if (err) return err; + if ((offset + i) >= 6) continue; + if (!diff) + diff |= (FDKmemcmp(&tmpDown, + &(hUniDrcConfig->downmixInstructions[offset + i]), + sizeof(DOWNMIX_INSTRUCTIONS)) != 0); + hUniDrcConfig->downmixInstructions[offset + i] = tmpDown; + } + } else { + diff |= _compAssign(&hUniDrcConfig->downmixInstructionsCountV1, 0); + } + + drcCoeffsAndInstructionsUniDrcV1Present = FDKreadBits(hBs, 1); + if (drcCoeffsAndInstructionsUniDrcV1Present == 1) { + diff |= _compAssign(&hUniDrcConfig->drcCoefficientsUniDrcCountV1, + FDKreadBits(hBs, 3)); + offset = hUniDrcConfig->drcCoefficientsUniDrcCountV0; + hUniDrcConfig->drcCoefficientsUniDrcCount = + fMin((UCHAR)(offset + hUniDrcConfig->drcCoefficientsUniDrcCountV1), + (UCHAR)2); + for (i = 0; i < hUniDrcConfig->drcCoefficientsUniDrcCountV1; i++) { + DRC_COEFFICIENTS_UNI_DRC tmpCoef; + FDKmemclear(&tmpCoef, sizeof(DRC_COEFFICIENTS_UNI_DRC)); + err = _readDrcCoefficientsUniDrc(hBs, 1, &tmpCoef); + if (err) return err; + if ((offset + i) >= 2) continue; + if (!diff) + diff |= (FDKmemcmp(&tmpCoef, + &(hUniDrcConfig->drcCoefficientsUniDrc[offset + i]), + sizeof(DRC_COEFFICIENTS_UNI_DRC)) != 0); + hUniDrcConfig->drcCoefficientsUniDrc[offset + i] = tmpCoef; + } + + diff |= _compAssign(&hUniDrcConfig->drcInstructionsUniDrcCountV1, + FDKreadBits(hBs, 6)); + offset = hUniDrcConfig->drcInstructionsUniDrcCount; + hUniDrcConfig->drcInstructionsUniDrcCount = + fMin((UCHAR)(offset + hUniDrcConfig->drcInstructionsUniDrcCountV1), + (UCHAR)12); + for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) { + DRC_INSTRUCTIONS_UNI_DRC tmpInst; + FDKmemclear(&tmpInst, sizeof(DRC_INSTRUCTIONS_UNI_DRC)); + err = _readDrcInstructionsUniDrc(hBs, 1, hUniDrcConfig, &tmpInst); + if (err) return err; + if ((offset + i) >= 12) continue; + if (!diff) + diff |= (FDKmemcmp(&tmpInst, + &(hUniDrcConfig->drcInstructionsUniDrc[offset + i]), + sizeof(DRC_INSTRUCTIONS_UNI_DRC)) != 0); + hUniDrcConfig->drcInstructionsUniDrc[offset + i] = tmpInst; + } + } else { + diff |= _compAssign(&hUniDrcConfig->drcCoefficientsUniDrcCountV1, 0); + diff |= _compAssign(&hUniDrcConfig->drcInstructionsUniDrcCountV1, 0); + } + + loudEqInstructionsPresent = FDKreadBits(hBs, 1); + if (loudEqInstructionsPresent == 1) { + loudEqInstructionsCount = FDKreadBits(hBs, 4); + for (i = 0; i < loudEqInstructionsCount; i++) { + _skipLoudEqInstructions(hBs); + } + } + + eqPresent = FDKreadBits(hBs, 1); + if (eqPresent == 1) { + _skipEqCoefficients(hBs); + eqInstructionsCount = FDKreadBits(hBs, 4); + for (i = 0; i < eqInstructionsCount; i++) { + _skipEqInstructions(hBs, hUniDrcConfig); + } + } + + hUniDrcConfig->diff = diff; + + return err; +} + +static DRC_ERROR _readUniDrcConfigExtension( + HANDLE_FDK_BITSTREAM hBs, HANDLE_UNI_DRC_CONFIG hUniDrcConfig) { + DRC_ERROR err = DE_OK; + int k, bitSizeLen, extSizeBits, bitSize; + UINT nBitsRemaining; + UNI_DRC_CONFIG_EXTENSION* pExt = &(hUniDrcConfig->uniDrcConfigExt); + + k = 0; + pExt->uniDrcConfigExtType[k] = FDKreadBits(hBs, 4); + while (pExt->uniDrcConfigExtType[k] != UNIDRCCONFEXT_TERM) { + if (k >= (8 - 1)) return DE_MEMORY_ERROR; + bitSizeLen = FDKreadBits(hBs, 4); + extSizeBits = bitSizeLen + 4; + + bitSize = FDKreadBits(hBs, extSizeBits); + pExt->extBitSize[k] = bitSize + 1; + nBitsRemaining = FDKgetValidBits(hBs); + + switch (pExt->uniDrcConfigExtType[k]) { + case UNIDRCCONFEXT_V1: + err = _readDrcExtensionV1(hBs, hUniDrcConfig); + if (err) return err; + if (nBitsRemaining != (pExt->extBitSize[k] + FDKgetValidBits(hBs))) + return DE_NOT_OK; + break; + case UNIDRCCONFEXT_PARAM_DRC: + /* add future extensions here */ + default: + FDKpushFor(hBs, pExt->extBitSize[k]); + break; + } + k++; + pExt->uniDrcConfigExtType[k] = FDKreadBits(hBs, 4); + } + + return err; +} + +DRC_ERROR +drcDec_readUniDrcConfig(HANDLE_FDK_BITSTREAM hBs, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig) { + DRC_ERROR err = DE_OK; + int i, diff = 0; + int drcDescriptionBasicPresent, drcCoefficientsBasicCount, + drcInstructionsBasicCount; + CHANNEL_LAYOUT tmpChan; + FDKmemclear(&tmpChan, sizeof(CHANNEL_LAYOUT)); + if (hUniDrcConfig == NULL) return DE_NOT_OK; + + diff |= _compAssign(&hUniDrcConfig->sampleRatePresent, FDKreadBits(hBs, 1)); + + if (hUniDrcConfig->sampleRatePresent == 1) { + diff |= + _compAssign(&hUniDrcConfig->sampleRate, FDKreadBits(hBs, 18) + 1000); + } + + diff |= _compAssign(&hUniDrcConfig->downmixInstructionsCountV0, + FDKreadBits(hBs, 7)); + + drcDescriptionBasicPresent = FDKreadBits(hBs, 1); + if (drcDescriptionBasicPresent == 1) { + drcCoefficientsBasicCount = FDKreadBits(hBs, 3); + drcInstructionsBasicCount = FDKreadBits(hBs, 4); + } else { + drcCoefficientsBasicCount = 0; + drcInstructionsBasicCount = 0; + } + + diff |= _compAssign(&hUniDrcConfig->drcCoefficientsUniDrcCountV0, + FDKreadBits(hBs, 3)); + diff |= _compAssign(&hUniDrcConfig->drcInstructionsUniDrcCountV0, + FDKreadBits(hBs, 6)); + + err = _readChannelLayout(hBs, &tmpChan); + if (err) return err; + + if (!diff) + diff |= (FDKmemcmp(&tmpChan, &hUniDrcConfig->channelLayout, + sizeof(CHANNEL_LAYOUT)) != 0); + hUniDrcConfig->channelLayout = tmpChan; + + hUniDrcConfig->downmixInstructionsCount = + fMin(hUniDrcConfig->downmixInstructionsCountV0, (UCHAR)6); + for (i = 0; i < hUniDrcConfig->downmixInstructionsCountV0; i++) { + DOWNMIX_INSTRUCTIONS tmpDown; + FDKmemclear(&tmpDown, sizeof(DOWNMIX_INSTRUCTIONS)); + err = _readDownmixInstructions(hBs, 0, &hUniDrcConfig->channelLayout, + &tmpDown); + if (err) return err; + if (i >= 6) continue; + if (!diff) + diff |= (FDKmemcmp(&tmpDown, &(hUniDrcConfig->downmixInstructions[i]), + sizeof(DOWNMIX_INSTRUCTIONS)) != 0); + hUniDrcConfig->downmixInstructions[i] = tmpDown; + } + + for (i = 0; i < drcCoefficientsBasicCount; i++) { + _skipDrcCoefficientsBasic(hBs); + } + for (i = 0; i < drcInstructionsBasicCount; i++) { + _skipDrcInstructionsBasic(hBs); + } + + hUniDrcConfig->drcCoefficientsUniDrcCount = + fMin(hUniDrcConfig->drcCoefficientsUniDrcCountV0, (UCHAR)2); + for (i = 0; i < hUniDrcConfig->drcCoefficientsUniDrcCountV0; i++) { + DRC_COEFFICIENTS_UNI_DRC tmpCoef; + FDKmemclear(&tmpCoef, sizeof(DRC_COEFFICIENTS_UNI_DRC)); + err = _readDrcCoefficientsUniDrc(hBs, 0, &tmpCoef); + if (err) return err; + if (i >= 2) continue; + if (!diff) + diff |= (FDKmemcmp(&tmpCoef, &(hUniDrcConfig->drcCoefficientsUniDrc[i]), + sizeof(DRC_COEFFICIENTS_UNI_DRC)) != 0); + hUniDrcConfig->drcCoefficientsUniDrc[i] = tmpCoef; + } + + hUniDrcConfig->drcInstructionsUniDrcCount = + fMin(hUniDrcConfig->drcInstructionsUniDrcCountV0, (UCHAR)12); + for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCountV0; i++) { + DRC_INSTRUCTIONS_UNI_DRC tmpInst; + FDKmemclear(&tmpInst, sizeof(DRC_INSTRUCTIONS_UNI_DRC)); + err = _readDrcInstructionsUniDrc(hBs, 0, hUniDrcConfig, &tmpInst); + if (err) return err; + if (i >= 12) continue; + if (!diff) + diff |= (FDKmemcmp(&tmpInst, &(hUniDrcConfig->drcInstructionsUniDrc[i]), + sizeof(DRC_INSTRUCTIONS_UNI_DRC)) != 0); + hUniDrcConfig->drcInstructionsUniDrc[i] = tmpInst; + } + + diff |= + _compAssign(&hUniDrcConfig->uniDrcConfigExtPresent, FDKreadBits(hBs, 1)); + hUniDrcConfig->diff = diff; + + if (hUniDrcConfig->uniDrcConfigExtPresent == 1) { + err = _readUniDrcConfigExtension(hBs, hUniDrcConfig); + if (err) return err; + } + + return err; +} + +/*******************/ +/* loudnessInfoSet */ +/*******************/ + +static DRC_ERROR _decodeMethodValue(HANDLE_FDK_BITSTREAM hBs, + const UCHAR methodDefinition, + FIXP_DBL* methodValue, INT isBox) { + int tmp; + FIXP_DBL val; + switch (methodDefinition) { + case MD_UNKNOWN_OTHER: + case MD_PROGRAM_LOUDNESS: + case MD_ANCHOR_LOUDNESS: + case MD_MAX_OF_LOUDNESS_RANGE: + case MD_MOMENTARY_LOUDNESS_MAX: + case MD_SHORT_TERM_LOUDNESS_MAX: + tmp = FDKreadBits(hBs, 8); + val = FL2FXCONST_DBL(-57.75f / (float)(1 << 7)) + + (FIXP_DBL)( + tmp << (DFRACT_BITS - 1 - 2 - 7)); /* -57.75 + tmp * 0.25; */ + break; + case MD_LOUDNESS_RANGE: + tmp = FDKreadBits(hBs, 8); + if (tmp == 0) + val = (FIXP_DBL)0; + else if (tmp <= 128) + val = (FIXP_DBL)(tmp << (DFRACT_BITS - 1 - 2 - 7)); /* tmp * 0.25; */ + else if (tmp <= 204) { + val = (FIXP_DBL)(tmp << (DFRACT_BITS - 1 - 1 - 7)) - + FL2FXCONST_DBL(32.0f / (float)(1 << 7)); /* 0.5 * tmp - 32.0f; */ + } else { + /* downscale by 1 more bit to prevent overflow at intermediate result */ + val = (FIXP_DBL)(tmp << (DFRACT_BITS - 1 - 8)) - + FL2FXCONST_DBL(134.0f / (float)(1 << 8)); /* tmp - 134.0; */ + val <<= 1; + } + break; + case MD_MIXING_LEVEL: + tmp = FDKreadBits(hBs, isBox ? 8 : 5); + val = (FIXP_DBL)(tmp << (DFRACT_BITS - 1 - 7)) + + FL2FXCONST_DBL(80.0f / (float)(1 << 7)); /* tmp + 80.0; */ + break; + case MD_ROOM_TYPE: + tmp = FDKreadBits(hBs, isBox ? 8 : 2); + val = (FIXP_DBL)(tmp << (DFRACT_BITS - 1 - 7)); /* tmp; */ + break; + case MD_SHORT_TERM_LOUDNESS: + tmp = FDKreadBits(hBs, 8); + val = FL2FXCONST_DBL(-116.0f / (float)(1 << 7)) + + (FIXP_DBL)( + tmp << (DFRACT_BITS - 1 - 1 - 7)); /* -116.0 + tmp * 0.5; */ + break; + default: + return DE_NOT_OK; /* invalid methodDefinition value */ + } + *methodValue = val; + return DE_OK; +} + +static DRC_ERROR _readLoudnessMeasurement(HANDLE_FDK_BITSTREAM hBs, + LOUDNESS_MEASUREMENT* pMeas) { + DRC_ERROR err = DE_OK; + + pMeas->methodDefinition = FDKreadBits(hBs, 4); + err = + _decodeMethodValue(hBs, pMeas->methodDefinition, &pMeas->methodValue, 0); + if (err) return err; + pMeas->measurementSystem = FDKreadBits(hBs, 4); + pMeas->reliability = FDKreadBits(hBs, 2); + + return err; +} + +static DRC_ERROR _readLoudnessInfo(HANDLE_FDK_BITSTREAM hBs, const int version, + LOUDNESS_INFO* loudnessInfo) { + DRC_ERROR err = DE_OK; + int bsSamplePeakLevel, bsTruePeakLevel, i; + int measurementCount; + + loudnessInfo->drcSetId = FDKreadBits(hBs, 6); + if (version >= 1) { + loudnessInfo->eqSetId = FDKreadBits(hBs, 6); + } else { + loudnessInfo->eqSetId = 0; + } + loudnessInfo->downmixId = FDKreadBits(hBs, 7); + + loudnessInfo->samplePeakLevelPresent = FDKreadBits(hBs, 1); + if (loudnessInfo->samplePeakLevelPresent) { + bsSamplePeakLevel = FDKreadBits(hBs, 12); + if (bsSamplePeakLevel == 0) { + loudnessInfo->samplePeakLevelPresent = 0; + loudnessInfo->samplePeakLevel = (FIXP_DBL)0; + } else { /* 20.0 - bsSamplePeakLevel * 0.03125; */ + loudnessInfo->samplePeakLevel = + FL2FXCONST_DBL(20.0f / (float)(1 << 7)) - + (FIXP_DBL)(bsSamplePeakLevel << (DFRACT_BITS - 1 - 5 - 7)); + } + } + + loudnessInfo->truePeakLevelPresent = FDKreadBits(hBs, 1); + if (loudnessInfo->truePeakLevelPresent) { + bsTruePeakLevel = FDKreadBits(hBs, 12); + if (bsTruePeakLevel == 0) { + loudnessInfo->truePeakLevelPresent = 0; + loudnessInfo->truePeakLevel = (FIXP_DBL)0; + } else { + loudnessInfo->truePeakLevel = + FL2FXCONST_DBL(20.0f / (float)(1 << 7)) - + (FIXP_DBL)(bsTruePeakLevel << (DFRACT_BITS - 1 - 5 - 7)); + } + loudnessInfo->truePeakLevelMeasurementSystem = FDKreadBits(hBs, 4); + loudnessInfo->truePeakLevelReliability = FDKreadBits(hBs, 2); + } + + measurementCount = FDKreadBits(hBs, 4); + loudnessInfo->measurementCount = fMin(measurementCount, 8); + for (i = 0; i < measurementCount; i++) { + LOUDNESS_MEASUREMENT tmpMeas; + FDKmemclear(&tmpMeas, sizeof(LOUDNESS_MEASUREMENT)); + err = _readLoudnessMeasurement(hBs, &tmpMeas); + if (err) return err; + if (i >= 8) continue; + loudnessInfo->loudnessMeasurement[i] = tmpMeas; + } + + return err; +} + +static DRC_ERROR _readLoudnessInfoSetExtEq( + HANDLE_FDK_BITSTREAM hBs, HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet) { + DRC_ERROR err = DE_OK; + int i, offset; + int diff = hLoudnessInfoSet->diff; + + diff |= _compAssign(&hLoudnessInfoSet->loudnessInfoAlbumCountV1, + FDKreadBits(hBs, 6)); + diff |= + _compAssign(&hLoudnessInfoSet->loudnessInfoCountV1, FDKreadBits(hBs, 6)); + + offset = hLoudnessInfoSet->loudnessInfoAlbumCountV0; + hLoudnessInfoSet->loudnessInfoAlbumCount = fMin( + (UCHAR)(offset + hLoudnessInfoSet->loudnessInfoAlbumCountV1), (UCHAR)12); + for (i = 0; i < hLoudnessInfoSet->loudnessInfoAlbumCountV1; i++) { + LOUDNESS_INFO tmpLoud; + FDKmemclear(&tmpLoud, sizeof(LOUDNESS_INFO)); + err = _readLoudnessInfo(hBs, 1, &tmpLoud); + if (err) return err; + if ((offset + i) >= 12) continue; + if (!diff) + diff |= (FDKmemcmp(&tmpLoud, + &(hLoudnessInfoSet->loudnessInfoAlbum[offset + i]), + sizeof(LOUDNESS_INFO)) != 0); + hLoudnessInfoSet->loudnessInfoAlbum[offset + i] = tmpLoud; + } + + offset = hLoudnessInfoSet->loudnessInfoCountV0; + hLoudnessInfoSet->loudnessInfoCount = + fMin((UCHAR)(offset + hLoudnessInfoSet->loudnessInfoCountV1), (UCHAR)12); + for (i = 0; i < hLoudnessInfoSet->loudnessInfoCountV1; i++) { + LOUDNESS_INFO tmpLoud; + FDKmemclear(&tmpLoud, sizeof(LOUDNESS_INFO)); + err = _readLoudnessInfo(hBs, 1, &tmpLoud); + if (err) return err; + if ((offset + i) >= 12) continue; + if (!diff) + diff |= + (FDKmemcmp(&tmpLoud, &(hLoudnessInfoSet->loudnessInfo[offset + i]), + sizeof(LOUDNESS_INFO)) != 0); + hLoudnessInfoSet->loudnessInfo[offset + i] = tmpLoud; + } + hLoudnessInfoSet->diff = diff; + return err; +} + +static DRC_ERROR _readLoudnessInfoSetExtension( + HANDLE_FDK_BITSTREAM hBs, HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet) { + DRC_ERROR err = DE_OK; + int k, bitSizeLen, extSizeBits, bitSize; + UINT nBitsRemaining; + LOUDNESS_INFO_SET_EXTENSION* pExt = &(hLoudnessInfoSet->loudnessInfoSetExt); + + k = 0; + pExt->loudnessInfoSetExtType[k] = FDKreadBits(hBs, 4); + while (pExt->loudnessInfoSetExtType[k] != UNIDRCLOUDEXT_TERM) { + if (k >= (8 - 1)) return DE_MEMORY_ERROR; + bitSizeLen = FDKreadBits(hBs, 4); + extSizeBits = bitSizeLen + 4; + + bitSize = FDKreadBits(hBs, extSizeBits); + pExt->extBitSize[k] = bitSize + 1; + nBitsRemaining = FDKgetValidBits(hBs); + + switch (pExt->loudnessInfoSetExtType[k]) { + case UNIDRCLOUDEXT_EQ: + err = _readLoudnessInfoSetExtEq(hBs, hLoudnessInfoSet); + if (err) return err; + if (nBitsRemaining != (pExt->extBitSize[k] + FDKgetValidBits(hBs))) + return DE_NOT_OK; + break; + /* add future extensions here */ + default: + FDKpushFor(hBs, pExt->extBitSize[k]); + break; + } + k++; + pExt->loudnessInfoSetExtType[k] = FDKreadBits(hBs, 4); + } + + return err; +} + +/* Parser for loundessInfoSet() */ +DRC_ERROR +drcDec_readLoudnessInfoSet(HANDLE_FDK_BITSTREAM hBs, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet) { + DRC_ERROR err = DE_OK; + int i, diff = 0; + if (hLoudnessInfoSet == NULL) return DE_NOT_OK; + + diff |= _compAssign(&hLoudnessInfoSet->loudnessInfoAlbumCountV0, + FDKreadBits(hBs, 6)); + diff |= + _compAssign(&hLoudnessInfoSet->loudnessInfoCountV0, FDKreadBits(hBs, 6)); + + hLoudnessInfoSet->loudnessInfoAlbumCount = + fMin(hLoudnessInfoSet->loudnessInfoAlbumCountV0, (UCHAR)12); + for (i = 0; i < hLoudnessInfoSet->loudnessInfoAlbumCountV0; i++) { + LOUDNESS_INFO tmpLoud; + FDKmemclear(&tmpLoud, sizeof(LOUDNESS_INFO)); + err = _readLoudnessInfo(hBs, 0, &tmpLoud); + if (err) return err; + if (i >= 12) continue; + if (!diff) + diff |= (FDKmemcmp(&tmpLoud, &(hLoudnessInfoSet->loudnessInfoAlbum[i]), + sizeof(LOUDNESS_INFO)) != 0); + hLoudnessInfoSet->loudnessInfoAlbum[i] = tmpLoud; + } + + hLoudnessInfoSet->loudnessInfoCount = + fMin(hLoudnessInfoSet->loudnessInfoCountV0, (UCHAR)12); + for (i = 0; i < hLoudnessInfoSet->loudnessInfoCountV0; i++) { + LOUDNESS_INFO tmpLoud; + FDKmemclear(&tmpLoud, sizeof(LOUDNESS_INFO)); + err = _readLoudnessInfo(hBs, 0, &tmpLoud); + if (err) return err; + if (i >= 12) continue; + if (!diff) + diff |= (FDKmemcmp(&tmpLoud, &(hLoudnessInfoSet->loudnessInfo[i]), + sizeof(LOUDNESS_INFO)) != 0); + hLoudnessInfoSet->loudnessInfo[i] = tmpLoud; + } + + diff |= _compAssign(&hLoudnessInfoSet->loudnessInfoSetExtPresent, + FDKreadBits(hBs, 1)); + hLoudnessInfoSet->diff = diff; + + if (hLoudnessInfoSet->loudnessInfoSetExtPresent) { + err = _readLoudnessInfoSetExtension(hBs, hLoudnessInfoSet); + if (err) return err; + } + + return err; +} diff --git a/libDRCdec/src/drcDec_reader.h b/libDRCdec/src/drcDec_reader.h new file mode 100644 index 0000000..1ab9b58 --- /dev/null +++ b/libDRCdec/src/drcDec_reader.h @@ -0,0 +1,130 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#ifndef DRCDEC_READER_H +#define DRCDEC_READER_H + +#include "drcDecoder.h" +#include "drcDec_types.h" +#include "FDK_bitstream.h" + +DRC_ERROR +drcDec_readUniDrc(HANDLE_FDK_BITSTREAM hBs, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + const int frameSize, const int deltaTminDefault, + HANDLE_UNI_DRC_GAIN hUniDrcGain); + +DRC_ERROR +drcDec_readUniDrcGain(HANDLE_FDK_BITSTREAM hBs, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, const int frameSize, + const int deltaTminDefault, + HANDLE_UNI_DRC_GAIN hUniDrcGain); + +DRC_ERROR +drcDec_readUniDrcConfig(HANDLE_FDK_BITSTREAM hBs, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig); + +DRC_ERROR +drcDec_readLoudnessInfoSet(HANDLE_FDK_BITSTREAM hBs, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet); + +#endif diff --git a/libDRCdec/src/drcDec_rom.cpp b/libDRCdec/src/drcDec_rom.cpp new file mode 100644 index 0000000..9f89689 --- /dev/null +++ b/libDRCdec/src/drcDec_rom.cpp @@ -0,0 +1,323 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "drcDec_types.h" +#include "drcDec_rom.h" + +const SCHAR deltaGain_codingProfile_0_1_huffman[24][2] = { + {1, 2}, {3, 4}, {-63, -65}, {5, -66}, {-64, 6}, {-80, 7}, + {8, 9}, {-68, 10}, {11, 12}, {-56, -67}, {-61, 13}, {-62, -69}, + {14, 15}, {16, -72}, {-71, 17}, {-70, -60}, {18, -59}, {19, 20}, + {21, -79}, {-57, -73}, {22, -58}, {-76, 23}, {-75, -74}, {-78, -77}}; + +const SCHAR deltaGain_codingProfile_2_huffman[48][2] = { + {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10}, {11, 12}, + {13, -65}, {14, -64}, {15, -66}, {16, -67}, {17, 18}, {19, -68}, + {20, -63}, {-69, 21}, {-59, 22}, {-61, -62}, {-60, 23}, {24, -58}, + {-70, -57}, {-56, -71}, {25, 26}, {27, -55}, {-72, 28}, {-54, 29}, + {-53, 30}, {-73, -52}, {31, -74}, {32, 33}, {-75, 34}, {-76, 35}, + {-51, 36}, {-78, 37}, {-77, 38}, {-96, 39}, {-48, 40}, {-50, -79}, + {41, 42}, {-80, -81}, {-82, 43}, {44, -49}, {45, -84}, {-83, -89}, + {-86, 46}, {-90, -85}, {-91, -93}, {-92, 47}, {-88, -87}, {-95, -94}}; + +const FIXP_SGL slopeSteepness[] = {FL2FXCONST_SGL(-3.0518f / (float)(1 << 2)), + FL2FXCONST_SGL(-1.2207f / (float)(1 << 2)), + FL2FXCONST_SGL(-0.4883f / (float)(1 << 2)), + FL2FXCONST_SGL(-0.1953f / (float)(1 << 2)), + FL2FXCONST_SGL(-0.0781f / (float)(1 << 2)), + FL2FXCONST_SGL(-0.0312f / (float)(1 << 2)), + FL2FXCONST_SGL(-0.005f / (float)(1 << 2)), + FL2FXCONST_SGL(0.0f / (float)(1 << 2)), + FL2FXCONST_SGL(0.005f / (float)(1 << 2)), + FL2FXCONST_SGL(0.0312f / (float)(1 << 2)), + FL2FXCONST_SGL(0.0781f / (float)(1 << 2)), + FL2FXCONST_SGL(0.1953f / (float)(1 << 2)), + FL2FXCONST_SGL(0.4883f / (float)(1 << 2)), + FL2FXCONST_SGL(1.2207f / (float)(1 << 2)), + FL2FXCONST_SGL(3.0518f / (float)(1 << 2))}; + +const SCHAR slopeSteepness_huffman[14][2] = { + {1, -57}, {-58, 2}, {3, 4}, {5, 6}, {7, -56}, + {8, -60}, {-61, -55}, {9, -59}, {10, -54}, {-64, 11}, + {-51, 12}, {-62, -50}, {-63, 13}, {-52, -53}}; + +const FIXP_DBL downmixCoeff[] = { + FL2FXCONST_DBL(1.0000000000 / (float)(1 << 2)), + FL2FXCONST_DBL(0.9440608763 / (float)(1 << 2)), + FL2FXCONST_DBL(0.8912509381 / (float)(1 << 2)), + FL2FXCONST_DBL(0.8413951416 / (float)(1 << 2)), + FL2FXCONST_DBL(0.7943282347 / (float)(1 << 2)), + FL2FXCONST_DBL(0.7498942093 / (float)(1 << 2)), + FL2FXCONST_DBL(0.7079457844 / (float)(1 << 2)), + FL2FXCONST_DBL(0.6683439176 / (float)(1 << 2)), + FL2FXCONST_DBL(0.6309573445 / (float)(1 << 2)), + FL2FXCONST_DBL(0.5956621435 / (float)(1 << 2)), + FL2FXCONST_DBL(0.5623413252 / (float)(1 << 2)), + FL2FXCONST_DBL(0.5308844442 / (float)(1 << 2)), + FL2FXCONST_DBL(0.5011872336 / (float)(1 << 2)), + FL2FXCONST_DBL(0.4216965034 / (float)(1 << 2)), + FL2FXCONST_DBL(0.3548133892 / (float)(1 << 2)), + FL2FXCONST_DBL(0.0000000000 / (float)(1 << 2))}; + +const FIXP_DBL downmixCoeffV1[] = { + FL2FXCONST_DBL(3.1622776602 / (float)(1 << 2)), + FL2FXCONST_DBL(1.9952623150 / (float)(1 << 2)), + FL2FXCONST_DBL(1.6788040181 / (float)(1 << 2)), + FL2FXCONST_DBL(1.4125375446 / (float)(1 << 2)), + FL2FXCONST_DBL(1.1885022274 / (float)(1 << 2)), + FL2FXCONST_DBL(1.0000000000 / (float)(1 << 2)), + FL2FXCONST_DBL(0.9440608763 / (float)(1 << 2)), + FL2FXCONST_DBL(0.8912509381 / (float)(1 << 2)), + FL2FXCONST_DBL(0.8413951416 / (float)(1 << 2)), + FL2FXCONST_DBL(0.7943282347 / (float)(1 << 2)), + FL2FXCONST_DBL(0.7498942093 / (float)(1 << 2)), + FL2FXCONST_DBL(0.7079457844 / (float)(1 << 2)), + FL2FXCONST_DBL(0.6683439176 / (float)(1 << 2)), + FL2FXCONST_DBL(0.6309573445 / (float)(1 << 2)), + FL2FXCONST_DBL(0.5956621435 / (float)(1 << 2)), + FL2FXCONST_DBL(0.5623413252 / (float)(1 << 2)), + FL2FXCONST_DBL(0.5308844442 / (float)(1 << 2)), + FL2FXCONST_DBL(0.5011872336 / (float)(1 << 2)), + FL2FXCONST_DBL(0.4731512590 / (float)(1 << 2)), + FL2FXCONST_DBL(0.4466835922 / (float)(1 << 2)), + FL2FXCONST_DBL(0.4216965034 / (float)(1 << 2)), + FL2FXCONST_DBL(0.3981071706 / (float)(1 << 2)), + FL2FXCONST_DBL(0.3548133892 / (float)(1 << 2)), + FL2FXCONST_DBL(0.3162277660 / (float)(1 << 2)), + FL2FXCONST_DBL(0.2818382931 / (float)(1 << 2)), + FL2FXCONST_DBL(0.2511886432 / (float)(1 << 2)), + FL2FXCONST_DBL(0.1778279410 / (float)(1 << 2)), + FL2FXCONST_DBL(0.1000000000 / (float)(1 << 2)), + FL2FXCONST_DBL(0.0562341325 / (float)(1 << 2)), + FL2FXCONST_DBL(0.0316227766 / (float)(1 << 2)), + FL2FXCONST_DBL(0.0100000000 / (float)(1 << 2)), + FL2FXCONST_DBL(0.0000000000 / (float)(1 << 2))}; + +const CUSTOM_DRC_CHAR_SIGMOID cicpDrcCharSigmoidLeft[] = { + {FL2FXCONST_SGL(32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(0.0f / (float)(1 << 2)), + FL2FXCONST_SGL(9.0f / (float)(1 << 5)), 0}, /* 1 */ + {FL2FXCONST_SGL(32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(0.2f / (float)(1 << 2)), + FL2FXCONST_SGL(9.0f / (float)(1 << 5)), 0}, /* 2 */ + {FL2FXCONST_SGL(32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(0.4f / (float)(1 << 2)), + FL2FXCONST_SGL(9.0f / (float)(1 << 5)), 0}, /* 3 */ + {FL2FXCONST_SGL(32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(0.6f / (float)(1 << 2)), + FL2FXCONST_SGL(9.0f / (float)(1 << 5)), 0}, /* 4 */ + {FL2FXCONST_SGL(32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(0.8f / (float)(1 << 2)), + FL2FXCONST_SGL(6.0f / (float)(1 << 5)), 0}, /* 5 */ + {FL2FXCONST_SGL(32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(1.0f / (float)(1 << 2)), + FL2FXCONST_SGL(5.0f / (float)(1 << 5)), 0}, /* 6 */ +}; + +const CUSTOM_DRC_CHAR_SIGMOID cicpDrcCharSigmoidRight[] = { + {FL2FXCONST_SGL(-32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(0.0f / (float)(1 << 2)), + FL2FXCONST_SGL(12.0f / (float)(1 << 5)), 0}, /* 1 */ + {FL2FXCONST_SGL(-32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(0.2f / (float)(1 << 2)), + FL2FXCONST_SGL(12.0f / (float)(1 << 5)), 0}, /* 2 */ + {FL2FXCONST_SGL(-32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(0.4f / (float)(1 << 2)), + FL2FXCONST_SGL(12.0f / (float)(1 << 5)), 0}, /* 3 */ + {FL2FXCONST_SGL(-32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(0.6f / (float)(1 << 2)), + FL2FXCONST_SGL(10.0f / (float)(1 << 5)), 0}, /* 4 */ + {FL2FXCONST_SGL(-32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(0.8f / (float)(1 << 2)), + FL2FXCONST_SGL(8.0f / (float)(1 << 5)), 0}, /* 5 */ + {FL2FXCONST_SGL(-32.0f / (float)(1 << 6)), + FL2FXCONST_SGL(1.0f / (float)(1 << 2)), + FL2FXCONST_SGL(6.0f / (float)(1 << 5)), 0}, /* 6 */ +}; + +const CUSTOM_DRC_CHAR_NODES cicpDrcCharNodesLeft[] = { + {2, + {FL2FXCONST_SGL(-31.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-41.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-53.0f / (float)(1 << 7))}, + {FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(6.0f / (float)(1 << 7))}}, /* 7 */ + {1, + {FL2FXCONST_SGL(-31.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-43.0f / (float)(1 << 7))}, + {FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(6.0f / (float)(1 << 7))}}, /* 8 */ + {2, + {FL2FXCONST_SGL(-31.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-41.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-65.0f / (float)(1 << 7))}, + {FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(12.0f / (float)(1 << 7))}}, /* 9 */ + {1, + {FL2FXCONST_SGL(-31.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-55.0f / (float)(1 << 7))}, + {FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(12.0f / (float)(1 << 7))}}, /* 10 */ + {1, + {FL2FXCONST_SGL(-31.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-50.0f / (float)(1 << 7))}, + {FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(15.0f / (float)(1 << 7))}} /* 11 */ +}; + +const CUSTOM_DRC_CHAR_NODES cicpDrcCharNodesRight[] = { + {4, + {FL2FXCONST_SGL(-31.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-21.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-11.0f / (float)(1 << 7)), + FL2FXCONST_SGL(9.0f / (float)(1 << 7)), + FL2FXCONST_SGL(19.0f / (float)(1 << 7))}, + {FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-5.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-24.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-34.0f / (float)(1 << 7))}}, /* 7 */ + {4, + {FL2FXCONST_SGL(-31.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-26.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-16.0f / (float)(1 << 7)), + FL2FXCONST_SGL(4.0f / (float)(1 << 7)), + FL2FXCONST_SGL(14.0f / (float)(1 << 7))}, + {FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-5.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-24.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-34.0f / (float)(1 << 7))}}, /* 8 */ + {3, + {FL2FXCONST_SGL(-31.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-21.0f / (float)(1 << 7)), + FL2FXCONST_SGL(9.0f / (float)(1 << 7)), + FL2FXCONST_SGL(29.0f / (float)(1 << 7))}, + {FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-15.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-35.0f / (float)(1 << 7))}}, /* 9 */ + {4, + {FL2FXCONST_SGL(-31.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-26.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-16.0f / (float)(1 << 7)), + FL2FXCONST_SGL(4.0f / (float)(1 << 7)), + FL2FXCONST_SGL(14.0f / (float)(1 << 7))}, + {FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-5.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-24.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-34.0f / (float)(1 << 7))}}, /* 10 */ + {4, + {FL2FXCONST_SGL(-31.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-26.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-16.0f / (float)(1 << 7)), + FL2FXCONST_SGL(4.0f / (float)(1 << 7)), + FL2FXCONST_SGL(14.0f / (float)(1 << 7))}, + {FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(0.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-5.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-24.0f / (float)(1 << 7)), + FL2FXCONST_SGL(-34.0f / (float)(1 << 7))}} /* 11 */ +}; diff --git a/libDRCdec/src/drcDec_rom.h b/libDRCdec/src/drcDec_rom.h new file mode 100644 index 0000000..daee882 --- /dev/null +++ b/libDRCdec/src/drcDec_rom.h @@ -0,0 +1,120 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#ifndef DRCDEC_ROM_H +#define DRCDEC_ROM_H + +extern const SCHAR deltaGain_codingProfile_0_1_huffman[24][2]; +extern const SCHAR deltaGain_codingProfile_2_huffman[48][2]; + +extern const FIXP_SGL slopeSteepness[]; +extern const SCHAR slopeSteepness_huffman[14][2]; + +extern const FIXP_DBL downmixCoeff[]; +extern const FIXP_DBL downmixCoeffV1[]; + +extern const CUSTOM_DRC_CHAR_SIGMOID cicpDrcCharSigmoidLeft[]; +extern const CUSTOM_DRC_CHAR_SIGMOID cicpDrcCharSigmoidRight[]; +extern const CUSTOM_DRC_CHAR_NODES cicpDrcCharNodesLeft[]; +extern const CUSTOM_DRC_CHAR_NODES cicpDrcCharNodesRight[]; + +#endif diff --git a/libDRCdec/src/drcDec_selectionProcess.cpp b/libDRCdec/src/drcDec_selectionProcess.cpp new file mode 100644 index 0000000..54b731d --- /dev/null +++ b/libDRCdec/src/drcDec_selectionProcess.cpp @@ -0,0 +1,3083 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): Andreas Hoelzer + + Description: DRC Set Selection + +*******************************************************************************/ + +#include "drcDec_selectionProcess.h" +#include "drcDec_tools.h" + +#define UNDEFINED_LOUDNESS_VALUE (FIXP_DBL) MAXVAL_DBL + +typedef enum { + DETR_NONE = 0, + DETR_NIGHT = 1, + DETR_NOISY = 2, + DETR_LIMITED = 3, + DETR_LOWLEVEL = 4, + DETR_DIALOG = 5, + DETR_GENERAL_COMPR = 6, + DETR_EXPAND = 7, + DETR_ARTISTIC = 8, + DETR_COUNT +} DRC_EFFECT_TYPE_REQUEST; + +typedef enum { + DFRT_EFFECT_TYPE, + DFRT_DYNAMIC_RANGE, + DFRT_DRC_CHARACTERISTIC +} DRC_FEATURE_REQUEST_TYPE; + +typedef enum { + MDR_DEFAULT = 0, + MDR_PROGRAM_LOUDNESS = 1, + MDR_ANCHOR_LOUDNESS = 2 +} METHOD_DEFINITION_REQUEST; + +typedef enum { + MSR_DEFAULT = 0, + MSR_BS_1770_4 = 1, + MSR_USER = 2, + MSR_EXPERT_PANEL = 3, + MSR_RESERVED_A = 4, + MSR_RESERVED_B = 5, + MSR_RESERVED_C = 6, + MSR_RESERVED_D = 7, + MSR_RESERVED_E = 8 +} MEASUREMENT_SYSTEM_REQUEST; + +typedef enum { + LPR_DEFAULT = 0, + LPR_OFF = 1, + LPR_HIGHPASS = 2 +} LOUDNESS_PREPROCESSING_REQUEST; + +typedef enum { + DRMRT_SHORT_TERM_LOUDNESS_TO_AVG = 0, + DRMRT_MOMENTARY_LOUDNESS_TO_AVG = 1, + DRMRT_TOP_OF_LOUDNESS_RANGE_TO_AVG = 2 +} DYN_RANGE_MEASUREMENT_REQUEST_TYPE; + +typedef enum { + TCRT_DOWNMIX_ID = 0, + TCRT_TARGET_LAYOUT = 1, + TCRT_TARGET_CHANNEL_COUNT = 2 +} TARGET_CONFIG_REQUEST_TYPE; + +typedef shouldBeUnion { + struct { + UCHAR numRequests; + UCHAR numRequestsDesired; + DRC_EFFECT_TYPE_REQUEST request[MAX_REQUESTS_DRC_EFFECT_TYPE]; + } drcEffectType; + struct { + DYN_RANGE_MEASUREMENT_REQUEST_TYPE measurementRequestType; + UCHAR requestedIsRange; + FIXP_DBL requestValue; /* e = 7 */ + FIXP_DBL requestValueMin; /* e = 7 */ + FIXP_DBL requestValueMax; /* e = 7 */ + } dynamicRange; + UCHAR drcCharacteristic; +} +DRC_FEATURE_REQUEST; + +typedef struct { + /* system parameters */ + SCHAR baseChannelCount; + SCHAR baseLayout; /* not supported */ + TARGET_CONFIG_REQUEST_TYPE targetConfigRequestType; + UCHAR numDownmixIdRequests; + UCHAR downmixIdRequested[MAX_REQUESTS_DOWNMIX_ID]; + UCHAR targetLayoutRequested; + UCHAR targetChannelCountRequested; + LONG audioSampleRate; /* needed for complexity estimation, currently not + supported */ + + /* loudness normalization parameters */ + UCHAR loudnessNormalizationOn; + FIXP_DBL targetLoudness; /* e = 7 */ + UCHAR albumMode; + UCHAR peakLimiterPresent; + UCHAR loudnessDeviationMax; /* resolution: 1 dB */ + METHOD_DEFINITION_REQUEST loudnessMeasurementMethod; + MEASUREMENT_SYSTEM_REQUEST loudnessMeasurementSystem; + LOUDNESS_PREPROCESSING_REQUEST loudnessMeasurementPreProc; /* not supported */ + LONG deviceCutOffFrequency; /* not supported */ + FIXP_DBL loudnessNormalizationGainDbMax; /* e = 7 */ + FIXP_DBL loudnessNormalizationGainModificationDb; /* e = 7 */ + FIXP_DBL outputPeakLevelMax; /* e = 7 */ + + /* dynamic range control parameters */ + UCHAR dynamicRangeControlOn; + UCHAR numDrcFeatureRequests; + DRC_FEATURE_REQUEST_TYPE drcFeatureRequestType[MAX_REQUESTS_DRC_FEATURE]; + DRC_FEATURE_REQUEST drcFeatureRequest[MAX_REQUESTS_DRC_FEATURE]; + + /* other */ + FIXP_SGL boost; /* e = 1 */ + FIXP_SGL compress; /* e = 1 */ + UCHAR drcCharacteristicTarget; /* not supported */ +} SEL_PROC_INPUT, *HANDLE_SEL_PROC_INPUT; + +/* Table E.1 of ISO/IEC DIS 23003-4: Recommended order of fallback effect type + * requests */ +static DRC_EFFECT_TYPE_REQUEST fallbackEffectTypeRequests[6][5] = { + /* Night */ {DETR_GENERAL_COMPR, DETR_NOISY, DETR_LIMITED, DETR_LOWLEVEL, + DETR_DIALOG}, + /* Noisy */ + {DETR_GENERAL_COMPR, DETR_NIGHT, DETR_LIMITED, DETR_LOWLEVEL, DETR_DIALOG}, + /* Limited */ + {DETR_GENERAL_COMPR, DETR_NIGHT, DETR_NOISY, DETR_LOWLEVEL, DETR_DIALOG}, + /* LowLevel */ + {DETR_GENERAL_COMPR, DETR_NOISY, DETR_NIGHT, DETR_LIMITED, DETR_DIALOG}, + /* Dialog */ + {DETR_GENERAL_COMPR, DETR_NIGHT, DETR_NOISY, DETR_LIMITED, DETR_LOWLEVEL}, + /* General */ + {DETR_NIGHT, DETR_NOISY, DETR_LIMITED, DETR_LOWLEVEL, DETR_DIALOG}}; + +/*******************************************/ +typedef struct { + UCHAR selectionFlag; + UCHAR downmixIdRequestIndex; + FIXP_DBL outputPeakLevel; /* e = 7 */ + FIXP_DBL loudnessNormalizationGainDbAdjusted; /* e = 7 */ + FIXP_DBL outputLoudness; /* e = 7 */ + DRC_INSTRUCTIONS_UNI_DRC* pInst; + +} DRCDEC_SELECTION_DATA; + +typedef struct { + UCHAR numData; + DRCDEC_SELECTION_DATA data[(12 + 1 + 6)]; + +} DRCDEC_SELECTION; + +/*******************************************/ +/* helper functions */ +/*******************************************/ + +static int _isError(int x) { + if (x < DRCDEC_SELECTION_PROCESS_WARNING) { + return 1; + } + + return 0; +} + +/* compare and assign */ +static inline int _compAssign(UCHAR* dest, const UCHAR src) { + int diff = 0; + if (*dest != src) diff = 1; + *dest = src; + return diff; +} + +static inline int _compAssign(SCHAR* dest, const SCHAR src) { + int diff = 0; + if (*dest != src) diff = 1; + *dest = src; + return diff; +} + +static inline int _compAssign(FIXP_DBL* dest, const FIXP_DBL src) { + int diff = 0; + if (*dest != src) diff = 1; + *dest = src; + return diff; +} + +static inline int _compAssign(FIXP_SGL* dest, const FIXP_SGL src) { + int diff = 0; + if (*dest != src) diff = 1; + *dest = src; + return diff; +} + +static inline int _compAssign(TARGET_CONFIG_REQUEST_TYPE* dest, const int src) { + int diff = 0; + if (*dest != src) diff = 1; + *dest = (TARGET_CONFIG_REQUEST_TYPE)src; + return diff; +} + +static inline int _compAssign(METHOD_DEFINITION_REQUEST* dest, const int src) { + int diff = 0; + if (*dest != src) diff = 1; + *dest = (METHOD_DEFINITION_REQUEST)src; + return diff; +} + +static inline int _compAssign(DRC_FEATURE_REQUEST_TYPE* dest, const int src) { + int diff = 0; + if (*dest != src) diff = 1; + *dest = (DRC_FEATURE_REQUEST_TYPE)src; + return diff; +} + +static inline int _compAssign(DRC_EFFECT_TYPE_REQUEST* dest, const int src) { + int diff = 0; + if (*dest != src) diff = 1; + *dest = (DRC_EFFECT_TYPE_REQUEST)src; + return diff; +} + +static DRCDEC_SELECTION_DATA* _drcdec_selection_addNew( + DRCDEC_SELECTION* pSelection); + +static DRCDEC_SELECTION_DATA* _drcdec_selection_add( + DRCDEC_SELECTION* pSelection, DRCDEC_SELECTION_DATA* pDataIn); + +static int _drcdec_selection_clear(DRCDEC_SELECTION* pSelection); + +static int _drcdec_selection_getNumber(DRCDEC_SELECTION* pSelection); + +static int _drcdec_selection_setNumber(DRCDEC_SELECTION* pSelection, int num); + +static DRCDEC_SELECTION_DATA* _drcdec_selection_getAt( + DRCDEC_SELECTION* pSelection, int at); + +static int _swapSelectionAndClear(DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected); + +static int _swapSelection(DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected); + +/*******************************************/ +/* declarations of static functions */ +/*******************************************/ + +static DRCDEC_SELECTION_PROCESS_RETURN _initDefaultParams( + HANDLE_SEL_PROC_INPUT hSelProcInput); + +static DRCDEC_SELECTION_PROCESS_RETURN _initCodecModeParams( + HANDLE_SEL_PROC_INPUT hSelProcInput, const SEL_PROC_CODEC_MODE codecMode); + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetPreSelection( + SEL_PROC_INPUT* hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected, SEL_PROC_CODEC_MODE codecMode); + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_peakValue0( + DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected); + +static DRCDEC_SELECTION_PROCESS_RETURN _dynamicRangeMeasurement( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, DRC_INSTRUCTIONS_UNI_DRC* pInst, + UCHAR downmixIdRequested, + DYN_RANGE_MEASUREMENT_REQUEST_TYPE dynamicRangeMeasurementType, + int albumMode, int* peakToAveragePresent, FIXP_DBL* peakToAverage); + +static DRCDEC_SELECTION_PROCESS_RETURN _channelLayoutToDownmixIdMapping( + HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig); + +static DRCDEC_SELECTION_PROCESS_RETURN _generateVirtualDrcSets( + HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + SEL_PROC_CODEC_MODE codecMode); + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetRequestSelection( + SEL_PROC_INPUT* hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected); + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection( + HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected, SEL_PROC_CODEC_MODE codecMode); + +static DRCDEC_SELECTION_PROCESS_RETURN _generateOutputInfo( + HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_SEL_PROC_OUTPUT hSelProcOutput, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + DRCDEC_SELECTION_DATA* pSelectionData, SEL_PROC_CODEC_MODE codecMode); + +static DRCDEC_SELECTION_PROCESS_RETURN _selectDownmixMatrix( + HANDLE_SEL_PROC_OUTPUT hSelProcOutput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig); + +static DRCDEC_SELECTION_PROCESS_RETURN _getLoudness( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int albumMode, + METHOD_DEFINITION_REQUEST measurementMethodRequested, + MEASUREMENT_SYSTEM_REQUEST measurementSystemRequested, + FIXP_DBL targetLoudness, int drcSetId, int downmixIdRequested, + FIXP_DBL* pLoudnessNormalizationGain, FIXP_DBL* pLoudness); + +static DRCDEC_SELECTION_PROCESS_RETURN _getMixingLevel( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int downmixIdRequested, + int drcSetIdRequested, int albumMode, FIXP_DBL* pMixingLevel); + +static DRCDEC_SELECTION_PROCESS_RETURN _getSignalPeakLevel( + HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, DRC_INSTRUCTIONS_UNI_DRC* pInst, + int downmixIdRequested, int* explicitPeakInformationPresent, + FIXP_DBL* signalPeakLevelOut, /* e = 7 */ + SEL_PROC_CODEC_MODE codecMode); + +static DRCDEC_SELECTION_PROCESS_RETURN _extractLoudnessPeakToAverageValue( + LOUDNESS_INFO* loudnessInfo, + DYN_RANGE_MEASUREMENT_REQUEST_TYPE dynamicRangeMeasurementType, + int* pLoudnessPeakToAverageValuePresent, + FIXP_DBL* pLoudnessPeakToAverageValue); + +static DRCDEC_SELECTION_PROCESS_RETURN _selectAlbumLoudness( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected); + +static int _findMethodDefinition(LOUDNESS_INFO* pLoudnessInfo, + int methodDefinition, int startIndex); + +/*******************************************/ +/* public functions */ +/*******************************************/ + +struct s_drcdec_selection_process { + SEL_PROC_CODEC_MODE codecMode; + SEL_PROC_INPUT selProcInput; + DRCDEC_SELECTION + selectionData[2]; /* 2 instances, one before and one after selection */ +}; + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_Create(HANDLE_DRC_SELECTION_PROCESS* phInstance) { + HANDLE_DRC_SELECTION_PROCESS hInstance; + hInstance = (HANDLE_DRC_SELECTION_PROCESS)FDKcalloc( + 1, sizeof(struct s_drcdec_selection_process)); + + if (!hInstance) return DRCDEC_SELECTION_PROCESS_OUTOFMEMORY; + + hInstance->codecMode = SEL_PROC_CODEC_MODE_UNDEFINED; + + *phInstance = hInstance; + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_Init(HANDLE_DRC_SELECTION_PROCESS hInstance) { + if (!hInstance) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + _initDefaultParams(&hInstance->selProcInput); + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_SetCodecMode(HANDLE_DRC_SELECTION_PROCESS hInstance, + const SEL_PROC_CODEC_MODE codecMode) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + if (!hInstance) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + switch (codecMode) { + case SEL_PROC_MPEG_4_AAC: + case SEL_PROC_MPEG_D_USAC: + case SEL_PROC_TEST_TIME_DOMAIN: + case SEL_PROC_TEST_QMF_DOMAIN: + case SEL_PROC_TEST_STFT_DOMAIN: + hInstance->codecMode = codecMode; + break; + + case SEL_PROC_CODEC_MODE_UNDEFINED: + default: + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + retVal = _initCodecModeParams(&(hInstance->selProcInput), + hInstance->codecMode = codecMode); + + return retVal; +} + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_SetParam(HANDLE_DRC_SELECTION_PROCESS hInstance, + const SEL_PROC_USER_PARAM requestType, + FIXP_DBL requestValue, int* pDiff) { + INT requestValueInt = (INT)requestValue; + int i, diff = 0; + SEL_PROC_INPUT* pSelProcInput = &(hInstance->selProcInput); + + switch (requestType) { + case SEL_PROC_LOUDNESS_NORMALIZATION_ON: + if ((requestValueInt != 0) && (requestValueInt != 1)) + return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE; + diff |= + _compAssign(&pSelProcInput->loudnessNormalizationOn, requestValueInt); + break; + case SEL_PROC_TARGET_LOUDNESS: + /* Lower boundary: drcSetTargetLoudnessValueLower default value. + Upper boundary: drcSetTargetLoudnessValueUpper default value */ + if ((requestValue < FL2FXCONST_DBL(-63.0f / (float)(1 << 7))) || + (requestValue > (FIXP_DBL)0)) + return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE; + if (requestValue > + FL2FXCONST_DBL(-10.0f / + (float)(1 << 7))) /* recommended maximum value */ + requestValue = FL2FXCONST_DBL(-10.0f / (float)(1 << 7)); + diff |= _compAssign(&pSelProcInput->targetLoudness, requestValue); + break; + case SEL_PROC_EFFECT_TYPE: + if ((requestValueInt < -1) || (requestValueInt >= DETR_COUNT)) + return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE; + /* Caution. This overrides all drcFeatureRequests requested so far! */ + if (requestValueInt == -1) { + diff |= _compAssign(&pSelProcInput->dynamicRangeControlOn, 0); + } else if (requestValueInt == DETR_NONE) { + diff |= _compAssign(&pSelProcInput->dynamicRangeControlOn, 1); + diff |= _compAssign(&pSelProcInput->numDrcFeatureRequests, 0); + } else { + diff |= _compAssign(&pSelProcInput->dynamicRangeControlOn, 1); + diff |= _compAssign(&pSelProcInput->numDrcFeatureRequests, 1); + diff |= _compAssign(&pSelProcInput->drcFeatureRequestType[0], + DFRT_EFFECT_TYPE); + diff |= _compAssign(&pSelProcInput->drcFeatureRequest[0] + .drcEffectType.numRequestsDesired, + 1); + diff |= _compAssign( + &pSelProcInput->drcFeatureRequest[0].drcEffectType.request[0], + requestValueInt); + if ((requestValueInt > DETR_NONE) && + (requestValueInt <= DETR_GENERAL_COMPR)) { + /* use fallback effect type requests */ + for (i = 0; i < 5; i++) { + diff |= + _compAssign(&pSelProcInput->drcFeatureRequest[0] + .drcEffectType.request[i + 1], + fallbackEffectTypeRequests[requestValueInt - 1][i]); + } + diff |= _compAssign( + &pSelProcInput->drcFeatureRequest[0].drcEffectType.numRequests, + 6); + } else { + diff |= _compAssign( + &pSelProcInput->drcFeatureRequest[0].drcEffectType.numRequests, + 1); + } + } + break; + case SEL_PROC_LOUDNESS_MEASUREMENT_METHOD: + if ((requestValueInt < 0) || (requestValueInt > 2)) + return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE; + diff |= _compAssign(&pSelProcInput->loudnessMeasurementMethod, + requestValueInt); + break; + case SEL_PROC_DOWNMIX_ID: + diff |= + _compAssign(&pSelProcInput->targetConfigRequestType, TCRT_DOWNMIX_ID); + if (requestValueInt < 0) { /* negative requests signal no downmixId */ + diff |= _compAssign(&pSelProcInput->numDownmixIdRequests, 0); + } else { + diff |= _compAssign(&pSelProcInput->numDownmixIdRequests, 1); + diff |= + _compAssign(&pSelProcInput->downmixIdRequested[0], requestValueInt); + } + break; + case SEL_PROC_TARGET_LAYOUT: + /* Request target layout according to ChannelConfiguration in ISO/IEC + * 23001-8 (CICP) */ + if ((requestValueInt < 1) || (requestValueInt > 63)) + return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE; + diff |= _compAssign(&pSelProcInput->targetConfigRequestType, + TCRT_TARGET_LAYOUT); + diff |= + _compAssign(&pSelProcInput->targetLayoutRequested, requestValueInt); + break; + case SEL_PROC_TARGET_CHANNEL_COUNT: + if ((requestValueInt < 1) || (requestValueInt > 8)) + return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE; + diff |= _compAssign(&pSelProcInput->targetConfigRequestType, + TCRT_TARGET_CHANNEL_COUNT); + diff |= _compAssign(&pSelProcInput->targetChannelCountRequested, + requestValueInt); + break; + case SEL_PROC_BASE_CHANNEL_COUNT: + if (requestValueInt < 0) + return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE; + diff |= _compAssign(&pSelProcInput->baseChannelCount, requestValueInt); + break; + case SEL_PROC_SAMPLE_RATE: + if (requestValueInt < 0) + return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE; + diff |= _compAssign(&pSelProcInput->audioSampleRate, requestValueInt); + break; + case SEL_PROC_BOOST: + if ((requestValue < (FIXP_DBL)0) || + (requestValue > FL2FXCONST_DBL(1.0f / (float)(1 << 1)))) + return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE; + diff |= _compAssign(&pSelProcInput->boost, FX_DBL2FX_SGL(requestValue)); + break; + case SEL_PROC_COMPRESS: + if ((requestValue < (FIXP_DBL)0) || + (requestValue > FL2FXCONST_DBL(1.0f / (float)(1 << 1)))) + return DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE; + diff |= + _compAssign(&pSelProcInput->compress, FX_DBL2FX_SGL(requestValue)); + break; + default: + return DRCDEC_SELECTION_PROCESS_INVALID_PARAM; + } + + if (pDiff != NULL) { + *pDiff |= diff; + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +FIXP_DBL +drcDec_SelectionProcess_GetParam(HANDLE_DRC_SELECTION_PROCESS hInstance, + const SEL_PROC_USER_PARAM requestType) { + SEL_PROC_INPUT* pSelProcInput = &(hInstance->selProcInput); + + switch (requestType) { + case SEL_PROC_LOUDNESS_NORMALIZATION_ON: + return (FIXP_DBL)pSelProcInput->loudnessNormalizationOn; + case SEL_PROC_DYNAMIC_RANGE_CONTROL_ON: + return (FIXP_DBL)pSelProcInput->dynamicRangeControlOn; + default: + return (FIXP_DBL)0; + } +} + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_Delete(HANDLE_DRC_SELECTION_PROCESS* phInstance) { + if (phInstance == NULL || *phInstance == NULL) + return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE; + + FDKfree(*phInstance); + *phInstance = NULL; + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_Process(HANDLE_DRC_SELECTION_PROCESS hInstance, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + HANDLE_SEL_PROC_OUTPUT hSelProcOutput) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + DRCDEC_SELECTION* pCandidatesSelected; + DRCDEC_SELECTION* pCandidatesPotential; + + if (hInstance == NULL) return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE; + + pCandidatesSelected = &(hInstance->selectionData[0]); + pCandidatesPotential = &(hInstance->selectionData[1]); + _drcdec_selection_setNumber(pCandidatesSelected, 0); + _drcdec_selection_setNumber(pCandidatesPotential, 0); + + retVal = _generateVirtualDrcSets(&(hInstance->selProcInput), hUniDrcConfig, + hInstance->codecMode); + if (retVal) return (retVal); + + if (hInstance->selProcInput.baseChannelCount != + hUniDrcConfig->channelLayout.baseChannelCount) { + hInstance->selProcInput.baseChannelCount = + hUniDrcConfig->channelLayout.baseChannelCount; + } + + if ((hInstance->selProcInput.targetConfigRequestType != 0) || + (hInstance->selProcInput.targetConfigRequestType == 0 && + hInstance->selProcInput.numDownmixIdRequests == 0)) { + retVal = _channelLayoutToDownmixIdMapping(&(hInstance->selProcInput), + hUniDrcConfig); + + if (_isError(retVal)) return (retVal); + } + + retVal = _drcSetPreSelection(&(hInstance->selProcInput), hUniDrcConfig, + hLoudnessInfoSet, &pCandidatesPotential, + &pCandidatesSelected, hInstance->codecMode); + if (retVal) return (retVal); + + if (hInstance->selProcInput.albumMode) { + _swapSelectionAndClear(&pCandidatesPotential, &pCandidatesSelected); + + retVal = _selectAlbumLoudness(hLoudnessInfoSet, pCandidatesPotential, + pCandidatesSelected); + if (retVal) return (retVal); + + if (_drcdec_selection_getNumber(pCandidatesSelected) == 0) { + _swapSelection(&pCandidatesPotential, &pCandidatesSelected); + } + } + + _swapSelectionAndClear(&pCandidatesPotential, &pCandidatesSelected); + + retVal = _drcSetRequestSelection(&(hInstance->selProcInput), hUniDrcConfig, + hLoudnessInfoSet, &pCandidatesPotential, + &pCandidatesSelected); + if (retVal) return (retVal); + + retVal = _drcSetFinalSelection(&(hInstance->selProcInput), hUniDrcConfig, + &pCandidatesPotential, &pCandidatesSelected, + hInstance->codecMode); + if (retVal) return (retVal); + + retVal = _generateOutputInfo( + &(hInstance->selProcInput), hSelProcOutput, hUniDrcConfig, + hLoudnessInfoSet, &(pCandidatesSelected->data[0]), hInstance->codecMode); + + if (_isError(retVal)) return (retVal); + + retVal = _selectDownmixMatrix(hSelProcOutput, hUniDrcConfig); + if (retVal) return (retVal); + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/*******************************************/ +/* static functions */ +/*******************************************/ + +static DRCDEC_SELECTION_PROCESS_RETURN _initDefaultParams( + HANDLE_SEL_PROC_INPUT hSelProcInput) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + if (hSelProcInput == NULL) return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE; + + /* system parameters */ + hSelProcInput->baseChannelCount = -1; + hSelProcInput->baseLayout = -1; + hSelProcInput->targetConfigRequestType = TCRT_DOWNMIX_ID; + hSelProcInput->numDownmixIdRequests = 0; + + /* loudness normalization parameters */ + hSelProcInput->albumMode = 0; + hSelProcInput->peakLimiterPresent = 0; + hSelProcInput->loudnessNormalizationOn = 1; + hSelProcInput->targetLoudness = FL2FXCONST_DBL(-24.0f / (float)(1 << 7)); + hSelProcInput->loudnessDeviationMax = DEFAULT_LOUDNESS_DEVIATION_MAX; + hSelProcInput->loudnessMeasurementMethod = MDR_DEFAULT; + hSelProcInput->loudnessMeasurementSystem = MSR_DEFAULT; + hSelProcInput->loudnessMeasurementPreProc = LPR_DEFAULT; + hSelProcInput->deviceCutOffFrequency = 500; + hSelProcInput->loudnessNormalizationGainDbMax = + (FIXP_DBL)MAXVAL_DBL; /* infinity as default */ + hSelProcInput->loudnessNormalizationGainModificationDb = (FIXP_DBL)0; + hSelProcInput->outputPeakLevelMax = (FIXP_DBL)0; + if (hSelProcInput->peakLimiterPresent == 1) { + hSelProcInput->outputPeakLevelMax = FL2FXCONST_DBL(6.0f / (float)(1 << 7)); + } + + /* dynamic range control parameters */ + hSelProcInput->dynamicRangeControlOn = 1; + + hSelProcInput->numDrcFeatureRequests = 0; + + /* other parameters */ + hSelProcInput->boost = FL2FXCONST_SGL(1.f / (float)(1 << 1)); + hSelProcInput->compress = FL2FXCONST_SGL(1.f / (float)(1 << 1)); + hSelProcInput->drcCharacteristicTarget = 0; + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _initCodecModeParams( + HANDLE_SEL_PROC_INPUT hSelProcInput, const SEL_PROC_CODEC_MODE codecMode) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + if (hSelProcInput == NULL) return DRCDEC_SELECTION_PROCESS_INVALID_HANDLE; + + switch (codecMode) { + case SEL_PROC_MPEG_H_3DA: + hSelProcInput->loudnessDeviationMax = 0; + hSelProcInput->peakLimiterPresent = 1; /* peak limiter is mandatory */ + /* The peak limiter also has to catch overshoots due to user + interactivity, downmixing etc. Therefore the maximum output peak level is + reduced to 0 dB. */ + hSelProcInput->outputPeakLevelMax = (FIXP_DBL)0; + break; + case SEL_PROC_MPEG_4_AAC: + case SEL_PROC_MPEG_D_USAC: + hSelProcInput->loudnessDeviationMax = DEFAULT_LOUDNESS_DEVIATION_MAX; + hSelProcInput->peakLimiterPresent = 1; + /* A peak limiter is present at the end of the decoder, therefore we can + * allow for a maximum output peak level greater than full scale + */ + hSelProcInput->outputPeakLevelMax = + FL2FXCONST_DBL(6.0f / (float)(1 << 7)); + break; + case SEL_PROC_TEST_TIME_DOMAIN: + case SEL_PROC_TEST_QMF_DOMAIN: + case SEL_PROC_TEST_STFT_DOMAIN: + /* for testing, adapt to default settings in reference software */ + hSelProcInput->loudnessNormalizationOn = 0; + hSelProcInput->dynamicRangeControlOn = 0; + break; + case SEL_PROC_CODEC_MODE_UNDEFINED: + default: + hSelProcInput->loudnessDeviationMax = DEFAULT_LOUDNESS_DEVIATION_MAX; + hSelProcInput->peakLimiterPresent = 0; + } + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _channelLayoutToDownmixIdMapping( + HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + DOWNMIX_INSTRUCTIONS* pDown = NULL; + + int i; + + hSelProcInput->numDownmixIdRequests = 0; + + switch (hSelProcInput->targetConfigRequestType) { + case TCRT_DOWNMIX_ID: + if (hSelProcInput->numDownmixIdRequests == 0) { + hSelProcInput->downmixIdRequested[0] = 0; + hSelProcInput->numDownmixIdRequests = 1; + } + + break; + + case TCRT_TARGET_LAYOUT: + if (hSelProcInput->targetLayoutRequested == hSelProcInput->baseLayout) { + hSelProcInput->downmixIdRequested[0] = 0; + hSelProcInput->numDownmixIdRequests = 1; + } + + if (hSelProcInput->numDownmixIdRequests == 0) { + for (i = 0; i < hUniDrcConfig->downmixInstructionsCount; i++) { + pDown = &(hUniDrcConfig->downmixInstructions[i]); + + if (hSelProcInput->targetLayoutRequested == pDown->targetLayout) { + hSelProcInput + ->downmixIdRequested[hSelProcInput->numDownmixIdRequests] = + pDown->downmixId; + hSelProcInput->numDownmixIdRequests++; + } + } + } + + if (hSelProcInput->baseLayout == -1) { + retVal = DRCDEC_SELECTION_PROCESS_WARNING; + } + + if (hSelProcInput->numDownmixIdRequests == 0) { + hSelProcInput->downmixIdRequested[0] = 0; + hSelProcInput->numDownmixIdRequests = 1; + retVal = DRCDEC_SELECTION_PROCESS_WARNING; + } + + break; + + case TCRT_TARGET_CHANNEL_COUNT: + if (hSelProcInput->targetChannelCountRequested == + hSelProcInput->baseChannelCount) { + hSelProcInput->downmixIdRequested[0] = 0; + hSelProcInput->numDownmixIdRequests = 1; + } + + if (hSelProcInput->numDownmixIdRequests == 0) { + for (i = 0; i < hUniDrcConfig->downmixInstructionsCount; i++) { + pDown = &(hUniDrcConfig->downmixInstructions[i]); + + if (hSelProcInput->targetChannelCountRequested == + pDown->targetChannelCount) { + hSelProcInput + ->downmixIdRequested[hSelProcInput->numDownmixIdRequests] = + pDown->downmixId; + hSelProcInput->numDownmixIdRequests++; + } + } + } + + if (hSelProcInput->baseChannelCount == -1) { + retVal = DRCDEC_SELECTION_PROCESS_WARNING; + } + + if (hSelProcInput->numDownmixIdRequests == 0) { + retVal = DRCDEC_SELECTION_PROCESS_WARNING; + hSelProcInput->downmixIdRequested[0] = 0; + hSelProcInput->numDownmixIdRequests = 1; + } + + break; + + default: + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + return retVal; +} + +/*******************************************/ + +/* Note: Numbering of DRC pre-selection steps according to MPEG-D Part-4 DRC + * Amd1 */ + +/* #1: DownmixId of DRC set matches the requested downmixId. + #2: Output channel layout of DRC set matches the requested layout. + #3: Channel count of DRC set matches the requested channel count. */ +static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement123( + int nRequestedDownmixId, DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, + int* pMatchFound) { + int i; + *pMatchFound = 0; + + for (i = 0; i < pDrcInstructionUniDrc->downmixIdCount; i++) { + if ((pDrcInstructionUniDrc->downmixId[i] == nRequestedDownmixId) || + (pDrcInstructionUniDrc->downmixId[i] == DOWNMIX_ID_ANY_DOWNMIX) || + ((pDrcInstructionUniDrc->downmixId[i] == DOWNMIX_ID_BASE_LAYOUT) && + (pDrcInstructionUniDrc->drcSetId > 0))) { + *pMatchFound = 1; + break; + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/* #4: The DRC set is not a "Fade-" or "Ducking-" only DRC set. */ +static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement4( + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction, int nDynamicRangeControlOn, + int* pMatchFound) { + *pMatchFound = 0; + + if (nDynamicRangeControlOn == 1) { + if ((pDrcInstruction->drcSetEffect != EB_FADE) && + (pDrcInstruction->drcSetEffect != EB_DUCK_OTHER) && + (pDrcInstruction->drcSetEffect != EB_DUCK_SELF) && + (pDrcInstruction->drcSetEffect != 0 || pDrcInstruction->drcSetId < 0)) { + *pMatchFound = 1; + } + } else { + *pMatchFound = 1; + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/* #5: The number of DRC bands is supported. */ +static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement5( + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, + DRC_COEFFICIENTS_UNI_DRC* pCoef, int* pMatchFound) { + int i; + + *pMatchFound = 1; + + if (pCoef == NULL) /* check for parametricDRC */ + { + *pMatchFound = 1; + return DRCDEC_SELECTION_PROCESS_NO_ERROR; + } + + for (i = 0; i < pDrcInstructionUniDrc->nDrcChannelGroups; i++) { + int indexDrcCoeff = pDrcInstructionUniDrc->gainSetIndexForChannelGroup[i]; + int bandCount = 0; + + if (indexDrcCoeff > pCoef->gainSetCount - 1) /* check for parametricDRC */ + { + *pMatchFound = 1; + return DRCDEC_SELECTION_PROCESS_NO_ERROR; + } + + GAIN_SET* gainSet = &(pCoef->gainSet[indexDrcCoeff]); + bandCount = gainSet->bandCount; + + if (bandCount > 4) { + *pMatchFound = 0; + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/* #6: Independent use of DRC set is permitted.*/ +static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement6( + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, int* pMatchFound) { + *pMatchFound = 0; + + if (((pDrcInstructionUniDrc->dependsOnDrcSetPresent == 0) && + (pDrcInstructionUniDrc->noIndependentUse == 0)) || + (pDrcInstructionUniDrc->dependsOnDrcSetPresent == 1)) { + *pMatchFound = 1; + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/* #7: DRC sets that require EQ are only permitted if EQ is supported. */ +static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement7( + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, int* pMatchFound) { + *pMatchFound = 1; + + if (pDrcInstructionUniDrc->requiresEq) { + /* EQ is not supported */ + *pMatchFound = 0; + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static void _setSelectionDataInfo(DRCDEC_SELECTION_DATA* pData, + FIXP_DBL loudness, + FIXP_DBL loudnessNormalizationGainDb, + FIXP_DBL loudnessNormalizationGainDbMax, + FIXP_DBL loudnessDeviationMax, + FIXP_DBL signalPeakLevel, + FIXP_DBL outputPeakLevelMax, + int applyAdjustment) { + FIXP_DBL adjustment = 0; + + if (applyAdjustment) { + adjustment = + fMax((FIXP_DBL)0, signalPeakLevel + loudnessNormalizationGainDb - + outputPeakLevelMax); + adjustment = fMin(adjustment, fMax((FIXP_DBL)0, loudnessDeviationMax)); + } + + pData->loudnessNormalizationGainDbAdjusted = fMin( + loudnessNormalizationGainDb - adjustment, loudnessNormalizationGainDbMax); + pData->outputLoudness = loudness + pData->loudnessNormalizationGainDbAdjusted; + pData->outputPeakLevel = + signalPeakLevel + pData->loudnessNormalizationGainDbAdjusted; +} + +static int _targetLoudnessInRange( + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, FIXP_DBL targetLoudness) { + int retVal = 0; + + FIXP_DBL drcSetTargetLoudnessValueUpper = + ((FIXP_DBL)pDrcInstructionUniDrc->drcSetTargetLoudnessValueUpper) + << (DFRACT_BITS - 1 - 7); + FIXP_DBL drcSetTargetLoudnessValueLower = + ((FIXP_DBL)pDrcInstructionUniDrc->drcSetTargetLoudnessValueLower) + << (DFRACT_BITS - 1 - 7); + + if (pDrcInstructionUniDrc->drcSetTargetLoudnessPresent && + drcSetTargetLoudnessValueUpper >= targetLoudness && + drcSetTargetLoudnessValueLower < targetLoudness) { + retVal = 1; + } + + return retVal; +} + +/* #8: The range of the target loudness specified for a DRC set has to include + * the requested decoder target loudness. */ +static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement8( + SEL_PROC_INPUT* hSelProcInput, int downmixIdIndex, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, + DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + int explicitPeakInformationPresent; + FIXP_DBL signalPeakLevel; + int addToCandidate = 0; + + FIXP_DBL loudnessNormalizationGainDb; + FIXP_DBL loudness; + + FIXP_DBL loudnessDeviationMax = + ((FIXP_DBL)hSelProcInput->loudnessDeviationMax) << (DFRACT_BITS - 1 - 7); + ; + + if (hSelProcInput->loudnessNormalizationOn) { + retVal = _getLoudness(hLoudnessInfoSet, hSelProcInput->albumMode, + hSelProcInput->loudnessMeasurementMethod, + hSelProcInput->loudnessMeasurementSystem, + hSelProcInput->targetLoudness, + pDrcInstructionUniDrc->drcSetId, + hSelProcInput->downmixIdRequested[downmixIdIndex], + &loudnessNormalizationGainDb, &loudness); + if (retVal) return (retVal); + } else { + loudnessNormalizationGainDb = (FIXP_DBL)0; + loudness = UNDEFINED_LOUDNESS_VALUE; + } + + retVal = _getSignalPeakLevel( + hSelProcInput, hUniDrcConfig, hLoudnessInfoSet, pDrcInstructionUniDrc, + hSelProcInput->downmixIdRequested[downmixIdIndex], + &explicitPeakInformationPresent, &signalPeakLevel, codecMode + + ); + if (retVal) return (retVal); + + if (hSelProcInput->dynamicRangeControlOn) { + if (explicitPeakInformationPresent == 0) { + if (pDrcInstructionUniDrc->drcSetTargetLoudnessPresent && + ((hSelProcInput->loudnessNormalizationOn && + _targetLoudnessInRange(pDrcInstructionUniDrc, + hSelProcInput->targetLoudness)) || + !hSelProcInput->loudnessNormalizationOn)) { + DRCDEC_SELECTION_DATA* pData = + _drcdec_selection_addNew(pCandidatesSelected); + if (pData == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + _setSelectionDataInfo(pData, loudness, loudnessNormalizationGainDb, + hSelProcInput->loudnessNormalizationGainDbMax, + loudnessDeviationMax, signalPeakLevel, + hSelProcInput->outputPeakLevelMax, 0); + pData->downmixIdRequestIndex = downmixIdIndex; + pData->pInst = pDrcInstructionUniDrc; + pData->selectionFlag = + 1; /* signal pre-selection step dealing with drcSetTargetLoudness */ + + if (hSelProcInput->loudnessNormalizationOn) { + pData->outputPeakLevel = + hSelProcInput->targetLoudness - + (((FIXP_DBL)pData->pInst->drcSetTargetLoudnessValueUpper) + << (DFRACT_BITS - 1 - 7)); + } else { + pData->outputPeakLevel = (FIXP_DBL)0; + } + } else { + if ((!hSelProcInput->loudnessNormalizationOn) || + (!pDrcInstructionUniDrc->drcSetTargetLoudnessPresent) || + (hSelProcInput->loudnessNormalizationOn && + _targetLoudnessInRange(pDrcInstructionUniDrc, + hSelProcInput->targetLoudness))) { + addToCandidate = 1; + } + } + } else { + addToCandidate = 1; + } + + if (addToCandidate) { + DRCDEC_SELECTION_DATA* pData = + _drcdec_selection_addNew(pCandidatesPotential); + if (pData == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + _setSelectionDataInfo(pData, loudness, loudnessNormalizationGainDb, + hSelProcInput->loudnessNormalizationGainDbMax, + loudnessDeviationMax, signalPeakLevel, + hSelProcInput->outputPeakLevelMax, 0); + pData->downmixIdRequestIndex = downmixIdIndex; + pData->pInst = pDrcInstructionUniDrc; + pData->selectionFlag = 0; + } + } else { + if (pDrcInstructionUniDrc->drcSetId < 0) { + DRCDEC_SELECTION_DATA* pData = + _drcdec_selection_addNew(pCandidatesSelected); + if (pData == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + _setSelectionDataInfo(pData, loudness, loudnessNormalizationGainDb, + hSelProcInput->loudnessNormalizationGainDbMax, + loudnessDeviationMax, signalPeakLevel, + hSelProcInput->outputPeakLevelMax, 1); + + pData->downmixIdRequestIndex = downmixIdIndex; + pData->pInst = pDrcInstructionUniDrc; + pData->selectionFlag = 0; + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/* #9: Clipping is minimized. */ +static DRCDEC_SELECTION_PROCESS_RETURN _preSelectionRequirement9( + SEL_PROC_INPUT* hSelProcInput, DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected) { + int i; + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + DRCDEC_SELECTION_DATA* pCandidate = + _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + if (pCandidate->outputPeakLevel <= hSelProcInput->outputPeakLevelMax) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetPreSelectionSingleInstruction( + SEL_PROC_INPUT* hSelProcInput, int downmixIdIndex, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc, + DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + int matchFound = 0; + DRC_COEFFICIENTS_UNI_DRC* pCoef = + selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED); + + retVal = _preSelectionRequirement123( + hSelProcInput->downmixIdRequested[downmixIdIndex], pDrcInstructionUniDrc, + &matchFound); + + if (!retVal && matchFound) + retVal = _preSelectionRequirement4(pDrcInstructionUniDrc, + hSelProcInput->dynamicRangeControlOn, + &matchFound); + + if (!retVal && matchFound) + retVal = + _preSelectionRequirement5(pDrcInstructionUniDrc, pCoef, &matchFound); + + if (!retVal && matchFound) + retVal = _preSelectionRequirement6(pDrcInstructionUniDrc, &matchFound); + + if (!retVal && matchFound) + retVal = _preSelectionRequirement7(pDrcInstructionUniDrc, &matchFound); + + if (!retVal && matchFound) + retVal = _preSelectionRequirement8( + hSelProcInput, downmixIdIndex, hUniDrcConfig, hLoudnessInfoSet, + pDrcInstructionUniDrc, pCandidatesPotential, pCandidatesSelected, + codecMode); + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetSelectionAddCandidates( + SEL_PROC_INPUT* hSelProcInput, DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + int nHitCount = 0; + int i; + + DRCDEC_SELECTION_DATA* pCandidate = NULL; + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc = NULL; + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + pDrcInstructionUniDrc = pCandidate->pInst; + + if (_targetLoudnessInRange(pDrcInstructionUniDrc, + hSelProcInput->targetLoudness)) { + nHitCount++; + } + } + + if (nHitCount != 0) { + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + pDrcInstructionUniDrc = pCandidate->pInst; + + if (_targetLoudnessInRange(pDrcInstructionUniDrc, + hSelProcInput->targetLoudness)) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + } else { + FIXP_DBL lowestPeakLevel = MAXVAL_DBL; /* e = 7 */ + FIXP_DBL peakLevel = 0; /* e = 7 */ + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + peakLevel = pCandidate->outputPeakLevel; + + if (peakLevel < lowestPeakLevel) { + lowestPeakLevel = peakLevel; + } + } + + /* add all with lowest peak level or max 1dB above */ + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + FIXP_DBL loudnessDeviationMax = + ((FIXP_DBL)hSelProcInput->loudnessDeviationMax) + << (DFRACT_BITS - 1 - 7); /* e = 7 */ + + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + peakLevel = pCandidate->outputPeakLevel; + + if (peakLevel == lowestPeakLevel || + peakLevel <= + lowestPeakLevel + FL2FXCONST_DBL(1.0f / (float)(1 << 7))) { + FIXP_DBL adjustment = + fMax((FIXP_DBL)0, peakLevel - hSelProcInput->outputPeakLevelMax); + adjustment = fMin(adjustment, fMax((FIXP_DBL)0, loudnessDeviationMax)); + + pCandidate->loudnessNormalizationGainDbAdjusted -= adjustment; + pCandidate->outputPeakLevel -= adjustment; + pCandidate->outputLoudness -= adjustment; + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + } + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _dependentDrcInstruction( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRC_INSTRUCTIONS_UNI_DRC* pInst, + DRC_INSTRUCTIONS_UNI_DRC** ppDrcInstructionsDependent) { + int i; + DRC_INSTRUCTIONS_UNI_DRC* pDependentDrc = NULL; + + for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) { + pDependentDrc = + (DRC_INSTRUCTIONS_UNI_DRC*)&(hUniDrcConfig->drcInstructionsUniDrc[i]); + + if (pDependentDrc->drcSetId == pInst->dependsOnDrcSet) { + break; + } + } + + if (i == hUniDrcConfig->drcInstructionsUniDrcCount) { + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + if (pDependentDrc->dependsOnDrcSetPresent == 1) { + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + *ppDrcInstructionsDependent = pDependentDrc; + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _selectDrcSetEffectNone( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected) { + int i; + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + DRCDEC_SELECTION_DATA* pCandidate = + _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + if ((pCandidate->pInst->drcSetEffect & 0xff) == 0) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _selectSingleEffectType( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRC_EFFECT_TYPE_REQUEST effectType, + DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected) { + int i; + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + DRC_INSTRUCTIONS_UNI_DRC* pInst; + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionsDependent; + + if (effectType == DETR_NONE) { + retVal = _selectDrcSetEffectNone(hUniDrcConfig, pCandidatesPotential, + pCandidatesSelected); + if (retVal) return (retVal); + } else { + int effectBitPosition = 1 << (effectType - 1); + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + DRCDEC_SELECTION_DATA* pCandidate = + _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + pInst = pCandidate->pInst; + + if (!pInst->dependsOnDrcSetPresent) { + if ((pInst->drcSetEffect & effectBitPosition)) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } else { + retVal = _dependentDrcInstruction(hUniDrcConfig, pInst, + &pDrcInstructionsDependent); + if (retVal) return (retVal); + + if (((pInst->drcSetEffect & effectBitPosition)) || + ((pDrcInstructionsDependent->drcSetEffect & effectBitPosition))) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + } + } + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _selectEffectTypeFeature( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, DRC_FEATURE_REQUEST drcFeatureRequest, + DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + int i; + int desiredEffectTypeFound = 0; + + for (i = 0; i < drcFeatureRequest.drcEffectType.numRequestsDesired; i++) { + retVal = _selectSingleEffectType( + hUniDrcConfig, drcFeatureRequest.drcEffectType.request[i], + *ppCandidatesPotential, *ppCandidatesSelected); + if (retVal) return (retVal); + + if (_drcdec_selection_getNumber(*ppCandidatesSelected)) { + desiredEffectTypeFound = 1; + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + } + } + + if (!desiredEffectTypeFound) { + for (i = drcFeatureRequest.drcEffectType.numRequestsDesired; + i < drcFeatureRequest.drcEffectType.numRequests; i++) { + retVal = _selectSingleEffectType( + hUniDrcConfig, drcFeatureRequest.drcEffectType.request[i], + *ppCandidatesPotential, *ppCandidatesSelected); + if (retVal) return (retVal); + + if (_drcdec_selection_getNumber(*ppCandidatesSelected)) { + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + break; + } + } + } + + _swapSelection(ppCandidatesPotential, ppCandidatesSelected); + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _selectDynamicRange( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + DRC_FEATURE_REQUEST drcFeatureRequest, UCHAR* pDownmixIdRequested, + int albumMode, DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* ppCandidatesSelected) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + int i; + int peakToAveragePresent; + FIXP_DBL peakToAverage; + + FIXP_DBL minVal = MAXVAL_DBL; + FIXP_DBL val = 0; + + int numSelectedCandidates = _drcdec_selection_getNumber(ppCandidatesSelected); + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + DRCDEC_SELECTION_DATA* pCandidate = + _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + retVal = _dynamicRangeMeasurement( + hLoudnessInfoSet, pCandidate->pInst, + pDownmixIdRequested[pCandidate->downmixIdRequestIndex], + drcFeatureRequest.dynamicRange.measurementRequestType, albumMode, + &peakToAveragePresent, &peakToAverage); + if (retVal) return (retVal); + + if (peakToAveragePresent) { + if (!drcFeatureRequest.dynamicRange.requestedIsRange) { + val = fAbs(drcFeatureRequest.dynamicRange.requestValue - peakToAverage); + + if (minVal > val) { + minVal = val; + + _drcdec_selection_setNumber(ppCandidatesSelected, + numSelectedCandidates); + } + if (_drcdec_selection_add(ppCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } else { + if ((peakToAverage >= drcFeatureRequest.dynamicRange.requestValueMin) && + (peakToAverage <= drcFeatureRequest.dynamicRange.requestValueMax)) { + if (_drcdec_selection_add(ppCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + } + } + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _selectSingleDrcCharacteristic( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, int requestedDrcCharacteristic, + DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected) { + int i, j, b; + int hit = 0; + + DRC_INSTRUCTIONS_UNI_DRC* pInst = NULL; + DRC_COEFFICIENTS_UNI_DRC* pCoef = NULL; + GAIN_SET* pGainSet = NULL; + + if (requestedDrcCharacteristic < 1) { + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + pCoef = selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED); + + if (pCoef == NULL) /* check for parametricDRC */ + { + return DRCDEC_SELECTION_PROCESS_NO_ERROR; + } + + for (i = 0; i < _drcdec_selection_getNumber(*ppCandidatesPotential); i++) { + DRCDEC_SELECTION_DATA* pCandidate = + _drcdec_selection_getAt(*ppCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + pInst = pCandidate->pInst; + + hit = 0; + + for (j = 0; j < pInst->nDrcChannelGroups; j++) { + int bandCount = 0; + int indexDrcCoeff = pInst->gainSetIndexForChannelGroup[j]; + + if (indexDrcCoeff > pCoef->gainSetCount - 1) /* check for parametricDRC */ + { + return DRCDEC_SELECTION_PROCESS_NO_ERROR; + } + + pGainSet = &(pCoef->gainSet[indexDrcCoeff]); + bandCount = pGainSet->bandCount; + + for (b = 0; b < bandCount; b++) { + if ((pGainSet->drcCharacteristic[b].isCICP) && + (pGainSet->drcCharacteristic[b].cicpIndex == + requestedDrcCharacteristic)) { + hit = 1; + break; + } + } + + if (hit) break; + } + + if (hit) { + if (_drcdec_selection_add(*ppCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + + if (_drcdec_selection_getNumber(*ppCandidatesSelected)) { + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _selectDrcCharacteristic( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, int drcCharacteristicRequested, + DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + const int secondTry[12] = {0, 2, 3, 4, 5, 6, 5, 9, 10, 7, 8, 10}; + + retVal = _selectSingleDrcCharacteristic( + hUniDrcConfig, drcCharacteristicRequested, ppCandidatesPotential, + ppCandidatesSelected); + if (retVal) return (retVal); + + if ((drcCharacteristicRequested <= 11) && + (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0)) { + retVal = _selectSingleDrcCharacteristic( + hUniDrcConfig, secondTry[drcCharacteristicRequested], + ppCandidatesPotential, ppCandidatesSelected); + if (retVal) return (retVal); + } + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) { + if ((drcCharacteristicRequested >= 2) && + (drcCharacteristicRequested <= 5)) { + retVal = _selectSingleDrcCharacteristic( + hUniDrcConfig, drcCharacteristicRequested - 1, ppCandidatesPotential, + ppCandidatesSelected); + if (retVal) return (retVal); + } else if (drcCharacteristicRequested == 11) { + retVal = _selectSingleDrcCharacteristic( + hUniDrcConfig, 9, ppCandidatesPotential, ppCandidatesSelected); + if (retVal) return (retVal); + } + } + + _swapSelection(ppCandidatesPotential, ppCandidatesSelected); + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_peakValue0( + DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected) { + int i; + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + DRCDEC_SELECTION_DATA* pCandidate = + _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + if (pCandidate->outputPeakLevel <= FIXP_DBL(0)) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_downmixId( + HANDLE_SEL_PROC_INPUT hSelProcInput, + DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected) { + int i, j; + DRCDEC_SELECTION_DATA* pCandidate = NULL; + DRC_INSTRUCTIONS_UNI_DRC* pInst = NULL; + + for (i = 0; i < _drcdec_selection_getNumber(*ppCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(*ppCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + pInst = pCandidate->pInst; + + for (j = 0; j < pInst->downmixIdCount; j++) { + if (DOWNMIX_ID_BASE_LAYOUT != pInst->downmixId[j] && + DOWNMIX_ID_ANY_DOWNMIX != pInst->downmixId[j] && + hSelProcInput + ->downmixIdRequested[pCandidate->downmixIdRequestIndex] == + pInst->downmixId[j]) { + if (_drcdec_selection_add(*ppCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + } + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) { + _swapSelection(ppCandidatesPotential, ppCandidatesSelected); + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static int _crossSum(int value) { + int sum = 0; + + while (value != 0) { + if ((value & 1) == 1) { + sum++; + } + + value >>= 1; + } + + return sum; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_effectTypes( + DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected) { + int i; + int minNumEffects = 1000; + int numEffects = 0; + int effects = 0; + DRCDEC_SELECTION_DATA* pCandidate = NULL; + DRC_INSTRUCTIONS_UNI_DRC* pInst = NULL; + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + pInst = pCandidate->pInst; + + effects = pInst->drcSetEffect; + effects &= 0xffff ^ (EB_GENERAL_COMPR); + numEffects = _crossSum(effects); + + if (numEffects < minNumEffects) { + minNumEffects = numEffects; + } + } + + /* add all with minimum number of effects */ + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + pInst = pCandidate->pInst; + + effects = pInst->drcSetEffect; + effects &= 0xffff ^ (EB_GENERAL_COMPR); + numEffects = _crossSum(effects); + + if (numEffects == minNumEffects) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _selectSmallestTargetLoudnessValueUpper( + DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected) { + int i; + SCHAR minVal = 0x7F; + SCHAR val = 0; + DRCDEC_SELECTION_DATA* pCandidate = NULL; + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + val = pCandidate->pInst->drcSetTargetLoudnessValueUpper; + + if (val < minVal) { + minVal = val; + } + } + + /* add all with same smallest drcSetTargetLoudnessValueUpper */ + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + val = pCandidate->pInst->drcSetTargetLoudnessValueUpper; + + if (val == minVal) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_targetLoudness( + FIXP_DBL targetLoudness, DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + int i; + DRCDEC_SELECTION_DATA* pCandidate = NULL; + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + if (pCandidate->selectionFlag == 0) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + + if (_drcdec_selection_getNumber(pCandidatesSelected) == 0) { + retVal = _selectSmallestTargetLoudnessValueUpper(pCandidatesPotential, + pCandidatesSelected); + if (retVal) return (retVal); + } + + if (_drcdec_selection_getNumber(pCandidatesSelected) > 1) { + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstructionUniDrc = NULL; + + _swapSelectionAndClear(&pCandidatesPotential, &pCandidatesSelected); + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + pDrcInstructionUniDrc = pCandidate->pInst; + + if (_targetLoudnessInRange(pDrcInstructionUniDrc, targetLoudness)) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + + if (_drcdec_selection_getNumber(pCandidatesSelected) > 1) { + _swapSelectionAndClear(&pCandidatesPotential, &pCandidatesSelected); + + retVal = _selectSmallestTargetLoudnessValueUpper(pCandidatesPotential, + pCandidatesSelected); + if (retVal) return (retVal); + } + } + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_peakValueLargest( + DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected) { + int i; + FIXP_DBL largestPeakLevel = MINVAL_DBL; + FIXP_DBL peakLevel = 0; + DRCDEC_SELECTION_DATA* pCandidate = NULL; + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + peakLevel = pCandidate->outputPeakLevel; + + if (peakLevel > largestPeakLevel) { + largestPeakLevel = peakLevel; + } + } + + /* add all with same largest peak level */ + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + peakLevel = pCandidate->outputPeakLevel; + + if (peakLevel == largestPeakLevel) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection_drcSetId( + DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected) { + int i; + int largestId = -1000; + int id = 0; + DRCDEC_SELECTION_DATA* pCandidate = NULL; + DRCDEC_SELECTION_DATA* pCandidateSelected = NULL; + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + pCandidate = _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + id = pCandidate->pInst->drcSetId; + + if (id > largestId) { + largestId = id; + pCandidateSelected = pCandidate; + } + } + + if (pCandidateSelected != NULL) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidateSelected) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } else { + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetFinalSelection( + HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + if (_drcdec_selection_getNumber(*ppCandidatesPotential) == 0) { + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } else if (_drcdec_selection_getNumber(*ppCandidatesPotential) == 1) { + _swapSelection(ppCandidatesPotential, ppCandidatesSelected); + /* finished */ + } else /* > 1 */ + { + retVal = _drcSetFinalSelection_peakValue0(*ppCandidatesPotential, + *ppCandidatesSelected); + if (retVal) return (retVal); + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) { + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + retVal = _drcSetFinalSelection_downmixId( + hSelProcInput, ppCandidatesPotential, ppCandidatesSelected); + if (retVal) return (retVal); + } + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) { + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + retVal = _drcSetFinalSelection_effectTypes(*ppCandidatesPotential, + *ppCandidatesSelected); + if (retVal) return (retVal); + } + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) { + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + retVal = _drcSetFinalSelection_targetLoudness( + hSelProcInput->targetLoudness, *ppCandidatesPotential, + *ppCandidatesSelected); + if (retVal) return (retVal); + } + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) { + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + retVal = _drcSetFinalSelection_peakValueLargest(*ppCandidatesPotential, + *ppCandidatesSelected); + if (retVal) return (retVal); + } + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 1) { + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + retVal = _drcSetFinalSelection_drcSetId(*ppCandidatesPotential, + *ppCandidatesSelected); + if (retVal) return (retVal); + } + } + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) { + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _generateVirtualDrcSets( + HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + SEL_PROC_CODEC_MODE codecMode) { + int i; + int nMixes = hUniDrcConfig->downmixInstructionsCount + 1; + int index = hUniDrcConfig->drcInstructionsUniDrcCount; + int indexVirtual = -1; + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction = + &(hUniDrcConfig->drcInstructionsUniDrc[index]); + + if (codecMode == SEL_PROC_MPEG_H_3DA) { + nMixes = 1; + } + + if ((index + nMixes) > (12 + 1 + 6)) { + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + FDKmemset(pDrcInstruction, 0, sizeof(DRC_INSTRUCTIONS_UNI_DRC)); + + pDrcInstruction->drcSetId = indexVirtual; + index++; + indexVirtual--; + pDrcInstruction->downmixIdCount = 1; + + if ((codecMode == SEL_PROC_MPEG_H_3DA) && + (hSelProcInput->numDownmixIdRequests)) { + pDrcInstruction->downmixId[0] = hSelProcInput->downmixIdRequested[0]; + } else { + pDrcInstruction->downmixId[0] = DOWNMIX_ID_BASE_LAYOUT; + } + + for (i = 1; i < nMixes; i++) { + pDrcInstruction = &(hUniDrcConfig->drcInstructionsUniDrc[index]); + FDKmemset(pDrcInstruction, 0, sizeof(DRC_INSTRUCTIONS_UNI_DRC)); + pDrcInstruction->drcSetId = indexVirtual; + pDrcInstruction->downmixId[0] = + hUniDrcConfig->downmixInstructions[i - 1].downmixId; + pDrcInstruction->downmixIdCount = 1; + index++; + indexVirtual--; + } + + hUniDrcConfig->drcInstructionsCountInclVirtual = + hUniDrcConfig->drcInstructionsUniDrcCount + nMixes; + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _generateOutputInfo( + HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_SEL_PROC_OUTPUT hSelProcOutput, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + DRCDEC_SELECTION_DATA* pSelectionData, SEL_PROC_CODEC_MODE codecMode) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + int i, j; + int hasDependend = 0; + int hasFading = 0; + int hasDucking = 0; + int selectedDrcSetIds; + int selectedDownmixIds; + FIXP_DBL mixingLevel = 0; + int albumMode = hSelProcInput->albumMode; + UCHAR* pDownmixIdRequested = hSelProcInput->downmixIdRequested; + FIXP_SGL boost = hSelProcInput->boost; + FIXP_SGL compress = hSelProcInput->compress; + + hSelProcOutput->numSelectedDrcSets = 1; + hSelProcOutput->selectedDrcSetIds[0] = pSelectionData->pInst->drcSetId; + hSelProcOutput->selectedDownmixIds[0] = + pSelectionData->pInst->drcApplyToDownmix == 1 + ? pSelectionData->pInst->downmixId[0] + : 0; + hSelProcOutput->loudnessNormalizationGainDb = + pSelectionData->loudnessNormalizationGainDbAdjusted + + hSelProcInput->loudnessNormalizationGainModificationDb; + hSelProcOutput->outputPeakLevelDb = pSelectionData->outputPeakLevel; + + hSelProcOutput->boost = boost; + hSelProcOutput->compress = compress; + hSelProcOutput->baseChannelCount = + hUniDrcConfig->channelLayout.baseChannelCount; + hSelProcOutput->targetChannelCount = + hUniDrcConfig->channelLayout.baseChannelCount; + hSelProcOutput->activeDownmixId = + pDownmixIdRequested[pSelectionData->downmixIdRequestIndex]; + + _getMixingLevel(hLoudnessInfoSet, *pDownmixIdRequested, + hSelProcOutput->selectedDrcSetIds[0], albumMode, + &mixingLevel); + hSelProcOutput->mixingLevel = mixingLevel; + + /*dependent*/ + if (pSelectionData->pInst->dependsOnDrcSetPresent) { + int dependsOnDrcSetID = pSelectionData->pInst->dependsOnDrcSet; + + for (i = 0; i < hUniDrcConfig->drcInstructionsCountInclVirtual; i++) { + if (hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId == + dependsOnDrcSetID) { + hSelProcOutput->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] = + hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId; + hSelProcOutput->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] = + hUniDrcConfig->drcInstructionsUniDrc[i].drcApplyToDownmix == 1 + ? hUniDrcConfig->drcInstructionsUniDrc[i].downmixId[0] + : 0; + hSelProcOutput->numSelectedDrcSets++; + hasDependend = 1; + break; + } + } + } + + /* fading */ + if (hSelProcInput->albumMode == 0) { + for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) { + DRC_INSTRUCTIONS_UNI_DRC* pInst = + &(hUniDrcConfig->drcInstructionsUniDrc[i]); + + if (pInst->drcSetEffect & EB_FADE) { + if (pInst->downmixId[0] == DOWNMIX_ID_ANY_DOWNMIX) { + hSelProcOutput->numSelectedDrcSets = hasDependend + 1; + hSelProcOutput + ->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] = + hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId; + hSelProcOutput + ->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] = + hUniDrcConfig->drcInstructionsUniDrc[i].drcApplyToDownmix == 1 + ? hUniDrcConfig->drcInstructionsUniDrc[i].downmixId[0] + : 0; + hSelProcOutput->numSelectedDrcSets++; + hasFading = 1; + + } else { + retVal = DRCDEC_SELECTION_PROCESS_NOT_OK; + if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + } + } + + /* ducking */ + for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) { + DRC_INSTRUCTIONS_UNI_DRC* pInst = + &(hUniDrcConfig->drcInstructionsUniDrc[i]); + + if (pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) { + for (j = 0; j < pInst->downmixIdCount; j++) { + if (pInst->downmixId[j] == hSelProcOutput->activeDownmixId) { + hSelProcOutput->numSelectedDrcSets = + hasDependend + 1; /* ducking overrides fading */ + + hSelProcOutput + ->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] = + hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId; + /* force ducking DRC set to be processed on base layout */ + hSelProcOutput + ->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] = 0; + hSelProcOutput->numSelectedDrcSets++; + hasDucking = 1; + } + } + } + } + + /* repeat for DOWNMIX_ID_BASE_LAYOUT if no ducking found*/ + + if (!hasDucking) { + for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) { + DRC_INSTRUCTIONS_UNI_DRC* pInst = + &(hUniDrcConfig->drcInstructionsUniDrc[i]); + + if (pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) { + for (j = 0; j < pInst->downmixIdCount; j++) { + if (pInst->downmixId[j] == DOWNMIX_ID_BASE_LAYOUT) { + hSelProcOutput->numSelectedDrcSets = hasDependend + hasFading + 1; + hSelProcOutput + ->selectedDrcSetIds[hSelProcOutput->numSelectedDrcSets] = + hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId; + /* force ducking DRC set to be processed on base layout */ + hSelProcOutput + ->selectedDownmixIds[hSelProcOutput->numSelectedDrcSets] = 0; + hSelProcOutput->numSelectedDrcSets++; + } + } + } + } + } + + if (hSelProcOutput->numSelectedDrcSets > 3) { + /* maximum permitted number of applied DRC sets is 3, see section 6.3.5 of + * ISO/IEC 23003-4 */ + hSelProcOutput->numSelectedDrcSets = 0; + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + /* sorting: Ducking/Fading -> Dependent -> Selected */ + if (hSelProcOutput->numSelectedDrcSets == 3) { + selectedDrcSetIds = hSelProcOutput->selectedDrcSetIds[0]; + selectedDownmixIds = hSelProcOutput->selectedDownmixIds[0]; + hSelProcOutput->selectedDrcSetIds[0] = hSelProcOutput->selectedDrcSetIds[2]; + hSelProcOutput->selectedDownmixIds[0] = + hSelProcOutput->selectedDownmixIds[2]; + hSelProcOutput->selectedDrcSetIds[2] = selectedDrcSetIds; + hSelProcOutput->selectedDownmixIds[2] = selectedDownmixIds; + } else if (hSelProcOutput->numSelectedDrcSets == 2) { + selectedDrcSetIds = hSelProcOutput->selectedDrcSetIds[0]; + selectedDownmixIds = hSelProcOutput->selectedDownmixIds[0]; + hSelProcOutput->selectedDrcSetIds[0] = hSelProcOutput->selectedDrcSetIds[1]; + hSelProcOutput->selectedDownmixIds[0] = + hSelProcOutput->selectedDownmixIds[1]; + hSelProcOutput->selectedDrcSetIds[1] = selectedDrcSetIds; + hSelProcOutput->selectedDownmixIds[1] = selectedDownmixIds; + } + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _selectDownmixMatrix( + HANDLE_SEL_PROC_OUTPUT hSelProcOutput, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig) { + int i; + hSelProcOutput->baseChannelCount = + hUniDrcConfig->channelLayout.baseChannelCount; + hSelProcOutput->targetChannelCount = + hUniDrcConfig->channelLayout.baseChannelCount; + hSelProcOutput->targetLayout = -1; + hSelProcOutput->downmixMatrixPresent = 0; + + if (hSelProcOutput->activeDownmixId != 0) { + for (i = 0; i < hUniDrcConfig->downmixInstructionsCount; i++) { + DOWNMIX_INSTRUCTIONS* pDown = &(hUniDrcConfig->downmixInstructions[i]); + + if (hSelProcOutput->activeDownmixId == pDown->downmixId) { + hSelProcOutput->targetChannelCount = pDown->targetChannelCount; + hSelProcOutput->targetLayout = pDown->targetLayout; + + if (pDown->downmixCoefficientsPresent) { + int j, k; + FIXP_DBL downmixOffset = getDownmixOffset( + pDown, hSelProcOutput->baseChannelCount); /* e = 1 */ + + for (j = 0; j < hSelProcOutput->baseChannelCount; j++) { + for (k = 0; k < hSelProcOutput->targetChannelCount; k++) { + hSelProcOutput->downmixMatrix[j][k] = + fMultDiv2( + downmixOffset, + pDown->downmixCoefficient[j + k * hSelProcOutput + ->baseChannelCount]) + << 2; + } + } + + hSelProcOutput->downmixMatrixPresent = 1; + } + break; + } + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetPreSelection( + SEL_PROC_INPUT* hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected, SEL_PROC_CODEC_MODE codecMode) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + int i, j; + + for (i = 0; i < hSelProcInput->numDownmixIdRequests; i++) { + for (j = 0; j < hUniDrcConfig->drcInstructionsCountInclVirtual; j++) { + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction = + &(hUniDrcConfig->drcInstructionsUniDrc[j]); + retVal = _drcSetPreSelectionSingleInstruction( + hSelProcInput, i, hUniDrcConfig, hLoudnessInfoSet, pDrcInstruction, + *ppCandidatesPotential, *ppCandidatesSelected, codecMode); + if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + + retVal = _preSelectionRequirement9(hSelProcInput, *ppCandidatesPotential, + *ppCandidatesSelected); + if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) { + retVal = _drcSetSelectionAddCandidates( + hSelProcInput, *ppCandidatesPotential, *ppCandidatesSelected); + if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _drcSetRequestSelection( + SEL_PROC_INPUT* hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected) { + DRCDEC_SELECTION_PROCESS_RETURN retVal; + int i; + + if (_drcdec_selection_getNumber(*ppCandidatesPotential) == 0) { + retVal = DRCDEC_SELECTION_PROCESS_NOT_OK; + if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + if (hSelProcInput->dynamicRangeControlOn) { + if (hSelProcInput->numDrcFeatureRequests == 0) { + retVal = _selectDrcSetEffectNone(hUniDrcConfig, *ppCandidatesPotential, + *ppCandidatesSelected); + if (retVal) return (retVal); + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) == 0) { + DRC_FEATURE_REQUEST fallbackRequest; + fallbackRequest.drcEffectType.numRequests = 5; + fallbackRequest.drcEffectType.numRequestsDesired = 5; + fallbackRequest.drcEffectType.request[0] = DETR_GENERAL_COMPR; + fallbackRequest.drcEffectType.request[1] = DETR_NIGHT; + fallbackRequest.drcEffectType.request[2] = DETR_NOISY; + fallbackRequest.drcEffectType.request[3] = DETR_LIMITED; + fallbackRequest.drcEffectType.request[4] = DETR_LOWLEVEL; + + retVal = _selectEffectTypeFeature(hUniDrcConfig, fallbackRequest, + ppCandidatesPotential, + ppCandidatesSelected); + if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + } else { + for (i = 0; i < hSelProcInput->numDrcFeatureRequests; i++) { + if (hSelProcInput->drcFeatureRequestType[i] == DFRT_EFFECT_TYPE) { + retVal = _selectEffectTypeFeature( + hUniDrcConfig, hSelProcInput->drcFeatureRequest[i], + ppCandidatesPotential, ppCandidatesSelected); + + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + else if (hSelProcInput->drcFeatureRequestType[i] == + DFRT_DYNAMIC_RANGE) { + retVal = _selectDynamicRange( + hUniDrcConfig, hLoudnessInfoSet, + hSelProcInput->drcFeatureRequest[i], + hSelProcInput->downmixIdRequested, hSelProcInput->albumMode, + *ppCandidatesPotential, *ppCandidatesSelected); + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 0) { + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + } + if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK; + } else if (hSelProcInput->drcFeatureRequestType[i] == + DFRT_DRC_CHARACTERISTIC) { + retVal = _selectDrcCharacteristic( + hUniDrcConfig, + hSelProcInput->drcFeatureRequest[i].drcCharacteristic, + ppCandidatesPotential, ppCandidatesSelected); + + if (_drcdec_selection_getNumber(*ppCandidatesSelected) > 0) { + _swapSelectionAndClear(ppCandidatesPotential, ppCandidatesSelected); + } + if (retVal) return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/*******************************************/ +static DRCDEC_SELECTION_PROCESS_RETURN _dynamicRangeMeasurement( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, DRC_INSTRUCTIONS_UNI_DRC* pInst, + UCHAR downmixIdRequested, + DYN_RANGE_MEASUREMENT_REQUEST_TYPE dynamicRangeMeasurementType, + int albumMode, int* pPeakToAveragePresent, FIXP_DBL* pPeakToAverage) { + int i; + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + int drcSetId = fMax(0, pInst->drcSetId); + + *pPeakToAveragePresent = 0; + + if (albumMode) { + for (i = 0; i < hLoudnessInfoSet->loudnessInfoAlbumCount; i++) { + LOUDNESS_INFO* pLoudnessInfo = &(hLoudnessInfoSet->loudnessInfoAlbum[i]); + + if (drcSetId == pLoudnessInfo->drcSetId) { + if (downmixIdRequested == pLoudnessInfo->downmixId) { + retVal = _extractLoudnessPeakToAverageValue( + pLoudnessInfo, dynamicRangeMeasurementType, pPeakToAveragePresent, + pPeakToAverage); + if (retVal) return (retVal); + } + } + } + } + + if (*pPeakToAveragePresent == 0) { + for (i = 0; i < hLoudnessInfoSet->loudnessInfoCount; i++) { + LOUDNESS_INFO* pLoudnessInfo = &(hLoudnessInfoSet->loudnessInfo[i]); + + if (drcSetId == pLoudnessInfo->drcSetId) { + if (downmixIdRequested == pLoudnessInfo->downmixId) { + retVal = _extractLoudnessPeakToAverageValue( + pLoudnessInfo, dynamicRangeMeasurementType, pPeakToAveragePresent, + pPeakToAverage); + if (retVal) return (retVal); + } + } + } + } + + return retVal; +} +/*******************************************/ + +static DRCDEC_SELECTION_DATA* _drcdec_selection_addNew( + DRCDEC_SELECTION* pSelection) { + if (pSelection->numData < (12 + 1 + 6)) { + DRCDEC_SELECTION_DATA* pData = &(pSelection->data[pSelection->numData]); + FDKmemset(pData, 0, sizeof(DRCDEC_SELECTION_DATA)); + pSelection->numData++; + + return pData; + } else { + return NULL; + } +} + +static DRCDEC_SELECTION_DATA* _drcdec_selection_add( + DRCDEC_SELECTION* pSelection, DRCDEC_SELECTION_DATA* pDataIn) { + if (pSelection->numData < (12 + 1 + 6)) { + DRCDEC_SELECTION_DATA* pData = &(pSelection->data[pSelection->numData]); + FDKmemcpy(pData, pDataIn, sizeof(DRCDEC_SELECTION_DATA)); + pSelection->numData++; + return pData; + } else { + return NULL; + } +} + +static int _drcdec_selection_clear(DRCDEC_SELECTION* pSelection) { + return pSelection->numData = 0; +} + +static int _drcdec_selection_getNumber(DRCDEC_SELECTION* pSelection) { + return pSelection->numData; +} + +static int _drcdec_selection_setNumber(DRCDEC_SELECTION* pSelection, int num) { + if (num >= 0 && num < pSelection->numData) { + return pSelection->numData = num; + } else { + return pSelection->numData; + } +} + +static DRCDEC_SELECTION_DATA* _drcdec_selection_getAt( + DRCDEC_SELECTION* pSelection, int at) { + if (at >= 0 && at < (12 + 1 + 6)) { + return &(pSelection->data[at]); + } else { + return NULL; + } +} + +static int _swapSelectionAndClear(DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected) { + DRCDEC_SELECTION* pTmp = *ppCandidatesPotential; + *ppCandidatesPotential = *ppCandidatesSelected; + *ppCandidatesSelected = pTmp; + _drcdec_selection_clear(*ppCandidatesSelected); + return 0; +} + +static int _swapSelection(DRCDEC_SELECTION** ppCandidatesPotential, + DRCDEC_SELECTION** ppCandidatesSelected) { + DRCDEC_SELECTION* pTmp = *ppCandidatesPotential; + *ppCandidatesPotential = *ppCandidatesSelected; + *ppCandidatesSelected = pTmp; + return 0; +} + +/*******************************************/ + +static LOUDNESS_INFO* _getLoudnessInfoStructure( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int drcSetId, int downmixId, + int albumMode) { + int i, j; + int count; + + LOUDNESS_INFO* pLoudnessInfo = NULL; + + if (albumMode) { + count = hLoudnessInfoSet->loudnessInfoAlbumCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum; + } else { + count = hLoudnessInfoSet->loudnessInfoCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfo; + } + + for (i = 0; i < count; i++) { + if ((pLoudnessInfo[i].drcSetId == drcSetId) && + (pLoudnessInfo[i].downmixId == downmixId)) { + for (j = 0; j < pLoudnessInfo[i].measurementCount; j++) { + if ((pLoudnessInfo[i].loudnessMeasurement[j].methodDefinition == 1) || + (pLoudnessInfo[i].loudnessMeasurement[j].methodDefinition == 2)) { + return &pLoudnessInfo[i]; + } + } + } + } + + return NULL; +} + +static LOUDNESS_INFO* _getApplicableLoudnessInfoStructure( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int drcSetId, + int downmixIdRequested, int albumMode) { + LOUDNESS_INFO* pLoudnessInfo = NULL; + + /* default value */ + pLoudnessInfo = _getLoudnessInfoStructure(hLoudnessInfoSet, drcSetId, + downmixIdRequested, albumMode); + + /* fallback values */ + if (pLoudnessInfo == NULL) { + pLoudnessInfo = + _getLoudnessInfoStructure(hLoudnessInfoSet, drcSetId, 0x7F, albumMode); + } + + if (pLoudnessInfo == NULL) { + pLoudnessInfo = _getLoudnessInfoStructure(hLoudnessInfoSet, 0x3F, + downmixIdRequested, albumMode); + } + + if (pLoudnessInfo == NULL) { + pLoudnessInfo = _getLoudnessInfoStructure(hLoudnessInfoSet, 0, + downmixIdRequested, albumMode); + } + + if (pLoudnessInfo == NULL) { + pLoudnessInfo = + _getLoudnessInfoStructure(hLoudnessInfoSet, 0x3F, 0x7F, albumMode); + } + + if (pLoudnessInfo == NULL) { + pLoudnessInfo = + _getLoudnessInfoStructure(hLoudnessInfoSet, 0, 0x7F, albumMode); + } + + if (pLoudnessInfo == NULL) { + pLoudnessInfo = + _getLoudnessInfoStructure(hLoudnessInfoSet, drcSetId, 0, albumMode); + } + + if (pLoudnessInfo == NULL) { + pLoudnessInfo = + _getLoudnessInfoStructure(hLoudnessInfoSet, 0x3F, 0, albumMode); + } + + if (pLoudnessInfo == NULL) { + pLoudnessInfo = + _getLoudnessInfoStructure(hLoudnessInfoSet, 0, 0, albumMode); + } + + return pLoudnessInfo; +} + +/*******************************************/ + +typedef struct { + FIXP_DBL value; + int order; +} VALUE_ORDER; + +void _initValueOrder(VALUE_ORDER* pValue) { + pValue->value = (FIXP_DBL)0; + pValue->order = -1; +} + +enum { + MS_BONUS0 = 0, + MS_BONUS1770, + MS_BONUSUSER, + MS_BONUSEXPERT, + MS_RESA, + MS_RESB, + MS_RESC, + MS_RESD, + MS_RESE, + MS_PROGRAMLOUDNESS, + MS_PEAKLOUDNESS +}; + +static DRCDEC_SELECTION_PROCESS_RETURN _getMethodValue( + VALUE_ORDER* pValueOrder, FIXP_DBL value, int measurementSystem, + int measurementSystemRequested) { + const int rows = 11; + const int columns = 12; + const int pOrdering[rows][columns] = { + {0, 0, 8, 0, 1, 3, 0, 5, 6, 7, 4, 2}, /* default = bonus1770 */ + {0, 0, 8, 0, 1, 3, 0, 5, 6, 7, 4, 2}, /* bonus1770 */ + {0, 0, 1, 0, 8, 5, 0, 2, 3, 4, 6, 7}, /* bonusUser */ + {0, 0, 3, 0, 1, 8, 0, 4, 5, 6, 7, 2}, /* bonusExpert */ + {0, 0, 5, 0, 1, 3, 0, 8, 6, 7, 4, 2}, /* ResA */ + {0, 0, 5, 0, 1, 3, 0, 6, 8, 7, 4, 2}, /* ResB */ + {0, 0, 5, 0, 1, 3, 0, 6, 7, 8, 4, 2}, /* ResC */ + {0, 0, 3, 0, 1, 7, 0, 4, 5, 6, 8, 2}, /* ResD */ + {0, 0, 1, 0, 7, 5, 0, 2, 3, 4, 6, 8}, /* ResE */ + {0, 0, 1, 0, 0, 0, 0, 2, 3, 4, 0, 0}, /* ProgramLoudness */ + {0, 7, 0, 0, 0, 0, 6, 5, 4, 3, 2, 1} /* PeakLoudness */ + }; + + if (measurementSystemRequested < 0 || measurementSystemRequested >= rows || + measurementSystem < 0 || measurementSystem >= columns) { + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + if (pOrdering[measurementSystemRequested][measurementSystem] > + pValueOrder->order) { + pValueOrder->order = + pOrdering[measurementSystemRequested][measurementSystem]; + pValueOrder->value = value; + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/*******************************************/ + +static DRCDEC_SELECTION_PROCESS_RETURN _getLoudness( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int albumMode, + METHOD_DEFINITION_REQUEST measurementMethodRequested, + MEASUREMENT_SYSTEM_REQUEST measurementSystemRequested, + FIXP_DBL targetLoudness, /* e = 7 */ + int drcSetId, int downmixIdRequested, + FIXP_DBL* pLoudnessNormalizationGain, /* e = 7 */ + FIXP_DBL* pLoudness) /* e = 7 */ +{ + int index; + + LOUDNESS_INFO* pLoudnessInfo = NULL; + VALUE_ORDER valueOrder; + + /* map MDR_DEFAULT to MDR_PROGRAM_LOUDNESS */ + METHOD_DEFINITION_REQUEST requestedMethodDefinition = + measurementMethodRequested < MDR_ANCHOR_LOUDNESS ? MDR_PROGRAM_LOUDNESS + : MDR_ANCHOR_LOUDNESS; + + if (measurementMethodRequested > MDR_ANCHOR_LOUDNESS) { + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + + _initValueOrder(&valueOrder); + + *pLoudness = UNDEFINED_LOUDNESS_VALUE; + *pLoudnessNormalizationGain = (FIXP_DBL)0; + + if (drcSetId < 0) { + drcSetId = 0; + } + + pLoudnessInfo = _getApplicableLoudnessInfoStructure( + hLoudnessInfoSet, drcSetId, downmixIdRequested, albumMode); + + if (albumMode && (pLoudnessInfo == NULL)) { + pLoudnessInfo = _getApplicableLoudnessInfoStructure( + hLoudnessInfoSet, drcSetId, downmixIdRequested, 0); + } + + if (pLoudnessInfo == NULL) { + return DRCDEC_SELECTION_PROCESS_NO_ERROR; + } + + index = -1; + + do { + index = _findMethodDefinition(pLoudnessInfo, requestedMethodDefinition, + index + 1); + + if (index >= 0) { + _getMethodValue( + &valueOrder, pLoudnessInfo->loudnessMeasurement[index].methodValue, + pLoudnessInfo->loudnessMeasurement[index].measurementSystem, + measurementSystemRequested); + } + } while (index >= 0); + + /* repeat with other method definition */ + if (valueOrder.order == -1) { + index = -1; + + do { + index = _findMethodDefinition( + pLoudnessInfo, + requestedMethodDefinition == MDR_PROGRAM_LOUDNESS + ? MDR_ANCHOR_LOUDNESS + : MDR_PROGRAM_LOUDNESS, + index + 1); + + if (index >= 0) { + _getMethodValue( + &valueOrder, pLoudnessInfo->loudnessMeasurement[index].methodValue, + pLoudnessInfo->loudnessMeasurement[index].measurementSystem, + measurementSystemRequested); + } + } while (index >= 0); + } + + if (valueOrder.order == -1) { + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } else { + *pLoudnessNormalizationGain = targetLoudness - valueOrder.value; + *pLoudness = valueOrder.value; + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/*******************************************/ + +static int _truePeakLevelIsPresent(HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + int drcSetId, int downmixId, int albumMode) { + int i; + int count; + LOUDNESS_INFO* pLoudnessInfo = NULL; + + if (albumMode) { + count = hLoudnessInfoSet->loudnessInfoAlbumCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum; + } else { + count = hLoudnessInfoSet->loudnessInfoCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfo; + } + + for (i = 0; i < count; i++) { + if ((pLoudnessInfo[i].drcSetId == drcSetId) && + (pLoudnessInfo[i].downmixId == downmixId)) { + if (pLoudnessInfo[i].truePeakLevelPresent) return 1; + } + } + + return 0; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _getTruePeakLevel( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int drcSetId, int downmixId, + int albumMode, FIXP_DBL* pTruePeakLevel) { + int i; + int count; + LOUDNESS_INFO* pLoudnessInfo = NULL; + + if (albumMode) { + count = hLoudnessInfoSet->loudnessInfoAlbumCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum; + } else { + count = hLoudnessInfoSet->loudnessInfoCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfo; + } + + for (i = 0; i < count; i++) { + if ((pLoudnessInfo[i].drcSetId == drcSetId) && + (pLoudnessInfo[i].downmixId == downmixId)) { + if (pLoudnessInfo[i].truePeakLevelPresent) { + *pTruePeakLevel = pLoudnessInfo[i].truePeakLevel; + return DRCDEC_SELECTION_PROCESS_NO_ERROR; + } + } + } + + return DRCDEC_SELECTION_PROCESS_NOT_OK; +} + +static int _samplePeakLevelIsPresent(HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + int drcSetId, int downmixId, + int albumMode) { + int i; + int count; + LOUDNESS_INFO* pLoudnessInfo = NULL; + + if (albumMode) { + count = hLoudnessInfoSet->loudnessInfoAlbumCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum; + } else { + count = hLoudnessInfoSet->loudnessInfoCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfo; + } + + for (i = 0; i < count; i++) { + if ((pLoudnessInfo[i].drcSetId == drcSetId) && + (pLoudnessInfo[i].downmixId == downmixId)) { + if (pLoudnessInfo[i].samplePeakLevelPresent) return 1; + } + } + + return 0; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _getSamplePeakLevel( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int drcSetId, int downmixId, + int albumMode, FIXP_DBL* pSamplePeakLevel /* e = 7 */ +) { + int i; + int count; + LOUDNESS_INFO* pLoudnessInfo = NULL; + + if (albumMode) { + count = hLoudnessInfoSet->loudnessInfoAlbumCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum; + } else { + count = hLoudnessInfoSet->loudnessInfoCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfo; + } + + for (i = 0; i < count; i++) { + if ((pLoudnessInfo[i].drcSetId == drcSetId) && + (pLoudnessInfo[i].downmixId == downmixId)) { + if (pLoudnessInfo[i].samplePeakLevelPresent) { + *pSamplePeakLevel = pLoudnessInfo[i].samplePeakLevel; + return DRCDEC_SELECTION_PROCESS_NO_ERROR; + } + } + } + + return DRCDEC_SELECTION_PROCESS_NOT_OK; +} + +static int _limiterPeakTargetIsPresent( + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction, int drcSetId, int downmixId) { + int i; + + if (pDrcInstruction->limiterPeakTargetPresent) { + if ((pDrcInstruction->downmixId[0] == downmixId) || + (pDrcInstruction->downmixId[0] == 0x7F)) { + return 1; + } + + for (i = 0; i < pDrcInstruction->downmixIdCount; i++) { + if (pDrcInstruction->downmixId[i] == downmixId) { + return 1; + } + } + } + + return 0; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _getLimiterPeakTarget( + DRC_INSTRUCTIONS_UNI_DRC* pDrcInstruction, int drcSetId, int downmixId, + FIXP_DBL* pLimiterPeakTarget) { + int i; + + if (pDrcInstruction->limiterPeakTargetPresent) { + if ((pDrcInstruction->downmixId[0] == downmixId) || + (pDrcInstruction->downmixId[0] == 0x7F)) { + *pLimiterPeakTarget = + ((FX_SGL2FX_DBL(pDrcInstruction->limiterPeakTarget) >> 2)); + return DRCDEC_SELECTION_PROCESS_NO_ERROR; + } + + for (i = 0; i < pDrcInstruction->downmixIdCount; i++) { + if (pDrcInstruction->downmixId[i] == downmixId) { + *pLimiterPeakTarget = + ((FX_SGL2FX_DBL(pDrcInstruction->limiterPeakTarget) >> 2)); + return DRCDEC_SELECTION_PROCESS_NO_ERROR; + } + } + } + + return DRCDEC_SELECTION_PROCESS_NOT_OK; +} + +static int _downmixCoefficientsArePresent(HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + int downmixId, int* pIndex) { + int i; + *pIndex = -1; + + for (i = 0; i < hUniDrcConfig->downmixInstructionsCount; i++) { + if (hUniDrcConfig->downmixInstructions[i].downmixId == downmixId) { + if (hUniDrcConfig->downmixInstructions[i].downmixCoefficientsPresent) { + *pIndex = i; + return 1; + } + } + } + + return 0; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _getSignalPeakLevel( + HANDLE_SEL_PROC_INPUT hSelProcInput, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, DRC_INSTRUCTIONS_UNI_DRC* pInst, + int downmixIdRequested, int* explicitPeakInformationPresent, + FIXP_DBL* signalPeakLevelOut, /* e = 7 */ + SEL_PROC_CODEC_MODE codecMode + +) { + DRCDEC_SELECTION_PROCESS_RETURN retVal = DRCDEC_SELECTION_PROCESS_NO_ERROR; + + int albumMode = hSelProcInput->albumMode; + + FIXP_DBL signalPeakLevelTmp = (FIXP_DBL)0; + FIXP_DBL signalPeakLevel = FIXP_DBL(0); + + int dmxId = downmixIdRequested; + + int drcSetId = pInst->drcSetId; + + if (drcSetId < 0) { + drcSetId = 0; + } + + *explicitPeakInformationPresent = 1; + + if (_truePeakLevelIsPresent(hLoudnessInfoSet, drcSetId, dmxId, albumMode)) { + retVal = _getTruePeakLevel(hLoudnessInfoSet, drcSetId, dmxId, albumMode, + &signalPeakLevel); + if (retVal) return (retVal); + } else if (_samplePeakLevelIsPresent(hLoudnessInfoSet, drcSetId, dmxId, + albumMode)) { + retVal = _getSamplePeakLevel(hLoudnessInfoSet, drcSetId, dmxId, albumMode, + &signalPeakLevel); + if (retVal) return (retVal); + } else if (_truePeakLevelIsPresent(hLoudnessInfoSet, 0x3F, dmxId, + albumMode)) { + retVal = _getTruePeakLevel(hLoudnessInfoSet, 0x3F, dmxId, albumMode, + &signalPeakLevel); + if (retVal) return (retVal); + } else if (_samplePeakLevelIsPresent(hLoudnessInfoSet, 0x3F, dmxId, + albumMode)) { + retVal = _getSamplePeakLevel(hLoudnessInfoSet, 0x3F, dmxId, albumMode, + &signalPeakLevel); + if (retVal) return (retVal); + } else if (_limiterPeakTargetIsPresent(pInst, drcSetId, dmxId)) { + retVal = _getLimiterPeakTarget(pInst, drcSetId, dmxId, &signalPeakLevel); + if (retVal) return (retVal); + } else if (dmxId != 0) { + int downmixInstructionIndex = 0; + FIXP_DBL downmixPeakLevelDB = 0; + + *explicitPeakInformationPresent = 0; + + signalPeakLevelTmp = FIXP_DBL(0); + + if (_downmixCoefficientsArePresent(hUniDrcConfig, dmxId, + &downmixInstructionIndex)) { + FIXP_DBL dB_m; + int dB_e; + FIXP_DBL coeff; + FIXP_DBL sum, maxSum; /* e = 7, so it is possible to sum up up to 32 + downmix coefficients (with e = 2) */ + int i, j; + DOWNMIX_INSTRUCTIONS* pDown = + &(hUniDrcConfig->downmixInstructions[downmixInstructionIndex]); + FIXP_DBL downmixOffset = getDownmixOffset( + pDown, hUniDrcConfig->channelLayout.baseChannelCount); /* e = 1 */ + maxSum = (FIXP_DBL)0; + + for (i = 0; i < pDown->targetChannelCount; i++) { + sum = (FIXP_DBL)0; + for (j = 0; j < hUniDrcConfig->channelLayout.baseChannelCount; j++) { + coeff = pDown->downmixCoefficient[j + i * hUniDrcConfig->channelLayout + .baseChannelCount]; + sum += coeff >> 5; + } + if (maxSum < sum) maxSum = sum; + } + + maxSum = fMultDiv2(maxSum, downmixOffset) << 2; + + if (maxSum == FL2FXCONST_DBL(1.0f / (float)(1 << 7))) { + downmixPeakLevelDB = (FIXP_DBL)0; + } else { + dB_m = lin2dB(maxSum, 7, &dB_e); /* e_maxSum = 7 */ + downmixPeakLevelDB = + scaleValue(dB_m, dB_e - 7); /* e_downmixPeakLevelDB = 7 */ + } + } + + if (_truePeakLevelIsPresent(hLoudnessInfoSet, drcSetId, 0, albumMode)) { + retVal = _getTruePeakLevel(hLoudnessInfoSet, drcSetId, 0, albumMode, + &signalPeakLevelTmp); + if (retVal) return (retVal); + } else if (_samplePeakLevelIsPresent(hLoudnessInfoSet, drcSetId, 0, + albumMode)) { + retVal = _getSamplePeakLevel(hLoudnessInfoSet, drcSetId, 0, albumMode, + &signalPeakLevelTmp); + if (retVal) return (retVal); + } else if (_truePeakLevelIsPresent(hLoudnessInfoSet, 0x3F, 0, albumMode)) { + retVal = _getTruePeakLevel(hLoudnessInfoSet, 0x3F, 0, albumMode, + &signalPeakLevelTmp); + if (retVal) return (retVal); + } else if (_samplePeakLevelIsPresent(hLoudnessInfoSet, 0x3F, 0, + albumMode)) { + retVal = _getSamplePeakLevel(hLoudnessInfoSet, 0x3F, 0, albumMode, + &signalPeakLevelTmp); + if (retVal) return (retVal); + } else if (_limiterPeakTargetIsPresent(pInst, drcSetId, 0)) { + retVal = _getLimiterPeakTarget(pInst, drcSetId, 0, &signalPeakLevelTmp); + if (retVal) return (retVal); + } + + signalPeakLevel = signalPeakLevelTmp + downmixPeakLevelDB; + } else { + signalPeakLevel = FIXP_DBL(0); /* worst case estimate */ + *explicitPeakInformationPresent = FIXP_DBL(0); + } + + *signalPeakLevelOut = signalPeakLevel; + + return retVal; +} + +static DRCDEC_SELECTION_PROCESS_RETURN _extractLoudnessPeakToAverageValue( + LOUDNESS_INFO* loudnessInfo, + DYN_RANGE_MEASUREMENT_REQUEST_TYPE dynamicRangeMeasurementType, + int* pLoudnessPeakToAverageValuePresent, + FIXP_DBL* pLoudnessPeakToAverageValue) { + int i; + + VALUE_ORDER valueOrderLoudness; + VALUE_ORDER valueOrderPeakLoudness; + + _initValueOrder(&valueOrderLoudness); + _initValueOrder(&valueOrderPeakLoudness); + + LOUDNESS_MEASUREMENT* pLoudnessMeasure = NULL; + + *pLoudnessPeakToAverageValuePresent = 0; + + for (i = 0; i < loudnessInfo->measurementCount; i++) { + pLoudnessMeasure = &(loudnessInfo->loudnessMeasurement[i]); + + if (pLoudnessMeasure->methodDefinition == MD_PROGRAM_LOUDNESS) { + _getMethodValue(&valueOrderLoudness, pLoudnessMeasure->methodValue, + pLoudnessMeasure->measurementSystem, MS_PROGRAMLOUDNESS); + } + + if ((dynamicRangeMeasurementType == DRMRT_SHORT_TERM_LOUDNESS_TO_AVG) && + (pLoudnessMeasure->methodDefinition == MD_SHORT_TERM_LOUDNESS_MAX)) { + _getMethodValue(&valueOrderPeakLoudness, pLoudnessMeasure->methodValue, + pLoudnessMeasure->measurementSystem, MS_PEAKLOUDNESS); + } + + if ((dynamicRangeMeasurementType == DRMRT_MOMENTARY_LOUDNESS_TO_AVG) && + (pLoudnessMeasure->methodDefinition == MD_MOMENTARY_LOUDNESS_MAX)) { + _getMethodValue(&valueOrderPeakLoudness, pLoudnessMeasure->methodValue, + pLoudnessMeasure->measurementSystem, MS_PEAKLOUDNESS); + } + + if ((dynamicRangeMeasurementType == DRMRT_TOP_OF_LOUDNESS_RANGE_TO_AVG) && + (pLoudnessMeasure->methodDefinition == MD_MAX_OF_LOUDNESS_RANGE)) { + _getMethodValue(&valueOrderPeakLoudness, pLoudnessMeasure->methodValue, + pLoudnessMeasure->measurementSystem, MS_PEAKLOUDNESS); + } + } + + if ((valueOrderLoudness.order > -1) && (valueOrderPeakLoudness.order > -1)) { + *pLoudnessPeakToAverageValue = + valueOrderPeakLoudness.value - valueOrderLoudness.value; + *pLoudnessPeakToAverageValuePresent = 1; + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/*******************************************/ + +static DRCDEC_SELECTION_PROCESS_RETURN _selectAlbumLoudness( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + DRCDEC_SELECTION* pCandidatesPotential, + DRCDEC_SELECTION* pCandidatesSelected) { + int i, j; + + for (i = 0; i < _drcdec_selection_getNumber(pCandidatesPotential); i++) { + DRCDEC_SELECTION_DATA* pCandidate = + _drcdec_selection_getAt(pCandidatesPotential, i); + if (pCandidate == NULL) return DRCDEC_SELECTION_PROCESS_NOT_OK; + + for (j = 0; j < hLoudnessInfoSet->loudnessInfoAlbumCount; j++) { + if (pCandidate->pInst->drcSetId == + hLoudnessInfoSet->loudnessInfoAlbum[j].drcSetId) { + if (_drcdec_selection_add(pCandidatesSelected, pCandidate) == NULL) + return DRCDEC_SELECTION_PROCESS_NOT_OK; + } + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/*******************************************/ + +static int _findMethodDefinition(LOUDNESS_INFO* pLoudnessInfo, + int methodDefinition, int startIndex) { + int i; + int index = -1; + + for (i = startIndex; i < pLoudnessInfo->measurementCount; i++) { + if (pLoudnessInfo->loudnessMeasurement[i].methodDefinition == + methodDefinition) { + index = i; + break; + } + } + + return index; +} + +/*******************************************/ + +static DRCDEC_SELECTION_PROCESS_RETURN _getMixingLevel( + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, int downmixIdRequested, + int drcSetIdRequested, int albumMode, FIXP_DBL* pMixingLevel) { + const FIXP_DBL mixingLevelDefault = FL2FXCONST_DBL(85.0f / (float)(1 << 7)); + + int i; + int count; + + LOUDNESS_INFO* pLoudnessInfo = NULL; + + *pMixingLevel = mixingLevelDefault; + + if (drcSetIdRequested < 0) { + drcSetIdRequested = 0; + } + + if (albumMode) { + count = hLoudnessInfoSet->loudnessInfoAlbumCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfoAlbum; + } else { + count = hLoudnessInfoSet->loudnessInfoCount; + pLoudnessInfo = hLoudnessInfoSet->loudnessInfo; + } + + for (i = 0; i < count; i++) { + if ((drcSetIdRequested == pLoudnessInfo[i].drcSetId) && + ((downmixIdRequested == pLoudnessInfo[i].downmixId) || + (DOWNMIX_ID_ANY_DOWNMIX == pLoudnessInfo[i].downmixId))) { + int index = _findMethodDefinition(&pLoudnessInfo[i], MD_MIXING_LEVEL, 0); + + if (index >= 0) { + *pMixingLevel = pLoudnessInfo[i].loudnessMeasurement[index].methodValue; + break; + } + } + } + + return DRCDEC_SELECTION_PROCESS_NO_ERROR; +} + +/*******************************************/ diff --git a/libDRCdec/src/drcDec_selectionProcess.h b/libDRCdec/src/drcDec_selectionProcess.h new file mode 100644 index 0000000..9e0e3fb --- /dev/null +++ b/libDRCdec/src/drcDec_selectionProcess.h @@ -0,0 +1,217 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): Andreas Hoelzer + + Description: DRC Set Selection + +*******************************************************************************/ + +#ifndef DRCDEC_SELECTIONPROCESS_H +#define DRCDEC_SELECTIONPROCESS_H + +#include "drcDec_types.h" +#include "drcDecoder.h" + +/* DRC set selection according to section 6.2 of ISO/IEC 23003-4 (MPEG-D DRC) */ +/* including ISO/IEC 23003-4/AMD1 (Amendment 1) */ + +typedef struct s_drcdec_selection_process* HANDLE_DRC_SELECTION_PROCESS; + +typedef enum { + DRCDEC_SELECTION_PROCESS_NO_ERROR = 0, + + DRCDEC_SELECTION_PROCESS_WARNING = -1000, + + DRCDEC_SELECTION_PROCESS_NOT_OK = -2000, + DRCDEC_SELECTION_PROCESS_OUTOFMEMORY, + DRCDEC_SELECTION_PROCESS_INVALID_HANDLE, + DRCDEC_SELECTION_PROCESS_NOT_SUPPORTED, + DRCDEC_SELECTION_PROCESS_INVALID_PARAM, + DRCDEC_SELECTION_PROCESS_PARAM_OUT_OF_RANGE + +} DRCDEC_SELECTION_PROCESS_RETURN; + +typedef enum { + SEL_PROC_TEST_TIME_DOMAIN = -100, + SEL_PROC_TEST_QMF_DOMAIN, + SEL_PROC_TEST_STFT_DOMAIN, + + SEL_PROC_CODEC_MODE_UNDEFINED = -1, + SEL_PROC_MPEG_4_AAC, + SEL_PROC_MPEG_D_USAC, + SEL_PROC_MPEG_H_3DA +} SEL_PROC_CODEC_MODE; + +typedef enum { + /* set and get user param */ + SEL_PROC_LOUDNESS_NORMALIZATION_ON, + /* get only user param */ + SEL_PROC_DYNAMIC_RANGE_CONTROL_ON, + /* set only user params */ + SEL_PROC_TARGET_LOUDNESS, + SEL_PROC_EFFECT_TYPE, + SEL_PROC_EFFECT_TYPE_FALLBACK_CODE, + SEL_PROC_LOUDNESS_MEASUREMENT_METHOD, + SEL_PROC_DOWNMIX_ID, + SEL_PROC_TARGET_LAYOUT, + SEL_PROC_TARGET_CHANNEL_COUNT, + SEL_PROC_BASE_CHANNEL_COUNT, + SEL_PROC_SAMPLE_RATE, + SEL_PROC_BOOST, + SEL_PROC_COMPRESS +} SEL_PROC_USER_PARAM; + +typedef struct s_selection_process_output { + FIXP_DBL outputPeakLevelDb; /* e = 7 */ + FIXP_DBL loudnessNormalizationGainDb; /* e = 7 */ + FIXP_DBL outputLoudness; /* e = 7 */ + + UCHAR numSelectedDrcSets; + SCHAR selectedDrcSetIds[MAX_ACTIVE_DRCS]; + UCHAR selectedDownmixIds[MAX_ACTIVE_DRCS]; + + UCHAR activeDownmixId; + UCHAR baseChannelCount; + UCHAR targetChannelCount; + SCHAR targetLayout; + UCHAR downmixMatrixPresent; + FIXP_DBL downmixMatrix[8][8]; /* e = 2 */ + + FIXP_SGL boost; /* e = 1 */ + FIXP_SGL compress; /* e = 1 */ + + FIXP_DBL mixingLevel; /* e = 7 */ + +} SEL_PROC_OUTPUT, *HANDLE_SEL_PROC_OUTPUT; + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_Create(HANDLE_DRC_SELECTION_PROCESS* phInstance); + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_Delete(HANDLE_DRC_SELECTION_PROCESS* phInstance); + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_Init(HANDLE_DRC_SELECTION_PROCESS hInstance); + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_SetCodecMode(HANDLE_DRC_SELECTION_PROCESS hInstance, + const SEL_PROC_CODEC_MODE codecMode); + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_SetParam(HANDLE_DRC_SELECTION_PROCESS hInstance, + const SEL_PROC_USER_PARAM requestType, + FIXP_DBL requestValue, int* pDiff); + +FIXP_DBL +drcDec_SelectionProcess_GetParam(HANDLE_DRC_SELECTION_PROCESS hInstance, + const SEL_PROC_USER_PARAM requestType); + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_SetMpeghParams( + HANDLE_DRC_SELECTION_PROCESS hInstance, const int numGroupIdsRequested, + const int* groupIdRequested, const int numGroupPresetIdsRequested, + const int* groupPresetIdRequested, + const int* numMembersGroupPresetIdsRequested, + const int groupPresetIdRequestedPreference, int* pDiff); + +DRCDEC_SELECTION_PROCESS_RETURN +drcDec_SelectionProcess_Process(HANDLE_DRC_SELECTION_PROCESS hInstance, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + HANDLE_LOUDNESS_INFO_SET hLoudnessInfoSet, + HANDLE_SEL_PROC_OUTPUT hSelProcOutput); + +#endif diff --git a/libDRCdec/src/drcDec_tools.cpp b/libDRCdec/src/drcDec_tools.cpp new file mode 100644 index 0000000..9a6feb1 --- /dev/null +++ b/libDRCdec/src/drcDec_tools.cpp @@ -0,0 +1,371 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "drcDec_types.h" +#include "drcDec_tools.h" +#include "fixpoint_math.h" +#include "drcDecoder.h" + +int getDeltaTmin(const int sampleRate) { + /* half_ms = round (0.0005 * sampleRate); */ + int half_ms = (sampleRate + 1000) / 2000; + int deltaTmin = 1; + if (sampleRate < 1000) { + return DE_NOT_OK; + } + while (deltaTmin <= half_ms) { + deltaTmin = deltaTmin << 1; + } + return deltaTmin; +} + +DRC_COEFFICIENTS_UNI_DRC* selectDrcCoefficients( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, const int location) { + int n; + int c = -1; + for (n = 0; n < hUniDrcConfig->drcCoefficientsUniDrcCount; n++) { + if (hUniDrcConfig->drcCoefficientsUniDrc[n].drcLocation == location) { + c = n; + } + } + if (c >= 0) { + return &(hUniDrcConfig->drcCoefficientsUniDrc[c]); + } + return NULL; /* possible during bitstream parsing */ +} + +DRC_INSTRUCTIONS_UNI_DRC* selectDrcInstructions( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, const int drcSetId) { + int i; + for (i = 0; i < hUniDrcConfig->drcInstructionsCountInclVirtual; i++) { + if (hUniDrcConfig->drcInstructionsUniDrc[i].drcSetId == drcSetId) { + return &(hUniDrcConfig->drcInstructionsUniDrc[i]); + } + } + return NULL; +} + +DOWNMIX_INSTRUCTIONS* selectDownmixInstructions( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, const int downmixId) { + int i; + for (i = 0; i < hUniDrcConfig->downmixInstructionsCount; i++) { + if (hUniDrcConfig->downmixInstructions[i].downmixId == downmixId) { + return &(hUniDrcConfig->downmixInstructions[i]); + } + } + return NULL; +} + +DRC_ERROR +deriveDrcChannelGroups( + const int drcSetEffect, /* in */ + const int channelCount, /* in */ + const SCHAR* gainSetIndex, /* in */ + const DUCKING_MODIFICATION* duckingModificationForChannel, /* in */ + UCHAR* nDrcChannelGroups, /* out */ + SCHAR* uniqueIndex, /* out (gainSetIndexForChannelGroup) */ + SCHAR* groupForChannel, /* out */ + DUCKING_MODIFICATION* duckingModificationForChannelGroup) /* out */ +{ + int duckingSequence = -1; + int c, n, g, match, idx; + FIXP_SGL factor; + FIXP_SGL uniqueScaling[8]; + + for (g = 0; g < 8; g++) { + uniqueIndex[g] = -10; + uniqueScaling[g] = FIXP_SGL(-1.0f); + } + + g = 0; + + if (drcSetEffect & EB_DUCK_OTHER) { + for (c = 0; c < channelCount; c++) { + match = 0; + if (c >= 8) return DE_MEMORY_ERROR; + idx = gainSetIndex[c]; + factor = duckingModificationForChannel[c].duckingScaling; + if (idx < 0) { + for (n = 0; n < g; n++) { + if (uniqueScaling[n] == factor) { + match = 1; + groupForChannel[c] = n; + break; + } + } + if (match == 0) { + if (g >= 8) return DE_MEMORY_ERROR; + uniqueIndex[g] = idx; + uniqueScaling[g] = factor; + groupForChannel[c] = g; + g++; + } + } else { + if ((duckingSequence > 0) && (duckingSequence != idx)) { + return DE_NOT_OK; + } + duckingSequence = idx; + groupForChannel[c] = -1; + } + } + if (duckingSequence == -1) { + return DE_NOT_OK; + } + } else if (drcSetEffect & EB_DUCK_SELF) { + for (c = 0; c < channelCount; c++) { + match = 0; + if (c >= 8) return DE_MEMORY_ERROR; + idx = gainSetIndex[c]; + factor = duckingModificationForChannel[c].duckingScaling; + if (idx >= 0) { + for (n = 0; n < g; n++) { + if ((uniqueIndex[n] == idx) && (uniqueScaling[n] == factor)) { + match = 1; + groupForChannel[c] = n; + break; + } + } + if (match == 0) { + if (g >= 8) return DE_MEMORY_ERROR; + uniqueIndex[g] = idx; + uniqueScaling[g] = factor; + groupForChannel[c] = g; + g++; + } + } else { + groupForChannel[c] = -1; + } + } + } else { /* no ducking */ + for (c = 0; c < channelCount; c++) { + if (c >= 8) return DE_MEMORY_ERROR; + idx = gainSetIndex[c]; + match = 0; + if (idx >= 0) { + for (n = 0; n < g; n++) { + if (uniqueIndex[n] == idx) { + match = 1; + groupForChannel[c] = n; + break; + } + } + if (match == 0) { + if (g >= 8) return DE_MEMORY_ERROR; + uniqueIndex[g] = idx; + groupForChannel[c] = g; + g++; + } + } else { + groupForChannel[c] = -1; + } + } + } + *nDrcChannelGroups = g; + + if (drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) { + for (g = 0; g < *nDrcChannelGroups; g++) { + if (drcSetEffect & EB_DUCK_OTHER) { + uniqueIndex[g] = duckingSequence; + } + duckingModificationForChannelGroup[g].duckingScaling = uniqueScaling[g]; + if (uniqueScaling[g] != FL2FXCONST_SGL(1.0f / (float)(1 << 2))) { + duckingModificationForChannelGroup[g].duckingScalingPresent = 1; + } else { + duckingModificationForChannelGroup[g].duckingScalingPresent = 0; + } + } + } + + return DE_OK; +} + +FIXP_DBL +dB2lin(const FIXP_DBL dB_m, const int dB_e, int* pLin_e) { + /* get linear value from dB. + return lin_val = 10^(dB_val/20) = 2^(log2(10)/20*dB_val) + with dB_val = dB_m *2^dB_e and lin_val = lin_m * 2^lin_e */ + FIXP_DBL lin_m = + f2Pow(fMult(dB_m, FL2FXCONST_DBL(0.1660964f * (float)(1 << 2))), dB_e - 2, + pLin_e); + + return lin_m; +} + +FIXP_DBL +lin2dB(const FIXP_DBL lin_m, const int lin_e, int* pDb_e) { + /* get dB value from linear value. + return dB_val = 20*log10(lin_val) + with dB_val = dB_m *2^dB_e and lin_val = lin_m * 2^lin_e */ + FIXP_DBL dB_m; + + if (lin_m == (FIXP_DBL)0) { /* return very small value representing -inf */ + dB_m = (FIXP_DBL)MINVAL_DBL; + *pDb_e = DFRACT_BITS - 1; + } else { + /* 20*log10(lin_val) = 20/log2(10)*log2(lin_val) */ + dB_m = fMultDiv2(FL2FXCONST_DBL(6.02059991f / (float)(1 << 3)), + fLog2(lin_m, lin_e, pDb_e)); + *pDb_e += 3 + 1; + } + + return dB_m; +} + +FIXP_DBL +approxDb2lin(const FIXP_DBL dB_m, const int dB_e, int* pLin_e) { + /* get linear value from approximate dB. + return lin_val = 2^(dB_val/6) + with dB_val = dB_m *2^dB_e and lin_val = lin_m * 2^lin_e */ + FIXP_DBL lin_m = + f2Pow(fMult(dB_m, FL2FXCONST_DBL(0.1666667f * (float)(1 << 2))), dB_e - 2, + pLin_e); + + return lin_m; +} + +int bitstreamContainsMultibandDrc(HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + const int downmixId) { + int i, g, d, seq; + DRC_INSTRUCTIONS_UNI_DRC* pInst; + DRC_COEFFICIENTS_UNI_DRC* pCoef = NULL; + int isMultiband = 0; + + pCoef = selectDrcCoefficients(hUniDrcConfig, LOCATION_SELECTED); + if (pCoef == NULL) return 0; + + for (i = 0; i < hUniDrcConfig->drcInstructionsUniDrcCount; i++) { + pInst = &(hUniDrcConfig->drcInstructionsUniDrc[i]); + for (d = 0; d < pInst->downmixIdCount; d++) { + if (downmixId == pInst->downmixId[d]) { + for (g = 0; g < pInst->nDrcChannelGroups; g++) { + seq = pInst->gainSetIndexForChannelGroup[g]; + if (pCoef->gainSet[seq].bandCount > 1) { + isMultiband = 1; + } + } + } + } + } + + return isMultiband; +} + +FIXP_DBL getDownmixOffset(DOWNMIX_INSTRUCTIONS* pDown, int baseChannelCount) { + FIXP_DBL downmixOffset = FL2FXCONST_DBL(1.0f / (1 << 1)); /* e = 1 */ + if ((pDown->bsDownmixOffset == 1) || (pDown->bsDownmixOffset == 2)) { + int e_a, e_downmixOffset; + FIXP_DBL a, q; + if (baseChannelCount <= pDown->targetChannelCount) return downmixOffset; + + q = fDivNorm((FIXP_DBL)pDown->targetChannelCount, + (FIXP_DBL)baseChannelCount); /* e = 0 */ + a = lin2dB(q, 0, &e_a); + if (pDown->bsDownmixOffset == 2) { + e_a += 1; /* a *= 2 */ + } + /* a = 0.5 * round (a) */ + a = fixp_round(a, e_a) >> 1; + downmixOffset = dB2lin(a, e_a, &e_downmixOffset); + downmixOffset = scaleValue(downmixOffset, e_downmixOffset - 1); + } + return downmixOffset; +} diff --git a/libDRCdec/src/drcDec_tools.h b/libDRCdec/src/drcDec_tools.h new file mode 100644 index 0000000..77a0ab7 --- /dev/null +++ b/libDRCdec/src/drcDec_tools.h @@ -0,0 +1,146 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#ifndef DRCDEC_TOOLS_H +#define DRCDEC_TOOLS_H + +#include "drcDec_types.h" +#include "drcDec_selectionProcess.h" + +int getDeltaTmin(const int sampleRate); + +DRC_COEFFICIENTS_UNI_DRC* selectDrcCoefficients( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, const int location); + +DRC_INSTRUCTIONS_UNI_DRC* selectDrcInstructions( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, const int drcSetId); + +DOWNMIX_INSTRUCTIONS* selectDownmixInstructions( + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, const int downmixId); + +DRC_ERROR +deriveDrcChannelGroups( + const int drcSetEffect, /* in */ + const int channelCount, /* in */ + const SCHAR* gainSetIndex, /* in */ + const DUCKING_MODIFICATION* duckingModificationForChannel, /* in */ + UCHAR* nDrcChannelGroups, /* out */ + SCHAR* uniqueIndex, /* out (gainSetIndexForChannelGroup) */ + SCHAR* groupForChannel, /* out */ + DUCKING_MODIFICATION* duckingModificationForChannelGroup); /* out */ + +FIXP_DBL +dB2lin(const FIXP_DBL dB_m, const int dB_e, int* pLin_e); + +FIXP_DBL +lin2dB(const FIXP_DBL lin_m, const int lin_e, int* pDb_e); + +FIXP_DBL +approxDb2lin(const FIXP_DBL dB_m, const int dB_e, int* pLin_e); + +int bitstreamContainsMultibandDrc(HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + const int downmixId); + +FIXP_DBL +getDownmixOffset(DOWNMIX_INSTRUCTIONS* pDown, int baseChannelCount); + +#endif diff --git a/libDRCdec/src/drcDec_types.h b/libDRCdec/src/drcDec_types.h new file mode 100644 index 0000000..28c17f3 --- /dev/null +++ b/libDRCdec/src/drcDec_types.h @@ -0,0 +1,428 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#ifndef DRCDEC_TYPES_H +#define DRCDEC_TYPES_H + +#include "common_fix.h" + +/* Data structures corresponding to static and dynamic DRC/Loudness payload + as defined in section 7 of MPEG-D DRC standard, ISO/IEC 23003-4 */ + +/**************/ +/* uniDrcGain */ +/**************/ + +typedef struct { + FIXP_SGL gainDb; /* e = 7 */ + SHORT time; +} GAIN_NODE; + +/* uniDrcGainExtension() (Table 56) */ +typedef struct { + UCHAR uniDrcGainExtType[8]; + ULONG extBitSize[8 - 1]; +} UNI_DRC_GAIN_EXTENSION; + +/* uniDrcGain() (Table 55) */ +typedef struct { + UCHAR nNodes[12]; /* unsaturated value, i.e. as provided in bitstream */ + GAIN_NODE gainNode[12][16]; + + UCHAR uniDrcGainExtPresent; + UNI_DRC_GAIN_EXTENSION uniDrcGainExtension; +} UNI_DRC_GAIN, *HANDLE_UNI_DRC_GAIN; + +/****************/ +/* uniDrcConfig */ +/****************/ + +typedef enum { + EB_NIGHT = 0x0001, + EB_NOISY = 0x0002, + EB_LIMITED = 0x0004, + EB_LOWLEVEL = 0x0008, + EB_DIALOG = 0x0010, + EB_GENERAL_COMPR = 0x0020, + EB_EXPAND = 0x0040, + EB_ARTISTIC = 0x0080, + EB_CLIPPING = 0x0100, + EB_FADE = 0x0200, + EB_DUCK_OTHER = 0x0400, + EB_DUCK_SELF = 0x0800 +} EFFECT_BIT; + +typedef enum { + GCP_REGULAR = 0, + GCP_FADING = 1, + GCP_CLIPPING_DUCKING = 2, + GCP_CONSTANT = 3 +} GAIN_CODING_PROFILE; + +typedef enum { GIT_SPLINE = 0, GIT_LINEAR = 1 } GAIN_INTERPOLATION_TYPE; + +typedef enum { CS_LEFT = 0, CS_RIGHT = 1 } CHARACTERISTIC_SIDE; + +typedef enum { CF_SIGMOID = 0, CF_NODES = 1 } CHARACTERISTIC_FORMAT; + +typedef enum { + GF_QMF32 = 0x1, + GF_QMFHYBRID39 = 0x2, + GF_QMF64 = 0x3, + GF_QMFHYBRID71 = 0x4, + GF_QMF128 = 0x5, + GF_QMFHYBRID135 = 0x6, + GF_UNIFORM = 0x7 +} EQ_SUBBAND_GAIN_FORMAT; + +typedef struct { + UCHAR duckingScalingPresent; + FIXP_SGL duckingScaling; /* e = 2 */ +} DUCKING_MODIFICATION; + +typedef struct { + UCHAR targetCharacteristicLeftPresent; + UCHAR targetCharacteristicLeftIndex; + UCHAR targetCharacteristicRightPresent; + UCHAR targetCharacteristicRightIndex; + UCHAR gainScalingPresent; + FIXP_SGL attenuationScaling; /* e = 2 */ + FIXP_SGL amplificationScaling; /* e = 2 */ + UCHAR gainOffsetPresent; + FIXP_SGL gainOffset; /* e = 4 */ +} GAIN_MODIFICATION; + +typedef union { + UCHAR crossoverFreqIndex; + USHORT startSubBandIndex; +} BAND_BORDER; + +typedef struct { + UCHAR left; + UCHAR right; +} CUSTOM_INDEX; + +typedef struct { + UCHAR present; + UCHAR isCICP; + union { + UCHAR cicpIndex; + CUSTOM_INDEX custom; + }; +} DRC_CHARACTERISTIC; + +typedef struct { + UCHAR gainCodingProfile; + UCHAR gainInterpolationType; + UCHAR fullFrame; + UCHAR timeAlignment; + UCHAR timeDeltaMinPresent; + USHORT timeDeltaMin; + UCHAR bandCount; + UCHAR drcBandType; + UCHAR gainSequenceIndex[4]; + DRC_CHARACTERISTIC drcCharacteristic[4]; + BAND_BORDER bandBorder[4]; +} GAIN_SET; + +typedef struct { + FIXP_SGL gain; /* e = 6 */ + FIXP_SGL ioRatio; /* e = 2 */ + FIXP_SGL exp; /* e = 5 */ + UCHAR flipSign; +} CUSTOM_DRC_CHAR_SIGMOID; + +typedef struct { + UCHAR characteristicNodeCount; + FIXP_SGL nodeLevel[4 + 1]; /* e = 7 */ + FIXP_SGL nodeGain[4 + 1]; /* e = 7 */ +} CUSTOM_DRC_CHAR_NODES; + +typedef shouldBeUnion { + CUSTOM_DRC_CHAR_SIGMOID sigmoid; + CUSTOM_DRC_CHAR_NODES nodes; +} +CUSTOM_DRC_CHAR; + +/* drcCoefficientsUniDrc() (Table 67) */ +typedef struct { + UCHAR drcLocation; + UCHAR drcFrameSizePresent; + USHORT drcFrameSize; + UCHAR characteristicLeftCount; + UCHAR characteristicLeftFormat[8]; + CUSTOM_DRC_CHAR customCharacteristicLeft[8]; + UCHAR characteristicRightCount; + UCHAR characteristicRightFormat[8]; + CUSTOM_DRC_CHAR customCharacteristicRight[8]; + UCHAR + gainSequenceCount; /* unsaturated value, i.e. as provided in bitstream */ + UCHAR gainSetCount; /* saturated to 12 */ + GAIN_SET gainSet[12]; + /* derived data */ + UCHAR gainSetIndexForGainSequence[12]; +} DRC_COEFFICIENTS_UNI_DRC; + +/* drcInstructionsUniDrc() (Table 72) */ +typedef struct { + SCHAR drcSetId; + UCHAR drcSetComplexityLevel; + UCHAR drcLocation; + UCHAR drcApplyToDownmix; + UCHAR downmixIdCount; + UCHAR downmixId[8]; + USHORT drcSetEffect; + UCHAR limiterPeakTargetPresent; + FIXP_SGL limiterPeakTarget; /* e = 5 */ + UCHAR drcSetTargetLoudnessPresent; + SCHAR drcSetTargetLoudnessValueUpper; + SCHAR drcSetTargetLoudnessValueLower; + UCHAR dependsOnDrcSetPresent; + union { + SCHAR dependsOnDrcSet; + UCHAR noIndependentUse; + }; + UCHAR requiresEq; + shouldBeUnion { + GAIN_MODIFICATION gainModificationForChannelGroup[8][4]; + DUCKING_MODIFICATION duckingModificationForChannel[8]; + }; + SCHAR gainSetIndex[8]; + + /* derived data */ + UCHAR drcChannelCount; + UCHAR nDrcChannelGroups; + SCHAR gainSetIndexForChannelGroup[8]; +} DRC_INSTRUCTIONS_UNI_DRC; + +/* channelLayout() (Table 62) */ +typedef struct { + UCHAR baseChannelCount; + UCHAR layoutSignalingPresent; + UCHAR definedLayout; + UCHAR speakerPosition[8]; +} CHANNEL_LAYOUT; + +/* downmixInstructions() (Table 63) */ +typedef struct { + UCHAR downmixId; + UCHAR targetChannelCount; + UCHAR targetLayout; + UCHAR downmixCoefficientsPresent; + UCHAR bsDownmixOffset; + FIXP_DBL downmixCoefficient[8 * 8]; /* e = 2 */ +} DOWNMIX_INSTRUCTIONS; + +typedef struct { + UCHAR uniDrcConfigExtType[8]; + ULONG extBitSize[8 - 1]; +} UNI_DRC_CONFIG_EXTENSION; + +/* uniDrcConfig() (Table 57) */ +typedef struct { + UCHAR sampleRatePresent; + ULONG sampleRate; + UCHAR downmixInstructionsCountV0; + UCHAR downmixInstructionsCountV1; + UCHAR downmixInstructionsCount; /* saturated to 6 */ + UCHAR drcCoefficientsUniDrcCountV0; + UCHAR drcCoefficientsUniDrcCountV1; + UCHAR drcCoefficientsUniDrcCount; /* saturated to 2 */ + UCHAR drcInstructionsUniDrcCountV0; + UCHAR drcInstructionsUniDrcCountV1; + UCHAR drcInstructionsUniDrcCount; /* saturated to (12 + 1 + 6) */ + CHANNEL_LAYOUT channelLayout; + DOWNMIX_INSTRUCTIONS downmixInstructions[6]; + DRC_COEFFICIENTS_UNI_DRC drcCoefficientsUniDrc[2]; + DRC_INSTRUCTIONS_UNI_DRC drcInstructionsUniDrc[(12 + 1 + 6)]; + UCHAR uniDrcConfigExtPresent; + UNI_DRC_CONFIG_EXTENSION uniDrcConfigExt; + + /* derived data */ + UCHAR drcInstructionsCountInclVirtual; + UCHAR diff; +} UNI_DRC_CONFIG, *HANDLE_UNI_DRC_CONFIG; + +/*******************/ +/* loudnessInfoSet */ +/*******************/ + +typedef enum { + MD_UNKNOWN_OTHER = 0, + MD_PROGRAM_LOUDNESS = 1, + MD_ANCHOR_LOUDNESS = 2, + MD_MAX_OF_LOUDNESS_RANGE = 3, + MD_MOMENTARY_LOUDNESS_MAX = 4, + MD_SHORT_TERM_LOUDNESS_MAX = 5, + MD_LOUDNESS_RANGE = 6, + MD_MIXING_LEVEL = 7, + MD_ROOM_TYPE = 8, + MD_SHORT_TERM_LOUDNESS = 9 +} METHOD_DEFINITION; + +typedef enum { + MS_UNKNOWN_OTHER = 0, + MS_EBU_R_128 = 1, + MS_BS_1770_4 = 2, + MS_BS_1770_4_PRE_PROCESSING = 3, + MS_USER = 4, + MS_EXPERT_PANEL = 5, + MS_BS_1771_1 = 6, + MS_RESERVED_A = 7, + MS_RESERVED_B = 8, + MS_RESERVED_C = 9, + MS_RESERVED_D = 10, + MS_RESERVED_E = 11 +} MEASUREMENT_SYSTEM; + +typedef enum { + R_UKNOWN = 0, + R_UNVERIFIED = 1, + R_CEILING = 2, + R_ACCURATE = 3 +} RELIABILITY; + +typedef struct { + UCHAR methodDefinition; + FIXP_DBL methodValue; /* e = 7 for all methodDefinitions */ + UCHAR measurementSystem; + UCHAR reliability; +} LOUDNESS_MEASUREMENT; + +/* loudnessInfo() (Table 59) */ +typedef struct { + SCHAR drcSetId; + UCHAR eqSetId; + UCHAR downmixId; + UCHAR samplePeakLevelPresent; + FIXP_DBL samplePeakLevel; /* e = 7 */ + UCHAR truePeakLevelPresent; + FIXP_DBL truePeakLevel; /* e = 7 */ + UCHAR truePeakLevelMeasurementSystem; + UCHAR truePeakLevelReliability; + UCHAR measurementCount; /* saturated to 8 */ + LOUDNESS_MEASUREMENT loudnessMeasurement[8]; +} LOUDNESS_INFO; + +/* loudnessInfoSetExtension() (Table 61) */ +typedef struct { + UCHAR loudnessInfoSetExtType[8]; + ULONG extBitSize[8 - 1]; +} LOUDNESS_INFO_SET_EXTENSION; + +/* loudnessInfoSet() (Table 58) */ +typedef struct { + UCHAR loudnessInfoAlbumCountV0; + UCHAR loudnessInfoAlbumCountV1; + UCHAR loudnessInfoAlbumCount; /* saturated to 12 */ + UCHAR loudnessInfoCountV0; + UCHAR loudnessInfoCountV1; + UCHAR loudnessInfoCount; /* saturated to 12 */ + LOUDNESS_INFO loudnessInfoAlbum[12]; + LOUDNESS_INFO loudnessInfo[12]; + UCHAR loudnessInfoSetExtPresent; + LOUDNESS_INFO_SET_EXTENSION loudnessInfoSetExt; + /* derived data */ + UCHAR diff; +} LOUDNESS_INFO_SET, *HANDLE_LOUDNESS_INFO_SET; + +#endif diff --git a/libDRCdec/src/drcDecoder.h b/libDRCdec/src/drcDecoder.h new file mode 100644 index 0000000..9826a7b --- /dev/null +++ b/libDRCdec/src/drcDecoder.h @@ -0,0 +1,142 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#ifndef DRCDECODER_H +#define DRCDECODER_H + +/* drcDecoder.h: definitions used in all submodules */ + +#define MAX_ACTIVE_DRCS 3 + +typedef enum { DM_REGULAR_DELAY = 0, DM_LOW_DELAY = 1 } DELAY_MODE; + +typedef enum { + DE_OK = 0, + DE_NOT_OK = -100, + DE_PARAM_OUT_OF_RANGE, + DE_PARAM_INVALID, + DE_MEMORY_ERROR +} DRC_ERROR; + +typedef enum { SDM_OFF, SDM_QMF64, SDM_QMF71, SDM_STFT256 } SUBBAND_DOMAIN_MODE; + +#define DOWNMIX_ID_BASE_LAYOUT 0x0 +#define DOWNMIX_ID_ANY_DOWNMIX 0x7F +#define DRC_SET_ID_NO_DRC 0x0 +#define DRC_SET_ID_ANY_DRC 0x3F + +#define LOCATION_MP4_INSTREAM_UNIDRC 0x1 +#define LOCATION_MP4_DYN_RANGE_INFO 0x2 +#define LOCATION_MP4_COMPRESSION_VALUE 0x3 +#define LOCATION_SELECTED \ + LOCATION_MP4_INSTREAM_UNIDRC /* set to location selected by system */ + +#define MAX_REQUESTS_DOWNMIX_ID 15 +#define MAX_REQUESTS_DRC_FEATURE 7 +#define MAX_REQUESTS_DRC_EFFECT_TYPE 15 + +#define DEFAULT_LOUDNESS_DEVIATION_MAX 63 + +#define DRC_INPUT_LOUDNESS_TARGET FL2FXCONST_DBL(-31.0f / (float)(1 << 7)) +#define DRC_INPUT_LOUDNESS_TARGET_SGL FL2FXCONST_SGL(-31.0f / (float)(1 << 7)) + +#endif diff --git a/libDRCdec/src/drcGainDec_init.cpp b/libDRCdec/src/drcGainDec_init.cpp new file mode 100644 index 0000000..38f3243 --- /dev/null +++ b/libDRCdec/src/drcGainDec_init.cpp @@ -0,0 +1,344 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "drcDec_types.h" +#include "drcDec_tools.h" +#include "drcDec_gainDecoder.h" +#include "drcGainDec_init.h" + +static DRC_ERROR _generateDrcInstructionsDerivedData( + HANDLE_DRC_GAIN_DECODER hGainDec, HANDLE_UNI_DRC_CONFIG hUniDrcConfig, + DRC_INSTRUCTIONS_UNI_DRC* pInst, DRC_COEFFICIENTS_UNI_DRC* pCoef, + ACTIVE_DRC* pActiveDrc) { + DRC_ERROR err = DE_OK; + int g; + int gainElementCount = 0; + UCHAR nDrcChannelGroups = 0; + SCHAR gainSetIndexForChannelGroup[8]; + + err = deriveDrcChannelGroups( + pInst->drcSetEffect, pInst->drcChannelCount, pInst->gainSetIndex, + pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF) + ? pInst->duckingModificationForChannel + : NULL, + &nDrcChannelGroups, gainSetIndexForChannelGroup, + pActiveDrc->channelGroupForChannel, + pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF) + ? pActiveDrc->duckingModificationForChannelGroup + : NULL); + if (err) return (err); + + /* sanity check */ + if (nDrcChannelGroups != pInst->nDrcChannelGroups) return DE_NOT_OK; + for (g = 0; g < pInst->nDrcChannelGroups; g++) { + if (gainSetIndexForChannelGroup[g] != pInst->gainSetIndexForChannelGroup[g]) + return DE_NOT_OK; + } + + for (g = 0; g < pInst->nDrcChannelGroups; g++) { + int seq = pInst->gainSetIndexForChannelGroup[g]; + if (seq != -1 && (hUniDrcConfig->drcCoefficientsUniDrcCount == 0 || + seq >= pCoef->gainSetCount)) { + pActiveDrc->channelGroupIsParametricDrc[g] = 1; + } else { + pActiveDrc->channelGroupIsParametricDrc[g] = 0; + if (seq >= pCoef->gainSetCount) { + return DE_NOT_OK; + } + } + } + + /* gainElementCount */ + if (pInst->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) { + for (g = 0; g < pInst->nDrcChannelGroups; g++) { + pActiveDrc->bandCountForChannelGroup[g] = 1; + } + pActiveDrc->gainElementCount = + pInst->nDrcChannelGroups; /* one gain element per channel group */ + } else { + for (g = 0; g < pInst->nDrcChannelGroups; g++) { + if (pActiveDrc->channelGroupIsParametricDrc[g]) { + gainElementCount++; + pActiveDrc->bandCountForChannelGroup[g] = 1; + } else { + int seq, bandCount; + seq = pInst->gainSetIndexForChannelGroup[g]; + bandCount = pCoef->gainSet[seq].bandCount; + pActiveDrc->bandCountForChannelGroup[g] = bandCount; + gainElementCount += bandCount; + } + } + pActiveDrc->gainElementCount = gainElementCount; + } + + /* prepare gainElementForGroup (cumulated sum of bandCountForChannelGroup) */ + pActiveDrc->gainElementForGroup[0] = 0; + for (g = 1; g < pInst->nDrcChannelGroups; g++) { + pActiveDrc->gainElementForGroup[g] = + pActiveDrc->gainElementForGroup[g - 1] + + pActiveDrc->bandCountForChannelGroup[g - 1]; /* index of first gain + sequence in channel + group */ + } + + return DE_OK; +} + +DRC_ERROR +initGainDec(HANDLE_DRC_GAIN_DECODER hGainDec, const int frameSize, + const int sampleRate) { + int i, j, k; + + if (frameSize < 1) { + return DE_NOT_OK; + } + + hGainDec->frameSize = frameSize; + + if (hGainDec->frameSize * 1000 < sampleRate) { + return DE_NOT_OK; + } + + hGainDec->deltaTminDefault = getDeltaTmin(sampleRate); + if (hGainDec->deltaTminDefault > hGainDec->frameSize) { + return DE_NOT_OK; + } + + for (i = 0; i < MAX_ACTIVE_DRCS; i++) { + for (j = 0; j < 8; j++) { + /* use startup node at the beginning */ + hGainDec->activeDrc[i].lnbIndexForChannel[j][0] = 0; + for (k = 1; k < NUM_LNB_FRAMES; k++) { + hGainDec->activeDrc[i].lnbIndexForChannel[j][k] = -1; + } + } + } + + for (j = 0; j < 8; j++) { + hGainDec->channelGain[j] = FL2FXCONST_DBL(1.0f / (float)(1 << 8)); + } + + for (i = 0; i < 4 * 1024 / 256; i++) { + hGainDec->dummySubbandGains[i] = FL2FXCONST_DBL(1.0f / (float)(1 << 7)); + } + + hGainDec->status = 0; /* startup */ + + return DE_OK; +} + +void initDrcGainBuffers(const int frameSize, DRC_GAIN_BUFFERS* drcGainBuffers) { + int i, c, j; + /* prepare 12 instances of node buffers */ + for (i = 0; i < 12; i++) { + for (j = 0; j < NUM_LNB_FRAMES; j++) { + drcGainBuffers->linearNodeBuffer[i].nNodes[j] = 1; + drcGainBuffers->linearNodeBuffer[i].linearNode[j][0].gainLin = + FL2FXCONST_DBL(1.0f / (float)(1 << 7)); + if (j == 0) { + drcGainBuffers->linearNodeBuffer[i].linearNode[j][0].time = + 0; /* initialize last node with startup node */ + } else { + drcGainBuffers->linearNodeBuffer[i].linearNode[j][0].time = + frameSize - 1; + } + } + } + + /* prepare dummyLnb, a linearNodeBuffer containing a constant gain of 0 dB, + * for the "no DRC processing" case */ + drcGainBuffers->dummyLnb.gainInterpolationType = GIT_LINEAR; + for (i = 0; i < NUM_LNB_FRAMES; i++) { + drcGainBuffers->dummyLnb.nNodes[i] = 1; + drcGainBuffers->dummyLnb.linearNode[i][0].gainLin = + FL2FXCONST_DBL(1.0f / (float)(1 << 7)); + drcGainBuffers->dummyLnb.linearNode[i][0].time = frameSize - 1; + } + + /* prepare channelGain delay line */ + for (c = 0; c < 8; c++) { + for (i = 0; i < NUM_LNB_FRAMES; i++) { + drcGainBuffers->channelGain[c][i] = + FL2FXCONST_DBL(1.0f / (float)(1 << 8)); + } + } + + drcGainBuffers->lnbPointer = 0; +} + +DRC_ERROR +initActiveDrc(HANDLE_DRC_GAIN_DECODER hGainDec, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, const int drcSetIdSelected, + const int downmixIdSelected) { + int g, isMultiband = 0; + DRC_ERROR err = DE_OK; + DRC_INSTRUCTIONS_UNI_DRC* pInst = NULL; + DRC_COEFFICIENTS_UNI_DRC* pCoef = NULL; + + pInst = selectDrcInstructions(hUniDrcConfig, drcSetIdSelected); + if (pInst == NULL) { + return DE_NOT_OK; + } + + if (pInst->drcSetId >= 0) { + pCoef = selectDrcCoefficients(hUniDrcConfig, pInst->drcLocation); + if (pCoef == NULL) { + return DE_NOT_OK; + } + + if (pCoef->drcFrameSizePresent) { + if (pCoef->drcFrameSize != hGainDec->frameSize) { + return DE_NOT_OK; + } + } + + err = _generateDrcInstructionsDerivedData( + hGainDec, hUniDrcConfig, pInst, pCoef, + &(hGainDec->activeDrc[hGainDec->nActiveDrcs])); + if (err) return err; + } + + hGainDec->activeDrc[hGainDec->nActiveDrcs].pInst = pInst; + hGainDec->activeDrc[hGainDec->nActiveDrcs].pCoef = pCoef; + + for (g = 0; g < pInst->nDrcChannelGroups; g++) { + if (hGainDec->activeDrc[hGainDec->nActiveDrcs].bandCountForChannelGroup[g] > + 1) { + if (hGainDec->multiBandActiveDrcIndex != -1) { + return DE_NOT_OK; + } + isMultiband = 1; + } + } + + if (isMultiband) { + /* Keep activeDrc index of multiband DRC set */ + hGainDec->multiBandActiveDrcIndex = hGainDec->nActiveDrcs; + } + + if ((hGainDec->channelGainActiveDrcIndex == -1) && + (downmixIdSelected == DOWNMIX_ID_BASE_LAYOUT) && + (hUniDrcConfig->drcInstructionsUniDrcCount > + 0)) { /* use this activeDrc to apply channelGains */ + hGainDec->channelGainActiveDrcIndex = hGainDec->nActiveDrcs; + } + + hGainDec->nActiveDrcs++; + if (hGainDec->nActiveDrcs > MAX_ACTIVE_DRCS) return DE_NOT_OK; + + return DE_OK; +} + +DRC_ERROR +initActiveDrcOffset(HANDLE_DRC_GAIN_DECODER hGainDec) { + int a, accGainElementCount; + + accGainElementCount = 0; + for (a = 0; a < hGainDec->nActiveDrcs; a++) { + hGainDec->activeDrc[a].activeDrcOffset = accGainElementCount; + accGainElementCount += hGainDec->activeDrc[a].gainElementCount; + } + + if (accGainElementCount > 12) return DE_NOT_OK; + + return DE_OK; +} diff --git a/libDRCdec/src/drcGainDec_init.h b/libDRCdec/src/drcGainDec_init.h new file mode 100644 index 0000000..9215bc3 --- /dev/null +++ b/libDRCdec/src/drcGainDec_init.h @@ -0,0 +1,120 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#ifndef DRCGAINDEC_INIT_H +#define DRCGAINDEC_INIT_H + +DRC_ERROR +initGainDec(HANDLE_DRC_GAIN_DECODER hGainDec, const int frameSize, + const int sampleRate); + +void initDrcGainBuffers(const int frameSize, DRC_GAIN_BUFFERS* drcGainBuffers); + +DRC_ERROR +initActiveDrc(HANDLE_DRC_GAIN_DECODER hGainDec, + HANDLE_UNI_DRC_CONFIG hUniDrcConfig, const int drcSetIdSelected, + const int downmixIdSelected); + +DRC_ERROR +initActiveDrcOffset(HANDLE_DRC_GAIN_DECODER hGainDec); + +#endif diff --git a/libDRCdec/src/drcGainDec_preprocess.cpp b/libDRCdec/src/drcGainDec_preprocess.cpp new file mode 100644 index 0000000..7919589 --- /dev/null +++ b/libDRCdec/src/drcGainDec_preprocess.cpp @@ -0,0 +1,714 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "drcDec_types.h" +#include "drcDec_gainDecoder.h" +#include "drcGainDec_preprocess.h" +#include "drcDec_tools.h" +#include "FDK_matrixCalloc.h" +#include "drcDec_rom.h" + +#define SLOPE_FACTOR_DB_TO_LINEAR \ + FL2FXCONST_DBL(0.1151f * (float)(1 << 3)) /* ln(10) / 20 */ + +typedef struct { + int drcSetEffect; + DUCKING_MODIFICATION* pDMod; + GAIN_MODIFICATION* pGMod; + int drcCharacteristicPresent; + CHARACTERISTIC_FORMAT characteristicFormatSource[2]; + const CUSTOM_DRC_CHAR* pCCharSource[2]; + CHARACTERISTIC_FORMAT characteristicFormatTarget[2]; + const CUSTOM_DRC_CHAR* pCCharTarget[2]; + int slopeIsNegative; + int limiterPeakTargetPresent; + FIXP_SGL limiterPeakTarget; + FIXP_DBL loudnessNormalizationGainDb; + FIXP_SGL compress; + FIXP_SGL boost; +} NODE_MODIFICATION; + +static DRC_ERROR _getCicpCharacteristic( + const int cicpCharacteristic, + CHARACTERISTIC_FORMAT pCharacteristicFormat[2], + const CUSTOM_DRC_CHAR* pCCharSource[2]) { + if ((cicpCharacteristic < 1) || (cicpCharacteristic > 11)) { + return DE_NOT_OK; + } + + if (cicpCharacteristic < 7) { /* sigmoid characteristic */ + pCharacteristicFormat[CS_LEFT] = CF_SIGMOID; + pCCharSource[CS_LEFT] = + (const CUSTOM_DRC_CHAR*)(&cicpDrcCharSigmoidLeft[cicpCharacteristic - + 1]); + pCharacteristicFormat[CS_RIGHT] = CF_SIGMOID; + pCCharSource[CS_RIGHT] = + (const CUSTOM_DRC_CHAR*)(&cicpDrcCharSigmoidRight[cicpCharacteristic - + 1]); + } else { /* nodes characteristic */ + pCharacteristicFormat[CS_LEFT] = CF_NODES; + pCCharSource[CS_LEFT] = + (const CUSTOM_DRC_CHAR*)(&cicpDrcCharNodesLeft[cicpCharacteristic - 7]); + pCharacteristicFormat[CS_RIGHT] = CF_NODES; + pCCharSource[CS_RIGHT] = + (const CUSTOM_DRC_CHAR*)(&cicpDrcCharNodesRight[cicpCharacteristic - + 7]); + } + return DE_OK; +} + +static int _getSign(FIXP_SGL in) { + if (in > (FIXP_DBL)0) return 1; + if (in < (FIXP_DBL)0) return -1; + return 0; +} + +static DRC_ERROR _getSlopeSign(const CHARACTERISTIC_FORMAT drcCharFormat, + const CUSTOM_DRC_CHAR* pCChar, int* pSlopeSign) { + if (drcCharFormat == CF_SIGMOID) { + *pSlopeSign = (pCChar->sigmoid.flipSign ? 1 : -1); + } else { + int k, slopeSign = 0, tmp_slopeSign; + for (k = 0; k < pCChar->nodes.characteristicNodeCount; k++) { + if (pCChar->nodes.nodeLevel[k + 1] > pCChar->nodes.nodeLevel[k]) { + tmp_slopeSign = + _getSign(pCChar->nodes.nodeGain[k + 1] - pCChar->nodes.nodeGain[k]); + } else { + tmp_slopeSign = -_getSign(pCChar->nodes.nodeGain[k + 1] - + pCChar->nodes.nodeGain[k]); + } + if ((slopeSign || tmp_slopeSign) && (slopeSign == -tmp_slopeSign)) + return DE_NOT_OK; /* DRC characteristic is not invertible */ + else + slopeSign = tmp_slopeSign; + } + *pSlopeSign = slopeSign; + } + return DE_OK; +} + +static DRC_ERROR _isSlopeNegative(const CHARACTERISTIC_FORMAT drcCharFormat[2], + const CUSTOM_DRC_CHAR* pCChar[2], + int* pSlopeIsNegative) { + DRC_ERROR err = DE_OK; + int slopeSign[2] = {0, 0}; + + err = _getSlopeSign(drcCharFormat[CS_LEFT], pCChar[CS_LEFT], + &slopeSign[CS_LEFT]); + if (err) return err; + + err = _getSlopeSign(drcCharFormat[CS_RIGHT], pCChar[CS_RIGHT], + &slopeSign[CS_RIGHT]); + if (err) return err; + + if ((slopeSign[CS_LEFT] || slopeSign[CS_RIGHT]) && + (slopeSign[CS_LEFT] == -slopeSign[CS_RIGHT])) + return DE_NOT_OK; /* DRC characteristic is not invertible */ + + *pSlopeIsNegative = (slopeSign[CS_LEFT] < 0); + return DE_OK; +} + +static DRC_ERROR _prepareDrcCharacteristic(const DRC_CHARACTERISTIC* pDChar, + DRC_COEFFICIENTS_UNI_DRC* pCoef, + const int b, + NODE_MODIFICATION* pNodeMod) { + DRC_ERROR err = DE_OK; + pNodeMod->drcCharacteristicPresent = pDChar->present; + if (pNodeMod->drcCharacteristicPresent) { + if (pDChar->isCICP == 1) { + err = _getCicpCharacteristic(pDChar->cicpIndex, + pNodeMod->characteristicFormatSource, + pNodeMod->pCCharSource); + if (err) return err; + } else { + pNodeMod->characteristicFormatSource[CS_LEFT] = + (CHARACTERISTIC_FORMAT) + pCoef->characteristicLeftFormat[pDChar->custom.left]; + pNodeMod->pCCharSource[CS_LEFT] = + &(pCoef->customCharacteristicLeft[pDChar->custom.left]); + pNodeMod->characteristicFormatSource[CS_RIGHT] = + (CHARACTERISTIC_FORMAT) + pCoef->characteristicRightFormat[pDChar->custom.right]; + pNodeMod->pCCharSource[CS_RIGHT] = + &(pCoef->customCharacteristicRight[pDChar->custom.right]); + } + err = _isSlopeNegative(pNodeMod->characteristicFormatSource, + pNodeMod->pCCharSource, &pNodeMod->slopeIsNegative); + if (err) return err; + + if (pNodeMod->pGMod != NULL) { + if (pNodeMod->pGMod[b].targetCharacteristicLeftPresent) { + pNodeMod->characteristicFormatTarget[CS_LEFT] = + (CHARACTERISTIC_FORMAT)pCoef->characteristicLeftFormat + [pNodeMod->pGMod[b].targetCharacteristicLeftIndex]; + pNodeMod->pCCharTarget[CS_LEFT] = + &(pCoef->customCharacteristicLeft + [pNodeMod->pGMod[b].targetCharacteristicLeftIndex]); + } + if (pNodeMod->pGMod[b].targetCharacteristicRightPresent) { + pNodeMod->characteristicFormatTarget[CS_RIGHT] = + (CHARACTERISTIC_FORMAT)pCoef->characteristicRightFormat + [pNodeMod->pGMod[b].targetCharacteristicRightIndex]; + pNodeMod->pCCharTarget[CS_RIGHT] = + &(pCoef->customCharacteristicRight + [pNodeMod->pGMod[b].targetCharacteristicRightIndex]); + } + } + } + return DE_OK; +} + +static DRC_ERROR _compressorIO_sigmoid_common( + const FIXP_DBL tmp, /* e = 7 */ + const FIXP_DBL gainDbLimit, /* e = 6 */ + const FIXP_DBL exp, /* e = 5 */ + const int inverse, FIXP_DBL* out) /* e = 7 */ +{ + FIXP_DBL x, tmp1, tmp2, invExp, denom; + int e_x, e_tmp1, e_tmp2, e_invExp, e_denom, e_out; + + if (exp < FL2FXCONST_DBL(1.0f / (float)(1 << 5))) { + return DE_NOT_OK; + } + + /* x = tmp / gainDbLimit; */ + x = fDivNormSigned(tmp, gainDbLimit, &e_x); + e_x += 7 - 6; + if (x < (FIXP_DBL)0) { + return DE_NOT_OK; + } + + /* out = tmp / pow(1.0f +/- pow(x, exp), 1.0f/exp); */ + tmp1 = fPow(x, e_x, exp, 5, &e_tmp1); + if (inverse) tmp1 = -tmp1; + tmp2 = fAddNorm(FL2FXCONST_DBL(1.0f / (float)(1 << 1)), 1, tmp1, e_tmp1, + &e_tmp2); + invExp = fDivNorm(FL2FXCONST_DBL(1.0f / (float)(1 << 1)), exp, &e_invExp); + e_invExp += 1 - 5; + denom = fPow(tmp2, e_tmp2, invExp, e_invExp, &e_denom); + *out = fDivNormSigned(tmp, denom, &e_out); + e_out += 7 - e_denom; + *out = scaleValueSaturate(*out, e_out - 7); + return DE_OK; +} + +static DRC_ERROR _compressorIO_sigmoid(const CUSTOM_DRC_CHAR_SIGMOID* pCChar, + const FIXP_DBL inLevelDb, /* e = 7 */ + FIXP_DBL* outGainDb) /* e = 7 */ +{ + FIXP_DBL tmp; + FIXP_SGL exp = pCChar->exp; + DRC_ERROR err = DE_OK; + + tmp = fMultDiv2(DRC_INPUT_LOUDNESS_TARGET - inLevelDb, pCChar->ioRatio); + tmp = SATURATE_LEFT_SHIFT(tmp, 2 + 1, DFRACT_BITS); + if (exp < (FIXP_SGL)MAXVAL_SGL) { + /* x = tmp / gainDbLimit; */ + /* *outGainDb = tmp / pow(1.0f + pow(x, exp), 1.0f/exp); */ + err = _compressorIO_sigmoid_common(tmp, FX_SGL2FX_DBL(pCChar->gain), + FX_SGL2FX_DBL(exp), 0, outGainDb); + if (err) return err; + } else { + *outGainDb = + tmp; /* scaling of outGainDb (7) is equal to scaling of tmp (7) */ + } + if (pCChar->flipSign == 1) { + *outGainDb = -*outGainDb; + } + return err; +} + +static DRC_ERROR _compressorIO_sigmoid_inverse( + const CUSTOM_DRC_CHAR_SIGMOID* pCChar, const FIXP_SGL gainDb, + FIXP_DBL* inLev) { + DRC_ERROR err = DE_OK; + FIXP_SGL ioRatio = pCChar->ioRatio; + FIXP_SGL exp = pCChar->exp; + FIXP_DBL tmp = FX_SGL2FX_DBL(gainDb), tmp_out; + int e_out; + + if (pCChar->flipSign == 1) { + tmp = -tmp; + } + if (exp < (FIXP_SGL)MAXVAL_SGL) { + /* x = tmp / gainDbLimit; */ + /* tmp = tmp / pow(1.0f - pow(x, exp), 1.0f / exp); */ + err = _compressorIO_sigmoid_common(tmp, FX_SGL2FX_DBL(pCChar->gain), + FX_SGL2FX_DBL(exp), 1, &tmp); + if (err) return err; + } + if (ioRatio == (FIXP_SGL)0) { + return DE_NOT_OK; + } + tmp_out = fDivNormSigned(tmp, FX_SGL2FX_DBL(ioRatio), &e_out); + e_out += 7 - 2; + tmp_out = fAddNorm(DRC_INPUT_LOUDNESS_TARGET, 7, -tmp_out, e_out, &e_out); + *inLev = scaleValueSaturate(tmp_out, e_out - 7); + + return err; +} + +static DRC_ERROR _compressorIO_nodes(const CUSTOM_DRC_CHAR_NODES* pCChar, + const FIXP_DBL inLevelDb, /* e = 7 */ + FIXP_DBL* outGainDb) /* e = 7 */ +{ + int n; + FIXP_DBL w; + const FIXP_SGL* nodeLevel = pCChar->nodeLevel; + const FIXP_SGL* nodeGain = pCChar->nodeGain; + + if (inLevelDb < DRC_INPUT_LOUDNESS_TARGET) { + for (n = 0; n < pCChar->characteristicNodeCount; n++) { + if ((inLevelDb <= FX_SGL2FX_DBL(nodeLevel[n])) && + (inLevelDb > FX_SGL2FX_DBL(nodeLevel[n + 1]))) { + w = fDivNorm(inLevelDb - FX_SGL2FX_DBL(nodeLevel[n + 1]), + FX_SGL2FX_DBL(nodeLevel[n] - nodeLevel[n + 1])); + *outGainDb = fMult(w, nodeGain[n]) + + fMult((FIXP_DBL)MAXVAL_DBL - w, nodeGain[n + 1]); + /* *outGainDb = (w * nodeGain[n] + (1.0-w) * nodeGain[n+1]); */ + return DE_OK; + } + } + } else { + for (n = 0; n < pCChar->characteristicNodeCount; n++) { + if ((inLevelDb >= FX_SGL2FX_DBL(nodeLevel[n])) && + (inLevelDb < FX_SGL2FX_DBL(nodeLevel[n + 1]))) { + w = fDivNorm(FX_SGL2FX_DBL(nodeLevel[n + 1]) - inLevelDb, + FX_SGL2FX_DBL(nodeLevel[n + 1] - nodeLevel[n])); + *outGainDb = fMult(w, nodeGain[n]) + + fMult((FIXP_DBL)MAXVAL_DBL - w, nodeGain[n + 1]); + /* *outGainDb = (w * nodeGain[n] + (1.0-w) * nodeGain[n+1]); */ + return DE_OK; + } + } + } + *outGainDb = FX_SGL2FX_DBL(nodeGain[pCChar->characteristicNodeCount]); + return DE_OK; +} + +static DRC_ERROR _compressorIO_nodes_inverse( + const CUSTOM_DRC_CHAR_NODES* pCChar, const FIXP_SGL gainDb, /* e = 7 */ + FIXP_DBL* inLev) /* e = 7 */ +{ + int n; + int k; + FIXP_DBL w; + int gainIsNegative = 0; + const FIXP_SGL* nodeLevel = pCChar->nodeLevel; + const FIXP_SGL* nodeGain = pCChar->nodeGain; + int nodeCount = pCChar->characteristicNodeCount; + for (k = 0; k < nodeCount; k++) { + if (pCChar->nodeGain[k + 1] < (FIXP_SGL)0) { + gainIsNegative = 1; + } + } + if (gainIsNegative == 1) { + if (gainDb <= nodeGain[nodeCount]) { + *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]); + } else { + if (gainDb >= (FIXP_SGL)0) { + *inLev = DRC_INPUT_LOUDNESS_TARGET; + } else { + for (n = 0; n < nodeCount; n++) { + if ((gainDb <= nodeGain[n]) && (gainDb > nodeGain[n + 1])) { + FIXP_SGL gainDelta = nodeGain[n] - nodeGain[n + 1]; + if (gainDelta == (FIXP_SGL)0) { + *inLev = FX_SGL2FX_DBL(nodeLevel[n]); + return DE_OK; + } + w = fDivNorm(gainDb - nodeGain[n + 1], gainDelta); + *inLev = fMult(w, nodeLevel[n]) + + fMult((FIXP_DBL)MAXVAL_DBL - w, nodeLevel[n + 1]); + /* *inLev = (w * nodeLevel[n] + (1.0-w) * nodeLevel[n+1]); */ + return DE_OK; + } + } + *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]); + } + } + } else { + if (gainDb >= nodeGain[nodeCount]) { + *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]); + } else { + if (gainDb <= (FIXP_SGL)0) { + *inLev = DRC_INPUT_LOUDNESS_TARGET; + } else { + for (n = 0; n < nodeCount; n++) { + if ((gainDb >= nodeGain[n]) && (gainDb < nodeGain[n + 1])) { + FIXP_SGL gainDelta = nodeGain[n + 1] - nodeGain[n]; + if (gainDelta == (FIXP_SGL)0) { + *inLev = FX_SGL2FX_DBL(nodeLevel[n]); + return DE_OK; + } + w = fDivNorm(nodeGain[n + 1] - gainDb, gainDelta); + *inLev = fMult(w, nodeLevel[n]) + + fMult((FIXP_DBL)MAXVAL_DBL - w, nodeLevel[n + 1]); + /* *inLev = (w * nodeLevel[n] + (1.0-w) * nodeLevel[n+1]); */ + return DE_OK; + } + } + *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]); + } + } + } + return DE_OK; +} + +static DRC_ERROR _mapGain(const CHARACTERISTIC_FORMAT pCCharFormatSource, + const CUSTOM_DRC_CHAR* pCCharSource, + const CHARACTERISTIC_FORMAT pCCharFormatTarget, + const CUSTOM_DRC_CHAR* pCCharTarget, + const FIXP_SGL gainInDb, /* e = 7 */ + FIXP_DBL* gainOutDb) /* e = 7 */ +{ + FIXP_DBL inLevel = (FIXP_DBL)0; + DRC_ERROR err = DE_OK; + + switch (pCCharFormatSource) { + case CF_SIGMOID: + err = _compressorIO_sigmoid_inverse( + (const CUSTOM_DRC_CHAR_SIGMOID*)pCCharSource, gainInDb, &inLevel); + if (err) return err; + break; + case CF_NODES: + err = _compressorIO_nodes_inverse( + (const CUSTOM_DRC_CHAR_NODES*)pCCharSource, gainInDb, &inLevel); + if (err) return err; + break; + default: + return DE_NOT_OK; + } + switch (pCCharFormatTarget) { + case CF_SIGMOID: + err = _compressorIO_sigmoid((const CUSTOM_DRC_CHAR_SIGMOID*)pCCharTarget, + inLevel, gainOutDb); + if (err) return err; + break; + case CF_NODES: + err = _compressorIO_nodes((const CUSTOM_DRC_CHAR_NODES*)pCCharTarget, + inLevel, gainOutDb); + if (err) return err; + break; + default: + break; + } + return DE_OK; +} + +static DRC_ERROR _toLinear( + const NODE_MODIFICATION* nodeMod, const int drcBand, + const FIXP_SGL gainDb, /* in: gain value in dB, e = 7 */ + const FIXP_SGL slopeDb, /* in: slope value in dB/deltaTmin, e = 2 */ + FIXP_DBL* gainLin, /* out: linear gain value, e = 7 */ + FIXP_DBL* slopeLin) /* out: linear slope value, e = 7 */ +{ + FIXP_DBL gainRatio_m = FL2FXCONST_DBL(1.0f / (float)(1 << 1)); + GAIN_MODIFICATION* pGMod = NULL; + DUCKING_MODIFICATION* pDMod = nodeMod->pDMod; + FIXP_DBL tmp_dbl, gainDb_modified, gainDb_offset, gainDb_out, gainLin_m, + slopeLin_m; + int gainLin_e, gainRatio_e = 1, gainDb_out_e; + if (nodeMod->pGMod != NULL) { + pGMod = &(nodeMod->pGMod[drcBand]); + } + if (((nodeMod->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) == 0) && + (nodeMod->drcSetEffect != EB_FADE) && + (nodeMod->drcSetEffect != EB_CLIPPING)) { + DRC_ERROR err = DE_OK; + FIXP_DBL gainDbMapped; + + if ((pGMod != NULL) && (nodeMod->drcCharacteristicPresent)) { + if (((gainDb > (FIXP_SGL)0) && nodeMod->slopeIsNegative) || + ((gainDb < (FIXP_SGL)0) && !nodeMod->slopeIsNegative)) { + /* left side */ + if (pGMod->targetCharacteristicLeftPresent == 1) { + err = _mapGain(nodeMod->characteristicFormatSource[CS_LEFT], + nodeMod->pCCharSource[CS_LEFT], + nodeMod->characteristicFormatTarget[CS_LEFT], + nodeMod->pCCharTarget[CS_LEFT], gainDb, &gainDbMapped); + if (err) return err; + gainRatio_m = fDivNormSigned( + gainDbMapped, FX_SGL2FX_DBL(gainDb), + &gainRatio_e); /* target characteristic in payload */ + } + } + + else { /* if (((gainDb < (FIXP_SGL)0) && nodeMod->slopeIsNegative) || + ((gainDb > (FIXP_SGL)0) && !nodeMod->slopeIsNegative)) */ + + /* right side */ + if (pGMod->targetCharacteristicRightPresent == 1) { + err = + _mapGain(nodeMod->characteristicFormatSource[CS_RIGHT], + nodeMod->pCCharSource[CS_RIGHT], + nodeMod->characteristicFormatTarget[CS_RIGHT], + nodeMod->pCCharTarget[CS_RIGHT], gainDb, &gainDbMapped); + if (err) return err; + gainRatio_m = fDivNormSigned( + gainDbMapped, FX_SGL2FX_DBL(gainDb), + &gainRatio_e); /* target characteristic in payload */ + } + } + } + if (gainDb < (FIXP_SGL)0) { + gainRatio_m = fMultDiv2(gainRatio_m, nodeMod->compress); + } else { + gainRatio_m = fMultDiv2(gainRatio_m, nodeMod->boost); + } + gainRatio_e += 2; + } + if ((pGMod != NULL) && (pGMod->gainScalingPresent == 1)) { + if (gainDb < (FIXP_SGL)0) { + gainRatio_m = fMultDiv2(gainRatio_m, pGMod->attenuationScaling); + } else { + gainRatio_m = fMultDiv2(gainRatio_m, pGMod->amplificationScaling); + } + gainRatio_e += 3; + } + if ((pDMod != NULL) && + (nodeMod->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) && + (pDMod->duckingScalingPresent == 1)) { + gainRatio_m = fMultDiv2(gainRatio_m, pDMod->duckingScaling); + gainRatio_e += 3; + } + + gainDb_modified = + fMultDiv2(gainDb, gainRatio_m); /* resulting e: 7 + gainRatio_e + 1*/ + gainDb_offset = (FIXP_DBL)0; + + if ((pGMod != NULL) && (pGMod->gainOffsetPresent == 1)) { + /* *gainLin *= (float)pow(2.0, (double)(pGMod->gainOffset/6.0f)); */ + gainDb_offset += FX_SGL2FX_DBL(pGMod->gainOffset) >> 4; /* resulting e: 8 */ + } + if ((nodeMod->limiterPeakTargetPresent == 1) && + (nodeMod->drcSetEffect == + EB_CLIPPING)) { /* The only drcSetEffect is "clipping prevention" */ + /* loudnessNormalizationGainModificationDb is included in + * loudnessNormalizationGainDb */ + /* *gainLin *= (float)pow(2.0, max(0.0, -nodeModification->limiterPeakTarget + * - nodeModification->loudnessNormalizationGainDb)/6.0); */ + gainDb_offset += fMax( + (FIXP_DBL)0, + (FX_SGL2FX_DBL(-nodeMod->limiterPeakTarget) >> 3) - + (nodeMod->loudnessNormalizationGainDb >> 1)); /* resulting e: 8 */ + } + if (gainDb_offset != (FIXP_DBL)0) { + gainDb_out = fAddNorm(gainDb_modified, 7 + gainRatio_e + 1, gainDb_offset, + 8, &gainDb_out_e); + } else { + gainDb_out = gainDb_modified; + gainDb_out_e = 7 + gainRatio_e + 1; + } + + /* *gainLin = (float)pow(2.0, (double)(gainDb_modified[1] / 6.0f)); */ + gainLin_m = approxDb2lin(gainDb_out, gainDb_out_e, &gainLin_e); + *gainLin = scaleValueSaturate(gainLin_m, gainLin_e - 7); + + /* *slopeLin = SLOPE_FACTOR_DB_TO_LINEAR * gainRatio * *gainLin * slopeDb; */ + if (slopeDb == (FIXP_SGL)0) { + *slopeLin = (FIXP_DBL)0; + } else { + tmp_dbl = + fMult(slopeDb, SLOPE_FACTOR_DB_TO_LINEAR); /* resulting e: 2 - 3 = -1 */ + tmp_dbl = fMult(tmp_dbl, gainRatio_m); /* resulting e: -1 + gainRatio_e */ + if (gainDb_offset != + (FIXP_DBL)0) { /* recalculate gainLin from gainDb that wasn't modified + by gainOffset and limiterPeakTarget */ + gainLin_m = approxDb2lin(gainDb_modified, 7 + gainRatio_e, &gainLin_e); + } + slopeLin_m = fMult(tmp_dbl, gainLin_m); + *slopeLin = + scaleValueSaturate(slopeLin_m, -1 + gainRatio_e + gainLin_e - 7); + } + + if ((nodeMod->limiterPeakTargetPresent == 1) && + (nodeMod->drcSetEffect == EB_CLIPPING)) { + if (*gainLin >= FL2FXCONST_DBL(1.0f / (float)(1 << 7))) { + *gainLin = FL2FXCONST_DBL(1.0f / (float)(1 << 7)); + *slopeLin = (FIXP_DBL)0; + } + } + + return DE_OK; +} + +/* prepare buffers containing linear nodes for each gain sequence */ +DRC_ERROR +prepareDrcGain(HANDLE_DRC_GAIN_DECODER hGainDec, + HANDLE_UNI_DRC_GAIN hUniDrcGain, const FIXP_SGL compress, + const FIXP_SGL boost, const FIXP_DBL loudnessNormalizationGainDb, + const int activeDrcIndex) { + int b, g, gainElementIndex; + DRC_GAIN_BUFFERS* drcGainBuffers = &(hGainDec->drcGainBuffers); + NODE_MODIFICATION nodeMod; + FDKmemclear(&nodeMod, sizeof(NODE_MODIFICATION)); + ACTIVE_DRC* pActiveDrc = &(hGainDec->activeDrc[activeDrcIndex]); + DRC_INSTRUCTIONS_UNI_DRC* pInst = pActiveDrc->pInst; + if (pInst == NULL) return DE_NOT_OK; + + nodeMod.drcSetEffect = pInst->drcSetEffect; + + nodeMod.compress = compress; + nodeMod.boost = boost; + nodeMod.loudnessNormalizationGainDb = loudnessNormalizationGainDb; + nodeMod.limiterPeakTargetPresent = pInst->limiterPeakTargetPresent; + nodeMod.limiterPeakTarget = pInst->limiterPeakTarget; + + gainElementIndex = 0; + for (g = 0; g < pInst->nDrcChannelGroups; g++) { + int gainSetIndex = 0; + int nDrcBands = 0; + DRC_COEFFICIENTS_UNI_DRC* pCoef = pActiveDrc->pCoef; + if (pCoef == NULL) return DE_NOT_OK; + + if (!pActiveDrc->channelGroupIsParametricDrc[g]) { + gainSetIndex = pInst->gainSetIndexForChannelGroup[g]; + + if (nodeMod.drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) { + nodeMod.pDMod = &(pActiveDrc->duckingModificationForChannelGroup[g]); + nodeMod.pGMod = NULL; + } else { + nodeMod.pGMod = pInst->gainModificationForChannelGroup[g]; + nodeMod.pDMod = NULL; + } + + nDrcBands = pActiveDrc->bandCountForChannelGroup[g]; + for (b = 0; b < nDrcBands; b++) { + DRC_ERROR err = DE_OK; + GAIN_SET* pGainSet = &(pCoef->gainSet[gainSetIndex]); + int seq = pGainSet->gainSequenceIndex[b]; + DRC_CHARACTERISTIC* pDChar = &(pGainSet->drcCharacteristic[b]); + + /* linearNodeBuffer contains a copy of the gain sequences (consisting of + nodes) that are relevant for decoding. It also contains gain + sequences of previous frames. */ + LINEAR_NODE_BUFFER* pLnb = + &(drcGainBuffers->linearNodeBuffer[pActiveDrc->activeDrcOffset + + gainElementIndex]); + int i, lnbp; + lnbp = drcGainBuffers->lnbPointer; + pLnb->gainInterpolationType = + (GAIN_INTERPOLATION_TYPE)pGainSet->gainInterpolationType; + + err = _prepareDrcCharacteristic(pDChar, pCoef, b, &nodeMod); + if (err) return err; + + /* copy a node buffer and convert from dB to linear */ + pLnb->nNodes[lnbp] = fMin((int)hUniDrcGain->nNodes[seq], 16); + for (i = 0; i < pLnb->nNodes[lnbp]; i++) { + FIXP_DBL gainLin, slopeLin; + err = _toLinear(&nodeMod, b, hUniDrcGain->gainNode[seq][i].gainDb, + (FIXP_SGL)0, &gainLin, &slopeLin); + if (err) return err; + pLnb->linearNode[lnbp][i].gainLin = gainLin; + pLnb->linearNode[lnbp][i].time = hUniDrcGain->gainNode[seq][i].time; + } + gainElementIndex++; + } + } else { + /* parametric DRC not supported */ + gainElementIndex++; + } + } + return DE_OK; +} diff --git a/libDRCdec/src/drcGainDec_preprocess.h b/libDRCdec/src/drcGainDec_preprocess.h new file mode 100644 index 0000000..4647407 --- /dev/null +++ b/libDRCdec/src/drcGainDec_preprocess.h @@ -0,0 +1,111 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#ifndef DRCGAINDEC_PREPROCESS_H +#define DRCGAINDEC_PREPROCESS_H + +DRC_ERROR +prepareDrcGain(HANDLE_DRC_GAIN_DECODER hGainDec, + HANDLE_UNI_DRC_GAIN hUniDrcGain, const FIXP_SGL compress, + const FIXP_SGL boost, const FIXP_DBL loudnessNormalizationGainDb, + const int activeDrcIndex); +#endif diff --git a/libDRCdec/src/drcGainDec_process.cpp b/libDRCdec/src/drcGainDec_process.cpp new file mode 100644 index 0000000..70c9533 --- /dev/null +++ b/libDRCdec/src/drcGainDec_process.cpp @@ -0,0 +1,532 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#include "drcDec_types.h" +#include "drcDec_gainDecoder.h" +#include "drcGainDec_process.h" + +#define E_TGAINSTEP 12 + +static DRC_ERROR _prepareLnbIndex(ACTIVE_DRC* pActiveDrc, + const int channelOffset, + const int drcChannelOffset, + const int numChannelsProcessed, + const int lnbPointer) { + int g, c; + DRC_INSTRUCTIONS_UNI_DRC* pInst = pActiveDrc->pInst; + + /* channelOffset: start index of physical channels + numChannelsProcessed: number of processed channels, physical channels and + DRC channels channelOffset + drcChannelOffset: start index of DRC channels, + i.e. the channel order referenced in pInst.sequenceIndex */ + + /* sanity checks */ + if ((channelOffset + numChannelsProcessed) > 8) return DE_NOT_OK; + + if ((channelOffset + drcChannelOffset + numChannelsProcessed) > 8) + return DE_NOT_OK; + + if ((channelOffset + drcChannelOffset) < 0) return DE_NOT_OK; + + /* prepare lnbIndexForChannel, a map of indices from each channel to its + * corresponding linearNodeBuffer instance */ + for (c = channelOffset; c < channelOffset + numChannelsProcessed; c++) { + if (pInst->drcSetId > 0) { + int drcChannel = c + drcChannelOffset; + /* fallback for configuration with more physical channels than DRC + channels: reuse DRC gain of first channel. This is necessary for HE-AAC + mono with stereo output */ + if (drcChannel >= pInst->drcChannelCount) drcChannel = 0; + g = pActiveDrc->channelGroupForChannel[drcChannel]; + if ((g >= 0) && !pActiveDrc->channelGroupIsParametricDrc[g]) { + pActiveDrc->lnbIndexForChannel[c][lnbPointer] = + pActiveDrc->activeDrcOffset + pActiveDrc->gainElementForGroup[g]; + } + } + } + + return DE_OK; +} + +static DRC_ERROR _interpolateDrcGain( + const GAIN_INTERPOLATION_TYPE gainInterpolationType, + const SHORT timePrev, /* time0 */ + const SHORT tGainStep, /* time1 - time0 */ + const SHORT start, const SHORT stop, const SHORT stepsize, + const FIXP_DBL gainLeft, const FIXP_DBL gainRight, const FIXP_DBL slopeLeft, + const FIXP_DBL slopeRight, FIXP_DBL* buffer) { + int n, n_buf; + int start_modulo, start_offset; + + if (tGainStep < 0) { + return DE_NOT_OK; + } + if (tGainStep == 0) { + return DE_OK; + } + + /* get start index offset and buffer index for downsampled interpolation */ + /* start_modulo = (start+timePrev)%stepsize; */ /* stepsize is a power of 2 */ + start_modulo = (start + timePrev) & (stepsize - 1); + start_offset = (start_modulo ? stepsize - start_modulo : 0); + /* n_buf = (start + timePrev + start_offset)/stepsize; */ + n_buf = (start + timePrev + start_offset) >> (15 - fixnormz_S(stepsize)); + + { /* gainInterpolationType == GIT_LINEAR */ + LONG a; + /* runs = ceil((stop - start - start_offset)/stepsize). This works for + * stepsize = 2^N only. */ + INT runs = (INT)(stop - start - start_offset + stepsize - 1) >> + (30 - CountLeadingBits(stepsize)); + INT n_min = fMin( + fMin(CntLeadingZeros(gainRight), CntLeadingZeros(gainLeft)) - 1, 8); + a = (LONG)((gainRight << n_min) - (gainLeft << n_min)) / tGainStep; + LONG a_step = a * stepsize; + n = start + start_offset; + a = a * n + (LONG)(gainLeft << n_min); + buffer += n_buf; +#if defined(FUNCTION_interpolateDrcGain_func1) + interpolateDrcGain_func1(buffer, a, a_step, n_min, runs); +#else + a -= a_step; + n_min = 8 - n_min; + for (int i = 0; i < runs; i++) { + a += a_step; + buffer[i] = fMultDiv2(buffer[i], (FIXP_DBL)a) << n_min; + } +#endif /* defined(FUNCTION_interpolateDrcGain_func1) */ + } + return DE_OK; +} + +static DRC_ERROR _processNodeSegments( + const int frameSize, const GAIN_INTERPOLATION_TYPE gainInterpolationType, + const int nNodes, const NODE_LIN* pNodeLin, const int offset, + const SHORT stepsize, + const NODE_LIN nodePrevious, /* the last node of the previous frame */ + const FIXP_DBL channelGain, FIXP_DBL* buffer) { + DRC_ERROR err = DE_OK; + SHORT timePrev, duration, start, stop, time; + int n; + FIXP_DBL gainLin = FL2FXCONST_DBL(1.0f / (float)(1 << 7)), gainLinPrev; + FIXP_DBL slopeLin = (FIXP_DBL)0, slopeLinPrev = (FIXP_DBL)0; + + timePrev = nodePrevious.time + offset; + gainLinPrev = nodePrevious.gainLin; + for (n = 0; n < nNodes; n++) { + time = pNodeLin[n].time + offset; + duration = time - timePrev; + gainLin = pNodeLin[n].gainLin; + if (channelGain != FL2FXCONST_DBL(1.0f / (float)(1 << 8))) + gainLin = + SATURATE_LEFT_SHIFT(fMultDiv2(gainLin, channelGain), 9, DFRACT_BITS); + + if ((timePrev >= (frameSize - 1)) || + (time < 0)) { /* This segment (between previous and current node) lies + outside of this audio frame */ + timePrev = time; + gainLinPrev = gainLin; + slopeLinPrev = slopeLin; + continue; + } + + /* start and stop are the boundaries of the region of this segment that lie + within this audio frame. Their values are relative to the beginning of + this segment. stop is the first sample that isn't processed any more. */ + start = fMax(-timePrev, 1); + stop = fMin(time, (SHORT)(frameSize - 1)) - timePrev + 1; + + err = _interpolateDrcGain(gainInterpolationType, timePrev, duration, start, + stop, stepsize, gainLinPrev, gainLin, + slopeLinPrev, slopeLin, buffer); + if (err) return err; + + timePrev = time; + gainLinPrev = gainLin; + } + return err; +} + +/* process DRC on time-domain signal */ +DRC_ERROR +processDrcTime(HANDLE_DRC_GAIN_DECODER hGainDec, const int activeDrcIndex, + const int delaySamples, const int channelOffset, + const int drcChannelOffset, const int numChannelsProcessed, + const int timeDataChannelOffset, FIXP_DBL* deinterleavedAudio) { + DRC_ERROR err = DE_OK; + int c, b, i; + ACTIVE_DRC* pActiveDrc = &(hGainDec->activeDrc[activeDrcIndex]); + DRC_GAIN_BUFFERS* pDrcGainBuffers = &(hGainDec->drcGainBuffers); + int lnbPointer = pDrcGainBuffers->lnbPointer, lnbIx; + LINEAR_NODE_BUFFER* pLinearNodeBuffer = pDrcGainBuffers->linearNodeBuffer; + LINEAR_NODE_BUFFER* pDummyLnb = &(pDrcGainBuffers->dummyLnb); + int offset = 0; + + if (hGainDec->delayMode == DM_REGULAR_DELAY) { + offset = hGainDec->frameSize; + } + + if ((delaySamples + offset) > + (NUM_LNB_FRAMES - 2) * + hGainDec->frameSize) /* if delaySamples is too big, NUM_LNB_FRAMES + should be increased */ + return DE_NOT_OK; + + err = _prepareLnbIndex(pActiveDrc, channelOffset, drcChannelOffset, + numChannelsProcessed, lnbPointer); + if (err) return err; + + deinterleavedAudio += + channelOffset * timeDataChannelOffset; /* apply channelOffset */ + + /* signal processing loop */ + for (c = channelOffset; c < channelOffset + numChannelsProcessed; c++) { + if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex) + pDrcGainBuffers->channelGain[c][lnbPointer] = hGainDec->channelGain[c]; + + b = 0; + { + LINEAR_NODE_BUFFER *pLnb, *pLnbPrevious; + NODE_LIN nodePrevious; + int lnbPointerDiff; + FIXP_DBL channelGain; + /* get pointer to oldest linearNodes */ + lnbIx = lnbPointer + 1 - NUM_LNB_FRAMES; + while (lnbIx < 0) lnbIx += NUM_LNB_FRAMES; + + if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex) + channelGain = pDrcGainBuffers->channelGain[c][lnbIx]; + else + channelGain = FL2FXCONST_DBL(1.0f / (float)(1 << 8)); + + /* Loop over all node buffers in linearNodeBuffer. + All nodes which are not relevant for the current frame are sorted out + inside _processNodeSegments. */ + for (i = 0; i < NUM_LNB_FRAMES - 1; i++) { + /* Prepare previous node */ + if (pActiveDrc->lnbIndexForChannel[c][lnbIx] >= 0) + pLnbPrevious = &( + pLinearNodeBuffer[pActiveDrc->lnbIndexForChannel[c][lnbIx] + b]); + else + pLnbPrevious = pDummyLnb; + nodePrevious = + pLnbPrevious->linearNode[lnbIx][pLnbPrevious->nNodes[lnbIx] - 1]; + nodePrevious.time -= hGainDec->frameSize; + if (channelGain != FL2FXCONST_DBL(1.0f / (float)(1 << 8))) + nodePrevious.gainLin = SATURATE_LEFT_SHIFT( + fMultDiv2(nodePrevious.gainLin, + pDrcGainBuffers->channelGain[c][lnbIx]), + 9, DFRACT_BITS); + + /* Prepare current linearNodeBuffer instance */ + lnbIx++; + if (lnbIx >= NUM_LNB_FRAMES) lnbIx = 0; + + /* if lnbIndexForChannel changes over time, use the old indices for + * smooth transitions */ + if (pActiveDrc->lnbIndexForChannel[c][lnbIx] >= 0) + pLnb = &( + pLinearNodeBuffer[pActiveDrc->lnbIndexForChannel[c][lnbIx] + b]); + else /* lnbIndexForChannel = -1 means "no DRC processing", due to + drcInstructionsIndex < 0, drcSetId < 0 or channel group < 0 */ + pLnb = pDummyLnb; + + if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex) + channelGain = pDrcGainBuffers->channelGain[c][lnbIx]; + + /* number of frames of offset with respect to lnbPointer */ + lnbPointerDiff = i - (NUM_LNB_FRAMES - 2); + + err = _processNodeSegments( + hGainDec->frameSize, pLnb->gainInterpolationType, + pLnb->nNodes[lnbIx], pLnb->linearNode[lnbIx], + lnbPointerDiff * hGainDec->frameSize + delaySamples + offset, 1, + nodePrevious, channelGain, deinterleavedAudio); + if (err) return err; + } + deinterleavedAudio += timeDataChannelOffset; /* proceed to next channel */ + } + } + return DE_OK; +} + +/* process DRC on subband-domain signal */ +DRC_ERROR +processDrcSubband(HANDLE_DRC_GAIN_DECODER hGainDec, const int activeDrcIndex, + const int delaySamples, const int channelOffset, + const int drcChannelOffset, const int numChannelsProcessed, + const int processSingleTimeslot, + FIXP_DBL* deinterleavedAudioReal[], + FIXP_DBL* deinterleavedAudioImag[]) { + DRC_ERROR err = DE_OK; + int b, c, g, m, m_start, m_stop, s, i; + FIXP_DBL gainSb; + DRC_INSTRUCTIONS_UNI_DRC* pInst = hGainDec->activeDrc[activeDrcIndex].pInst; + DRC_GAIN_BUFFERS* pDrcGainBuffers = &(hGainDec->drcGainBuffers); + ACTIVE_DRC* pActiveDrc = &(hGainDec->activeDrc[activeDrcIndex]); + int activeDrcOffset = pActiveDrc->activeDrcOffset; + int lnbPointer = pDrcGainBuffers->lnbPointer, lnbIx; + LINEAR_NODE_BUFFER* pLinearNodeBuffer = pDrcGainBuffers->linearNodeBuffer; + FIXP_DBL(*subbandGains)[4 * 1024 / 256] = hGainDec->subbandGains; + FIXP_DBL* dummySubbandGains = hGainDec->dummySubbandGains; + SUBBAND_DOMAIN_MODE subbandDomainMode = hGainDec->subbandDomainSupported; + int signalIndex = 0; + int frameSizeSb = 0; + int nDecoderSubbands; + SHORT L = 0; /* L: downsampling factor */ + int offset = 0; + FIXP_DBL *audioReal = NULL, *audioImag = NULL; + + if (hGainDec->delayMode == DM_REGULAR_DELAY) { + offset = hGainDec->frameSize; + } + + if ((delaySamples + offset) > + (NUM_LNB_FRAMES - 2) * + hGainDec->frameSize) /* if delaySamples is too big, NUM_LNB_FRAMES + should be increased */ + return DE_NOT_OK; + + switch (subbandDomainMode) { +#if ((1024 / 256) >= (4096 / SUBBAND_DOWNSAMPLING_FACTOR_QMF64)) + case SDM_QMF64: + nDecoderSubbands = SUBBAND_NUM_BANDS_QMF64; + L = SUBBAND_DOWNSAMPLING_FACTOR_QMF64; + /* analysisDelay = SUBBAND_ANALYSIS_DELAY_QMF64; */ + break; + case SDM_QMF71: + nDecoderSubbands = SUBBAND_NUM_BANDS_QMF71; + L = SUBBAND_DOWNSAMPLING_FACTOR_QMF71; + /* analysisDelay = SUBBAND_ANALYSIS_DELAY_QMF71; */ + break; +#else + case SDM_QMF64: + case SDM_QMF71: + /* QMF domain processing is not supported. */ + return DE_NOT_OK; +#endif + case SDM_STFT256: + nDecoderSubbands = SUBBAND_NUM_BANDS_STFT256; + L = SUBBAND_DOWNSAMPLING_FACTOR_STFT256; + /* analysisDelay = SUBBAND_ANALYSIS_DELAY_STFT256; */ + break; + default: + return DE_NOT_OK; + } + + /* frameSizeSb = hGainDec->frameSize/L; */ /* L is a power of 2 */ + frameSizeSb = + hGainDec->frameSize >> (15 - fixnormz_S(L)); /* timeslots per frame */ + + if ((processSingleTimeslot < 0) || (processSingleTimeslot >= frameSizeSb)) { + m_start = 0; + m_stop = frameSizeSb; + } else { + m_start = processSingleTimeslot; + m_stop = m_start + 1; + } + + err = _prepareLnbIndex(pActiveDrc, channelOffset, drcChannelOffset, + numChannelsProcessed, lnbPointer); + if (err) return err; + + if (!pActiveDrc->subbandGainsReady) /* only for the first time per frame that + processDrcSubband is called */ + { + /* write subbandGains */ + for (g = 0; g < pInst->nDrcChannelGroups; g++) { + b = 0; + { + LINEAR_NODE_BUFFER* pLnb = + &(pLinearNodeBuffer[activeDrcOffset + + pActiveDrc->gainElementForGroup[g] + b]); + NODE_LIN nodePrevious; + int lnbPointerDiff; + + for (m = 0; m < frameSizeSb; m++) { + subbandGains[activeDrcOffset + g][b * frameSizeSb + m] = + FL2FXCONST_DBL(1.0f / (float)(1 << 7)); + } + + lnbIx = lnbPointer - (NUM_LNB_FRAMES - 1); + while (lnbIx < 0) lnbIx += NUM_LNB_FRAMES; + + /* Loop over all node buffers in linearNodeBuffer. + All nodes which are not relevant for the current frame are sorted out + inside _processNodeSegments. */ + for (i = 0; i < NUM_LNB_FRAMES - 1; i++) { + /* Prepare previous node */ + nodePrevious = pLnb->linearNode[lnbIx][pLnb->nNodes[lnbIx] - 1]; + nodePrevious.time -= hGainDec->frameSize; + + lnbIx++; + if (lnbIx >= NUM_LNB_FRAMES) lnbIx = 0; + + /* number of frames of offset with respect to lnbPointer */ + lnbPointerDiff = i - (NUM_LNB_FRAMES - 2); + + err = _processNodeSegments( + hGainDec->frameSize, pLnb->gainInterpolationType, + pLnb->nNodes[lnbIx], pLnb->linearNode[lnbIx], + lnbPointerDiff * hGainDec->frameSize + delaySamples + offset - + (L - 1) / 2, + L, nodePrevious, FL2FXCONST_DBL(1.0f / (float)(1 << 8)), + &(subbandGains[activeDrcOffset + g][b * frameSizeSb])); + if (err) return err; + } + } + } + pActiveDrc->subbandGainsReady = 1; + } + + for (c = channelOffset; c < channelOffset + numChannelsProcessed; c++) { + FIXP_DBL* thisSubbandGainsBuffer; + if (pInst->drcSetId > 0) + g = pActiveDrc->channelGroupForChannel[c + drcChannelOffset]; + else + g = -1; + + audioReal = deinterleavedAudioReal[signalIndex]; + if (subbandDomainMode != SDM_STFT256) { + audioImag = deinterleavedAudioImag[signalIndex]; + } + + if ((g >= 0) && !pActiveDrc->channelGroupIsParametricDrc[g]) { + thisSubbandGainsBuffer = subbandGains[activeDrcOffset + g]; + } else { + thisSubbandGainsBuffer = dummySubbandGains; + } + + for (m = m_start; m < m_stop; m++) { + INT n_min = 8; + { /* single-band DRC */ + gainSb = thisSubbandGainsBuffer[m]; + if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex) + gainSb = SATURATE_LEFT_SHIFT( + fMultDiv2(gainSb, hGainDec->channelGain[c]), 9, DFRACT_BITS); + /* normalize gainSb for keeping signal precision */ + n_min = fMin(CntLeadingZeros(gainSb) - 1, n_min); + gainSb <<= n_min; + n_min = 8 - n_min; + if (subbandDomainMode == + SDM_STFT256) { /* For STFT filterbank, real and imaginary parts are + interleaved. */ + for (s = 0; s < nDecoderSubbands; s++) { + *audioReal = fMultDiv2(*audioReal, gainSb) << n_min; + audioReal++; + *audioReal = fMultDiv2(*audioReal, gainSb) << n_min; + audioReal++; + } + } else { + for (s = 0; s < nDecoderSubbands; s++) { + *audioReal = fMultDiv2(*audioReal, gainSb) << n_min; + audioReal++; + *audioImag = fMultDiv2(*audioImag, gainSb) << n_min; + audioImag++; + } + } + } + } + signalIndex++; + } + return DE_OK; +} diff --git a/libDRCdec/src/drcGainDec_process.h b/libDRCdec/src/drcGainDec_process.h new file mode 100644 index 0000000..f751aba --- /dev/null +++ b/libDRCdec/src/drcGainDec_process.h @@ -0,0 +1,119 @@ +/* ----------------------------------------------------------------------------- +Software License for The Fraunhofer FDK AAC Codec Library for Android + +© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten +Forschung e.V. All rights reserved. + + 1. INTRODUCTION +The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software +that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding +scheme for digital audio. This FDK AAC Codec software is intended to be used on +a wide variety of Android devices. + +AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient +general perceptual audio codecs. AAC-ELD is considered the best-performing +full-bandwidth communications codec by independent studies and is widely +deployed. AAC has been standardized by ISO and IEC as part of the MPEG +specifications. + +Patent licenses for necessary patent claims for the FDK AAC Codec (including +those of Fraunhofer) may be obtained through Via Licensing +(www.vialicensing.com) or through the respective patent owners individually for +the purpose of encoding or decoding bit streams in products that are compliant +with the ISO/IEC MPEG audio standards. Please note that most manufacturers of +Android devices already license these patent claims through Via Licensing or +directly from the patent owners, and therefore FDK AAC Codec software may +already be covered under those patent licenses when it is used for those +licensed purposes only. + +Commercially-licensed AAC software libraries, including floating-point versions +with enhanced sound quality, are also available from Fraunhofer. Users are +encouraged to check the Fraunhofer website for additional applications +information and documentation. + +2. COPYRIGHT LICENSE + +Redistribution and use in source and binary forms, with or without modification, +are permitted without payment of copyright license fees provided that you +satisfy the following conditions: + +You must retain the complete text of this software license in redistributions of +the FDK AAC Codec or your modifications thereto in source code form. + +You must retain the complete text of this software license in the documentation +and/or other materials provided with redistributions of the FDK AAC Codec or +your modifications thereto in binary form. You must make available free of +charge copies of the complete source code of the FDK AAC Codec and your +modifications thereto to recipients of copies in binary form. + +The name of Fraunhofer may not be used to endorse or promote products derived +from this library without prior written permission. + +You may not charge copyright license fees for anyone to use, copy or distribute +the FDK AAC Codec software or your modifications thereto. + +Your modified versions of the FDK AAC Codec must carry prominent notices stating +that you changed the software and the date of any change. For modified versions +of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android" +must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK +AAC Codec Library for Android." + +3. NO PATENT LICENSE + +NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without +limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE. +Fraunhofer provides no warranty of patent non-infringement with respect to this +software. + +You may use this FDK AAC Codec software or modifications thereto only for +purposes that are authorized by appropriate patent licenses. + +4. DISCLAIMER + +This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright +holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +including but not limited to the implied warranties of merchantability and +fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, +or consequential damages, including but not limited to procurement of substitute +goods or services; loss of use, data, or profits, or business interruption, +however caused and on any theory of liability, whether in contract, strict +liability, or tort (including negligence), arising in any way out of the use of +this software, even if advised of the possibility of such damage. + +5. CONTACT INFORMATION + +Fraunhofer Institute for Integrated Circuits IIS +Attention: Audio and Multimedia Departments - FDK AAC LL +Am Wolfsmantel 33 +91058 Erlangen, Germany + +www.iis.fraunhofer.de/amm +amm-info@iis.fraunhofer.de +----------------------------------------------------------------------------- */ + +/************************* MPEG-D DRC decoder library ************************** + + Author(s): + + Description: + +*******************************************************************************/ + +#ifndef DRCGAINDEC_PROCESS_H +#define DRCGAINDEC_PROCESS_H + +DRC_ERROR +processDrcTime(HANDLE_DRC_GAIN_DECODER hGainDec, const int activeDrcIndex, + const int delaySamples, const int channelOffset, + const int drcChannelOffset, const int numChannelsProcessed, + const int timeDataChannelOffset, FIXP_DBL* deinterleavedAudio); + +DRC_ERROR +processDrcSubband(HANDLE_DRC_GAIN_DECODER hGainDec, const int activeDrcIndex, + const int delaySamples, const int channelOffset, + const int drcChannelOffset, const int numChannelsProcessed, + const int processSingleTimeslot, + FIXP_DBL* deinterleavedAudioReal[], + FIXP_DBL* deinterleavedAudioImag[]); +#endif |