PageRenderTime 315ms CodeModel.GetById 60ms app.highlight 194ms RepoModel.GetById 48ms app.codeStats 0ms

/libPCMutils/src/pcmutils_lib.cpp

https://bitbucket.org/cyanogenmod/android_external_aac
C++ | 1281 lines | 827 code | 164 blank | 290 comment | 143 complexity | 9c737a92f02d1b738d0f3ca5a9fdc8e5 MD5 | raw file
   1
   2/* -----------------------------------------------------------------------------------------------------------
   3Software License for The Fraunhofer FDK AAC Codec Library for Android
   4
   5� Copyright  1995 - 2012 Fraunhofer-Gesellschaft zur F�rderung der angewandten Forschung e.V.
   6  All rights reserved.
   7
   8 1.    INTRODUCTION
   9The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
  10the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
  11This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
  12
  13AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
  14audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
  15independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
  16of the MPEG specifications.
  17
  18Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
  19may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
  20individually for the purpose of encoding or decoding bit streams in products that are compliant with
  21the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
  22these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
  23software may already be covered under those patent licenses when it is used for those licensed purposes only.
  24
  25Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
  26are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
  27applications information and documentation.
  28
  292.    COPYRIGHT LICENSE
  30
  31Redistribution and use in source and binary forms, with or without modification, are permitted without
  32payment of copyright license fees provided that you satisfy the following conditions:
  33
  34You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
  35your modifications thereto in source code form.
  36
  37You must retain the complete text of this software license in the documentation and/or other materials
  38provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
  39You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
  40modifications thereto to recipients of copies in binary form.
  41
  42The name of Fraunhofer may not be used to endorse or promote products derived from this library without
  43prior written permission.
  44
  45You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
  46software or your modifications thereto.
  47
  48Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
  49and 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
  533.    NO PATENT LICENSE
  54
  55NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
  56ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
  57respect to this software.
  58
  59You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
  60by appropriate patent licenses.
  61
  624.    DISCLAIMER
  63
  64This 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
  66of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  67CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
  68including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
  69or business interruption, however caused and on any theory of liability, whether in contract, strict
  70liability, or tort (including negligence), arising in any way out of the use of this software, even if
  71advised of the possibility of such damage.
  72
  735.    CONTACT INFORMATION
  74
  75Fraunhofer Institute for Integrated Circuits IIS
  76Attention: Audio and Multimedia Departments - FDK AAC LL
  77Am Wolfsmantel 33
  7891058 Erlangen, Germany
  79
  80www.iis.fraunhofer.de/amm
  81amm-info@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 */
 139typedef 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: */
 176static 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
 188static 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
 235typedef 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: */
 246struct 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 */
 259C_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 **/
 271static
 272PCM_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 **/
 399void 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 **/
 492PCMDMX_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 **/
 523PCMDMX_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 **/
 561PCMDMX_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 **/
 635PCMDMX_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 **/
 715PCMDMX_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 **/
 756PCMDMX_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 **/
1226PCMDMX_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 */
1245PCMDMX_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