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