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