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