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