aboutsummaryrefslogtreecommitdiffstats
path: root/libPCMutils/src
diff options
context:
space:
mode:
authorFraunhofer IIS FDK <audio-fdk@iis.fraunhofer.de>2018-02-26 20:17:00 +0100
committerJean-Michel Trivi <jmtrivi@google.com>2018-04-19 11:21:15 -0700
commit6cfabd35363c3ef5e3b209b867169a500b3ccc3c (patch)
tree01c0a19f2735e8b5d2407555fe992d4230d089eb /libPCMutils/src
parent6288a1e34c4dede4c2806beb1736ece6580558c7 (diff)
downloadfdk-aac-6cfabd35363c3ef5e3b209b867169a500b3ccc3c.tar.gz
fdk-aac-6cfabd35363c3ef5e3b209b867169a500b3ccc3c.tar.bz2
fdk-aac-6cfabd35363c3ef5e3b209b867169a500b3ccc3c.zip
Upgrade to FDKv2
Bug: 71430241 Test: CTS DecoderTest and DecoderTestAacDrc original-Change-Id: Iaa20f749b8a04d553b20247cfe1a8930ebbabe30 Apply clang-format also on header files. original-Change-Id: I14de1ef16bbc79ec0283e745f98356a10efeb2e4 Fixes for MPEG-D DRC original-Change-Id: If1de2d74bbbac84b3f67de3b88b83f6a23b8a15c Catch unsupported tw_mdct at an early stage original-Change-Id: Ied9dd00d754162a0e3ca1ae3e6b854315d818afe Fixing PVC transition frames original-Change-Id: Ib75725abe39252806c32d71176308f2c03547a4e Move qmf bands sanity check original-Change-Id: Iab540c3013c174d9490d2ae100a4576f51d8dbc4 Initialize scaling variable original-Change-Id: I3c4087101b70e998c71c1689b122b0d7762e0f9e Add 16 qmf band configuration to getSlotNrgHQ() original-Change-Id: I49a5d30f703a1b126ff163df9656db2540df21f1 Always apply byte alignment at the end of the AudioMuxElement original-Change-Id: I42d560287506d65d4c3de8bfe3eb9a4ebeb4efc7 Setup SBR element only if no parse error exists original-Change-Id: I1915b73704bc80ab882b9173d6bec59cbd073676 Additional array index check in HCR original-Change-Id: I18cc6e501ea683b5009f1bbee26de8ddd04d8267 Fix fade-in index selection in concealment module original-Change-Id: Ibf802ed6ed8c05e9257e1f3b6d0ac1162e9b81c1 Enable explicit backward compatible parser for AAC_LD original-Change-Id: I27e9c678dcb5d40ed760a6d1e06609563d02482d Skip spatial specific config in explicit backward compatible ASC original-Change-Id: Iff7cc365561319e886090cedf30533f562ea4d6e Update flags description in decoder API original-Change-Id: I9a5b4f8da76bb652f5580cbd3ba9760425c43830 Add QMF domain reset function original-Change-Id: I4f89a8a2c0277d18103380134e4ed86996e9d8d6 DRC upgrade v2.1.0 original-Change-Id: I5731c0540139dab220094cd978ef42099fc45b74 Fix integer overflow in sqrtFixp_lookup() original-Change-Id: I429a6f0d19aa2cc957e0f181066f0ca73968c914 Fix integer overflow in invSqrtNorm2() original-Change-Id: I84de5cbf9fb3adeb611db203fe492fabf4eb6155 Fix integer overflow in GenerateRandomVector() original-Change-Id: I3118a641008bd9484d479e5b0b1ee2b5d7d44d74 Fix integer overflow in adjustTimeSlot_EldGrid() original-Change-Id: I29d503c247c5c8282349b79df940416a512fb9d5 Fix integer overflow in FDKsbrEnc_codeEnvelope() original-Change-Id: I6b34b61ebb9d525b0c651ed08de2befc1f801449 Follow-up on: Fix integer overflow in adjustTimeSlot_EldGrid() original-Change-Id: I6f8f578cc7089e5eb7c7b93e580b72ca35ad689a Fix integer overflow in get_pk_v2() original-Change-Id: I63375bed40d45867f6eeaa72b20b1f33e815938c Fix integer overflow in Syn_filt_zero() original-Change-Id: Ie0c02fdfbe03988f9d3b20d10cd9fe4c002d1279 Fix integer overflow in CFac_CalcFacSignal() original-Change-Id: Id2d767c40066c591b51768e978eb8af3b803f0c5 Fix integer overflow in FDKaacEnc_FDKaacEnc_calcPeNoAH() original-Change-Id: Idcbd0f4a51ae2550ed106aa6f3d678d1f9724841 Fix integer overflow in sbrDecoder_calculateGainVec() original-Change-Id: I7081bcbe29c5cede9821b38d93de07c7add2d507 Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I4a95ddc18de150102352d4a1845f06094764c881 Fix integer overflow in Pred_Lt4() original-Change-Id: I4dbd012b2de7d07c3e70a47b92e3bfae8dbc750a Fix integer overflow in FDKsbrEnc_InitSbrFastTransientDetector() original-Change-Id: I788cbec1a4a00f44c2f3a72ad7a4afa219807d04 Fix unsigned integer overflow in FDKaacEnc_WriteBitstream() original-Change-Id: I68fc75166e7d2cd5cd45b18dbe3d8c2a92f1822a Fix unsigned integer overflow in FDK_MetadataEnc_Init() original-Change-Id: Ie8d025f9bcdb2442c704bd196e61065c03c10af4 Fix overflow in pseudo random number generators original-Change-Id: I3e2551ee01356297ca14e3788436ede80bd5513c Fix unsigned integer overflow in sbrDecoder_Parse() original-Change-Id: I3f231b2f437e9c37db4d5b964164686710eee971 Fix unsigned integer overflow in longsub() original-Change-Id: I73c2bc50415cac26f1f5a29e125bbe75f9180a6e Fix unsigned integer overflow in CAacDecoder_DecodeFrame() original-Change-Id: Ifce2db4b1454b46fa5f887e9d383f1cc43b291e4 Fix overflow at CLpdChannelStream_Read() original-Change-Id: Idb9d822ce3a4272e4794b643644f5434e2d4bf3f Fix unsigned integer overflow in Hcr_State_BODY_SIGN_ESC__ESC_WORD() original-Change-Id: I1ccf77c0015684b85534c5eb97162740a870b71c Fix unsigned integer overflow in UsacConfig_Parse() original-Change-Id: Ie6d27f84b6ae7eef092ecbff4447941c77864d9f Fix unsigned integer overflow in aacDecoder_drcParse() original-Change-Id: I713f28e883eea3d70b6fa56a7b8f8c22bcf66ca0 Fix unsigned integer overflow in aacDecoder_drcReadCompression() original-Change-Id: Ia34dfeb88c4705c558bce34314f584965cafcf7a Fix unsigned integer overflow in CDataStreamElement_Read() original-Change-Id: Iae896cc1d11f0a893d21be6aa90bd3e60a2c25f0 Fix unsigned integer overflow in transportDec_AdjustEndOfAccessUnit() original-Change-Id: I64cf29a153ee784bb4a16fdc088baabebc0007dc Fix unsigned integer overflow in transportDec_GetAuBitsRemaining() original-Change-Id: I975b3420faa9c16a041874ba0db82e92035962e4 Fix unsigned integer overflow in extractExtendedData() original-Change-Id: I2a59eb09e2053cfb58dfb75fcecfad6b85a80a8f Fix signed integer overflow in CAacDecoder_ExtPayloadParse() original-Change-Id: I4ad5ca4e3b83b5d964f1c2f8c5e7b17c477c7929 Fix unsigned integer overflow in CAacDecoder_DecodeFrame() original-Change-Id: I29a39df77d45c52a0c9c5c83c1ba81f8d0f25090 Follow-up on: Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I8fb194ffc073a3432a380845be71036a272d388f Fix signed integer overflow in _interpolateDrcGain() original-Change-Id: I879ec9ab14005069a7c47faf80e8bc6e03d22e60 Fix unsigned integer overflow in FDKreadBits() original-Change-Id: I1f47a6a8037ff70375aa8844947d5681bb4287ad Fix unsigned integer overflow in FDKbyteAlign() original-Change-Id: Id5f3a11a0c9e50fc6f76ed6c572dbd4e9f2af766 Fix unsigned integer overflow in FDK_get32() original-Change-Id: I9d33b8e97e3d38cbb80629cb859266ca0acdce96 Fix unsigned integer overflow in FDK_pushBack() original-Change-Id: Ic87f899bc8c6acf7a377a8ca7f3ba74c3a1e1c19 Fix unsigned integer overflow in FDK_pushForward() original-Change-Id: I3b754382f6776a34be1602e66694ede8e0b8effc Fix unsigned integer overflow in ReadPsData() original-Change-Id: I25361664ba8139e32bbbef2ca8c106a606ce9c37 Fix signed integer overflow in E_UTIL_residu() original-Change-Id: I8c3abd1f437ee869caa8fb5903ce7d3d641b6aad REVERT: Follow-up on: Integer overflow in CLpc_SynthesisLattice(). original-Change-Id: I3d340099acb0414795c8dfbe6362bc0a8f045f9b Follow-up on: Fix integer overflow in CLpc_SynthesisLattice() original-Change-Id: I4aedb8b3a187064e9f4d985175aa55bb99cc7590 Follow-up on: Fix unsigned integer overflow in aacDecoder_drcParse() original-Change-Id: I2aa2e13916213bf52a67e8b0518e7bf7e57fb37d Fix integer overflow in acelp original-Change-Id: Ie6390c136d84055f8b728aefbe4ebef6e029dc77 Fix unsigned integer overflow in aacDecoder_UpdateBitStreamCounters() original-Change-Id: I391ffd97ddb0b2c184cba76139bfb356a3b4d2e2 Adjust concealment default settings original-Change-Id: I6a95db935a327c47df348030bcceafcb29f54b21 Saturate estimatedStartPos original-Change-Id: I27be2085e0ae83ec9501409f65e003f6bcba1ab6 Negative shift exponent in _interpolateDrcGain() original-Change-Id: I18edb26b26d002aafd5e633d4914960f7a359c29 Negative shift exponent in calculateICC() original-Change-Id: I3dcd2ae98d2eb70ee0d59750863cbb2a6f4f8aba Too large shift exponent in FDK_put() original-Change-Id: Ib7d9aaa434d2d8de4a13b720ca0464b31ca9b671 Too large shift exponent in CalcInvLdData() original-Change-Id: I43e6e78d4cd12daeb1dcd5d82d1798bdc2550262 Member access within null pointer of type SBR_CHANNEL original-Change-Id: Idc5e4ea8997810376d2f36bbdf628923b135b097 Member access within null pointer of type CpePersistentData original-Change-Id: Ib6c91cb0d37882768e5baf63324e429589de0d9d Member access within null pointer FDKaacEnc_psyMain() original-Change-Id: I7729b7f4479970531d9dc823abff63ca52e01997 Member access within null pointer FDKaacEnc_GetPnsParam() original-Change-Id: I9aa3b9f3456ae2e0f7483dbd5b3dde95fc62da39 Member access within null pointer FDKsbrEnc_EnvEncodeFrame() original-Change-Id: I67936f90ea714e90b3e81bc0dd1472cc713eb23a Add HCR sanity check original-Change-Id: I6c1d9732ebcf6af12f50b7641400752f74be39f7 Fix memory issue for HBE edge case with 8:3 SBR original-Change-Id: I11ea58a61e69fbe8bf75034b640baee3011e63e9 Additional SBR parametrization sanity check for ELD original-Change-Id: Ie26026fbfe174c2c7b3691f6218b5ce63e322140 Add MPEG-D DRC channel layout check original-Change-Id: Iea70a74f171b227cce636a9eac4ba662777a2f72 Additional out-of-bounds checks in MPEG-D DRC original-Change-Id: Ife4a8c3452c6fde8a0a09e941154a39a769777d4 Change-Id: Ic63cb2f628720f54fe9b572b0cb528e2599c624e
Diffstat (limited to 'libPCMutils/src')
-rw-r--r--libPCMutils/src/limiter.cpp588
-rw-r--r--libPCMutils/src/pcm_utils.cpp195
-rw-r--r--libPCMutils/src/pcmdmx_lib.cpp2659
-rw-r--r--libPCMutils/src/pcmutils_lib.cpp2510
-rw-r--r--libPCMutils/src/version.h119
5 files changed, 3303 insertions, 2768 deletions
diff --git a/libPCMutils/src/limiter.cpp b/libPCMutils/src/limiter.cpp
index af724f0..a799a51 100644
--- a/libPCMutils/src/limiter.cpp
+++ b/libPCMutils/src/limiter.cpp
@@ -1,74 +1,85 @@
-
-/* -----------------------------------------------------------------------------------------------------------
+/* -----------------------------------------------------------------------------
Software License for The Fraunhofer FDK AAC Codec Library for Android
-© Copyright 1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
- All rights reserved.
+© 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.
+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:
+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 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
+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.
+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.
+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."
+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.
+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.
+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.
+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
@@ -79,46 +90,28 @@ Am Wolfsmantel 33
www.iis.fraunhofer.de/amm
amm-info@iis.fraunhofer.de
------------------------------------------------------------------------------------------------------------ */
+----------------------------------------------------------------------------- */
-/************************ FDK PCM postprocessor module *********************
+/**************************** PCM utility library ******************************
Author(s): Matthias Neusinger
+
Description: Hard limiter for clipping prevention
*******************************************************************************/
#include "limiter.h"
+#include "FDK_core.h"
-
-struct TDLimiter {
- unsigned int attack;
- FIXP_DBL attackConst, releaseConst;
- unsigned int attackMs, releaseMs, maxAttackMs;
- FIXP_PCM threshold;
- unsigned int channels, maxChannels;
- unsigned int sampleRate, maxSampleRate;
- FIXP_DBL cor, max;
- FIXP_DBL* maxBuf;
- FIXP_DBL* delayBuf;
- unsigned int maxBufIdx, delayBufIdx;
- FIXP_DBL smoothState0;
- FIXP_DBL minGain;
-
- FIXP_DBL additionalGainPrev;
- FIXP_DBL additionalGainFilterState;
- FIXP_DBL additionalGainFilterState1;
-};
+/* library version */
+#include "version.h"
+/* library title */
+#define TDLIMIT_LIB_TITLE "TD Limiter Lib"
/* create limiter */
-TDLimiterPtr createLimiter(
- unsigned int maxAttackMs,
- unsigned int releaseMs,
- INT_PCM threshold,
- unsigned int maxChannels,
- unsigned int maxSampleRate
- )
-{
+TDLimiterPtr pcmLimiter_Create(unsigned int maxAttackMs, unsigned int releaseMs,
+ FIXP_DBL threshold, unsigned int maxChannels,
+ UINT maxSampleRate) {
TDLimiterPtr limiter = NULL;
unsigned int attack, release;
FIXP_DBL attackConst, releaseConst, exponent;
@@ -133,16 +126,17 @@ TDLimiterPtr createLimiter(
if (!limiter) return NULL;
/* alloc max and delay buffers */
- limiter->maxBuf = (FIXP_DBL*)FDKcalloc(attack + 1, sizeof(FIXP_DBL));
- limiter->delayBuf = (FIXP_DBL*)FDKcalloc(attack * maxChannels, sizeof(FIXP_DBL));
+ limiter->maxBuf = (FIXP_DBL*)FDKcalloc(attack + 1, sizeof(FIXP_DBL));
+ limiter->delayBuf =
+ (FIXP_DBL*)FDKcalloc(attack * maxChannels, sizeof(FIXP_DBL));
if (!limiter->maxBuf || !limiter->delayBuf) {
- destroyLimiter(limiter);
+ pcmLimiter_Destroy(limiter);
return NULL;
}
/* attackConst = pow(0.1, 1.0 / (attack + 1)) */
- exponent = invFixp(attack+1);
+ exponent = invFixp(attack + 1);
attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
attackConst = scaleValue(attackConst, e_ans);
@@ -152,140 +146,107 @@ TDLimiterPtr createLimiter(
releaseConst = scaleValue(releaseConst, e_ans);
/* init parameters */
- limiter->attackMs = maxAttackMs;
- limiter->maxAttackMs = maxAttackMs;
- limiter->releaseMs = releaseMs;
- limiter->attack = attack;
- limiter->attackConst = attackConst;
- limiter->releaseConst = releaseConst;
- limiter->threshold = (FIXP_PCM)threshold;
- limiter->channels = maxChannels;
- limiter->maxChannels = maxChannels;
- limiter->sampleRate = maxSampleRate;
+ limiter->attackMs = maxAttackMs;
+ limiter->maxAttackMs = maxAttackMs;
+ limiter->releaseMs = releaseMs;
+ limiter->attack = attack;
+ limiter->attackConst = attackConst;
+ limiter->releaseConst = releaseConst;
+ limiter->threshold = threshold >> TDL_GAIN_SCALING;
+ limiter->channels = maxChannels;
+ limiter->maxChannels = maxChannels;
+ limiter->sampleRate = maxSampleRate;
limiter->maxSampleRate = maxSampleRate;
- resetLimiter(limiter);
+ pcmLimiter_Reset(limiter);
return limiter;
}
-
-/* reset limiter */
-TDLIMITER_ERROR resetLimiter(TDLimiterPtr limiter)
-{
- if (limiter != NULL) {
-
- limiter->maxBufIdx = 0;
- limiter->delayBufIdx = 0;
- limiter->max = (FIXP_DBL)0;
- limiter->cor = FL2FXCONST_DBL(1.0f/(1<<1));
- limiter->smoothState0 = FL2FXCONST_DBL(1.0f/(1<<1));
- limiter->minGain = FL2FXCONST_DBL(1.0f/(1<<1));
-
- limiter->additionalGainPrev = FL2FXCONST_DBL(1.0f/(1<<TDL_GAIN_SCALING));
- limiter->additionalGainFilterState = FL2FXCONST_DBL(1.0f/(1<<TDL_GAIN_SCALING));
- limiter->additionalGainFilterState1 = FL2FXCONST_DBL(1.0f/(1<<TDL_GAIN_SCALING));
-
- FDKmemset(limiter->maxBuf, 0, (limiter->attack + 1) * sizeof(FIXP_DBL) );
- FDKmemset(limiter->delayBuf, 0, limiter->attack * limiter->channels * sizeof(FIXP_DBL) );
- }
- else {
- return TDLIMIT_INVALID_HANDLE;
- }
-
- return TDLIMIT_OK;
-}
-
-
-/* destroy limiter */
-TDLIMITER_ERROR destroyLimiter(TDLimiterPtr limiter)
-{
- if (limiter != NULL) {
- FDKfree(limiter->maxBuf);
- FDKfree(limiter->delayBuf);
-
- FDKfree(limiter);
- }
- else {
- return TDLIMIT_INVALID_HANDLE;
- }
- return TDLIMIT_OK;
-}
-
/* apply limiter */
-TDLIMITER_ERROR applyLimiter(TDLimiterPtr limiter,
- INT_PCM* samples,
- FIXP_DBL* pGain,
- const INT* gain_scale,
- const UINT gain_size,
- const UINT gain_delay,
- const UINT nSamples)
-{
+TDLIMITER_ERROR pcmLimiter_Apply(TDLimiterPtr limiter, PCM_LIM* samplesIn,
+ INT_PCM* samplesOut, FIXP_DBL* RESTRICT pGain,
+ const INT* RESTRICT gain_scale,
+ const UINT gain_size, const UINT gain_delay,
+ const UINT nSamples) {
unsigned int i, j;
- FIXP_PCM tmp1, tmp2;
- FIXP_DBL tmp, old, gain, additionalGain, additionalGainUnfiltered;
- FIXP_DBL minGain = FL2FXCONST_DBL(1.0f/(1<<1));
+ FIXP_DBL tmp1;
+ FIXP_DBL tmp2;
+ FIXP_DBL tmp, old, gain, additionalGain = 0, additionalGainUnfiltered;
+ FIXP_DBL minGain = FL2FXCONST_DBL(1.0f / (1 << 1));
FDK_ASSERT(gain_size == 1);
FDK_ASSERT(gain_delay <= nSamples);
- if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
+ if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
{
- unsigned int channels = limiter->channels;
- unsigned int attack = limiter->attack;
- FIXP_DBL attackConst = limiter->attackConst;
- FIXP_DBL releaseConst = limiter->releaseConst;
- FIXP_DBL threshold = FX_PCM2FX_DBL(limiter->threshold)>>TDL_GAIN_SCALING;
-
- FIXP_DBL max = limiter->max;
- FIXP_DBL* maxBuf = limiter->maxBuf;
- unsigned int maxBufIdx = limiter->maxBufIdx;
- FIXP_DBL cor = limiter->cor;
- FIXP_DBL* delayBuf = limiter->delayBuf;
- unsigned int delayBufIdx = limiter->delayBufIdx;
-
- FIXP_DBL smoothState0 = limiter->smoothState0;
- FIXP_DBL additionalGainSmoothState = limiter->additionalGainFilterState;
- FIXP_DBL additionalGainSmoothState1 = limiter->additionalGainFilterState1;
-
- for (i = 0; i < nSamples; i++) {
-
- if (i < gain_delay) {
- additionalGainUnfiltered = limiter->additionalGainPrev;
- } else {
- additionalGainUnfiltered = pGain[0];
- }
-
- /* Smooth additionalGain */
- /* [b,a] = butter(1, 0.01) */
- static const FIXP_SGL b[] = { FL2FXCONST_SGL(0.015466*2.0), FL2FXCONST_SGL( 0.015466*2.0) };
- static const FIXP_SGL a[] = { FL2FXCONST_SGL(1.000000), FL2FXCONST_SGL(-0.96907) };
- /* [b,a] = butter(1, 0.001) */
- //static const FIXP_SGL b[] = { FL2FXCONST_SGL(0.0015683*2.0), FL2FXCONST_SGL( 0.0015683*2.0) };
- //static const FIXP_SGL a[] = { FL2FXCONST_SGL(1.0000000), FL2FXCONST_SGL(-0.99686) };
- additionalGain = - fMult(additionalGainSmoothState, a[1]) + fMultDiv2( additionalGainUnfiltered, b[0]) + fMultDiv2(additionalGainSmoothState1, b[1]);
- additionalGainSmoothState1 = additionalGainUnfiltered;
- additionalGainSmoothState = additionalGain;
-
- /* Apply the additional scaling that has no delay and no smoothing */
+ unsigned int channels = limiter->channels;
+ unsigned int attack = limiter->attack;
+ FIXP_DBL attackConst = limiter->attackConst;
+ FIXP_DBL releaseConst = limiter->releaseConst;
+ FIXP_DBL threshold = limiter->threshold;
+
+ FIXP_DBL max = limiter->max;
+ FIXP_DBL* maxBuf = limiter->maxBuf;
+ unsigned int maxBufIdx = limiter->maxBufIdx;
+ FIXP_DBL cor = limiter->cor;
+ FIXP_DBL* delayBuf = limiter->delayBuf;
+ unsigned int delayBufIdx = limiter->delayBufIdx;
+
+ FIXP_DBL smoothState0 = limiter->smoothState0;
+ FIXP_DBL additionalGainSmoothState = limiter->additionalGainFilterState;
+ FIXP_DBL additionalGainSmoothState1 = limiter->additionalGainFilterState1;
+
+ if (!gain_delay) {
+ additionalGain = pGain[0];
if (gain_scale[0] > 0) {
additionalGain <<= gain_scale[0];
} else {
- additionalGain >>= gain_scale[0];
+ additionalGain >>= -gain_scale[0];
}
+ }
+
+ for (i = 0; i < nSamples; i++) {
+ if (gain_delay) {
+ if (i < gain_delay) {
+ additionalGainUnfiltered = limiter->additionalGainPrev;
+ } else {
+ additionalGainUnfiltered = pGain[0];
+ }
- /* get maximum absolute sample value of all channels, including the additional gain. */
- tmp1 = (FIXP_PCM)0;
+ /* Smooth additionalGain */
+ /* [b,a] = butter(1, 0.01) */
+ static const FIXP_SGL b[] = {FL2FXCONST_SGL(0.015466 * 2.0),
+ FL2FXCONST_SGL(0.015466 * 2.0)};
+ static const FIXP_SGL a[] = {(FIXP_SGL)MAXVAL_SGL,
+ FL2FXCONST_SGL(-0.96907)};
+ additionalGain = -fMult(additionalGainSmoothState, a[1]) +
+ fMultDiv2(additionalGainUnfiltered, b[0]) +
+ fMultDiv2(additionalGainSmoothState1, b[1]);
+ additionalGainSmoothState1 = additionalGainUnfiltered;
+ additionalGainSmoothState = additionalGain;
+
+ /* Apply the additional scaling that has no delay and no smoothing */
+ if (gain_scale[0] > 0) {
+ additionalGain <<= gain_scale[0];
+ } else {
+ additionalGain >>= -gain_scale[0];
+ }
+ }
+ /* get maximum absolute sample value of all channels, including the
+ * additional gain. */
+ tmp1 = (FIXP_DBL)0;
for (j = 0; j < channels; j++) {
- tmp2 = (FIXP_PCM)samples[i * channels + j];
- if (tmp2 == (FIXP_PCM)SAMPLE_MIN) /* protect fAbs from -1.0 value */
- tmp2 = (FIXP_PCM)(SAMPLE_MIN+1);
- tmp1 = fMax(tmp1, fAbs(tmp2));
+ tmp2 = PCM_LIM2FIXP_DBL(samplesIn[j]);
+ tmp2 = fAbs(tmp2);
+ tmp2 = FIXP_DBL(INT(tmp2) ^ INT((tmp2 >> (SAMPLE_BITS_LIM - 1))));
+ tmp1 = fMax(tmp1, tmp2);
}
- tmp = SATURATE_LEFT_SHIFT(fMultDiv2(tmp1, additionalGain), 1, DFRACT_BITS);
+ tmp = fMult(tmp1, additionalGain);
- /* set threshold as lower border to save calculations in running maximum algorithm */
+ /* set threshold as lower border to save calculations in running maximum
+ * algorithm */
tmp = fMax(tmp, threshold);
/* running maximum */
@@ -295,75 +256,97 @@ TDLIMITER_ERROR applyLimiter(TDLimiterPtr limiter,
if (tmp >= max) {
/* new sample is greater than old maximum, so it is the new maximum */
max = tmp;
- }
- else if (old < max) {
+ } else if (old < max) {
/* maximum does not change, as the sample, which has left the window was
not the maximum */
- }
- else {
+ } else {
/* the old maximum has left the window, we have to search the complete
buffer for the new max */
max = maxBuf[0];
for (j = 1; j <= attack; j++) {
- if (maxBuf[j] > max) max = maxBuf[j];
+ max = fMax(max, maxBuf[j]);
}
}
maxBufIdx++;
- if (maxBufIdx >= attack+1) maxBufIdx = 0;
+ if (maxBufIdx >= attack + 1) maxBufIdx = 0;
/* calc gain */
/* gain is downscaled by one, so that gain = 1.0 can be represented */
if (max > threshold) {
- gain = fDivNorm(threshold, max)>>1;
- }
- else {
- gain = FL2FXCONST_DBL(1.0f/(1<<1));
+ gain = fDivNorm(threshold, max) >> 1;
+ } else {
+ gain = FL2FXCONST_DBL(1.0f / (1 << 1));
}
/* gain smoothing, method: TDL_EXPONENTIAL */
/* first order IIR filter with attack correction to avoid overshoots */
- /* correct the 'aiming' value of the exponential attack to avoid the remaining overshoot */
+ /* correct the 'aiming' value of the exponential attack to avoid the
+ * remaining overshoot */
if (gain < smoothState0) {
- cor = fMin(cor, fMultDiv2((gain - fMultDiv2(FL2FXCONST_SGL(0.1f*(1<<1)),smoothState0)), FL2FXCONST_SGL(1.11111111f/(1<<1)))<<2);
- }
- else {
+ cor = fMin(cor,
+ fMultDiv2((gain - fMultDiv2(FL2FXCONST_SGL(0.1f * (1 << 1)),
+ smoothState0)),
+ FL2FXCONST_SGL(1.11111111f / (1 << 1)))
+ << 2);
+ } else {
cor = gain;
}
/* smoothing filter */
if (cor < smoothState0) {
- smoothState0 = fMult(attackConst,(smoothState0 - cor)) + cor; /* attack */
+ smoothState0 =
+ fMult(attackConst, (smoothState0 - cor)) + cor; /* attack */
smoothState0 = fMax(smoothState0, gain); /* avoid overshooting target */
- }
- else {
+ } else {
/* sign inversion twice to round towards +infinity,
so that gain can converge to 1.0 again,
for bit-identical output when limiter is not active */
- smoothState0 = -fMult(releaseConst,-(smoothState0 - cor)) + cor; /* release */
+ smoothState0 =
+ -fMult(releaseConst, -(smoothState0 - cor)) + cor; /* release */
}
gain = smoothState0;
- /* lookahead delay, apply gain */
- for (j = 0; j < channels; j++) {
-
- tmp = delayBuf[delayBufIdx * channels + j];
- delayBuf[delayBufIdx * channels + j] = fMult((FIXP_PCM)samples[i * channels + j], additionalGain);
+ FIXP_DBL* p_delayBuf = &delayBuf[delayBufIdx * channels + 0];
+ if (gain < FL2FXCONST_DBL(1.0f / (1 << 1))) {
+ gain <<= 1;
+ /* lookahead delay, apply gain */
+ for (j = 0; j < channels; j++) {
+ tmp = p_delayBuf[j];
+ p_delayBuf[j] = fMult((FIXP_PCM_LIM)samplesIn[j], additionalGain);
- /* Apply gain to delayed signal */
- if (gain < FL2FXCONST_DBL(1.0f/(1<<1)))
- tmp = fMult(tmp,gain<<1);
+ /* Apply gain to delayed signal */
+ tmp = fMultDiv2(tmp, gain);
- samples[i * channels + j] = FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT(tmp,TDL_GAIN_SCALING,DFRACT_BITS));
+ samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT(
+ tmp, TDL_GAIN_SCALING + 1, DFRACT_BITS));
+ }
+ gain >>= 1;
+ } else {
+ /* lookahead delay, apply gain=1.0f */
+ for (j = 0; j < channels; j++) {
+ tmp = p_delayBuf[j];
+ p_delayBuf[j] = fMult((FIXP_PCM_LIM)samplesIn[j], additionalGain);
+ samplesOut[j] = (INT_PCM)FX_DBL2FX_PCM((FIXP_DBL)SATURATE_LEFT_SHIFT(
+ tmp, TDL_GAIN_SCALING, DFRACT_BITS));
+ }
}
+
delayBufIdx++;
- if (delayBufIdx >= attack) delayBufIdx = 0;
+ if (delayBufIdx >= attack) {
+ delayBufIdx = 0;
+ }
/* save minimum gain factor */
- if (gain < minGain) minGain = gain;
- }
+ if (gain < minGain) {
+ minGain = gain;
+ }
+ /* advance sample pointer by <channel> samples */
+ samplesIn += channels;
+ samplesOut += channels;
+ }
limiter->max = max;
limiter->maxBufIdx = maxBufIdx;
@@ -382,34 +365,99 @@ TDLIMITER_ERROR applyLimiter(TDLimiterPtr limiter,
}
}
+/* set limiter threshold */
+TDLIMITER_ERROR pcmLimiter_SetThreshold(TDLimiterPtr limiter,
+ FIXP_DBL threshold) {
+ if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
+
+ limiter->threshold = threshold >> TDL_GAIN_SCALING;
+
+ return TDLIMIT_OK;
+}
+
+/* reset limiter */
+TDLIMITER_ERROR pcmLimiter_Reset(TDLimiterPtr limiter) {
+ if (limiter != NULL) {
+ limiter->maxBufIdx = 0;
+ limiter->delayBufIdx = 0;
+ limiter->max = (FIXP_DBL)0;
+ limiter->cor = FL2FXCONST_DBL(1.0f / (1 << 1));
+ limiter->smoothState0 = FL2FXCONST_DBL(1.0f / (1 << 1));
+ limiter->minGain = FL2FXCONST_DBL(1.0f / (1 << 1));
+
+ limiter->additionalGainPrev =
+ FL2FXCONST_DBL(1.0f / (1 << TDL_GAIN_SCALING));
+ limiter->additionalGainFilterState =
+ FL2FXCONST_DBL(1.0f / (1 << TDL_GAIN_SCALING));
+ limiter->additionalGainFilterState1 =
+ FL2FXCONST_DBL(1.0f / (1 << TDL_GAIN_SCALING));
+
+ FDKmemset(limiter->maxBuf, 0, (limiter->attack + 1) * sizeof(FIXP_DBL));
+ FDKmemset(limiter->delayBuf, 0,
+ limiter->attack * limiter->channels * sizeof(FIXP_DBL));
+ } else {
+ return TDLIMIT_INVALID_HANDLE;
+ }
+
+ return TDLIMIT_OK;
+}
+
+/* destroy limiter */
+TDLIMITER_ERROR pcmLimiter_Destroy(TDLimiterPtr limiter) {
+ if (limiter != NULL) {
+ FDKfree(limiter->maxBuf);
+ FDKfree(limiter->delayBuf);
+
+ FDKfree(limiter);
+ } else {
+ return TDLIMIT_INVALID_HANDLE;
+ }
+ return TDLIMIT_OK;
+}
+
/* get delay in samples */
-unsigned int getLimiterDelay(TDLimiterPtr limiter)
-{
+unsigned int pcmLimiter_GetDelay(TDLimiterPtr limiter) {
FDK_ASSERT(limiter != NULL);
return limiter->attack;
}
+/* get maximum gain reduction of last processed block */
+INT pcmLimiter_GetMaxGainReduction(TDLimiterPtr limiter) {
+ /* maximum gain reduction in dB = -20 * log10(limiter->minGain)
+ = -20 * log2(limiter->minGain)/log2(10) = -6.0206*log2(limiter->minGain) */
+ int e_ans;
+ FIXP_DBL loggain, maxGainReduction;
+
+ FDK_ASSERT(limiter != NULL);
+
+ loggain = fLog2(limiter->minGain, 1, &e_ans);
+
+ maxGainReduction = fMult(loggain, FL2FXCONST_DBL(-6.0206f / (1 << 3)));
+
+ return fixp_roundToInt(maxGainReduction, (e_ans + 3));
+}
+
/* set number of channels */
-TDLIMITER_ERROR setLimiterNChannels(TDLimiterPtr limiter, unsigned int nChannels)
-{
- if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
+TDLIMITER_ERROR pcmLimiter_SetNChannels(TDLimiterPtr limiter,
+ unsigned int nChannels) {
+ if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
if (nChannels > limiter->maxChannels) return TDLIMIT_INVALID_PARAMETER;
limiter->channels = nChannels;
- //resetLimiter(limiter);
+ // pcmLimiter_Reset(limiter);
return TDLIMIT_OK;
}
/* set sampling rate */
-TDLIMITER_ERROR setLimiterSampleRate(TDLimiterPtr limiter, unsigned int sampleRate)
-{
+TDLIMITER_ERROR pcmLimiter_SetSampleRate(TDLimiterPtr limiter,
+ UINT sampleRate) {
unsigned int attack, release;
FIXP_DBL attackConst, releaseConst, exponent;
INT e_ans;
- if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
+ if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
if (sampleRate > limiter->maxSampleRate) return TDLIMIT_INVALID_PARAMETER;
@@ -418,7 +466,7 @@ TDLIMITER_ERROR setLimiterSampleRate(TDLimiterPtr limiter, unsigned int sampleRa
release = (unsigned int)(limiter->releaseMs * sampleRate / 1000);
/* attackConst = pow(0.1, 1.0 / (attack + 1)) */
- exponent = invFixp(attack+1);
+ exponent = invFixp(attack + 1);
attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
attackConst = scaleValue(attackConst, e_ans);
@@ -427,25 +475,25 @@ TDLIMITER_ERROR setLimiterSampleRate(TDLimiterPtr limiter, unsigned int sampleRa
releaseConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
releaseConst = scaleValue(releaseConst, e_ans);
- limiter->attack = attack;
- limiter->attackConst = attackConst;
- limiter->releaseConst = releaseConst;
- limiter->sampleRate = sampleRate;
+ limiter->attack = attack;
+ limiter->attackConst = attackConst;
+ limiter->releaseConst = releaseConst;
+ limiter->sampleRate = sampleRate;
/* reset */
- //resetLimiter(limiter);
+ // pcmLimiter_Reset(limiter);
return TDLIMIT_OK;
}
/* set attack time */
-TDLIMITER_ERROR setLimiterAttack(TDLimiterPtr limiter, unsigned int attackMs)
-{
+TDLIMITER_ERROR pcmLimiter_SetAttack(TDLimiterPtr limiter,
+ unsigned int attackMs) {
unsigned int attack;
FIXP_DBL attackConst, exponent;
INT e_ans;
- if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
+ if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
if (attackMs > limiter->maxAttackMs) return TDLIMIT_INVALID_PARAMETER;
@@ -453,25 +501,25 @@ TDLIMITER_ERROR setLimiterAttack(TDLimiterPtr limiter, unsigned int attackMs)
attack = (unsigned int)(attackMs * limiter->sampleRate / 1000);
/* attackConst = pow(0.1, 1.0 / (attack + 1)) */
- exponent = invFixp(attack+1);
+ exponent = invFixp(attack + 1);
attackConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
attackConst = scaleValue(attackConst, e_ans);
- limiter->attack = attack;
- limiter->attackConst = attackConst;
- limiter->attackMs = attackMs;
+ limiter->attack = attack;
+ limiter->attackConst = attackConst;
+ limiter->attackMs = attackMs;
return TDLIMIT_OK;
}
/* set release time */
-TDLIMITER_ERROR setLimiterRelease(TDLimiterPtr limiter, unsigned int releaseMs)
-{
+TDLIMITER_ERROR pcmLimiter_SetRelease(TDLimiterPtr limiter,
+ unsigned int releaseMs) {
unsigned int release;
FIXP_DBL releaseConst, exponent;
INT e_ans;
- if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
+ if (limiter == NULL) return TDLIMIT_INVALID_HANDLE;
/* calculate release time in samples */
release = (unsigned int)(releaseMs * limiter->sampleRate / 1000);
@@ -481,18 +529,42 @@ TDLIMITER_ERROR setLimiterRelease(TDLimiterPtr limiter, unsigned int releaseMs)
releaseConst = fPow(FL2FXCONST_DBL(0.1f), 0, exponent, 0, &e_ans);
releaseConst = scaleValue(releaseConst, e_ans);
- limiter->releaseConst = releaseConst;
- limiter->releaseMs = releaseMs;
+ limiter->releaseConst = releaseConst;
+ limiter->releaseMs = releaseMs;
return TDLIMIT_OK;
}
-/* set limiter threshold */
-TDLIMITER_ERROR setLimiterThreshold(TDLimiterPtr limiter, INT_PCM threshold)
-{
- if ( limiter == NULL ) return TDLIMIT_INVALID_HANDLE;
+/* Get library info for this module. */
+TDLIMITER_ERROR pcmLimiter_GetLibInfo(LIB_INFO* info) {
+ int i;
+
+ if (info == NULL) {
+ return TDLIMIT_INVALID_PARAMETER;
+ }
+
+ /* 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 TDLIMIT_UNKNOWN;
+ }
+
+ /* Add the library info */
+ info[i].module_id = FDK_TDLIMIT;
+ info[i].version =
+ LIB_VERSION(PCMUTIL_LIB_VL0, PCMUTIL_LIB_VL1, PCMUTIL_LIB_VL2);
+ LIB_VERSION_STRING(info + i);
+ info[i].build_date = PCMUTIL_LIB_BUILD_DATE;
+ info[i].build_time = PCMUTIL_LIB_BUILD_TIME;
+ info[i].title = TDLIMIT_LIB_TITLE;
+
+ /* Set flags */
+ info[i].flags = CAPF_LIMITER;
- limiter->threshold = (FIXP_PCM)threshold;
+ /* Add lib info for FDK tools (if not yet done). */
+ FDK_toolsGetLibInfo(info);
return TDLIMIT_OK;
}
diff --git a/libPCMutils/src/pcm_utils.cpp b/libPCMutils/src/pcm_utils.cpp
new file mode 100644
index 0000000..5dd18d9
--- /dev/null
+++ b/libPCMutils/src/pcm_utils.cpp
@@ -0,0 +1,195 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** PCM utility library ******************************
+
+ Author(s): Arthur Tritthart, Alfonso Pino Garcia
+
+ Description: Functions that perform (de)interleaving combined with format
+change
+
+*******************************************************************************/
+
+#include "pcm_utils.h"
+
+/* library version */
+#include "version.h"
+
+void FDK_interleave(const FIXP_DBL *RESTRICT pIn, LONG *RESTRICT pOut,
+ const UINT channels, const UINT frameSize,
+ const UINT length) {
+ for (UINT sample = 0; sample < length; sample++) {
+ const FIXP_DBL *In = &pIn[sample];
+ for (UINT ch = 0; ch < channels; ch++) {
+ *pOut++ = (LONG)In[0];
+ In += frameSize;
+ }
+ }
+}
+
+void FDK_interleave(const FIXP_DBL *RESTRICT pIn, SHORT *RESTRICT pOut,
+ const UINT channels, const UINT frameSize,
+ const UINT length) {
+ for (UINT sample = 0; sample < length; sample++) {
+ const FIXP_DBL *In = &pIn[sample];
+ for (UINT ch = 0; ch < channels; ch++) {
+ *pOut++ = (SHORT)FX_DBL2FX_SGL(In[0]);
+ In += frameSize;
+ }
+ }
+}
+
+void FDK_interleave(const FIXP_SGL *RESTRICT pIn, SHORT *RESTRICT pOut,
+ const UINT channels, const UINT frameSize,
+ const UINT length) {
+ for (UINT sample = 0; sample < length; sample++) {
+ const FIXP_SGL *In = &pIn[sample];
+ for (UINT ch = 0; ch < channels; ch++) {
+ *pOut++ = (SHORT)In[0];
+ In += frameSize;
+ }
+ }
+}
+
+void FDK_deinterleave(const LONG *RESTRICT pIn, SHORT *RESTRICT _pOut,
+ const UINT channels, const UINT frameSize,
+ const UINT length) {
+ for (UINT ch = 0; ch < channels; ch++) {
+ SHORT *pOut = _pOut + length * ch;
+ const LONG *In = &pIn[ch];
+ for (UINT sample = 0; sample < frameSize; sample++) {
+ *pOut++ = (SHORT)(In[0] >> 16);
+ In += channels;
+ }
+ }
+}
+
+void FDK_deinterleave(const LONG *RESTRICT pIn, LONG *RESTRICT _pOut,
+ const UINT channels, const UINT frameSize,
+ const UINT length) {
+ for (UINT ch = 0; ch < channels; ch++) {
+ LONG *pOut = _pOut + length * ch;
+ const LONG *In = &pIn[ch];
+ for (UINT sample = 0; sample < frameSize; sample++) {
+ *pOut++ = In[0];
+ In += channels;
+ }
+ }
+}
+
+void FDK_deinterleave(const SHORT *RESTRICT pIn, SHORT *RESTRICT _pOut,
+ const UINT channels, const UINT frameSize,
+ const UINT length) {
+ for (UINT ch = 0; ch < channels; ch++) {
+ SHORT *pOut = _pOut + length * ch;
+ const SHORT *In = &pIn[ch];
+ for (UINT sample = 0; sample < frameSize; sample++) {
+ *pOut++ = In[0];
+ In += channels;
+ }
+ }
+}
+
+void FDK_deinterleave(const SHORT *RESTRICT pIn, LONG *RESTRICT _pOut,
+ const UINT channels, const UINT frameSize,
+ const UINT length) {
+ for (UINT ch = 0; ch < channels; ch++) {
+ LONG *pOut = _pOut + length * ch;
+ const SHORT *In = &pIn[ch];
+ for (UINT sample = 0; sample < frameSize; sample++) {
+ *pOut++ = (LONG)In[0] << 16;
+ In += channels;
+ }
+ }
+}
diff --git a/libPCMutils/src/pcmdmx_lib.cpp b/libPCMutils/src/pcmdmx_lib.cpp
new file mode 100644
index 0000000..b09a848
--- /dev/null
+++ b/libPCMutils/src/pcmdmx_lib.cpp
@@ -0,0 +1,2659 @@
+/* -----------------------------------------------------------------------------
+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
+----------------------------------------------------------------------------- */
+
+/**************************** PCM utility library ******************************
+
+ Author(s): Christian Griebel
+
+ Description: Defines functions that perform downmixing or a simple channel
+ expansion in the PCM time domain.
+
+*******************************************************************************/
+
+#include "pcmdmx_lib.h"
+
+#include "genericStds.h"
+#include "fixpoint_math.h"
+#include "FDK_core.h"
+
+/* library version */
+#include "version.h"
+/* library title */
+#define PCMDMX_LIB_TITLE "PCM Downmix Lib"
+
+#define FALSE 0
+#define TRUE 1
+#define IN 0
+#define OUT 1
+
+/* Type definitions: */
+#define FIXP_DMX FIXP_SGL
+#define FX_DMX2FX_DBL(x) FX_SGL2FX_DBL((FIXP_SGL)(x))
+#define FX_DBL2FX_DMX(x) FX_DBL2FX_SGL(x)
+#define FL2FXCONST_DMX(x) FL2FXCONST_SGL(x)
+#define MAXVAL_DMX MAXVAL_SGL
+#define FX_DMX2SHRT(x) ((SHORT)(x))
+#define FX_DMX2FL(x) FX_DBL2FL(FX_DMX2FX_DBL(x))
+
+/* Fixed and unique channel group indices.
+ * The last group index has to be smaller than ( 4 ). */
+#define CH_GROUP_FRONT (0)
+#define CH_GROUP_SIDE (1)
+#define CH_GROUP_REAR (2)
+#define CH_GROUP_LFE (3)
+
+/* Fixed and unique channel plain indices. */
+#define CH_PLAIN_NORMAL (0)
+#define CH_PLAIN_TOP (1)
+#define CH_PLAIN_BOTTOM (2)
+
+/* The ordering of the following fixed channel labels has to be in MPEG-4 style.
+ * From the center to the back with left and right channel interleaved (starting
+ * with left). The last channel label index has to be smaller than ( 8 ). */
+#define CENTER_FRONT_CHANNEL (0) /* C */
+#define LEFT_FRONT_CHANNEL (1) /* L */
+#define RIGHT_FRONT_CHANNEL (2) /* R */
+#define LEFT_REAR_CHANNEL \
+ (3) /* Lr (aka left back channel) or center back channel */
+#define RIGHT_REAR_CHANNEL (4) /* Rr (aka right back channel) */
+#define LOW_FREQUENCY_CHANNEL (5) /* Lf */
+#define LEFT_MULTIPRPS_CHANNEL (6) /* Left multipurpose channel */
+#define RIGHT_MULTIPRPS_CHANNEL (7) /* Right multipurpose channel */
+
+/* 22.2 channel specific fixed channel lables: */
+#define LEFT_SIDE_CHANNEL (8) /* Lss */
+#define RIGHT_SIDE_CHANNEL (9) /* Rss */
+#define CENTER_REAR_CHANNEL (10) /* Cs */
+#define CENTER_FRONT_CHANNEL_TOP (11) /* Cv */
+#define LEFT_FRONT_CHANNEL_TOP (12) /* Lv */
+#define RIGHT_FRONT_CHANNEL_TOP (13) /* Rv */
+#define LEFT_SIDE_CHANNEL_TOP (14) /* Lvss */
+#define RIGHT_SIDE_CHANNEL_TOP (15) /* Rvss */
+#define CENTER_SIDE_CHANNEL_TOP (16) /* Ts */
+#define LEFT_REAR_CHANNEL_TOP (17) /* Lvr */
+#define RIGHT_REAR_CHANNEL_TOP (18) /* Rvr */
+#define CENTER_REAR_CHANNEL_TOP (19) /* Cvr */
+#define CENTER_FRONT_CHANNEL_BOTTOM (20) /* Cb */
+#define LEFT_FRONT_CHANNEL_BOTTOM (21) /* Lb */
+#define RIGHT_FRONT_CHANNEL_BOTTOM (22) /* Rb */
+#define LOW_FREQUENCY_CHANNEL_2 (23) /* LFE2 */
+
+/* More constants */
+#define ONE_CHANNEL (1)
+#define TWO_CHANNEL (2)
+#define SIX_CHANNEL (6)
+#define EIGHT_CHANNEL (8)
+#define TWENTY_FOUR_CHANNEL (24)
+
+#define PCMDMX_THRESHOLD_MAP_HEAT_1 (0) /* Store only exact matches */
+#define PCMDMX_THRESHOLD_MAP_HEAT_2 (20)
+#define PCMDMX_THRESHOLD_MAP_HEAT_3 \
+ (256) /* Do not assign normal channels to LFE */
+
+#define SP_Z_NRM (0)
+#define SP_Z_TOP (2)
+#define SP_Z_BOT (-2)
+#define SP_Z_LFE (-18)
+#define SP_Z_MUL (8) /* Should be smaller than SP_Z_LFE */
+
+typedef struct {
+ SCHAR x; /* horizontal position: center (0), left (-), right (+) */
+ SCHAR y; /* deepth position: front, side, back, position */
+ SCHAR z; /* heigth positions: normal, top, bottom, lfe */
+} PCM_DMX_SPEAKER_POSITION;
+
+/* CAUTION: The maximum x-value should be less or equal to
+ * PCMDMX_SPKR_POS_X_MAX_WIDTH. */
+static const PCM_DMX_SPEAKER_POSITION spkrSlotPos[] = {
+ /* x, y, z */
+ {0, 0, SP_Z_NRM}, /* 0 CENTER_FRONT_CHANNEL */
+ {-2, 0, SP_Z_NRM}, /* 1 LEFT_FRONT_CHANNEL */
+ {2, 0, SP_Z_NRM}, /* 2 RIGHT_FRONT_CHANNEL */
+ {-3, 4, SP_Z_NRM}, /* 3 LEFT_REAR_CHANNEL */
+ {3, 4, SP_Z_NRM}, /* 4 RIGHT_REAR_CHANNEL */
+ {0, 0, SP_Z_LFE}, /* 5 LOW_FREQUENCY_CHANNEL */
+ {-2, 2, SP_Z_MUL}, /* 6 LEFT_MULTIPRPS_CHANNEL */
+ {2, 2, SP_Z_MUL} /* 7 RIGHT_MULTIPRPS_CHANNEL */
+};
+
+/* List of packed channel modes */
+typedef enum { /* CH_MODE_<numFrontCh>_<numSideCh>_<numBackCh>_<numLfCh> */
+ CH_MODE_UNDEFINED = 0x0000,
+ /* 1 channel */
+ CH_MODE_1_0_0_0 = 0x0001, /* chCfg 1 */
+ /* 2 channels */
+ CH_MODE_2_0_0_0 = 0x0002 /* chCfg 2 */
+ /* 3 channels */
+ ,
+ CH_MODE_3_0_0_0 = 0x0003, /* chCfg 3 */
+ CH_MODE_2_0_1_0 = 0x0102,
+ CH_MODE_2_0_0_1 = 0x1002,
+ /* 4 channels */
+ CH_MODE_3_0_1_0 = 0x0103, /* chCfg 4 */
+ CH_MODE_2_0_2_0 = 0x0202,
+ CH_MODE_2_0_1_1 = 0x1102,
+ CH_MODE_4_0_0_0 = 0x0004,
+ /* 5 channels */
+ CH_MODE_3_0_2_0 = 0x0203, /* chCfg 5 */
+ CH_MODE_2_0_2_1 = 0x1202,
+ CH_MODE_3_0_1_1 = 0x1103,
+ CH_MODE_3_2_0_0 = 0x0023,
+ CH_MODE_5_0_0_0 = 0x0005,
+ /* 6 channels */
+ CH_MODE_3_0_2_1 = 0x1203, /* chCfg 6 */
+ CH_MODE_3_2_0_1 = 0x1023,
+ CH_MODE_3_2_1_0 = 0x0123,
+ CH_MODE_5_0_1_0 = 0x0105,
+ CH_MODE_6_0_0_0 = 0x0006,
+ /* 7 channels */
+ CH_MODE_2_2_2_1 = 0x1222,
+ CH_MODE_3_0_3_1 = 0x1303, /* chCfg 11 */
+ CH_MODE_3_2_1_1 = 0x1123,
+ CH_MODE_3_2_2_0 = 0x0223,
+ CH_MODE_3_0_2_2 = 0x2203,
+ CH_MODE_5_0_2_0 = 0x0205,
+ CH_MODE_5_0_1_1 = 0x1105,
+ CH_MODE_7_0_0_0 = 0x0007,
+ /* 8 channels */
+ CH_MODE_3_2_2_1 = 0x1223,
+ CH_MODE_3_0_4_1 = 0x1403, /* chCfg 12 */
+ CH_MODE_5_0_2_1 = 0x1205, /* chCfg 7 + 14 */
+ CH_MODE_5_2_1_0 = 0x0125,
+ CH_MODE_3_2_1_2 = 0x2123,
+ CH_MODE_2_2_2_2 = 0x2222,
+ CH_MODE_3_0_3_2 = 0x2303,
+ CH_MODE_8_0_0_0 = 0x0008
+
+} PCM_DMX_CHANNEL_MODE;
+
+/* These are the channel configurations linked to
+ the number of output channels give by the user: */
+static const PCM_DMX_CHANNEL_MODE outChModeTable[(8) + 1] = {
+ CH_MODE_UNDEFINED,
+ CH_MODE_1_0_0_0, /* 1 channel */
+ CH_MODE_2_0_0_0 /* 2 channels */
+ ,
+ CH_MODE_3_0_0_0, /* 3 channels */
+ CH_MODE_3_0_1_0, /* 4 channels */
+ CH_MODE_3_0_2_0, /* 5 channels */
+ CH_MODE_3_0_2_1 /* 6 channels */
+ ,
+ CH_MODE_3_0_3_1, /* 7 channels */
+ CH_MODE_3_0_4_1 /* 8 channels */
+};
+
+static const FIXP_DMX abMixLvlValueTab[8] = {
+ FL2FXCONST_DMX(0.500f), /* scaled by 1 */
+ FL2FXCONST_DMX(0.841f), FL2FXCONST_DMX(0.707f), FL2FXCONST_DMX(0.596f),
+ FL2FXCONST_DMX(0.500f), FL2FXCONST_DMX(0.422f), FL2FXCONST_DMX(0.355f),
+ FL2FXCONST_DMX(0.0f)};
+
+static const FIXP_DMX lfeMixLvlValueTab[16] = {
+ /* value, scale */
+ FL2FXCONST_DMX(0.7905f), /* 2 */
+ FL2FXCONST_DMX(0.5000f), /* 2 */
+ FL2FXCONST_DMX(0.8395f), /* 1 */
+ FL2FXCONST_DMX(0.7065f), /* 1 */
+ FL2FXCONST_DMX(0.5945f), /* 1 */
+ FL2FXCONST_DMX(0.500f), /* 1 */
+ FL2FXCONST_DMX(0.841f), /* 0 */
+ FL2FXCONST_DMX(0.707f), /* 0 */
+ FL2FXCONST_DMX(0.596f), /* 0 */
+ FL2FXCONST_DMX(0.500f), /* 0 */
+ FL2FXCONST_DMX(0.316f), /* 0 */
+ FL2FXCONST_DMX(0.178f), /* 0 */
+ FL2FXCONST_DMX(0.100f), /* 0 */
+ FL2FXCONST_DMX(0.032f), /* 0 */
+ FL2FXCONST_DMX(0.010f), /* 0 */
+ FL2FXCONST_DMX(0.000f) /* 0 */
+};
+
+/* MPEG matrix mixdown:
+ Set 1: L' = (1 + 2^-0.5 + A )^-1 * [L + C * 2^-0.5 + A * Ls];
+ R' = (1 + 2^-0.5 + A )^-1 * [R + C * 2^-0.5 + A * Rs];
+
+ Set 2: L' = (1 + 2^-0.5 + 2A )^-1 * [L + C * 2^-0.5 - A * (Ls + Rs)];
+ R' = (1 + 2^-0.5 + 2A )^-1 * [R + C * 2^-0.5 + A * (Ls + Rs)];
+
+ M = (3 + 2A)^-1 * [L + C + R + A*(Ls + Rs)];
+*/
+static const FIXP_DMX mpegMixDownIdx2Coef[4] = {
+ FL2FXCONST_DMX(0.70710678f), FL2FXCONST_DMX(0.5f),
+ FL2FXCONST_DMX(0.35355339f), FL2FXCONST_DMX(0.0f)};
+
+static const FIXP_DMX mpegMixDownIdx2PreFact[3][4] = {
+ {/* Set 1: */
+ FL2FXCONST_DMX(0.4142135623730950f), FL2FXCONST_DMX(0.4530818393219728f),
+ FL2FXCONST_DMX(0.4852813742385703f), FL2FXCONST_DMX(0.5857864376269050f)},
+ {/* Set 2: */
+ FL2FXCONST_DMX(0.3203772410170407f), FL2FXCONST_DMX(0.3693980625181293f),
+ FL2FXCONST_DMX(0.4142135623730950f), FL2FXCONST_DMX(0.5857864376269050f)},
+ {/* Mono DMX set: */
+ FL2FXCONST_DMX(0.2265409196609864f), FL2FXCONST_DMX(0.25f),
+ FL2FXCONST_DMX(0.2697521433898179f), FL2FXCONST_DMX(0.3333333333333333f)}};
+
+#define TYPE_NONE (0x00)
+#define TYPE_PCE_DATA (0x01)
+#define TYPE_DSE_CLEV_DATA (0x02)
+#define TYPE_DSE_SLEV_DATA (0x04)
+#define TYPE_DSE_DMIX_AB_DATA (0x08)
+#define TYPE_DSE_DMIX_LFE_DATA (0x10)
+#define TYPE_DSE_DMX_GAIN_DATA (0x20)
+#define TYPE_DSE_DMX_CGL_DATA (0x40)
+#define TYPE_DSE_DATA (0x7E)
+
+typedef struct {
+ UINT typeFlags;
+ /* From DSE */
+ UCHAR cLevIdx;
+ UCHAR sLevIdx;
+ UCHAR dmixIdxA;
+ UCHAR dmixIdxB;
+ UCHAR dmixIdxLfe;
+ UCHAR dmxGainIdx2;
+ UCHAR dmxGainIdx5;
+ /* From PCE */
+ UCHAR matrixMixdownIdx;
+ /* Attributes: */
+ SCHAR pseudoSurround; /*!< If set to 1 the signal is pseudo surround
+ compatible. The value 0 tells that it is not. If the
+ value is -1 the information is not available. */
+ UINT expiryCount; /*!< Counter to monitor the life time of a meta data set. */
+
+} DMX_BS_META_DATA;
+
+/* Default metadata */
+static const DMX_BS_META_DATA dfltMetaData = {0, 2, 2, 2, 2, 15,
+ 0, 0, 0, -1, 0};
+
+/* Dynamic (user) params:
+ See the definition of PCMDMX_PARAM for details on the specific fields. */
+typedef struct {
+ DMX_PROFILE_TYPE dmxProfile; /*!< Linked to DMX_PRFL_STANDARD */
+ UINT expiryFrame; /*!< Linked to DMX_BS_DATA_EXPIRY_FRAME */
+ DUAL_CHANNEL_MODE dualChannelMode; /*!< Linked to DMX_DUAL_CHANNEL_MODE */
+ PSEUDO_SURROUND_MODE
+ pseudoSurrMode; /*!< Linked to DMX_PSEUDO_SURROUND_MODE */
+ SHORT numOutChannelsMin; /*!< Linked to MIN_NUMBER_OF_OUTPUT_CHANNELS */
+ SHORT numOutChannelsMax; /*!< Linked to MAX_NUMBER_OF_OUTPUT_CHANNELS */
+ UCHAR frameDelay; /*!< Linked to DMX_BS_DATA_DELAY */
+
+} PCM_DMX_USER_PARAMS;
+
+/* Modules main data structure: */
+struct PCM_DMX_INSTANCE {
+ /* Metadata */
+ DMX_BS_META_DATA bsMetaData[(1) + 1];
+ PCM_DMX_USER_PARAMS userParams;
+
+ UCHAR applyProcessing; /*!< Flag to en-/disable modules processing.
+ The max channel limiting is done independently. */
+};
+
+/* Memory allocation macro */
+C_ALLOC_MEM(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1)
+
+static UINT getSpeakerDistance(PCM_DMX_SPEAKER_POSITION posA,
+ PCM_DMX_SPEAKER_POSITION posB) {
+ PCM_DMX_SPEAKER_POSITION diff;
+
+ diff.x = posA.x - posB.x;
+ diff.y = posA.y - posB.y;
+ diff.z = posA.z - posB.z;
+
+ return ((diff.x * diff.x) + (diff.y * diff.y) + (diff.z * diff.z));
+}
+
+static PCM_DMX_SPEAKER_POSITION getSpeakerPos(AUDIO_CHANNEL_TYPE chType,
+ UCHAR chIndex, UCHAR numChInGrp) {
+#define PCMDMX_SPKR_POS_X_MAX_WIDTH (3)
+#define PCMDMX_SPKR_POS_Y_SPREAD (2)
+#define PCMDMX_SPKR_POS_Z_SPREAD (2)
+
+ PCM_DMX_SPEAKER_POSITION spkrPos = {0, 0, 0};
+ AUDIO_CHANNEL_TYPE chGrp = (AUDIO_CHANNEL_TYPE)(chType & 0x0F);
+ unsigned fHasCenter = numChInGrp & 0x1;
+ unsigned chGrpWidth = numChInGrp >> 1;
+ unsigned fIsCenter = 0;
+ unsigned fIsLfe = (chType == ACT_LFE) ? 1 : 0;
+ int offset = 0;
+
+ FDK_ASSERT(chIndex < numChInGrp);
+
+ if ((chGrp == ACT_FRONT) && fHasCenter) {
+ if (chIndex == 0) fIsCenter = 1;
+ chIndex = (UCHAR)fMax(0, chIndex - 1);
+ } else if (fHasCenter && (chIndex == numChInGrp - 1)) {
+ fIsCenter = 1;
+ }
+ /* now all even indices are left (-) */
+ if (!fIsCenter) {
+ offset = chIndex >> 1;
+ if ((chGrp > ACT_FRONT) && (chType != ACT_SIDE) && !fIsLfe) {
+ /* the higher the index the lower the distance to the center position */
+ offset = chGrpWidth - fHasCenter - offset;
+ }
+ if ((chIndex & 0x1) == 0) { /* even */
+ offset = -(offset + 1);
+ } else {
+ offset += 1;
+ }
+ }
+ /* apply the offset */
+ if (chType == ACT_SIDE) {
+ spkrPos.x = (offset < 0) ? -PCMDMX_SPKR_POS_X_MAX_WIDTH
+ : PCMDMX_SPKR_POS_X_MAX_WIDTH;
+ spkrPos.y = /* 1x */ PCMDMX_SPKR_POS_Y_SPREAD + (SCHAR)fAbs(offset) - 1;
+ spkrPos.z = 0;
+ } else {
+ unsigned spread =
+ ((chGrpWidth == 1) && (!fIsLfe)) ? PCMDMX_SPKR_POS_X_MAX_WIDTH - 1 : 1;
+ spkrPos.x = (SCHAR)offset * (SCHAR)spread;
+ if (fIsLfe) {
+ spkrPos.y = 0;
+ spkrPos.z = SP_Z_LFE;
+ } else {
+ spkrPos.y = (SCHAR)fMax((SCHAR)chGrp - 1, 0) * PCMDMX_SPKR_POS_Y_SPREAD;
+ spkrPos.z = (SCHAR)chType >> 4;
+ if (spkrPos.z == 2) { /* ACT_BOTTOM */
+ spkrPos.z = -1;
+ }
+ spkrPos.z *= PCMDMX_SPKR_POS_Z_SPREAD;
+ }
+ }
+ return spkrPos;
+}
+
+/** Return the channel mode of a given horizontal channel plain (normal, top,
+ *bottom) for a given channel configuration. NOTE: This function shall get
+ *obsolete once the channel mode has been changed to be nonambiguous.
+ * @param [in] Index of the requested channel plain.
+ * @param [in] The packed channel mode for the complete channel configuration
+ *(all plains).
+ * @param [in] The MPEG-4 channel configuration index which is necessary in
+ *cases where the (packed) channel mode is ambiguous.
+ * @returns Returns the packed channel mode of the requested channel plain.
+ **/
+static PCM_DMX_CHANNEL_MODE getChMode4Plain(
+ const int plainIndex, const PCM_DMX_CHANNEL_MODE totChMode,
+ const int chCfg) {
+ PCM_DMX_CHANNEL_MODE plainChMode = totChMode;
+
+ switch (totChMode) {
+ case CH_MODE_5_0_2_1:
+ if (chCfg == 14) {
+ switch (plainIndex) {
+ case CH_PLAIN_BOTTOM:
+ plainChMode = (PCM_DMX_CHANNEL_MODE)0x0000;
+ break;
+ case CH_PLAIN_TOP:
+ plainChMode = CH_MODE_2_0_0_0;
+ break;
+ case CH_PLAIN_NORMAL:
+ default:
+ plainChMode = CH_MODE_3_0_2_1;
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return plainChMode;
+}
+
+static inline UINT getIdxSum(UCHAR numCh) {
+ UINT result = 0;
+ int i;
+ for (i = 1; i < numCh; i += 1) {
+ result += i;
+ }
+ return result;
+}
+
+/** Evaluate a given channel configuration and extract a packed channel mode. In
+ *addition the function generates a channel offset table for the mapping to the
+ *internal representation. This function is the inverse to the
+ *getChannelDescription() routine.
+ * @param [in] The total number of channels of the given configuration.
+ * @param [in] Array holding the corresponding channel types for each channel.
+ * @param [in] Array holding the corresponding channel type indices for each
+ *channel.
+ * @param [out] Array where the buffer offsets for each channel are stored into.
+ * @param [out] The generated packed channel mode that represents the given
+ *input configuration.
+ * @returns Returns an error code.
+ **/
+static PCMDMX_ERROR getChannelMode(
+ const UINT numChannels, /* in */
+ const AUDIO_CHANNEL_TYPE channelType[], /* in */
+ UCHAR channelIndices[], /* in */
+ UCHAR offsetTable[(8)], /* out */
+ PCM_DMX_CHANNEL_MODE *chMode /* out */
+) {
+ UINT idxSum[(3)][(4)];
+ UCHAR numCh[(3)][(4)];
+ UCHAR mapped[(8)];
+ PCM_DMX_SPEAKER_POSITION spkrPos[(8)];
+ PCMDMX_ERROR err = PCMDMX_OK;
+ unsigned ch, numMappedInChs = 0;
+ unsigned startSlot;
+ unsigned stopSlot = LOW_FREQUENCY_CHANNEL;
+
+ FDK_ASSERT(channelType != NULL);
+ FDK_ASSERT(channelIndices != NULL);
+ FDK_ASSERT(offsetTable != NULL);
+ FDK_ASSERT(chMode != NULL);
+
+ /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */
+ FDKmemclear(idxSum, (3) * (4) * sizeof(UINT));
+ FDKmemclear(numCh, (3) * (4) * sizeof(UCHAR));
+ FDKmemclear(mapped, (8) * sizeof(UCHAR));
+ FDKmemclear(spkrPos, (8) * sizeof(PCM_DMX_SPEAKER_POSITION));
+ /* Init output */
+ FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
+ *chMode = CH_MODE_UNDEFINED;
+
+ /* Determine how many channels are assigned to each channels each group: */
+ for (ch = 0; ch < numChannels; ch += 1) {
+ unsigned chGrp = fMax(
+ (channelType[ch] & 0x0F) - 1,
+ 0); /* Assign all undefined channels (ACT_NONE) to front channels. */
+ numCh[channelType[ch] >> 4][chGrp] += 1;
+ idxSum[channelType[ch] >> 4][chGrp] += channelIndices[ch];
+ }
+ if (numChannels > TWO_CHANNEL) {
+ int chGrp;
+ /* Sanity check on the indices */
+ for (chGrp = 0; chGrp < (4); chGrp += 1) {
+ int plane;
+ for (plane = 0; plane < (3); plane += 1) {
+ if (idxSum[plane][chGrp] != getIdxSum(numCh[plane][chGrp])) {
+ unsigned idxCnt = 0;
+ for (ch = 0; ch < numChannels; ch += 1) {
+ if (channelType[ch] ==
+ (AUDIO_CHANNEL_TYPE)((plane << 4) | ((chGrp + 1) & 0xF))) {
+ channelIndices[ch] = idxCnt++;
+ }
+ }
+ err = PCMDMX_INVALID_CH_CONFIG;
+ }
+ }
+ }
+ }
+ /* Mapping HEAT 1:
+ * Determine the speaker position of each input channel and map it to a
+ * internal slot if it matches exactly (with zero distance). */
+ for (ch = 0; ch < numChannels; ch += 1) {
+ UINT mapDist = (unsigned)-1;
+ unsigned mapCh, mapPos = (unsigned)-1;
+ unsigned chGrp = fMax(
+ (channelType[ch] & 0x0F) - 1,
+ 0); /* Assign all undefined channels (ACT_NONE) to front channels. */
+
+ spkrPos[ch] = getSpeakerPos(channelType[ch], channelIndices[ch],
+ numCh[channelType[ch] >> 4][chGrp]);
+
+ for (mapCh = 0; mapCh <= stopSlot; mapCh += 1) {
+ if (offsetTable[mapCh] == 255) {
+ UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
+ if (dist < mapDist) {
+ mapPos = mapCh;
+ mapDist = dist;
+ }
+ }
+ }
+ if (mapDist <= PCMDMX_THRESHOLD_MAP_HEAT_1) {
+ offsetTable[mapPos] = (UCHAR)ch;
+ mapped[ch] = 1;
+ numMappedInChs += 1;
+ }
+ }
+
+ /* Mapping HEAT 2:
+ * Go through the unmapped input channels and assign them to the internal
+ * slots that matches best (least distance). But assign center channels to
+ * center slots only. */
+ startSlot =
+ ((numCh[CH_PLAIN_NORMAL][CH_GROUP_FRONT] & 0x1) || (numChannels >= (8)))
+ ? 0
+ : 1;
+ for (ch = 0; ch < (unsigned)numChannels; ch += 1) {
+ if (!mapped[ch]) {
+ UINT mapDist = (unsigned)-1;
+ unsigned mapCh, mapPos = (unsigned)-1;
+
+ for (mapCh = startSlot; mapCh <= stopSlot; mapCh += 1) {
+ if (offsetTable[mapCh] == 255) {
+ UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
+ if (dist < mapDist) {
+ mapPos = mapCh;
+ mapDist = dist;
+ }
+ }
+ }
+ if ((mapPos <= stopSlot) && (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_2) &&
+ (((spkrPos[ch].x != 0) && (spkrSlotPos[mapPos].x != 0)) /* XOR */
+ || ((spkrPos[ch].x == 0) &&
+ (spkrSlotPos[mapPos].x ==
+ 0)))) { /* Assign center channels to center slots only. */
+ offsetTable[mapPos] = (UCHAR)ch;
+ mapped[ch] = 1;
+ numMappedInChs += 1;
+ }
+ }
+ }
+
+ /* Mapping HEAT 3:
+ * Assign the rest by searching for the nearest input channel for each
+ * internal slot. */
+ for (ch = startSlot; (ch < (8)) && (numMappedInChs < numChannels); ch += 1) {
+ if (offsetTable[ch] == 255) {
+ UINT mapDist = (unsigned)-1;
+ unsigned mapCh, mapPos = (unsigned)-1;
+
+ for (mapCh = 0; mapCh < (unsigned)numChannels; mapCh += 1) {
+ if (!mapped[mapCh]) {
+ UINT dist = getSpeakerDistance(spkrPos[mapCh], spkrSlotPos[ch]);
+ if (dist < mapDist) {
+ mapPos = mapCh;
+ mapDist = dist;
+ }
+ }
+ }
+ if (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_3) {
+ offsetTable[ch] = (UCHAR)mapPos;
+ mapped[mapPos] = 1;
+ numMappedInChs += 1;
+ if ((spkrPos[mapPos].x == 0) && (spkrSlotPos[ch].x != 0) &&
+ (numChannels <
+ (8))) { /* Skip the paired slot if we assigned a center channel. */
+ ch += 1;
+ }
+ }
+ }
+ }
+
+ /* Finaly compose the channel mode */
+ for (ch = 0; ch < (4); ch += 1) {
+ int plane, numChInGrp = 0;
+ for (plane = 0; plane < (3); plane += 1) {
+ numChInGrp += numCh[plane][ch];
+ }
+ *chMode = (PCM_DMX_CHANNEL_MODE)(*chMode | (numChInGrp << (ch * 4)));
+ }
+
+ return err;
+}
+
+/** Generate a channel offset table and complete channel description for a given
+ *(packed) channel mode. This function is the inverse to the getChannelMode()
+ *routine but does not support weird channel configurations.
+ * @param [in] The packed channel mode of the configuration to be processed.
+ * @param [in] Array containing the channel mapping to be used (From MPEG PCE
+ *ordering to whatever is required).
+ * @param [out] Array where corresponding channel types for each channels are
+ *stored into.
+ * @param [out] Array where corresponding channel type indices for each output
+ *channel are stored into.
+ * @param [out] Array where the buffer offsets for each channel are stored into.
+ * @returns None.
+ **/
+static void getChannelDescription(
+ const PCM_DMX_CHANNEL_MODE chMode, /* in */
+ const FDK_channelMapDescr *const mapDescr, /* in */
+ AUDIO_CHANNEL_TYPE channelType[], /* out */
+ UCHAR channelIndices[], /* out */
+ UCHAR offsetTable[(8)] /* out */
+) {
+ int grpIdx, plainIdx, numPlains = 1, numTotalChannels = 0;
+ int chCfg, ch = 0;
+
+ FDK_ASSERT(channelType != NULL);
+ FDK_ASSERT(channelIndices != NULL);
+ FDK_ASSERT(mapDescr != NULL);
+ FDK_ASSERT(offsetTable != NULL);
+
+ /* Init output arrays */
+ FDKmemclear(channelType, (8) * sizeof(AUDIO_CHANNEL_TYPE));
+ FDKmemclear(channelIndices, (8) * sizeof(UCHAR));
+ FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
+
+ /* Summerize to get the total number of channels */
+ for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
+ numTotalChannels += (chMode >> (grpIdx * 4)) & 0xF;
+ }
+
+ /* Get the appropriate channel map */
+ switch (chMode) {
+ case CH_MODE_1_0_0_0:
+ case CH_MODE_2_0_0_0:
+ case CH_MODE_3_0_0_0:
+ case CH_MODE_3_0_1_0:
+ case CH_MODE_3_0_2_0:
+ case CH_MODE_3_0_2_1:
+ chCfg = numTotalChannels;
+ break;
+ case CH_MODE_3_0_3_1:
+ chCfg = 11;
+ break;
+ case CH_MODE_3_0_4_1:
+ chCfg = 12;
+ break;
+ case CH_MODE_5_0_2_1:
+ chCfg = 7;
+ break;
+ default:
+ /* fallback */
+ chCfg = 0;
+ break;
+ }
+
+ /* Compose channel offset table */
+
+ for (plainIdx = 0; plainIdx < numPlains; plainIdx += 1) {
+ PCM_DMX_CHANNEL_MODE plainChMode;
+ UCHAR numChInGrp[(4)];
+
+ plainChMode = getChMode4Plain(plainIdx, chMode, chCfg);
+
+ /* Extract the number of channels per group */
+ numChInGrp[CH_GROUP_FRONT] = plainChMode & 0xF;
+ numChInGrp[CH_GROUP_SIDE] = (plainChMode >> 4) & 0xF;
+ numChInGrp[CH_GROUP_REAR] = (plainChMode >> 8) & 0xF;
+ numChInGrp[CH_GROUP_LFE] = (plainChMode >> 12) & 0xF;
+
+ /* Non-symmetric channels */
+ if ((numChInGrp[CH_GROUP_FRONT] & 0x1) && (plainIdx == CH_PLAIN_NORMAL)) {
+ /* Odd number of front channels -> we have a center channel.
+ In MPEG-4 the center has the index 0. */
+ int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
+ offsetTable[CENTER_FRONT_CHANNEL] = (UCHAR)mappedIdx;
+ channelType[mappedIdx] = ACT_FRONT;
+ channelIndices[mappedIdx] = 0;
+ ch += 1;
+ }
+
+ for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
+ AUDIO_CHANNEL_TYPE type = ACT_NONE;
+ int chMapPos = 0, maxChannels = 0;
+ int chIdx = 0; /* Index of channel within the specific group */
+
+ switch (grpIdx) {
+ case CH_GROUP_FRONT:
+ type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_FRONT);
+ switch (plainIdx) {
+ default:
+ chMapPos = LEFT_FRONT_CHANNEL;
+ chIdx = numChInGrp[grpIdx] & 0x1;
+ break;
+ }
+ maxChannels = 3;
+ break;
+ case CH_GROUP_SIDE:
+ /* Always map side channels to the multipurpose group. */
+ type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_SIDE);
+ if (plainIdx == CH_PLAIN_TOP) {
+ chMapPos = LEFT_SIDE_CHANNEL_TOP;
+ maxChannels = 3;
+ } else {
+ chMapPos = LEFT_MULTIPRPS_CHANNEL;
+ maxChannels = 2;
+ }
+ break;
+ case CH_GROUP_REAR:
+ type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_BACK);
+ if (plainIdx == CH_PLAIN_TOP) {
+ chMapPos = LEFT_REAR_CHANNEL_TOP;
+ maxChannels = 3;
+ } else {
+ chMapPos = LEFT_REAR_CHANNEL;
+ maxChannels = 2;
+ }
+ break;
+ case CH_GROUP_LFE:
+ if (plainIdx == CH_PLAIN_NORMAL) {
+ type = ACT_LFE;
+ chMapPos = LOW_FREQUENCY_CHANNEL;
+ maxChannels = 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Map all channels in this group */
+ for (; chIdx < numChInGrp[grpIdx]; chIdx += 1) {
+ int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
+ if ((chIdx == maxChannels) || (offsetTable[chMapPos] < 255)) {
+ /* No space left in this channel group! */
+ if (offsetTable[LEFT_MULTIPRPS_CHANNEL] ==
+ 255) { /* Use the multipurpose group: */
+ chMapPos = LEFT_MULTIPRPS_CHANNEL;
+ } else {
+ FDK_ASSERT(0);
+ }
+ }
+ offsetTable[chMapPos] = (UCHAR)mappedIdx;
+ channelType[mappedIdx] = type;
+ channelIndices[mappedIdx] = (UCHAR)chIdx;
+ chMapPos += 1;
+ ch += 1;
+ }
+ }
+ }
+}
+
+/** Private helper function for downmix matrix manipulation that initializes
+ * one row in a given downmix matrix (corresponding to one output channel).
+ * @param [inout] Pointer to fixed-point parts of the downmix matrix.
+ * @param [inout] Pointer to scale factor matrix associated to the downmix
+ *factors.
+ * @param [in] Index of channel (row) to be initialized.
+ * @returns Nothing to return.
+ **/
+static void dmxInitChannel(FIXP_DMX mixFactors[(8)][(8)],
+ INT mixScales[(8)][(8)], const unsigned int outCh) {
+ unsigned int inCh;
+ for (inCh = 0; inCh < (8); inCh += 1) {
+ if (inCh == outCh) {
+ mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.5f);
+ mixScales[outCh][inCh] = 1;
+ } else {
+ mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.0f);
+ mixScales[outCh][inCh] = 0;
+ }
+ }
+}
+
+/** Private helper function for downmix matrix manipulation that does a reset
+ * of one row in a given downmix matrix (corresponding to one output channel).
+ * @param [inout] Pointer to fixed-point parts of the downmix matrix.
+ * @param [inout] Pointer to scale factor matrix associated to the downmix
+ *factors.
+ * @param [in] Index of channel (row) to be cleared/reset.
+ * @returns Nothing to return.
+ **/
+static void dmxClearChannel(FIXP_DMX mixFactors[(8)][(8)],
+ INT mixScales[(8)][(8)], const unsigned int outCh) {
+ FDK_ASSERT((outCh >= 0) && (outCh < (8)));
+ FDKmemclear(&mixFactors[outCh], (8) * sizeof(FIXP_DMX));
+ FDKmemclear(&mixScales[outCh], (8) * sizeof(INT));
+}
+
+/** Private helper function for downmix matrix manipulation that applies a
+ *source channel (row) scaled by a given mix factor to a destination channel
+ *(row) in a given downmix matrix. Existing mix factors of the destination
+ *channel (row) will get overwritten.
+ * @param [inout] Pointer to fixed-point parts of the downmix matrix.
+ * @param [inout] Pointer to scale factor matrix associated to the downmix
+ *factors.
+ * @param [in] Index of source channel (row).
+ * @param [in] Index of destination channel (row).
+ * @param [in] Fixed-point part of mix factor to be applied.
+ * @param [in] Scale factor of mix factor to be applied.
+ * @returns Nothing to return.
+ **/
+static void dmxSetChannel(FIXP_DMX mixFactors[(8)][(8)],
+ INT mixScales[(8)][(8)], const unsigned int dstCh,
+ const unsigned int srcCh, const FIXP_DMX factor,
+ const INT scale) {
+ int ch;
+ for (ch = 0; ch < (8); ch += 1) {
+ if (mixFactors[srcCh][ch] != (FIXP_DMX)0) {
+ mixFactors[dstCh][ch] =
+ FX_DBL2FX_DMX(fMult(mixFactors[srcCh][ch], factor));
+ mixScales[dstCh][ch] = mixScales[srcCh][ch] + scale;
+ }
+ }
+}
+
+/** Private helper function for downmix matrix manipulation that adds a source
+ *channel (row) scaled by a given mix factor to a destination channel (row) in a
+ *given downmix matrix.
+ * @param [inout] Pointer to fixed-point parts of the downmix matrix.
+ * @param [inout] Pointer to scale factor matrix associated to the downmix
+ *factors.
+ * @param [in] Index of source channel (row).
+ * @param [in] Index of destination channel (row).
+ * @param [in] Fixed-point part of mix factor to be applied.
+ * @param [in] Scale factor of mix factor to be applied.
+ * @returns Nothing to return.
+ **/
+static void dmxAddChannel(FIXP_DMX mixFactors[(8)][(8)],
+ INT mixScales[(8)][(8)], const unsigned int dstCh,
+ const unsigned int srcCh, const FIXP_DMX factor,
+ const INT scale) {
+ int ch;
+ for (ch = 0; ch < (8); ch += 1) {
+ FIXP_DBL addFact = fMult(mixFactors[srcCh][ch], factor);
+ if (addFact != (FIXP_DMX)0) {
+ INT newScale = mixScales[srcCh][ch] + scale;
+ if (mixFactors[dstCh][ch] != (FIXP_DMX)0) {
+ if (newScale > mixScales[dstCh][ch]) {
+ mixFactors[dstCh][ch] >>= newScale - mixScales[dstCh][ch];
+ } else {
+ addFact >>= mixScales[dstCh][ch] - newScale;
+ newScale = mixScales[dstCh][ch];
+ }
+ }
+ mixFactors[dstCh][ch] += FX_DBL2FX_DMX(addFact);
+ mixScales[dstCh][ch] = newScale;
+ }
+ }
+}
+
+/** Private function that creates a downmix factor matrix depending on the input
+ and output
+ * configuration, the user parameters as well as the given metadata. This
+ function is the modules
+ * brain and hold all downmix algorithms.
+ * @param [in] Flag that indicates if inChMode holds a real (packed) channel
+ mode or has been converted to a MPEG-4 channel configuration index.
+ * @param [in] Dependent on the inModeIsCfg flag this field hands in a (packed)
+ channel mode or the corresponding MPEG-4 channel configuration index.of the
+ input configuration.
+ * @param [in] The (packed) channel mode of the output configuration.
+ * @param [in] Pointer to structure holding all current user parameter.
+ * @param [in] Pointer to field holding all current meta data.
+ * @param [out] Pointer to fixed-point parts of the downmix matrix. Normalized
+ to one scale factor.
+ * @param [out] The common scale factor of the downmix matrix.
+ * @returns An error code.
+ **/
+static PCMDMX_ERROR getMixFactors(const UCHAR inModeIsCfg,
+ PCM_DMX_CHANNEL_MODE inChMode,
+ const PCM_DMX_CHANNEL_MODE outChMode,
+ const PCM_DMX_USER_PARAMS *pParams,
+ const DMX_BS_META_DATA *pMetaData,
+ FIXP_DMX mixFactors[(8)][(8)],
+ INT *pOutScale) {
+ PCMDMX_ERROR err = PCMDMX_OK;
+ INT mixScales[(8)][(8)];
+ INT maxScale = 0;
+ int numInChannel;
+ int numOutChannel;
+ int dmxMethod;
+ unsigned int outCh, inChCfg = 0;
+ unsigned int valid[(8)] = {0};
+
+ FDK_ASSERT(pMetaData != NULL);
+ FDK_ASSERT(mixFactors != NULL);
+ /* Check on a supported output configuration.
+ Add new one only after extensive testing! */
+ if (!((outChMode == CH_MODE_1_0_0_0) || (outChMode == CH_MODE_2_0_0_0) ||
+ (outChMode == CH_MODE_3_0_2_1) || (outChMode == CH_MODE_3_0_4_1) ||
+ (outChMode == CH_MODE_5_0_2_1))) {
+ FDK_ASSERT(0);
+ }
+
+ if (inModeIsCfg) {
+ /* Convert channel config to channel mode: */
+ inChCfg = (unsigned int)inChMode;
+ switch (inChCfg) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ inChMode = outChModeTable[inChCfg];
+ break;
+ case 11:
+ inChMode = CH_MODE_3_0_3_1;
+ break;
+ case 12:
+ inChMode = CH_MODE_3_0_4_1;
+ break;
+ case 7:
+ case 14:
+ inChMode = CH_MODE_5_0_2_1;
+ break;
+ default:
+ FDK_ASSERT(0);
+ }
+ }
+
+ /* Extract the total number of input channels */
+ numInChannel = (inChMode & 0xF) + ((inChMode >> 4) & 0xF) +
+ ((inChMode >> 8) & 0xF) + ((inChMode >> 12) & 0xF);
+ /* Extract the total number of output channels */
+ numOutChannel = (outChMode & 0xF) + ((outChMode >> 4) & 0xF) +
+ ((outChMode >> 8) & 0xF) + ((outChMode >> 12) & 0xF);
+
+ /* MPEG ammendment 4 aka ETSI metadata and fallback mode: */
+
+ /* Create identity DMX matrix: */
+ for (outCh = 0; outCh < (8); outCh += 1) {
+ dmxInitChannel(mixFactors, mixScales, outCh);
+ }
+ if (((inChMode >> 12) & 0xF) == 0) {
+ /* Clear empty or wrongly mapped input channel */
+ dmxClearChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL);
+ }
+
+ /* FIRST STAGE: */
+ if (numInChannel > SIX_CHANNEL) { /* Always use MPEG equations either with
+ meta data or with default values. */
+ FIXP_DMX dMixFactA, dMixFactB;
+ INT dMixScaleA, dMixScaleB;
+ int isValidCfg = TRUE;
+
+ /* Get factors from meta data */
+ dMixFactA = abMixLvlValueTab[pMetaData->dmixIdxA];
+ dMixScaleA = (pMetaData->dmixIdxA == 0) ? 1 : 0;
+ dMixFactB = abMixLvlValueTab[pMetaData->dmixIdxB];
+ dMixScaleB = (pMetaData->dmixIdxB == 0) ? 1 : 0;
+
+ /* Check if input is in the list of supported configurations */
+ switch (inChMode) {
+ case CH_MODE_3_2_1_1: /* chCfg 11 but with side channels */
+ case CH_MODE_3_2_1_0:
+ isValidCfg = FALSE;
+ err = PCMDMX_INVALID_MODE;
+ case CH_MODE_3_0_3_1: /* chCfg 11 */
+ /* 6.1ch: C' = C; L' = L; R' = R; LFE' = LFE;
+ Ls' = Ls*dmix_a_idx + Cs*dmix_b_idx;
+ Rs' = Rs*dmix_a_idx + Cs*dmix_b_idx; */
+ dmxClearChannel(
+ mixFactors, mixScales,
+ RIGHT_MULTIPRPS_CHANNEL); /* clear empty input channel */
+ dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
+ LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
+ dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
+ LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
+ RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
+ LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
+ break;
+ case CH_MODE_3_0_4_1: /* chCfg 12 */
+ /* 7.1ch Surround Back: C' = C; L' = L; R' = R; LFE' = LFE;
+ Ls' = Ls*dmix_a_idx + Lsr*dmix_b_idx;
+ Rs' = Rs*dmix_a_idx + Rsr*dmix_b_idx; */
+ dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
+ LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
+ dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
+ LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
+ RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
+ RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
+ break;
+ case CH_MODE_5_0_1_0:
+ case CH_MODE_5_0_1_1:
+ dmxClearChannel(mixFactors, mixScales,
+ RIGHT_REAR_CHANNEL); /* clear empty input channel */
+ dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
+ LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
+ dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
+ LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
+ case CH_MODE_5_2_1_0:
+ isValidCfg = FALSE;
+ err = PCMDMX_INVALID_MODE;
+ case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */
+ if (inChCfg == 14) {
+ /* 7.1ch Front Height: C' = C; Ls' = Ls; Rs' = Rs; LFE' = LFE;
+ L' = L*dmix_a_idx + Lv*dmix_b_idx;
+ R' = R*dmix_a_idx + Rv*dmix_b_idx; */
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
+ } else {
+ /* 7.1ch Front: Ls' = Ls; Rs' = Rs; LFE' = LFE;
+ C' = C + (Lc+Rc)*dmix_a_idx;
+ L' = L + Lc*dmix_b_idx;
+ R' = R + Rc*dmix_b_idx; */
+ dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
+ LEFT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
+ dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
+ RIGHT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
+ }
+ break;
+ default:
+ /* Nothing to do. Just use the identity matrix. */
+ isValidCfg = FALSE;
+ err = PCMDMX_INVALID_MODE;
+ break;
+ }
+
+ /* Add additional DMX gain */
+ if ((isValidCfg == TRUE) &&
+ (pMetaData->dmxGainIdx5 != 0)) { /* Apply DMX gain 5 */
+ FIXP_DMX dmxGain;
+ INT dmxScale;
+ INT sign = (pMetaData->dmxGainIdx5 & 0x40) ? -1 : 1;
+ INT val = pMetaData->dmxGainIdx5 & 0x3F;
+
+ /* 10^(dmx_gain_5/80) */
+ dmxGain = FX_DBL2FX_DMX(
+ fLdPow(FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
+ (FIXP_DBL)(sign * val * (LONG)FL2FXCONST_DBL(0.0125f)), 0,
+ &dmxScale));
+ /* Currently only positive scale factors supported! */
+ if (dmxScale < 0) {
+ dmxGain >>= -dmxScale;
+ dmxScale = 0;
+ }
+
+ dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
+ CENTER_FRONT_CHANNEL, dmxGain, dmxScale);
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, dmxGain, dmxScale);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, dmxGain, dmxScale);
+ dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL,
+ dmxGain, dmxScale);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
+ RIGHT_REAR_CHANNEL, dmxGain, dmxScale);
+ dmxSetChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL,
+ LOW_FREQUENCY_CHANNEL, dmxGain, dmxScale);
+ }
+
+ /* Mark the output channels */
+ valid[CENTER_FRONT_CHANNEL] = 1;
+ valid[LEFT_FRONT_CHANNEL] = 1;
+ valid[RIGHT_FRONT_CHANNEL] = 1;
+ valid[LEFT_REAR_CHANNEL] = 1;
+ valid[RIGHT_REAR_CHANNEL] = 1;
+ valid[LOW_FREQUENCY_CHANNEL] = 1;
+
+ /* Update channel mode for the next stage */
+ inChMode = CH_MODE_3_0_2_1;
+ }
+
+ /* For the X (> 6) to 6 channel downmix we had no choice.
+ To mix from 6 to 2 (or 1) channel(s) we have several possibilities (MPEG
+ DSE | MPEG PCE | ITU | ARIB | DLB). Use profile and the metadata
+ available flags to determine which equation to use: */
+
+#define DMX_METHOD_MPEG_AMD4 1
+#define DMX_METHOD_MPEG_LEGACY 2
+#define DMX_METHOD_ARIB_JAPAN 4
+#define DMX_METHOD_ITU_RECOM 8
+#define DMX_METHOD_CUSTOM 16
+
+ dmxMethod = DMX_METHOD_MPEG_AMD4; /* default */
+
+ if ((pParams->dmxProfile == DMX_PRFL_FORCE_MATRIX_MIX) &&
+ (pMetaData->typeFlags & TYPE_PCE_DATA)) {
+ dmxMethod = DMX_METHOD_MPEG_LEGACY;
+ } else if (!(pMetaData->typeFlags &
+ (TYPE_DSE_CLEV_DATA | TYPE_DSE_SLEV_DATA))) {
+ switch (pParams->dmxProfile) {
+ default:
+ case DMX_PRFL_STANDARD:
+ /* dmxMethod = DMX_METHOD_MPEG_AMD4; */
+ break;
+ case DMX_PRFL_MATRIX_MIX:
+ case DMX_PRFL_FORCE_MATRIX_MIX:
+ if (pMetaData->typeFlags & TYPE_PCE_DATA) {
+ dmxMethod = DMX_METHOD_MPEG_LEGACY;
+ }
+ break;
+ case DMX_PRFL_ARIB_JAPAN:
+ dmxMethod = DMX_METHOD_ARIB_JAPAN;
+ break;
+ }
+ }
+
+ /* SECOND STAGE: */
+ if (numOutChannel <= TWO_CHANNEL) {
+ /* Create DMX matrix according to input configuration */
+ switch (inChMode) {
+ case CH_MODE_2_0_0_0: /* chCfg 2 */
+ /* Apply the dual channel mode. */
+ switch (pParams->dualChannelMode) {
+ case CH1_MODE: /* L' = 0.707 * Ch1;
+ R' = 0.707 * Ch1; */
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
+ break;
+ case CH2_MODE: /* L' = 0.707 * Ch2;
+ R' = 0.707 * Ch2; */
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
+ break;
+ case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2;
+ R' = 0.5*Ch1 + 0.5*Ch2; */
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
+ break;
+ default:
+ case STEREO_MODE:
+ /* Nothing to do */
+ break;
+ }
+ break;
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * - - - - - - - - - - - - - - - - - - - */
+ case CH_MODE_2_0_1_0: {
+ FIXP_DMX sMixLvl;
+ if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
+ /* L' = 0.707*L + 0.5*S; R' = 0.707*R + 0.5*S; */
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
+ sMixLvl = FL2FXCONST_DMX(0.5f);
+ } else { /* L' = L + 0.707*S; R' = R + 0.707*S; */
+ sMixLvl = FL2FXCONST_DMX(0.707f);
+ }
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_REAR_CHANNEL, sMixLvl, 0);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ LEFT_REAR_CHANNEL, sMixLvl, 0);
+ } break;
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * - - - - - - - - - - - - - - - - - - - */
+ case CH_MODE_3_0_0_0: /* chCfg 3 */
+ {
+ FIXP_DMX cMixLvl;
+ if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
+ /* L' = 0.707*L + 0.5*C; R' = 0.707*R + 0.5*C; */
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
+ cMixLvl = FL2FXCONST_DMX(0.5f);
+ } else { /* L' = L + 0.707*C; R' = R + 0.707*C; */
+ cMixLvl = FL2FXCONST_DMX(0.707f);
+ }
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ CENTER_FRONT_CHANNEL, cMixLvl, 0);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ CENTER_FRONT_CHANNEL, cMixLvl, 0);
+ } break;
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * - - - - - - - - - - - - - - - - - - - */
+ case CH_MODE_3_0_1_0: /* chCfg 4 */
+ {
+ FIXP_DMX csMixLvl;
+ if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
+ /* L' = 0.707*L + 0.5*C + 0.5*S; R' = 0.707*R + 0.5*C + 0.5*S; */
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
+ csMixLvl = FL2FXCONST_DMX(0.5f);
+ } else { /* L' = L + 0.707*C + 0.707*S;
+ R' = R + 0.707*C + 0.707*S; */
+ csMixLvl = FL2FXCONST_DMX(0.707f);
+ }
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ CENTER_FRONT_CHANNEL, csMixLvl, 0);
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_REAR_CHANNEL, csMixLvl, 0);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ CENTER_FRONT_CHANNEL, csMixLvl, 0);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ LEFT_REAR_CHANNEL, csMixLvl, 0);
+ } break;
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * - - - - - - - - - - - - - - - - - - - */
+ case CH_MODE_3_0_2_0: /* chCfg 5 */
+ case CH_MODE_3_0_2_1: /* chCfg 6 */
+ {
+ switch (dmxMethod) {
+ default:
+ case DMX_METHOD_MPEG_AMD4: {
+ FIXP_DMX cMixLvl, sMixLvl, lMixLvl;
+ INT cMixScale, sMixScale, lMixScale;
+
+ /* Get factors from meta data */
+ cMixLvl = abMixLvlValueTab[pMetaData->cLevIdx];
+ cMixScale = (pMetaData->cLevIdx == 0) ? 1 : 0;
+ sMixLvl = abMixLvlValueTab[pMetaData->sLevIdx];
+ sMixScale = (pMetaData->sLevIdx == 0) ? 1 : 0;
+ lMixLvl = lfeMixLvlValueTab[pMetaData->dmixIdxLfe];
+ if (pMetaData->dmixIdxLfe <= 1) {
+ lMixScale = 2;
+ } else if (pMetaData->dmixIdxLfe <= 5) {
+ lMixScale = 1;
+ } else {
+ lMixScale = 0;
+ }
+ /* Setup the DMX matrix */
+ if ((pParams->pseudoSurrMode == FORCE_PS_DMX) ||
+ ((pParams->pseudoSurrMode == AUTO_PS_DMX) &&
+ (pMetaData->pseudoSurround ==
+ 1))) { /* L' = L + C*clev - (Ls+Rs)*slev + LFE*lflev;
+ R' = R + C*clev + (Ls+Rs)*slev + LFE*lflev; */
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_REAR_CHANNEL, -sMixLvl, sMixScale);
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ RIGHT_REAR_CHANNEL, -sMixLvl, sMixScale);
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ LEFT_REAR_CHANNEL, sMixLvl, sMixScale);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_REAR_CHANNEL, sMixLvl, sMixScale);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
+ } else { /* L' = L + C*clev + Ls*slev + LFE*llev;
+ R' = R + C*clev + Rs*slev + LFE*llev; */
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_REAR_CHANNEL, sMixLvl, sMixScale);
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_REAR_CHANNEL, sMixLvl, sMixScale);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
+ }
+
+ /* Add additional DMX gain */
+ if (pMetaData->dmxGainIdx2 != 0) { /* Apply DMX gain 2 */
+ FIXP_DMX dmxGain;
+ INT dmxScale;
+ INT sign = (pMetaData->dmxGainIdx2 & 0x40) ? -1 : 1;
+ INT val = pMetaData->dmxGainIdx2 & 0x3F;
+
+ /* 10^(dmx_gain_2/80) */
+ dmxGain = FX_DBL2FX_DMX(
+ fLdPow(FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
+ (FIXP_DBL)(sign * val * (LONG)FL2FXCONST_DBL(0.0125f)),
+ 0, &dmxScale));
+ /* Currently only positive scale factors supported! */
+ if (dmxScale < 0) {
+ dmxGain >>= -dmxScale;
+ dmxScale = 0;
+ }
+
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, dmxGain, dmxScale);
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, dmxGain, dmxScale);
+ }
+ } break;
+ case DMX_METHOD_ARIB_JAPAN:
+ case DMX_METHOD_MPEG_LEGACY: {
+ FIXP_DMX flev, clev, slevLL, slevLR, slevRL, slevRR;
+ FIXP_DMX mtrxMixDwnCoef =
+ mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx];
+
+ if ((pParams->pseudoSurrMode == FORCE_PS_DMX) ||
+ ((pParams->pseudoSurrMode == AUTO_PS_DMX) &&
+ (pMetaData->pseudoSurround == 1))) {
+ if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
+ /* 3/2 input: L' = 0.707 * [L+0.707*C-k*Ls-k*Rs];
+ R' = 0.707 * [R+0.707*C+k*Ls+k*Rs]; */
+ flev = mpegMixDownIdx2Coef[0]; /* a = 0.707 */
+ } else { /* 3/2 input: L' = (1.707+2*A)^-1 *
+ [L+0.707*C-A*Ls-A*Rs]; R' = (1.707+2*A)^-1 *
+ [R+0.707*C+A*Ls+A*Rs]; */
+ flev = mpegMixDownIdx2PreFact[1][pMetaData->matrixMixdownIdx];
+ }
+ slevRR = slevRL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
+ slevLL = slevLR = -slevRL;
+ } else {
+ if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
+ /* 3/2 input: L' = 0.707 * [L+0.707*C+k*Ls];
+ R' = 0.707 * [R+0.707*C+k*Rs]; */
+ flev = mpegMixDownIdx2Coef[0]; /* a = 0.707 */
+ } else { /* 3/2 input: L' = (1.707+A)^-1 * [L+0.707*C+A*Ls];
+ R' = (1.707+A)^-1 * [R+0.707*C+A*Rs]; */
+ flev = mpegMixDownIdx2PreFact[0][pMetaData->matrixMixdownIdx];
+ }
+ slevRR = slevLL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
+ slevLR = slevRL = (FIXP_DMX)0;
+ }
+ /* common factor */
+ clev =
+ FX_DBL2FX_DMX(fMult(flev, mpegMixDownIdx2Coef[0] /* 0.707 */));
+
+ dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, flev, 0);
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ CENTER_FRONT_CHANNEL, clev, 0);
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ LEFT_REAR_CHANNEL, slevLL, 0);
+ dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
+ RIGHT_REAR_CHANNEL, slevLR, 0);
+
+ dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, flev, 0);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ CENTER_FRONT_CHANNEL, clev, 0);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ LEFT_REAR_CHANNEL, slevRL, 0);
+ dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
+ RIGHT_REAR_CHANNEL, slevRR, 0);
+ } break;
+ } /* switch (dmxMethod) */
+ } break;
+ default:
+ /* This configuration does not fit to any known downmix equation! */
+ err = PCMDMX_INVALID_MODE;
+ break;
+ } /* switch (inChMode) */
+
+ /* Mark the output channels */
+ FDKmemclear(valid, (8) * sizeof(unsigned int));
+ valid[LEFT_FRONT_CHANNEL] = 1;
+ valid[RIGHT_FRONT_CHANNEL] = 1;
+ }
+
+ if (numOutChannel == ONE_CHANNEL) {
+ FIXP_DMX monoMixLevel;
+ INT monoMixScale = 0;
+
+ dmxClearChannel(mixFactors, mixScales,
+ CENTER_FRONT_CHANNEL); /* C is not in the mix */
+
+ if (dmxMethod ==
+ DMX_METHOD_MPEG_LEGACY) { /* C' = (3+2*A)^-1 * [C+L+R+A*Ls+A+Rs]; */
+ monoMixLevel = mpegMixDownIdx2PreFact[2][pMetaData->matrixMixdownIdx];
+
+ mixFactors[CENTER_FRONT_CHANNEL][CENTER_FRONT_CHANNEL] = monoMixLevel;
+ mixFactors[CENTER_FRONT_CHANNEL][LEFT_FRONT_CHANNEL] = monoMixLevel;
+ mixFactors[CENTER_FRONT_CHANNEL][RIGHT_FRONT_CHANNEL] = monoMixLevel;
+ monoMixLevel = FX_DBL2FX_DMX(fMult(
+ monoMixLevel, mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx]));
+ mixFactors[CENTER_FRONT_CHANNEL][LEFT_REAR_CHANNEL] = monoMixLevel;
+ mixFactors[CENTER_FRONT_CHANNEL][RIGHT_REAR_CHANNEL] = monoMixLevel;
+ } else {
+ switch (dmxMethod) {
+ case DMX_METHOD_MPEG_AMD4:
+ /* C' = L + R; */
+ monoMixLevel = FL2FXCONST_DMX(0.5f);
+ monoMixScale = 1;
+ break;
+ default:
+ /* C' = 0.5*L + 0.5*R; */
+ monoMixLevel = FL2FXCONST_DMX(0.5f);
+ monoMixScale = 0;
+ break;
+ }
+ dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
+ LEFT_FRONT_CHANNEL, monoMixLevel, monoMixScale);
+ dmxAddChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
+ RIGHT_FRONT_CHANNEL, monoMixLevel, monoMixScale);
+ }
+
+ /* Mark the output channel */
+ FDKmemclear(valid, (8) * sizeof(unsigned int));
+ valid[CENTER_FRONT_CHANNEL] = 1;
+ }
+
+#define MAX_SEARCH_START_VAL (-7)
+
+ {
+ LONG chSum[(8)];
+ INT chSumMax = MAX_SEARCH_START_VAL;
+
+ /* Determine the current maximum scale factor */
+ for (outCh = 0; outCh < (8); outCh += 1) {
+ if (valid[outCh] != 0) {
+ unsigned int inCh;
+ for (inCh = 0; inCh < (8); inCh += 1) {
+ if (mixScales[outCh][inCh] > maxScale) { /* Store the new maximum */
+ maxScale = mixScales[outCh][inCh];
+ }
+ }
+ }
+ }
+
+ /* Individualy analyse output chanal levels */
+ for (outCh = 0; outCh < (8); outCh += 1) {
+ chSum[outCh] = MAX_SEARCH_START_VAL;
+ if (valid[outCh] != 0) {
+ int ovrflwProtScale = 0;
+ unsigned int inCh;
+
+ /* Accumulate all factors for each output channel */
+ chSum[outCh] = 0;
+ for (inCh = 0; inCh < (8); inCh += 1) {
+ SHORT addFact = FX_DMX2SHRT(mixFactors[outCh][inCh]);
+ if (mixScales[outCh][inCh] <= maxScale) {
+ addFact >>= maxScale - mixScales[outCh][inCh];
+ } else {
+ addFact <<= mixScales[outCh][inCh] - maxScale;
+ }
+ chSum[outCh] += addFact;
+ }
+ if (chSum[outCh] > (LONG)MAXVAL_SGL) {
+ while (chSum[outCh] > (LONG)MAXVAL_SGL) {
+ ovrflwProtScale += 1;
+ chSum[outCh] >>= 1;
+ }
+ } else if (chSum[outCh] > 0) {
+ while ((chSum[outCh] << 1) <= (LONG)MAXVAL_SGL) {
+ ovrflwProtScale -= 1;
+ chSum[outCh] <<= 1;
+ }
+ }
+ /* Store the differential scaling in the same array */
+ chSum[outCh] = ovrflwProtScale;
+ }
+ }
+
+ for (outCh = 0; outCh < (8); outCh += 1) {
+ if ((valid[outCh] != 0) &&
+ (chSum[outCh] > chSumMax)) { /* Store the new maximum */
+ chSumMax = chSum[outCh];
+ }
+ }
+ maxScale = fMax(maxScale + chSumMax, 0);
+
+ /* Normalize all factors */
+ for (outCh = 0; outCh < (8); outCh += 1) {
+ if (valid[outCh] != 0) {
+ unsigned int inCh;
+ for (inCh = 0; inCh < (8); inCh += 1) {
+ if (mixFactors[outCh][inCh] != (FIXP_DMX)0) {
+ if (mixScales[outCh][inCh] <= maxScale) {
+ mixFactors[outCh][inCh] >>= maxScale - mixScales[outCh][inCh];
+ } else {
+ mixFactors[outCh][inCh] <<= mixScales[outCh][inCh] - maxScale;
+ }
+ mixScales[outCh][inCh] = maxScale;
+ }
+ }
+ }
+ }
+ }
+
+ /* return the scale factor */
+ *pOutScale = maxScale;
+
+ return (err);
+}
+
+/** Open and initialize an instance of the PCM downmix module
+ * @param [out] Pointer to a buffer receiving the handle of the new instance.
+ * @returns Returns an error code.
+ **/
+PCMDMX_ERROR pcmDmx_Open(HANDLE_PCM_DOWNMIX *pSelf) {
+ HANDLE_PCM_DOWNMIX self;
+
+ if (pSelf == NULL) {
+ return (PCMDMX_INVALID_HANDLE);
+ }
+
+ *pSelf = NULL;
+
+ self = (HANDLE_PCM_DOWNMIX)GetPcmDmxInstance(0);
+ if (self == NULL) {
+ return (PCMDMX_OUT_OF_MEMORY);
+ }
+
+ /* Reset the full instance */
+ pcmDmx_Reset(self, PCMDMX_RESET_FULL);
+
+ *pSelf = self;
+
+ return (PCMDMX_OK);
+}
+
+/** Reset all static values like e.g. mixdown coefficients.
+ * @param [in] Handle of PCM downmix module instance.
+ * @param [in] Flags telling which parts of the module shall be reset.
+ * @returns Returns an error code.
+ **/
+PCMDMX_ERROR pcmDmx_Reset(HANDLE_PCM_DOWNMIX self, UINT flags) {
+ if (self == NULL) {
+ return (PCMDMX_INVALID_HANDLE);
+ }
+
+ if (flags & PCMDMX_RESET_PARAMS) {
+ PCM_DMX_USER_PARAMS *pParams = &self->userParams;
+
+ pParams->dualChannelMode = STEREO_MODE;
+ pParams->pseudoSurrMode = NEVER_DO_PS_DMX;
+ pParams->numOutChannelsMax = (6);
+ pParams->numOutChannelsMin = (0);
+ pParams->frameDelay = 0;
+ pParams->expiryFrame = (0);
+
+ self->applyProcessing = 0;
+ }
+
+ if (flags & PCMDMX_RESET_BS_DATA) {
+ int slot;
+ /* Init all slots with a default set */
+ for (slot = 0; slot <= (1); slot += 1) {
+ FDKmemcpy(&self->bsMetaData[slot], &dfltMetaData,
+ sizeof(DMX_BS_META_DATA));
+ }
+ }
+
+ return (PCMDMX_OK);
+}
+
+/** Set one parameter for one instance of the PCM downmix module.
+ * @param [in] Handle of PCM downmix module instance.
+ * @param [in] Parameter to be set.
+ * @param [in] Parameter value.
+ * @returns Returns an error code.
+ **/
+PCMDMX_ERROR pcmDmx_SetParam(HANDLE_PCM_DOWNMIX self, const PCMDMX_PARAM param,
+ const INT value) {
+ switch (param) {
+ case DMX_PROFILE_SETTING:
+ switch ((DMX_PROFILE_TYPE)value) {
+ case DMX_PRFL_STANDARD:
+ case DMX_PRFL_MATRIX_MIX:
+ case DMX_PRFL_FORCE_MATRIX_MIX:
+ case DMX_PRFL_ARIB_JAPAN:
+ break;
+ default:
+ return (PCMDMX_UNABLE_TO_SET_PARAM);
+ }
+ if (self == NULL) return (PCMDMX_INVALID_HANDLE);
+ self->userParams.dmxProfile = (DMX_PROFILE_TYPE)value;
+ break;
+
+ case DMX_BS_DATA_EXPIRY_FRAME:
+ if (self == NULL) return (PCMDMX_INVALID_HANDLE);
+ self->userParams.expiryFrame = (value > 0) ? (UINT)value : 0;
+ break;
+
+ case DMX_BS_DATA_DELAY:
+ if ((value > (1)) || (value < 0)) {
+ return (PCMDMX_UNABLE_TO_SET_PARAM);
+ }
+ if (self == NULL) {
+ return (PCMDMX_INVALID_HANDLE);
+ }
+ self->userParams.frameDelay = (UCHAR)value;
+ break;
+
+ case MIN_NUMBER_OF_OUTPUT_CHANNELS:
+ switch (value) { /* supported output channels */
+ case -1:
+ case 0:
+ case ONE_CHANNEL:
+ case TWO_CHANNEL:
+ case SIX_CHANNEL:
+ case EIGHT_CHANNEL:
+ break;
+ default:
+ return (PCMDMX_UNABLE_TO_SET_PARAM);
+ }
+ if (self == NULL) return (PCMDMX_INVALID_HANDLE);
+ /* Store the new value */
+ self->userParams.numOutChannelsMin = (value > 0) ? (SHORT)value : -1;
+ if ((value > 0) && (self->userParams.numOutChannelsMax > 0) &&
+ (value > self->userParams
+ .numOutChannelsMax)) { /* MIN > MAX would be an invalid
+ state. Thus set MAX = MIN in
+ this case. */
+ self->userParams.numOutChannelsMax = self->userParams.numOutChannelsMin;
+ }
+ break;
+
+ case MAX_NUMBER_OF_OUTPUT_CHANNELS:
+ switch (value) { /* supported output channels */
+ case -1:
+ case 0:
+ case ONE_CHANNEL:
+ case TWO_CHANNEL:
+ case SIX_CHANNEL:
+ case EIGHT_CHANNEL:
+ break;
+ default:
+ return (PCMDMX_UNABLE_TO_SET_PARAM);
+ }
+ if (self == NULL) return (PCMDMX_INVALID_HANDLE);
+ /* Store the new value */
+ self->userParams.numOutChannelsMax = (value > 0) ? (SHORT)value : -1;
+ if ((value > 0) &&
+ (value < self->userParams
+ .numOutChannelsMin)) { /* MAX < MIN would be an invalid
+ state. Thus set MIN = MAX in
+ this case. */
+ self->userParams.numOutChannelsMin = self->userParams.numOutChannelsMax;
+ }
+ break;
+
+ case DMX_DUAL_CHANNEL_MODE:
+ switch ((DUAL_CHANNEL_MODE)value) {
+ case STEREO_MODE:
+ case CH1_MODE:
+ case CH2_MODE:
+ case MIXED_MODE:
+ break;
+ default:
+ return (PCMDMX_UNABLE_TO_SET_PARAM);
+ }
+ if (self == NULL) return (PCMDMX_INVALID_HANDLE);
+ self->userParams.dualChannelMode = (DUAL_CHANNEL_MODE)value;
+ self->applyProcessing = ((DUAL_CHANNEL_MODE)value != STEREO_MODE)
+ ? 1
+ : 0; /* Force processing if necessary. */
+ break;
+
+ case DMX_PSEUDO_SURROUND_MODE:
+ switch ((PSEUDO_SURROUND_MODE)value) {
+ case NEVER_DO_PS_DMX:
+ case AUTO_PS_DMX:
+ case FORCE_PS_DMX:
+ break;
+ default:
+ return (PCMDMX_UNABLE_TO_SET_PARAM);
+ }
+ if (self == NULL) return (PCMDMX_INVALID_HANDLE);
+ self->userParams.pseudoSurrMode = (PSEUDO_SURROUND_MODE)value;
+ break;
+
+ default:
+ return (PCMDMX_UNKNOWN_PARAM);
+ }
+
+ return (PCMDMX_OK);
+}
+
+/** Get one parameter value of one PCM downmix module instance.
+ * @param [in] Handle of PCM downmix module instance.
+ * @param [in] Parameter to be set.
+ * @param [out] Pointer to buffer receiving the parameter value.
+ * @returns Returns an error code.
+ **/
+PCMDMX_ERROR pcmDmx_GetParam(HANDLE_PCM_DOWNMIX self, const PCMDMX_PARAM param,
+ INT *const pValue) {
+ PCM_DMX_USER_PARAMS *pUsrParams;
+
+ if ((self == NULL) || (pValue == NULL)) {
+ return (PCMDMX_INVALID_HANDLE);
+ }
+ pUsrParams = &self->userParams;
+
+ switch (param) {
+ case DMX_PROFILE_SETTING:
+ *pValue = (INT)pUsrParams->dmxProfile;
+ break;
+ case DMX_BS_DATA_EXPIRY_FRAME:
+ *pValue = (INT)pUsrParams->expiryFrame;
+ break;
+ case DMX_BS_DATA_DELAY:
+ *pValue = (INT)pUsrParams->frameDelay;
+ break;
+ case MIN_NUMBER_OF_OUTPUT_CHANNELS:
+ *pValue = (INT)pUsrParams->numOutChannelsMin;
+ break;
+ case MAX_NUMBER_OF_OUTPUT_CHANNELS:
+ *pValue = (INT)pUsrParams->numOutChannelsMax;
+ break;
+ case DMX_DUAL_CHANNEL_MODE:
+ *pValue = (INT)pUsrParams->dualChannelMode;
+ break;
+ case DMX_PSEUDO_SURROUND_MODE:
+ *pValue = (INT)pUsrParams->pseudoSurrMode;
+ break;
+ default:
+ return (PCMDMX_UNKNOWN_PARAM);
+ }
+
+ return (PCMDMX_OK);
+}
+
+/*
+ * Read DMX meta-data from a data stream element.
+ */
+PCMDMX_ERROR pcmDmx_Parse(HANDLE_PCM_DOWNMIX self, HANDLE_FDK_BITSTREAM hBs,
+ UINT ancDataBits, int isMpeg2) {
+ PCMDMX_ERROR errorStatus = PCMDMX_OK;
+
+#define MAX_DSE_ANC_BYTES (16) /* 15 bytes */
+#define ANC_DATA_SYNC_BYTE (0xBC) /* ancillary data sync byte. */
+
+ DMX_BS_META_DATA *pBsMetaData;
+
+ int skip4Dmx = 0, skip4Ext = 0;
+ int dmxLvlAvail = 0, extDataAvail = 0;
+ UINT foundNewData = 0;
+ UINT minAncBits = ((isMpeg2) ? 5 : 3) * 8;
+
+ if ((self == NULL) || (hBs == NULL)) {
+ return (PCMDMX_INVALID_HANDLE);
+ }
+
+ /* sanity checks */
+ if ((ancDataBits < minAncBits) || (ancDataBits > FDKgetValidBits(hBs))) {
+ return (PCMDMX_CORRUPT_ANC_DATA);
+ }
+
+ pBsMetaData = &self->bsMetaData[0];
+
+ if (isMpeg2) {
+ /* skip DVD ancillary data */
+ FDKpushFor(hBs, 16);
+ }
+
+ /* check sync word */
+ if (FDKreadBits(hBs, 8) != ANC_DATA_SYNC_BYTE) {
+ return (PCMDMX_CORRUPT_ANC_DATA);
+ }
+
+ /* skip MPEG audio type and Dolby surround mode */
+ FDKpushFor(hBs, 4);
+
+ if (isMpeg2) {
+ /* int numAncBytes = */ FDKreadBits(hBs, 4);
+ /* advanced dynamic range control */
+ if (FDKreadBit(hBs)) skip4Dmx += 24;
+ /* dialog normalization */
+ if (FDKreadBit(hBs)) skip4Dmx += 8;
+ /* reproduction_level */
+ if (FDKreadBit(hBs)) skip4Dmx += 8;
+ } else {
+ FDKpushFor(hBs, 2); /* drc presentation mode */
+ pBsMetaData->pseudoSurround = (SCHAR)FDKreadBit(hBs);
+ FDKpushFor(hBs, 4); /* reserved bits */
+ }
+
+ /* downmixing levels MPEGx status */
+ dmxLvlAvail = FDKreadBit(hBs);
+
+ if (isMpeg2) {
+ /* scale factor CRC status */
+ if (FDKreadBit(hBs)) skip4Ext += 16;
+ } else {
+ /* ancillary data extension status */
+ extDataAvail = FDKreadBit(hBs);
+ }
+
+ /* audio coding and compression status */
+ if (FDKreadBit(hBs)) skip4Ext += 16;
+ /* coarse grain timecode status */
+ if (FDKreadBit(hBs)) skip4Ext += 16;
+ /* fine grain timecode status */
+ if (FDKreadBit(hBs)) skip4Ext += 16;
+
+ /* skip the useless data to get to the DMX levels */
+ FDKpushFor(hBs, skip4Dmx);
+
+ /* downmix_levels_MPEGX */
+ if (dmxLvlAvail) {
+ if (FDKreadBit(hBs)) { /* center_mix_level_on */
+ pBsMetaData->cLevIdx = (UCHAR)FDKreadBits(hBs, 3);
+ foundNewData |= TYPE_DSE_CLEV_DATA;
+ } else {
+ FDKreadBits(hBs, 3);
+ }
+ if (FDKreadBit(hBs)) { /* surround_mix_level_on */
+ pBsMetaData->sLevIdx = (UCHAR)FDKreadBits(hBs, 3);
+ foundNewData |= TYPE_DSE_SLEV_DATA;
+ } else {
+ FDKreadBits(hBs, 3);
+ }
+ }
+
+ /* skip the useless data to get to the ancillary data extension */
+ FDKpushFor(hBs, skip4Ext);
+
+ /* anc data extension (MPEG-4 only) */
+ if (extDataAvail) {
+ int extDmxLvlSt, extDmxGainSt, extDmxLfeSt;
+
+ FDKreadBit(hBs); /* reserved bit */
+ extDmxLvlSt = FDKreadBit(hBs);
+ extDmxGainSt = FDKreadBit(hBs);
+ extDmxLfeSt = FDKreadBit(hBs);
+ FDKreadBits(hBs, 4); /* reserved bits */
+
+ if (extDmxLvlSt) {
+ pBsMetaData->dmixIdxA = (UCHAR)FDKreadBits(hBs, 3);
+ pBsMetaData->dmixIdxB = (UCHAR)FDKreadBits(hBs, 3);
+ FDKreadBits(hBs, 2); /* reserved bits */
+ foundNewData |= TYPE_DSE_DMIX_AB_DATA;
+ }
+ if (extDmxGainSt) {
+ pBsMetaData->dmxGainIdx5 = (UCHAR)FDKreadBits(hBs, 7);
+ FDKreadBit(hBs); /* reserved bit */
+ pBsMetaData->dmxGainIdx2 = (UCHAR)FDKreadBits(hBs, 7);
+ FDKreadBit(hBs); /* reserved bit */
+ foundNewData |= TYPE_DSE_DMX_GAIN_DATA;
+ }
+ if (extDmxLfeSt) {
+ pBsMetaData->dmixIdxLfe = (UCHAR)FDKreadBits(hBs, 4);
+ FDKreadBits(hBs, 4); /* reserved bits */
+ foundNewData |= TYPE_DSE_DMIX_LFE_DATA;
+ }
+ }
+
+ /* final sanity check on the amount of read data */
+ if ((INT)FDKgetValidBits(hBs) < 0) {
+ errorStatus = PCMDMX_CORRUPT_ANC_DATA;
+ }
+
+ if ((errorStatus == PCMDMX_OK) && (foundNewData != 0)) {
+ /* announce new data */
+ pBsMetaData->typeFlags |= foundNewData;
+ /* reset expiry counter */
+ pBsMetaData->expiryCount = 0;
+ }
+
+ return (errorStatus);
+}
+
+/*
+ * Read DMX meta-data from a data stream element.
+ */
+PCMDMX_ERROR pcmDmx_ReadDvbAncData(HANDLE_PCM_DOWNMIX self, UCHAR *pAncDataBuf,
+ UINT ancDataBytes, int isMpeg2) {
+ PCMDMX_ERROR errorStatus = PCMDMX_OK;
+ FDK_BITSTREAM bs;
+ HANDLE_FDK_BITSTREAM hBs = &bs;
+
+ if (self == NULL) {
+ return (PCMDMX_INVALID_HANDLE);
+ }
+
+ /* sanity checks */
+ if ((pAncDataBuf == NULL) || (ancDataBytes == 0)) {
+ return (PCMDMX_CORRUPT_ANC_DATA);
+ }
+
+ FDKinitBitStream(hBs, pAncDataBuf, MAX_DSE_ANC_BYTES, ancDataBytes * 8,
+ BS_READER);
+
+ errorStatus = pcmDmx_Parse(self, hBs, ancDataBytes * 8, isMpeg2);
+
+ return (errorStatus);
+}
+
+/** Set the matrix mixdown information extracted from the PCE of an AAC
+ *bitstream. Note: Call only if matrix_mixdown_idx_present is true.
+ * @param [in] Handle of PCM downmix module instance.
+ * @param [in] The 2 bit matrix mixdown index extracted from PCE.
+ * @param [in] The pseudo surround enable flag extracted from PCE.
+ * @returns Returns an error code.
+ **/
+PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce(HANDLE_PCM_DOWNMIX self,
+ int matrixMixdownPresent,
+ int matrixMixdownIdx,
+ int pseudoSurroundEnable) {
+ if (self == NULL) {
+ return (PCMDMX_INVALID_HANDLE);
+ }
+
+ {
+ DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0];
+
+ if (matrixMixdownPresent) {
+ pBsMetaData->pseudoSurround = (pseudoSurroundEnable) ? 1 : 0;
+ pBsMetaData->matrixMixdownIdx = matrixMixdownIdx & 0x03;
+ pBsMetaData->typeFlags |= TYPE_PCE_DATA;
+ /* Reset expiry counter */
+ pBsMetaData->expiryCount = 0;
+ }
+ }
+
+ return (PCMDMX_OK);
+}
+
+/** Apply down or up mixing.
+ * @param [in] Handle of PCM downmix module instance.
+ * @param [inout] Pointer to buffer that hold the time domain signal.
+ * @param [in] Pointer where the amount of output samples is returned into.
+ * @param [in] Size of pPcmBuf.
+ * @param [inout] Pointer where the amount of output channels is returned into.
+ * @param [in] Input and output samples are processed interleaved.
+ * @param [inout] Array where the corresponding channel type for each output
+ *audio channel is stored into.
+ * @param [inout] Array where the corresponding channel type index for each
+ *output audio channel is stored into.
+ * @param [in] Array containing the out channel mapping to be used (From MPEG
+ *PCE ordering to whatever is required).
+ * @param [out] Pointer on a field receiving the scale factor that has to be
+ *applied on all samples afterwards. If the handed pointer is NULL scaling is
+ *done internally.
+ * @returns Returns an error code.
+ **/
+PCMDMX_ERROR pcmDmx_ApplyFrame(HANDLE_PCM_DOWNMIX self, DMX_PCM *pPcmBuf,
+ const int pcmBufSize, UINT frameSize,
+ INT *nChannels, INT fInterleaved,
+ AUDIO_CHANNEL_TYPE channelType[],
+ UCHAR channelIndices[],
+ const FDK_channelMapDescr *const mapDescr,
+ INT *pDmxOutScale) {
+ PCM_DMX_USER_PARAMS *pParam = NULL;
+ PCMDMX_ERROR errorStatus = PCMDMX_OK;
+ DUAL_CHANNEL_MODE dualChannelMode;
+ PCM_DMX_CHANNEL_MODE inChMode;
+ PCM_DMX_CHANNEL_MODE outChMode;
+ INT devNull; /* Just a dummy to avoid a lot of branches in the code */
+ int numOutChannels, numInChannels;
+ int inStride, outStride, offset;
+ int dmxMaxScale, dmxScale;
+ int slot;
+ UCHAR inOffsetTable[(8)];
+
+ DMX_BS_META_DATA bsMetaData;
+
+ if ((self == NULL) || (nChannels == NULL) || (channelType == NULL) ||
+ (channelIndices == NULL) || (!FDK_chMapDescr_isValid(mapDescr))) {
+ return (PCMDMX_INVALID_HANDLE);
+ }
+
+ /* Init the output scaling */
+ dmxScale = 0;
+ if (pDmxOutScale != NULL) {
+ /* Avoid final scaling internally and hand it to the outside world. */
+ *pDmxOutScale = 0;
+ dmxMaxScale = (3);
+ } else {
+ /* Apply the scaling internally. */
+ pDmxOutScale = &devNull; /* redirect to temporal stack memory */
+ dmxMaxScale = 0;
+ }
+
+ pParam = &self->userParams;
+ numInChannels = *nChannels;
+
+ /* Perform some input sanity checks */
+ if (pPcmBuf == NULL) {
+ return (PCMDMX_INVALID_ARGUMENT);
+ }
+ if (frameSize == 0) {
+ return (PCMDMX_INVALID_ARGUMENT);
+ }
+ if (numInChannels == 0) {
+ return (PCMDMX_INVALID_ARGUMENT);
+ }
+ if (numInChannels > (8)) {
+ return (PCMDMX_INVALID_CH_CONFIG);
+ }
+
+ /* Check on misconfiguration */
+ FDK_ASSERT((pParam->numOutChannelsMax <= 0) ||
+ (pParam->numOutChannelsMax >= pParam->numOutChannelsMin));
+
+ /* Determine if the module has to do processing */
+ if ((self->applyProcessing == 0) &&
+ ((pParam->numOutChannelsMax <= 0) ||
+ (pParam->numOutChannelsMax >= numInChannels)) &&
+ (pParam->numOutChannelsMin <= numInChannels)) {
+ /* Nothing to do */
+ return (errorStatus);
+ }
+
+ /* Determine the number of output channels */
+ if ((pParam->numOutChannelsMax > 0) &&
+ (numInChannels > pParam->numOutChannelsMax)) {
+ numOutChannels = pParam->numOutChannelsMax;
+ } else if (numInChannels < pParam->numOutChannelsMin) {
+ numOutChannels = pParam->numOutChannelsMin;
+ } else {
+ numOutChannels = numInChannels;
+ }
+
+ /* Check I/O buffer size */
+ if ((UINT)pcmBufSize < (UINT)numOutChannels * frameSize) {
+ return (PCMDMX_OUTPUT_BUFFER_TOO_SMALL);
+ }
+
+ dualChannelMode = pParam->dualChannelMode;
+
+ /* Analyse input channel configuration and get channel offset
+ * table that can be accessed with the fixed channel labels. */
+ errorStatus = getChannelMode(numInChannels, channelType, channelIndices,
+ inOffsetTable, &inChMode);
+ if (PCMDMX_IS_FATAL_ERROR(errorStatus) || (inChMode == CH_MODE_UNDEFINED)) {
+ /* We don't need to restore because the channel
+ configuration has not been changed. Just exit. */
+ return (PCMDMX_INVALID_CH_CONFIG);
+ }
+
+ /* Set input stride and offset */
+ if (fInterleaved) {
+ inStride = numInChannels;
+ offset = 1; /* Channel specific offset factor */
+ } else {
+ inStride = 1;
+ offset = frameSize; /* Channel specific offset factor */
+ }
+
+ /* Reset downmix meta data if necessary */
+ if ((pParam->expiryFrame > 0) &&
+ (++self->bsMetaData[0].expiryCount >
+ pParam
+ ->expiryFrame)) { /* The metadata read from bitstream is too old. */
+#ifdef FDK_ASSERT_ENABLE
+ PCMDMX_ERROR err = pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
+ FDK_ASSERT(err == PCMDMX_OK);
+#else
+ pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
+#endif
+ }
+ FDKmemcpy(&bsMetaData, &self->bsMetaData[pParam->frameDelay],
+ sizeof(DMX_BS_META_DATA));
+ /* Maintain delay line */
+ for (slot = pParam->frameDelay; slot > 0; slot -= 1) {
+ FDKmemcpy(&self->bsMetaData[slot], &self->bsMetaData[slot - 1],
+ sizeof(DMX_BS_META_DATA));
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * - - - - - - - - - - - - - - - - - - */
+ if (numInChannels > numOutChannels) { /* Apply downmix */
+ DMX_PCM *pInPcm[(8)] = {NULL};
+ DMX_PCM *pOutPcm[(8)] = {NULL};
+ FIXP_DMX mixFactors[(8)][(8)];
+ UCHAR outOffsetTable[(8)];
+ UINT sample;
+ int chCfg = 0;
+ int bypScale = 0;
+
+ if (numInChannels > SIX_CHANNEL) {
+ AUDIO_CHANNEL_TYPE multiPurposeChType[2];
+
+ /* Get the type of the multipurpose channels */
+ multiPurposeChType[0] =
+ channelType[inOffsetTable[LEFT_MULTIPRPS_CHANNEL]];
+ multiPurposeChType[1] =
+ channelType[inOffsetTable[RIGHT_MULTIPRPS_CHANNEL]];
+
+ /* Check if the input configuration is one defined in the standard. */
+ switch (inChMode) {
+ case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */
+ /* Further analyse the input config to distinguish the two
+ * CH_MODE_5_0_2_1 configs. */
+ if ((multiPurposeChType[0] == ACT_FRONT_TOP) &&
+ (multiPurposeChType[1] == ACT_FRONT_TOP)) {
+ chCfg = 14;
+ } else {
+ chCfg = 7;
+ }
+ break;
+ case CH_MODE_3_0_3_1: /* chCfg 11 */
+ chCfg = 11;
+ break;
+ case CH_MODE_3_0_4_1: /* chCfg 12 */
+ chCfg = 12;
+ break;
+ default:
+ chCfg = 0; /* Not a known config */
+ break;
+ }
+ }
+
+ /* Set this stages output stride and channel mode: */
+ outStride = (fInterleaved) ? numOutChannels : 1;
+ outChMode = outChModeTable[numOutChannels];
+ FDK_ASSERT(outChMode != CH_MODE_UNDEFINED);
+
+ /* Get channel description and channel mapping for the desired output
+ * configuration. */
+ getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
+ outOffsetTable);
+ /* Now there is no way back because we modified the channel configuration!
+ */
+
+ /* Create the DMX matrix */
+ errorStatus =
+ getMixFactors((chCfg > 0) ? 1 : 0,
+ (chCfg > 0) ? (PCM_DMX_CHANNEL_MODE)chCfg : inChMode,
+ outChMode, pParam, &bsMetaData, mixFactors, &dmxScale);
+ /* No fatal errors can occur here. The function is designed to always return
+ a valid matrix. The error code is used to signal configurations and
+ matrices that are not conform to any standard. */
+
+ /* Determine the final scaling */
+ bypScale = fMin(dmxMaxScale, dmxScale);
+ *pDmxOutScale += bypScale;
+ dmxScale -= bypScale;
+
+ { /* Set channel pointer for input. Remove empty cols. */
+ int inCh, outCh, map[(8)];
+ int ch = 0;
+ for (inCh = 0; inCh < (8); inCh += 1) {
+ if (inOffsetTable[inCh] < (UCHAR)numInChannels) {
+ pInPcm[ch] = &pPcmBuf[inOffsetTable[inCh] * offset];
+ map[ch++] = inCh;
+ }
+ }
+ for (; ch < (8); ch += 1) {
+ map[ch] = ch;
+ }
+
+ /* Remove unused cols from factor matrix */
+ for (inCh = 0; inCh < numInChannels; inCh += 1) {
+ if (inCh != map[inCh]) {
+ for (outCh = 0; outCh < (8); outCh += 1) {
+ mixFactors[outCh][inCh] = mixFactors[outCh][map[inCh]];
+ }
+ }
+ }
+
+ /* Set channel pointer for output. Remove empty cols. */
+ ch = 0;
+ for (outCh = 0; outCh < (8); outCh += 1) {
+ if (outOffsetTable[outCh] < (UCHAR)numOutChannels) {
+ pOutPcm[ch] = &pPcmBuf[outOffsetTable[outCh] * offset];
+ map[ch++] = outCh;
+ }
+ }
+ for (; ch < (8); ch += 1) {
+ map[ch] = ch;
+ }
+
+ /* Remove unused rows from factor matrix */
+ for (outCh = 0; outCh < numOutChannels; outCh += 1) {
+ if (outCh != map[outCh]) {
+ FDKmemcpy(&mixFactors[outCh], &mixFactors[map[outCh]],
+ (8) * sizeof(FIXP_DMX));
+ }
+ }
+ }
+
+ /* Sample processing loop */
+ for (sample = 0; sample < frameSize; sample++) {
+ DMX_PCM tIn[(8)] = {0};
+ FIXP_DBL tOut[(8)] = {(FIXP_DBL)0};
+ int inCh, outCh;
+
+ /* Preload all input samples */
+ for (inCh = 0; inCh < numInChannels; inCh += 1) {
+ if (pInPcm[inCh] != NULL) {
+ tIn[inCh] = *pInPcm[inCh];
+ pInPcm[inCh] += inStride;
+ } else {
+ tIn[inCh] = (DMX_PCM)0;
+ }
+ }
+ /* Apply downmix coefficients to input samples and accumulate for output
+ */
+ for (outCh = 0; outCh < numOutChannels; outCh += 1) {
+ for (inCh = 0; inCh < numInChannels; inCh += 1) {
+ tOut[outCh] += fMult((DMX_PCMF)tIn[inCh], mixFactors[outCh][inCh]);
+ }
+ FDK_ASSERT(pOutPcm[outCh] >= pPcmBuf);
+ FDK_ASSERT(pOutPcm[outCh] < &pPcmBuf[pcmBufSize]);
+ /* Write sample */
+ *pOutPcm[outCh] = (DMX_PCM)SATURATE_SHIFT(
+ tOut[outCh], DFRACT_BITS - DMX_PCM_BITS - dmxScale, DMX_PCM_BITS);
+ pOutPcm[outCh] += outStride;
+ }
+ }
+
+ /* Update the number of output channels */
+ *nChannels = numOutChannels;
+
+ } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ - - - - - - - - - - - - - - - - - - */
+ else if (numInChannels < numOutChannels) { /* Apply rudimentary upmix */
+ /* Set up channel pointer */
+ UCHAR outOffsetTable[(8)];
+
+ /* FIRST STAGE
+ Create a stereo/dual channel signal */
+ if (numInChannels == ONE_CHANNEL) {
+ DMX_PCM *pInPcm[(8)];
+ DMX_PCM *pOutLF, *pOutRF;
+ UINT sample;
+
+ /* Set this stages output stride and channel mode: */
+ outStride = (fInterleaved) ? TWO_CHANNEL : 1;
+ outChMode = outChModeTable[TWO_CHANNEL];
+
+ /* Get channel description and channel mapping for this
+ * stages number of output channels (always STEREO). */
+ getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
+ outOffsetTable);
+ /* Now there is no way back because we modified the channel configuration!
+ */
+
+ /* Set input channel pointer. The first channel is always at index 0. */
+ pInPcm[CENTER_FRONT_CHANNEL] =
+ &pPcmBuf[(frameSize - 1) *
+ inStride]; /* Considering input mapping could lead to a
+ invalid pointer here if the channel is not
+ declared to be a front channel. */
+
+ /* Set output channel pointer (for this stage). */
+ pOutLF = &pPcmBuf[outOffsetTable[LEFT_FRONT_CHANNEL] * offset +
+ (frameSize - 1) * outStride];
+ pOutRF = &pPcmBuf[outOffsetTable[RIGHT_FRONT_CHANNEL] * offset +
+ (frameSize - 1) * outStride];
+
+ /* 1/0 input: */
+ for (sample = 0; sample < frameSize; sample++) {
+ /* L' = C; R' = C; */
+ *pOutLF = *pOutRF = *pInPcm[CENTER_FRONT_CHANNEL];
+
+ pInPcm[CENTER_FRONT_CHANNEL] -= inStride;
+ pOutLF -= outStride;
+ pOutRF -= outStride;
+ }
+
+ /* Prepare for next stage: */
+ inStride = outStride;
+ inChMode = outChMode;
+ FDKmemcpy(inOffsetTable, outOffsetTable, (8) * sizeof(UCHAR));
+ }
+
+ /* SECOND STAGE
+ Extend with zero channels to achieved the desired number of output
+ channels. */
+ if (numOutChannels > TWO_CHANNEL) {
+ DMX_PCM *pIn[(8)] = {NULL};
+ DMX_PCM *pOut[(8)] = {NULL};
+ UINT sample;
+ AUDIO_CHANNEL_TYPE inChTypes[(8)];
+ UCHAR inChIndices[(8)];
+ UCHAR numChPerGrp[2][(4)];
+ int nContentCh = 0; /* Number of channels with content */
+ int nEmptyCh = 0; /* Number of channels with content */
+ int ch, chGrp, isCompatible = 1;
+
+ /* Do not change the signalling which is the channel types and indices.
+ Just reorder and add channels. So first save the input signalling. */
+ FDKmemcpy(inChTypes, channelType,
+ numInChannels * sizeof(AUDIO_CHANNEL_TYPE));
+ FDKmemclear(inChTypes + numInChannels,
+ ((8) - numInChannels) * sizeof(AUDIO_CHANNEL_TYPE));
+ FDKmemcpy(inChIndices, channelIndices, numInChannels * sizeof(UCHAR));
+ FDKmemclear(inChIndices + numInChannels,
+ ((8) - numInChannels) * sizeof(UCHAR));
+
+ /* Set this stages output stride and channel mode: */
+ outStride = (fInterleaved) ? numOutChannels : 1;
+ outChMode = outChModeTable[numOutChannels];
+ FDK_ASSERT(outChMode != CH_MODE_UNDEFINED);
+
+ /* Check if input channel config can be easily mapped to the desired
+ * output config. */
+ for (chGrp = 0; chGrp < (4); chGrp += 1) {
+ numChPerGrp[IN][chGrp] = (inChMode >> (chGrp * 4)) & 0xF;
+ numChPerGrp[OUT][chGrp] = (outChMode >> (chGrp * 4)) & 0xF;
+
+ if (numChPerGrp[IN][chGrp] > numChPerGrp[OUT][chGrp]) {
+ isCompatible = 0;
+ break;
+ }
+ }
+
+ if (isCompatible) {
+ /* Get new channel description and channel
+ * mapping for the desired output channel mode. */
+ getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
+ outOffsetTable);
+ /* If the input config has a back center channel but the output
+ config has not, copy it to left and right (if available). */
+ if ((numChPerGrp[IN][CH_GROUP_REAR] % 2) &&
+ !(numChPerGrp[OUT][CH_GROUP_REAR] % 2)) {
+ if (numChPerGrp[IN][CH_GROUP_REAR] == 1) {
+ inOffsetTable[RIGHT_REAR_CHANNEL] =
+ inOffsetTable[LEFT_REAR_CHANNEL];
+ } else if (numChPerGrp[IN][CH_GROUP_REAR] == 3) {
+ inOffsetTable[RIGHT_MULTIPRPS_CHANNEL] =
+ inOffsetTable[LEFT_MULTIPRPS_CHANNEL];
+ }
+ }
+ } else {
+ /* Just copy and extend the original config */
+ FDKmemcpy(outOffsetTable, inOffsetTable, (8) * sizeof(UCHAR));
+ }
+
+ /* Set I/O channel pointer.
+ Note: The following assignment algorithm clears the channel offset
+ tables. Thus they can not be used afterwards. */
+ for (ch = 0; ch < (8); ch += 1) {
+ if ((outOffsetTable[ch] < 255) &&
+ (inOffsetTable[ch] < 255)) { /* Set I/O pointer: */
+ pIn[nContentCh] =
+ &pPcmBuf[inOffsetTable[ch] * offset + (frameSize - 1) * inStride];
+ pOut[nContentCh] = &pPcmBuf[outOffsetTable[ch] * offset +
+ (frameSize - 1) * outStride];
+ /* Update signalling */
+ channelType[outOffsetTable[ch]] = inChTypes[inOffsetTable[ch]];
+ channelIndices[outOffsetTable[ch]] = inChIndices[inOffsetTable[ch]];
+ inOffsetTable[ch] = 255;
+ outOffsetTable[ch] = 255;
+ nContentCh += 1;
+ }
+ }
+ if (isCompatible) {
+ /* Assign the remaining input channels.
+ This is just a safety appliance. We should never need it. */
+ for (ch = 0; ch < (8); ch += 1) {
+ if (inOffsetTable[ch] < 255) {
+ int outCh;
+ for (outCh = 0; outCh < (8); outCh += 1) {
+ if (outOffsetTable[outCh] < 255) {
+ break;
+ }
+ }
+ if (outCh >= (8)) {
+ FDK_ASSERT(0);
+ break;
+ }
+ /* Set I/O pointer: */
+ pIn[nContentCh] = &pPcmBuf[inOffsetTable[ch] * offset +
+ (frameSize - 1) * inStride];
+ pOut[nContentCh] = &pPcmBuf[outOffsetTable[outCh] * offset +
+ (frameSize - 1) * outStride];
+ /* Update signalling */
+ FDK_ASSERT(inOffsetTable[outCh] < numInChannels);
+ FDK_ASSERT(outOffsetTable[outCh] < numOutChannels);
+ channelType[outOffsetTable[outCh]] = inChTypes[inOffsetTable[ch]];
+ channelIndices[outOffsetTable[outCh]] =
+ inChIndices[inOffsetTable[ch]];
+ inOffsetTable[ch] = 255;
+ outOffsetTable[outCh] = 255;
+ nContentCh += 1;
+ }
+ }
+ /* Set the remaining output channel pointer */
+ for (ch = 0; ch < (8); ch += 1) {
+ if (outOffsetTable[ch] < 255) {
+ pOut[nContentCh + nEmptyCh] = &pPcmBuf[outOffsetTable[ch] * offset +
+ (frameSize - 1) * outStride];
+ /* Expand output signalling */
+ channelType[outOffsetTable[ch]] = ACT_NONE;
+ channelIndices[outOffsetTable[ch]] = (UCHAR)nEmptyCh;
+ outOffsetTable[ch] = 255;
+ nEmptyCh += 1;
+ }
+ }
+ } else {
+ /* Set the remaining output channel pointer */
+ for (ch = nContentCh; ch < numOutChannels; ch += 1) {
+ pOut[ch] = &pPcmBuf[ch * offset + (frameSize - 1) * outStride];
+ /* Expand output signalling */
+ channelType[ch] = ACT_NONE;
+ channelIndices[ch] = (UCHAR)nEmptyCh;
+ nEmptyCh += 1;
+ }
+ }
+
+ /* First copy the channels that have signal */
+ for (sample = 0; sample < frameSize; sample += 1) {
+ DMX_PCM tIn[(8)];
+ /* Read all channel samples */
+ for (ch = 0; ch < nContentCh; ch += 1) {
+ tIn[ch] = *pIn[ch];
+ pIn[ch] -= inStride;
+ }
+ /* Write all channel samples */
+ for (ch = 0; ch < nContentCh; ch += 1) {
+ *pOut[ch] = tIn[ch];
+ pOut[ch] -= outStride;
+ }
+ }
+
+ /* Clear all the other channels */
+ for (sample = 0; sample < frameSize; sample++) {
+ for (ch = nContentCh; ch < numOutChannels; ch += 1) {
+ *pOut[ch] = (DMX_PCM)0;
+ pOut[ch] -= outStride;
+ }
+ }
+ }
+
+ /* update the number of output channels */
+ *nChannels = numOutChannels;
+ } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ - - - - - - - - - - - - - - - - - - */
+ else if (numInChannels == numOutChannels) {
+ /* Don't need to change the channel description here */
+
+ switch (numInChannels) {
+ case 2: { /* Set up channel pointer */
+ DMX_PCM *pInPcm[(8)];
+ DMX_PCM *pOutL, *pOutR;
+ FIXP_DMX flev;
+
+ UINT sample;
+
+ if (fInterleaved) {
+ inStride = numInChannels;
+ outStride =
+ 2; /* fixed !!! (below stereo is donwmixed to mono if required */
+ offset = 1; /* Channel specific offset factor */
+ } else {
+ inStride = 1;
+ outStride = 1;
+ offset = frameSize; /* Channel specific offset factor */
+ }
+
+ /* Set input channel pointer */
+ pInPcm[LEFT_FRONT_CHANNEL] =
+ &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL] * offset];
+ pInPcm[RIGHT_FRONT_CHANNEL] =
+ &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL] * offset];
+
+ /* Set output channel pointer (same as input) */
+ pOutL = pInPcm[LEFT_FRONT_CHANNEL];
+ pOutR = pInPcm[RIGHT_FRONT_CHANNEL];
+
+ /* Set downmix levels: */
+ flev = FL2FXCONST_DMX(0.70710678f);
+ /* 2/0 input: */
+ switch (dualChannelMode) {
+ case CH1_MODE: /* L' = 0.707 * Ch1; R' = 0.707 * Ch1 */
+ for (sample = 0; sample < frameSize; sample++) {
+ *pOutL = *pOutR = (DMX_PCM)SATURATE_RIGHT_SHIFT(
+ fMult((DMX_PCMF)*pInPcm[LEFT_FRONT_CHANNEL], flev),
+ DFRACT_BITS - DMX_PCM_BITS, DMX_PCM_BITS);
+
+ pInPcm[LEFT_FRONT_CHANNEL] += inStride;
+ pOutL += outStride;
+ pOutR += outStride;
+ }
+ break;
+ case CH2_MODE: /* L' = 0.707 * Ch2; R' = 0.707 * Ch2 */
+ for (sample = 0; sample < frameSize; sample++) {
+ *pOutL = *pOutR = (DMX_PCM)SATURATE_RIGHT_SHIFT(
+ fMult((DMX_PCMF)*pInPcm[RIGHT_FRONT_CHANNEL], flev),
+ DFRACT_BITS - DMX_PCM_BITS, DMX_PCM_BITS);
+
+ pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
+ pOutL += outStride;
+ pOutR += outStride;
+ }
+ break;
+ case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2; R' = 0.5*Ch1 + 0.5*Ch2 */
+ for (sample = 0; sample < frameSize; sample++) {
+ *pOutL = *pOutR = (*pInPcm[LEFT_FRONT_CHANNEL] >> 1) +
+ (*pInPcm[RIGHT_FRONT_CHANNEL] >> 1);
+
+ pInPcm[LEFT_FRONT_CHANNEL] += inStride;
+ pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
+ pOutL += outStride;
+ pOutR += outStride;
+ }
+ break;
+ default:
+ case STEREO_MODE:
+ /* nothing to do */
+ break;
+ }
+ } break;
+
+ default:
+ /* nothing to do */
+ break;
+ }
+ }
+
+ return (errorStatus);
+}
+
+/** Close an instance of the PCM downmix module.
+ * @param [inout] Pointer to a buffer containing the handle of the instance.
+ * @returns Returns an error code.
+ **/
+PCMDMX_ERROR pcmDmx_Close(HANDLE_PCM_DOWNMIX *pSelf) {
+ if (pSelf == NULL) {
+ return (PCMDMX_INVALID_HANDLE);
+ }
+
+ FreePcmDmxInstance(pSelf);
+ *pSelf = NULL;
+
+ return (PCMDMX_OK);
+}
+
+/** Get library info for this module.
+ * @param [out] Pointer to an allocated LIB_INFO structure.
+ * @returns Returns an error code.
+ */
+PCMDMX_ERROR pcmDmx_GetLibInfo(LIB_INFO *info) {
+ int i;
+
+ if (info == NULL) {
+ return PCMDMX_INVALID_ARGUMENT;
+ }
+
+ /* 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 PCMDMX_INVALID_ARGUMENT;
+ }
+
+ /* Add the library info */
+ info[i].module_id = FDK_PCMDMX;
+ info[i].version =
+ LIB_VERSION(PCMUTIL_LIB_VL0, PCMUTIL_LIB_VL1, PCMUTIL_LIB_VL2);
+ LIB_VERSION_STRING(info + i);
+ info[i].build_date = PCMUTIL_LIB_BUILD_DATE;
+ info[i].build_time = PCMUTIL_LIB_BUILD_TIME;
+ info[i].title = PCMDMX_LIB_TITLE;
+
+ /* Set flags */
+ info[i].flags = 0 | CAPF_DMX_BLIND /* At least blind downmixing is possible */
+ | CAPF_DMX_PCE /* Guided downmix with data from MPEG-2/4
+ Program Config Elements (PCE). */
+ | CAPF_DMX_ARIB /* PCE guided downmix with slightly different
+ equations and levels. */
+ | CAPF_DMX_DVB /* Guided downmix with data from DVB ancillary
+ data fields. */
+ | CAPF_DMX_CH_EXP /* Simple upmixing by dublicating channels
+ or adding zero channels. */
+ | CAPF_DMX_6_CH | CAPF_DMX_8_CH;
+
+ /* Add lib info for FDK tools (if not yet done). */
+ FDK_toolsGetLibInfo(info);
+
+ return PCMDMX_OK;
+}
diff --git a/libPCMutils/src/pcmutils_lib.cpp b/libPCMutils/src/pcmutils_lib.cpp
deleted file mode 100644
index 9303d16..0000000
--- a/libPCMutils/src/pcmutils_lib.cpp
+++ /dev/null
@@ -1,2510 +0,0 @@
-
-/* -----------------------------------------------------------------------------------------------------------
-Software License for The Fraunhofer FDK AAC Codec Library for Android
-
-© Copyright 1995 - 2013 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
------------------------------------------------------------------------------------------------------------ */
-
-/**************************** FDK PCM utils module **************************
-
- Author(s): Christian Griebel
- Description: Defines functions that perform downmixing or a simple channel
- expansion in the PCM time domain.
-
-*******************************************************************************/
-#ifndef __linux__
-#include <log/log.h>
-#endif
-#include "pcmutils_lib.h"
-
-#include "genericStds.h"
-#include "fixpoint_math.h"
-#include "FDK_core.h"
-
-
-/* ------------------------ *
- * GLOBAL SETTINGS (GFR): *
- * ------------------------ */
-#define DSE_METADATA_ENABLE /*!< Enable this to support MPEG/ETSI DVB ancillary data for
- encoder assisted downmixing of MPEG-4 AAC and
- MPEG-1/2 layer 2 streams. */
-#define PCE_METADATA_ENABLE /*!< Enable this to support MPEG matrix mixdown with a
- coefficient carried in the PCE. */
-
-#define PCM_DMX_MAX_IN_CHANNELS ( 8 ) /* Neither the maximum number of input nor the maximum number of output channels ... */
-#define PCM_DMX_MAX_OUT_CHANNELS ( 8 ) /* ... must exceed the maximum number of channels that the framework can handle. */
-
-/* ------------------------ *
- * SPECIFIC SETTINGS: *
- * ------------------------ */
-#define PCM_CHANNEL_EXTENSION_ENABLE /*!< Allow module to duplicate mono signals or add zero channels to achieve the
- desired number of output channels. */
-
-#define PCM_DMX_DFLT_MAX_OUT_CHANNELS ( 6 ) /*!< The maximum number of output channels. If the value is greater than 0 the module
- will automatically create a mixdown for all input signals with more channels
- than specified. */
-#define PCM_DMX_DFLT_MIN_OUT_CHANNELS ( 0 ) /*!< The minimum number of output channels. If the value is greater than 0 the module
- will do channel extension automatically for all input signals with less channels
- than specified. */
-#define PCM_DMX_MAX_DELAY_FRAMES ( 1 ) /*!< The maximum delay frames to align the bitstreams payload with the PCM output. */
-#define PCM_DMX_DFLT_EXPIRY_FRAME ( 50 ) /*!< If value is greater than 0 the mixdown coefficients will expire by default after the
- given number of frames. The value 50 corresponds to at least 500ms (FL 960 @ 96kHz) */
-/* #define PCMDMX_DEBUG */
-
-/* Derived setting:
- * No need to edit beyond this line. */
-#if defined(DSE_METADATA_ENABLE) || defined(PCE_METADATA_ENABLE) || defined(ARIB_MIXDOWN_ENABLE)
- #define PCM_DOWNMIX_ENABLE /*!< Generally enable down mixing. */
-#endif
-#if (PCM_DMX_MAX_IN_CHANNELS > 2) || (PCM_DMX_MAX_OUT_CHANNELS > 2)
- #define PCM_DMX_MAX_CHANNELS ( 8 )
- #define PCM_DMX_MAX_CHANNEL_GROUPS ( 4 )
- #define PCM_DMX_MAX_CHANNELS_PER_GROUP PCM_DMX_MAX_CHANNELS /* All channels can be in one group */
-#else
- #define PCM_DMX_MAX_CHANNELS ( 3 ) /* Need to add 1 because there are three channel positions in first channel group. */
- #define PCM_DMX_MAX_CHANNEL_GROUPS ( 1 ) /* Only front channels supported. */
- #define PCM_DMX_MAX_CHANNELS_PER_GROUP ( 2 ) /* The maximum over all channel groups */
-#endif
-#if (PCM_DMX_MAX_IN_CHANNELS > PCM_DMX_MAX_OUT_CHANNELS)
- #define PCM_DMX_MAX_IO_CHANNELS PCM_DMX_MAX_IN_CHANNELS
-#else
- #define PCM_DMX_MAX_IO_CHANNELS PCM_DMX_MAX_OUT_CHANNELS
-#endif
-
-/* Decoder library info */
-#define PCMDMX_LIB_VL0 2
-#define PCMDMX_LIB_VL1 4
-#define PCMDMX_LIB_VL2 2
-#define PCMDMX_LIB_TITLE "PCM Downmix Lib"
-#ifdef __ANDROID__
-#define PCMDMX_LIB_BUILD_DATE ""
-#define PCMDMX_LIB_BUILD_TIME ""
-#else
-#define PCMDMX_LIB_BUILD_DATE __DATE__
-#define PCMDMX_LIB_BUILD_TIME __TIME__
-#endif
-
-
-/* Fixed and unique channel group indices.
- * The last group index has to be smaller than PCM_DMX_MAX_CHANNEL_GROUPS. */
-#define CH_GROUP_FRONT ( 0 )
-#define CH_GROUP_SIDE ( 1 )
-#define CH_GROUP_REAR ( 2 )
-#define CH_GROUP_LFE ( 3 )
-
-/* The ordering of the following fixed channel labels has to be in MPEG-4 style.
- * From the center to the back with left and right channel interleaved (starting with left).
- * The last channel label index has to be smaller than PCM_DMX_MAX_CHANNELS. */
-#define CENTER_FRONT_CHANNEL ( 0 ) /* C */
-#define LEFT_FRONT_CHANNEL ( 1 ) /* L */
-#define RIGHT_FRONT_CHANNEL ( 2 ) /* R */
-#define LEFT_REAR_CHANNEL ( 3 ) /* Lr (aka left back channel) or center back channel */
-#define RIGHT_REAR_CHANNEL ( 4 ) /* Rr (aka right back channel) */
-#define LOW_FREQUENCY_CHANNEL ( 5 ) /* Lf */
-#define LEFT_MULTIPRPS_CHANNEL ( 6 ) /* Left multipurpose channel */
-#define RIGHT_MULTIPRPS_CHANNEL ( 7 ) /* Right multipurpose channel */
-
-/* More constants */
-#define ONE_CHANNEL ( 1 )
-#define TWO_CHANNEL ( 2 )
-#define SIX_CHANNEL ( 6 )
-#define EIGHT_CHANNEL ( 8 )
-
-#define PCMDMX_A_IDX_DEFAULT ( 2 )
-#define PCMDMX_B_IDX_DEFAULT ( 2 )
-#define PCMDMX_LFE_IDX_DEFAULT ( 15 )
-#define PCMDMX_GAIN_5_DEFAULT ( 0 )
-#define PCMDMX_GAIN_2_DEFAULT ( 0 )
-
-#define PCMDMX_MAX_HEADROOM ( 3 ) /* Defines the maximum PCM scaling headroom that can be done by a
- postprocessing step. This value must be greater or equal to 0. */
-
-#define FALSE 0
-#define TRUE 1
-#define IN 0
-#define OUT 1
-
-/* Type definitions: */
-#ifndef DMX_HIGH_PRECISION_ENABLE
- #define FIXP_DMX FIXP_SGL
- #define FX_DMX2FX_DBL(x) FX_SGL2FX_DBL((FIXP_SGL)(x))
- #define FX_DBL2FX_DMX(x) FX_DBL2FX_SGL(x)
- #define FL2FXCONST_DMX(x) FL2FXCONST_SGL(x)
- #define MAXVAL_DMX MAXVAL_SGL
- #define FX_DMX2SHRT(x) ((SHORT)(x))
- #define FX_DMX2FL(x) FX_DBL2FL(FX_DMX2FX_DBL(x))
-#else
- #define FIXP_DMX FIXP_DBL
- #define FX_DMX2FX_DBL(x) ((FIXP_DBL)(x))
- #define FX_DBL2FX_DMX(x) ((FIXP_DBL)(x)
- #define FL2FXCONST_DMX(x) FL2FXCONST_DBL(x)
- #define MAXVAL_DMX MAXVAL_DBL
- #define FX_DMX2SHRT(x) ((SHORT)((x)>>FRACT_BITS))
- #define FX_DMX2FL(x) FX_DBL2FL(x)
-#endif
-
-/* The number of channels positions for each group in the internal representation.
- * See the channel labels above. */
-static const UCHAR maxChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS] = {
-#if (PCM_DMX_MAX_CHANNELS > 3)
- 3, 0, 2, 1
-#else
- PCM_DMX_MAX_CHANNELS_PER_GROUP
-#endif
-};
-
-/* List of packed channel modes */
-typedef enum
-{ /* CH_MODE_<numFrontCh>_<numSideCh>_<numBackCh>_<numLfCh> */
- CH_MODE_UNDEFINED = 0x0000,
- /* 1 channel */
- CH_MODE_1_0_0_0 = 0x0001, /* chCfg 1 */
- /* 2 channels */
- CH_MODE_2_0_0_0 = 0x0002, /* chCfg 2 */
- /* 3 channels */
- CH_MODE_3_0_0_0 = 0x0003, /* chCfg 3 */
- CH_MODE_2_0_1_0 = 0x0102,
- CH_MODE_2_0_0_1 = 0x1002,
- /* 4 channels */
- CH_MODE_3_0_1_0 = 0x0103, /* chCfg 4 */
- CH_MODE_2_0_2_0 = 0x0202,
- CH_MODE_2_0_1_1 = 0x1102,
- CH_MODE_4_0_0_0 = 0x0004,
- /* 5 channels */
- CH_MODE_3_0_2_0 = 0x0203, /* chCfg 5 */
- CH_MODE_2_0_2_1 = 0x1202,
- CH_MODE_3_0_1_1 = 0x1103,
- CH_MODE_3_2_0_0 = 0x0023,
- CH_MODE_5_0_0_0 = 0x0005,
- /* 6 channels */
- CH_MODE_3_0_2_1 = 0x1203, /* chCfg 6 */
- CH_MODE_3_2_0_1 = 0x1023,
- CH_MODE_3_2_1_0 = 0x0123,
- CH_MODE_5_0_1_0 = 0x0105,
- CH_MODE_6_0_0_0 = 0x0006,
- /* 7 channels */
- CH_MODE_2_2_2_1 = 0x1222,
- CH_MODE_3_0_3_1 = 0x1303, /* chCfg 11 */
- CH_MODE_3_2_1_1 = 0x1123,
- CH_MODE_3_2_2_0 = 0x0223,
- CH_MODE_3_0_2_2 = 0x2203,
- CH_MODE_5_0_2_0 = 0x0205,
- CH_MODE_5_0_1_1 = 0x1105,
- CH_MODE_7_0_0_0 = 0x0007,
- /* 8 channels */
- CH_MODE_3_2_2_1 = 0x1223,
- CH_MODE_3_0_4_1 = 0x1403, /* chCfg 12 */
- CH_MODE_5_0_2_1 = 0x1205, /* chCfg 7 + 14 */
- CH_MODE_5_2_1_0 = 0x0125,
- CH_MODE_3_2_1_2 = 0x2123,
- CH_MODE_2_2_2_2 = 0x2222,
- CH_MODE_3_0_3_2 = 0x2303,
- CH_MODE_8_0_0_0 = 0x0008
-
-} PCM_DMX_CHANNEL_MODE;
-
-
-/* These are the channel configurations linked to
- the number of output channels give by the user: */
-static const PCM_DMX_CHANNEL_MODE outChModeTable[PCM_DMX_MAX_CHANNELS+1] =
-{
- CH_MODE_UNDEFINED,
- CH_MODE_1_0_0_0, /* 1 channel */
- CH_MODE_2_0_0_0, /* 2 channels */
- CH_MODE_3_0_0_0 /* 3 channels */
-#if (PCM_DMX_MAX_CHANNELS > 3)
- ,CH_MODE_3_0_1_0, /* 4 channels */
- CH_MODE_3_0_2_0, /* 5 channels */
- CH_MODE_3_0_2_1, /* 6 channels */
- CH_MODE_3_0_3_1, /* 7 channels */
- CH_MODE_3_0_4_1 /* 8 channels */
-#endif
-};
-
-static const FIXP_DMX abMixLvlValueTab[8] =
-{
- FL2FXCONST_DMX(0.500f), /* scaled by 1 */
- FL2FXCONST_DMX(0.841f),
- FL2FXCONST_DMX(0.707f),
- FL2FXCONST_DMX(0.596f),
- FL2FXCONST_DMX(0.500f),
- FL2FXCONST_DMX(0.422f),
- FL2FXCONST_DMX(0.355f),
- FL2FXCONST_DMX(0.0f)
-};
-
-static const FIXP_DMX lfeMixLvlValueTab[16] =
-{ /* value, scale */
- FL2FXCONST_DMX(0.7905f), /* 2 */
- FL2FXCONST_DMX(0.5000f), /* 2 */
- FL2FXCONST_DMX(0.8395f), /* 1 */
- FL2FXCONST_DMX(0.7065f), /* 1 */
- FL2FXCONST_DMX(0.5945f), /* 1 */
- FL2FXCONST_DMX(0.500f), /* 1 */
- FL2FXCONST_DMX(0.841f), /* 0 */
- FL2FXCONST_DMX(0.707f), /* 0 */
- FL2FXCONST_DMX(0.596f), /* 0 */
- FL2FXCONST_DMX(0.500f), /* 0 */
- FL2FXCONST_DMX(0.316f), /* 0 */
- FL2FXCONST_DMX(0.178f), /* 0 */
- FL2FXCONST_DMX(0.100f), /* 0 */
- FL2FXCONST_DMX(0.032f), /* 0 */
- FL2FXCONST_DMX(0.010f), /* 0 */
- FL2FXCONST_DMX(0.000f) /* 0 */
-};
-
-
-
-#ifdef PCE_METADATA_ENABLE
- /* MPEG matrix mixdown:
- Set 1: L' = (1 + 2^-0.5 + A )^-1 * [L + C * 2^-0.5 + A * Ls];
- R' = (1 + 2^-0.5 + A )^-1 * [R + C * 2^-0.5 + A * Rs];
-
- Set 2: L' = (1 + 2^-0.5 + 2A )^-1 * [L + C * 2^-0.5 - A * (Ls + Rs)];
- R' = (1 + 2^-0.5 + 2A )^-1 * [R + C * 2^-0.5 + A * (Ls + Rs)];
-
- M = (3 + 2A)^-1 * [L + C + R + A*(Ls + Rs)];
- */
- static const FIXP_DMX mpegMixDownIdx2Coef[4] =
- {
- FL2FXCONST_DMX(0.70710678f),
- FL2FXCONST_DMX(0.5f),
- FL2FXCONST_DMX(0.35355339f),
- FL2FXCONST_DMX(0.0f)
- };
-
- static const FIXP_SGL mpegMixDownIdx2PreFact[3][4] =
- { { /* Set 1: */
- FL2FXCONST_DMX(0.4142135623730950f),
- FL2FXCONST_DMX(0.4530818393219728f),
- FL2FXCONST_DMX(0.4852813742385703f),
- FL2FXCONST_DMX(0.5857864376269050f)
- },{ /* Set 2: */
- FL2FXCONST_DMX(0.3203772410170407f),
- FL2FXCONST_DMX(0.3693980625181293f),
- FL2FXCONST_DMX(0.4142135623730950f),
- FL2FXCONST_DMX(0.5857864376269050f)
- },{ /* Mono DMX set: */
- FL2FXCONST_DMX(0.2265409196609864f),
- FL2FXCONST_DMX(0.25f),
- FL2FXCONST_DMX(0.2697521433898179f),
- FL2FXCONST_DMX(0.3333333333333333f) }
- };
-#endif /* PCE_METADATA_ENABLE */
-
-
-#define TYPE_NONE ( 0x0 )
-#define TYPE_DSE_DATA ( 0x1 )
-#define TYPE_PCE_DATA ( 0x2 )
-
-typedef struct
-{
- UINT typeFlags;
- /* From DSE */
- UCHAR cLevIdx;
- UCHAR sLevIdx;
- UCHAR dmixIdxA;
- UCHAR dmixIdxB;
- UCHAR dmixIdxLfe;
- UCHAR dmxGainIdx2;
- UCHAR dmxGainIdx5;
-#ifdef PCE_METADATA_ENABLE
- /* From PCE */
- UCHAR matrixMixdownIdx;
-#endif
- /* Attributes: */
- SCHAR pseudoSurround; /*!< If set to 1 the signal is pseudo surround compatible. The value 0 tells
- that it is not. If the value is -1 the information is not available. */
- UINT expiryCount; /*!< Counter to monitor the life time of a meta data set. */
-
-} DMX_BS_META_DATA;
-
-/* Default metadata */
-static const DMX_BS_META_DATA dfltMetaData = {
- 0, 2, 2, 2, 2, 15, 0, 0,
-#ifdef PCE_METADATA_ENABLE
- 0,
-#endif
- -1, 0
-};
-
-/* Dynamic (user) params:
- See the definition of PCMDMX_PARAM for details on the specific fields. */
-typedef struct
-{
- UINT expiryFrame; /*!< Linked to DMX_BS_DATA_EXPIRY_FRAME */
- DUAL_CHANNEL_MODE dualChannelMode; /*!< Linked to DMX_DUAL_CHANNEL_MODE */
- PSEUDO_SURROUND_MODE pseudoSurrMode; /*!< Linked to DMX_PSEUDO_SURROUND_MODE */
- SHORT numOutChannelsMin; /*!< Linked to MIN_NUMBER_OF_OUTPUT_CHANNELS */
- SHORT numOutChannelsMax; /*!< Linked to MAX_NUMBER_OF_OUTPUT_CHANNELS */
- UCHAR frameDelay; /*!< Linked to DMX_BS_DATA_DELAY */
-
-} PCM_DMX_USER_PARAMS;
-
-/* Modules main data structure: */
-struct PCM_DMX_INSTANCE
-{
- /* Metadata */
- DMX_BS_META_DATA bsMetaData[PCM_DMX_MAX_DELAY_FRAMES+1];
- PCM_DMX_USER_PARAMS userParams;
-
- UCHAR applyProcessing; /*!< Flag to en-/disable modules processing.
- The max channel limiting is done independently. */
-};
-
-/* Memory allocation macro */
-C_ALLOC_MEM_STATIC(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1)
-
-
-/** Evaluate a given channel configuration and extract a packed channel mode. In addition the
- * function generates a channel offset table for the mapping to the internal representation.
- * This function is the inverse to the getChannelDescription() routine.
- * @param [in] The total number of channels of the given configuration.
- * @param [in] Array holding the corresponding channel types for each channel.
- * @param [in] Array holding the corresponding channel type indices for each channel.
- * @param [out] Array where the buffer offsets for each channel are stored into.
- * @param [out] The generated packed channel mode that represents the given input configuration.
- * @returns Returns an error code.
- **/
-static
-PCMDMX_ERROR getChannelMode (
- const INT numChannels, /* in */
- const AUDIO_CHANNEL_TYPE channelType[], /* in */
- const UCHAR channelIndices[], /* in */
- UCHAR offsetTable[PCM_DMX_MAX_CHANNELS], /* out */
- PCM_DMX_CHANNEL_MODE *chMode /* out */
- )
-{
- UCHAR chIdx[PCM_DMX_MAX_CHANNEL_GROUPS][PCM_DMX_MAX_CHANNELS_PER_GROUP];
- UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS]; /* Total num of channels per group of the input config */
- UCHAR numChFree[PCM_DMX_MAX_CHANNEL_GROUPS]; /* Number of free slots per group in the internal repr. */
- UCHAR hardToPlace[PCM_DMX_MAX_CHANNELS]; /* List of channels not matching the internal repr. */
- UCHAR h2pSortIdx[PCM_DMX_MAX_CHANNELS];
- PCMDMX_ERROR err = PCMDMX_OK;
- int ch, grpIdx;
- int numChToPlace = 0;
-
- FDK_ASSERT(channelType != NULL);
- FDK_ASSERT(channelIndices != NULL);
- FDK_ASSERT(offsetTable != NULL);
- FDK_ASSERT(chMode != NULL);
-
- /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */
- FDKmemclear(numChInGrp, PCM_DMX_MAX_CHANNEL_GROUPS*sizeof(UCHAR));
- FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
- FDKmemset(chIdx, 255, PCM_DMX_MAX_CHANNEL_GROUPS*PCM_DMX_MAX_CHANNELS_PER_GROUP*sizeof(UCHAR));
- FDKmemset(hardToPlace, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
- FDKmemset(h2pSortIdx, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
- /* Get the restrictions of the internal representation */
- FDKmemcpy(numChFree, maxChInGrp, PCM_DMX_MAX_CHANNEL_GROUPS*sizeof(UCHAR));
-
- *chMode = CH_MODE_UNDEFINED;
-
- /* Categorize channels */
- for (ch = 0; ch < numChannels; ch += 1) {
- UCHAR chGrpIdx = channelIndices[ch];
- int i = 0, j;
-
- switch (channelType[ch]) {
- case ACT_FRONT_TOP:
- chGrpIdx += numChInGrp[CH_GROUP_FRONT]; /* Append after normal plain */
- case ACT_FRONT:
- grpIdx = CH_GROUP_FRONT;
- break;
-#if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
- case ACT_SIDE_TOP:
- chGrpIdx += numChInGrp[CH_GROUP_SIDE]; /* Append after normal plain */
- case ACT_SIDE:
- grpIdx = CH_GROUP_SIDE;
- break;
- case ACT_BACK_TOP:
- chGrpIdx += numChInGrp[CH_GROUP_REAR]; /* Append after normal plain */
- case ACT_BACK:
- grpIdx = CH_GROUP_REAR;
- break;
- case ACT_LFE:
- grpIdx = CH_GROUP_LFE;
- break;
-#endif
- default:
- /* Found a channel that can not be categorized! Most likely due to corrupt input signalling.
- The rescue strategy is to append it to the front channels (=> ignore index).
- This could cause strange behaviour so return an error to signal it. */
- err = PCMDMX_INVALID_MODE;
- grpIdx = CH_GROUP_FRONT;
- chGrpIdx = numChannels + numChToPlace;
- numChToPlace += 1;
- break;
- }
-
- if (numChInGrp[grpIdx] < PCM_DMX_MAX_CHANNELS_PER_GROUP) {
- /* Sort channels by index */
- while ( (i < numChInGrp[grpIdx]) && (chGrpIdx > channelIndices[chIdx[grpIdx][i]]) ) {
- i += 1;
- }
- for (j = numChInGrp[grpIdx]; j > i; j -= 1) {
- chIdx[grpIdx][j] = chIdx[grpIdx][j-1];
- }
- chIdx[grpIdx][i] = ch;
- numChInGrp[grpIdx] += 1;
- }
- }
-
-#if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
- FDK_ASSERT( (numChInGrp[CH_GROUP_FRONT]+numChInGrp[CH_GROUP_SIDE]
- +numChInGrp[CH_GROUP_REAR]+numChInGrp[CH_GROUP_LFE]) == numChannels);
-#else
- FDK_ASSERT( numChInGrp[CH_GROUP_FRONT] == numChannels );
-#endif
-
- /* Compose channel offset table:
- * Map all channels to the internal representation. */
- numChToPlace = 0;
-
- /* Non-symmetric channels */
- if (numChInGrp[CH_GROUP_FRONT] & 0x1) {
- /* Odd number of front channels -> we have a center channel.
- In MPEG-4 the center has the index 0. */
- offsetTable[CENTER_FRONT_CHANNEL] = chIdx[CH_GROUP_FRONT][0];
- numChFree[CH_GROUP_FRONT] -= 1;
- }
-
- for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
- int chMapPos = 0;
- ch = 0; /* Index of channel within the specific group */
-
- switch (grpIdx) {
- case CH_GROUP_FRONT:
- chMapPos = LEFT_FRONT_CHANNEL;
- ch = numChInGrp[grpIdx] & 0x1;
- break;
-#if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
- case CH_GROUP_SIDE:
- break;
- case CH_GROUP_REAR:
- chMapPos = LEFT_REAR_CHANNEL;
- break;
- case CH_GROUP_LFE:
- chMapPos = LOW_FREQUENCY_CHANNEL;
- break;
-#endif
- default:
- FDK_ASSERT(0);
- continue;
- }
-
- /* Map all channels of the group */
- for ( ; ch < numChInGrp[grpIdx]; ch += 1) {
- if (numChFree[grpIdx] > 0) {
- offsetTable[chMapPos] = chIdx[grpIdx][ch];
- chMapPos += 1;
- numChFree[grpIdx] -= 1;
- } else {
- /* Add to the list of hardship cases considering a MPEG-like sorting order: */
- int pos, sortIdx = grpIdx*PCM_DMX_MAX_CHANNELS_PER_GROUP + channelIndices[chIdx[grpIdx][ch]];
- for (pos = numChToPlace; pos > 0; pos -= 1) {
- if (h2pSortIdx[pos-1] > sortIdx) {
- hardToPlace[pos] = hardToPlace[pos-1];
- h2pSortIdx[pos] = h2pSortIdx[pos-1];
- } else {
- /* Insert channel at the current index/position */
- break;
- }
- }
- hardToPlace[pos] = chIdx[grpIdx][ch];
- h2pSortIdx[pos] = sortIdx;
- numChToPlace += 1;
- }
- }
- }
-
- { /* Assign the hardship cases */
- int chMapPos = 0;
- int mappingHeat = 0;
- for (ch = 0; ch < numChToPlace; ch+=1) {
- int chAssigned = 0;
-
- /* Just assigning the channels to the next best slot can lead to undesired results (especially for x/x/1.x
- configurations). Thus use the MPEG-like sorting index to find the best fitting slot for each channel.
- If this is not possible the sorting index will be ignored (mappingHeat >= 2). */
- for ( ; chMapPos < PCM_DMX_MAX_CHANNELS; chMapPos+=1) {
- if (offsetTable[chMapPos] == 255) {
- int prvSortIdx = 0;
- int nxtSortIdx = (CH_GROUP_LFE+1)*PCM_DMX_MAX_CHANNELS_PER_GROUP;
-
- if (mappingHeat < 2) {
- if (chMapPos < LEFT_REAR_CHANNEL) {
- /* Got front channel slot */
- prvSortIdx = CH_GROUP_FRONT*PCM_DMX_MAX_CHANNELS_PER_GROUP + chMapPos - CENTER_FRONT_CHANNEL;
- nxtSortIdx = CH_GROUP_SIDE *PCM_DMX_MAX_CHANNELS_PER_GROUP;
- }
- else if (chMapPos < LOW_FREQUENCY_CHANNEL) {
- /* Got back channel slot */
- prvSortIdx = CH_GROUP_REAR*PCM_DMX_MAX_CHANNELS_PER_GROUP + chMapPos - LEFT_REAR_CHANNEL;
- nxtSortIdx = CH_GROUP_LFE *PCM_DMX_MAX_CHANNELS_PER_GROUP;
- }
- else if (chMapPos < LEFT_MULTIPRPS_CHANNEL) {
- /* Got lfe channel slot */
- prvSortIdx = CH_GROUP_LFE *PCM_DMX_MAX_CHANNELS_PER_GROUP + chMapPos - LOW_FREQUENCY_CHANNEL;
- nxtSortIdx = (CH_GROUP_LFE+1)*PCM_DMX_MAX_CHANNELS_PER_GROUP;
- }
- }
-
- /* Assign the channel only if its sort index is within the range */
- if ( (h2pSortIdx[ch] >= prvSortIdx)
- && (h2pSortIdx[ch] < nxtSortIdx) ) {
- offsetTable[chMapPos++] = hardToPlace[ch];
- chAssigned = 1;
- break;
- }
- }
- }
- if (chAssigned == 0) {
- chMapPos = 0;
- ch -= 1;
- mappingHeat += 1;
- continue;
- }
- }
- }
-
- /* Compose the channel mode */
- *chMode = (PCM_DMX_CHANNEL_MODE)( (numChInGrp[CH_GROUP_FRONT] & 0xF)
-#if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
- | (numChInGrp[CH_GROUP_SIDE] & 0xF) << 4
- | (numChInGrp[CH_GROUP_REAR] & 0xF) << 8
- | (numChInGrp[CH_GROUP_LFE] & 0xF) << 12
-#endif
- );
-
- return err;
-}
-
-
-/** Generate a channel offset table and complete channel description for a given (packed) channel mode.
- * This function is the inverse to the getChannelMode() routine but does not support weird channel
- * configurations. All channels have to be in the normal height layer and there must not be more
- * channels in each group than given by maxChInGrp.
- * @param [in] The packed channel mode of the configuration to be processed.
- * @param [in] Array containing the channel mapping to be used (From MPEG PCE ordering to whatever is required).
- * @param [out] Array where corresponding channel types for each channels are stored into.
- * @param [out] Array where corresponding channel type indices for each output channel are stored into.
- * @param [out] Array where the buffer offsets for each channel are stored into.
- * @returns None.
- **/
-static
-void getChannelDescription (
- const PCM_DMX_CHANNEL_MODE chMode, /* in */
- const UCHAR channelMapping[][8], /* in */
- AUDIO_CHANNEL_TYPE channelType[], /* out */
- UCHAR channelIndices[], /* out */
- UCHAR offsetTable[PCM_DMX_MAX_CHANNELS] /* out */
- )
-{
- const UCHAR *pChannelMap;
- int grpIdx, ch = 0, numChannels = 0;
- UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS];
-
- FDK_ASSERT(channelType != NULL);
- FDK_ASSERT(channelIndices != NULL);
- FDK_ASSERT(channelMapping != NULL);
- FDK_ASSERT(offsetTable != NULL);
-
- /* Init output arrays */
- FDKmemclear(channelType, PCM_DMX_MAX_IO_CHANNELS*sizeof(AUDIO_CHANNEL_TYPE));
- FDKmemclear(channelIndices, PCM_DMX_MAX_IO_CHANNELS*sizeof(UCHAR));
- FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
-
- /* Extract the number of channels per group */
- numChInGrp[CH_GROUP_FRONT] = chMode & 0xF;
-#if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
- numChInGrp[CH_GROUP_SIDE] = (chMode >> 4) & 0xF;
- numChInGrp[CH_GROUP_REAR] = (chMode >> 8) & 0xF;
- numChInGrp[CH_GROUP_LFE] = (chMode >> 12) & 0xF;
-#endif
-
- /* Summerize to get the total number of channels */
- for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
- numChannels += numChInGrp[grpIdx];
- }
-
- /* Get the appropriate channel map */
- switch (chMode) {
- case CH_MODE_1_0_0_0:
- case CH_MODE_2_0_0_0:
- case CH_MODE_3_0_0_0:
- case CH_MODE_3_0_1_0:
- case CH_MODE_3_0_2_0:
- case CH_MODE_3_0_2_1:
- pChannelMap = channelMapping[numChannels];
- break;
- case CH_MODE_3_0_3_1:
- pChannelMap = channelMapping[11];
- break;
- case CH_MODE_3_0_4_1:
- pChannelMap = channelMapping[12];
- break;
- case CH_MODE_5_0_2_1:
- pChannelMap = channelMapping[7];
- break;
- default:
- /* fallback */
- pChannelMap = channelMapping[0];
- break;
- }
-
- /* Compose channel offset table */
-
- /* Non-symmetric channels */
- if (numChInGrp[CH_GROUP_FRONT] & 0x1) {
- /* Odd number of front channels -> we have a center channel.
- In MPEG-4 the center has the index 0. */
- int mappedIdx = pChannelMap[ch];
- offsetTable[CENTER_FRONT_CHANNEL] = mappedIdx;
- channelType[mappedIdx] = ACT_FRONT;
- channelIndices[mappedIdx] = 0;
- ch += 1;
- }
-
- for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
- AUDIO_CHANNEL_TYPE type = ACT_NONE;
- int chMapPos = 0, maxChannels = 0;
- int chIdx = 0; /* Index of channel within the specific group */
-
- switch (grpIdx) {
- case CH_GROUP_FRONT:
- type = ACT_FRONT;
- chMapPos = LEFT_FRONT_CHANNEL;
- maxChannels = 3;
- chIdx = numChInGrp[grpIdx] & 0x1;
- break;
-#if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
- case CH_GROUP_SIDE:
- /* Always map side channels to the multipurpose group. */
- type = ACT_SIDE;
- chMapPos = LEFT_MULTIPRPS_CHANNEL;
- break;
- case CH_GROUP_REAR:
- type = ACT_BACK;
- chMapPos = LEFT_REAR_CHANNEL;
- maxChannels = 2;
- break;
- case CH_GROUP_LFE:
- type = ACT_LFE;
- chMapPos = LOW_FREQUENCY_CHANNEL;
- maxChannels = 1;
- break;
-#endif
- default:
- break;
- }
-
- /* Map all channels in this group */
- for ( ; chIdx < numChInGrp[grpIdx]; chIdx += 1) {
- int mappedIdx = pChannelMap[ch];
- if (chIdx == maxChannels) {
- /* No space left in this channel group!
- Use the multipurpose group instead: */
- chMapPos = LEFT_MULTIPRPS_CHANNEL;
- }
- offsetTable[chMapPos] = mappedIdx;
- channelType[mappedIdx] = type;
- channelIndices[mappedIdx] = chIdx;
- chMapPos += 1;
- ch += 1;
- }
- }
-}
-
-/** Private helper function for downmix matrix manipulation that initializes
- * one row in a given downmix matrix (corresponding to one output channel).
- * @param [inout] Pointer to fixed-point parts of the downmix matrix.
- * @param [inout] Pointer to scale factor matrix associated to the downmix factors.
- * @param [in] Index of channel (row) to be initialized.
- * @returns Nothing to return.
- **/
-static
-void dmxInitChannel(
- FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
- INT mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
- const unsigned int outCh
- )
-{
- unsigned int inCh;
- for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) {
- if (inCh == outCh) {
- mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.5f);
- mixScales[outCh][inCh] = 1;
- } else {
- mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.0f);
- mixScales[outCh][inCh] = 0;
- }
- }
-}
-
-/** Private helper function for downmix matrix manipulation that does a reset
- * of one row in a given downmix matrix (corresponding to one output channel).
- * @param [inout] Pointer to fixed-point parts of the downmix matrix.
- * @param [inout] Pointer to scale factor matrix associated to the downmix factors.
- * @param [in] Index of channel (row) to be cleared/reset.
- * @returns Nothing to return.
- **/
-static
-void dmxClearChannel(
- FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
- INT mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
- const unsigned int outCh
- )
-{
- FDKmemclear(&mixFactors[outCh], PCM_DMX_MAX_CHANNELS*sizeof(FIXP_DMX));
- FDKmemclear(&mixScales[outCh], PCM_DMX_MAX_CHANNELS*sizeof(INT));
-}
-
-/** Private helper function for downmix matrix manipulation that applies a source channel (row)
- * scaled by a given mix factor to a destination channel (row) in a given downmix matrix.
- * Existing mix factors of the destination channel (row) will get overwritten.
- * @param [inout] Pointer to fixed-point parts of the downmix matrix.
- * @param [inout] Pointer to scale factor matrix associated to the downmix factors.
- * @param [in] Index of source channel (row).
- * @param [in] Index of destination channel (row).
- * @param [in] Fixed-point part of mix factor to be applied.
- * @param [in] Scale factor of mix factor to be applied.
- * @returns Nothing to return.
- **/
-static
-void dmxSetChannel(
- FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
- INT mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
- const unsigned int dstCh,
- const unsigned int srcCh,
- const FIXP_DMX factor,
- const INT scale
- )
-{
- int ch;
- for (ch=0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) {
- if (mixFactors[srcCh][ch] != (FIXP_DMX)0) {
- mixFactors[dstCh][ch] = FX_DBL2FX_DMX(fMult(mixFactors[srcCh][ch], factor));
- mixScales[dstCh][ch] = mixScales[srcCh][ch] + scale;
- }
- }
-}
-
-/** Private helper function for downmix matrix manipulation that adds a source channel (row)
- * scaled by a given mix factor to a destination channel (row) in a given downmix matrix.
- * @param [inout] Pointer to fixed-point parts of the downmix matrix.
- * @param [inout] Pointer to scale factor matrix associated to the downmix factors.
- * @param [in] Index of source channel (row).
- * @param [in] Index of destination channel (row).
- * @param [in] Fixed-point part of mix factor to be applied.
- * @param [in] Scale factor of mix factor to be applied.
- * @returns Nothing to return.
- **/
-static
-void dmxAddChannel(
- FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
- INT mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
- const unsigned int dstCh,
- const unsigned int srcCh,
- const FIXP_DMX factor,
- const INT scale
- )
-{
- int ch;
- for (ch=0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) {
- FIXP_DBL addFact = fMult(mixFactors[srcCh][ch], factor);
- if (addFact != (FIXP_DMX)0) {
- INT newScale = mixScales[srcCh][ch] + scale;
- if (mixFactors[dstCh][ch] != (FIXP_DMX)0) {
- if (newScale > mixScales[dstCh][ch]) {
- mixFactors[dstCh][ch] >>= newScale - mixScales[dstCh][ch];
- } else {
- addFact >>= mixScales[dstCh][ch] - newScale;
- newScale = mixScales[dstCh][ch];
- }
- }
- mixFactors[dstCh][ch] += FX_DBL2FX_DMX(addFact);
- mixScales[dstCh][ch] = newScale;
- }
- }
-}
-
-
-/** Private function that creates a downmix factor matrix depending on the input and output
- * configuration, the user parameters as well as the given metadata. This function is the modules
- * brain and hold all downmix algorithms.
- * @param [in] Flag that indicates if inChMode holds a real (packed) channel mode or has been
- converted to a MPEG-4 channel configuration index.
- * @param [in] Dependent on the inModeIsCfg flag this field hands in a (packed) channel mode or
- the corresponding MPEG-4 channel configuration index.of the input configuration.
- * @param [in] The (packed) channel mode of the output configuration.
- * @param [in] Pointer to structure holding all current user parameter.
- * @param [in] Pointer to field holding all current meta data.
- * @param [out] Pointer to fixed-point parts of the downmix matrix. Normalized to one scale factor.
- * @param [out] The common scale factor of the downmix matrix.
- * @returns An error code.
- **/
-static
-PCMDMX_ERROR getMixFactors (
- const UCHAR inModeIsCfg,
- PCM_DMX_CHANNEL_MODE inChMode,
- const PCM_DMX_CHANNEL_MODE outChMode,
- const PCM_DMX_USER_PARAMS *pParams,
- const DMX_BS_META_DATA *pMetaData,
- FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
- INT *pOutScale
- )
-{
- PCMDMX_ERROR err = PCMDMX_OK;
- INT mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS];
- INT maxScale = 0;
- int numInChannel, numOutChannel;
- unsigned int outCh, inCh, inChCfg = 0;
- unsigned int valid[PCM_DMX_MAX_CHANNELS] = { 0 };
-
- FDK_ASSERT(pMetaData != NULL);
- FDK_ASSERT(mixFactors != NULL);
- /* Check on a supported output configuration */
- FDK_ASSERT( (outChMode == CH_MODE_1_0_0_0)
- || (outChMode == CH_MODE_2_0_0_0)
- || (outChMode == CH_MODE_3_0_2_1) );
-
- if (inModeIsCfg) {
- /* Workaround for the ambiguity of the internal channel modes.
- Convert channel config to channel mode: */
- inChCfg = (unsigned int)inChMode;
- switch (inChCfg) {
- case 1: case 2: case 3:
-#if (PCM_DMX_MAX_CHANNELS > 3)
- case 4: case 5: case 6:
-#endif
- inChMode = outChModeTable[inChCfg];
- break;
- case 11:
- inChMode = CH_MODE_3_0_3_1;
- break;
- case 12:
- inChMode = CH_MODE_3_0_4_1;
- break;
- case 7: case 14:
- inChMode = CH_MODE_5_0_2_1;
- break;
- default:
- FDK_ASSERT(0);
- }
- }
-
- /* Extract the total number of input channels */
- numInChannel = (inChMode&0xF)
- + ((inChMode>> 4)&0xF)
- + ((inChMode>> 8)&0xF)
- + ((inChMode>>12)&0xF);
- /* Extract the total number of output channels */
- numOutChannel = (outChMode&0xF)
- + ((outChMode>> 4)&0xF)
- + ((outChMode>> 8)&0xF)
- + ((outChMode>>12)&0xF);
-
- /* MPEG ammendment 4 aka ETSI metadata and fallback mode: */
-
-
- /* Create identity DMX matrix: */
- for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
- dmxInitChannel( mixFactors, mixScales, outCh );
- }
- if (((inChMode>>12)&0xF) == 0) {
- /* Clear empty or wrongly mapped input channel */
- dmxClearChannel( mixFactors, mixScales, LOW_FREQUENCY_CHANNEL );
- }
-
- /* FIRST STAGE: */
- if (numInChannel > SIX_CHANNEL)
- { /* Always use MPEG equations either with meta data or with default values. */
- FIXP_DMX dMixFactA, dMixFactB;
- INT dMixScaleA, dMixScaleB;
- int isValidCfg = TRUE;
-
- /* Get factors from meta data */
- dMixFactA = abMixLvlValueTab[pMetaData->dmixIdxA];
- dMixScaleA = (pMetaData->dmixIdxA==0) ? 1 : 0;
- dMixFactB = abMixLvlValueTab[pMetaData->dmixIdxB];
- dMixScaleB = (pMetaData->dmixIdxB==0) ? 1 : 0;
-
- /* Check if input is in the list of supported configurations */
- switch (inChMode) {
- case CH_MODE_3_0_3_1: /* chCfg 11 */
- /* 6.1ch: C' = C; L' = L; R' = R; LFE' = LFE;
- Ls' = Ls*dmix_a_idx + Cs*dmix_b_idx;
- Rs' = Rs*dmix_a_idx + Cs*dmix_b_idx; */
- dmxClearChannel( mixFactors, mixScales, RIGHT_MULTIPRPS_CHANNEL ); /* clear empty input channel */
- dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA );
- dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB );
- dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA );
- dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB );
- break;
- case CH_MODE_3_2_1_0:
- case CH_MODE_3_2_1_1: /* chCfg 11 but with side channels */
- /* 6.1ch: C' = C; L' = L; R' = R; LFE' = LFE;
- Ls' = Ls*dmix_a_idx + Cs*dmix_b_idx;
- Rs' = Rs*dmix_a_idx + Cs*dmix_b_idx; */
- dmxClearChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL ); /* clear empty input channel */
- dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactB, dMixScaleB );
- dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA );
- dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactB, dMixScaleB );
- dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA );
- isValidCfg = FALSE;
- err = PCMDMX_INVALID_MODE;
- break;
- case CH_MODE_5_2_1_0:
- case CH_MODE_5_0_1_0:
- case CH_MODE_5_0_1_1:
- /* Ls' = Cs*dmix_a_idx;
- Rs' = Cs*dmix_a_idx; */
- dmxClearChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL ); /* clear empty input channel */
- dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA );
- dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA );
- isValidCfg = FALSE;
- err = PCMDMX_INVALID_MODE;
- break;
- case CH_MODE_3_0_4_1: /* chCfg 12 */
- /* 7.1ch Surround Back: C' = C; L' = L; R' = R; LFE' = LFE;
- Ls' = Ls*dmix_a_idx + Lsr*dmix_b_idx;
- Rs' = Rs*dmix_a_idx + Rsr*dmix_b_idx; */
- dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA );
- dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB );
- dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA );
- dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB );
- break;
- case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */
- if (inChCfg == 14) {
- /* 7.1ch Front Height: C' = C; Ls' = Ls; Rs' = Rs; LFE' = LFE;
- L' = L*dmix_a_idx + Lv*dmix_b_idx;
- R' = R*dmix_a_idx + Rv*dmix_b_idx; */
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, dMixFactA, dMixScaleA );
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, dMixFactA, dMixScaleA );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB );
- } else {
- /* 7.1ch Front: Ls' = Ls; Rs' = Rs; LFE' = LFE;
- C' = C + (Lc+Rc)*dmix_a_idx;
- L' = L + Lc*dmix_b_idx;
- R' = R + Rc*dmix_b_idx;
- CAUTION: L+R are not at (MPEG) index 1+2. */
- dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, dMixFactA, dMixScaleA );
- dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, dMixFactA, dMixScaleA );
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, dMixFactB, dMixScaleB );
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_MULTIPRPS_CHANNEL, FL2FXCONST_DMX(0.5f), 1 );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, dMixFactB, dMixScaleB );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_MULTIPRPS_CHANNEL, FL2FXCONST_DMX(0.5f), 1 );
- }
- break;
- default:
- /* Nothing to do. Just use the identity matrix. */
- isValidCfg = FALSE;
- err = PCMDMX_INVALID_MODE;
- break;
- }
-
- /* Add additional DMX gain */
- if ( (isValidCfg == TRUE)
- && (pMetaData->dmxGainIdx5 != 0))
- { /* Apply DMX gain 5 */
- FIXP_DMX dmxGain;
- INT dmxScale;
- INT sign = (pMetaData->dmxGainIdx5 & 0x40) ? -1 : 1;
- INT val = pMetaData->dmxGainIdx5 & 0x3F;
-
- /* 10^(dmx_gain_5/80) */
- dmxGain = FX_DBL2FX_DMX( fLdPow(
- FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
- (FIXP_DBL)(sign*val*(LONG)FL2FXCONST_DBL(0.0125f)), 0,
- &dmxScale )
- );
- /* Currently only positive scale factors supported! */
- if (dmxScale < 0) {
- dmxGain >>= -dmxScale;
- dmxScale = 0;
- }
-
- dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, dmxGain, dmxScale );
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, dmxGain, dmxScale );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, dmxGain, dmxScale );
- dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dmxGain, dmxScale );
- dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_REAR_CHANNEL, dmxGain, dmxScale );
- dmxSetChannel( mixFactors, mixScales, LOW_FREQUENCY_CHANNEL, LOW_FREQUENCY_CHANNEL, dmxGain, dmxScale );
- }
-
- /* Mark the output channels */
- valid[CENTER_FRONT_CHANNEL] = 1;
- valid[LEFT_FRONT_CHANNEL] = 1;
- valid[RIGHT_FRONT_CHANNEL] = 1;
- valid[LEFT_REAR_CHANNEL] = 1;
- valid[RIGHT_REAR_CHANNEL] = 1;
- valid[LOW_FREQUENCY_CHANNEL] = 1;
-
- /* Update channel mode for the next stage */
- inChMode = CH_MODE_3_0_2_1;
- }
-
- /* SECOND STAGE: */
- if (numOutChannel <= TWO_CHANNEL) {
- /* Create DMX matrix according to input configuration */
- switch (inChMode) {
- case CH_MODE_2_0_0_0: /* chCfg 2 */
- /* Apply the dual channel mode. */
- switch (pParams->dualChannelMode) {
- case CH1_MODE: /* L' = 0.707 * Ch1;
- R' = 0.707 * Ch1; */
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- break;
- case CH2_MODE: /* L' = 0.707 * Ch2;
- R' = 0.707 * Ch2; */
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- break;
- case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2;
- R' = 0.5*Ch1 + 0.5*Ch2; */
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0 );
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0 );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0 );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0 );
- break;
- default:
- case STEREO_MODE:
- /* Nothing to do */
- break;
- }
- break;
- case CH_MODE_2_0_1_0:
- /* L' = L + 0.707*S;
- R' = R + 0.707*S; */
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- break;
- case CH_MODE_3_0_0_0: /* chCfg 3 */
- /* L' = L + 0.707*C;
- R' = R + 0.707*C; */
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- break;
- case CH_MODE_3_0_1_0: /* chCfg 4 */
- /* L' = L + 0.707*C + 0.707*S;
- R' = R + 0.707*C + 0.707*S; */
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
- break;
- case CH_MODE_3_0_2_0: /* chCfg 5 */
- case CH_MODE_3_0_2_1: /* chCfg 6 */
- /* MPEG + ITU + DLB
- But because the default downmix equations and coefficients are equal we stick to MPEG. */
- if ( (pMetaData->typeFlags & TYPE_DSE_DATA)
- || !(pMetaData->typeFlags & TYPE_PCE_DATA) )
- {
- FIXP_DMX cMixLvl, sMixLvl, lMixLvl;
- INT cMixScale, sMixScale, lMixScale;
-
- /* Get factors from meta data */
- cMixLvl = abMixLvlValueTab[pMetaData->cLevIdx];
- cMixScale = (pMetaData->cLevIdx==0) ? 1 : 0;
- sMixLvl = abMixLvlValueTab[pMetaData->sLevIdx];
- sMixScale = (pMetaData->sLevIdx==0) ? 1 : 0;
- lMixLvl = lfeMixLvlValueTab[pMetaData->dmixIdxLfe];
- if (pMetaData->dmixIdxLfe <= 1) {
- lMixScale = 2;
- } else if (pMetaData->dmixIdxLfe <= 5) {
- lMixScale = 1;
- } else {
- lMixScale = 0;
- }
- /* Setup the DMX matrix */
- if ( (pParams->pseudoSurrMode == FORCE_PS_DMX)
- || ((pParams->pseudoSurrMode == AUTO_PS_DMX) && (pMetaData->pseudoSurround==1)))
- { /* L' = L + C*clev - (Ls+Rs)*slev + LFE*lflev;
- R' = R + C*clev + (Ls+Rs)*slev + LFE*lflev; */
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, cMixLvl, cMixScale );
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, -sMixLvl, sMixScale );
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL, -sMixLvl, sMixScale );
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, cMixLvl, cMixScale );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, sMixLvl, sMixScale );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL, sMixLvl, sMixScale );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale );
- }
- else
- { /* L' = L + C*clev + Ls*slev + LFE*llev;
- R' = R + C*clev + Rs*slev + LFE*llev; */
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, cMixLvl, cMixScale );
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, sMixLvl, sMixScale );
- dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, cMixLvl, cMixScale );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL, sMixLvl, sMixScale );
- dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale );
- }
-
- /* Add additional DMX gain */
- if ( pMetaData->dmxGainIdx2 != 0 )
- { /* Apply DMX gain 2 */
- FIXP_DMX dmxGain;
- INT dmxScale;
- INT sign = (pMetaData->dmxGainIdx2 & 0x40) ? -1 : 1;
- INT val = pMetaData->dmxGainIdx2 & 0x3F;
-
- /* 10^(dmx_gain_2/80) */
- dmxGain = FX_DBL2FX_DMX( fLdPow(
- FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
- (FIXP_DBL)(sign*val*(LONG)FL2FXCONST_DBL(0.0125f)), 0,
- &dmxScale )
- );
- /* Currently only positive scale factors supported! */
- if (dmxScale < 0) {
- dmxGain >>= -dmxScale;
- dmxScale = 0;
- }
-
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, dmxGain, dmxScale );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, dmxGain, dmxScale );
- }
- }
-#ifdef PCE_METADATA_ENABLE
- else {
- FIXP_DMX flev, clev, slevLL, slevLR, slevRL, slevRR;
- FIXP_DMX mtrxMixDwnCoef = mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx];
-
- if ( (pParams->pseudoSurrMode == FORCE_PS_DMX)
- || ((pParams->pseudoSurrMode == AUTO_PS_DMX) && (pMetaData->pseudoSurround==1)))
- { /* 3/2 input: L' = (1.707+2*A)^-1 * [L+0.707*C-A*Ls-A*Rs];
- R' = (1.707+2*A)^-1 * [R+0.707*C+A*Ls+A*Rs]; */
- flev = mpegMixDownIdx2PreFact[1][pMetaData->matrixMixdownIdx];
- slevRR = slevRL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
- slevLL = slevLR = -slevRL;
- }
- else {
- /* 3/2 input: L' = (1.707+A)^-1 * [L+0.707*C+A*Ls];
- R' = (1.707+A)^-1 * [R+0.707*C+A*Rs]; */
- flev = mpegMixDownIdx2PreFact[0][pMetaData->matrixMixdownIdx];
- slevRR = slevLL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
- slevLR = slevRL = (FIXP_SGL)0;
- }
- /* common factor */
- clev = FX_DBL2FX_DMX(fMult(flev, mpegMixDownIdx2Coef[0] /* 0.707 */));
-
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, flev, 0 );
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, clev, 0 );
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, slevLL, 0 );
- dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL, slevLR, 0 );
-
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, flev, 0 );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, clev, 0 );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, slevRL, 0 );
- dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL, slevRR, 0 );
- }
-#endif /* PCE_METADATA_ENABLE */
- break;
- default:
- /* This configuration does not fit to any known downmix equation! */
- err = PCMDMX_INVALID_MODE;
- break;
- }
- /* Mark the output channels */
- FDKmemclear(valid, PCM_DMX_MAX_CHANNELS*sizeof(unsigned int));
- valid[LEFT_FRONT_CHANNEL] = 1;
- valid[RIGHT_FRONT_CHANNEL] = 1;
- /* Update channel mode for the next stage */
- inChMode = CH_MODE_2_0_0_0;
- }
-
- if (numOutChannel == ONE_CHANNEL) {
- FIXP_DMX monoMixLevel;
- INT monoMixScale;
-
-#ifdef PCE_METADATA_ENABLE
- if ( (pMetaData->typeFlags & TYPE_PCE_DATA)
- && !(pMetaData->typeFlags & TYPE_DSE_DATA) )
- { /* C' = (3+2*A)^-1 * [C+L+R+A*Ls+A+Rs]; */
- monoMixLevel = mpegMixDownIdx2PreFact[2][pMetaData->matrixMixdownIdx];
- monoMixScale = 0;
-
- dmxClearChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL );
- mixFactors[CENTER_FRONT_CHANNEL][CENTER_FRONT_CHANNEL] = monoMixLevel;
- mixFactors[CENTER_FRONT_CHANNEL][LEFT_FRONT_CHANNEL] = monoMixLevel;
- mixFactors[CENTER_FRONT_CHANNEL][RIGHT_FRONT_CHANNEL] = monoMixLevel;
- monoMixLevel = FX_DBL2FX_DMX(fMult(monoMixLevel, mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx]));
- mixFactors[CENTER_FRONT_CHANNEL][LEFT_REAR_CHANNEL] = monoMixLevel;
- mixFactors[CENTER_FRONT_CHANNEL][RIGHT_REAR_CHANNEL] = monoMixLevel;
- }
- else
-#endif
- { /* C' = L + R; [default] */
- monoMixLevel = FL2FXCONST_DMX(0.5f);
- monoMixScale = 1;
- dmxClearChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL ); /* C is not in the mix */
- dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, monoMixLevel, monoMixScale );
- dmxAddChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, monoMixLevel, monoMixScale );
- }
-
- /* Mark the output channel */
- FDKmemclear(valid, PCM_DMX_MAX_CHANNELS*sizeof(unsigned int));
- valid[CENTER_FRONT_CHANNEL] = 1;
- }
-
-#define MAX_SEARCH_START_VAL ( -7 )
-
- {
- LONG chSum[PCM_DMX_MAX_CHANNELS];
- INT chSumMax = MAX_SEARCH_START_VAL;
-
- /* Determine the current maximum scale factor */
- for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
- if (valid[outCh]!=0) {
- for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) {
- if (mixScales[outCh][inCh] > maxScale)
- { /* Store the new maximum */
- maxScale = mixScales[outCh][inCh];
- }
- }
- }
- }
-
- /* Individualy analyse output chanal levels */
- for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
- chSum[outCh] = MAX_SEARCH_START_VAL;
- if (valid[outCh]!=0) {
- int ovrflwProtScale = 0;
-
- /* Accumulate all factors for each output channel */
- chSum[outCh] = 0;
- for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) {
- SHORT addFact = FX_DMX2SHRT(mixFactors[outCh][inCh]);
- if ( mixScales[outCh][inCh] <= maxScale ) {
- addFact >>= maxScale - mixScales[outCh][inCh];
- } else {
- addFact <<= mixScales[outCh][inCh] - maxScale;
- }
- chSum[outCh] += addFact;
- }
- if (chSum[outCh] > (LONG)MAXVAL_SGL) {
- while (chSum[outCh] > (LONG)MAXVAL_SGL) {
- ovrflwProtScale += 1;
- chSum[outCh] >>= 1;
- }
- } else if (chSum[outCh] > 0) {
- while ((chSum[outCh]<<1) <= (LONG)MAXVAL_SGL) {
- ovrflwProtScale -= 1;
- chSum[outCh] <<= 1;
- }
- }
- /* Store the differential scaling in the same array */
- chSum[outCh] = ovrflwProtScale;
- }
- }
-
- for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
- if ( (valid[outCh] != 0)
- && (chSum[outCh] > chSumMax) )
- { /* Store the new maximum */
- chSumMax = chSum[outCh];
- }
- }
- maxScale = FDKmax(maxScale+chSumMax, 0);
-
- /* Normalize all factors */
- for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
- if (valid[outCh]!=0) {
- for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) {
- if (mixFactors[outCh][inCh] != (FIXP_DMX)0) {
- if ( mixScales[outCh][inCh] <= maxScale ) {
- mixFactors[outCh][inCh] >>= maxScale - mixScales[outCh][inCh];
- } else {
- mixFactors[outCh][inCh] <<= mixScales[outCh][inCh] - maxScale;
- }
- mixScales[outCh][inCh] = maxScale;
- }
- }
- }
- }
- }
-
-
- /* return the scale factor */
- *pOutScale = maxScale;
-
- return (err);
-}
-
-
-/** Open and initialize an instance of the PCM downmix module
- * @param [out] Pointer to a buffer receiving the handle of the new instance.
- * @returns Returns an error code.
- **/
-PCMDMX_ERROR pcmDmx_Open (
- HANDLE_PCM_DOWNMIX *pSelf
- )
-{
- HANDLE_PCM_DOWNMIX self;
-
- if (pSelf == NULL) {
- return (PCMDMX_INVALID_HANDLE);
- }
-
- *pSelf = NULL;
-
- self = (HANDLE_PCM_DOWNMIX) GetPcmDmxInstance( 0 );
- if (self == NULL) {
- return (PCMDMX_OUT_OF_MEMORY);
- }
-
- /* Reset the full instance */
- pcmDmx_Reset( self, PCMDMX_RESET_FULL );
-
- *pSelf = self;
-
- return (PCMDMX_OK);
-}
-
-
-/** Reset all static values like e.g. mixdown coefficients.
- * @param [in] Handle of PCM downmix module instance.
- * @param [in] Flags telling which parts of the module shall be reset.
- * @returns Returns an error code.
- **/
-PCMDMX_ERROR pcmDmx_Reset (
- HANDLE_PCM_DOWNMIX self,
- UINT flags
- )
-{
- if (self == NULL) { return (PCMDMX_INVALID_HANDLE); }
-
- if (flags & PCMDMX_RESET_PARAMS) {
- PCM_DMX_USER_PARAMS *pParams = &self->userParams;
-
- pParams->dualChannelMode = STEREO_MODE;
- pParams->pseudoSurrMode = NEVER_DO_PS_DMX;
- pParams->numOutChannelsMax = PCM_DMX_DFLT_MAX_OUT_CHANNELS;
- pParams->numOutChannelsMin = PCM_DMX_DFLT_MIN_OUT_CHANNELS;
- pParams->frameDelay = 0;
- pParams->expiryFrame = PCM_DMX_DFLT_EXPIRY_FRAME;
-
- self->applyProcessing = 0;
- }
-
- if (flags & PCMDMX_RESET_BS_DATA) {
- int slot;
- /* Init all slots with a default set */
- for (slot = 0; slot <= PCM_DMX_MAX_DELAY_FRAMES; slot += 1) {
- FDKmemcpy(&self->bsMetaData[slot], &dfltMetaData, sizeof(DMX_BS_META_DATA));
- }
- }
-
- return (PCMDMX_OK);
-}
-
-
-/** Set one parameter for one instance of the PCM downmix module.
- * @param [in] Handle of PCM downmix module instance.
- * @param [in] Parameter to be set.
- * @param [in] Parameter value.
- * @returns Returns an error code.
- **/
-PCMDMX_ERROR pcmDmx_SetParam (
- HANDLE_PCM_DOWNMIX self,
- const PCMDMX_PARAM param,
- const INT value
- )
-{
- switch (param)
- {
- case DMX_BS_DATA_EXPIRY_FRAME:
- if (self == NULL)
- return (PCMDMX_INVALID_HANDLE);
- self->userParams.expiryFrame = (value > 0) ? (UINT)value : 0;
- break;
-
- case DMX_BS_DATA_DELAY:
- if ( (value > PCM_DMX_MAX_DELAY_FRAMES)
- || (value < 0) ) {
- return (PCMDMX_UNABLE_TO_SET_PARAM);
- }
- if (self == NULL) {
- return (PCMDMX_INVALID_HANDLE);
- }
- self->userParams.frameDelay = (UCHAR)value;
- break;
-
- case MIN_NUMBER_OF_OUTPUT_CHANNELS:
- switch (value) { /* supported output channels */
- case -1: case 0: case ONE_CHANNEL: case TWO_CHANNEL:
-#if (PCM_DMX_MAX_OUT_CHANNELS >= 6)
- case SIX_CHANNEL:
-#endif
-#if (PCM_DMX_MAX_OUT_CHANNELS >= 8)
- case EIGHT_CHANNEL:
-#endif
- break;
- default:
- return (PCMDMX_UNABLE_TO_SET_PARAM);
- }
- if (self == NULL)
- return (PCMDMX_INVALID_HANDLE);
- /* Store the new value */
- self->userParams.numOutChannelsMin = (value > 0) ? value : -1;
- if ( (value > 0)
- && (self->userParams.numOutChannelsMax > 0)
- && (value > self->userParams.numOutChannelsMax) )
- { /* MIN > MAX would be an invalid state. Thus set MAX = MIN in this case. */
- self->userParams.numOutChannelsMax = self->userParams.numOutChannelsMin;
- }
- break;
-
- case MAX_NUMBER_OF_OUTPUT_CHANNELS:
- switch (value) { /* supported output channels */
- case -1: case 0: case ONE_CHANNEL: case TWO_CHANNEL:
-#if (PCM_DMX_MAX_OUT_CHANNELS >= 6)
- case SIX_CHANNEL:
-#endif
-#if (PCM_DMX_MAX_OUT_CHANNELS >= 8)
- case EIGHT_CHANNEL:
-#endif
- break;
- default:
- return (PCMDMX_UNABLE_TO_SET_PARAM);
- }
- if (self == NULL)
- return (PCMDMX_INVALID_HANDLE);
- /* Store the new value */
- self->userParams.numOutChannelsMax = (value > 0) ? value : -1;
- if ( (value > 0)
- && (value < self->userParams.numOutChannelsMin) )
- { /* MAX < MIN would be an invalid state. Thus set MIN = MAX in this case. */
- self->userParams.numOutChannelsMin = self->userParams.numOutChannelsMax;
- }
- break;
-
- case DMX_DUAL_CHANNEL_MODE:
- switch ((DUAL_CHANNEL_MODE)value) {
- case STEREO_MODE:
- case CH1_MODE:
- case CH2_MODE:
- case MIXED_MODE:
- break;
- default:
- return (PCMDMX_UNABLE_TO_SET_PARAM);
- }
- if (self == NULL)
- return (PCMDMX_INVALID_HANDLE);
- self->userParams.dualChannelMode = (DUAL_CHANNEL_MODE)value;
- self->applyProcessing = 1; /* Force processing */
- break;
-
- case DMX_PSEUDO_SURROUND_MODE:
- switch ((PSEUDO_SURROUND_MODE)value) {
- case NEVER_DO_PS_DMX:
- case AUTO_PS_DMX:
- case FORCE_PS_DMX:
- break;
- default:
- return (PCMDMX_UNABLE_TO_SET_PARAM);
- }
- if (self == NULL)
- return (PCMDMX_INVALID_HANDLE);
- self->userParams.pseudoSurrMode = (PSEUDO_SURROUND_MODE)value;
- break;
-
- default:
- return (PCMDMX_UNKNOWN_PARAM);
- }
-
- return (PCMDMX_OK);
-}
-
-/** Get one parameter value of one PCM downmix module instance.
- * @param [in] Handle of PCM downmix module instance.
- * @param [in] Parameter to be set.
- * @param [out] Pointer to buffer receiving the parameter value.
- * @returns Returns an error code.
- **/
-PCMDMX_ERROR pcmDmx_GetParam (
- HANDLE_PCM_DOWNMIX self,
- const PCMDMX_PARAM param,
- INT * const pValue
- )
-{
- PCM_DMX_USER_PARAMS *pUsrParams;
-
- if ( (self == NULL)
- || (pValue == NULL) ) {
- return (PCMDMX_INVALID_HANDLE);
- }
- pUsrParams = &self->userParams;
-
- switch (param)
- {
- case DMX_BS_DATA_EXPIRY_FRAME:
- *pValue = (INT)pUsrParams->expiryFrame;
- break;
- case DMX_BS_DATA_DELAY:
- *pValue = (INT)pUsrParams->frameDelay;
- break;
- case MIN_NUMBER_OF_OUTPUT_CHANNELS:
- *pValue = (INT)pUsrParams->numOutChannelsMin;
- break;
- case MAX_NUMBER_OF_OUTPUT_CHANNELS:
- *pValue = (INT)pUsrParams->numOutChannelsMax;
- break;
- case DMX_DUAL_CHANNEL_MODE:
- *pValue = (INT)pUsrParams->dualChannelMode;
- break;
- case DMX_PSEUDO_SURROUND_MODE:
- *pValue = (INT)pUsrParams->pseudoSurrMode;
- break;
- default:
- return (PCMDMX_UNKNOWN_PARAM);
- }
-
- return (PCMDMX_OK);
-}
-
-
-#ifdef DSE_METADATA_ENABLE
-
-#define MAX_DSE_ANC_BYTES ( 16 ) /* 15 bytes */
-#define ANC_DATA_SYNC_BYTE ( 0xBC ) /* ancillary data sync byte. */
-
-/*
- * Read DMX meta-data from a data stream element.
- */
-PCMDMX_ERROR pcmDmx_Parse (
- HANDLE_PCM_DOWNMIX self,
- HANDLE_FDK_BITSTREAM hBs,
- UINT ancDataBits,
- int isMpeg2
- )
-{
- PCMDMX_ERROR errorStatus = PCMDMX_OK;
- DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0];
-
- int skip4Dmx = 0, skip4Ext = 0;
- int dmxLvlAvail = 0, extDataAvail = 0;
- int foundNewData = 0;
- UINT minAncBits = ((isMpeg2) ? 5 : 3)*8;
-
- if ( (self == NULL)
- || (hBs == NULL) ) { return (PCMDMX_INVALID_HANDLE); }
-
- ancDataBits = FDKgetValidBits(hBs);
-
- /* sanity checks */
- if ( (ancDataBits < minAncBits)
- || (ancDataBits > FDKgetValidBits(hBs)) ) {
- return (PCMDMX_CORRUPT_ANC_DATA);
- }
-
- pBsMetaData = &self->bsMetaData[0];
-
- if (isMpeg2) {
- /* skip DVD ancillary data */
- FDKpushFor(hBs, 16);
- }
-
- /* check sync word */
- if (FDKreadBits(hBs,8) != ANC_DATA_SYNC_BYTE) {
- return (PCMDMX_CORRUPT_ANC_DATA);
- }
-
- /* skip MPEG audio type and Dolby surround mode */
- FDKpushFor(hBs, 4);
-
- if (isMpeg2) {
- /* int numAncBytes = */ FDKreadBits(hBs, 4);
- /* advanced dynamic range control */
- if (FDKreadBit(hBs)) skip4Dmx += 24;
- /* dialog normalization */
- if (FDKreadBit(hBs)) skip4Dmx += 8;
- /* reproduction_level */
- if (FDKreadBit(hBs)) skip4Dmx += 8;
- } else {
- FDKpushFor(hBs, 2); /* drc presentation mode */
- pBsMetaData->pseudoSurround = FDKreadBit(hBs);
- FDKpushFor(hBs, 4); /* reserved bits */
- }
-
- /* downmixing levels MPEGx status */
- dmxLvlAvail = FDKreadBit(hBs);
-
- if (isMpeg2) {
- /* scale factor CRC status */
- if (FDKreadBit(hBs)) skip4Ext += 16;
- } else {
- /* ancillary data extension status */
- extDataAvail = FDKreadBit(hBs);
- }
-
- /* audio coding and compression status */
- if (FDKreadBit(hBs)) skip4Ext += 16;
- /* coarse grain timecode status */
- if (FDKreadBit(hBs)) skip4Ext += 16;
- /* fine grain timecode status */
- if (FDKreadBit(hBs)) skip4Ext += 16;
-
- /* skip the useless data to get to the DMX levels */
- FDKpushFor(hBs, skip4Dmx);
-
- /* downmix_levels_MPEGX */
- if (dmxLvlAvail)
- {
- if (FDKreadBit(hBs)) { /* center_mix_level_on */
- pBsMetaData->cLevIdx = FDKreadBits(hBs, 3);
- foundNewData = 1;
- } else {
- FDKreadBits(hBs, 3);
- }
- if (FDKreadBit(hBs)) { /* surround_mix_level_on */
- pBsMetaData->sLevIdx = FDKreadBits(hBs, 3);
- foundNewData = 1;
- } else {
- FDKreadBits(hBs, 3);
- }
- }
-
- /* skip the useless data to get to the ancillary data extension */
- FDKpushFor(hBs, skip4Ext);
-
- /* anc data extension (MPEG-4 only) */
- if (extDataAvail) {
- int extDmxLvlSt, extDmxGainSt, extDmxLfeSt;
-
- FDKreadBit(hBs); /* reserved bit */
- extDmxLvlSt = FDKreadBit(hBs);
- extDmxGainSt = FDKreadBit(hBs);
- extDmxLfeSt = FDKreadBit(hBs);
- FDKreadBits(hBs, 4); /* reserved bits */
-
- if (extDmxLvlSt) {
- pBsMetaData->dmixIdxA = FDKreadBits(hBs, 3);
- pBsMetaData->dmixIdxB = FDKreadBits(hBs, 3);
- FDKreadBits(hBs, 2); /* reserved bits */
- foundNewData = 1;
- }
- if (extDmxGainSt) {
- pBsMetaData->dmxGainIdx5 = FDKreadBits(hBs, 7);
- FDKreadBit(hBs); /* reserved bit */
- pBsMetaData->dmxGainIdx2 = FDKreadBits(hBs, 7);
- FDKreadBit(hBs); /* reserved bit */
- foundNewData = 1;
- }
- if (extDmxLfeSt) {
- pBsMetaData->dmixIdxLfe = FDKreadBits(hBs, 4);
- FDKreadBits(hBs, 4); /* reserved bits */
- foundNewData = 1;
- }
- }
-
- /* final sanity check on the amount of read data */
- if ((INT)FDKgetValidBits(hBs) < 0) {
- errorStatus = PCMDMX_CORRUPT_ANC_DATA;
- }
-
- if ( (errorStatus == PCMDMX_OK)
- && (foundNewData == 1) ) {
- /* announce new data */
- pBsMetaData->typeFlags |= TYPE_DSE_DATA;
- /* reset expiry counter */
- pBsMetaData->expiryCount = 0;
- }
-
- return (errorStatus);
-}
-
-/*
- * Read DMX meta-data from a data stream element.
- */
-PCMDMX_ERROR pcmDmx_ReadDvbAncData (
- HANDLE_PCM_DOWNMIX self,
- UCHAR *pAncDataBuf,
- UINT ancDataBytes,
- int isMpeg2
- )
-{
- FDK_BITSTREAM bs;
- HANDLE_FDK_BITSTREAM hBs = &bs;
- PCMDMX_ERROR errorStatus = PCMDMX_OK;
-
- if (self == NULL) { return (PCMDMX_INVALID_HANDLE); }
-
- /* sanity checks */
- if ( (pAncDataBuf == NULL)
- || (ancDataBytes == 0) ) {
- return (PCMDMX_CORRUPT_ANC_DATA);
- }
-
- FDKinitBitStream (hBs, pAncDataBuf, MAX_DSE_ANC_BYTES, ancDataBytes*8, BS_READER);
-
- errorStatus = pcmDmx_Parse (
- self,
- hBs,
- ancDataBytes*8,
- isMpeg2 );
-
- return (errorStatus);
-}
-#endif /* DSE_METADATA_ENABLE */
-
-#ifdef PCE_METADATA_ENABLE
-/** Set the matrix mixdown information extracted from the PCE of an AAC bitstream.
- * Note: Call only if matrix_mixdown_idx_present is true.
- * @param [in] Handle of PCM downmix module instance.
- * @param [in] The 2 bit matrix mixdown index extracted from PCE.
- * @param [in] The pseudo surround enable flag extracted from PCE.
- * @returns Returns an error code.
- **/
-PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce (
- HANDLE_PCM_DOWNMIX self,
- int matrixMixdownPresent,
- int matrixMixdownIdx,
- int pseudoSurroundEnable
- )
-{
- DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0];
-
- if (self == NULL) {
- return (PCMDMX_INVALID_HANDLE);
- }
-
- if (matrixMixdownPresent) {
- pBsMetaData->pseudoSurround = pseudoSurroundEnable;
- pBsMetaData->matrixMixdownIdx = matrixMixdownIdx & 0x03;
- pBsMetaData->typeFlags |= TYPE_PCE_DATA;
- /* Reset expiry counter */
- pBsMetaData->expiryCount = 0;
- }
-
- return (PCMDMX_OK);
-}
-#endif /* PCE_METADATA_ENABLE */
-
-
-/** Apply down or up mixing.
- * @param [in] Handle of PCM downmix module instance.
- * @param [inout] Pointer to buffer that hold the time domain signal.
- * @param [in] Pointer where the amount of output samples is returned into.
- * @param [inout] Pointer where the amount of output channels is returned into.
- * @param [in] Flag which indicates if output time data are writtern interleaved or as subsequent blocks.
- * @param [inout] Array where the corresponding channel type for each output audio channel is stored into.
- * @param [inout] Array where the corresponding channel type index for each output audio channel is stored into.
- * @param [in] Array containing the out channel mapping to be used (From MPEG PCE ordering to whatever is required).
- * @param [out] Pointer on a field receiving the scale factor that has to be applied on all samples afterwards.
- * If the handed pointer is NULL scaling is done internally.
- * @returns Returns an error code.
- **/
-PCMDMX_ERROR pcmDmx_ApplyFrame (
- HANDLE_PCM_DOWNMIX self,
- INT_PCM *pPcmBuf,
- UINT frameSize,
- INT *nChannels,
- int fInterleaved,
- AUDIO_CHANNEL_TYPE channelType[],
- UCHAR channelIndices[],
- const UCHAR channelMapping[][8],
- INT *pDmxOutScale
- )
-{
- PCM_DMX_USER_PARAMS *pParam = NULL;
- PCMDMX_ERROR errorStatus = PCMDMX_OK;
- DUAL_CHANNEL_MODE dualChannelMode;
- PCM_DMX_CHANNEL_MODE inChMode;
- PCM_DMX_CHANNEL_MODE outChMode;
- INT devNull; /* Just a dummy to avoid a lot of branches in the code */
- int numOutChannels, numInChannels;
- int inStride, outStride, offset;
- int dmxMaxScale, dmxScale;
- int ch, slot;
- UCHAR inOffsetTable[PCM_DMX_MAX_CHANNELS];
-
- DMX_BS_META_DATA bsMetaData;
-
- if ( (self == NULL)
- || (nChannels == NULL)
- || (channelType == NULL)
- || (channelIndices == NULL)
- || (channelMapping == NULL) ) {
- return (PCMDMX_INVALID_HANDLE);
- }
-
- /* Init the output scaling */
- dmxScale = 0;
- if (pDmxOutScale != NULL) {
- /* Avoid final scaling internally and hand it to the outside world. */
- *pDmxOutScale = 0;
- dmxMaxScale = PCMDMX_MAX_HEADROOM;
- } else {
- /* Apply the scaling internally. */
- pDmxOutScale = &devNull; /* redirect to temporal stack memory */
- dmxMaxScale = 0;
- }
-
- pParam = &self->userParams;
- numInChannels = *nChannels;
-
- /* Perform some input sanity checks */
- if (pPcmBuf == NULL) { return (PCMDMX_INVALID_ARGUMENT); }
- if (frameSize == 0) { return (PCMDMX_INVALID_ARGUMENT); }
- if ( (numInChannels == 0)
- || (numInChannels > PCM_DMX_MAX_IN_CHANNELS) )
- { return (PCMDMX_INVALID_ARGUMENT); }
-
- /* Check on misconfiguration */
- FDK_ASSERT( (pParam->numOutChannelsMax <= 0) \
- || (pParam->numOutChannelsMax >= pParam->numOutChannelsMin));
-
- /* Determine if the module has to do processing */
- if ( (self->applyProcessing == 0)
- && ((pParam->numOutChannelsMax <= 0)
- || (pParam->numOutChannelsMax >= numInChannels))
- && (pParam->numOutChannelsMin <= numInChannels) ) {
- /* Nothing to do */
- return (errorStatus);
- }
-
- /* Determine the number of output channels */
- if ( (pParam->numOutChannelsMax > 0)
- && (numInChannels > pParam->numOutChannelsMax) ) {
- numOutChannels = pParam->numOutChannelsMax;
- }
- else if (numInChannels < pParam->numOutChannelsMin) {
- numOutChannels = pParam->numOutChannelsMin;
- }
- else {
- numOutChannels = numInChannels;
- }
-
- dualChannelMode = pParam->dualChannelMode;
-
- /* Analyse input channel configuration and get channel offset
- * table that can be accessed with the fixed channel labels. */
- errorStatus = getChannelMode(
- numInChannels,
- channelType,
- channelIndices,
- inOffsetTable,
- &inChMode
- );
- if ( PCMDMX_IS_FATAL_ERROR(errorStatus)
- || (inChMode == CH_MODE_UNDEFINED) ) {
- /* We don't need to restore because the channel
- configuration has not been changed. Just exit. */
- return (PCMDMX_INVALID_CH_CONFIG);
- }
-
- /* Set input stride and offset */
- if (fInterleaved) {
- inStride = numInChannels;
- offset = 1; /* Channel specific offset factor */
- } else {
- inStride = 1;
- offset = frameSize; /* Channel specific offset factor */
- }
-
- /* Reset downmix meta data if necessary */
- if ( (pParam->expiryFrame > 0)
- && (++self->bsMetaData[0].expiryCount > pParam->expiryFrame) )
- { /* The metadata read from bitstream is too old. */
- PCMDMX_ERROR err = pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
- FDK_ASSERT(err == PCMDMX_OK);
- }
- FDKmemcpy(&bsMetaData, &self->bsMetaData[pParam->frameDelay], sizeof(DMX_BS_META_DATA));
- /* Maintain delay line */
- for (slot = pParam->frameDelay; slot > 0; slot -= 1) {
- FDKmemcpy(&self->bsMetaData[slot], &self->bsMetaData[slot-1], sizeof(DMX_BS_META_DATA));
- }
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-#ifdef PCM_DOWNMIX_ENABLE
- if ( numInChannels > numOutChannels )
- { /* Apply downmix */
- INT_PCM *pInPcm[PCM_DMX_MAX_IN_CHANNELS] = { NULL };
- INT_PCM *pOutPcm[PCM_DMX_MAX_OUT_CHANNELS] = { NULL };
- FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS];
- UCHAR outOffsetTable[PCM_DMX_MAX_CHANNELS];
- UINT sample;
- int chCfg = 0;
- int bypScale = 0;
-
-#if (PCM_DMX_MAX_IN_CHANNELS >= 7)
- if (numInChannels > SIX_CHANNEL) {
- AUDIO_CHANNEL_TYPE multiPurposeChType[2];
-
- /* Get the type of the multipurpose channels */
- multiPurposeChType[0] = channelType[inOffsetTable[LEFT_MULTIPRPS_CHANNEL]];
- multiPurposeChType[1] = channelType[inOffsetTable[RIGHT_MULTIPRPS_CHANNEL]];
-
- /* Check if the input configuration is one defined in the standard. */
- switch (inChMode) {
- case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */
- /* Further analyse the input config to distinguish the two CH_MODE_5_0_2_1 configs. */
- if ( (multiPurposeChType[0] == ACT_FRONT_TOP)
- && (multiPurposeChType[1] == ACT_FRONT_TOP) ) {
- chCfg = 14;
- } else {
- chCfg = 7;
- }
- break;
- case CH_MODE_3_0_3_1: /* chCfg 11 */
- chCfg = 11;
- break;
- case CH_MODE_3_0_4_1: /* chCfg 12 */
- chCfg = 12;
- break;
- default:
- chCfg = 0; /* Not a known config */
- break;
- }
- }
-#endif
-
- /* Set this stages output stride and channel mode: */
- outStride = (fInterleaved) ? numOutChannels : 1;
- outChMode = outChModeTable[numOutChannels];
-
- /* Get channel description and channel mapping for the desired output configuration. */
- getChannelDescription(
- outChMode,
- channelMapping,
- channelType,
- channelIndices,
- outOffsetTable
- );
- /* Now there is no way back because we modified the channel configuration! */
-
- /* Create the DMX matrix */
- errorStatus = getMixFactors (
- (chCfg>0) ? 1 : 0,
- (chCfg>0) ? (PCM_DMX_CHANNEL_MODE)chCfg : inChMode,
- outChMode,
- pParam,
- &bsMetaData,
- mixFactors,
- &dmxScale
- );
- /* No fatal errors can occur here. The function is designed to always return a valid matrix.
- The error code is used to signal configurations and matrices that are not conform to any standard. */
-
- /* Determine the final scaling */
- bypScale = FDKmin(dmxMaxScale, dmxScale);
- *pDmxOutScale += bypScale;
- dmxScale -= bypScale;
-
- { /* Set channel pointer for input. Remove empty cols. */
- int inCh, outCh, map[PCM_DMX_MAX_CHANNELS];
- ch = 0;
- for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) {
- if (inOffsetTable[inCh] != 255) {
- pInPcm[ch] = &pPcmBuf[inOffsetTable[inCh]*offset];
- map[ch++] = inCh;
- }
- }
- if (ch != numInChannels) {
-#ifndef __linux__
- ALOGE("b/23876444");
-#endif
- return PCMDMX_INVALID_ARGUMENT;
- }
-
- /* Remove unused cols from factor matrix */
- for (inCh=0; inCh < numInChannels; inCh+=1) {
- if (inCh != map[inCh]) {
- int outCh;
- for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
- mixFactors[outCh][inCh] = mixFactors[outCh][map[inCh]];
- }
- }
- }
-
- /* Set channel pointer for output. Remove empty cols. */
- ch = 0;
- for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
- if (outOffsetTable[outCh] != 255) {
- pOutPcm[ch] = &pPcmBuf[outOffsetTable[outCh]*offset];
- map[ch++] = outCh;
- }
- }
- FDK_ASSERT(ch == numOutChannels);
-
- /* Remove unused rows from factor matrix */
- for (outCh=0; outCh < numOutChannels; outCh+=1) {
- if (outCh != map[outCh]) {
- FDKmemcpy(&mixFactors[outCh], &mixFactors[map[outCh]], PCM_DMX_MAX_CHANNELS*sizeof(FIXP_DMX));
- }
- }
- }
-
- /* Sample processing loop */
- for (sample = 0; sample < frameSize; sample++)
- {
- FIXP_PCM tIn[PCM_DMX_MAX_IN_CHANNELS];
- FIXP_DBL tOut[PCM_DMX_MAX_OUT_CHANNELS] = { (FIXP_DBL)0 };
- int inCh, outCh;
-
- /* Preload all input samples */
- for (inCh=0; inCh < numInChannels; inCh+=1) {
- tIn[inCh] = (FIXP_PCM)*pInPcm[inCh];
- pInPcm[inCh] += inStride;
- }
- /* Apply downmix coefficients to input samples and accumulate for output */
- for (outCh=0; outCh < numOutChannels; outCh+=1) {
- for (inCh=0; inCh < numInChannels; inCh+=1) {
- tOut[outCh] += fMult(tIn[inCh], mixFactors[outCh][inCh]);
- }
- /* Write sample */
-#if (SAMPLE_BITS == DFRACT_BITS)
- *pOutPcm[outCh] = (INT_PCM)SATURATE_LEFT_SHIFT(tOut[outCh], dmxScale, SAMPLE_BITS);
-#else
- *pOutPcm[outCh] = (INT_PCM)SATURATE_RIGHT_SHIFT(tOut[outCh], DFRACT_BITS-SAMPLE_BITS-dmxScale, SAMPLE_BITS);
-#endif
- pOutPcm[outCh] += outStride;
- }
- }
-
- /* Update the number of output channels */
- *nChannels = numOutChannels;
-
- } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- else
-#endif /* PCM_DOWNMIX_ENABLE */
-#ifdef PCM_CHANNEL_EXTENSION_ENABLE
- if ( numInChannels < numOutChannels )
- { /* Apply rudimentary upmix */
- /* Set up channel pointer */
- UINT sample;
- UCHAR outOffsetTable[PCM_DMX_MAX_CHANNELS];
-
- /* FIRST STAGE
- Create a stereo/dual channel signal */
- if (numInChannels == ONE_CHANNEL)
- {
- INT_PCM *pInPcm[PCM_DMX_MAX_CHANNELS];
- INT_PCM *pOutLF, *pOutRF;
-
- /* Set this stages output stride and channel mode: */
- outStride = (fInterleaved) ? TWO_CHANNEL : 1;
- outChMode = outChModeTable[TWO_CHANNEL];
-
- /* Get channel description and channel mapping for this
- * stages number of output channels (always STEREO). */
- getChannelDescription(
- outChMode,
- channelMapping,
- channelType,
- channelIndices,
- outOffsetTable
- );
- /* Now there is no way back because we modified the channel configuration! */
-
- /* Set input channel pointer. The first channel is always at index 0. */
- pInPcm[CENTER_FRONT_CHANNEL] = &pPcmBuf[(frameSize-1)*inStride]; /* Considering input mapping could lead to a invalid pointer
- here if the channel is not declared to be a front channel. */
-
- /* Set output channel pointer (for this stage). */
- pOutLF = &pPcmBuf[outOffsetTable[LEFT_FRONT_CHANNEL]*offset+(frameSize-1)*outStride];
- pOutRF = &pPcmBuf[outOffsetTable[RIGHT_FRONT_CHANNEL]*offset+(frameSize-1)*outStride];
-
- /* 1/0 input: */
- for (sample = 0; sample < frameSize; sample++) {
- /* L' = C; R' = C; */
- *pOutLF = *pOutRF = *pInPcm[CENTER_FRONT_CHANNEL];
-
- pInPcm[CENTER_FRONT_CHANNEL] -= inStride;
- pOutLF -= outStride; pOutRF -= outStride;
- }
-
- /* Prepare for next stage: */
- inStride = outStride;
- inChMode = outChMode;
- FDKmemcpy(inOffsetTable, outOffsetTable, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
- }
-
-#if (PCM_DMX_MAX_OUT_CHANNELS > 2)
- /* SECOND STAGE
- Extend with zero channels to achieved the desired number of output channels. */
- if (numOutChannels > TWO_CHANNEL)
- {
- INT_PCM *pIn[PCM_DMX_MAX_CHANNELS] = { NULL };
- INT_PCM *pOut[PCM_DMX_MAX_CHANNELS] = { NULL };
- AUDIO_CHANNEL_TYPE inChTypes[PCM_DMX_MAX_CHANNELS];
- UCHAR inChIndices[PCM_DMX_MAX_CHANNELS];
- UCHAR numChPerGrp[2][PCM_DMX_MAX_CHANNEL_GROUPS];
- int nContentCh = 0; /* Number of channels with content */
- int nEmptyCh = 0; /* Number of channels with content */
- int ch, chGrp, isCompatible = 1;
-
- /* Do not change the signalling which is the channel types and indices.
- Just reorder and add channels. So first save the input signalling. */
- FDKmemcpy(inChTypes, channelType, PCM_DMX_MAX_CHANNELS*sizeof(AUDIO_CHANNEL_TYPE));
- FDKmemcpy(inChIndices, channelIndices, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
-
- /* Set this stages output stride and channel mode: */
- outStride = (fInterleaved) ? numOutChannels : 1;
- outChMode = outChModeTable[numOutChannels];
-
- /* Check if input channel config can be easily mapped to the desired output config. */
- for (chGrp = 0; chGrp < PCM_DMX_MAX_CHANNEL_GROUPS; chGrp += 1) {
- numChPerGrp[IN][chGrp] = (inChMode >> (chGrp*4)) & 0xF;
- numChPerGrp[OUT][chGrp] = (outChMode >> (chGrp*4)) & 0xF;
-
- if (numChPerGrp[IN][chGrp] > numChPerGrp[OUT][chGrp]) {
- isCompatible = 0;
- break;
- }
- }
-
- if ( isCompatible ) {
- /* Get new channel description and channel
- * mapping for the desired output channel mode. */
- getChannelDescription(
- outChMode,
- channelMapping,
- channelType,
- channelIndices,
- outOffsetTable
- );
- /* If the input config has a back center channel but the output
- config has not, copy it to left and right (if available). */
- if ( (numChPerGrp[IN][CH_GROUP_REAR]%2)
- && !(numChPerGrp[OUT][CH_GROUP_REAR]%2) ) {
- if (numChPerGrp[IN][CH_GROUP_REAR] == 1) {
- inOffsetTable[RIGHT_REAR_CHANNEL] = inOffsetTable[LEFT_REAR_CHANNEL];
- } else if (numChPerGrp[IN][CH_GROUP_REAR] == 3) {
- inOffsetTable[RIGHT_MULTIPRPS_CHANNEL] = inOffsetTable[LEFT_MULTIPRPS_CHANNEL];
- }
- }
- }
- else {
- /* Just copy and extend the original config */
- FDKmemcpy(outOffsetTable, inOffsetTable, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
- }
-
- /* Set I/O channel pointer.
- Note: The following assignment algorithm clears the channel offset tables.
- Thus they can not be used afterwards. */
- for (ch = 0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) {
- if ( (outOffsetTable[ch] < 255)
- && (inOffsetTable[ch] < 255) )
- { /* Set I/O pointer: */
- pIn[nContentCh] = &pPcmBuf[inOffsetTable[ch]*offset+(frameSize-1)*inStride];
- pOut[nContentCh] = &pPcmBuf[outOffsetTable[ch]*offset+(frameSize-1)*outStride];
- /* Update signalling */
- channelType[outOffsetTable[ch]] = inChTypes[inOffsetTable[ch]];
- channelIndices[outOffsetTable[ch]] = inChIndices[inOffsetTable[ch]];
- inOffsetTable[ch] = 255;
- outOffsetTable[ch] = 255;
- nContentCh += 1;
- }
- }
- if ( isCompatible ) {
- /* Assign the remaining input channels.
- This is just a safety appliance. We should never need it. */
- for (ch = 0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) {
- if (inOffsetTable[ch] < 255) {
- int outCh;
- for (outCh = 0 ; outCh < PCM_DMX_MAX_CHANNELS; outCh += 1) {
- if (outOffsetTable[outCh] < 255) {
- break;
- }
- }
- /* Set I/O pointer: */
- pIn[nContentCh] = &pPcmBuf[inOffsetTable[ch]*offset+(frameSize-1)*inStride];
- pOut[nContentCh] = &pPcmBuf[outOffsetTable[outCh]*offset+(frameSize-1)*outStride];
- /* Update signalling */
- channelType[outOffsetTable[outCh]] = inChTypes[inOffsetTable[ch]];
- channelIndices[outOffsetTable[outCh]] = inChIndices[inOffsetTable[ch]];
- inOffsetTable[ch] = 255;
- outOffsetTable[outCh] = 255;
- nContentCh += 1;
- }
- }
- /* Set the remaining output channel pointer */
- for (ch = 0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) {
- if (outOffsetTable[ch] < 255) {
- pOut[nContentCh+nEmptyCh] = &pPcmBuf[outOffsetTable[ch]*offset+(frameSize-1)*outStride];
- /* Expand output signalling */
- channelType[outOffsetTable[ch]] = ACT_NONE;
- channelIndices[outOffsetTable[ch]] = nEmptyCh;
- outOffsetTable[ch] = 255;
- nEmptyCh += 1;
- }
- }
- }
- else {
- /* Set the remaining output channel pointer */
- for (ch = nContentCh; ch < numOutChannels; ch+=1) {
- pOut[ch] = &pPcmBuf[ch*offset+(frameSize-1)*outStride];
- /* Expand output signalling */
- channelType[ch] = ACT_NONE;
- channelIndices[ch] = nEmptyCh;
- nEmptyCh += 1;
- }
- }
-
- /* First copy the channels that have signal */
- for (sample = 0; sample < frameSize; sample+=1) {
- INT_PCM tIn[PCM_DMX_MAX_CHANNELS];
- /* Read all channel samples */
- for (ch = 0; ch < nContentCh; ch+=1) {
- tIn[ch] = *pIn[ch];
- pIn[ch] -= inStride;
- }
- /* Write all channel samples */
- for (ch = 0; ch < nContentCh; ch+=1) {
- *pOut[ch] = tIn[ch];
- pOut[ch] -= outStride;
- }
- }
-
- /* Clear all the other channels */
- for (sample = 0; sample < frameSize; sample++) {
- for (ch = nContentCh; ch < numOutChannels; ch+=1) {
- *pOut[ch] = (INT_PCM)0;
- pOut[ch] -= outStride;
- }
- }
- }
-#endif /* if (PCM_DMX_MAX_OUT_CHANNELS > 2) */
-
- /* update the number of output channels */
- *nChannels = numOutChannels;
- } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- else
-#endif /* PCM_CHANNEL_EXTENSION_ENABLE */
- if ( numInChannels == numOutChannels )
- {
- /* Don't need to change the channel description here */
-
- switch (numInChannels)
- {
- case 2:
- { /* Set up channel pointer */
- INT_PCM *pInPcm[PCM_DMX_MAX_CHANNELS];
- INT_PCM *pOutL, *pOutR;
- FIXP_DMX flev;
-
- UINT sample;
- int inStride, outStride, offset;
-
- if (fInterleaved) {
- inStride = numInChannels;
- outStride = 2; /* fixed !!! (below stereo is donwmixed to mono if required */
- offset = 1; /* Channel specific offset factor */
- } else {
- inStride = 1;
- outStride = 1;
- offset = frameSize; /* Channel specific offset factor */
- }
-
- /* Set input channel pointer */
- pInPcm[LEFT_FRONT_CHANNEL] = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset];
- pInPcm[RIGHT_FRONT_CHANNEL] = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset];
-
- /* Set output channel pointer (same as input) */
- pOutL = pInPcm[LEFT_FRONT_CHANNEL];
- pOutR = pInPcm[RIGHT_FRONT_CHANNEL];
-
- /* Set downmix levels: */
- flev = FL2FXCONST_DMX(0.70710678f);
- /* 2/0 input: */
- switch (dualChannelMode)
- {
- case CH1_MODE: /* L' = 0.707 * Ch1; R' = 0.707 * Ch1 */
- for (sample = 0; sample < frameSize; sample++) {
- *pOutL = *pOutR =
- (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInPcm[LEFT_FRONT_CHANNEL], flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
-
- pInPcm[LEFT_FRONT_CHANNEL] += inStride;
- pOutL += outStride; pOutR += outStride;
- }
- break;
- case CH2_MODE: /* L' = 0.707 * Ch2; R' = 0.707 * Ch2 */
- for (sample = 0; sample < frameSize; sample++) {
- *pOutL = *pOutR =
- (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInPcm[RIGHT_FRONT_CHANNEL], flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
-
- pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
- pOutL += outStride; pOutR += outStride;
- }
- break;
- case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2; R' = 0.5*Ch1 + 0.5*Ch2 */
- for (sample = 0; sample < frameSize; sample++) {
- *pOutL = *pOutR = (*pInPcm[LEFT_FRONT_CHANNEL] >> 1) + (*pInPcm[RIGHT_FRONT_CHANNEL] >> 1);
-
- pInPcm[LEFT_FRONT_CHANNEL] += inStride; pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
- pOutL += outStride; pOutR += outStride;
- }
- break;
- default:
- case STEREO_MODE:
- /* nothing to do */
- break;
- }
- }
- break;
-
- default:
- /* nothing to do */
- break;
- }
- }
-
- return (errorStatus);
-}
-
-
-/** Close an instance of the PCM downmix module.
- * @param [inout] Pointer to a buffer containing the handle of the instance.
- * @returns Returns an error code.
- **/
-PCMDMX_ERROR pcmDmx_Close (
- HANDLE_PCM_DOWNMIX *pSelf
- )
-{
- if (pSelf == NULL) {
- return (PCMDMX_INVALID_HANDLE);
- }
-
- FreePcmDmxInstance( pSelf );
- *pSelf = NULL;
-
- return (PCMDMX_OK);
-}
-
-
-/** Get library info for this module.
- * @param [out] Pointer to an allocated LIB_INFO structure.
- * @returns Returns an error code.
- */
-PCMDMX_ERROR pcmDmx_GetLibInfo( LIB_INFO *info )
-{
- int i;
-
- if (info == NULL) {
- return PCMDMX_INVALID_ARGUMENT;
- }
-
- /* 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 PCMDMX_UNKNOWN;
- }
-
- /* Add the library info */
- info[i].module_id = FDK_PCMDMX;
- info[i].version = LIB_VERSION(PCMDMX_LIB_VL0, PCMDMX_LIB_VL1, PCMDMX_LIB_VL2);
- LIB_VERSION_STRING(info+i);
- info[i].build_date = PCMDMX_LIB_BUILD_DATE;
- info[i].build_time = PCMDMX_LIB_BUILD_TIME;
- info[i].title = PCMDMX_LIB_TITLE;
-
- /* Set flags */
- info[i].flags = 0
-#ifdef PCM_DOWNMIX_ENABLE
- | CAPF_DMX_BLIND /* At least blind downmixing is possible */
- #ifdef PCE_METADATA_ENABLE
- | CAPF_DMX_PCE /* Guided downmix with data from MPEG-2/4 Program Config Elements (PCE). */
- #ifdef ARIB_MIXDOWN_ENABLE
- | CAPF_DMX_ARIB /* PCE guided downmix with slightly different equations and levels. */
- #endif
- #endif /* PCE_METADATA_ENABLE */
- #ifdef DSE_METADATA_ENABLE
- | CAPF_DMX_DVB /* Guided downmix with data from DVB ancillary data fields. */
- #endif
-#endif /* PCM_DOWNMIX_ENABLE */
-#ifdef PCM_CHANNEL_EXTENSION_ENABLE
- | CAPF_DMX_CH_EXP /* Simple upmixing by dublicating channels or adding zero channels. */
-#endif
- ;
-
- /* Add lib info for FDK tools (if not yet done). */
- FDK_toolsGetLibInfo(info);
-
- return PCMDMX_OK;
-}
-
-
-
diff --git a/libPCMutils/src/version.h b/libPCMutils/src/version.h
new file mode 100644
index 0000000..fa31af1
--- /dev/null
+++ b/libPCMutils/src/version.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
+----------------------------------------------------------------------------- */
+
+/**************************** PCM utility library ******************************
+
+ Author(s):
+
+ Description:
+
+*******************************************************************************/
+
+#if !defined(VERSION_H)
+#define VERSION_H
+
+/* library info */
+#define PCMUTIL_LIB_VL0 3
+#define PCMUTIL_LIB_VL1 0
+#define PCMUTIL_LIB_VL2 0
+#define PCMUTIL_LIB_TITLE "PCM Utility Lib"
+#ifdef __ANDROID__
+#define PCMUTIL_LIB_BUILD_DATE ""
+#define PCMUTIL_LIB_BUILD_TIME ""
+#else
+#define PCMUTIL_LIB_BUILD_DATE __DATE__
+#define PCMUTIL_LIB_BUILD_TIME __TIME__
+#endif
+
+#endif /* !defined(VERSION_H) */