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