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