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