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