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