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 - 2012 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 to interface with the PCM post processing
     88                 module.
     89 
     90 *******************************************************************************/
     91 
     92 #include "pcmutils_lib.h"
     93 
     94 #include "genericStds.h"
     95 #include "fixpoint_math.h"
     96 
     97 /* Decoder library info */
     98 #define PCMDMX_LIB_VL0 2
     99 #define PCMDMX_LIB_VL1 3
    100 #define PCMDMX_LIB_VL2 1
    101 #define PCMDMX_LIB_TITLE "PCM Downmix Lib"
    102 #define PCMDMX_LIB_BUILD_DATE __DATE__
    103 #define PCMDMX_LIB_BUILD_TIME __TIME__
    104 
    105 /* Library settings */
    106 #define PCM_DMX_MAX_DELAY_FRAMES        ( 1 )
    107 #define PCM_DMX_MAX_CHANNELS            ( 8 )
    108 #define PCM_DMX_MAX_CHANNEL_GROUPS      ( 4 )
    109 #define PCM_DMX_MAX_CHANNELS_PER_GROUP  ( 3 )   /* The maximum over all groups */
    110 #define PCMDMX_DFLT_EXPIRY_FRAME        ( 50 )  /* At least 500ms (FL 960 @ 96kHz) */
    111 
    112 /* Fixed and unique channel group indices.
    113  * The last group index has to be smaller than PCM_DMX_MAX_CHANNEL_GROUPS. */
    114 #define CH_GROUP_FRONT ( 0 )
    115 #define CH_GROUP_SIDE  ( 1 )
    116 #define CH_GROUP_REAR  ( 2 )
    117 #define CH_GROUP_LFE   ( 3 )
    118 
    119 /* The ordering of the following fixed channel labels has to be in MPEG-4 style.
    120  * From the center to the back with left and right channel interleaved (starting with left).
    121  * The last channel label index has to be smaller than PCM_DMX_MAX_CHANNELS. */
    122 #define CENTER_FRONT_CHANNEL    ( 0 )     /* C  */
    123 #define LEFT_FRONT_CHANNEL      ( 1 )     /* L  */
    124 #define RIGHT_FRONT_CHANNEL     ( 2 )     /* R  */
    125 #define LEFT_OUTSIDE_CHANNEL    ( 3 )     /* Lo */
    126 #define RIGHT_OUTSIDE_CHANNEL   ( 4 )     /* Ro */
    127 #define LEFT_REAR_CHANNEL       ( 5 )     /* Lr  aka left back channel  */
    128 #define RIGHT_REAR_CHANNEL      ( 6 )     /* Rr  aka right back channel */
    129 #define LOW_FREQUENCY_CHANNEL   ( 7 )     /* Lf */
    130 
    131 /* More constants */
    132 #define ANC_DATA_SYNC_BYTE      ( 0xBC )  /* ancillary data sync byte. */
    133 #define ATTENUATION_FACTOR_1    ( FL2FXCONST_SGL(0.70710678f) )
    134 #define TWO_CHANNEL             ( 2 )
    135 
    136 /* Sanity checks on library setting: */
    137 
    138 /* List of packed channel modes */
    139 typedef enum
    140 { /* CH_MODE_<numFrontCh>_<numOutsideCh>_<numRearCh>_<numLfCh> */
    141   CH_MODE_UNDEFINED = 0x0000,
    142   /* 1 channel */
    143   CH_MODE_1_0_0_0   = 0x0001,   /* chCfg 1 */
    144   /* 2 channels */
    145   CH_MODE_2_0_0_0   = 0x0002,   /* chCfg 2 */
    146   /* 3 channels */
    147   CH_MODE_3_0_0_0   = 0x0003,   /* chCfg 3 */
    148   CH_MODE_2_0_1_0   = 0x0102,
    149   CH_MODE_2_0_0_1   = 0x1002,
    150   /* 4 channels */
    151   CH_MODE_3_0_1_0   = 0x0103,   /* chCfg 4 */
    152   CH_MODE_2_0_2_0   = 0x0202,
    153   CH_MODE_2_0_1_1   = 0x1102,
    154   /* 5 channels */
    155   CH_MODE_3_0_2_0   = 0x0203,   /* chCfg 5 */
    156   CH_MODE_2_0_2_1   = 0x1202,
    157   CH_MODE_3_0_1_1   = 0x1103,
    158   CH_MODE_3_2_0_0   = 0x0023,
    159   /* 6 channels */
    160   CH_MODE_3_0_2_1   = 0x1203,   /* chCfg 6 */
    161   CH_MODE_3_2_1_0   = 0x0123,
    162   /* 7 channels */
    163   CH_MODE_2_2_2_1   = 0x1222,
    164   CH_MODE_3_2_1_1   = 0x1123,
    165   CH_MODE_3_2_2_0   = 0x0223,
    166   /* 8 channels */
    167   CH_MODE_3_2_2_1   = 0x1222,   /* chCfg 7 */
    168   CH_MODE_3_2_1_2   = 0x2123,
    169   CH_MODE_2_2_2_2   = 0x2222
    170 
    171 } PCM_DMX_CHANNEL_MODE;
    172 
    173 
    174 /* These are the channel configurations linked to
    175    the number of output channels give by the user: */
    176 static const PCM_DMX_CHANNEL_MODE outChModeTable[PCM_DMX_MAX_CHANNELS] =
    177 {
    178   CH_MODE_1_0_0_0,  /* 1 channel  */
    179   CH_MODE_2_0_0_0,  /* 2 channels */
    180   CH_MODE_3_0_0_0,  /* 3 channels */
    181   CH_MODE_3_0_1_0,  /* 4 channels */
    182   CH_MODE_3_0_2_0,  /* 5 channels */
    183   CH_MODE_3_0_2_1,  /* 6 channels */
    184   CH_MODE_3_2_2_0,  /* 7 channels */
    185   CH_MODE_3_2_2_1   /* 8 channels */
    186 };
    187 
    188 static const FIXP_SGL dvbDownmixFactors[8] =
    189 {
    190   FL2FXCONST_SGL(1.0f),
    191   FL2FXCONST_SGL(0.841f),
    192   FL2FXCONST_SGL(0.707f),
    193   FL2FXCONST_SGL(0.596f),
    194   FL2FXCONST_SGL(0.500f),
    195   FL2FXCONST_SGL(0.422f),
    196   FL2FXCONST_SGL(0.355f),
    197   FL2FXCONST_SGL(0.0f)
    198 };
    199 
    200 
    201   /* MPEG matrix mixdown:
    202       Set 1:  L' = (1 + 2^-0.5 + A )^-1 * [L + C * 2^-0.5 + A * Ls];
    203               R' = (1 + 2^-0.5 + A )^-1 * [R + C * 2^-0.5 + A * Rs];
    204 
    205       Set 2:  L' = (1 + 2^-0.5 + 2A )^-1 * [L + C * 2^-0.5 - A * (Ls + Rs)];
    206               R' = (1 + 2^-0.5 + 2A )^-1 * [R + C * 2^-0.5 + A * (Ls + Rs)];
    207 
    208       M = (3 + 2A)^-1 * [L + C + R + A*(Ls + Rs)];
    209   */
    210   static const FIXP_SGL mpegMixDownIdx2Coef[4] =
    211   {
    212     FL2FXCONST_SGL(0.70710678f),
    213     FL2FXCONST_SGL(0.5f),
    214     FL2FXCONST_SGL(0.35355339f),
    215     FL2FXCONST_SGL(0.0f)
    216   };
    217 
    218   static const FIXP_SGL mpegMixDownIdx2PreFact[4] =
    219   {
    220     FL2FXCONST_SGL(0.4142135623730950f),
    221     FL2FXCONST_SGL(0.4530818393219728f),
    222     FL2FXCONST_SGL(0.4852813742385703f),
    223     FL2FXCONST_SGL(0.5857864376269050f)
    224   };
    225 
    226   typedef struct
    227   {
    228     USHORT  matrixMixdownIdx;       /*!< MPEG mixdown index extracted from PCE.            */
    229     USHORT  pseudoSurroundEnable;   /*!< Pseudo surround enable flag extracted from PCE.   */
    230     USHORT  mixdownAvailable;       /*!< Will be set to 1 if we found a valid coefficient. */
    231 
    232   } MPEG_MIXDOWN_INFO;
    233 
    234 
    235 typedef struct
    236 {
    237   FIXP_SGL  centerMixLevelValue;    /*!< DVB mixdown level for the center channel extracted from anc data.  */
    238   FIXP_SGL  surroundMixLevelValue;  /*!< DVB mixdown level for back channels extracted from anc data.       */
    239 
    240   UCHAR     mixLevelsAvail;         /*!< Will be set to 1 if we found a valid coefficient.                  */
    241 
    242 } DVB_MIXDOWN_LEVELS;
    243 
    244 
    245 /* Modules main data structure: */
    246 struct PCM_DMX_INSTANCE
    247 {
    248   DVB_MIXDOWN_LEVELS  dvbMixDownLevels[PCM_DMX_MAX_DELAY_FRAMES+1];
    249   MPEG_MIXDOWN_INFO   mpegMixDownInfo[PCM_DMX_MAX_DELAY_FRAMES+1];
    250   DUAL_CHANNEL_MODE dualChannelMode;
    251   UINT expiryFrame;
    252   UINT expiryCount;
    253   SHORT numOutputChannels;
    254   UCHAR applyProcessing;
    255   UCHAR frameDelay;
    256 };
    257 
    258 /* Memory allocation macro */
    259 C_ALLOC_MEM_STATIC(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1)
    260 
    261 
    262 /** Evaluate a given channel configuration and extract a packed channel mode and generate a channel offset table
    263  *  This function is the inverse to the getChannelDescription() routine.
    264  * @param [in] The total number of channels of the given configuration.
    265  * @param [in] Array holding the corresponding channel types for each channel.
    266  * @param [in] Array holding the corresponding channel type indices for each channel.
    267  * @param [out] Array where the buffer offsets for each channel are stored into.
    268  * @returns Returns the packed channel mode.
    269  **/
    270 static
    271 PCM_DMX_CHANNEL_MODE getChannelMode (
    272         const INT                numChannels,                           /* in */
    273         const AUDIO_CHANNEL_TYPE channelType[],                         /* in */
    274         const UCHAR              channelIndices[],                      /* in */
    275         UCHAR                    offsetTable[PCM_DMX_MAX_CHANNELS]      /* out */
    276       )
    277 {
    278   UINT  chMode = CH_MODE_UNDEFINED;
    279   UCHAR chIdx[PCM_DMX_MAX_CHANNEL_GROUPS][PCM_DMX_MAX_CHANNELS_PER_GROUP];
    280   UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS];
    281   int   ch, grpIdx, err = 0;
    282 
    283   FDK_ASSERT(channelType != NULL);
    284   FDK_ASSERT(channelIndices != NULL);
    285   FDK_ASSERT(offsetTable != NULL);
    286 
    287   /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */
    288   FDKmemclear(numChInGrp, PCM_DMX_MAX_CHANNEL_GROUPS*sizeof(UCHAR));
    289   FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
    290   FDKmemset(chIdx, 255, PCM_DMX_MAX_CHANNEL_GROUPS*PCM_DMX_MAX_CHANNELS_PER_GROUP*sizeof(UCHAR));
    291 
    292   /* Categorize channels */
    293   for (ch = 0; ch < numChannels; ch += 1) {
    294     int i = 0, j, chGrpIdx = channelIndices[ch];
    295 
    296     switch (channelType[ch]) {
    297     case ACT_FRONT:
    298     case ACT_FRONT_TOP:
    299       grpIdx = CH_GROUP_FRONT;
    300       break;
    301     case ACT_SIDE:
    302     case ACT_SIDE_TOP:
    303       grpIdx = CH_GROUP_SIDE;
    304       break;
    305     case ACT_BACK:
    306     case ACT_BACK_TOP:
    307       grpIdx = CH_GROUP_REAR;
    308       break;
    309     case ACT_LFE:
    310       grpIdx = CH_GROUP_LFE;
    311       break;
    312     default:
    313       err = -1;
    314       continue;
    315     }
    316 
    317     if (numChInGrp[grpIdx] < PCM_DMX_MAX_CHANNELS_PER_GROUP) {
    318       /* Sort channels by index */
    319       while ( (i < numChInGrp[grpIdx]) && (chGrpIdx > channelIndices[chIdx[grpIdx][i]]) ) {
    320         i += 1;
    321       }
    322       for (j = numChInGrp[grpIdx]; j > i; j -= 1) {
    323         chIdx[grpIdx][j] = chIdx[grpIdx][j-1];
    324       }
    325       chIdx[grpIdx][i] = ch;
    326       numChInGrp[grpIdx] += 1;
    327     }
    328   }
    329 
    330   /* Compose channel offset table */
    331 
    332   /* Non-symmetric channels */
    333   if (numChInGrp[CH_GROUP_FRONT] & 0x1) {
    334     /* Odd number of front channels -> we have a center channel.
    335        In MPEG-4 the center has the index 0. */
    336     offsetTable[CENTER_FRONT_CHANNEL] = chIdx[CH_GROUP_FRONT][0];
    337   }
    338 
    339   for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
    340     int chMapPos, maxChannels = 0;
    341     ch = 0;
    342 
    343     switch (grpIdx) {
    344     case CH_GROUP_FRONT:
    345       chMapPos = LEFT_FRONT_CHANNEL;
    346       maxChannels = 3;
    347       ch = numChInGrp[grpIdx] & 0x1;
    348       break;
    349     case CH_GROUP_SIDE:
    350       chMapPos = LEFT_OUTSIDE_CHANNEL;
    351       maxChannels = 2;
    352       break;
    353     case CH_GROUP_REAR:
    354       chMapPos = LEFT_REAR_CHANNEL;
    355       maxChannels = 2;
    356       break;
    357     case CH_GROUP_LFE:
    358       chMapPos = LOW_FREQUENCY_CHANNEL;
    359       maxChannels = 1;
    360       break;
    361     default:
    362       err = -1;
    363       continue;
    364     }
    365 
    366     for ( ; ch < numChInGrp[grpIdx]; ch += 1) {
    367       if (ch < maxChannels) {
    368         offsetTable[chMapPos] = chIdx[grpIdx][ch];
    369         chMapPos += 1;
    370       } else {
    371         err = -1;
    372       }
    373     }
    374   }
    375 
    376   if (err == 0) {
    377     /* Compose the channel mode */
    378     chMode = (numChInGrp[CH_GROUP_LFE]   & 0xF) << 12
    379            | (numChInGrp[CH_GROUP_REAR]  & 0xF) <<  8
    380            | (numChInGrp[CH_GROUP_SIDE]  & 0xF) <<  4
    381            | (numChInGrp[CH_GROUP_FRONT] & 0xF);
    382   }
    383 
    384   return (PCM_DMX_CHANNEL_MODE)chMode;
    385 }
    386 
    387 
    388 /** Generate a channel offset table and complete channel description for a given (packed) channel mode.
    389  *  This function is the inverse to the getChannelMode() routine.
    390  * @param [in] The total number of channels of the given configuration.
    391  * @param [in] Array containing the channel mapping to be used (From MPEG PCE ordering to whatever is required).
    392  * @param [out] Array where corresponding channel types for each channels are stored into.
    393  * @param [out] Array where corresponding channel type indices for each output channel are stored into.
    394  * @param [out] Array where the buffer offsets for each channel are stored into.
    395  * @returns None.
    396  **/
    397 void getChannelDescription (
    398         const PCM_DMX_CHANNEL_MODE  chMode,                                 /* in */
    399         const UCHAR                 channelMapping[][PCM_DMX_MAX_CHANNELS], /* in */
    400         AUDIO_CHANNEL_TYPE          channelType[],                          /* out */
    401         UCHAR                       channelIndices[],                       /* out */
    402         UCHAR                       offsetTable[PCM_DMX_MAX_CHANNELS]       /* out */
    403       )
    404 {
    405   const UCHAR *pChannelMap;
    406   int   grpIdx, ch = 0, numChannels = 0;
    407   UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS];
    408 
    409   FDK_ASSERT(channelType != NULL);
    410   FDK_ASSERT(channelIndices != NULL);
    411   FDK_ASSERT(channelMapping != NULL);
    412   FDK_ASSERT(offsetTable != NULL);
    413 
    414   /* Init output arrays */
    415   FDKmemclear(channelType,    PCM_DMX_MAX_CHANNELS*sizeof(AUDIO_CHANNEL_TYPE));
    416   FDKmemclear(channelIndices, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
    417   FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
    418 
    419   /* Extract the number of channels per group */
    420   numChInGrp[CH_GROUP_FRONT] =  chMode        & 0xF;
    421   numChInGrp[CH_GROUP_SIDE]  = (chMode >>  4) & 0xF;
    422   numChInGrp[CH_GROUP_REAR]  = (chMode >>  8) & 0xF;
    423   numChInGrp[CH_GROUP_LFE]   = (chMode >> 12) & 0xF;
    424 
    425   /* Summerize to get the total number of channels */
    426   for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
    427     numChannels += numChInGrp[grpIdx];
    428   }
    429 
    430   /* Get the appropriate channel map */
    431   pChannelMap = channelMapping[numChannels-1];
    432 
    433   /* Compose channel offset table */
    434 
    435   /* Non-symmetric channels */
    436   if (numChInGrp[CH_GROUP_FRONT] & 0x1) {
    437     /* Odd number of front channels -> we have a center channel.
    438        In MPEG-4 the center has the index 0. */
    439     offsetTable[CENTER_FRONT_CHANNEL] = pChannelMap[0];
    440     channelType[0] = ACT_FRONT;
    441     ch += 1;
    442   }
    443 
    444   for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
    445     AUDIO_CHANNEL_TYPE type;
    446     int chMapPos, maxChannels = 0;
    447     int chIdx = 0;
    448 
    449     switch (grpIdx) {
    450     case CH_GROUP_FRONT:
    451       type = ACT_FRONT;
    452       chMapPos = LEFT_FRONT_CHANNEL;
    453       maxChannels = 3;
    454       chIdx = numChInGrp[grpIdx] & 0x1;
    455       break;
    456     case CH_GROUP_SIDE:
    457       type = ACT_SIDE;
    458       chMapPos = LEFT_OUTSIDE_CHANNEL;
    459       maxChannels = 2;
    460       break;
    461     case CH_GROUP_REAR:
    462       type = ACT_BACK;
    463       chMapPos = LEFT_REAR_CHANNEL;
    464       maxChannels = 2;
    465       break;
    466     case CH_GROUP_LFE:
    467       type = ACT_LFE;
    468       chMapPos = LOW_FREQUENCY_CHANNEL;
    469       maxChannels = 1;
    470       break;
    471     default:
    472       break;
    473     }
    474 
    475     for ( ; (chIdx < numChInGrp[grpIdx]) && (chIdx < maxChannels); chIdx += 1) {
    476       offsetTable[chMapPos] = pChannelMap[ch];
    477       channelType[ch]    = type;
    478       channelIndices[ch] = chIdx;
    479       chMapPos += 1;
    480       ch += 1;
    481     }
    482   }
    483 }
    484 
    485 
    486 /** Open and initialize an instance of the PCM downmix module
    487  * @param [out] Pointer to a buffer receiving the handle of the new instance.
    488  * @returns Returns an error code.
    489  **/
    490 PCMDMX_ERROR pcmDmx_Open (
    491     HANDLE_PCM_DOWNMIX *pSelf
    492   )
    493 {
    494   HANDLE_PCM_DOWNMIX self;
    495 
    496   if (pSelf == NULL) {
    497     return (PCMDMX_INVALID_HANDLE);
    498   }
    499 
    500   *pSelf = NULL;
    501 
    502   self = (HANDLE_PCM_DOWNMIX) GetPcmDmxInstance( 0 );
    503   if (self == NULL) {
    504     return (PCMDMX_OUT_OF_MEMORY);
    505   }
    506 
    507   /* Reset the full instance */
    508   pcmDmx_Reset( self, PCMDMX_RESET_FULL );
    509 
    510   *pSelf = self;
    511 
    512   return (PCMDMX_OK);
    513 }
    514 
    515 
    516 /** Reset all static values like e.g. mixdown coefficients.
    517  * @param [in] Handle of PCM downmix module instance.
    518  * @param [in] Flags telling which parts of the module shall be reset.
    519  * @returns Returns an error code.
    520  **/
    521 PCMDMX_ERROR pcmDmx_Reset (
    522     HANDLE_PCM_DOWNMIX  self,
    523     UINT                flags
    524   )
    525 {
    526   if (self == NULL) { return (PCMDMX_INVALID_HANDLE); }
    527 
    528   if (flags & PCMDMX_RESET_PARAMS) {
    529     self->dualChannelMode   = STEREO_MODE;
    530     self->numOutputChannels = 0;
    531     self->applyProcessing   = 0;
    532     self->frameDelay        = 0;
    533     self->expiryFrame       = PCMDMX_DFLT_EXPIRY_FRAME;
    534   }
    535 
    536   if (flags & PCMDMX_RESET_BS_DATA) {
    537     int slot;
    538     for (slot = 0; slot <= PCM_DMX_MAX_DELAY_FRAMES; slot += 1) {
    539       self->dvbMixDownLevels[slot].centerMixLevelValue    = dvbDownmixFactors[2]; /* 0.707 */
    540       self->dvbMixDownLevels[slot].surroundMixLevelValue  = dvbDownmixFactors[0]; /* 1.000 */
    541       self->dvbMixDownLevels[slot].mixLevelsAvail = 0;
    542 
    543       self->mpegMixDownInfo[slot].mixdownAvailable = 0;
    544     }
    545     /* Reset expiry counter */
    546     self->expiryCount = 0;
    547   }
    548 
    549   return (PCMDMX_OK);
    550 }
    551 
    552 
    553 /** Set one parameter for one instance of the PCM downmix module.
    554  * @param [in] Handle of PCM downmix module instance.
    555  * @param [in] Parameter to be set.
    556  * @param [in] Parameter value.
    557  * @returns Returns an error code.
    558  **/
    559 PCMDMX_ERROR pcmDmx_SetParam (
    560     HANDLE_PCM_DOWNMIX  self,
    561     PCMDMX_PARAM        param,
    562     UINT                value
    563   )
    564 {
    565   switch (param)
    566   {
    567   case DMX_BS_DATA_EXPIRY_FRAME:
    568     if (self == NULL)
    569       return (PCMDMX_INVALID_HANDLE);
    570     self->expiryFrame = value;
    571     break;
    572 
    573   case DMX_BS_DATA_DELAY:
    574     if (value > PCM_DMX_MAX_DELAY_FRAMES) {
    575       return (PCMDMX_UNABLE_TO_SET_PARAM);
    576     }
    577     if (self == NULL) {
    578       return (PCMDMX_INVALID_HANDLE);
    579     }
    580     self->frameDelay = value;
    581     break;
    582 
    583   case NUMBER_OF_OUTPUT_CHANNELS:
    584     switch ((int)value) {  /* supported output channels */
    585     case -1: case 0: case 1: case 2:
    586     case 6: case 8:
    587       break;
    588     default:
    589       return (PCMDMX_UNABLE_TO_SET_PARAM);
    590     }
    591     if (self == NULL)
    592       return (PCMDMX_INVALID_HANDLE);
    593     if ((int)value > 0) {
    594       self->numOutputChannels = (int)value;
    595       self->applyProcessing = 1;
    596     } else {
    597       self->numOutputChannels = 0;
    598       self->applyProcessing = 0;
    599     }
    600     break;
    601 
    602   case DUAL_CHANNEL_DOWNMIX_MODE:
    603     switch ((DUAL_CHANNEL_MODE)value) {
    604     case STEREO_MODE:
    605     case CH1_MODE:
    606     case CH2_MODE:
    607     case MIXED_MODE:
    608       break;
    609     default:
    610       return (PCMDMX_UNABLE_TO_SET_PARAM);
    611     }
    612     if (self == NULL)
    613       return (PCMDMX_INVALID_HANDLE);
    614     self->dualChannelMode = (DUAL_CHANNEL_MODE)value;
    615     self->applyProcessing = 1;
    616     break;
    617 
    618   default:
    619     return (PCMDMX_UNKNOWN_PARAM);
    620   }
    621 
    622   return (PCMDMX_OK);
    623 }
    624 
    625 
    626 /** Read the ancillary data transported in DSEs of DVB streams with MPEG-4 content
    627  * @param [in] Handle of PCM downmix module instance.
    628  * @param [in] Pointer to ancillary data buffer.
    629  * @param [in] Size of ancillary data.
    630  * @param [in] Flag indicating wheter the DVB ancillary data is from an MPEG-1/2 or an MPEG-4 stream.
    631  * @returns Returns an error code.
    632  **/
    633 PCMDMX_ERROR pcmDmx_ReadDvbAncData (
    634     HANDLE_PCM_DOWNMIX  self,
    635     UCHAR *pAncDataBuf,
    636     UINT   ancDataBytes,
    637     int    isMpeg2
    638   )
    639 {
    640   DVB_MIXDOWN_LEVELS *pDownmixLevels = &self->dvbMixDownLevels[0];
    641 
    642   int   offset = (isMpeg2) ? 2 : 0;
    643   UCHAR ancDataStatus;
    644 
    645   if (self == NULL) { return (PCMDMX_INVALID_HANDLE); }
    646 
    647   /* sanity checks */
    648   if (pAncDataBuf == NULL || ancDataBytes < (UCHAR)(3+offset)) {
    649     return (PCMDMX_CORRUPT_ANC_DATA);
    650   }
    651 
    652   /* check sync word */
    653   if (pAncDataBuf[offset] != ANC_DATA_SYNC_BYTE) {
    654     return (PCMDMX_CORRUPT_ANC_DATA);
    655   }
    656 
    657   offset += 2;
    658   ancDataStatus = pAncDataBuf[offset++];
    659 
    660   if (isMpeg2) {
    661     /* skip advanced_dynamic_range_control */
    662     if (ancDataStatus & 0x80) offset += 3;
    663     /* skip dialog_normalization */
    664     if (ancDataStatus & 0x40) offset += 1;
    665     /* skip reproduction_level */
    666     if (ancDataStatus & 0x20) offset += 1;
    667   }
    668   else {
    669     /* check reserved bits */
    670     if (ancDataStatus & 0xE8) { return (PCMDMX_CORRUPT_ANC_DATA); }
    671   }
    672 
    673   /* downmix_levels_MPEGX */
    674   if (ancDataStatus & 0x10)
    675   {
    676     int   foundNewData = 0;
    677     UCHAR downmixData = pAncDataBuf[offset++];
    678 
    679     if (downmixData & 0x80) {  /* center_mix_level_on */
    680       pDownmixLevels->centerMixLevelValue =
    681         dvbDownmixFactors[(downmixData >> 4) & 0x07];
    682       foundNewData = 1;
    683     } else {
    684       pDownmixLevels->centerMixLevelValue = dvbDownmixFactors[0];
    685       if (downmixData & 0x70) { return (PCMDMX_CORRUPT_ANC_DATA); }
    686     }
    687 
    688     if (downmixData & 0x08) {  /* surround_mix_level_on */
    689       pDownmixLevels->surroundMixLevelValue =
    690         dvbDownmixFactors[downmixData & 0x07];
    691       foundNewData = 1;
    692     } else {
    693       pDownmixLevels->surroundMixLevelValue = dvbDownmixFactors[0];
    694       if (downmixData & 0x07) { return (PCMDMX_CORRUPT_ANC_DATA); }
    695     }
    696 
    697     pDownmixLevels->mixLevelsAvail = foundNewData;
    698   }
    699 
    700   /* Reset expiry counter */
    701   self->expiryCount = 0;
    702 
    703   return (PCMDMX_OK);
    704 }
    705 
    706 /** Set the matrix mixdown information extracted from the PCE of an AAC bitstream.
    707  *  Note: Call only if matrix_mixdown_idx_present is true.
    708  * @param [in] Handle of PCM downmix module instance.
    709  * @param [in] The 2 bit matrix mixdown index extracted from PCE.
    710  * @param [in] The pseudo surround enable flag extracted from PCE.
    711  * @returns Returns an error code.
    712  **/
    713 PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce (
    714     HANDLE_PCM_DOWNMIX  self,
    715     int                 matrixMixdownPresent,
    716     int                 matrixMixdownIdx,
    717     int                 pseudoSurroundEnable
    718   )
    719 {
    720   MPEG_MIXDOWN_INFO *pMpegMixDownInfo;
    721 
    722   if (self == NULL) {
    723     return (PCMDMX_INVALID_HANDLE);
    724   }
    725 
    726   pMpegMixDownInfo = &self->mpegMixDownInfo[0];
    727 
    728   if (matrixMixdownPresent) {
    729     pMpegMixDownInfo->matrixMixdownIdx     = matrixMixdownIdx & 0x03;
    730     pMpegMixDownInfo->pseudoSurroundEnable = pseudoSurroundEnable;
    731   }
    732 
    733   pMpegMixDownInfo->mixdownAvailable = matrixMixdownPresent;
    734   /* Reset expiry counter */
    735   self->expiryCount = 0;
    736 
    737   return (PCMDMX_OK);
    738 }
    739 
    740 
    741 /** Apply down or up mixing.
    742  * @param [in]    Handle of PCM downmix module instance.
    743  * @param [inout] Pointer to time buffer. Depending on interface configuration, the content of pTimeData is ignored,
    744  *                and the internal QMF buffer will be used as input data source. Otherwise, the MPEG Surround processing is
    745  *                applied to the timesignal pTimeData. For both variants, the resulting MPEG Surround signal is written into pTimeData.
    746  * @param [in]    Pointer where the amount of output samples is returned into.
    747  * @param [inout] Pointer where the amount of output channels is returned into.
    748  * @param [in]    Flag which indicates if output time data are writtern interleaved or as subsequent blocks.
    749  * @param [inout] Array where the corresponding channel type for each output audio channel is stored into.
    750  * @param [inout] Array where the corresponding channel type index for each output audio channel is stored into.
    751  * @param [in]    Array containing the output channel mapping to be used (From MPEG PCE ordering to whatever is required).
    752  * @returns Returns an error code.
    753  **/
    754 PCMDMX_ERROR pcmDmx_ApplyFrame (
    755         HANDLE_PCM_DOWNMIX      self,
    756         INT_PCM                *pPcmBuf,
    757         UINT                    frameSize,
    758         INT                    *nChannels,
    759 
    760         int                     fInterleaved,
    761         AUDIO_CHANNEL_TYPE      channelType[],
    762         UCHAR                   channelIndices[],
    763         const UCHAR             channelMapping[][8]
    764   )
    765 {
    766   PCMDMX_ERROR  errorStatus = PCMDMX_OK;
    767   DUAL_CHANNEL_MODE  dualChannelMode;
    768   PCM_DMX_CHANNEL_MODE  inChMode;
    769   int   numOutChannels;
    770   int   numInChannels = *nChannels;
    771   int   slot;
    772   UCHAR inOffsetTable[PCM_DMX_MAX_CHANNELS];
    773 
    774   MPEG_MIXDOWN_INFO   mpegMixDownInfo;
    775   DVB_MIXDOWN_LEVELS  dvbMixDownLevels;
    776 
    777   if (self == NULL) { return (PCMDMX_INVALID_HANDLE); }
    778 
    779   if ( (self->expiryFrame > 0)
    780     && (++self->expiryCount > self->expiryFrame) )
    781   { /* The metadata read from bitstream is too old. */
    782     errorStatus = pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
    783   }
    784 
    785   FDKmemcpy(&mpegMixDownInfo, &self->mpegMixDownInfo[self->frameDelay], sizeof(MPEG_MIXDOWN_INFO));
    786   /* Maintain delay line */
    787   for (slot = self->frameDelay; slot > 0; slot -= 1) {
    788     FDKmemcpy(&self->mpegMixDownInfo[slot], &self->mpegMixDownInfo[slot-1], sizeof(MPEG_MIXDOWN_INFO));
    789   }
    790   FDKmemcpy(&dvbMixDownLevels, &self->dvbMixDownLevels[self->frameDelay], sizeof(DVB_MIXDOWN_LEVELS));
    791   /* Maintain delay line */
    792   for (slot = self->frameDelay; slot > 0; slot -= 1) {
    793     FDKmemcpy(&self->dvbMixDownLevels[slot], &self->dvbMixDownLevels[slot-1], sizeof(DVB_MIXDOWN_LEVELS));
    794   }
    795 
    796   if (self->applyProcessing == 0) { return (errorStatus); }
    797 
    798   if (pPcmBuf == NULL)     { return (PCMDMX_INVALID_ARGUMENT); }
    799   if (frameSize == 0)      { return (PCMDMX_INVALID_ARGUMENT); }
    800   if (numInChannels == 0)  { return (PCMDMX_INVALID_ARGUMENT); }
    801 
    802   if (self->numOutputChannels <= 0) {
    803     numOutChannels = numInChannels;
    804   } else {
    805     numOutChannels = self->numOutputChannels;
    806   }
    807   dualChannelMode = self->dualChannelMode;
    808 
    809   /* Analyse input channel configuration and get channel offset
    810    * table that can be accessed with the fixed channel labels. */
    811   inChMode = getChannelMode(
    812                    numInChannels,
    813                    channelType,
    814                    channelIndices,
    815                    inOffsetTable
    816                  );
    817   if (inChMode == CH_MODE_UNDEFINED) {
    818     /* We don't need to restore because the channel
    819        configuration has not been changed. Just exit. */
    820     return (PCMDMX_INVALID_CH_CONFIG);
    821   }
    822 
    823   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    824   if ( numInChannels > numOutChannels )
    825   { /* Apply downmix */
    826     INT_PCM  *pInCF, *pInLF, *pInRF, *pInLO, *pInRO, *pInLR, *pInRR, *pOutL, *pOutR;
    827     FIXP_SGL  flev, clev, slev;
    828 
    829     UINT   sample;
    830     int    inStride, outStride, offset;
    831     int    useGuidedDownMix = 0;
    832     UCHAR  outOffsetTable[PCM_DMX_MAX_CHANNELS];
    833 
    834     /* Set I/O strides and offsets */
    835     if (fInterleaved) {
    836       inStride  = numInChannels;
    837       outStride = TWO_CHANNEL;   /* The output of STAGE ONE is always STEREO !!!
    838                                     STAGE TWO creates a downmix to mono if required. */
    839       offset = 1;                /* Channel specific offset factor */
    840     } else {
    841       inStride  = 1;
    842       outStride = 1;
    843       offset = frameSize;        /* Channel specific offset factor */
    844     }
    845 
    846     /* Get channel description and channel mapping for this
    847      * stages number of output channels (always STEREO). */
    848     getChannelDescription(
    849             CH_MODE_2_0_0_0,
    850             channelMapping,
    851             channelType,
    852             channelIndices,
    853             outOffsetTable
    854            );
    855     /* Now there is no way back because we modified the channel configuration! */
    856 
    857     /* Set channel pointer for input */
    858     pInCF = &pPcmBuf[inOffsetTable[CENTER_FRONT_CHANNEL]*offset];
    859     pInLF = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset];
    860     pInRF = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset];
    861     pInLO = &pPcmBuf[inOffsetTable[LEFT_OUTSIDE_CHANNEL]*offset];
    862     pInRO = &pPcmBuf[inOffsetTable[RIGHT_OUTSIDE_CHANNEL]*offset];
    863     pInLR = &pPcmBuf[inOffsetTable[LEFT_REAR_CHANNEL]*offset];
    864     pInRR = &pPcmBuf[inOffsetTable[RIGHT_REAR_CHANNEL]*offset];
    865 
    866     /* Set channel pointer for output
    867        Caution: Different channel mapping compared to input */
    868     pOutL = &pPcmBuf[outOffsetTable[LEFT_FRONT_CHANNEL]*offset];    /* LEFT_FRONT_CHANNEL  */
    869     pOutR = &pPcmBuf[outOffsetTable[RIGHT_FRONT_CHANNEL]*offset];   /* RIGHT_FRONT_CHANNEL */
    870 
    871     /* Set downmix levels: */
    872     flev = ATTENUATION_FACTOR_1;    /* 0.707 */
    873     clev = ATTENUATION_FACTOR_1;    /* 0.707 */
    874     slev = ATTENUATION_FACTOR_1;    /* 0.707 */
    875 
    876     if ( dvbMixDownLevels.mixLevelsAvail ) {
    877       clev = dvbMixDownLevels.centerMixLevelValue;
    878       slev = dvbMixDownLevels.surroundMixLevelValue;
    879       useGuidedDownMix = 1;
    880     }
    881 
    882     /* FIRST STAGE:
    883          Always downmix to 2 channel output: */
    884     switch ( inChMode )
    885     {
    886     case CH_MODE_2_0_0_0:
    887     case CH_MODE_2_0_0_1:
    888       /* 2/0 input: */
    889       switch (dualChannelMode)
    890       {
    891       case CH1_MODE:  /* L' = 0.707 * Ch1;  R' = 0.707 * Ch1 */
    892         for (sample = 0; sample < frameSize; sample++) {
    893           *pOutL = *pOutR =
    894             (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInLF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
    895 
    896           pInLF += inStride;
    897           pOutL += outStride; pOutR += outStride;
    898         }
    899         break;
    900 
    901       case CH2_MODE:  /* L' = 0.707 * Ch2;  R' = 0.707 * Ch2 */
    902         for (sample = 0; sample < frameSize; sample++) {
    903           *pOutL = *pOutR =
    904             (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInRF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
    905 
    906           pInRF += inStride;
    907           pOutL += outStride; pOutR += outStride;
    908         }
    909         break;
    910       case MIXED_MODE:  /* L' = 0.5*Ch1 + 0.5*Ch2;  R' = 0.5*Ch1 + 0.5*Ch2 */
    911         for (sample = 0; sample < frameSize; sample++) {
    912           *pOutL = *pOutR = (*pInLF >> 1) + (*pInRF >> 1);
    913 
    914           pInLF += inStride;  pInRF += inStride;
    915           pOutL += outStride; pOutR += outStride;
    916         }
    917         break;
    918       default:
    919       case STEREO_MODE:
    920         /* nothing to do */
    921         break;
    922       }
    923       break;
    924 
    925     case CH_MODE_3_0_0_0:
    926       /* 3/0 input:  L' = L + 0.707*C;  R' = R + 0.707*C; */
    927       for (sample = 0; sample < frameSize; sample++)
    928       {
    929         FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev);
    930 #if (SAMPLE_BITS == 32)
    931         /* left channel */
    932         *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>1)+tCF, 1, SAMPLE_BITS);
    933         /* right channel */
    934         *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>1)+tCF, 1, SAMPLE_BITS);
    935 #else
    936         /* left channel */
    937         *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>1)+tCF, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS);
    938         /* right channel */
    939         *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>1)+tCF, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS);
    940 #endif
    941         pInLF += inStride;  pInRF += inStride;  pInCF  += inStride;
    942         pOutL += outStride; pOutR += outStride;
    943       }
    944       break;
    945 
    946     /* 2/1 input: not supported!
    947     case CH_MODE_2_0_1_0: */
    948 
    949     case CH_MODE_3_0_1_0:
    950       if (useGuidedDownMix) {
    951         /* 3/1 input:  L' = L + clev*C + 0.707*slev*S;  R' = R + clev*C + 0.707*slev*S; */
    952         slev = FX_DBL2FX_SGL(fMult(flev, slev));  /* 0.707*slef */
    953 
    954         for (sample = 0; sample < frameSize; sample++)
    955         {
    956           FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 1;
    957           FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 1;
    958 #if (SAMPLE_BITS == 32)
    959           /* left channel */
    960           *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF+tLR, 2, SAMPLE_BITS);
    961           /* right channel */
    962           *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, 2, SAMPLE_BITS);
    963 #else
    964           /* left channel */
    965           *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF-tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
    966           /* right channel */
    967           *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
    968 #endif
    969           pInLF += inStride;  pInRF += inStride;  pInCF  += inStride;  pInLR  += inStride;
    970           pOutL += outStride; pOutR += outStride;
    971         }
    972       } else {
    973         /* 3/1 input:  L' = L + 0.707*C - 0.707*S;  R' = R + 0.707*C + 0.707*S */
    974         for (sample = 0; sample < frameSize; sample++)
    975         {
    976           FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 1;
    977           FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 1;
    978 #if (SAMPLE_BITS == 32)
    979           /* left channel */
    980           *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF-tLR, 2, SAMPLE_BITS);
    981           /* right channel */
    982           *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, 2, SAMPLE_BITS);
    983 #else
    984           /* left channel */
    985           *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF-tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
    986           /* right channel */
    987           *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
    988 #endif
    989           pInLF += inStride;  pInRF += inStride;  pInCF  += inStride;  pInLR  += inStride;
    990           pOutL += outStride; pOutR += outStride;
    991         }
    992       }
    993       break;
    994 
    995     /* 2/2 input: not supported!
    996     case CH_MODE_2_0_2_0: */
    997 
    998     case CH_MODE_3_0_2_0:   /* 5.0ch input */
    999     case CH_MODE_3_0_2_1:   /* 5.1ch input */
   1000       if (useGuidedDownMix) {
   1001         /* 3/2 input:  L' = L + clev*C + slev*Ls;  R' = R + clev*C + slev*Rs; */
   1002         for (sample = 0; sample < frameSize; sample++)
   1003         {
   1004           FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 1;
   1005           FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 1;
   1006           FIXP_DBL tRR = fMultDiv2((FIXP_PCM)*pInRR, slev) >> 1;
   1007 #if (SAMPLE_BITS == 32)
   1008           /* left channel */
   1009           *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF+tLR, 2, SAMPLE_BITS);
   1010           /* right channel */
   1011           *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tRR, 2, SAMPLE_BITS);
   1012 #else
   1013           /* left channel */
   1014           *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
   1015           /* right channel */
   1016           *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tRR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
   1017 #endif
   1018           pInLF += inStride;  pInRF += inStride;  pInCF  += inStride;  pInLR  += inStride;  pInRR  += inStride;
   1019           pOutL += outStride; pOutR += outStride;
   1020         }
   1021       }
   1022       else if (mpegMixDownInfo.mixdownAvailable) {
   1023         /* 3/2 input: L' = (1.707+A)^-1 * [L+0.707*C+A*Ls]; R'= (1.707+A)^-1 * [R+0.707*C+A*Rs]; */
   1024         FIXP_SGL mtrxMixDwnCoef    = mpegMixDownIdx2Coef[mpegMixDownInfo.matrixMixdownIdx];
   1025         FIXP_SGL mtrxMixDwnPreFact = mpegMixDownIdx2PreFact[mpegMixDownInfo.matrixMixdownIdx];
   1026         clev = FX_DBL2FX_SGL(fMult(mtrxMixDwnPreFact, flev /* 0.707 */));
   1027         flev = mtrxMixDwnPreFact;
   1028         slev = FX_DBL2FX_SGL(fMult(mtrxMixDwnPreFact, mtrxMixDwnCoef));
   1029 
   1030         for (sample = 0; sample < frameSize; sample++)
   1031         {
   1032           FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev);
   1033           FIXP_DBL tLF = fMultDiv2((FIXP_PCM)*pInLF, flev);
   1034           FIXP_DBL tRF = fMultDiv2((FIXP_PCM)*pInRF, flev);
   1035           FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev);
   1036           FIXP_DBL tRR = fMultDiv2((FIXP_PCM)*pInRR, slev);
   1037 
   1038 #if (SAMPLE_BITS == 32)
   1039           /* left channel */
   1040           *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT(tLF+tCF+tLR, 1, SAMPLE_BITS);
   1041           /* right channel */
   1042           *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT(tRF+tCF+tRR, 1, SAMPLE_BITS);
   1043 #else
   1044           /* left channel */
   1045           *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT(tLF+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS);
   1046           /* right channel */
   1047           *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT(tRF+tCF+tRR, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS);
   1048 #endif
   1049 
   1050           pInLF += inStride;  pInRF += inStride;  pInCF  += inStride;  pInLR  += inStride;  pInRR  += inStride;
   1051           pOutL += outStride; pOutR += outStride;
   1052         }
   1053       }
   1054       else {
   1055         /* 3/2 input:  L' = L + 0.707*C - 0.707*Ls - 0.707*Rs;  R' = R + 0.707*C + 0.707*Ls + 0.707*Rs */
   1056         for (sample = 0; sample < frameSize; sample++)
   1057         {
   1058           FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 2;
   1059           FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 2;
   1060           FIXP_DBL tRR = fMultDiv2((FIXP_PCM)*pInRR, slev) >> 2;
   1061 #if (SAMPLE_BITS == 32)
   1062           /* left channel */
   1063           *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>3)+tCF-tLR-tRR, 3, SAMPLE_BITS);
   1064           /* right channel */
   1065           *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>3)+tCF+tLR+tRR, 3, SAMPLE_BITS);
   1066 #else
   1067           /* left channel */
   1068           *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>3)+tCF-tLR-tRR, DFRACT_BITS-SAMPLE_BITS-3, SAMPLE_BITS);
   1069           /* right channel */
   1070           *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>3)+tCF+tLR+tRR, DFRACT_BITS-SAMPLE_BITS-3, SAMPLE_BITS);
   1071 #endif
   1072           pInLF += inStride;  pInRF += inStride;  pInCF  += inStride;  pInLR  += inStride;  pInRR  += inStride;
   1073           pOutL += outStride; pOutR += outStride;
   1074         }
   1075       }
   1076       break;
   1077 
   1078     default:
   1079       errorStatus = PCMDMX_INVALID_MODE;
   1080       break;
   1081     }
   1082 
   1083     /* SECOND STAGE:
   1084          If desired create a mono donwmix:
   1085          Note: Input are always two channels! */
   1086     if (numOutChannels == 1)
   1087     {
   1088       INT_PCM *pOutC;
   1089       FIXP_SGL mlev;
   1090 
   1091       if (useGuidedDownMix) mlev = FL2FXCONST_SGL(1.0f); else mlev = flev;
   1092 
   1093       /* Output of STAGE ONE = Input of STAGE TWO */
   1094       FDKmemcpy(inOffsetTable, outOffsetTable, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
   1095 
   1096       /* Set I/O strides and offsets */
   1097       inStride  = outStride;          /* output from STAGE ONE */
   1098       outStride = numOutChannels;     /* final output */
   1099 
   1100       /* Get channel description and channel mapping for this
   1101        * stages number of output channels (always MONO). */
   1102       getChannelDescription(
   1103               CH_MODE_1_0_0_0,
   1104               channelMapping,
   1105               channelType,
   1106               channelIndices,
   1107               outOffsetTable
   1108              );
   1109 
   1110       /* Set input channel pointer. */
   1111       pInLF = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset];
   1112       pInRF = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset];
   1113 
   1114       /* Set output channel pointer */
   1115       pOutC = &pPcmBuf[outOffsetTable[CENTER_FRONT_CHANNEL]*offset];
   1116 
   1117       /* C' = 0.707*L + 0.707*R */
   1118       for (sample = 0; sample < frameSize; sample++) {
   1119 #if (SAMPLE_BITS == 32)
   1120         *pOutC =
   1121           (INT_PCM)SATURATE_LEFT_SHIFT(fMultDiv2((FIXP_PCM)*pInLF,mlev)+fMultDiv2((FIXP_PCM)*pInRF,mlev), 1, SAMPLE_BITS);
   1122 #else
   1123         *pOutC =
   1124           (INT_PCM)SATURATE_RIGHT_SHIFT(fMultDiv2((FIXP_PCM)*pInLF,mlev)+fMultDiv2((FIXP_PCM)*pInRF,mlev), DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS);
   1125 #endif
   1126 
   1127         pInLF += inStride; pInRF += inStride;
   1128         pOutC += 1;
   1129       }
   1130       /* Finished STAGE TWO */
   1131     }
   1132 
   1133     /* Update the number of output channels */
   1134     *nChannels = self->numOutputChannels;
   1135 
   1136   } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
   1137   else
   1138   if ( numInChannels == numOutChannels )
   1139   {
   1140     /* Don't need to change the channel description here */
   1141 
   1142     switch (numInChannels)
   1143     {
   1144     case 2:
   1145       { /* Set up channel pointer */
   1146         INT_PCM *pInLF, *pInRF, *pOutL, *pOutR;
   1147         FIXP_SGL flev;
   1148 
   1149         UINT sample;
   1150         int inStride, outStride, offset;
   1151 
   1152         if (fInterleaved) {
   1153           inStride  = numInChannels;
   1154           outStride = 2;  /* fixed !!! (below stereo is donwmixed to mono if required */
   1155           offset = 1; /* Channel specific offset factor */
   1156         } else {
   1157           inStride  = 1;
   1158           outStride = 1;
   1159           offset = frameSize;  /* Channel specific offset factor */
   1160         }
   1161 
   1162         /* Set input channel pointer */
   1163         pInLF = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset];
   1164         pInRF = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset];
   1165 
   1166         /* Set output channel pointer (same as input) */
   1167         pOutL  =  pInLF;
   1168         pOutR  =  pInRF;
   1169 
   1170         /* Set downmix levels: */
   1171         flev = ATTENUATION_FACTOR_1;    /* 0.707 */
   1172         /* 2/0 input: */
   1173         switch (dualChannelMode)
   1174         {
   1175         case CH1_MODE:  /* L' = 0.707 * Ch1;  R' = 0.707 * Ch1 */
   1176           for (sample = 0; sample < frameSize; sample++) {
   1177             *pOutL = *pOutR =
   1178               (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInLF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
   1179 
   1180             pInLF += inStride;
   1181             pOutL += outStride; pOutR += outStride;
   1182           }
   1183           break;
   1184         case CH2_MODE:  /* L' = 0.707 * Ch2;  R' = 0.707 * Ch2 */
   1185           for (sample = 0; sample < frameSize; sample++) {
   1186             *pOutL = *pOutR =
   1187               (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInRF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
   1188 
   1189             pInRF += inStride;
   1190             pOutL += outStride; pOutR += outStride;
   1191           }
   1192           break;
   1193         case MIXED_MODE:  /* L' = 0.5*Ch1 + 0.5*Ch2;  R' = 0.5*Ch1 + 0.5*Ch2 */
   1194           for (sample = 0; sample < frameSize; sample++) {
   1195             *pOutL = *pOutR = (*pInLF >> 1) + (*pInRF >> 1);
   1196 
   1197             pInLF += inStride;  pInRF += inStride;
   1198             pOutL += outStride; pOutR += outStride;
   1199           }
   1200           break;
   1201         default:
   1202         case STEREO_MODE:
   1203           /* nothing to do */
   1204           break;
   1205         }
   1206       }
   1207       break;
   1208 
   1209     default:
   1210       /* nothing to do */
   1211       break;
   1212     }
   1213   }
   1214 
   1215   return (errorStatus);
   1216 }
   1217 
   1218 
   1219 /** Close an instance of the PCM downmix module.
   1220  * @param [inout] Pointer to a buffer containing the handle of the instance.
   1221  * @returns Returns an error code.
   1222  **/
   1223 PCMDMX_ERROR pcmDmx_Close (
   1224     HANDLE_PCM_DOWNMIX *pSelf
   1225   )
   1226 {
   1227   if (pSelf == NULL) {
   1228     return (PCMDMX_INVALID_HANDLE);
   1229   }
   1230 
   1231   FreePcmDmxInstance( pSelf );
   1232   *pSelf = NULL;
   1233 
   1234   return (PCMDMX_OK);
   1235 }
   1236 
   1237 
   1238 /** Get library info for this module.
   1239  * @param [out] Pointer to an allocated LIB_INFO structure.
   1240  * @returns Returns an error code.
   1241  */
   1242 PCMDMX_ERROR pcmDmx_GetLibInfo( LIB_INFO *info )
   1243 {
   1244   int i;
   1245 
   1246   if (info == NULL) {
   1247     return PCMDMX_INVALID_ARGUMENT;
   1248   }
   1249 
   1250   /* Search for next free tab */
   1251   for (i = 0; i < FDK_MODULE_LAST; i++) {
   1252     if (info[i].module_id == FDK_NONE) break;
   1253   }
   1254   if (i == FDK_MODULE_LAST) {
   1255     return PCMDMX_UNKNOWN;
   1256   }
   1257   info += i;
   1258 
   1259   /* Add the library info */
   1260   info->module_id  = FDK_PCMDMX;
   1261   info->version    = LIB_VERSION(PCMDMX_LIB_VL0, PCMDMX_LIB_VL1, PCMDMX_LIB_VL2);
   1262   LIB_VERSION_STRING(info);
   1263   info->build_date = PCMDMX_LIB_BUILD_DATE;
   1264   info->build_time = PCMDMX_LIB_BUILD_TIME;
   1265   info->title      = PCMDMX_LIB_TITLE;
   1266 
   1267   /* Set flags */
   1268   info->flags = 0
   1269       | CAPF_DMX_BLIND   /* At least blind downmixing is possible */
   1270       | CAPF_DMX_PCE     /* Guided downmix with data from MPEG-2/4 Program Config Elements (PCE). */
   1271       | CAPF_DMX_DVB     /* Guided downmix with data from DVB ancillary data fields. */
   1272       ;
   1273 
   1274   return PCMDMX_OK;
   1275 }
   1276 
   1277 
   1278 
   1279