aboutsummaryrefslogtreecommitdiffstats
path: root/libDRCdec/src
diff options
context:
space:
mode:
Diffstat (limited to 'libDRCdec/src')
-rw-r--r--libDRCdec/src/FDK_drcDecLib.cpp891
-rw-r--r--libDRCdec/src/drcDec_gainDecoder.cpp445
-rw-r--r--libDRCdec/src/drcDec_gainDecoder.h264
-rw-r--r--libDRCdec/src/drcDec_reader.cpp2027
-rw-r--r--libDRCdec/src/drcDec_reader.h130
-rw-r--r--libDRCdec/src/drcDec_rom.cpp323
-rw-r--r--libDRCdec/src/drcDec_rom.h120
-rw-r--r--libDRCdec/src/drcDec_selectionProcess.cpp3083
-rw-r--r--libDRCdec/src/drcDec_selectionProcess.h217
-rw-r--r--libDRCdec/src/drcDec_tools.cpp371
-rw-r--r--libDRCdec/src/drcDec_tools.h146
-rw-r--r--libDRCdec/src/drcDec_types.h428
-rw-r--r--libDRCdec/src/drcDecoder.h142
-rw-r--r--libDRCdec/src/drcGainDec_init.cpp344
-rw-r--r--libDRCdec/src/drcGainDec_init.h120
-rw-r--r--libDRCdec/src/drcGainDec_preprocess.cpp714
-rw-r--r--libDRCdec/src/drcGainDec_preprocess.h111
-rw-r--r--libDRCdec/src/drcGainDec_process.cpp532
-rw-r--r--libDRCdec/src/drcGainDec_process.h119
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