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