Home | History | Annotate | Download | only in src
      1 
      2 /* -----------------------------------------------------------------------------------------------------------
      3 Software License for The Fraunhofer FDK AAC Codec Library for Android
      4 
      5  Copyright  1995 - 2013 Fraunhofer-Gesellschaft zur Frderung der angewandten Forschung e.V.
      6   All rights reserved.
      7 
      8  1.    INTRODUCTION
      9 The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
     10 the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
     11 This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
     12 
     13 AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
     14 audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
     15 independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
     16 of the MPEG specifications.
     17 
     18 Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
     19 may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
     20 individually for the purpose of encoding or decoding bit streams in products that are compliant with
     21 the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
     22 these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
     23 software may already be covered under those patent licenses when it is used for those licensed purposes only.
     24 
     25 Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
     26 are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
     27 applications information and documentation.
     28 
     29 2.    COPYRIGHT LICENSE
     30 
     31 Redistribution and use in source and binary forms, with or without modification, are permitted without
     32 payment of copyright license fees provided that you satisfy the following conditions:
     33 
     34 You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
     35 your modifications thereto in source code form.
     36 
     37 You must retain the complete text of this software license in the documentation and/or other materials
     38 provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
     39 You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
     40 modifications thereto to recipients of copies in binary form.
     41 
     42 The name of Fraunhofer may not be used to endorse or promote products derived from this library without
     43 prior written permission.
     44 
     45 You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
     46 software or your modifications thereto.
     47 
     48 Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
     49 and the date of any change. For modified versions of the FDK AAC Codec, the term
     50 "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
     51 "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
     52 
     53 3.    NO PATENT LICENSE
     54 
     55 NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
     56 ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
     57 respect to this software.
     58 
     59 You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
     60 by appropriate patent licenses.
     61 
     62 4.    DISCLAIMER
     63 
     64 This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
     65 "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
     66 of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
     67 CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
     68 including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
     69 or business interruption, however caused and on any theory of liability, whether in contract, strict
     70 liability, or tort (including negligence), arising in any way out of the use of this software, even if
     71 advised of the possibility of such damage.
     72 
     73 5.    CONTACT INFORMATION
     74 
     75 Fraunhofer Institute for Integrated Circuits IIS
     76 Attention: Audio and Multimedia Departments - FDK AAC LL
     77 Am Wolfsmantel 33
     78 91058 Erlangen, Germany
     79 
     80 www.iis.fraunhofer.de/amm
     81 amm-info (at) iis.fraunhofer.de
     82 ----------------------------------------------------------------------------------------------------------- */
     83 
     84 /****************************  FDK PCM utils module  **************************
     85 
     86    Author(s):   Christian Griebel
     87    Description: Defines functions that perform downmixing or a simple channel
     88                 expansion in the PCM time domain.
     89 
     90 *******************************************************************************/
     91 #ifndef __linux__
     92 #include <log/log.h>
     93 #endif
     94 #include "pcmutils_lib.h"
     95 
     96 #include "genericStds.h"
     97 #include "fixpoint_math.h"
     98 #include "FDK_core.h"
     99 
    100 
    101 /* ------------------------ *
    102  *  GLOBAL SETTINGS (GFR):  *
    103  * ------------------------ */
    104 #define DSE_METADATA_ENABLE          /*!< Enable this to support MPEG/ETSI DVB ancillary data for
    105                                           encoder assisted downmixing of MPEG-4 AAC and
    106                                           MPEG-1/2 layer 2 streams.                             */
    107 #define PCE_METADATA_ENABLE          /*!< Enable this to support MPEG matrix mixdown with a
    108                                           coefficient carried in the PCE.                       */
    109 
    110 #define PCM_DMX_MAX_IN_CHANNELS          ( 8 )   /* Neither the maximum number of input nor the maximum number of output channels ... */
    111 #define PCM_DMX_MAX_OUT_CHANNELS         ( 8 )   /* ... must exceed the maximum number of channels that the framework can handle. */
    112 
    113 /* ------------------------ *
    114  *    SPECIFIC SETTINGS:    *
    115  * ------------------------ */
    116 #define PCM_CHANNEL_EXTENSION_ENABLE             /*!< Allow module to duplicate mono signals or add zero channels to achieve the
    117                                                       desired number of output channels. */
    118 
    119 #define PCM_DMX_DFLT_MAX_OUT_CHANNELS    ( 6 )   /*!< The maximum number of output channels. If the value is greater than 0 the module
    120                                                       will automatically create a mixdown for all input signals with more channels
    121                                                       than specified. */
    122 #define PCM_DMX_DFLT_MIN_OUT_CHANNELS    ( 0 )   /*!< The minimum number of output channels. If the value is greater than 0 the module
    123                                                       will do channel extension automatically for all input signals with less channels
    124                                                       than specified. */
    125 #define PCM_DMX_MAX_DELAY_FRAMES         ( 1 )   /*!< The maximum delay frames to align the bitstreams payload with the PCM output. */
    126 #define PCM_DMX_DFLT_EXPIRY_FRAME        ( 50 )  /*!< If value is greater than 0 the mixdown coefficients will expire by default after the
    127                                                       given number of frames. The value 50 corresponds to at least 500ms (FL 960 @ 96kHz) */
    128 /* #define PCMDMX_DEBUG */
    129 
    130 /* Derived setting:
    131  *   No need to edit beyond this line. */
    132 #if defined(DSE_METADATA_ENABLE) || defined(PCE_METADATA_ENABLE) || defined(ARIB_MIXDOWN_ENABLE)
    133  #define PCM_DOWNMIX_ENABLE                      /*!< Generally enable down mixing.                         */
    134 #endif
    135 #if (PCM_DMX_MAX_IN_CHANNELS > 2) || (PCM_DMX_MAX_OUT_CHANNELS > 2)
    136  #define PCM_DMX_MAX_CHANNELS            ( 8 )
    137  #define PCM_DMX_MAX_CHANNEL_GROUPS      ( 4 )
    138  #define PCM_DMX_MAX_CHANNELS_PER_GROUP  PCM_DMX_MAX_CHANNELS   /* All channels can be in one group */
    139 #else
    140  #define PCM_DMX_MAX_CHANNELS            ( 3 )   /* Need to add 1 because there are three channel positions in first channel group. */
    141  #define PCM_DMX_MAX_CHANNEL_GROUPS      ( 1 )   /* Only front channels supported. */
    142  #define PCM_DMX_MAX_CHANNELS_PER_GROUP  ( 2 )   /* The maximum over all channel groups */
    143 #endif
    144 #if (PCM_DMX_MAX_IN_CHANNELS > PCM_DMX_MAX_OUT_CHANNELS)
    145  #define PCM_DMX_MAX_IO_CHANNELS  PCM_DMX_MAX_IN_CHANNELS
    146 #else
    147  #define PCM_DMX_MAX_IO_CHANNELS  PCM_DMX_MAX_OUT_CHANNELS
    148 #endif
    149 
    150 /* Decoder library info */
    151 #define PCMDMX_LIB_VL0 2
    152 #define PCMDMX_LIB_VL1 4
    153 #define PCMDMX_LIB_VL2 2
    154 #define PCMDMX_LIB_TITLE "PCM Downmix Lib"
    155 #ifdef __ANDROID__
    156 #define PCMDMX_LIB_BUILD_DATE ""
    157 #define PCMDMX_LIB_BUILD_TIME ""
    158 #else
    159 #define PCMDMX_LIB_BUILD_DATE __DATE__
    160 #define PCMDMX_LIB_BUILD_TIME __TIME__
    161 #endif
    162 
    163 
    164 /* Fixed and unique channel group indices.
    165  * The last group index has to be smaller than PCM_DMX_MAX_CHANNEL_GROUPS. */
    166 #define CH_GROUP_FRONT ( 0 )
    167 #define CH_GROUP_SIDE  ( 1 )
    168 #define CH_GROUP_REAR  ( 2 )
    169 #define CH_GROUP_LFE   ( 3 )
    170 
    171 /* The ordering of the following fixed channel labels has to be in MPEG-4 style.
    172  * From the center to the back with left and right channel interleaved (starting with left).
    173  * The last channel label index has to be smaller than PCM_DMX_MAX_CHANNELS. */
    174 #define CENTER_FRONT_CHANNEL    ( 0 )     /* C  */
    175 #define LEFT_FRONT_CHANNEL      ( 1 )     /* L  */
    176 #define RIGHT_FRONT_CHANNEL     ( 2 )     /* R  */
    177 #define LEFT_REAR_CHANNEL       ( 3 )     /* Lr (aka left back channel) or center back channel */
    178 #define RIGHT_REAR_CHANNEL      ( 4 )     /* Rr (aka right back channel) */
    179 #define LOW_FREQUENCY_CHANNEL   ( 5 )     /* Lf */
    180 #define LEFT_MULTIPRPS_CHANNEL  ( 6 )     /* Left multipurpose channel */
    181 #define RIGHT_MULTIPRPS_CHANNEL ( 7 )     /* Right multipurpose channel */
    182 
    183 /* More constants */
    184 #define ONE_CHANNEL             ( 1 )
    185 #define TWO_CHANNEL             ( 2 )
    186 #define SIX_CHANNEL             ( 6 )
    187 #define EIGHT_CHANNEL           ( 8 )
    188 
    189 #define PCMDMX_A_IDX_DEFAULT    ( 2 )
    190 #define PCMDMX_B_IDX_DEFAULT    ( 2 )
    191 #define PCMDMX_LFE_IDX_DEFAULT  ( 15 )
    192 #define PCMDMX_GAIN_5_DEFAULT   ( 0 )
    193 #define PCMDMX_GAIN_2_DEFAULT   ( 0 )
    194 
    195 #define PCMDMX_MAX_HEADROOM     ( 3 )     /* Defines the maximum PCM scaling headroom that can be done by a
    196                                              postprocessing step. This value must be greater or equal to 0. */
    197 
    198 #define FALSE  0
    199 #define TRUE   1
    200 #define IN     0
    201 #define OUT    1
    202 
    203 /* Type definitions: */
    204 #ifndef DMX_HIGH_PRECISION_ENABLE
    205  #define FIXP_DMX          FIXP_SGL
    206  #define FX_DMX2FX_DBL(x)  FX_SGL2FX_DBL((FIXP_SGL)(x))
    207  #define FX_DBL2FX_DMX(x)  FX_DBL2FX_SGL(x)
    208  #define FL2FXCONST_DMX(x) FL2FXCONST_SGL(x)
    209  #define MAXVAL_DMX        MAXVAL_SGL
    210  #define FX_DMX2SHRT(x)    ((SHORT)(x))
    211  #define FX_DMX2FL(x)      FX_DBL2FL(FX_DMX2FX_DBL(x))
    212 #else
    213  #define FIXP_DMX          FIXP_DBL
    214  #define FX_DMX2FX_DBL(x)  ((FIXP_DBL)(x))
    215  #define FX_DBL2FX_DMX(x)  ((FIXP_DBL)(x)
    216  #define FL2FXCONST_DMX(x) FL2FXCONST_DBL(x)
    217  #define MAXVAL_DMX        MAXVAL_DBL
    218  #define FX_DMX2SHRT(x)    ((SHORT)((x)>>FRACT_BITS))
    219  #define FX_DMX2FL(x)      FX_DBL2FL(x)
    220 #endif
    221 
    222 /* The number of channels positions for each group in the internal representation.
    223  * See the channel labels above. */
    224 static const UCHAR maxChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS] = {
    225 #if (PCM_DMX_MAX_CHANNELS > 3)
    226   3, 0, 2, 1
    227 #else
    228   PCM_DMX_MAX_CHANNELS_PER_GROUP
    229 #endif
    230 };
    231 
    232 /* List of packed channel modes */
    233 typedef enum
    234 { /* CH_MODE_<numFrontCh>_<numSideCh>_<numBackCh>_<numLfCh> */
    235   CH_MODE_UNDEFINED = 0x0000,
    236   /* 1 channel */
    237   CH_MODE_1_0_0_0   = 0x0001,   /* chCfg 1 */
    238   /* 2 channels */
    239   CH_MODE_2_0_0_0   = 0x0002,   /* chCfg 2 */
    240   /* 3 channels */
    241   CH_MODE_3_0_0_0   = 0x0003,   /* chCfg 3 */
    242   CH_MODE_2_0_1_0   = 0x0102,
    243   CH_MODE_2_0_0_1   = 0x1002,
    244   /* 4 channels */
    245   CH_MODE_3_0_1_0   = 0x0103,   /* chCfg 4 */
    246   CH_MODE_2_0_2_0   = 0x0202,
    247   CH_MODE_2_0_1_1   = 0x1102,
    248   CH_MODE_4_0_0_0   = 0x0004,
    249   /* 5 channels */
    250   CH_MODE_3_0_2_0   = 0x0203,   /* chCfg 5 */
    251   CH_MODE_2_0_2_1   = 0x1202,
    252   CH_MODE_3_0_1_1   = 0x1103,
    253   CH_MODE_3_2_0_0   = 0x0023,
    254   CH_MODE_5_0_0_0   = 0x0005,
    255   /* 6 channels */
    256   CH_MODE_3_0_2_1   = 0x1203,   /* chCfg 6 */
    257   CH_MODE_3_2_0_1   = 0x1023,
    258   CH_MODE_3_2_1_0   = 0x0123,
    259   CH_MODE_5_0_1_0   = 0x0105,
    260   CH_MODE_6_0_0_0   = 0x0006,
    261   /* 7 channels */
    262   CH_MODE_2_2_2_1   = 0x1222,
    263   CH_MODE_3_0_3_1   = 0x1303,   /* chCfg 11 */
    264   CH_MODE_3_2_1_1   = 0x1123,
    265   CH_MODE_3_2_2_0   = 0x0223,
    266   CH_MODE_3_0_2_2   = 0x2203,
    267   CH_MODE_5_0_2_0   = 0x0205,
    268   CH_MODE_5_0_1_1   = 0x1105,
    269   CH_MODE_7_0_0_0   = 0x0007,
    270   /* 8 channels */
    271   CH_MODE_3_2_2_1   = 0x1223,
    272   CH_MODE_3_0_4_1   = 0x1403,   /* chCfg 12 */
    273   CH_MODE_5_0_2_1   = 0x1205,   /* chCfg 7 + 14 */
    274   CH_MODE_5_2_1_0   = 0x0125,
    275   CH_MODE_3_2_1_2   = 0x2123,
    276   CH_MODE_2_2_2_2   = 0x2222,
    277   CH_MODE_3_0_3_2   = 0x2303,
    278   CH_MODE_8_0_0_0   = 0x0008
    279 
    280 } PCM_DMX_CHANNEL_MODE;
    281 
    282 
    283 /* These are the channel configurations linked to
    284    the number of output channels give by the user: */
    285 static const PCM_DMX_CHANNEL_MODE outChModeTable[PCM_DMX_MAX_CHANNELS+1] =
    286 {
    287   CH_MODE_UNDEFINED,
    288   CH_MODE_1_0_0_0,  /* 1 channel  */
    289   CH_MODE_2_0_0_0,  /* 2 channels */
    290   CH_MODE_3_0_0_0   /* 3 channels */
    291 #if (PCM_DMX_MAX_CHANNELS > 3)
    292  ,CH_MODE_3_0_1_0,  /* 4 channels */
    293   CH_MODE_3_0_2_0,  /* 5 channels */
    294   CH_MODE_3_0_2_1,  /* 6 channels */
    295   CH_MODE_3_0_3_1,  /* 7 channels */
    296   CH_MODE_3_0_4_1   /* 8 channels */
    297 #endif
    298 };
    299 
    300 static const FIXP_DMX abMixLvlValueTab[8] =
    301 {
    302   FL2FXCONST_DMX(0.500f),   /* scaled by 1 */
    303   FL2FXCONST_DMX(0.841f),
    304   FL2FXCONST_DMX(0.707f),
    305   FL2FXCONST_DMX(0.596f),
    306   FL2FXCONST_DMX(0.500f),
    307   FL2FXCONST_DMX(0.422f),
    308   FL2FXCONST_DMX(0.355f),
    309   FL2FXCONST_DMX(0.0f)
    310 };
    311 
    312 static const FIXP_DMX lfeMixLvlValueTab[16] =
    313 { /*             value,        scale */
    314   FL2FXCONST_DMX(0.7905f),  /*     2 */
    315   FL2FXCONST_DMX(0.5000f),  /*     2 */
    316   FL2FXCONST_DMX(0.8395f),  /*     1 */
    317   FL2FXCONST_DMX(0.7065f),  /*     1 */
    318   FL2FXCONST_DMX(0.5945f),  /*     1 */
    319   FL2FXCONST_DMX(0.500f),   /*     1 */
    320   FL2FXCONST_DMX(0.841f),   /*     0 */
    321   FL2FXCONST_DMX(0.707f),   /*     0 */
    322   FL2FXCONST_DMX(0.596f),   /*     0 */
    323   FL2FXCONST_DMX(0.500f),   /*     0 */
    324   FL2FXCONST_DMX(0.316f),   /*     0 */
    325   FL2FXCONST_DMX(0.178f),   /*     0 */
    326   FL2FXCONST_DMX(0.100f),   /*     0 */
    327   FL2FXCONST_DMX(0.032f),   /*     0 */
    328   FL2FXCONST_DMX(0.010f),   /*     0 */
    329   FL2FXCONST_DMX(0.000f)    /*     0 */
    330 };
    331 
    332 
    333 
    334 #ifdef PCE_METADATA_ENABLE
    335   /* MPEG matrix mixdown:
    336       Set 1:  L' = (1 + 2^-0.5 + A )^-1 * [L + C * 2^-0.5 + A * Ls];
    337               R' = (1 + 2^-0.5 + A )^-1 * [R + C * 2^-0.5 + A * Rs];
    338 
    339       Set 2:  L' = (1 + 2^-0.5 + 2A )^-1 * [L + C * 2^-0.5 - A * (Ls + Rs)];
    340               R' = (1 + 2^-0.5 + 2A )^-1 * [R + C * 2^-0.5 + A * (Ls + Rs)];
    341 
    342       M = (3 + 2A)^-1 * [L + C + R + A*(Ls + Rs)];
    343   */
    344   static const FIXP_DMX mpegMixDownIdx2Coef[4] =
    345   {
    346     FL2FXCONST_DMX(0.70710678f),
    347     FL2FXCONST_DMX(0.5f),
    348     FL2FXCONST_DMX(0.35355339f),
    349     FL2FXCONST_DMX(0.0f)
    350   };
    351 
    352   static const FIXP_SGL mpegMixDownIdx2PreFact[3][4] =
    353   { {  /* Set 1: */
    354     FL2FXCONST_DMX(0.4142135623730950f),
    355     FL2FXCONST_DMX(0.4530818393219728f),
    356     FL2FXCONST_DMX(0.4852813742385703f),
    357     FL2FXCONST_DMX(0.5857864376269050f)
    358   },{  /* Set 2: */
    359     FL2FXCONST_DMX(0.3203772410170407f),
    360     FL2FXCONST_DMX(0.3693980625181293f),
    361     FL2FXCONST_DMX(0.4142135623730950f),
    362     FL2FXCONST_DMX(0.5857864376269050f)
    363   },{  /* Mono DMX set: */
    364     FL2FXCONST_DMX(0.2265409196609864f),
    365     FL2FXCONST_DMX(0.25f),
    366     FL2FXCONST_DMX(0.2697521433898179f),
    367     FL2FXCONST_DMX(0.3333333333333333f) }
    368   };
    369 #endif  /* PCE_METADATA_ENABLE */
    370 
    371 
    372 #define TYPE_NONE      ( 0x0 )
    373 #define TYPE_DSE_DATA  ( 0x1 )
    374 #define TYPE_PCE_DATA  ( 0x2 )
    375 
    376 typedef struct
    377 {
    378   UINT   typeFlags;
    379   /* From DSE */
    380   UCHAR  cLevIdx;
    381   UCHAR  sLevIdx;
    382   UCHAR  dmixIdxA;
    383   UCHAR  dmixIdxB;
    384   UCHAR  dmixIdxLfe;
    385   UCHAR  dmxGainIdx2;
    386   UCHAR  dmxGainIdx5;
    387 #ifdef PCE_METADATA_ENABLE
    388   /* From PCE */
    389   UCHAR  matrixMixdownIdx;
    390 #endif
    391   /* Attributes: */
    392   SCHAR  pseudoSurround;               /*!< If set to 1 the signal is pseudo surround compatible. The value 0 tells
    393                                             that it is not. If the value is -1 the information is not available.  */
    394   UINT   expiryCount;                  /*!< Counter to monitor the life time of a meta data set. */
    395 
    396 } DMX_BS_META_DATA;
    397 
    398 /* Default metadata */
    399 static const DMX_BS_META_DATA  dfltMetaData = {
    400   0, 2, 2, 2, 2, 15, 0, 0,
    401 #ifdef PCE_METADATA_ENABLE
    402   0,
    403 #endif
    404   -1, 0
    405 };
    406 
    407 /* Dynamic (user) params:
    408      See the definition of PCMDMX_PARAM for details on the specific fields. */
    409 typedef struct
    410 {
    411   UINT   expiryFrame;                   /*!< Linked to DMX_BS_DATA_EXPIRY_FRAME       */
    412   DUAL_CHANNEL_MODE dualChannelMode;    /*!< Linked to DMX_DUAL_CHANNEL_MODE          */
    413   PSEUDO_SURROUND_MODE pseudoSurrMode;  /*!< Linked to DMX_PSEUDO_SURROUND_MODE       */
    414   SHORT  numOutChannelsMin;             /*!< Linked to MIN_NUMBER_OF_OUTPUT_CHANNELS  */
    415   SHORT  numOutChannelsMax;             /*!< Linked to MAX_NUMBER_OF_OUTPUT_CHANNELS  */
    416   UCHAR  frameDelay;                    /*!< Linked to DMX_BS_DATA_DELAY              */
    417 
    418 } PCM_DMX_USER_PARAMS;
    419 
    420 /* Modules main data structure: */
    421 struct PCM_DMX_INSTANCE
    422 {
    423   /* Metadata */
    424   DMX_BS_META_DATA     bsMetaData[PCM_DMX_MAX_DELAY_FRAMES+1];
    425   PCM_DMX_USER_PARAMS  userParams;
    426 
    427   UCHAR  applyProcessing;              /*!< Flag to en-/disable modules processing.
    428                                             The max channel limiting is done independently. */
    429 };
    430 
    431 /* Memory allocation macro */
    432 C_ALLOC_MEM_STATIC(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1)
    433 
    434 
    435 /** Evaluate a given channel configuration and extract a packed channel mode. In addition the
    436  *  function generates a channel offset table for the mapping to the internal representation.
    437  *  This function is the inverse to the getChannelDescription() routine.
    438  * @param [in] The total number of channels of the given configuration.
    439  * @param [in] Array holding the corresponding channel types for each channel.
    440  * @param [in] Array holding the corresponding channel type indices for each channel.
    441  * @param [out] Array where the buffer offsets for each channel are stored into.
    442  * @param [out] The generated packed channel mode that represents the given input configuration.
    443  * @returns Returns an error code.
    444  **/
    445 static
    446 PCMDMX_ERROR getChannelMode (
    447         const INT                numChannels,                           /* in */
    448         const AUDIO_CHANNEL_TYPE channelType[],                         /* in */
    449         const UCHAR              channelIndices[],                      /* in */
    450         UCHAR                    offsetTable[PCM_DMX_MAX_CHANNELS],     /* out */
    451         PCM_DMX_CHANNEL_MODE    *chMode                                 /* out */
    452       )
    453 {
    454   UCHAR chIdx[PCM_DMX_MAX_CHANNEL_GROUPS][PCM_DMX_MAX_CHANNELS_PER_GROUP];
    455   UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS]; /* Total num of channels per group of the input config */
    456   UCHAR numChFree[PCM_DMX_MAX_CHANNEL_GROUPS];  /* Number of free slots per group in the internal repr. */
    457   UCHAR hardToPlace[PCM_DMX_MAX_CHANNELS];      /* List of channels not matching the internal repr. */
    458   UCHAR h2pSortIdx[PCM_DMX_MAX_CHANNELS];
    459   PCMDMX_ERROR err = PCMDMX_OK;
    460   int   ch, grpIdx;
    461   int   numChToPlace = 0;
    462 
    463   FDK_ASSERT(channelType != NULL);
    464   FDK_ASSERT(channelIndices != NULL);
    465   FDK_ASSERT(offsetTable != NULL);
    466   FDK_ASSERT(chMode != NULL);
    467 
    468   /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */
    469   FDKmemclear(numChInGrp, PCM_DMX_MAX_CHANNEL_GROUPS*sizeof(UCHAR));
    470   FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
    471   FDKmemset(chIdx, 255, PCM_DMX_MAX_CHANNEL_GROUPS*PCM_DMX_MAX_CHANNELS_PER_GROUP*sizeof(UCHAR));
    472   FDKmemset(hardToPlace, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
    473   FDKmemset(h2pSortIdx, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
    474   /* Get the restrictions of the internal representation */
    475   FDKmemcpy(numChFree, maxChInGrp, PCM_DMX_MAX_CHANNEL_GROUPS*sizeof(UCHAR));
    476 
    477   *chMode = CH_MODE_UNDEFINED;
    478 
    479   /* Categorize channels */
    480   for (ch = 0; ch < numChannels; ch += 1) {
    481     UCHAR chGrpIdx = channelIndices[ch];
    482     int i = 0, j;
    483 
    484     switch (channelType[ch]) {
    485     case ACT_FRONT_TOP:
    486       chGrpIdx += numChInGrp[CH_GROUP_FRONT];  /* Append after normal plain */
    487     case ACT_FRONT:
    488       grpIdx = CH_GROUP_FRONT;
    489       break;
    490 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
    491     case ACT_SIDE_TOP:
    492       chGrpIdx += numChInGrp[CH_GROUP_SIDE];   /* Append after normal plain */
    493     case ACT_SIDE:
    494       grpIdx = CH_GROUP_SIDE;
    495       break;
    496     case ACT_BACK_TOP:
    497       chGrpIdx += numChInGrp[CH_GROUP_REAR];   /* Append after normal plain */
    498     case ACT_BACK:
    499       grpIdx = CH_GROUP_REAR;
    500       break;
    501     case ACT_LFE:
    502       grpIdx = CH_GROUP_LFE;
    503       break;
    504 #endif
    505     default:
    506       /* Found a channel that can not be categorized! Most likely due to corrupt input signalling.
    507          The rescue strategy is to append it to the front channels (=> ignore index).
    508          This could cause strange behaviour so return an error to signal it. */
    509       err = PCMDMX_INVALID_MODE;
    510       grpIdx = CH_GROUP_FRONT;
    511       chGrpIdx = numChannels + numChToPlace;
    512       numChToPlace += 1;
    513       break;
    514     }
    515 
    516     if (numChInGrp[grpIdx] < PCM_DMX_MAX_CHANNELS_PER_GROUP) {
    517       /* Sort channels by index */
    518       while ( (i < numChInGrp[grpIdx]) && (chGrpIdx > channelIndices[chIdx[grpIdx][i]]) ) {
    519         i += 1;
    520       }
    521       for (j = numChInGrp[grpIdx]; j > i; j -= 1) {
    522         chIdx[grpIdx][j] = chIdx[grpIdx][j-1];
    523       }
    524       chIdx[grpIdx][i] = ch;
    525       numChInGrp[grpIdx] += 1;
    526     }
    527   }
    528 
    529 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
    530   FDK_ASSERT( (numChInGrp[CH_GROUP_FRONT]+numChInGrp[CH_GROUP_SIDE]
    531               +numChInGrp[CH_GROUP_REAR]+numChInGrp[CH_GROUP_LFE]) == numChannels);
    532 #else
    533   FDK_ASSERT( numChInGrp[CH_GROUP_FRONT] == numChannels );
    534 #endif
    535 
    536   /* Compose channel offset table:
    537    * Map all channels to the internal representation. */
    538   numChToPlace = 0;
    539 
    540   /* Non-symmetric channels */
    541   if (numChInGrp[CH_GROUP_FRONT] & 0x1) {
    542     /* Odd number of front channels -> we have a center channel.
    543        In MPEG-4 the center has the index 0. */
    544     offsetTable[CENTER_FRONT_CHANNEL] = chIdx[CH_GROUP_FRONT][0];
    545     numChFree[CH_GROUP_FRONT] -= 1;
    546   }
    547 
    548   for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
    549     int chMapPos = 0;
    550     ch = 0;  /* Index of channel within the specific group */
    551 
    552     switch (grpIdx) {
    553     case CH_GROUP_FRONT:
    554       chMapPos = LEFT_FRONT_CHANNEL;
    555       ch = numChInGrp[grpIdx] & 0x1;
    556       break;
    557 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
    558     case CH_GROUP_SIDE:
    559       break;
    560     case CH_GROUP_REAR:
    561       chMapPos = LEFT_REAR_CHANNEL;
    562       break;
    563     case CH_GROUP_LFE:
    564       chMapPos = LOW_FREQUENCY_CHANNEL;
    565       break;
    566 #endif
    567     default:
    568       FDK_ASSERT(0);
    569       continue;
    570     }
    571 
    572     /* Map all channels of the group */
    573     for ( ; ch < numChInGrp[grpIdx]; ch += 1) {
    574       if (numChFree[grpIdx] > 0) {
    575         offsetTable[chMapPos] = chIdx[grpIdx][ch];
    576         chMapPos += 1;
    577         numChFree[grpIdx] -= 1;
    578       } else {
    579         /* Add to the list of hardship cases considering a MPEG-like sorting order: */
    580         int pos, sortIdx = grpIdx*PCM_DMX_MAX_CHANNELS_PER_GROUP + channelIndices[chIdx[grpIdx][ch]];
    581         for (pos = numChToPlace; pos > 0; pos -= 1) {
    582           if (h2pSortIdx[pos-1] > sortIdx) {
    583             hardToPlace[pos] = hardToPlace[pos-1];
    584             h2pSortIdx[pos] = h2pSortIdx[pos-1];
    585           } else {
    586             /* Insert channel at the current index/position */
    587             break;
    588           }
    589         }
    590         hardToPlace[pos] = chIdx[grpIdx][ch];
    591         h2pSortIdx[pos] = sortIdx;
    592         numChToPlace += 1;
    593       }
    594     }
    595   }
    596 
    597   { /* Assign the hardship cases */
    598     int chMapPos = 0;
    599     int mappingHeat = 0;
    600     for (ch = 0; ch < numChToPlace; ch+=1) {
    601       int chAssigned = 0;
    602 
    603       /* Just assigning the channels to the next best slot can lead to undesired results (especially for x/x/1.x
    604          configurations). Thus use the MPEG-like sorting index to find the best fitting slot for each channel.
    605          If this is not possible the sorting index will be ignored (mappingHeat >= 2). */
    606       for ( ; chMapPos < PCM_DMX_MAX_CHANNELS; chMapPos+=1) {
    607         if (offsetTable[chMapPos] == 255) {
    608           int prvSortIdx = 0;
    609           int nxtSortIdx = (CH_GROUP_LFE+1)*PCM_DMX_MAX_CHANNELS_PER_GROUP;
    610 
    611           if (mappingHeat < 2) {
    612             if (chMapPos < LEFT_REAR_CHANNEL) {
    613               /* Got front channel slot */
    614               prvSortIdx = CH_GROUP_FRONT*PCM_DMX_MAX_CHANNELS_PER_GROUP + chMapPos - CENTER_FRONT_CHANNEL;
    615               nxtSortIdx = CH_GROUP_SIDE *PCM_DMX_MAX_CHANNELS_PER_GROUP;
    616             }
    617             else if (chMapPos < LOW_FREQUENCY_CHANNEL) {
    618               /* Got back channel slot */
    619               prvSortIdx = CH_GROUP_REAR*PCM_DMX_MAX_CHANNELS_PER_GROUP + chMapPos - LEFT_REAR_CHANNEL;
    620               nxtSortIdx = CH_GROUP_LFE *PCM_DMX_MAX_CHANNELS_PER_GROUP;
    621             }
    622             else if (chMapPos < LEFT_MULTIPRPS_CHANNEL) {
    623               /* Got lfe channel slot */
    624               prvSortIdx =  CH_GROUP_LFE   *PCM_DMX_MAX_CHANNELS_PER_GROUP + chMapPos - LOW_FREQUENCY_CHANNEL;
    625               nxtSortIdx = (CH_GROUP_LFE+1)*PCM_DMX_MAX_CHANNELS_PER_GROUP;
    626             }
    627           }
    628 
    629           /* Assign the channel only if its sort index is within the range */
    630           if ( (h2pSortIdx[ch] >= prvSortIdx)
    631             && (h2pSortIdx[ch] <  nxtSortIdx) ) {
    632             offsetTable[chMapPos++] = hardToPlace[ch];
    633             chAssigned = 1;
    634             break;
    635           }
    636         }
    637       }
    638       if (chAssigned == 0) {
    639         chMapPos = 0;
    640         ch -= 1;
    641         mappingHeat += 1;
    642         continue;
    643       }
    644     }
    645   }
    646 
    647   /* Compose the channel mode */
    648   *chMode = (PCM_DMX_CHANNEL_MODE)( (numChInGrp[CH_GROUP_FRONT] & 0xF)
    649 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
    650                                   | (numChInGrp[CH_GROUP_SIDE]  & 0xF) <<  4
    651                                   | (numChInGrp[CH_GROUP_REAR]  & 0xF) <<  8
    652                                   | (numChInGrp[CH_GROUP_LFE]   & 0xF) << 12
    653 #endif
    654                                   );
    655 
    656   return err;
    657 }
    658 
    659 
    660 /** Generate a channel offset table and complete channel description for a given (packed) channel mode.
    661  *  This function is the inverse to the getChannelMode() routine but does not support weird channel
    662  *  configurations. All channels have to be in the normal height layer and there must not be more
    663  *  channels in each group than given by maxChInGrp.
    664  * @param [in] The packed channel mode of the configuration to be processed.
    665  * @param [in] Array containing the channel mapping to be used (From MPEG PCE ordering to whatever is required).
    666  * @param [out] Array where corresponding channel types for each channels are stored into.
    667  * @param [out] Array where corresponding channel type indices for each output channel are stored into.
    668  * @param [out] Array where the buffer offsets for each channel are stored into.
    669  * @returns None.
    670  **/
    671 static
    672 void getChannelDescription (
    673         const PCM_DMX_CHANNEL_MODE  chMode,                                 /* in */
    674         const UCHAR                 channelMapping[][8],                    /* in */
    675         AUDIO_CHANNEL_TYPE          channelType[],                          /* out */
    676         UCHAR                       channelIndices[],                       /* out */
    677         UCHAR                       offsetTable[PCM_DMX_MAX_CHANNELS]       /* out */
    678       )
    679 {
    680   const UCHAR *pChannelMap;
    681   int   grpIdx, ch = 0, numChannels = 0;
    682   UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS];
    683 
    684   FDK_ASSERT(channelType != NULL);
    685   FDK_ASSERT(channelIndices != NULL);
    686   FDK_ASSERT(channelMapping != NULL);
    687   FDK_ASSERT(offsetTable != NULL);
    688 
    689   /* Init output arrays */
    690   FDKmemclear(channelType,    PCM_DMX_MAX_IO_CHANNELS*sizeof(AUDIO_CHANNEL_TYPE));
    691   FDKmemclear(channelIndices, PCM_DMX_MAX_IO_CHANNELS*sizeof(UCHAR));
    692   FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
    693 
    694   /* Extract the number of channels per group */
    695   numChInGrp[CH_GROUP_FRONT] =  chMode        & 0xF;
    696 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
    697   numChInGrp[CH_GROUP_SIDE]  = (chMode >>  4) & 0xF;
    698   numChInGrp[CH_GROUP_REAR]  = (chMode >>  8) & 0xF;
    699   numChInGrp[CH_GROUP_LFE]   = (chMode >> 12) & 0xF;
    700 #endif
    701 
    702   /* Summerize to get the total number of channels */
    703   for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
    704     numChannels += numChInGrp[grpIdx];
    705   }
    706 
    707   /* Get the appropriate channel map */
    708   switch (chMode) {
    709   case CH_MODE_1_0_0_0:
    710   case CH_MODE_2_0_0_0:
    711   case CH_MODE_3_0_0_0:
    712   case CH_MODE_3_0_1_0:
    713   case CH_MODE_3_0_2_0:
    714   case CH_MODE_3_0_2_1:
    715     pChannelMap = channelMapping[numChannels];
    716     break;
    717   case CH_MODE_3_0_3_1:
    718     pChannelMap = channelMapping[11];
    719     break;
    720   case CH_MODE_3_0_4_1:
    721     pChannelMap = channelMapping[12];
    722     break;
    723   case CH_MODE_5_0_2_1:
    724     pChannelMap = channelMapping[7];
    725     break;
    726   default:
    727     /* fallback */
    728     pChannelMap = channelMapping[0];
    729     break;
    730   }
    731 
    732   /* Compose channel offset table */
    733 
    734   /* Non-symmetric channels */
    735   if (numChInGrp[CH_GROUP_FRONT] & 0x1) {
    736     /* Odd number of front channels -> we have a center channel.
    737        In MPEG-4 the center has the index 0. */
    738     int mappedIdx = pChannelMap[ch];
    739     offsetTable[CENTER_FRONT_CHANNEL] = mappedIdx;
    740     channelType[mappedIdx]    = ACT_FRONT;
    741     channelIndices[mappedIdx] = 0;
    742     ch += 1;
    743   }
    744 
    745   for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
    746     AUDIO_CHANNEL_TYPE type = ACT_NONE;
    747     int chMapPos = 0, maxChannels = 0;
    748     int chIdx = 0;  /* Index of channel within the specific group */
    749 
    750     switch (grpIdx) {
    751     case CH_GROUP_FRONT:
    752       type = ACT_FRONT;
    753       chMapPos = LEFT_FRONT_CHANNEL;
    754       maxChannels = 3;
    755       chIdx = numChInGrp[grpIdx] & 0x1;
    756       break;
    757 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1)
    758     case CH_GROUP_SIDE:
    759       /* Always map side channels to the multipurpose group. */
    760       type = ACT_SIDE;
    761       chMapPos = LEFT_MULTIPRPS_CHANNEL;
    762       break;
    763     case CH_GROUP_REAR:
    764       type = ACT_BACK;
    765       chMapPos = LEFT_REAR_CHANNEL;
    766       maxChannels = 2;
    767       break;
    768     case CH_GROUP_LFE:
    769       type = ACT_LFE;
    770       chMapPos = LOW_FREQUENCY_CHANNEL;
    771       maxChannels = 1;
    772       break;
    773 #endif
    774     default:
    775       break;
    776     }
    777 
    778     /* Map all channels in this group */
    779     for ( ; chIdx < numChInGrp[grpIdx]; chIdx += 1) {
    780       int mappedIdx = pChannelMap[ch];
    781       if (chIdx == maxChannels) {
    782         /* No space left in this channel group!
    783            Use the multipurpose group instead: */
    784         chMapPos = LEFT_MULTIPRPS_CHANNEL;
    785       }
    786       offsetTable[chMapPos]     = mappedIdx;
    787       channelType[mappedIdx]    = type;
    788       channelIndices[mappedIdx] = chIdx;
    789       chMapPos += 1;
    790       ch += 1;
    791     }
    792   }
    793 }
    794 
    795 /** Private helper function for downmix matrix manipulation that initializes
    796  *  one row in a given downmix matrix (corresponding to one output channel).
    797  * @param [inout] Pointer to fixed-point parts of the downmix matrix.
    798  * @param [inout] Pointer to scale factor matrix associated to the downmix factors.
    799  * @param [in]    Index of channel (row) to be initialized.
    800  * @returns       Nothing to return.
    801  **/
    802 static
    803 void dmxInitChannel(
    804         FIXP_DMX            mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
    805         INT                 mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
    806         const unsigned int  outCh
    807        )
    808 {
    809   unsigned int inCh;
    810   for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) {
    811     if (inCh == outCh) {
    812       mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.5f);
    813       mixScales[outCh][inCh]  = 1;
    814     } else {
    815       mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.0f);
    816       mixScales[outCh][inCh]  = 0;
    817     }
    818   }
    819 }
    820 
    821 /** Private helper function for downmix matrix manipulation that does a reset
    822  *  of one row in a given downmix matrix (corresponding to one output channel).
    823  * @param [inout] Pointer to fixed-point parts of the downmix matrix.
    824  * @param [inout] Pointer to scale factor matrix associated to the downmix factors.
    825  * @param [in]    Index of channel (row) to be cleared/reset.
    826  * @returns       Nothing to return.
    827  **/
    828 static
    829 void dmxClearChannel(
    830         FIXP_DMX            mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
    831         INT                 mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
    832         const unsigned int  outCh
    833        )
    834 {
    835   FDKmemclear(&mixFactors[outCh], PCM_DMX_MAX_CHANNELS*sizeof(FIXP_DMX));
    836   FDKmemclear(&mixScales[outCh],  PCM_DMX_MAX_CHANNELS*sizeof(INT));
    837 }
    838 
    839 /** Private helper function for downmix matrix manipulation that applies a source channel (row)
    840  *  scaled by a given mix factor to a destination channel (row) in a given downmix matrix.
    841  *  Existing mix factors of the destination channel (row) will get overwritten.
    842  * @param [inout] Pointer to fixed-point parts of the downmix matrix.
    843  * @param [inout] Pointer to scale factor matrix associated to the downmix factors.
    844  * @param [in]    Index of source channel (row).
    845  * @param [in]    Index of destination channel (row).
    846  * @param [in]    Fixed-point part of mix factor to be applied.
    847  * @param [in]    Scale factor of mix factor to be applied.
    848  * @returns       Nothing to return.
    849  **/
    850 static
    851 void dmxSetChannel(
    852         FIXP_DMX            mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
    853         INT                 mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
    854         const unsigned int  dstCh,
    855         const unsigned int  srcCh,
    856         const FIXP_DMX      factor,
    857         const INT           scale
    858        )
    859 {
    860   int ch;
    861   for (ch=0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) {
    862     if (mixFactors[srcCh][ch] != (FIXP_DMX)0) {
    863       mixFactors[dstCh][ch] = FX_DBL2FX_DMX(fMult(mixFactors[srcCh][ch], factor));
    864       mixScales[dstCh][ch]  = mixScales[srcCh][ch] + scale;
    865     }
    866   }
    867 }
    868 
    869 /** Private helper function for downmix matrix manipulation that adds a source channel (row)
    870  *  scaled by a given mix factor to a destination channel (row) in a given downmix matrix.
    871  * @param [inout] Pointer to fixed-point parts of the downmix matrix.
    872  * @param [inout] Pointer to scale factor matrix associated to the downmix factors.
    873  * @param [in]    Index of source channel (row).
    874  * @param [in]    Index of destination channel (row).
    875  * @param [in]    Fixed-point part of mix factor to be applied.
    876  * @param [in]    Scale factor of mix factor to be applied.
    877  * @returns       Nothing to return.
    878  **/
    879 static
    880 void dmxAddChannel(
    881         FIXP_DMX            mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
    882         INT                 mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
    883         const unsigned int  dstCh,
    884         const unsigned int  srcCh,
    885         const FIXP_DMX      factor,
    886         const INT           scale
    887        )
    888 {
    889   int ch;
    890   for (ch=0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) {
    891     FIXP_DBL addFact = fMult(mixFactors[srcCh][ch], factor);
    892     if (addFact != (FIXP_DMX)0) {
    893       INT newScale = mixScales[srcCh][ch] + scale;
    894       if (mixFactors[dstCh][ch] != (FIXP_DMX)0) {
    895         if (newScale > mixScales[dstCh][ch]) {
    896           mixFactors[dstCh][ch] >>= newScale - mixScales[dstCh][ch];
    897         } else {
    898           addFact >>= mixScales[dstCh][ch] - newScale;
    899           newScale  = mixScales[dstCh][ch];
    900         }
    901       }
    902       mixFactors[dstCh][ch] += FX_DBL2FX_DMX(addFact);
    903       mixScales[dstCh][ch]   = newScale;
    904     }
    905   }
    906 }
    907 
    908 
    909 /** Private function that creates a downmix factor matrix depending on the input and output
    910  *  configuration, the user parameters as well as the given metadata. This function is the modules
    911  *  brain and hold all downmix algorithms.
    912  * @param [in]  Flag that indicates if inChMode holds a real (packed) channel mode or has been
    913                 converted to a MPEG-4 channel configuration index.
    914  * @param [in]  Dependent on the inModeIsCfg flag this field hands in a (packed) channel mode or
    915                 the corresponding MPEG-4 channel configuration index.of the input configuration.
    916  * @param [in]  The (packed) channel mode of the output configuration.
    917  * @param [in]  Pointer to structure holding all current user parameter.
    918  * @param [in]  Pointer to field holding all current meta data.
    919  * @param [out] Pointer to fixed-point parts of the downmix matrix. Normalized to one scale factor.
    920  * @param [out] The common scale factor of the downmix matrix.
    921  * @returns     An error code.
    922  **/
    923 static
    924 PCMDMX_ERROR getMixFactors (
    925         const UCHAR                 inModeIsCfg,
    926         PCM_DMX_CHANNEL_MODE        inChMode,
    927         const PCM_DMX_CHANNEL_MODE  outChMode,
    928         const PCM_DMX_USER_PARAMS  *pParams,
    929         const DMX_BS_META_DATA     *pMetaData,
    930         FIXP_DMX                    mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS],
    931         INT                        *pOutScale
    932       )
    933 {
    934   PCMDMX_ERROR err = PCMDMX_OK;
    935   INT  mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS];
    936   INT  maxScale = 0;
    937   int  numInChannel, numOutChannel;
    938   unsigned int  outCh, inCh, inChCfg = 0;
    939   unsigned int  valid[PCM_DMX_MAX_CHANNELS] = { 0 };
    940 
    941   FDK_ASSERT(pMetaData  != NULL);
    942   FDK_ASSERT(mixFactors != NULL);
    943   /* Check on a supported output configuration */
    944   FDK_ASSERT( (outChMode == CH_MODE_1_0_0_0)
    945            || (outChMode == CH_MODE_2_0_0_0)
    946            || (outChMode == CH_MODE_3_0_2_1) );
    947 
    948   if (inModeIsCfg) {
    949     /* Workaround for the ambiguity of the internal channel modes.
    950        Convert channel config to channel mode: */
    951     inChCfg  = (unsigned int)inChMode;
    952     switch (inChCfg) {
    953     case 1: case 2: case 3:
    954 #if (PCM_DMX_MAX_CHANNELS > 3)
    955     case 4: case 5: case 6:
    956 #endif
    957       inChMode = outChModeTable[inChCfg];
    958       break;
    959     case 11:
    960       inChMode = CH_MODE_3_0_3_1;
    961       break;
    962     case 12:
    963       inChMode = CH_MODE_3_0_4_1;
    964       break;
    965     case 7: case 14:
    966       inChMode = CH_MODE_5_0_2_1;
    967       break;
    968     default:
    969       FDK_ASSERT(0);
    970     }
    971   }
    972 
    973   /* Extract the total number of input channels */
    974   numInChannel  =  (inChMode&0xF)
    975                 + ((inChMode>> 4)&0xF)
    976                 + ((inChMode>> 8)&0xF)
    977                 + ((inChMode>>12)&0xF);
    978   /* Extract the total number of output channels */
    979   numOutChannel =  (outChMode&0xF)
    980                 + ((outChMode>> 4)&0xF)
    981                 + ((outChMode>> 8)&0xF)
    982                 + ((outChMode>>12)&0xF);
    983 
    984   /* MPEG ammendment 4 aka ETSI metadata and fallback mode: */
    985 
    986 
    987   /* Create identity DMX matrix: */
    988   for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
    989     dmxInitChannel( mixFactors, mixScales, outCh );
    990   }
    991   if (((inChMode>>12)&0xF) == 0) {
    992     /* Clear empty or wrongly mapped input channel */
    993     dmxClearChannel( mixFactors, mixScales, LOW_FREQUENCY_CHANNEL );
    994   }
    995 
    996   /* FIRST STAGE: */
    997   if (numInChannel > SIX_CHANNEL)
    998   { /* Always use MPEG equations either with meta data or with default values. */
    999     FIXP_DMX  dMixFactA, dMixFactB;
   1000     INT       dMixScaleA, dMixScaleB;
   1001     int       isValidCfg = TRUE;
   1002 
   1003     /* Get factors from meta data */
   1004     dMixFactA  = abMixLvlValueTab[pMetaData->dmixIdxA];
   1005     dMixScaleA = (pMetaData->dmixIdxA==0) ? 1 : 0;
   1006     dMixFactB  = abMixLvlValueTab[pMetaData->dmixIdxB];
   1007     dMixScaleB = (pMetaData->dmixIdxB==0) ? 1 : 0;
   1008 
   1009     /* Check if input is in the list of supported configurations */
   1010     switch (inChMode) {
   1011     case CH_MODE_3_0_3_1:   /* chCfg 11 */
   1012       /* 6.1ch:  C' = C;  L' = L;  R' = R;  LFE' = LFE;
   1013                  Ls' = Ls*dmix_a_idx + Cs*dmix_b_idx;
   1014                  Rs' = Rs*dmix_a_idx + Cs*dmix_b_idx; */
   1015       dmxClearChannel( mixFactors, mixScales, RIGHT_MULTIPRPS_CHANNEL );  /* clear empty input channel */
   1016       dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL,  LEFT_REAR_CHANNEL,      dMixFactA, dMixScaleA );
   1017       dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL,  LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB );
   1018       dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_REAR_CHANNEL,     dMixFactA, dMixScaleA );
   1019       dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB );
   1020       break;
   1021     case CH_MODE_3_2_1_0:
   1022     case CH_MODE_3_2_1_1:   /* chCfg 11 but with side channels */
   1023       /* 6.1ch:  C' = C;  L' = L;  R' = R;  LFE' = LFE;
   1024                  Ls' = Ls*dmix_a_idx + Cs*dmix_b_idx;
   1025                  Rs' = Rs*dmix_a_idx + Cs*dmix_b_idx; */
   1026       dmxClearChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL );  /* clear empty input channel */
   1027       dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, LEFT_REAR_CHANNEL,       dMixFactB, dMixScaleB );
   1028       dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA );
   1029       dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL,  LEFT_REAR_CHANNEL,       dMixFactB, dMixScaleB );
   1030       dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL,  LEFT_MULTIPRPS_CHANNEL,  dMixFactA, dMixScaleA );
   1031       isValidCfg = FALSE;
   1032       err = PCMDMX_INVALID_MODE;
   1033       break;
   1034     case CH_MODE_5_2_1_0:
   1035     case CH_MODE_5_0_1_0:
   1036     case CH_MODE_5_0_1_1:
   1037       /*         Ls' = Cs*dmix_a_idx;
   1038                  Rs' = Cs*dmix_a_idx; */
   1039       dmxClearChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL );  /* clear empty input channel */
   1040       dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA );
   1041       dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL,  LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA );
   1042       isValidCfg = FALSE;
   1043       err = PCMDMX_INVALID_MODE;
   1044       break;
   1045     case CH_MODE_3_0_4_1:   /* chCfg 12 */
   1046       /* 7.1ch Surround Back:  C' = C;  L' = L;  R' = R;  LFE' = LFE;
   1047                                Ls' = Ls*dmix_a_idx + Lsr*dmix_b_idx;
   1048                                Rs' = Rs*dmix_a_idx + Rsr*dmix_b_idx; */
   1049       dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL,  LEFT_REAR_CHANNEL,       dMixFactA, dMixScaleA );
   1050       dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL,  LEFT_MULTIPRPS_CHANNEL,  dMixFactB, dMixScaleB );
   1051       dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_REAR_CHANNEL,      dMixFactA, dMixScaleA );
   1052       dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB );
   1053       break;
   1054     case CH_MODE_5_0_2_1:   /* chCfg 7 || 14 */
   1055       if (inChCfg == 14) {
   1056         /* 7.1ch Front Height:  C' = C;  Ls' = Ls;  Rs' = Rs;  LFE' = LFE;
   1057                                 L' = L*dmix_a_idx + Lv*dmix_b_idx;
   1058                                 R' = R*dmix_a_idx + Rv*dmix_b_idx; */
   1059         dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LEFT_FRONT_CHANNEL,      dMixFactA, dMixScaleA );
   1060         dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LEFT_MULTIPRPS_CHANNEL,  dMixFactB, dMixScaleB );
   1061         dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL,     dMixFactA, dMixScaleA );
   1062         dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB );
   1063       } else {
   1064         /* 7.1ch Front:  Ls' = Ls;  Rs' = Rs;  LFE' = LFE;
   1065                          C' = C + (Lc+Rc)*dmix_a_idx;
   1066                          L' = L + Lc*dmix_b_idx;
   1067                          R' = R + Rc*dmix_b_idx;
   1068                          CAUTION: L+R are not at (MPEG) index 1+2. */
   1069         dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, LEFT_FRONT_CHANNEL,      dMixFactA, dMixScaleA );
   1070         dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL,     dMixFactA, dMixScaleA );
   1071         dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,   LEFT_FRONT_CHANNEL,      dMixFactB, dMixScaleB );
   1072         dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,   LEFT_MULTIPRPS_CHANNEL,  FL2FXCONST_DMX(0.5f), 1 );
   1073         dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL,  RIGHT_FRONT_CHANNEL,     dMixFactB, dMixScaleB );
   1074         dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL,  RIGHT_MULTIPRPS_CHANNEL, FL2FXCONST_DMX(0.5f), 1 );
   1075       }
   1076       break;
   1077     default:
   1078       /* Nothing to do. Just use the identity matrix. */
   1079       isValidCfg = FALSE;
   1080       err = PCMDMX_INVALID_MODE;
   1081       break;
   1082     }
   1083 
   1084     /* Add additional DMX gain */
   1085     if ( (isValidCfg == TRUE)
   1086       && (pMetaData->dmxGainIdx5 != 0))
   1087     { /* Apply DMX gain 5 */
   1088       FIXP_DMX dmxGain;
   1089       INT      dmxScale;
   1090       INT      sign = (pMetaData->dmxGainIdx5 & 0x40) ? -1 : 1;
   1091       INT      val  = pMetaData->dmxGainIdx5 & 0x3F;
   1092 
   1093       /* 10^(dmx_gain_5/80) */
   1094       dmxGain = FX_DBL2FX_DMX( fLdPow(
   1095                                     FL2FXCONST_DBL(0.830482023721841f), 2,  /* log2(10) */
   1096                                     (FIXP_DBL)(sign*val*(LONG)FL2FXCONST_DBL(0.0125f)), 0,
   1097                                    &dmxScale )
   1098                                );
   1099       /* Currently only positive scale factors supported! */
   1100       if (dmxScale < 0) {
   1101         dmxGain >>= -dmxScale;
   1102         dmxScale  =  0;
   1103       }
   1104 
   1105       dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL,  CENTER_FRONT_CHANNEL,  dmxGain, dmxScale );
   1106       dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,    LEFT_FRONT_CHANNEL,    dmxGain, dmxScale );
   1107       dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL,   RIGHT_FRONT_CHANNEL,   dmxGain, dmxScale );
   1108       dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL,     LEFT_REAR_CHANNEL,     dmxGain, dmxScale );
   1109       dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL,    RIGHT_REAR_CHANNEL,    dmxGain, dmxScale );
   1110       dmxSetChannel( mixFactors, mixScales, LOW_FREQUENCY_CHANNEL, LOW_FREQUENCY_CHANNEL, dmxGain, dmxScale );
   1111     }
   1112 
   1113     /* Mark the output channels */
   1114     valid[CENTER_FRONT_CHANNEL]  = 1;
   1115     valid[LEFT_FRONT_CHANNEL]    = 1;
   1116     valid[RIGHT_FRONT_CHANNEL]   = 1;
   1117     valid[LEFT_REAR_CHANNEL]     = 1;
   1118     valid[RIGHT_REAR_CHANNEL]    = 1;
   1119     valid[LOW_FREQUENCY_CHANNEL] = 1;
   1120 
   1121     /* Update channel mode for the next stage */
   1122     inChMode = CH_MODE_3_0_2_1;
   1123   }
   1124 
   1125   /* SECOND STAGE: */
   1126   if (numOutChannel <= TWO_CHANNEL) {
   1127     /* Create DMX matrix according to input configuration */
   1128     switch (inChMode) {
   1129     case CH_MODE_2_0_0_0:   /* chCfg 2 */
   1130       /* Apply the dual channel mode. */
   1131       switch (pParams->dualChannelMode) {
   1132       case CH1_MODE:  /* L' = 0.707 * Ch1;
   1133                          R' = 0.707 * Ch1; */
   1134         dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LEFT_FRONT_CHANNEL,  FL2FXCONST_DMX(0.707f), 0 );
   1135         dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL,  FL2FXCONST_DMX(0.707f), 0 );
   1136         break;
   1137       case CH2_MODE:  /* L' = 0.707 * Ch2;
   1138                          R' = 0.707 * Ch2; */
   1139         dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
   1140         dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
   1141         break;
   1142       case MIXED_MODE:  /* L' = 0.5*Ch1 + 0.5*Ch2;
   1143                            R' = 0.5*Ch1 + 0.5*Ch2; */
   1144         dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LEFT_FRONT_CHANNEL,  FL2FXCONST_DMX(0.5f), 0 );
   1145         dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0 );
   1146         dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL,  FL2FXCONST_DMX(0.5f), 0 );
   1147         dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0 );
   1148         break;
   1149       default:
   1150       case STEREO_MODE:
   1151         /* Nothing to do */
   1152         break;
   1153       }
   1154       break;
   1155     case CH_MODE_2_0_1_0:
   1156       /* L' = L + 0.707*S;
   1157          R' = R + 0.707*S; */
   1158       dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LEFT_REAR_CHANNEL,   FL2FXCONST_DMX(0.707f), 0 );
   1159       dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL,   FL2FXCONST_DMX(0.707f), 0 );
   1160       break;
   1161     case CH_MODE_3_0_0_0:   /* chCfg 3 */
   1162       /* L' = L + 0.707*C;
   1163          R' = R + 0.707*C; */
   1164       dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
   1165       dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
   1166       break;
   1167     case CH_MODE_3_0_1_0:   /* chCfg 4 */
   1168       /* L' = L + 0.707*C + 0.707*S;
   1169          R' = R + 0.707*C + 0.707*S; */
   1170       dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
   1171       dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LEFT_REAR_CHANNEL,    FL2FXCONST_DMX(0.707f), 0 );
   1172       dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 );
   1173       dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL,    FL2FXCONST_DMX(0.707f), 0 );
   1174       break;
   1175     case CH_MODE_3_0_2_0:   /* chCfg 5 */
   1176     case CH_MODE_3_0_2_1:   /* chCfg 6 */
   1177       /* MPEG + ITU + DLB
   1178          But because the default downmix equations and coefficients are equal we stick to MPEG. */
   1179       if (  (pMetaData->typeFlags & TYPE_DSE_DATA)
   1180         || !(pMetaData->typeFlags & TYPE_PCE_DATA) )
   1181       {
   1182         FIXP_DMX  cMixLvl, sMixLvl, lMixLvl;
   1183         INT       cMixScale, sMixScale, lMixScale;
   1184 
   1185         /* Get factors from meta data */
   1186         cMixLvl   = abMixLvlValueTab[pMetaData->cLevIdx];
   1187         cMixScale = (pMetaData->cLevIdx==0) ? 1 : 0;
   1188         sMixLvl   = abMixLvlValueTab[pMetaData->sLevIdx];
   1189         sMixScale = (pMetaData->sLevIdx==0) ? 1 : 0;
   1190         lMixLvl   = lfeMixLvlValueTab[pMetaData->dmixIdxLfe];
   1191         if (pMetaData->dmixIdxLfe <= 1) {
   1192           lMixScale = 2;
   1193         } else if (pMetaData->dmixIdxLfe <= 5) {
   1194           lMixScale = 1;
   1195         } else {
   1196           lMixScale = 0;
   1197         }
   1198         /* Setup the DMX matrix */
   1199         if ( (pParams->pseudoSurrMode == FORCE_PS_DMX)
   1200           || ((pParams->pseudoSurrMode == AUTO_PS_DMX) && (pMetaData->pseudoSurround==1)))
   1201         { /* L' = L + C*clev - (Ls+Rs)*slev + LFE*lflev;
   1202              R' = R + C*clev + (Ls+Rs)*slev + LFE*lflev; */
   1203           dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  CENTER_FRONT_CHANNEL,  cMixLvl, cMixScale );
   1204           dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LEFT_REAR_CHANNEL,    -sMixLvl, sMixScale );
   1205           dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  RIGHT_REAR_CHANNEL,   -sMixLvl, sMixScale );
   1206           dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale );
   1207           dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL,  cMixLvl, cMixScale );
   1208           dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL,     sMixLvl, sMixScale );
   1209           dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL,    sMixLvl, sMixScale );
   1210           dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale );
   1211         }
   1212         else
   1213         { /* L' = L + C*clev + Ls*slev + LFE*llev;
   1214              R' = R + C*clev + Rs*slev + LFE*llev; */
   1215           dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  CENTER_FRONT_CHANNEL,  cMixLvl, cMixScale );
   1216           dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LEFT_REAR_CHANNEL,     sMixLvl, sMixScale );
   1217           dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale );
   1218           dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL,  cMixLvl, cMixScale );
   1219           dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL,    sMixLvl, sMixScale );
   1220           dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale );
   1221         }
   1222 
   1223         /* Add additional DMX gain */
   1224         if ( pMetaData->dmxGainIdx2 != 0 )
   1225         { /* Apply DMX gain 2 */
   1226           FIXP_DMX dmxGain;
   1227           INT      dmxScale;
   1228           INT      sign = (pMetaData->dmxGainIdx2 & 0x40) ? -1 : 1;
   1229           INT      val  = pMetaData->dmxGainIdx2 & 0x3F;
   1230 
   1231           /* 10^(dmx_gain_2/80) */
   1232           dmxGain = FX_DBL2FX_DMX( fLdPow(
   1233                                         FL2FXCONST_DBL(0.830482023721841f), 2,  /* log2(10) */
   1234                                         (FIXP_DBL)(sign*val*(LONG)FL2FXCONST_DBL(0.0125f)), 0,
   1235                                        &dmxScale )
   1236                                    );
   1237           /* Currently only positive scale factors supported! */
   1238           if (dmxScale < 0) {
   1239             dmxGain >>= -dmxScale;
   1240             dmxScale  =  0;
   1241           }
   1242 
   1243           dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LEFT_FRONT_CHANNEL,  dmxGain, dmxScale );
   1244           dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, dmxGain, dmxScale );
   1245         }
   1246       }
   1247 #ifdef PCE_METADATA_ENABLE
   1248       else {
   1249         FIXP_DMX  flev, clev, slevLL, slevLR, slevRL, slevRR;
   1250         FIXP_DMX  mtrxMixDwnCoef = mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx];
   1251 
   1252         if ( (pParams->pseudoSurrMode == FORCE_PS_DMX)
   1253           || ((pParams->pseudoSurrMode == AUTO_PS_DMX) && (pMetaData->pseudoSurround==1)))
   1254         { /* 3/2 input: L' = (1.707+2*A)^-1 * [L+0.707*C-A*Ls-A*Rs];
   1255                         R' = (1.707+2*A)^-1 * [R+0.707*C+A*Ls+A*Rs]; */
   1256           flev = mpegMixDownIdx2PreFact[1][pMetaData->matrixMixdownIdx];
   1257           slevRR = slevRL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
   1258           slevLL = slevLR = -slevRL;
   1259         }
   1260         else {
   1261           /* 3/2 input: L' = (1.707+A)^-1 * [L+0.707*C+A*Ls];
   1262                         R' = (1.707+A)^-1 * [R+0.707*C+A*Rs]; */
   1263           flev = mpegMixDownIdx2PreFact[0][pMetaData->matrixMixdownIdx];
   1264           slevRR = slevLL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
   1265           slevLR = slevRL = (FIXP_SGL)0;
   1266         }
   1267         /* common factor */
   1268         clev  = FX_DBL2FX_DMX(fMult(flev, mpegMixDownIdx2Coef[0] /* 0.707 */));
   1269 
   1270         dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LEFT_FRONT_CHANNEL,   flev,   0 );
   1271         dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  CENTER_FRONT_CHANNEL, clev,   0 );
   1272         dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  LEFT_REAR_CHANNEL,    slevLL, 0 );
   1273         dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL,  RIGHT_REAR_CHANNEL,   slevLR, 0 );
   1274 
   1275         dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL,  flev,   0 );
   1276         dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, clev,   0 );
   1277         dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL,    slevRL, 0 );
   1278         dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL,   slevRR, 0 );
   1279       }
   1280 #endif  /* PCE_METADATA_ENABLE */
   1281       break;
   1282     default:
   1283       /* This configuration does not fit to any known downmix equation! */
   1284       err = PCMDMX_INVALID_MODE;
   1285       break;
   1286     }
   1287     /* Mark the output channels */
   1288     FDKmemclear(valid, PCM_DMX_MAX_CHANNELS*sizeof(unsigned int));
   1289     valid[LEFT_FRONT_CHANNEL]  = 1;
   1290     valid[RIGHT_FRONT_CHANNEL] = 1;
   1291     /* Update channel mode for the next stage */
   1292     inChMode = CH_MODE_2_0_0_0;
   1293   }
   1294 
   1295   if (numOutChannel == ONE_CHANNEL) {
   1296     FIXP_DMX monoMixLevel;
   1297     INT      monoMixScale;
   1298 
   1299 #ifdef PCE_METADATA_ENABLE
   1300     if (  (pMetaData->typeFlags & TYPE_PCE_DATA)
   1301       && !(pMetaData->typeFlags & TYPE_DSE_DATA) )
   1302     { /* C' = (3+2*A)^-1 * [C+L+R+A*Ls+A+Rs]; */
   1303       monoMixLevel = mpegMixDownIdx2PreFact[2][pMetaData->matrixMixdownIdx];
   1304       monoMixScale = 0;
   1305 
   1306       dmxClearChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL );
   1307       mixFactors[CENTER_FRONT_CHANNEL][CENTER_FRONT_CHANNEL] = monoMixLevel;
   1308       mixFactors[CENTER_FRONT_CHANNEL][LEFT_FRONT_CHANNEL]   = monoMixLevel;
   1309       mixFactors[CENTER_FRONT_CHANNEL][RIGHT_FRONT_CHANNEL]  = monoMixLevel;
   1310       monoMixLevel = FX_DBL2FX_DMX(fMult(monoMixLevel, mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx]));
   1311       mixFactors[CENTER_FRONT_CHANNEL][LEFT_REAR_CHANNEL]    = monoMixLevel;
   1312       mixFactors[CENTER_FRONT_CHANNEL][RIGHT_REAR_CHANNEL]   = monoMixLevel;
   1313     }
   1314     else
   1315 #endif
   1316     { /* C' = L + R; [default] */
   1317       monoMixLevel = FL2FXCONST_DMX(0.5f);
   1318       monoMixScale = 1;
   1319       dmxClearChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL );  /* C is not in the mix */
   1320       dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, LEFT_FRONT_CHANNEL,  monoMixLevel, monoMixScale );
   1321       dmxAddChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, monoMixLevel, monoMixScale );
   1322     }
   1323 
   1324     /* Mark the output channel */
   1325     FDKmemclear(valid, PCM_DMX_MAX_CHANNELS*sizeof(unsigned int));
   1326     valid[CENTER_FRONT_CHANNEL] = 1;
   1327   }
   1328 
   1329 #define MAX_SEARCH_START_VAL  ( -7 )
   1330 
   1331   {
   1332     LONG chSum[PCM_DMX_MAX_CHANNELS];
   1333     INT  chSumMax = MAX_SEARCH_START_VAL;
   1334 
   1335     /* Determine the current maximum scale factor */
   1336     for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
   1337       if (valid[outCh]!=0) {
   1338         for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) {
   1339           if (mixScales[outCh][inCh] > maxScale)
   1340           { /* Store the new maximum */
   1341             maxScale = mixScales[outCh][inCh];
   1342           }
   1343         }
   1344       }
   1345     }
   1346 
   1347     /* Individualy analyse output chanal levels */
   1348     for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
   1349       chSum[outCh] = MAX_SEARCH_START_VAL;
   1350       if (valid[outCh]!=0) {
   1351         int  ovrflwProtScale = 0;
   1352 
   1353         /* Accumulate all factors for each output channel */
   1354         chSum[outCh] = 0;
   1355         for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) {
   1356           SHORT addFact = FX_DMX2SHRT(mixFactors[outCh][inCh]);
   1357           if ( mixScales[outCh][inCh] <= maxScale ) {
   1358             addFact >>= maxScale - mixScales[outCh][inCh];
   1359           } else {
   1360             addFact <<= mixScales[outCh][inCh] - maxScale;
   1361           }
   1362           chSum[outCh] += addFact;
   1363         }
   1364         if (chSum[outCh] > (LONG)MAXVAL_SGL) {
   1365           while (chSum[outCh] > (LONG)MAXVAL_SGL) {
   1366             ovrflwProtScale += 1;
   1367             chSum[outCh] >>= 1;
   1368           }
   1369         } else if (chSum[outCh] > 0) {
   1370           while ((chSum[outCh]<<1) <= (LONG)MAXVAL_SGL) {
   1371             ovrflwProtScale -= 1;
   1372             chSum[outCh] <<= 1;
   1373           }
   1374         }
   1375         /* Store the differential scaling in the same array */
   1376         chSum[outCh] = ovrflwProtScale;
   1377       }
   1378     }
   1379 
   1380     for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
   1381       if ( (valid[outCh] != 0)
   1382         && (chSum[outCh] > chSumMax) )
   1383       { /* Store the new maximum */
   1384         chSumMax = chSum[outCh];
   1385       }
   1386     }
   1387     maxScale = FDKmax(maxScale+chSumMax, 0);
   1388 
   1389     /* Normalize all factors */
   1390     for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
   1391       if (valid[outCh]!=0) {
   1392         for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) {
   1393           if (mixFactors[outCh][inCh] != (FIXP_DMX)0) {
   1394             if ( mixScales[outCh][inCh] <= maxScale ) {
   1395               mixFactors[outCh][inCh] >>= maxScale - mixScales[outCh][inCh];
   1396             } else {
   1397               mixFactors[outCh][inCh] <<= mixScales[outCh][inCh] - maxScale;
   1398             }
   1399             mixScales[outCh][inCh] = maxScale;
   1400           }
   1401         }
   1402       }
   1403     }
   1404   }
   1405 
   1406 
   1407   /* return the scale factor */
   1408   *pOutScale = maxScale;
   1409 
   1410   return (err);
   1411 }
   1412 
   1413 
   1414 /** Open and initialize an instance of the PCM downmix module
   1415  * @param [out] Pointer to a buffer receiving the handle of the new instance.
   1416  * @returns Returns an error code.
   1417  **/
   1418 PCMDMX_ERROR pcmDmx_Open (
   1419     HANDLE_PCM_DOWNMIX *pSelf
   1420   )
   1421 {
   1422   HANDLE_PCM_DOWNMIX self;
   1423 
   1424   if (pSelf == NULL) {
   1425     return (PCMDMX_INVALID_HANDLE);
   1426   }
   1427 
   1428   *pSelf = NULL;
   1429 
   1430   self = (HANDLE_PCM_DOWNMIX) GetPcmDmxInstance( 0 );
   1431   if (self == NULL) {
   1432     return (PCMDMX_OUT_OF_MEMORY);
   1433   }
   1434 
   1435   /* Reset the full instance */
   1436   pcmDmx_Reset( self, PCMDMX_RESET_FULL );
   1437 
   1438   *pSelf = self;
   1439 
   1440   return (PCMDMX_OK);
   1441 }
   1442 
   1443 
   1444 /** Reset all static values like e.g. mixdown coefficients.
   1445  * @param [in] Handle of PCM downmix module instance.
   1446  * @param [in] Flags telling which parts of the module shall be reset.
   1447  * @returns Returns an error code.
   1448  **/
   1449 PCMDMX_ERROR pcmDmx_Reset (
   1450     HANDLE_PCM_DOWNMIX  self,
   1451     UINT                flags
   1452   )
   1453 {
   1454   if (self == NULL) { return (PCMDMX_INVALID_HANDLE); }
   1455 
   1456   if (flags & PCMDMX_RESET_PARAMS) {
   1457     PCM_DMX_USER_PARAMS *pParams = &self->userParams;
   1458 
   1459     pParams->dualChannelMode   = STEREO_MODE;
   1460     pParams->pseudoSurrMode    = NEVER_DO_PS_DMX;
   1461     pParams->numOutChannelsMax = PCM_DMX_DFLT_MAX_OUT_CHANNELS;
   1462     pParams->numOutChannelsMin = PCM_DMX_DFLT_MIN_OUT_CHANNELS;
   1463     pParams->frameDelay        = 0;
   1464     pParams->expiryFrame       = PCM_DMX_DFLT_EXPIRY_FRAME;
   1465 
   1466     self->applyProcessing      = 0;
   1467   }
   1468 
   1469   if (flags & PCMDMX_RESET_BS_DATA) {
   1470     int slot;
   1471     /* Init all slots with a default set */
   1472     for (slot = 0; slot <= PCM_DMX_MAX_DELAY_FRAMES; slot += 1) {
   1473       FDKmemcpy(&self->bsMetaData[slot], &dfltMetaData, sizeof(DMX_BS_META_DATA));
   1474     }
   1475   }
   1476 
   1477   return (PCMDMX_OK);
   1478 }
   1479 
   1480 
   1481 /** Set one parameter for one instance of the PCM downmix module.
   1482  * @param [in] Handle of PCM downmix module instance.
   1483  * @param [in] Parameter to be set.
   1484  * @param [in] Parameter value.
   1485  * @returns Returns an error code.
   1486  **/
   1487 PCMDMX_ERROR pcmDmx_SetParam (
   1488     HANDLE_PCM_DOWNMIX  self,
   1489     const PCMDMX_PARAM  param,
   1490     const INT           value
   1491   )
   1492 {
   1493   switch (param)
   1494   {
   1495   case DMX_BS_DATA_EXPIRY_FRAME:
   1496     if (self == NULL)
   1497       return (PCMDMX_INVALID_HANDLE);
   1498     self->userParams.expiryFrame = (value > 0) ? (UINT)value : 0;
   1499     break;
   1500 
   1501   case DMX_BS_DATA_DELAY:
   1502     if ( (value > PCM_DMX_MAX_DELAY_FRAMES)
   1503       || (value < 0) ) {
   1504       return (PCMDMX_UNABLE_TO_SET_PARAM);
   1505     }
   1506     if (self == NULL) {
   1507       return (PCMDMX_INVALID_HANDLE);
   1508     }
   1509     self->userParams.frameDelay = (UCHAR)value;
   1510     break;
   1511 
   1512   case MIN_NUMBER_OF_OUTPUT_CHANNELS:
   1513     switch (value) {  /* supported output channels */
   1514     case -1: case 0: case ONE_CHANNEL: case TWO_CHANNEL:
   1515 #if (PCM_DMX_MAX_OUT_CHANNELS >= 6)
   1516     case SIX_CHANNEL:
   1517 #endif
   1518 #if (PCM_DMX_MAX_OUT_CHANNELS >= 8)
   1519     case EIGHT_CHANNEL:
   1520 #endif
   1521       break;
   1522     default:
   1523       return (PCMDMX_UNABLE_TO_SET_PARAM);
   1524     }
   1525     if (self == NULL)
   1526       return (PCMDMX_INVALID_HANDLE);
   1527     /* Store the new value */
   1528     self->userParams.numOutChannelsMin = (value > 0) ? value : -1;
   1529     if ( (value > 0)
   1530       && (self->userParams.numOutChannelsMax > 0)
   1531       && (value > self->userParams.numOutChannelsMax) )
   1532     { /* MIN > MAX would be an invalid state. Thus set MAX = MIN in this case. */
   1533       self->userParams.numOutChannelsMax = self->userParams.numOutChannelsMin;
   1534     }
   1535     break;
   1536 
   1537   case MAX_NUMBER_OF_OUTPUT_CHANNELS:
   1538     switch (value) {  /* supported output channels */
   1539     case -1: case 0: case ONE_CHANNEL: case TWO_CHANNEL:
   1540 #if (PCM_DMX_MAX_OUT_CHANNELS >= 6)
   1541     case SIX_CHANNEL:
   1542 #endif
   1543 #if (PCM_DMX_MAX_OUT_CHANNELS >= 8)
   1544     case EIGHT_CHANNEL:
   1545 #endif
   1546       break;
   1547     default:
   1548       return (PCMDMX_UNABLE_TO_SET_PARAM);
   1549     }
   1550     if (self == NULL)
   1551       return (PCMDMX_INVALID_HANDLE);
   1552     /* Store the new value */
   1553     self->userParams.numOutChannelsMax = (value > 0) ? value : -1;
   1554     if ( (value > 0)
   1555       && (value < self->userParams.numOutChannelsMin) )
   1556     { /* MAX < MIN would be an invalid state. Thus set MIN = MAX in this case. */
   1557       self->userParams.numOutChannelsMin = self->userParams.numOutChannelsMax;
   1558     }
   1559     break;
   1560 
   1561   case DMX_DUAL_CHANNEL_MODE:
   1562     switch ((DUAL_CHANNEL_MODE)value) {
   1563     case STEREO_MODE:
   1564     case CH1_MODE:
   1565     case CH2_MODE:
   1566     case MIXED_MODE:
   1567       break;
   1568     default:
   1569       return (PCMDMX_UNABLE_TO_SET_PARAM);
   1570     }
   1571     if (self == NULL)
   1572       return (PCMDMX_INVALID_HANDLE);
   1573     self->userParams.dualChannelMode = (DUAL_CHANNEL_MODE)value;
   1574     self->applyProcessing = 1;  /* Force processing */
   1575     break;
   1576 
   1577   case DMX_PSEUDO_SURROUND_MODE:
   1578     switch ((PSEUDO_SURROUND_MODE)value) {
   1579     case NEVER_DO_PS_DMX:
   1580     case AUTO_PS_DMX:
   1581     case FORCE_PS_DMX:
   1582       break;
   1583     default:
   1584       return (PCMDMX_UNABLE_TO_SET_PARAM);
   1585     }
   1586     if (self == NULL)
   1587       return (PCMDMX_INVALID_HANDLE);
   1588     self->userParams.pseudoSurrMode = (PSEUDO_SURROUND_MODE)value;
   1589     break;
   1590 
   1591   default:
   1592     return (PCMDMX_UNKNOWN_PARAM);
   1593   }
   1594 
   1595   return (PCMDMX_OK);
   1596 }
   1597 
   1598 /** Get one parameter value of one PCM downmix module instance.
   1599  * @param [in] Handle of PCM downmix module instance.
   1600  * @param [in] Parameter to be set.
   1601  * @param [out] Pointer to buffer receiving the parameter value.
   1602  * @returns Returns an error code.
   1603  **/
   1604 PCMDMX_ERROR pcmDmx_GetParam (
   1605     HANDLE_PCM_DOWNMIX  self,
   1606     const PCMDMX_PARAM  param,
   1607     INT * const         pValue
   1608   )
   1609 {
   1610   PCM_DMX_USER_PARAMS *pUsrParams;
   1611 
   1612   if ( (self == NULL)
   1613     || (pValue == NULL) ) {
   1614     return (PCMDMX_INVALID_HANDLE);
   1615   }
   1616   pUsrParams = &self->userParams;
   1617 
   1618   switch (param)
   1619   {
   1620   case DMX_BS_DATA_EXPIRY_FRAME:
   1621     *pValue = (INT)pUsrParams->expiryFrame;
   1622     break;
   1623   case DMX_BS_DATA_DELAY:
   1624     *pValue = (INT)pUsrParams->frameDelay;
   1625     break;
   1626   case MIN_NUMBER_OF_OUTPUT_CHANNELS:
   1627     *pValue = (INT)pUsrParams->numOutChannelsMin;
   1628     break;
   1629   case MAX_NUMBER_OF_OUTPUT_CHANNELS:
   1630     *pValue = (INT)pUsrParams->numOutChannelsMax;
   1631     break;
   1632   case DMX_DUAL_CHANNEL_MODE:
   1633     *pValue = (INT)pUsrParams->dualChannelMode;
   1634     break;
   1635   case DMX_PSEUDO_SURROUND_MODE:
   1636     *pValue = (INT)pUsrParams->pseudoSurrMode;
   1637     break;
   1638   default:
   1639     return (PCMDMX_UNKNOWN_PARAM);
   1640   }
   1641 
   1642   return (PCMDMX_OK);
   1643 }
   1644 
   1645 
   1646 #ifdef DSE_METADATA_ENABLE
   1647 
   1648 #define MAX_DSE_ANC_BYTES       ( 16 )    /* 15 bytes */
   1649 #define ANC_DATA_SYNC_BYTE      ( 0xBC )  /* ancillary data sync byte. */
   1650 
   1651 /*
   1652  * Read DMX meta-data from a data stream element.
   1653  */
   1654 PCMDMX_ERROR pcmDmx_Parse (
   1655     HANDLE_PCM_DOWNMIX  self,
   1656     HANDLE_FDK_BITSTREAM  hBs,
   1657     UINT  ancDataBits,
   1658     int    isMpeg2
   1659   )
   1660 {
   1661   PCMDMX_ERROR errorStatus = PCMDMX_OK;
   1662   DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0];
   1663 
   1664   int   skip4Dmx = 0, skip4Ext = 0;
   1665   int   dmxLvlAvail = 0, extDataAvail = 0;
   1666   int   foundNewData = 0;
   1667   UINT  minAncBits = ((isMpeg2) ? 5 : 3)*8;
   1668 
   1669   if ( (self == NULL)
   1670     || (hBs  == NULL) ) { return (PCMDMX_INVALID_HANDLE); }
   1671 
   1672   ancDataBits = FDKgetValidBits(hBs);
   1673 
   1674   /* sanity checks */
   1675   if ( (ancDataBits < minAncBits)
   1676     || (ancDataBits > FDKgetValidBits(hBs)) ) {
   1677     return (PCMDMX_CORRUPT_ANC_DATA);
   1678   }
   1679 
   1680   pBsMetaData = &self->bsMetaData[0];
   1681 
   1682   if (isMpeg2) {
   1683     /* skip DVD ancillary data */
   1684     FDKpushFor(hBs, 16);
   1685   }
   1686 
   1687   /* check sync word */
   1688   if (FDKreadBits(hBs,8) != ANC_DATA_SYNC_BYTE) {
   1689     return (PCMDMX_CORRUPT_ANC_DATA);
   1690   }
   1691 
   1692   /* skip MPEG audio type and Dolby surround mode */
   1693   FDKpushFor(hBs, 4);
   1694 
   1695   if (isMpeg2) {
   1696     /* int numAncBytes = */ FDKreadBits(hBs, 4);
   1697     /* advanced dynamic range control */
   1698     if (FDKreadBit(hBs)) skip4Dmx += 24;
   1699     /* dialog normalization */
   1700     if (FDKreadBit(hBs)) skip4Dmx += 8;
   1701     /* reproduction_level */
   1702     if (FDKreadBit(hBs)) skip4Dmx += 8;
   1703   } else {
   1704     FDKpushFor(hBs, 2);   /* drc presentation mode */
   1705     pBsMetaData->pseudoSurround = FDKreadBit(hBs);
   1706     FDKpushFor(hBs, 4);   /* reserved bits */
   1707   }
   1708 
   1709   /* downmixing levels MPEGx status */
   1710   dmxLvlAvail  = FDKreadBit(hBs);
   1711 
   1712   if (isMpeg2) {
   1713     /* scale factor CRC status */
   1714     if (FDKreadBit(hBs)) skip4Ext += 16;
   1715   } else {
   1716     /* ancillary data extension status */
   1717     extDataAvail = FDKreadBit(hBs);
   1718   }
   1719 
   1720   /* audio coding and compression status */
   1721   if (FDKreadBit(hBs)) skip4Ext += 16;
   1722   /* coarse grain timecode status */
   1723   if (FDKreadBit(hBs)) skip4Ext += 16;
   1724   /* fine grain timecode status */
   1725   if (FDKreadBit(hBs)) skip4Ext += 16;
   1726 
   1727   /* skip the useless data to get to the DMX levels */
   1728   FDKpushFor(hBs, skip4Dmx);
   1729 
   1730   /* downmix_levels_MPEGX */
   1731   if (dmxLvlAvail)
   1732   {
   1733     if (FDKreadBit(hBs)) {  /* center_mix_level_on */
   1734       pBsMetaData->cLevIdx = FDKreadBits(hBs, 3);
   1735       foundNewData = 1;
   1736     } else {
   1737       FDKreadBits(hBs, 3);
   1738     }
   1739     if (FDKreadBit(hBs)) {  /* surround_mix_level_on */
   1740       pBsMetaData->sLevIdx = FDKreadBits(hBs, 3);
   1741       foundNewData = 1;
   1742     } else {
   1743       FDKreadBits(hBs, 3);
   1744     }
   1745   }
   1746 
   1747   /* skip the useless data to get to the ancillary data extension */
   1748   FDKpushFor(hBs, skip4Ext);
   1749 
   1750   /* anc data extension (MPEG-4 only) */
   1751   if (extDataAvail) {
   1752     int extDmxLvlSt, extDmxGainSt, extDmxLfeSt;
   1753 
   1754     FDKreadBit(hBs);        /* reserved bit */
   1755     extDmxLvlSt  = FDKreadBit(hBs);
   1756     extDmxGainSt = FDKreadBit(hBs);
   1757     extDmxLfeSt  = FDKreadBit(hBs);
   1758     FDKreadBits(hBs, 4);    /* reserved bits */
   1759 
   1760     if (extDmxLvlSt) {
   1761       pBsMetaData->dmixIdxA = FDKreadBits(hBs, 3);
   1762       pBsMetaData->dmixIdxB = FDKreadBits(hBs, 3);
   1763       FDKreadBits(hBs, 2);  /* reserved bits */
   1764       foundNewData = 1;
   1765     }
   1766     if (extDmxGainSt) {
   1767       pBsMetaData->dmxGainIdx5 = FDKreadBits(hBs, 7);
   1768       FDKreadBit(hBs);      /* reserved bit */
   1769       pBsMetaData->dmxGainIdx2 = FDKreadBits(hBs, 7);
   1770       FDKreadBit(hBs);      /* reserved bit */
   1771       foundNewData = 1;
   1772     }
   1773     if (extDmxLfeSt) {
   1774       pBsMetaData->dmixIdxLfe = FDKreadBits(hBs, 4);
   1775       FDKreadBits(hBs, 4);  /* reserved bits */
   1776       foundNewData = 1;
   1777     }
   1778   }
   1779 
   1780   /* final sanity check on the amount of read data */
   1781   if ((INT)FDKgetValidBits(hBs) < 0) {
   1782     errorStatus = PCMDMX_CORRUPT_ANC_DATA;
   1783   }
   1784 
   1785   if ( (errorStatus  == PCMDMX_OK)
   1786     && (foundNewData == 1) ) {
   1787     /* announce new data */
   1788     pBsMetaData->typeFlags |= TYPE_DSE_DATA;
   1789     /* reset expiry counter */
   1790     pBsMetaData->expiryCount = 0;
   1791   }
   1792 
   1793   return (errorStatus);
   1794 }
   1795 
   1796 /*
   1797  * Read DMX meta-data from a data stream element.
   1798  */
   1799 PCMDMX_ERROR pcmDmx_ReadDvbAncData (
   1800     HANDLE_PCM_DOWNMIX  self,
   1801     UCHAR *pAncDataBuf,
   1802     UINT   ancDataBytes,
   1803     int    isMpeg2
   1804   )
   1805 {
   1806   FDK_BITSTREAM bs;
   1807   HANDLE_FDK_BITSTREAM hBs = &bs;
   1808   PCMDMX_ERROR errorStatus = PCMDMX_OK;
   1809 
   1810   if (self == NULL) { return (PCMDMX_INVALID_HANDLE); }
   1811 
   1812   /* sanity checks */
   1813   if ( (pAncDataBuf == NULL)
   1814     || (ancDataBytes == 0) ) {
   1815     return (PCMDMX_CORRUPT_ANC_DATA);
   1816   }
   1817 
   1818   FDKinitBitStream (hBs, pAncDataBuf, MAX_DSE_ANC_BYTES, ancDataBytes*8, BS_READER);
   1819 
   1820   errorStatus = pcmDmx_Parse (
   1821                         self,
   1822                         hBs,
   1823                         ancDataBytes*8,
   1824                         isMpeg2 );
   1825 
   1826   return (errorStatus);
   1827 }
   1828 #endif  /* DSE_METADATA_ENABLE */
   1829 
   1830 #ifdef PCE_METADATA_ENABLE
   1831 /** Set the matrix mixdown information extracted from the PCE of an AAC bitstream.
   1832  *  Note: Call only if matrix_mixdown_idx_present is true.
   1833  * @param [in] Handle of PCM downmix module instance.
   1834  * @param [in] The 2 bit matrix mixdown index extracted from PCE.
   1835  * @param [in] The pseudo surround enable flag extracted from PCE.
   1836  * @returns Returns an error code.
   1837  **/
   1838 PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce (
   1839     HANDLE_PCM_DOWNMIX  self,
   1840     int                 matrixMixdownPresent,
   1841     int                 matrixMixdownIdx,
   1842     int                 pseudoSurroundEnable
   1843   )
   1844 {
   1845   DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0];
   1846 
   1847   if (self == NULL) {
   1848     return (PCMDMX_INVALID_HANDLE);
   1849   }
   1850 
   1851   if (matrixMixdownPresent) {
   1852     pBsMetaData->pseudoSurround = pseudoSurroundEnable;
   1853     pBsMetaData->matrixMixdownIdx = matrixMixdownIdx & 0x03;
   1854     pBsMetaData->typeFlags |= TYPE_PCE_DATA;
   1855     /* Reset expiry counter */
   1856     pBsMetaData->expiryCount = 0;
   1857   }
   1858 
   1859   return (PCMDMX_OK);
   1860 }
   1861 #endif  /* PCE_METADATA_ENABLE */
   1862 
   1863 
   1864 /** Apply down or up mixing.
   1865  * @param [in]    Handle of PCM downmix module instance.
   1866  * @param [inout] Pointer to buffer that hold the time domain signal.
   1867  * @param [in]    Pointer where the amount of output samples is returned into.
   1868  * @param [inout] Pointer where the amount of output channels is returned into.
   1869  * @param [in]    Flag which indicates if output time data are writtern interleaved or as subsequent blocks.
   1870  * @param [inout] Array where the corresponding channel type for each output audio channel is stored into.
   1871  * @param [inout] Array where the corresponding channel type index for each output audio channel is stored into.
   1872  * @param [in]    Array containing the out channel mapping to be used (From MPEG PCE ordering to whatever is required).
   1873  * @param [out]   Pointer on a field receiving the scale factor that has to be applied on all samples afterwards.
   1874  *                If the handed pointer is NULL scaling is done internally.
   1875  * @returns Returns an error code.
   1876  **/
   1877 PCMDMX_ERROR pcmDmx_ApplyFrame (
   1878         HANDLE_PCM_DOWNMIX      self,
   1879         INT_PCM                *pPcmBuf,
   1880         UINT                    frameSize,
   1881         INT                    *nChannels,
   1882         int                     fInterleaved,
   1883         AUDIO_CHANNEL_TYPE      channelType[],
   1884         UCHAR                   channelIndices[],
   1885         const UCHAR             channelMapping[][8],
   1886         INT                    *pDmxOutScale
   1887   )
   1888 {
   1889   PCM_DMX_USER_PARAMS  *pParam = NULL;
   1890   PCMDMX_ERROR  errorStatus = PCMDMX_OK;
   1891   DUAL_CHANNEL_MODE  dualChannelMode;
   1892   PCM_DMX_CHANNEL_MODE  inChMode;
   1893   PCM_DMX_CHANNEL_MODE  outChMode;
   1894   INT   devNull;  /* Just a dummy to avoid a lot of branches in the code */
   1895   int   numOutChannels, numInChannels;
   1896   int   inStride, outStride, offset;
   1897   int   dmxMaxScale, dmxScale;
   1898   int   ch, slot;
   1899   UCHAR inOffsetTable[PCM_DMX_MAX_CHANNELS];
   1900 
   1901   DMX_BS_META_DATA  bsMetaData;
   1902 
   1903   if ( (self           == NULL)
   1904     || (nChannels      == NULL)
   1905     || (channelType    == NULL)
   1906     || (channelIndices == NULL)
   1907     || (channelMapping == NULL) ) {
   1908     return (PCMDMX_INVALID_HANDLE);
   1909   }
   1910 
   1911   /* Init the output scaling */
   1912   dmxScale = 0;
   1913   if (pDmxOutScale != NULL) {
   1914     /* Avoid final scaling internally and hand it to the outside world. */
   1915     *pDmxOutScale = 0;
   1916     dmxMaxScale = PCMDMX_MAX_HEADROOM;
   1917   } else {
   1918     /* Apply the scaling internally. */
   1919     pDmxOutScale = &devNull;  /* redirect to temporal stack memory */
   1920     dmxMaxScale = 0;
   1921   }
   1922 
   1923   pParam = &self->userParams;
   1924   numInChannels = *nChannels;
   1925 
   1926   /* Perform some input sanity checks */
   1927   if (pPcmBuf == NULL)     { return (PCMDMX_INVALID_ARGUMENT); }
   1928   if (frameSize == 0)      { return (PCMDMX_INVALID_ARGUMENT); }
   1929   if ( (numInChannels == 0)
   1930     || (numInChannels > PCM_DMX_MAX_IN_CHANNELS) )
   1931                            { return (PCMDMX_INVALID_ARGUMENT); }
   1932 
   1933   /* Check on misconfiguration */
   1934   FDK_ASSERT( (pParam->numOutChannelsMax <= 0) \
   1935            || (pParam->numOutChannelsMax >= pParam->numOutChannelsMin));
   1936 
   1937   /* Determine if the module has to do processing */
   1938   if (   (self->applyProcessing == 0)
   1939     &&  ((pParam->numOutChannelsMax <= 0)
   1940       || (pParam->numOutChannelsMax >= numInChannels))
   1941     &&   (pParam->numOutChannelsMin <= numInChannels) ) {
   1942     /* Nothing to do */
   1943     return (errorStatus);
   1944   }
   1945 
   1946   /* Determine the number of output channels */
   1947   if ( (pParam->numOutChannelsMax > 0)
   1948     && (numInChannels > pParam->numOutChannelsMax) ) {
   1949     numOutChannels = pParam->numOutChannelsMax;
   1950   }
   1951   else if (numInChannels < pParam->numOutChannelsMin) {
   1952     numOutChannels = pParam->numOutChannelsMin;
   1953   }
   1954   else {
   1955     numOutChannels = numInChannels;
   1956   }
   1957 
   1958   dualChannelMode = pParam->dualChannelMode;
   1959 
   1960   /* Analyse input channel configuration and get channel offset
   1961    * table that can be accessed with the fixed channel labels. */
   1962   errorStatus = getChannelMode(
   1963                    numInChannels,
   1964                    channelType,
   1965                    channelIndices,
   1966                    inOffsetTable,
   1967                   &inChMode
   1968                  );
   1969   if ( PCMDMX_IS_FATAL_ERROR(errorStatus)
   1970     || (inChMode == CH_MODE_UNDEFINED) ) {
   1971     /* We don't need to restore because the channel
   1972        configuration has not been changed. Just exit. */
   1973     return (PCMDMX_INVALID_CH_CONFIG);
   1974   }
   1975 
   1976   /* Set input stride and offset */
   1977   if (fInterleaved) {
   1978     inStride  = numInChannels;
   1979     offset = 1;                /* Channel specific offset factor */
   1980   } else {
   1981     inStride  = 1;
   1982     offset = frameSize;        /* Channel specific offset factor */
   1983   }
   1984 
   1985   /* Reset downmix meta data if necessary */
   1986   if ( (pParam->expiryFrame > 0)
   1987     && (++self->bsMetaData[0].expiryCount > pParam->expiryFrame) )
   1988   { /* The metadata read from bitstream is too old. */
   1989     PCMDMX_ERROR err = pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
   1990     FDK_ASSERT(err == PCMDMX_OK);
   1991   }
   1992   FDKmemcpy(&bsMetaData, &self->bsMetaData[pParam->frameDelay], sizeof(DMX_BS_META_DATA));
   1993   /* Maintain delay line */
   1994   for (slot = pParam->frameDelay; slot > 0; slot -= 1) {
   1995     FDKmemcpy(&self->bsMetaData[slot], &self->bsMetaData[slot-1], sizeof(DMX_BS_META_DATA));
   1996   }
   1997 
   1998   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
   1999 #ifdef PCM_DOWNMIX_ENABLE
   2000   if ( numInChannels > numOutChannels )
   2001   { /* Apply downmix */
   2002     INT_PCM  *pInPcm[PCM_DMX_MAX_IN_CHANNELS] = { NULL };
   2003     INT_PCM  *pOutPcm[PCM_DMX_MAX_OUT_CHANNELS] = { NULL };
   2004     FIXP_DMX  mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS];
   2005     UCHAR     outOffsetTable[PCM_DMX_MAX_CHANNELS];
   2006     UINT      sample;
   2007     int       chCfg = 0;
   2008     int       bypScale = 0;
   2009 
   2010 #if (PCM_DMX_MAX_IN_CHANNELS >= 7)
   2011     if (numInChannels > SIX_CHANNEL) {
   2012       AUDIO_CHANNEL_TYPE multiPurposeChType[2];
   2013 
   2014       /* Get the type of the multipurpose channels */
   2015       multiPurposeChType[0] = channelType[inOffsetTable[LEFT_MULTIPRPS_CHANNEL]];
   2016       multiPurposeChType[1] = channelType[inOffsetTable[RIGHT_MULTIPRPS_CHANNEL]];
   2017 
   2018       /* Check if the input configuration is one defined in the standard. */
   2019       switch (inChMode) {
   2020       case CH_MODE_5_0_2_1:  /* chCfg 7 || 14 */
   2021         /* Further analyse the input config to distinguish the two CH_MODE_5_0_2_1 configs. */
   2022         if ( (multiPurposeChType[0] == ACT_FRONT_TOP)
   2023           && (multiPurposeChType[1] == ACT_FRONT_TOP) ) {
   2024           chCfg = 14;
   2025         } else {
   2026           chCfg = 7;
   2027         }
   2028         break;
   2029       case CH_MODE_3_0_3_1:  /* chCfg 11 */
   2030         chCfg = 11;
   2031         break;
   2032       case CH_MODE_3_0_4_1:  /* chCfg 12 */
   2033         chCfg = 12;
   2034         break;
   2035       default:
   2036         chCfg = 0;  /* Not a known config */
   2037         break;
   2038       }
   2039     }
   2040 #endif
   2041 
   2042     /* Set this stages output stride and channel mode: */
   2043     outStride = (fInterleaved) ? numOutChannels : 1;
   2044     outChMode = outChModeTable[numOutChannels];
   2045 
   2046     /* Get channel description and channel mapping for the desired output configuration. */
   2047     getChannelDescription(
   2048             outChMode,
   2049             channelMapping,
   2050             channelType,
   2051             channelIndices,
   2052             outOffsetTable
   2053            );
   2054     /* Now there is no way back because we modified the channel configuration! */
   2055 
   2056     /* Create the DMX matrix */
   2057     errorStatus = getMixFactors (
   2058                        (chCfg>0) ? 1 : 0,
   2059                        (chCfg>0) ? (PCM_DMX_CHANNEL_MODE)chCfg : inChMode,
   2060                        outChMode,
   2061                        pParam,
   2062                       &bsMetaData,
   2063                        mixFactors,
   2064                       &dmxScale
   2065                      );
   2066     /* No fatal errors can occur here. The function is designed to always return a valid matrix.
   2067        The error code is used to signal configurations and matrices that are not conform to any standard. */
   2068 
   2069     /* Determine the final scaling */
   2070     bypScale = FDKmin(dmxMaxScale, dmxScale);
   2071     *pDmxOutScale += bypScale;
   2072     dmxScale -= bypScale;
   2073 
   2074     { /* Set channel pointer for input. Remove empty cols. */
   2075       int inCh, outCh, map[PCM_DMX_MAX_CHANNELS];
   2076       ch = 0;
   2077       for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) {
   2078         if (inOffsetTable[inCh] != 255) {
   2079           pInPcm[ch] = &pPcmBuf[inOffsetTable[inCh]*offset];
   2080           map[ch++]  = inCh;
   2081         }
   2082       }
   2083       if (ch != numInChannels) {
   2084 #ifndef __linux__
   2085           ALOGE("b/23876444");
   2086 #endif
   2087           return PCMDMX_INVALID_ARGUMENT;
   2088       }
   2089 
   2090       /* Remove unused cols from factor matrix */
   2091       for (inCh=0; inCh < numInChannels; inCh+=1) {
   2092         if (inCh != map[inCh]) {
   2093           int outCh;
   2094           for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
   2095             mixFactors[outCh][inCh] = mixFactors[outCh][map[inCh]];
   2096           }
   2097         }
   2098       }
   2099 
   2100       /* Set channel pointer for output. Remove empty cols. */
   2101       ch = 0;
   2102       for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) {
   2103         if (outOffsetTable[outCh] != 255) {
   2104           pOutPcm[ch] = &pPcmBuf[outOffsetTable[outCh]*offset];
   2105           map[ch++]  = outCh;
   2106         }
   2107       }
   2108       FDK_ASSERT(ch == numOutChannels);
   2109 
   2110       /* Remove unused rows from factor matrix */
   2111       for (outCh=0; outCh < numOutChannels; outCh+=1) {
   2112         if (outCh != map[outCh]) {
   2113           FDKmemcpy(&mixFactors[outCh], &mixFactors[map[outCh]], PCM_DMX_MAX_CHANNELS*sizeof(FIXP_DMX));
   2114         }
   2115       }
   2116     }
   2117 
   2118     /* Sample processing loop */
   2119     for (sample = 0; sample < frameSize; sample++)
   2120     {
   2121       FIXP_PCM tIn[PCM_DMX_MAX_IN_CHANNELS];
   2122       FIXP_DBL tOut[PCM_DMX_MAX_OUT_CHANNELS] = { (FIXP_DBL)0 };
   2123       int inCh, outCh;
   2124 
   2125       /* Preload all input samples */
   2126       for (inCh=0; inCh < numInChannels; inCh+=1) {
   2127         tIn[inCh] = (FIXP_PCM)*pInPcm[inCh];
   2128         pInPcm[inCh] += inStride;
   2129       }
   2130       /* Apply downmix coefficients to input samples and accumulate for output */
   2131       for (outCh=0; outCh < numOutChannels; outCh+=1) {
   2132         for (inCh=0; inCh < numInChannels; inCh+=1) {
   2133           tOut[outCh] += fMult(tIn[inCh], mixFactors[outCh][inCh]);
   2134         }
   2135         /* Write sample */
   2136 #if (SAMPLE_BITS == DFRACT_BITS)
   2137         *pOutPcm[outCh] = (INT_PCM)SATURATE_LEFT_SHIFT(tOut[outCh], dmxScale, SAMPLE_BITS);
   2138 #else
   2139         *pOutPcm[outCh] = (INT_PCM)SATURATE_RIGHT_SHIFT(tOut[outCh], DFRACT_BITS-SAMPLE_BITS-dmxScale, SAMPLE_BITS);
   2140 #endif
   2141         pOutPcm[outCh] += outStride;
   2142       }
   2143     }
   2144 
   2145     /* Update the number of output channels */
   2146     *nChannels = numOutChannels;
   2147 
   2148   } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
   2149   else
   2150 #endif /* PCM_DOWNMIX_ENABLE */
   2151 #ifdef PCM_CHANNEL_EXTENSION_ENABLE
   2152   if ( numInChannels < numOutChannels )
   2153   { /* Apply rudimentary upmix */
   2154     /* Set up channel pointer */
   2155     UINT     sample;
   2156     UCHAR    outOffsetTable[PCM_DMX_MAX_CHANNELS];
   2157 
   2158     /* FIRST STAGE
   2159          Create a stereo/dual channel signal */
   2160     if (numInChannels == ONE_CHANNEL)
   2161     {
   2162       INT_PCM  *pInPcm[PCM_DMX_MAX_CHANNELS];
   2163       INT_PCM  *pOutLF, *pOutRF;
   2164 
   2165       /* Set this stages output stride and channel mode: */
   2166       outStride = (fInterleaved) ? TWO_CHANNEL : 1;
   2167       outChMode = outChModeTable[TWO_CHANNEL];
   2168 
   2169       /* Get channel description and channel mapping for this
   2170        * stages number of output channels (always STEREO). */
   2171       getChannelDescription(
   2172               outChMode,
   2173               channelMapping,
   2174               channelType,
   2175               channelIndices,
   2176               outOffsetTable
   2177              );
   2178       /* Now there is no way back because we modified the channel configuration! */
   2179 
   2180       /* Set input channel pointer. The first channel is always at index 0. */
   2181       pInPcm[CENTER_FRONT_CHANNEL] = &pPcmBuf[(frameSize-1)*inStride];  /* Considering input mapping could lead to a invalid pointer
   2182                                                                            here if the channel is not declared to be a front channel. */
   2183 
   2184       /* Set output channel pointer (for this stage). */
   2185       pOutLF = &pPcmBuf[outOffsetTable[LEFT_FRONT_CHANNEL]*offset+(frameSize-1)*outStride];
   2186       pOutRF = &pPcmBuf[outOffsetTable[RIGHT_FRONT_CHANNEL]*offset+(frameSize-1)*outStride];
   2187 
   2188       /* 1/0 input: */
   2189       for (sample = 0; sample < frameSize; sample++) {
   2190         /* L' = C;  R' = C; */
   2191         *pOutLF = *pOutRF = *pInPcm[CENTER_FRONT_CHANNEL];
   2192 
   2193         pInPcm[CENTER_FRONT_CHANNEL] -= inStride;
   2194         pOutLF -= outStride; pOutRF -= outStride;
   2195       }
   2196 
   2197       /* Prepare for next stage: */
   2198       inStride = outStride;
   2199       inChMode = outChMode;
   2200       FDKmemcpy(inOffsetTable, outOffsetTable, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
   2201     }
   2202 
   2203 #if (PCM_DMX_MAX_OUT_CHANNELS > 2)
   2204     /* SECOND STAGE
   2205          Extend with zero channels to achieved the desired number of output channels. */
   2206     if (numOutChannels > TWO_CHANNEL)
   2207     {
   2208       INT_PCM *pIn[PCM_DMX_MAX_CHANNELS]  = { NULL };
   2209       INT_PCM *pOut[PCM_DMX_MAX_CHANNELS] = { NULL };
   2210       AUDIO_CHANNEL_TYPE  inChTypes[PCM_DMX_MAX_CHANNELS];
   2211       UCHAR    inChIndices[PCM_DMX_MAX_CHANNELS];
   2212       UCHAR    numChPerGrp[2][PCM_DMX_MAX_CHANNEL_GROUPS];
   2213       int      nContentCh = 0;  /* Number of channels with content */
   2214       int      nEmptyCh = 0;    /* Number of channels with content */
   2215       int      ch, chGrp, isCompatible = 1;
   2216 
   2217       /* Do not change the signalling which is the channel types and indices.
   2218          Just reorder and add channels. So first save the input signalling. */
   2219       FDKmemcpy(inChTypes, channelType, PCM_DMX_MAX_CHANNELS*sizeof(AUDIO_CHANNEL_TYPE));
   2220       FDKmemcpy(inChIndices, channelIndices, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
   2221 
   2222       /* Set this stages output stride and channel mode: */
   2223       outStride = (fInterleaved) ? numOutChannels : 1;
   2224       outChMode = outChModeTable[numOutChannels];
   2225 
   2226       /* Check if input channel config can be easily mapped to the desired output config. */
   2227       for (chGrp = 0; chGrp < PCM_DMX_MAX_CHANNEL_GROUPS; chGrp += 1) {
   2228         numChPerGrp[IN][chGrp] = (inChMode >> (chGrp*4)) & 0xF;
   2229         numChPerGrp[OUT][chGrp] = (outChMode >> (chGrp*4)) & 0xF;
   2230 
   2231         if (numChPerGrp[IN][chGrp] > numChPerGrp[OUT][chGrp]) {
   2232           isCompatible = 0;
   2233           break;
   2234         }
   2235       }
   2236 
   2237       if ( isCompatible ) {
   2238         /* Get new channel description and channel
   2239          * mapping for the desired output channel mode. */
   2240         getChannelDescription(
   2241                 outChMode,
   2242                 channelMapping,
   2243                 channelType,
   2244                 channelIndices,
   2245                 outOffsetTable
   2246                );
   2247         /* If the input config has a back center channel but the output
   2248            config has not, copy it to left and right (if available). */
   2249         if (  (numChPerGrp[IN][CH_GROUP_REAR]%2)
   2250           && !(numChPerGrp[OUT][CH_GROUP_REAR]%2) ) {
   2251           if (numChPerGrp[IN][CH_GROUP_REAR] == 1) {
   2252             inOffsetTable[RIGHT_REAR_CHANNEL] = inOffsetTable[LEFT_REAR_CHANNEL];
   2253           } else if (numChPerGrp[IN][CH_GROUP_REAR] == 3) {
   2254             inOffsetTable[RIGHT_MULTIPRPS_CHANNEL] = inOffsetTable[LEFT_MULTIPRPS_CHANNEL];
   2255           }
   2256         }
   2257       }
   2258       else {
   2259         /* Just copy and extend the original config */
   2260         FDKmemcpy(outOffsetTable, inOffsetTable, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
   2261       }
   2262 
   2263       /* Set I/O channel pointer.
   2264          Note: The following assignment algorithm clears the channel offset tables.
   2265                Thus they can not be used afterwards. */
   2266       for (ch = 0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) {
   2267         if ( (outOffsetTable[ch] < 255)
   2268           && (inOffsetTable[ch] < 255) )
   2269         { /* Set I/O pointer: */
   2270           pIn[nContentCh] = &pPcmBuf[inOffsetTable[ch]*offset+(frameSize-1)*inStride];
   2271           pOut[nContentCh] = &pPcmBuf[outOffsetTable[ch]*offset+(frameSize-1)*outStride];
   2272           /* Update signalling */
   2273           channelType[outOffsetTable[ch]] = inChTypes[inOffsetTable[ch]];
   2274           channelIndices[outOffsetTable[ch]] = inChIndices[inOffsetTable[ch]];
   2275           inOffsetTable[ch] = 255;
   2276           outOffsetTable[ch] = 255;
   2277           nContentCh += 1;
   2278         }
   2279       }
   2280       if ( isCompatible ) {
   2281         /* Assign the remaining input channels.
   2282            This is just a safety appliance. We should never need it. */
   2283         for (ch = 0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) {
   2284           if (inOffsetTable[ch] < 255) {
   2285             int  outCh;
   2286             for (outCh = 0 ; outCh < PCM_DMX_MAX_CHANNELS; outCh += 1) {
   2287               if (outOffsetTable[outCh] < 255) {
   2288                 break;
   2289               }
   2290             }
   2291             /* Set I/O pointer: */
   2292             pIn[nContentCh] = &pPcmBuf[inOffsetTable[ch]*offset+(frameSize-1)*inStride];
   2293             pOut[nContentCh] = &pPcmBuf[outOffsetTable[outCh]*offset+(frameSize-1)*outStride];
   2294             /* Update signalling */
   2295             channelType[outOffsetTable[outCh]] = inChTypes[inOffsetTable[ch]];
   2296             channelIndices[outOffsetTable[outCh]] = inChIndices[inOffsetTable[ch]];
   2297             inOffsetTable[ch] = 255;
   2298             outOffsetTable[outCh] = 255;
   2299             nContentCh += 1;
   2300           }
   2301         }
   2302         /* Set the remaining output channel pointer */
   2303         for (ch = 0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) {
   2304           if (outOffsetTable[ch] < 255) {
   2305             pOut[nContentCh+nEmptyCh] = &pPcmBuf[outOffsetTable[ch]*offset+(frameSize-1)*outStride];
   2306             /* Expand output signalling */
   2307             channelType[outOffsetTable[ch]] = ACT_NONE;
   2308             channelIndices[outOffsetTable[ch]] = nEmptyCh;
   2309             outOffsetTable[ch] = 255;
   2310             nEmptyCh += 1;
   2311           }
   2312         }
   2313       }
   2314       else {
   2315         /* Set the remaining output channel pointer */
   2316         for (ch = nContentCh; ch < numOutChannels; ch+=1) {
   2317           pOut[ch] = &pPcmBuf[ch*offset+(frameSize-1)*outStride];
   2318           /* Expand output signalling */
   2319           channelType[ch] = ACT_NONE;
   2320           channelIndices[ch] = nEmptyCh;
   2321           nEmptyCh += 1;
   2322         }
   2323       }
   2324 
   2325       /* First copy the channels that have signal */
   2326       for (sample = 0; sample < frameSize; sample+=1) {
   2327         INT_PCM tIn[PCM_DMX_MAX_CHANNELS];
   2328         /* Read all channel samples */
   2329         for (ch = 0; ch < nContentCh; ch+=1) {
   2330           tIn[ch] = *pIn[ch];
   2331           pIn[ch] -= inStride;
   2332         }
   2333         /* Write all channel samples */
   2334         for (ch = 0; ch < nContentCh; ch+=1) {
   2335           *pOut[ch] = tIn[ch];
   2336           pOut[ch] -= outStride;
   2337         }
   2338       }
   2339 
   2340       /* Clear all the other channels */
   2341       for (sample = 0; sample < frameSize; sample++) {
   2342         for (ch = nContentCh; ch < numOutChannels; ch+=1) {
   2343           *pOut[ch] = (INT_PCM)0;
   2344           pOut[ch] -= outStride;
   2345         }
   2346       }
   2347     }
   2348 #endif  /* if (PCM_DMX_MAX_OUT_CHANNELS > 2) */
   2349 
   2350     /* update the number of output channels */
   2351     *nChannels = numOutChannels;
   2352   } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
   2353   else
   2354 #endif /* PCM_CHANNEL_EXTENSION_ENABLE */
   2355   if ( numInChannels == numOutChannels )
   2356   {
   2357     /* Don't need to change the channel description here */
   2358 
   2359     switch (numInChannels)
   2360     {
   2361     case 2:
   2362       { /* Set up channel pointer */
   2363         INT_PCM  *pInPcm[PCM_DMX_MAX_CHANNELS];
   2364         INT_PCM  *pOutL, *pOutR;
   2365         FIXP_DMX  flev;
   2366 
   2367         UINT sample;
   2368         int inStride, outStride, offset;
   2369 
   2370         if (fInterleaved) {
   2371           inStride  = numInChannels;
   2372           outStride = 2;  /* fixed !!! (below stereo is donwmixed to mono if required */
   2373           offset = 1; /* Channel specific offset factor */
   2374         } else {
   2375           inStride  = 1;
   2376           outStride = 1;
   2377           offset = frameSize;  /* Channel specific offset factor */
   2378         }
   2379 
   2380         /* Set input channel pointer */
   2381         pInPcm[LEFT_FRONT_CHANNEL]  = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset];
   2382         pInPcm[RIGHT_FRONT_CHANNEL] = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset];
   2383 
   2384         /* Set output channel pointer (same as input) */
   2385         pOutL  =  pInPcm[LEFT_FRONT_CHANNEL];
   2386         pOutR  =  pInPcm[RIGHT_FRONT_CHANNEL];
   2387 
   2388         /* Set downmix levels: */
   2389         flev = FL2FXCONST_DMX(0.70710678f);
   2390         /* 2/0 input: */
   2391         switch (dualChannelMode)
   2392         {
   2393         case CH1_MODE:  /* L' = 0.707 * Ch1;  R' = 0.707 * Ch1 */
   2394           for (sample = 0; sample < frameSize; sample++) {
   2395             *pOutL = *pOutR =
   2396               (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInPcm[LEFT_FRONT_CHANNEL], flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
   2397 
   2398             pInPcm[LEFT_FRONT_CHANNEL] += inStride;
   2399             pOutL += outStride; pOutR += outStride;
   2400           }
   2401           break;
   2402         case CH2_MODE:  /* L' = 0.707 * Ch2;  R' = 0.707 * Ch2 */
   2403           for (sample = 0; sample < frameSize; sample++) {
   2404             *pOutL = *pOutR =
   2405               (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInPcm[RIGHT_FRONT_CHANNEL], flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
   2406 
   2407             pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
   2408             pOutL += outStride; pOutR += outStride;
   2409           }
   2410           break;
   2411         case MIXED_MODE:  /* L' = 0.5*Ch1 + 0.5*Ch2;  R' = 0.5*Ch1 + 0.5*Ch2 */
   2412           for (sample = 0; sample < frameSize; sample++) {
   2413             *pOutL = *pOutR = (*pInPcm[LEFT_FRONT_CHANNEL] >> 1) + (*pInPcm[RIGHT_FRONT_CHANNEL] >> 1);
   2414 
   2415             pInPcm[LEFT_FRONT_CHANNEL] += inStride;  pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
   2416             pOutL += outStride; pOutR += outStride;
   2417           }
   2418           break;
   2419         default:
   2420         case STEREO_MODE:
   2421           /* nothing to do */
   2422           break;
   2423         }
   2424       }
   2425       break;
   2426 
   2427     default:
   2428       /* nothing to do */
   2429       break;
   2430     }
   2431   }
   2432 
   2433   return (errorStatus);
   2434 }
   2435 
   2436 
   2437 /** Close an instance of the PCM downmix module.
   2438  * @param [inout] Pointer to a buffer containing the handle of the instance.
   2439  * @returns Returns an error code.
   2440  **/
   2441 PCMDMX_ERROR pcmDmx_Close (
   2442     HANDLE_PCM_DOWNMIX *pSelf
   2443   )
   2444 {
   2445   if (pSelf == NULL) {
   2446     return (PCMDMX_INVALID_HANDLE);
   2447   }
   2448 
   2449   FreePcmDmxInstance( pSelf );
   2450   *pSelf = NULL;
   2451 
   2452   return (PCMDMX_OK);
   2453 }
   2454 
   2455 
   2456 /** Get library info for this module.
   2457  * @param [out] Pointer to an allocated LIB_INFO structure.
   2458  * @returns Returns an error code.
   2459  */
   2460 PCMDMX_ERROR pcmDmx_GetLibInfo( LIB_INFO *info )
   2461 {
   2462   int i;
   2463 
   2464   if (info == NULL) {
   2465     return PCMDMX_INVALID_ARGUMENT;
   2466   }
   2467 
   2468   /* Search for next free tab */
   2469   for (i = 0; i < FDK_MODULE_LAST; i++) {
   2470     if (info[i].module_id == FDK_NONE) break;
   2471   }
   2472   if (i == FDK_MODULE_LAST) {
   2473     return PCMDMX_UNKNOWN;
   2474   }
   2475 
   2476   /* Add the library info */
   2477   info[i].module_id  = FDK_PCMDMX;
   2478   info[i].version    = LIB_VERSION(PCMDMX_LIB_VL0, PCMDMX_LIB_VL1, PCMDMX_LIB_VL2);
   2479   LIB_VERSION_STRING(info+i);
   2480   info[i].build_date = PCMDMX_LIB_BUILD_DATE;
   2481   info[i].build_time = PCMDMX_LIB_BUILD_TIME;
   2482   info[i].title      = PCMDMX_LIB_TITLE;
   2483 
   2484   /* Set flags */
   2485   info[i].flags = 0
   2486 #ifdef PCM_DOWNMIX_ENABLE
   2487       | CAPF_DMX_BLIND   /* At least blind downmixing is possible */
   2488  #ifdef PCE_METADATA_ENABLE
   2489       | CAPF_DMX_PCE     /* Guided downmix with data from MPEG-2/4 Program Config Elements (PCE). */
   2490   #ifdef ARIB_MIXDOWN_ENABLE
   2491       | CAPF_DMX_ARIB    /* PCE guided downmix with slightly different equations and levels. */
   2492   #endif
   2493  #endif /* PCE_METADATA_ENABLE */
   2494  #ifdef DSE_METADATA_ENABLE
   2495       | CAPF_DMX_DVB     /* Guided downmix with data from DVB ancillary data fields. */
   2496  #endif
   2497 #endif /* PCM_DOWNMIX_ENABLE */
   2498 #ifdef PCM_CHANNEL_EXTENSION_ENABLE
   2499       | CAPF_DMX_CH_EXP  /* Simple upmixing by dublicating channels or adding zero channels. */
   2500 #endif
   2501       ;
   2502 
   2503   /* Add lib info for FDK tools (if not yet done). */
   2504   FDK_toolsGetLibInfo(info);
   2505 
   2506   return PCMDMX_OK;
   2507 }
   2508 
   2509 
   2510 
   2511