1 /* -----------------------------------------------------------------------------
2 Software License for The Fraunhofer FDK AAC Codec Library for Android
3
4 © Copyright 1995 - 2018 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
getIdxSum(UCHAR numCh)497 static inline UINT getIdxSum(UCHAR numCh) {
498 UINT result = 0;
499 int i;
500 for (i = 1; i < numCh; i += 1) {
501 result += i;
502 }
503 return result;
504 }
505
506 /** Evaluate a given channel configuration and extract a packed channel mode. In
507 *addition the function generates a channel offset table for the mapping to the
508 *internal representation. This function is the inverse to the
509 *getChannelDescription() routine.
510 * @param [in] The total number of channels of the given configuration.
511 * @param [in] Array holding the corresponding channel types for each channel.
512 * @param [in] Array holding the corresponding channel type indices for each
513 *channel.
514 * @param [out] Array where the buffer offsets for each channel are stored into.
515 * @param [out] The generated packed channel mode that represents the given
516 *input configuration.
517 * @returns Returns an error code.
518 **/
getChannelMode(const UINT numChannels,const AUDIO_CHANNEL_TYPE channelType[],UCHAR channelIndices[],UCHAR offsetTable[(8)],PCM_DMX_CHANNEL_MODE * chMode)519 static PCMDMX_ERROR getChannelMode(
520 const UINT numChannels, /* in */
521 const AUDIO_CHANNEL_TYPE channelType[], /* in */
522 UCHAR channelIndices[], /* in */
523 UCHAR offsetTable[(8)], /* out */
524 PCM_DMX_CHANNEL_MODE *chMode /* out */
525 ) {
526 UINT idxSum[(3)][(4)];
527 UCHAR numCh[(3)][(4)];
528 UCHAR mapped[(8)];
529 PCM_DMX_SPEAKER_POSITION spkrPos[(8)];
530 PCMDMX_ERROR err = PCMDMX_OK;
531 unsigned ch, numMappedInChs = 0;
532 unsigned startSlot;
533 unsigned stopSlot = LOW_FREQUENCY_CHANNEL;
534
535 FDK_ASSERT(channelType != NULL);
536 FDK_ASSERT(channelIndices != NULL);
537 FDK_ASSERT(offsetTable != NULL);
538 FDK_ASSERT(chMode != NULL);
539
540 /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */
541 FDKmemclear(idxSum, (3) * (4) * sizeof(UINT));
542 FDKmemclear(numCh, (3) * (4) * sizeof(UCHAR));
543 FDKmemclear(mapped, (8) * sizeof(UCHAR));
544 FDKmemclear(spkrPos, (8) * sizeof(PCM_DMX_SPEAKER_POSITION));
545 /* Init output */
546 FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
547 *chMode = CH_MODE_UNDEFINED;
548
549 /* Determine how many channels are assigned to each channels each group: */
550 for (ch = 0; ch < numChannels; ch += 1) {
551 unsigned chGrp = fMax(
552 (channelType[ch] & 0x0F) - 1,
553 0); /* Assign all undefined channels (ACT_NONE) to front channels. */
554 numCh[channelType[ch] >> 4][chGrp] += 1;
555 idxSum[channelType[ch] >> 4][chGrp] += channelIndices[ch];
556 }
557 if (numChannels > TWO_CHANNEL) {
558 int chGrp;
559 /* Sanity check on the indices */
560 for (chGrp = 0; chGrp < (4); chGrp += 1) {
561 int plane;
562 for (plane = 0; plane < (3); plane += 1) {
563 if (idxSum[plane][chGrp] != getIdxSum(numCh[plane][chGrp])) {
564 unsigned idxCnt = 0;
565 for (ch = 0; ch < numChannels; ch += 1) {
566 if (channelType[ch] ==
567 (AUDIO_CHANNEL_TYPE)((plane << 4) | ((chGrp + 1) & 0xF))) {
568 channelIndices[ch] = idxCnt++;
569 }
570 }
571 err = PCMDMX_INVALID_CH_CONFIG;
572 }
573 }
574 }
575 }
576 /* Mapping HEAT 1:
577 * Determine the speaker position of each input channel and map it to a
578 * internal slot if it matches exactly (with zero distance). */
579 for (ch = 0; ch < numChannels; ch += 1) {
580 UINT mapDist = (unsigned)-1;
581 unsigned mapCh, mapPos = (unsigned)-1;
582 unsigned chGrp = fMax(
583 (channelType[ch] & 0x0F) - 1,
584 0); /* Assign all undefined channels (ACT_NONE) to front channels. */
585
586 spkrPos[ch] = getSpeakerPos(channelType[ch], channelIndices[ch],
587 numCh[channelType[ch] >> 4][chGrp]);
588
589 for (mapCh = 0; mapCh <= stopSlot; mapCh += 1) {
590 if (offsetTable[mapCh] == 255) {
591 UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
592 if (dist < mapDist) {
593 mapPos = mapCh;
594 mapDist = dist;
595 }
596 }
597 }
598 if (mapDist <= PCMDMX_THRESHOLD_MAP_HEAT_1) {
599 offsetTable[mapPos] = (UCHAR)ch;
600 mapped[ch] = 1;
601 numMappedInChs += 1;
602 }
603 }
604
605 /* Mapping HEAT 2:
606 * Go through the unmapped input channels and assign them to the internal
607 * slots that matches best (least distance). But assign center channels to
608 * center slots only. */
609 startSlot =
610 ((numCh[CH_PLAIN_NORMAL][CH_GROUP_FRONT] & 0x1) || (numChannels >= (8)))
611 ? 0
612 : 1;
613 for (ch = 0; ch < (unsigned)numChannels; ch += 1) {
614 if (!mapped[ch]) {
615 UINT mapDist = (unsigned)-1;
616 unsigned mapCh, mapPos = (unsigned)-1;
617
618 for (mapCh = startSlot; mapCh <= stopSlot; mapCh += 1) {
619 if (offsetTable[mapCh] == 255) {
620 UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
621 if (dist < mapDist) {
622 mapPos = mapCh;
623 mapDist = dist;
624 }
625 }
626 }
627 if ((mapPos <= stopSlot) && (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_2) &&
628 (((spkrPos[ch].x != 0) && (spkrSlotPos[mapPos].x != 0)) /* XOR */
629 || ((spkrPos[ch].x == 0) &&
630 (spkrSlotPos[mapPos].x ==
631 0)))) { /* Assign center channels to center slots only. */
632 offsetTable[mapPos] = (UCHAR)ch;
633 mapped[ch] = 1;
634 numMappedInChs += 1;
635 }
636 }
637 }
638
639 /* Mapping HEAT 3:
640 * Assign the rest by searching for the nearest input channel for each
641 * internal slot. */
642 for (ch = startSlot; (ch < (8)) && (numMappedInChs < numChannels); ch += 1) {
643 if (offsetTable[ch] == 255) {
644 UINT mapDist = (unsigned)-1;
645 unsigned mapCh, mapPos = (unsigned)-1;
646
647 for (mapCh = 0; mapCh < (unsigned)numChannels; mapCh += 1) {
648 if (!mapped[mapCh]) {
649 UINT dist = getSpeakerDistance(spkrPos[mapCh], spkrSlotPos[ch]);
650 if (dist < mapDist) {
651 mapPos = mapCh;
652 mapDist = dist;
653 }
654 }
655 }
656 if (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_3) {
657 offsetTable[ch] = (UCHAR)mapPos;
658 mapped[mapPos] = 1;
659 numMappedInChs += 1;
660 if ((spkrPos[mapPos].x == 0) && (spkrSlotPos[ch].x != 0) &&
661 (numChannels <
662 (8))) { /* Skip the paired slot if we assigned a center channel. */
663 ch += 1;
664 }
665 }
666 }
667 }
668
669 /* Finaly compose the channel mode */
670 for (ch = 0; ch < (4); ch += 1) {
671 int plane, numChInGrp = 0;
672 for (plane = 0; plane < (3); plane += 1) {
673 numChInGrp += numCh[plane][ch];
674 }
675 *chMode = (PCM_DMX_CHANNEL_MODE)(*chMode | (numChInGrp << (ch * 4)));
676 }
677
678 return err;
679 }
680
681 /** Generate a channel offset table and complete channel description for a given
682 *(packed) channel mode. This function is the inverse to the getChannelMode()
683 *routine but does not support weird channel configurations.
684 * @param [in] The packed channel mode of the configuration to be processed.
685 * @param [in] Array containing the channel mapping to be used (From MPEG PCE
686 *ordering to whatever is required).
687 * @param [out] Array where corresponding channel types for each channels are
688 *stored into.
689 * @param [out] Array where corresponding channel type indices for each output
690 *channel are stored into.
691 * @param [out] Array where the buffer offsets for each channel are stored into.
692 * @returns None.
693 **/
getChannelDescription(const PCM_DMX_CHANNEL_MODE chMode,const FDK_channelMapDescr * const mapDescr,AUDIO_CHANNEL_TYPE channelType[],UCHAR channelIndices[],UCHAR offsetTable[(8)])694 static void getChannelDescription(
695 const PCM_DMX_CHANNEL_MODE chMode, /* in */
696 const FDK_channelMapDescr *const mapDescr, /* in */
697 AUDIO_CHANNEL_TYPE channelType[], /* out */
698 UCHAR channelIndices[], /* out */
699 UCHAR offsetTable[(8)] /* out */
700 ) {
701 int grpIdx, plainIdx, numPlains = 1, numTotalChannels = 0;
702 int chCfg, ch = 0;
703
704 FDK_ASSERT(channelType != NULL);
705 FDK_ASSERT(channelIndices != NULL);
706 FDK_ASSERT(mapDescr != NULL);
707 FDK_ASSERT(offsetTable != NULL);
708
709 /* Init output arrays */
710 FDKmemclear(channelType, (8) * sizeof(AUDIO_CHANNEL_TYPE));
711 FDKmemclear(channelIndices, (8) * sizeof(UCHAR));
712 FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
713
714 /* Summerize to get the total number of channels */
715 for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
716 numTotalChannels += (chMode >> (grpIdx * 4)) & 0xF;
717 }
718
719 /* Get the appropriate channel map */
720 switch (chMode) {
721 case CH_MODE_1_0_0_0:
722 case CH_MODE_2_0_0_0:
723 case CH_MODE_3_0_0_0:
724 case CH_MODE_3_0_1_0:
725 case CH_MODE_3_0_2_0:
726 case CH_MODE_3_0_2_1:
727 chCfg = numTotalChannels;
728 break;
729 case CH_MODE_3_0_3_1:
730 chCfg = 11;
731 break;
732 case CH_MODE_3_0_4_1:
733 chCfg = 12;
734 break;
735 case CH_MODE_5_0_2_1:
736 chCfg = 7;
737 break;
738 default:
739 /* fallback */
740 chCfg = 0;
741 break;
742 }
743
744 /* Compose channel offset table */
745
746 for (plainIdx = 0; plainIdx < numPlains; plainIdx += 1) {
747 PCM_DMX_CHANNEL_MODE plainChMode;
748 UCHAR numChInGrp[(4)];
749
750 plainChMode = getChMode4Plain(plainIdx, chMode, chCfg);
751
752 /* Extract the number of channels per group */
753 numChInGrp[CH_GROUP_FRONT] = plainChMode & 0xF;
754 numChInGrp[CH_GROUP_SIDE] = (plainChMode >> 4) & 0xF;
755 numChInGrp[CH_GROUP_REAR] = (plainChMode >> 8) & 0xF;
756 numChInGrp[CH_GROUP_LFE] = (plainChMode >> 12) & 0xF;
757
758 /* Non-symmetric channels */
759 if ((numChInGrp[CH_GROUP_FRONT] & 0x1) && (plainIdx == CH_PLAIN_NORMAL)) {
760 /* Odd number of front channels -> we have a center channel.
761 In MPEG-4 the center has the index 0. */
762 int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
763 offsetTable[CENTER_FRONT_CHANNEL] = (UCHAR)mappedIdx;
764 channelType[mappedIdx] = ACT_FRONT;
765 channelIndices[mappedIdx] = 0;
766 ch += 1;
767 }
768
769 for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
770 AUDIO_CHANNEL_TYPE type = ACT_NONE;
771 int chMapPos = 0, maxChannels = 0;
772 int chIdx = 0; /* Index of channel within the specific group */
773
774 switch (grpIdx) {
775 case CH_GROUP_FRONT:
776 type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_FRONT);
777 switch (plainIdx) {
778 default:
779 chMapPos = LEFT_FRONT_CHANNEL;
780 chIdx = numChInGrp[grpIdx] & 0x1;
781 break;
782 }
783 maxChannels = 3;
784 break;
785 case CH_GROUP_SIDE:
786 /* Always map side channels to the multipurpose group. */
787 type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_SIDE);
788 if (plainIdx == CH_PLAIN_TOP) {
789 chMapPos = LEFT_SIDE_CHANNEL_TOP;
790 maxChannels = 3;
791 } else {
792 chMapPos = LEFT_MULTIPRPS_CHANNEL;
793 maxChannels = 2;
794 }
795 break;
796 case CH_GROUP_REAR:
797 type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_BACK);
798 if (plainIdx == CH_PLAIN_TOP) {
799 chMapPos = LEFT_REAR_CHANNEL_TOP;
800 maxChannels = 3;
801 } else {
802 chMapPos = LEFT_REAR_CHANNEL;
803 maxChannels = 2;
804 }
805 break;
806 case CH_GROUP_LFE:
807 if (plainIdx == CH_PLAIN_NORMAL) {
808 type = ACT_LFE;
809 chMapPos = LOW_FREQUENCY_CHANNEL;
810 maxChannels = 1;
811 }
812 break;
813 default:
814 break;
815 }
816
817 /* Map all channels in this group */
818 for (; chIdx < numChInGrp[grpIdx]; chIdx += 1) {
819 int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
820 if ((chIdx == maxChannels) || (offsetTable[chMapPos] < 255)) {
821 /* No space left in this channel group! */
822 if (offsetTable[LEFT_MULTIPRPS_CHANNEL] ==
823 255) { /* Use the multipurpose group: */
824 chMapPos = LEFT_MULTIPRPS_CHANNEL;
825 } else {
826 FDK_ASSERT(0);
827 }
828 }
829 offsetTable[chMapPos] = (UCHAR)mappedIdx;
830 channelType[mappedIdx] = type;
831 channelIndices[mappedIdx] = (UCHAR)chIdx;
832 chMapPos += 1;
833 ch += 1;
834 }
835 }
836 }
837 }
838
839 /** Private helper function for downmix matrix manipulation that initializes
840 * one row in a given downmix matrix (corresponding to one output channel).
841 * @param [inout] Pointer to fixed-point parts of the downmix matrix.
842 * @param [inout] Pointer to scale factor matrix associated to the downmix
843 *factors.
844 * @param [in] Index of channel (row) to be initialized.
845 * @returns Nothing to return.
846 **/
dmxInitChannel(FIXP_DMX mixFactors[(8)][(8)],INT mixScales[(8)][(8)],const unsigned int outCh)847 static void dmxInitChannel(FIXP_DMX mixFactors[(8)][(8)],
848 INT mixScales[(8)][(8)], const unsigned int outCh) {
849 unsigned int inCh;
850 for (inCh = 0; inCh < (8); inCh += 1) {
851 if (inCh == outCh) {
852 mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.5f);
853 mixScales[outCh][inCh] = 1;
854 } else {
855 mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.0f);
856 mixScales[outCh][inCh] = 0;
857 }
858 }
859 }
860
861 /** Private helper function for downmix matrix manipulation that does a reset
862 * of one row in a given downmix matrix (corresponding to one output channel).
863 * @param [inout] Pointer to fixed-point parts of the downmix matrix.
864 * @param [inout] Pointer to scale factor matrix associated to the downmix
865 *factors.
866 * @param [in] Index of channel (row) to be cleared/reset.
867 * @returns Nothing to return.
868 **/
dmxClearChannel(FIXP_DMX mixFactors[(8)][(8)],INT mixScales[(8)][(8)],const unsigned int outCh)869 static void dmxClearChannel(FIXP_DMX mixFactors[(8)][(8)],
870 INT mixScales[(8)][(8)], const unsigned int outCh) {
871 FDK_ASSERT((outCh >= 0) && (outCh < (8)));
872 FDKmemclear(&mixFactors[outCh], (8) * sizeof(FIXP_DMX));
873 FDKmemclear(&mixScales[outCh], (8) * sizeof(INT));
874 }
875
876 /** Private helper function for downmix matrix manipulation that applies a
877 *source channel (row) scaled by a given mix factor to a destination channel
878 *(row) in a given downmix matrix. Existing mix factors of the destination
879 *channel (row) will get overwritten.
880 * @param [inout] Pointer to fixed-point parts of the downmix matrix.
881 * @param [inout] Pointer to scale factor matrix associated to the downmix
882 *factors.
883 * @param [in] Index of source channel (row).
884 * @param [in] Index of destination channel (row).
885 * @param [in] Fixed-point part of mix factor to be applied.
886 * @param [in] Scale factor of mix factor to be applied.
887 * @returns Nothing to return.
888 **/
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)889 static void dmxSetChannel(FIXP_DMX mixFactors[(8)][(8)],
890 INT mixScales[(8)][(8)], const unsigned int dstCh,
891 const unsigned int srcCh, const FIXP_DMX factor,
892 const INT scale) {
893 int ch;
894 for (ch = 0; ch < (8); ch += 1) {
895 if (mixFactors[srcCh][ch] != (FIXP_DMX)0) {
896 mixFactors[dstCh][ch] =
897 FX_DBL2FX_DMX(fMult(mixFactors[srcCh][ch], factor));
898 mixScales[dstCh][ch] = mixScales[srcCh][ch] + scale;
899 }
900 }
901 }
902
903 /** Private helper function for downmix matrix manipulation that adds a source
904 *channel (row) scaled by a given mix factor to a destination channel (row) in a
905 *given downmix matrix.
906 * @param [inout] Pointer to fixed-point parts of the downmix matrix.
907 * @param [inout] Pointer to scale factor matrix associated to the downmix
908 *factors.
909 * @param [in] Index of source channel (row).
910 * @param [in] Index of destination channel (row).
911 * @param [in] Fixed-point part of mix factor to be applied.
912 * @param [in] Scale factor of mix factor to be applied.
913 * @returns Nothing to return.
914 **/
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)915 static void dmxAddChannel(FIXP_DMX mixFactors[(8)][(8)],
916 INT mixScales[(8)][(8)], const unsigned int dstCh,
917 const unsigned int srcCh, const FIXP_DMX factor,
918 const INT scale) {
919 int ch;
920 for (ch = 0; ch < (8); ch += 1) {
921 FIXP_DBL addFact = fMult(mixFactors[srcCh][ch], factor);
922 if (addFact != (FIXP_DMX)0) {
923 INT newScale = mixScales[srcCh][ch] + scale;
924 if (mixFactors[dstCh][ch] != (FIXP_DMX)0) {
925 if (newScale > mixScales[dstCh][ch]) {
926 mixFactors[dstCh][ch] >>= newScale - mixScales[dstCh][ch];
927 } else {
928 addFact >>= mixScales[dstCh][ch] - newScale;
929 newScale = mixScales[dstCh][ch];
930 }
931 }
932 mixFactors[dstCh][ch] += FX_DBL2FX_DMX(addFact);
933 mixScales[dstCh][ch] = newScale;
934 }
935 }
936 }
937
938 /** Private function that creates a downmix factor matrix depending on the input
939 and output
940 * configuration, the user parameters as well as the given metadata. This
941 function is the modules
942 * brain and hold all downmix algorithms.
943 * @param [in] Flag that indicates if inChMode holds a real (packed) channel
944 mode or has been converted to a MPEG-4 channel configuration index.
945 * @param [in] Dependent on the inModeIsCfg flag this field hands in a (packed)
946 channel mode or the corresponding MPEG-4 channel configuration index.of the
947 input configuration.
948 * @param [in] The (packed) channel mode of the output configuration.
949 * @param [in] Pointer to structure holding all current user parameter.
950 * @param [in] Pointer to field holding all current meta data.
951 * @param [out] Pointer to fixed-point parts of the downmix matrix. Normalized
952 to one scale factor.
953 * @param [out] The common scale factor of the downmix matrix.
954 * @returns An error code.
955 **/
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)956 static PCMDMX_ERROR getMixFactors(const UCHAR inModeIsCfg,
957 PCM_DMX_CHANNEL_MODE inChMode,
958 const PCM_DMX_CHANNEL_MODE outChMode,
959 const PCM_DMX_USER_PARAMS *pParams,
960 const DMX_BS_META_DATA *pMetaData,
961 FIXP_DMX mixFactors[(8)][(8)],
962 INT *pOutScale) {
963 PCMDMX_ERROR err = PCMDMX_OK;
964 INT mixScales[(8)][(8)];
965 INT maxScale = 0;
966 int numInChannel;
967 int numOutChannel;
968 int dmxMethod;
969 unsigned int outCh, inChCfg = 0;
970 unsigned int valid[(8)] = {0};
971
972 FDK_ASSERT(pMetaData != NULL);
973 FDK_ASSERT(mixFactors != NULL);
974 /* Check on a supported output configuration.
975 Add new one only after extensive testing! */
976 if (!((outChMode == CH_MODE_1_0_0_0) || (outChMode == CH_MODE_2_0_0_0) ||
977 (outChMode == CH_MODE_3_0_2_1) || (outChMode == CH_MODE_3_0_4_1) ||
978 (outChMode == CH_MODE_5_0_2_1))) {
979 FDK_ASSERT(0);
980 }
981
982 if (inModeIsCfg) {
983 /* Convert channel config to channel mode: */
984 inChCfg = (unsigned int)inChMode;
985 switch (inChCfg) {
986 case 1:
987 case 2:
988 case 3:
989 case 4:
990 case 5:
991 case 6:
992 inChMode = outChModeTable[inChCfg];
993 break;
994 case 11:
995 inChMode = CH_MODE_3_0_3_1;
996 break;
997 case 12:
998 inChMode = CH_MODE_3_0_4_1;
999 break;
1000 case 7:
1001 case 14:
1002 inChMode = CH_MODE_5_0_2_1;
1003 break;
1004 default:
1005 FDK_ASSERT(0);
1006 }
1007 }
1008
1009 /* Extract the total number of input channels */
1010 numInChannel = (inChMode & 0xF) + ((inChMode >> 4) & 0xF) +
1011 ((inChMode >> 8) & 0xF) + ((inChMode >> 12) & 0xF);
1012 /* Extract the total number of output channels */
1013 numOutChannel = (outChMode & 0xF) + ((outChMode >> 4) & 0xF) +
1014 ((outChMode >> 8) & 0xF) + ((outChMode >> 12) & 0xF);
1015
1016 /* MPEG ammendment 4 aka ETSI metadata and fallback mode: */
1017
1018 /* Create identity DMX matrix: */
1019 for (outCh = 0; outCh < (8); outCh += 1) {
1020 dmxInitChannel(mixFactors, mixScales, outCh);
1021 }
1022 if (((inChMode >> 12) & 0xF) == 0) {
1023 /* Clear empty or wrongly mapped input channel */
1024 dmxClearChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL);
1025 }
1026
1027 /* FIRST STAGE: */
1028 if (numInChannel > SIX_CHANNEL) { /* Always use MPEG equations either with
1029 meta data or with default values. */
1030 FIXP_DMX dMixFactA, dMixFactB;
1031 INT dMixScaleA, dMixScaleB;
1032 int isValidCfg = TRUE;
1033
1034 /* Get factors from meta data */
1035 dMixFactA = abMixLvlValueTab[pMetaData->dmixIdxA];
1036 dMixScaleA = (pMetaData->dmixIdxA == 0) ? 1 : 0;
1037 dMixFactB = abMixLvlValueTab[pMetaData->dmixIdxB];
1038 dMixScaleB = (pMetaData->dmixIdxB == 0) ? 1 : 0;
1039
1040 /* Check if input is in the list of supported configurations */
1041 switch (inChMode) {
1042 case CH_MODE_3_2_1_1: /* chCfg 11 but with side channels */
1043 case CH_MODE_3_2_1_0:
1044 isValidCfg = FALSE;
1045 err = PCMDMX_INVALID_MODE;
1046 FDK_FALLTHROUGH;
1047 case CH_MODE_3_0_3_1: /* chCfg 11 */
1048 /* 6.1ch: C' = C; L' = L; R' = R; LFE' = LFE;
1049 Ls' = Ls*dmix_a_idx + Cs*dmix_b_idx;
1050 Rs' = Rs*dmix_a_idx + Cs*dmix_b_idx; */
1051 dmxClearChannel(
1052 mixFactors, mixScales,
1053 RIGHT_MULTIPRPS_CHANNEL); /* clear empty input channel */
1054 dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1055 LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1056 dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1057 LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1058 dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1059 RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1060 dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1061 LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1062 break;
1063 case CH_MODE_3_0_4_1: /* chCfg 12 */
1064 /* 7.1ch Surround Back: C' = C; L' = L; R' = R; LFE' = LFE;
1065 Ls' = Ls*dmix_a_idx + Lsr*dmix_b_idx;
1066 Rs' = Rs*dmix_a_idx + Rsr*dmix_b_idx; */
1067 dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1068 LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1069 dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1070 LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1071 dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1072 RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1073 dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1074 RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1075 break;
1076 case CH_MODE_5_0_1_0:
1077 case CH_MODE_5_0_1_1:
1078 dmxClearChannel(mixFactors, mixScales,
1079 RIGHT_REAR_CHANNEL); /* clear empty input channel */
1080 dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1081 LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1082 dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1083 LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1084 FDK_FALLTHROUGH;
1085 case CH_MODE_5_2_1_0:
1086 isValidCfg = FALSE;
1087 err = PCMDMX_INVALID_MODE;
1088 FDK_FALLTHROUGH;
1089 case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */
1090 if (inChCfg == 14) {
1091 /* 7.1ch Front Height: C' = C; Ls' = Ls; Rs' = Rs; LFE' = LFE;
1092 L' = L*dmix_a_idx + Lv*dmix_b_idx;
1093 R' = R*dmix_a_idx + Rv*dmix_b_idx; */
1094 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1095 LEFT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
1096 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1097 LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1098 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1099 RIGHT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
1100 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1101 RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1102 } else {
1103 /* 7.1ch Front: Ls' = Ls; Rs' = Rs; LFE' = LFE;
1104 C' = C + (Lc+Rc)*dmix_a_idx;
1105 L' = L + Lc*dmix_b_idx;
1106 R' = R + Rc*dmix_b_idx; */
1107 dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1108 LEFT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
1109 dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1110 RIGHT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
1111 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1112 LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1113 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1114 LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1115 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1116 RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1117 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1118 RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1119 }
1120 break;
1121 default:
1122 /* Nothing to do. Just use the identity matrix. */
1123 isValidCfg = FALSE;
1124 err = PCMDMX_INVALID_MODE;
1125 break;
1126 }
1127
1128 /* Add additional DMX gain */
1129 if ((isValidCfg == TRUE) &&
1130 (pMetaData->dmxGainIdx5 != 0)) { /* Apply DMX gain 5 */
1131 FIXP_DMX dmxGain;
1132 INT dmxScale;
1133 INT sign = (pMetaData->dmxGainIdx5 & 0x40) ? -1 : 1;
1134 INT val = pMetaData->dmxGainIdx5 & 0x3F;
1135
1136 /* 10^(dmx_gain_5/80) */
1137 dmxGain = FX_DBL2FX_DMX(
1138 fLdPow(FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
1139 (FIXP_DBL)(sign * val * (LONG)FL2FXCONST_DBL(0.0125f)), 0,
1140 &dmxScale));
1141 /* Currently only positive scale factors supported! */
1142 if (dmxScale < 0) {
1143 dmxGain >>= -dmxScale;
1144 dmxScale = 0;
1145 }
1146
1147 dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1148 CENTER_FRONT_CHANNEL, dmxGain, dmxScale);
1149 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1150 LEFT_FRONT_CHANNEL, dmxGain, dmxScale);
1151 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1152 RIGHT_FRONT_CHANNEL, dmxGain, dmxScale);
1153 dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL,
1154 dmxGain, dmxScale);
1155 dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1156 RIGHT_REAR_CHANNEL, dmxGain, dmxScale);
1157 dmxSetChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL,
1158 LOW_FREQUENCY_CHANNEL, dmxGain, dmxScale);
1159 }
1160
1161 /* Mark the output channels */
1162 valid[CENTER_FRONT_CHANNEL] = 1;
1163 valid[LEFT_FRONT_CHANNEL] = 1;
1164 valid[RIGHT_FRONT_CHANNEL] = 1;
1165 valid[LEFT_REAR_CHANNEL] = 1;
1166 valid[RIGHT_REAR_CHANNEL] = 1;
1167 valid[LOW_FREQUENCY_CHANNEL] = 1;
1168
1169 /* Update channel mode for the next stage */
1170 inChMode = CH_MODE_3_0_2_1;
1171 }
1172
1173 /* For the X (> 6) to 6 channel downmix we had no choice.
1174 To mix from 6 to 2 (or 1) channel(s) we have several possibilities (MPEG
1175 DSE | MPEG PCE | ITU | ARIB | DLB). Use profile and the metadata
1176 available flags to determine which equation to use: */
1177
1178 #define DMX_METHOD_MPEG_AMD4 1
1179 #define DMX_METHOD_MPEG_LEGACY 2
1180 #define DMX_METHOD_ARIB_JAPAN 4
1181 #define DMX_METHOD_ITU_RECOM 8
1182 #define DMX_METHOD_CUSTOM 16
1183
1184 dmxMethod = DMX_METHOD_MPEG_AMD4; /* default */
1185
1186 if ((pParams->dmxProfile == DMX_PRFL_FORCE_MATRIX_MIX) &&
1187 (pMetaData->typeFlags & TYPE_PCE_DATA)) {
1188 dmxMethod = DMX_METHOD_MPEG_LEGACY;
1189 } else if (!(pMetaData->typeFlags &
1190 (TYPE_DSE_CLEV_DATA | TYPE_DSE_SLEV_DATA))) {
1191 switch (pParams->dmxProfile) {
1192 default:
1193 case DMX_PRFL_STANDARD:
1194 /* dmxMethod = DMX_METHOD_MPEG_AMD4; */
1195 break;
1196 case DMX_PRFL_MATRIX_MIX:
1197 case DMX_PRFL_FORCE_MATRIX_MIX:
1198 if (pMetaData->typeFlags & TYPE_PCE_DATA) {
1199 dmxMethod = DMX_METHOD_MPEG_LEGACY;
1200 }
1201 break;
1202 case DMX_PRFL_ARIB_JAPAN:
1203 dmxMethod = DMX_METHOD_ARIB_JAPAN;
1204 break;
1205 }
1206 }
1207
1208 /* SECOND STAGE: */
1209 if (numOutChannel <= TWO_CHANNEL) {
1210 /* Create DMX matrix according to input configuration */
1211 switch (inChMode) {
1212 case CH_MODE_2_0_0_0: /* chCfg 2 */
1213 /* Apply the dual channel mode. */
1214 switch (pParams->dualChannelMode) {
1215 case CH1_MODE: /* L' = 0.707 * Ch1;
1216 R' = 0.707 * Ch1; */
1217 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1218 LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1219 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1220 LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1221 break;
1222 case CH2_MODE: /* L' = 0.707 * Ch2;
1223 R' = 0.707 * Ch2; */
1224 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1225 RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1226 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1227 RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1228 break;
1229 case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2;
1230 R' = 0.5*Ch1 + 0.5*Ch2; */
1231 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1232 LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1233 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1234 RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1235 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1236 LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1237 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1238 RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1239 break;
1240 default:
1241 case STEREO_MODE:
1242 /* Nothing to do */
1243 break;
1244 }
1245 break;
1246 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1247 * - - - - - - - - - - - - - - - - - - - */
1248 case CH_MODE_2_0_1_0: {
1249 FIXP_DMX sMixLvl;
1250 if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1251 /* L' = 0.707*L + 0.5*S; R' = 0.707*R + 0.5*S; */
1252 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1253 LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1254 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1255 RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1256 sMixLvl = FL2FXCONST_DMX(0.5f);
1257 } else { /* L' = L + 0.707*S; R' = R + 0.707*S; */
1258 sMixLvl = FL2FXCONST_DMX(0.707f);
1259 }
1260 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1261 LEFT_REAR_CHANNEL, sMixLvl, 0);
1262 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1263 LEFT_REAR_CHANNEL, sMixLvl, 0);
1264 } break;
1265 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1266 * - - - - - - - - - - - - - - - - - - - */
1267 case CH_MODE_3_0_0_0: /* chCfg 3 */
1268 {
1269 FIXP_DMX cMixLvl;
1270 if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1271 /* L' = 0.707*L + 0.5*C; R' = 0.707*R + 0.5*C; */
1272 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1273 LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1274 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1275 RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1276 cMixLvl = FL2FXCONST_DMX(0.5f);
1277 } else { /* L' = L + 0.707*C; R' = R + 0.707*C; */
1278 cMixLvl = FL2FXCONST_DMX(0.707f);
1279 }
1280 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1281 CENTER_FRONT_CHANNEL, cMixLvl, 0);
1282 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1283 CENTER_FRONT_CHANNEL, cMixLvl, 0);
1284 } break;
1285 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1286 * - - - - - - - - - - - - - - - - - - - */
1287 case CH_MODE_3_0_1_0: /* chCfg 4 */
1288 {
1289 FIXP_DMX csMixLvl;
1290 if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1291 /* L' = 0.707*L + 0.5*C + 0.5*S; R' = 0.707*R + 0.5*C + 0.5*S; */
1292 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1293 LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1294 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1295 RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1296 csMixLvl = FL2FXCONST_DMX(0.5f);
1297 } else { /* L' = L + 0.707*C + 0.707*S;
1298 R' = R + 0.707*C + 0.707*S; */
1299 csMixLvl = FL2FXCONST_DMX(0.707f);
1300 }
1301 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1302 CENTER_FRONT_CHANNEL, csMixLvl, 0);
1303 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1304 LEFT_REAR_CHANNEL, csMixLvl, 0);
1305 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1306 CENTER_FRONT_CHANNEL, csMixLvl, 0);
1307 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1308 LEFT_REAR_CHANNEL, csMixLvl, 0);
1309 } break;
1310 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1311 * - - - - - - - - - - - - - - - - - - - */
1312 case CH_MODE_3_0_2_0: /* chCfg 5 */
1313 case CH_MODE_3_0_2_1: /* chCfg 6 */
1314 {
1315 switch (dmxMethod) {
1316 default:
1317 case DMX_METHOD_MPEG_AMD4: {
1318 FIXP_DMX cMixLvl, sMixLvl, lMixLvl;
1319 INT cMixScale, sMixScale, lMixScale;
1320
1321 /* Get factors from meta data */
1322 cMixLvl = abMixLvlValueTab[pMetaData->cLevIdx];
1323 cMixScale = (pMetaData->cLevIdx == 0) ? 1 : 0;
1324 sMixLvl = abMixLvlValueTab[pMetaData->sLevIdx];
1325 sMixScale = (pMetaData->sLevIdx == 0) ? 1 : 0;
1326 lMixLvl = lfeMixLvlValueTab[pMetaData->dmixIdxLfe];
1327 if (pMetaData->dmixIdxLfe <= 1) {
1328 lMixScale = 2;
1329 } else if (pMetaData->dmixIdxLfe <= 5) {
1330 lMixScale = 1;
1331 } else {
1332 lMixScale = 0;
1333 }
1334 /* Setup the DMX matrix */
1335 if ((pParams->pseudoSurrMode == FORCE_PS_DMX) ||
1336 ((pParams->pseudoSurrMode == AUTO_PS_DMX) &&
1337 (pMetaData->pseudoSurround ==
1338 1))) { /* L' = L + C*clev - (Ls+Rs)*slev + LFE*lflev;
1339 R' = R + C*clev + (Ls+Rs)*slev + LFE*lflev; */
1340 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1341 CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1342 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1343 LEFT_REAR_CHANNEL, -sMixLvl, sMixScale);
1344 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1345 RIGHT_REAR_CHANNEL, -sMixLvl, sMixScale);
1346 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1347 LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1348 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1349 CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1350 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1351 LEFT_REAR_CHANNEL, sMixLvl, sMixScale);
1352 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1353 RIGHT_REAR_CHANNEL, sMixLvl, sMixScale);
1354 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1355 LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1356 } else { /* L' = L + C*clev + Ls*slev + LFE*llev;
1357 R' = R + C*clev + Rs*slev + LFE*llev; */
1358 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1359 CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1360 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1361 LEFT_REAR_CHANNEL, sMixLvl, sMixScale);
1362 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1363 LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1364 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1365 CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1366 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1367 RIGHT_REAR_CHANNEL, sMixLvl, sMixScale);
1368 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1369 LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1370 }
1371
1372 /* Add additional DMX gain */
1373 if (pMetaData->dmxGainIdx2 != 0) { /* Apply DMX gain 2 */
1374 FIXP_DMX dmxGain;
1375 INT dmxScale;
1376 INT sign = (pMetaData->dmxGainIdx2 & 0x40) ? -1 : 1;
1377 INT val = pMetaData->dmxGainIdx2 & 0x3F;
1378
1379 /* 10^(dmx_gain_2/80) */
1380 dmxGain = FX_DBL2FX_DMX(
1381 fLdPow(FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
1382 (FIXP_DBL)(sign * val * (LONG)FL2FXCONST_DBL(0.0125f)),
1383 0, &dmxScale));
1384 /* Currently only positive scale factors supported! */
1385 if (dmxScale < 0) {
1386 dmxGain >>= -dmxScale;
1387 dmxScale = 0;
1388 }
1389
1390 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1391 LEFT_FRONT_CHANNEL, dmxGain, dmxScale);
1392 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1393 RIGHT_FRONT_CHANNEL, dmxGain, dmxScale);
1394 }
1395 } break;
1396 case DMX_METHOD_ARIB_JAPAN:
1397 case DMX_METHOD_MPEG_LEGACY: {
1398 FIXP_DMX flev, clev, slevLL, slevLR, slevRL, slevRR;
1399 FIXP_DMX mtrxMixDwnCoef =
1400 mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx];
1401
1402 if ((pParams->pseudoSurrMode == FORCE_PS_DMX) ||
1403 ((pParams->pseudoSurrMode == AUTO_PS_DMX) &&
1404 (pMetaData->pseudoSurround == 1))) {
1405 if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1406 /* 3/2 input: L' = 0.707 * [L+0.707*C-k*Ls-k*Rs];
1407 R' = 0.707 * [R+0.707*C+k*Ls+k*Rs]; */
1408 flev = mpegMixDownIdx2Coef[0]; /* a = 0.707 */
1409 } else { /* 3/2 input: L' = (1.707+2*A)^-1 *
1410 [L+0.707*C-A*Ls-A*Rs]; R' = (1.707+2*A)^-1 *
1411 [R+0.707*C+A*Ls+A*Rs]; */
1412 flev = mpegMixDownIdx2PreFact[1][pMetaData->matrixMixdownIdx];
1413 }
1414 slevRR = slevRL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
1415 slevLL = slevLR = -slevRL;
1416 } else {
1417 if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1418 /* 3/2 input: L' = 0.707 * [L+0.707*C+k*Ls];
1419 R' = 0.707 * [R+0.707*C+k*Rs]; */
1420 flev = mpegMixDownIdx2Coef[0]; /* a = 0.707 */
1421 } else { /* 3/2 input: L' = (1.707+A)^-1 * [L+0.707*C+A*Ls];
1422 R' = (1.707+A)^-1 * [R+0.707*C+A*Rs]; */
1423 flev = mpegMixDownIdx2PreFact[0][pMetaData->matrixMixdownIdx];
1424 }
1425 slevRR = slevLL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
1426 slevLR = slevRL = (FIXP_DMX)0;
1427 }
1428 /* common factor */
1429 clev =
1430 FX_DBL2FX_DMX(fMult(flev, mpegMixDownIdx2Coef[0] /* 0.707 */));
1431
1432 dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1433 LEFT_FRONT_CHANNEL, flev, 0);
1434 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1435 CENTER_FRONT_CHANNEL, clev, 0);
1436 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1437 LEFT_REAR_CHANNEL, slevLL, 0);
1438 dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1439 RIGHT_REAR_CHANNEL, slevLR, 0);
1440
1441 dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1442 RIGHT_FRONT_CHANNEL, flev, 0);
1443 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1444 CENTER_FRONT_CHANNEL, clev, 0);
1445 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1446 LEFT_REAR_CHANNEL, slevRL, 0);
1447 dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1448 RIGHT_REAR_CHANNEL, slevRR, 0);
1449 } break;
1450 } /* switch (dmxMethod) */
1451 } break;
1452 default:
1453 /* This configuration does not fit to any known downmix equation! */
1454 err = PCMDMX_INVALID_MODE;
1455 break;
1456 } /* switch (inChMode) */
1457
1458 /* Mark the output channels */
1459 FDKmemclear(valid, (8) * sizeof(unsigned int));
1460 valid[LEFT_FRONT_CHANNEL] = 1;
1461 valid[RIGHT_FRONT_CHANNEL] = 1;
1462 }
1463
1464 if (numOutChannel == ONE_CHANNEL) {
1465 FIXP_DMX monoMixLevel;
1466 INT monoMixScale = 0;
1467
1468 dmxClearChannel(mixFactors, mixScales,
1469 CENTER_FRONT_CHANNEL); /* C is not in the mix */
1470
1471 if (dmxMethod ==
1472 DMX_METHOD_MPEG_LEGACY) { /* C' = (3+2*A)^-1 * [C+L+R+A*Ls+A+Rs]; */
1473 monoMixLevel = mpegMixDownIdx2PreFact[2][pMetaData->matrixMixdownIdx];
1474
1475 mixFactors[CENTER_FRONT_CHANNEL][CENTER_FRONT_CHANNEL] = monoMixLevel;
1476 mixFactors[CENTER_FRONT_CHANNEL][LEFT_FRONT_CHANNEL] = monoMixLevel;
1477 mixFactors[CENTER_FRONT_CHANNEL][RIGHT_FRONT_CHANNEL] = monoMixLevel;
1478 monoMixLevel = FX_DBL2FX_DMX(fMult(
1479 monoMixLevel, mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx]));
1480 mixFactors[CENTER_FRONT_CHANNEL][LEFT_REAR_CHANNEL] = monoMixLevel;
1481 mixFactors[CENTER_FRONT_CHANNEL][RIGHT_REAR_CHANNEL] = monoMixLevel;
1482 } else {
1483 switch (dmxMethod) {
1484 case DMX_METHOD_MPEG_AMD4:
1485 /* C' = L + R; */
1486 monoMixLevel = FL2FXCONST_DMX(0.5f);
1487 monoMixScale = 1;
1488 break;
1489 default:
1490 /* C' = 0.5*L + 0.5*R; */
1491 monoMixLevel = FL2FXCONST_DMX(0.5f);
1492 monoMixScale = 0;
1493 break;
1494 }
1495 dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1496 LEFT_FRONT_CHANNEL, monoMixLevel, monoMixScale);
1497 dmxAddChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1498 RIGHT_FRONT_CHANNEL, monoMixLevel, monoMixScale);
1499 }
1500
1501 /* Mark the output channel */
1502 FDKmemclear(valid, (8) * sizeof(unsigned int));
1503 valid[CENTER_FRONT_CHANNEL] = 1;
1504 }
1505
1506 #define MAX_SEARCH_START_VAL (-7)
1507
1508 {
1509 LONG chSum[(8)];
1510 INT chSumMax = MAX_SEARCH_START_VAL;
1511
1512 /* Determine the current maximum scale factor */
1513 for (outCh = 0; outCh < (8); outCh += 1) {
1514 if (valid[outCh] != 0) {
1515 unsigned int inCh;
1516 for (inCh = 0; inCh < (8); inCh += 1) {
1517 if (mixScales[outCh][inCh] > maxScale) { /* Store the new maximum */
1518 maxScale = mixScales[outCh][inCh];
1519 }
1520 }
1521 }
1522 }
1523
1524 /* Individualy analyse output chanal levels */
1525 for (outCh = 0; outCh < (8); outCh += 1) {
1526 chSum[outCh] = MAX_SEARCH_START_VAL;
1527 if (valid[outCh] != 0) {
1528 int ovrflwProtScale = 0;
1529 unsigned int inCh;
1530
1531 /* Accumulate all factors for each output channel */
1532 chSum[outCh] = 0;
1533 for (inCh = 0; inCh < (8); inCh += 1) {
1534 SHORT addFact = FX_DMX2SHRT(mixFactors[outCh][inCh]);
1535 if (mixScales[outCh][inCh] <= maxScale) {
1536 addFact >>= maxScale - mixScales[outCh][inCh];
1537 } else {
1538 addFact <<= mixScales[outCh][inCh] - maxScale;
1539 }
1540 chSum[outCh] += addFact;
1541 }
1542 if (chSum[outCh] > (LONG)MAXVAL_SGL) {
1543 while (chSum[outCh] > (LONG)MAXVAL_SGL) {
1544 ovrflwProtScale += 1;
1545 chSum[outCh] >>= 1;
1546 }
1547 } else if (chSum[outCh] > 0) {
1548 while ((chSum[outCh] << 1) <= (LONG)MAXVAL_SGL) {
1549 ovrflwProtScale -= 1;
1550 chSum[outCh] <<= 1;
1551 }
1552 }
1553 /* Store the differential scaling in the same array */
1554 chSum[outCh] = ovrflwProtScale;
1555 }
1556 }
1557
1558 for (outCh = 0; outCh < (8); outCh += 1) {
1559 if ((valid[outCh] != 0) &&
1560 (chSum[outCh] > chSumMax)) { /* Store the new maximum */
1561 chSumMax = chSum[outCh];
1562 }
1563 }
1564 maxScale = fMax(maxScale + chSumMax, 0);
1565
1566 /* Normalize all factors */
1567 for (outCh = 0; outCh < (8); outCh += 1) {
1568 if (valid[outCh] != 0) {
1569 unsigned int inCh;
1570 for (inCh = 0; inCh < (8); inCh += 1) {
1571 if (mixFactors[outCh][inCh] != (FIXP_DMX)0) {
1572 if (mixScales[outCh][inCh] <= maxScale) {
1573 mixFactors[outCh][inCh] >>= maxScale - mixScales[outCh][inCh];
1574 } else {
1575 mixFactors[outCh][inCh] <<= mixScales[outCh][inCh] - maxScale;
1576 }
1577 mixScales[outCh][inCh] = maxScale;
1578 }
1579 }
1580 }
1581 }
1582 }
1583
1584 /* return the scale factor */
1585 *pOutScale = maxScale;
1586
1587 return (err);
1588 }
1589
1590 /** Open and initialize an instance of the PCM downmix module
1591 * @param [out] Pointer to a buffer receiving the handle of the new instance.
1592 * @returns Returns an error code.
1593 **/
pcmDmx_Open(HANDLE_PCM_DOWNMIX * pSelf)1594 PCMDMX_ERROR pcmDmx_Open(HANDLE_PCM_DOWNMIX *pSelf) {
1595 HANDLE_PCM_DOWNMIX self;
1596
1597 if (pSelf == NULL) {
1598 return (PCMDMX_INVALID_HANDLE);
1599 }
1600
1601 *pSelf = NULL;
1602
1603 self = (HANDLE_PCM_DOWNMIX)GetPcmDmxInstance(0);
1604 if (self == NULL) {
1605 return (PCMDMX_OUT_OF_MEMORY);
1606 }
1607
1608 /* Reset the full instance */
1609 pcmDmx_Reset(self, PCMDMX_RESET_FULL);
1610
1611 *pSelf = self;
1612
1613 return (PCMDMX_OK);
1614 }
1615
1616 /** Reset all static values like e.g. mixdown coefficients.
1617 * @param [in] Handle of PCM downmix module instance.
1618 * @param [in] Flags telling which parts of the module shall be reset.
1619 * @returns Returns an error code.
1620 **/
pcmDmx_Reset(HANDLE_PCM_DOWNMIX self,UINT flags)1621 PCMDMX_ERROR pcmDmx_Reset(HANDLE_PCM_DOWNMIX self, UINT flags) {
1622 if (self == NULL) {
1623 return (PCMDMX_INVALID_HANDLE);
1624 }
1625
1626 if (flags & PCMDMX_RESET_PARAMS) {
1627 PCM_DMX_USER_PARAMS *pParams = &self->userParams;
1628
1629 pParams->dualChannelMode = STEREO_MODE;
1630 pParams->pseudoSurrMode = NEVER_DO_PS_DMX;
1631 pParams->numOutChannelsMax = (6);
1632 pParams->numOutChannelsMin = (0);
1633 pParams->frameDelay = 0;
1634 pParams->expiryFrame = (0);
1635
1636 self->applyProcessing = 0;
1637 }
1638
1639 if (flags & PCMDMX_RESET_BS_DATA) {
1640 int slot;
1641 /* Init all slots with a default set */
1642 for (slot = 0; slot <= (1); slot += 1) {
1643 FDKmemcpy(&self->bsMetaData[slot], &dfltMetaData,
1644 sizeof(DMX_BS_META_DATA));
1645 }
1646 }
1647
1648 return (PCMDMX_OK);
1649 }
1650
1651 /** Set one parameter for one instance of the PCM downmix module.
1652 * @param [in] Handle of PCM downmix module instance.
1653 * @param [in] Parameter to be set.
1654 * @param [in] Parameter value.
1655 * @returns Returns an error code.
1656 **/
pcmDmx_SetParam(HANDLE_PCM_DOWNMIX self,const PCMDMX_PARAM param,const INT value)1657 PCMDMX_ERROR pcmDmx_SetParam(HANDLE_PCM_DOWNMIX self, const PCMDMX_PARAM param,
1658 const INT value) {
1659 switch (param) {
1660 case DMX_PROFILE_SETTING:
1661 switch ((DMX_PROFILE_TYPE)value) {
1662 case DMX_PRFL_STANDARD:
1663 case DMX_PRFL_MATRIX_MIX:
1664 case DMX_PRFL_FORCE_MATRIX_MIX:
1665 case DMX_PRFL_ARIB_JAPAN:
1666 break;
1667 default:
1668 return (PCMDMX_UNABLE_TO_SET_PARAM);
1669 }
1670 if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1671 self->userParams.dmxProfile = (DMX_PROFILE_TYPE)value;
1672 break;
1673
1674 case DMX_BS_DATA_EXPIRY_FRAME:
1675 if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1676 self->userParams.expiryFrame = (value > 0) ? (UINT)value : 0;
1677 break;
1678
1679 case DMX_BS_DATA_DELAY:
1680 if ((value > (1)) || (value < 0)) {
1681 return (PCMDMX_UNABLE_TO_SET_PARAM);
1682 }
1683 if (self == NULL) {
1684 return (PCMDMX_INVALID_HANDLE);
1685 }
1686 self->userParams.frameDelay = (UCHAR)value;
1687 break;
1688
1689 case MIN_NUMBER_OF_OUTPUT_CHANNELS:
1690 switch (value) { /* supported output channels */
1691 case -1:
1692 case 0:
1693 case ONE_CHANNEL:
1694 case TWO_CHANNEL:
1695 case SIX_CHANNEL:
1696 case EIGHT_CHANNEL:
1697 break;
1698 default:
1699 return (PCMDMX_UNABLE_TO_SET_PARAM);
1700 }
1701 if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1702 /* Store the new value */
1703 self->userParams.numOutChannelsMin = (value > 0) ? (SHORT)value : -1;
1704 if ((value > 0) && (self->userParams.numOutChannelsMax > 0) &&
1705 (value > self->userParams
1706 .numOutChannelsMax)) { /* MIN > MAX would be an invalid
1707 state. Thus set MAX = MIN in
1708 this case. */
1709 self->userParams.numOutChannelsMax = self->userParams.numOutChannelsMin;
1710 }
1711 break;
1712
1713 case MAX_NUMBER_OF_OUTPUT_CHANNELS:
1714 switch (value) { /* supported output channels */
1715 case -1:
1716 case 0:
1717 case ONE_CHANNEL:
1718 case TWO_CHANNEL:
1719 case SIX_CHANNEL:
1720 case EIGHT_CHANNEL:
1721 break;
1722 default:
1723 return (PCMDMX_UNABLE_TO_SET_PARAM);
1724 }
1725 if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1726 /* Store the new value */
1727 self->userParams.numOutChannelsMax = (value > 0) ? (SHORT)value : -1;
1728 if ((value > 0) &&
1729 (value < self->userParams
1730 .numOutChannelsMin)) { /* MAX < MIN would be an invalid
1731 state. Thus set MIN = MAX in
1732 this case. */
1733 self->userParams.numOutChannelsMin = self->userParams.numOutChannelsMax;
1734 }
1735 break;
1736
1737 case DMX_DUAL_CHANNEL_MODE:
1738 switch ((DUAL_CHANNEL_MODE)value) {
1739 case STEREO_MODE:
1740 case CH1_MODE:
1741 case CH2_MODE:
1742 case MIXED_MODE:
1743 break;
1744 default:
1745 return (PCMDMX_UNABLE_TO_SET_PARAM);
1746 }
1747 if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1748 self->userParams.dualChannelMode = (DUAL_CHANNEL_MODE)value;
1749 self->applyProcessing = ((DUAL_CHANNEL_MODE)value != STEREO_MODE)
1750 ? 1
1751 : 0; /* Force processing if necessary. */
1752 break;
1753
1754 case DMX_PSEUDO_SURROUND_MODE:
1755 switch ((PSEUDO_SURROUND_MODE)value) {
1756 case NEVER_DO_PS_DMX:
1757 case AUTO_PS_DMX:
1758 case FORCE_PS_DMX:
1759 break;
1760 default:
1761 return (PCMDMX_UNABLE_TO_SET_PARAM);
1762 }
1763 if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1764 self->userParams.pseudoSurrMode = (PSEUDO_SURROUND_MODE)value;
1765 break;
1766
1767 default:
1768 return (PCMDMX_UNKNOWN_PARAM);
1769 }
1770
1771 return (PCMDMX_OK);
1772 }
1773
1774 /** Get one parameter value of one PCM downmix module instance.
1775 * @param [in] Handle of PCM downmix module instance.
1776 * @param [in] Parameter to be set.
1777 * @param [out] Pointer to buffer receiving the parameter value.
1778 * @returns Returns an error code.
1779 **/
pcmDmx_GetParam(HANDLE_PCM_DOWNMIX self,const PCMDMX_PARAM param,INT * const pValue)1780 PCMDMX_ERROR pcmDmx_GetParam(HANDLE_PCM_DOWNMIX self, const PCMDMX_PARAM param,
1781 INT *const pValue) {
1782 PCM_DMX_USER_PARAMS *pUsrParams;
1783
1784 if ((self == NULL) || (pValue == NULL)) {
1785 return (PCMDMX_INVALID_HANDLE);
1786 }
1787 pUsrParams = &self->userParams;
1788
1789 switch (param) {
1790 case DMX_PROFILE_SETTING:
1791 *pValue = (INT)pUsrParams->dmxProfile;
1792 break;
1793 case DMX_BS_DATA_EXPIRY_FRAME:
1794 *pValue = (INT)pUsrParams->expiryFrame;
1795 break;
1796 case DMX_BS_DATA_DELAY:
1797 *pValue = (INT)pUsrParams->frameDelay;
1798 break;
1799 case MIN_NUMBER_OF_OUTPUT_CHANNELS:
1800 *pValue = (INT)pUsrParams->numOutChannelsMin;
1801 break;
1802 case MAX_NUMBER_OF_OUTPUT_CHANNELS:
1803 *pValue = (INT)pUsrParams->numOutChannelsMax;
1804 break;
1805 case DMX_DUAL_CHANNEL_MODE:
1806 *pValue = (INT)pUsrParams->dualChannelMode;
1807 break;
1808 case DMX_PSEUDO_SURROUND_MODE:
1809 *pValue = (INT)pUsrParams->pseudoSurrMode;
1810 break;
1811 default:
1812 return (PCMDMX_UNKNOWN_PARAM);
1813 }
1814
1815 return (PCMDMX_OK);
1816 }
1817
1818 /*
1819 * Read DMX meta-data from a data stream element.
1820 */
pcmDmx_Parse(HANDLE_PCM_DOWNMIX self,HANDLE_FDK_BITSTREAM hBs,UINT ancDataBits,int isMpeg2)1821 PCMDMX_ERROR pcmDmx_Parse(HANDLE_PCM_DOWNMIX self, HANDLE_FDK_BITSTREAM hBs,
1822 UINT ancDataBits, int isMpeg2) {
1823 PCMDMX_ERROR errorStatus = PCMDMX_OK;
1824
1825 #define MAX_DSE_ANC_BYTES (16) /* 15 bytes */
1826 #define ANC_DATA_SYNC_BYTE (0xBC) /* ancillary data sync byte. */
1827
1828 DMX_BS_META_DATA *pBsMetaData;
1829
1830 int skip4Dmx = 0, skip4Ext = 0;
1831 int dmxLvlAvail = 0, extDataAvail = 0;
1832 UINT foundNewData = 0;
1833 UINT minAncBits = ((isMpeg2) ? 5 : 3) * 8;
1834
1835 if ((self == NULL) || (hBs == NULL)) {
1836 return (PCMDMX_INVALID_HANDLE);
1837 }
1838
1839 /* sanity checks */
1840 if ((ancDataBits < minAncBits) || (ancDataBits > FDKgetValidBits(hBs))) {
1841 return (PCMDMX_CORRUPT_ANC_DATA);
1842 }
1843
1844 pBsMetaData = &self->bsMetaData[0];
1845
1846 if (isMpeg2) {
1847 /* skip DVD ancillary data */
1848 FDKpushFor(hBs, 16);
1849 }
1850
1851 /* check sync word */
1852 if (FDKreadBits(hBs, 8) != ANC_DATA_SYNC_BYTE) {
1853 return (PCMDMX_CORRUPT_ANC_DATA);
1854 }
1855
1856 /* skip MPEG audio type and Dolby surround mode */
1857 FDKpushFor(hBs, 4);
1858
1859 if (isMpeg2) {
1860 /* int numAncBytes = */ FDKreadBits(hBs, 4);
1861 /* advanced dynamic range control */
1862 if (FDKreadBit(hBs)) skip4Dmx += 24;
1863 /* dialog normalization */
1864 if (FDKreadBit(hBs)) skip4Dmx += 8;
1865 /* reproduction_level */
1866 if (FDKreadBit(hBs)) skip4Dmx += 8;
1867 } else {
1868 FDKpushFor(hBs, 2); /* drc presentation mode */
1869 pBsMetaData->pseudoSurround = (SCHAR)FDKreadBit(hBs);
1870 FDKpushFor(hBs, 4); /* reserved bits */
1871 }
1872
1873 /* downmixing levels MPEGx status */
1874 dmxLvlAvail = FDKreadBit(hBs);
1875
1876 if (isMpeg2) {
1877 /* scale factor CRC status */
1878 if (FDKreadBit(hBs)) skip4Ext += 16;
1879 } else {
1880 /* ancillary data extension status */
1881 extDataAvail = FDKreadBit(hBs);
1882 }
1883
1884 /* audio coding and compression status */
1885 if (FDKreadBit(hBs)) skip4Ext += 16;
1886 /* coarse grain timecode status */
1887 if (FDKreadBit(hBs)) skip4Ext += 16;
1888 /* fine grain timecode status */
1889 if (FDKreadBit(hBs)) skip4Ext += 16;
1890
1891 /* skip the useless data to get to the DMX levels */
1892 FDKpushFor(hBs, skip4Dmx);
1893
1894 /* downmix_levels_MPEGX */
1895 if (dmxLvlAvail) {
1896 if (FDKreadBit(hBs)) { /* center_mix_level_on */
1897 pBsMetaData->cLevIdx = (UCHAR)FDKreadBits(hBs, 3);
1898 foundNewData |= TYPE_DSE_CLEV_DATA;
1899 } else {
1900 FDKreadBits(hBs, 3);
1901 }
1902 if (FDKreadBit(hBs)) { /* surround_mix_level_on */
1903 pBsMetaData->sLevIdx = (UCHAR)FDKreadBits(hBs, 3);
1904 foundNewData |= TYPE_DSE_SLEV_DATA;
1905 } else {
1906 FDKreadBits(hBs, 3);
1907 }
1908 }
1909
1910 /* skip the useless data to get to the ancillary data extension */
1911 FDKpushFor(hBs, skip4Ext);
1912
1913 /* anc data extension (MPEG-4 only) */
1914 if (extDataAvail) {
1915 int extDmxLvlSt, extDmxGainSt, extDmxLfeSt;
1916
1917 FDKreadBit(hBs); /* reserved bit */
1918 extDmxLvlSt = FDKreadBit(hBs);
1919 extDmxGainSt = FDKreadBit(hBs);
1920 extDmxLfeSt = FDKreadBit(hBs);
1921 FDKreadBits(hBs, 4); /* reserved bits */
1922
1923 if (extDmxLvlSt) {
1924 pBsMetaData->dmixIdxA = (UCHAR)FDKreadBits(hBs, 3);
1925 pBsMetaData->dmixIdxB = (UCHAR)FDKreadBits(hBs, 3);
1926 FDKreadBits(hBs, 2); /* reserved bits */
1927 foundNewData |= TYPE_DSE_DMIX_AB_DATA;
1928 }
1929 if (extDmxGainSt) {
1930 pBsMetaData->dmxGainIdx5 = (UCHAR)FDKreadBits(hBs, 7);
1931 FDKreadBit(hBs); /* reserved bit */
1932 pBsMetaData->dmxGainIdx2 = (UCHAR)FDKreadBits(hBs, 7);
1933 FDKreadBit(hBs); /* reserved bit */
1934 foundNewData |= TYPE_DSE_DMX_GAIN_DATA;
1935 }
1936 if (extDmxLfeSt) {
1937 pBsMetaData->dmixIdxLfe = (UCHAR)FDKreadBits(hBs, 4);
1938 FDKreadBits(hBs, 4); /* reserved bits */
1939 foundNewData |= TYPE_DSE_DMIX_LFE_DATA;
1940 }
1941 }
1942
1943 /* final sanity check on the amount of read data */
1944 if ((INT)FDKgetValidBits(hBs) < 0) {
1945 errorStatus = PCMDMX_CORRUPT_ANC_DATA;
1946 }
1947
1948 if ((errorStatus == PCMDMX_OK) && (foundNewData != 0)) {
1949 /* announce new data */
1950 pBsMetaData->typeFlags |= foundNewData;
1951 /* reset expiry counter */
1952 pBsMetaData->expiryCount = 0;
1953 }
1954
1955 return (errorStatus);
1956 }
1957
1958 /*
1959 * Read DMX meta-data from a data stream element.
1960 */
pcmDmx_ReadDvbAncData(HANDLE_PCM_DOWNMIX self,UCHAR * pAncDataBuf,UINT ancDataBytes,int isMpeg2)1961 PCMDMX_ERROR pcmDmx_ReadDvbAncData(HANDLE_PCM_DOWNMIX self, UCHAR *pAncDataBuf,
1962 UINT ancDataBytes, int isMpeg2) {
1963 PCMDMX_ERROR errorStatus = PCMDMX_OK;
1964 FDK_BITSTREAM bs;
1965 HANDLE_FDK_BITSTREAM hBs = &bs;
1966
1967 if (self == NULL) {
1968 return (PCMDMX_INVALID_HANDLE);
1969 }
1970
1971 /* sanity checks */
1972 if ((pAncDataBuf == NULL) || (ancDataBytes == 0)) {
1973 return (PCMDMX_CORRUPT_ANC_DATA);
1974 }
1975
1976 FDKinitBitStream(hBs, pAncDataBuf, MAX_DSE_ANC_BYTES, ancDataBytes * 8,
1977 BS_READER);
1978
1979 errorStatus = pcmDmx_Parse(self, hBs, ancDataBytes * 8, isMpeg2);
1980
1981 return (errorStatus);
1982 }
1983
1984 /** Set the matrix mixdown information extracted from the PCE of an AAC
1985 *bitstream. Note: Call only if matrix_mixdown_idx_present is true.
1986 * @param [in] Handle of PCM downmix module instance.
1987 * @param [in] The 2 bit matrix mixdown index extracted from PCE.
1988 * @param [in] The pseudo surround enable flag extracted from PCE.
1989 * @returns Returns an error code.
1990 **/
pcmDmx_SetMatrixMixdownFromPce(HANDLE_PCM_DOWNMIX self,int matrixMixdownPresent,int matrixMixdownIdx,int pseudoSurroundEnable)1991 PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce(HANDLE_PCM_DOWNMIX self,
1992 int matrixMixdownPresent,
1993 int matrixMixdownIdx,
1994 int pseudoSurroundEnable) {
1995 if (self == NULL) {
1996 return (PCMDMX_INVALID_HANDLE);
1997 }
1998
1999 {
2000 DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0];
2001
2002 if (matrixMixdownPresent) {
2003 pBsMetaData->pseudoSurround = (pseudoSurroundEnable) ? 1 : 0;
2004 pBsMetaData->matrixMixdownIdx = matrixMixdownIdx & 0x03;
2005 pBsMetaData->typeFlags |= TYPE_PCE_DATA;
2006 /* Reset expiry counter */
2007 pBsMetaData->expiryCount = 0;
2008 }
2009 }
2010
2011 return (PCMDMX_OK);
2012 }
2013
2014 /** Apply down or up mixing.
2015 * @param [in] Handle of PCM downmix module instance.
2016 * @param [inout] Pointer to buffer that hold the time domain signal.
2017 * @param [in] Pointer where the amount of output samples is returned into.
2018 * @param [in] Size of pPcmBuf.
2019 * @param [inout] Pointer where the amount of output channels is returned into.
2020 * @param [in] Input and output samples are processed interleaved.
2021 * @param [inout] Array where the corresponding channel type for each output
2022 *audio channel is stored into.
2023 * @param [inout] Array where the corresponding channel type index for each
2024 *output audio channel is stored into.
2025 * @param [in] Array containing the out channel mapping to be used (From MPEG
2026 *PCE ordering to whatever is required).
2027 * @param [out] Pointer on a field receiving the scale factor that has to be
2028 *applied on all samples afterwards. If the handed pointer is NULL scaling is
2029 *done internally.
2030 * @returns Returns an error code.
2031 **/
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)2032 PCMDMX_ERROR pcmDmx_ApplyFrame(HANDLE_PCM_DOWNMIX self, DMX_PCM *pPcmBuf,
2033 const int pcmBufSize, UINT frameSize,
2034 INT *nChannels, INT fInterleaved,
2035 AUDIO_CHANNEL_TYPE channelType[],
2036 UCHAR channelIndices[],
2037 const FDK_channelMapDescr *const mapDescr,
2038 INT *pDmxOutScale) {
2039 PCM_DMX_USER_PARAMS *pParam = NULL;
2040 PCMDMX_ERROR errorStatus = PCMDMX_OK;
2041 DUAL_CHANNEL_MODE dualChannelMode;
2042 PCM_DMX_CHANNEL_MODE inChMode;
2043 PCM_DMX_CHANNEL_MODE outChMode;
2044 INT devNull; /* Just a dummy to avoid a lot of branches in the code */
2045 int numOutChannels, numInChannels;
2046 int inStride, outStride, offset;
2047 int dmxMaxScale, dmxScale;
2048 int slot;
2049 UCHAR inOffsetTable[(8)];
2050
2051 DMX_BS_META_DATA bsMetaData;
2052
2053 if ((self == NULL) || (nChannels == NULL) || (channelType == NULL) ||
2054 (channelIndices == NULL) || (!FDK_chMapDescr_isValid(mapDescr))) {
2055 return (PCMDMX_INVALID_HANDLE);
2056 }
2057
2058 /* Init the output scaling */
2059 dmxScale = 0;
2060 if (pDmxOutScale != NULL) {
2061 /* Avoid final scaling internally and hand it to the outside world. */
2062 *pDmxOutScale = 0;
2063 dmxMaxScale = (3);
2064 } else {
2065 /* Apply the scaling internally. */
2066 pDmxOutScale = &devNull; /* redirect to temporal stack memory */
2067 dmxMaxScale = 0;
2068 }
2069
2070 pParam = &self->userParams;
2071 numInChannels = *nChannels;
2072
2073 /* Perform some input sanity checks */
2074 if (pPcmBuf == NULL) {
2075 return (PCMDMX_INVALID_ARGUMENT);
2076 }
2077 if (frameSize == 0) {
2078 return (PCMDMX_INVALID_ARGUMENT);
2079 }
2080 if (numInChannels == 0) {
2081 return (PCMDMX_INVALID_ARGUMENT);
2082 }
2083 if (numInChannels > (8)) {
2084 return (PCMDMX_INVALID_CH_CONFIG);
2085 }
2086
2087 /* Check on misconfiguration */
2088 FDK_ASSERT((pParam->numOutChannelsMax <= 0) ||
2089 (pParam->numOutChannelsMax >= pParam->numOutChannelsMin));
2090
2091 /* Determine if the module has to do processing */
2092 if ((self->applyProcessing == 0) &&
2093 ((pParam->numOutChannelsMax <= 0) ||
2094 (pParam->numOutChannelsMax >= numInChannels)) &&
2095 (pParam->numOutChannelsMin <= numInChannels)) {
2096 /* Nothing to do */
2097 return (errorStatus);
2098 }
2099
2100 /* Determine the number of output channels */
2101 if ((pParam->numOutChannelsMax > 0) &&
2102 (numInChannels > pParam->numOutChannelsMax)) {
2103 numOutChannels = pParam->numOutChannelsMax;
2104 } else if (numInChannels < pParam->numOutChannelsMin) {
2105 numOutChannels = pParam->numOutChannelsMin;
2106 } else {
2107 numOutChannels = numInChannels;
2108 }
2109
2110 /* Check I/O buffer size */
2111 if ((UINT)pcmBufSize < (UINT)numOutChannels * frameSize) {
2112 return (PCMDMX_OUTPUT_BUFFER_TOO_SMALL);
2113 }
2114
2115 dualChannelMode = pParam->dualChannelMode;
2116
2117 /* Analyse input channel configuration and get channel offset
2118 * table that can be accessed with the fixed channel labels. */
2119 errorStatus = getChannelMode(numInChannels, channelType, channelIndices,
2120 inOffsetTable, &inChMode);
2121 if (PCMDMX_IS_FATAL_ERROR(errorStatus) || (inChMode == CH_MODE_UNDEFINED)) {
2122 /* We don't need to restore because the channel
2123 configuration has not been changed. Just exit. */
2124 return (PCMDMX_INVALID_CH_CONFIG);
2125 }
2126
2127 /* Set input stride and offset */
2128 if (fInterleaved) {
2129 inStride = numInChannels;
2130 offset = 1; /* Channel specific offset factor */
2131 } else {
2132 inStride = 1;
2133 offset = frameSize; /* Channel specific offset factor */
2134 }
2135
2136 /* Reset downmix meta data if necessary */
2137 if ((pParam->expiryFrame > 0) &&
2138 (++self->bsMetaData[0].expiryCount >
2139 pParam
2140 ->expiryFrame)) { /* The metadata read from bitstream is too old. */
2141 #ifdef FDK_ASSERT_ENABLE
2142 PCMDMX_ERROR err = pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
2143 FDK_ASSERT(err == PCMDMX_OK);
2144 #else
2145 pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
2146 #endif
2147 }
2148 FDKmemcpy(&bsMetaData, &self->bsMetaData[pParam->frameDelay],
2149 sizeof(DMX_BS_META_DATA));
2150 /* Maintain delay line */
2151 for (slot = pParam->frameDelay; slot > 0; slot -= 1) {
2152 FDKmemcpy(&self->bsMetaData[slot], &self->bsMetaData[slot - 1],
2153 sizeof(DMX_BS_META_DATA));
2154 }
2155
2156 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2157 * - - - - - - - - - - - - - - - - - - */
2158 if (numInChannels > numOutChannels) { /* Apply downmix */
2159 DMX_PCM *pInPcm[(8)] = {NULL};
2160 DMX_PCM *pOutPcm[(8)] = {NULL};
2161 FIXP_DMX mixFactors[(8)][(8)];
2162 UCHAR outOffsetTable[(8)];
2163 UINT sample;
2164 int chCfg = 0;
2165 int bypScale = 0;
2166
2167 if (numInChannels > SIX_CHANNEL) {
2168 AUDIO_CHANNEL_TYPE multiPurposeChType[2];
2169
2170 /* Get the type of the multipurpose channels */
2171 multiPurposeChType[0] =
2172 channelType[inOffsetTable[LEFT_MULTIPRPS_CHANNEL]];
2173 multiPurposeChType[1] =
2174 channelType[inOffsetTable[RIGHT_MULTIPRPS_CHANNEL]];
2175
2176 /* Check if the input configuration is one defined in the standard. */
2177 switch (inChMode) {
2178 case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */
2179 /* Further analyse the input config to distinguish the two
2180 * CH_MODE_5_0_2_1 configs. */
2181 if ((multiPurposeChType[0] == ACT_FRONT_TOP) &&
2182 (multiPurposeChType[1] == ACT_FRONT_TOP)) {
2183 chCfg = 14;
2184 } else {
2185 chCfg = 7;
2186 }
2187 break;
2188 case CH_MODE_3_0_3_1: /* chCfg 11 */
2189 chCfg = 11;
2190 break;
2191 case CH_MODE_3_0_4_1: /* chCfg 12 */
2192 chCfg = 12;
2193 break;
2194 default:
2195 chCfg = 0; /* Not a known config */
2196 break;
2197 }
2198 }
2199
2200 /* Set this stages output stride and channel mode: */
2201 outStride = (fInterleaved) ? numOutChannels : 1;
2202 outChMode = outChModeTable[numOutChannels];
2203 FDK_ASSERT(outChMode != CH_MODE_UNDEFINED);
2204
2205 /* Get channel description and channel mapping for the desired output
2206 * configuration. */
2207 getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
2208 outOffsetTable);
2209 /* Now there is no way back because we modified the channel configuration!
2210 */
2211
2212 /* Create the DMX matrix */
2213 errorStatus =
2214 getMixFactors((chCfg > 0) ? 1 : 0,
2215 (chCfg > 0) ? (PCM_DMX_CHANNEL_MODE)chCfg : inChMode,
2216 outChMode, pParam, &bsMetaData, mixFactors, &dmxScale);
2217 /* No fatal errors can occur here. The function is designed to always return
2218 a valid matrix. The error code is used to signal configurations and
2219 matrices that are not conform to any standard. */
2220
2221 /* Determine the final scaling */
2222 bypScale = fMin(dmxMaxScale, dmxScale);
2223 *pDmxOutScale += bypScale;
2224 dmxScale -= bypScale;
2225
2226 { /* Set channel pointer for input. Remove empty cols. */
2227 int inCh, outCh, map[(8)];
2228 int ch = 0;
2229 for (inCh = 0; inCh < (8); inCh += 1) {
2230 if (inOffsetTable[inCh] < (UCHAR)numInChannels) {
2231 pInPcm[ch] = &pPcmBuf[inOffsetTable[inCh] * offset];
2232 map[ch++] = inCh;
2233 }
2234 }
2235 for (; ch < (8); ch += 1) {
2236 map[ch] = ch;
2237 }
2238
2239 /* Remove unused cols from factor matrix */
2240 for (inCh = 0; inCh < numInChannels; inCh += 1) {
2241 if (inCh != map[inCh]) {
2242 for (outCh = 0; outCh < (8); outCh += 1) {
2243 mixFactors[outCh][inCh] = mixFactors[outCh][map[inCh]];
2244 }
2245 }
2246 }
2247
2248 /* Set channel pointer for output. Remove empty cols. */
2249 ch = 0;
2250 for (outCh = 0; outCh < (8); outCh += 1) {
2251 if (outOffsetTable[outCh] < (UCHAR)numOutChannels) {
2252 pOutPcm[ch] = &pPcmBuf[outOffsetTable[outCh] * offset];
2253 map[ch++] = outCh;
2254 }
2255 }
2256 for (; ch < (8); ch += 1) {
2257 map[ch] = ch;
2258 }
2259
2260 /* Remove unused rows from factor matrix */
2261 for (outCh = 0; outCh < numOutChannels; outCh += 1) {
2262 if (outCh != map[outCh]) {
2263 FDKmemcpy(&mixFactors[outCh], &mixFactors[map[outCh]],
2264 (8) * sizeof(FIXP_DMX));
2265 }
2266 }
2267 }
2268
2269 /* Sample processing loop */
2270 for (sample = 0; sample < frameSize; sample++) {
2271 DMX_PCM tIn[(8)] = {0};
2272 FIXP_DBL tOut[(8)] = {(FIXP_DBL)0};
2273 int inCh, outCh;
2274
2275 /* Preload all input samples */
2276 for (inCh = 0; inCh < numInChannels; inCh += 1) {
2277 if (pInPcm[inCh] != NULL) {
2278 tIn[inCh] = *pInPcm[inCh];
2279 pInPcm[inCh] += inStride;
2280 } else {
2281 tIn[inCh] = (DMX_PCM)0;
2282 }
2283 }
2284 /* Apply downmix coefficients to input samples and accumulate for output
2285 */
2286 for (outCh = 0; outCh < numOutChannels; outCh += 1) {
2287 for (inCh = 0; inCh < numInChannels; inCh += 1) {
2288 tOut[outCh] += fMult((DMX_PCMF)tIn[inCh], mixFactors[outCh][inCh]);
2289 }
2290 FDK_ASSERT(pOutPcm[outCh] >= pPcmBuf);
2291 FDK_ASSERT(pOutPcm[outCh] < &pPcmBuf[pcmBufSize]);
2292 /* Write sample */
2293 *pOutPcm[outCh] = (DMX_PCM)SATURATE_SHIFT(
2294 tOut[outCh], DFRACT_BITS - DMX_PCM_BITS - dmxScale, DMX_PCM_BITS);
2295 pOutPcm[outCh] += outStride;
2296 }
2297 }
2298
2299 /* Update the number of output channels */
2300 *nChannels = numOutChannels;
2301
2302 } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2303 - - - - - - - - - - - - - - - - - - */
2304 else if (numInChannels < numOutChannels) { /* Apply rudimentary upmix */
2305 /* Set up channel pointer */
2306 UCHAR outOffsetTable[(8)];
2307
2308 /* FIRST STAGE
2309 Create a stereo/dual channel signal */
2310 if (numInChannels == ONE_CHANNEL) {
2311 DMX_PCM *pInPcm[(8)];
2312 DMX_PCM *pOutLF, *pOutRF;
2313 UINT sample;
2314
2315 /* Set this stages output stride and channel mode: */
2316 outStride = (fInterleaved) ? TWO_CHANNEL : 1;
2317 outChMode = outChModeTable[TWO_CHANNEL];
2318
2319 /* Get channel description and channel mapping for this
2320 * stages number of output channels (always STEREO). */
2321 getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
2322 outOffsetTable);
2323 /* Now there is no way back because we modified the channel configuration!
2324 */
2325
2326 /* Set input channel pointer. The first channel is always at index 0. */
2327 pInPcm[CENTER_FRONT_CHANNEL] =
2328 &pPcmBuf[(frameSize - 1) *
2329 inStride]; /* Considering input mapping could lead to a
2330 invalid pointer here if the channel is not
2331 declared to be a front channel. */
2332
2333 /* Set output channel pointer (for this stage). */
2334 pOutLF = &pPcmBuf[outOffsetTable[LEFT_FRONT_CHANNEL] * offset +
2335 (frameSize - 1) * outStride];
2336 pOutRF = &pPcmBuf[outOffsetTable[RIGHT_FRONT_CHANNEL] * offset +
2337 (frameSize - 1) * outStride];
2338
2339 /* 1/0 input: */
2340 for (sample = 0; sample < frameSize; sample++) {
2341 /* L' = C; R' = C; */
2342 *pOutLF = *pOutRF = *pInPcm[CENTER_FRONT_CHANNEL];
2343
2344 pInPcm[CENTER_FRONT_CHANNEL] -= inStride;
2345 pOutLF -= outStride;
2346 pOutRF -= outStride;
2347 }
2348
2349 /* Prepare for next stage: */
2350 inStride = outStride;
2351 inChMode = outChMode;
2352 FDKmemcpy(inOffsetTable, outOffsetTable, (8) * sizeof(UCHAR));
2353 }
2354
2355 /* SECOND STAGE
2356 Extend with zero channels to achieved the desired number of output
2357 channels. */
2358 if (numOutChannels > TWO_CHANNEL) {
2359 DMX_PCM *pIn[(8)] = {NULL};
2360 DMX_PCM *pOut[(8)] = {NULL};
2361 UINT sample;
2362 AUDIO_CHANNEL_TYPE inChTypes[(8)];
2363 UCHAR inChIndices[(8)];
2364 UCHAR numChPerGrp[2][(4)];
2365 int nContentCh = 0; /* Number of channels with content */
2366 int nEmptyCh = 0; /* Number of channels with content */
2367 int ch, chGrp, isCompatible = 1;
2368
2369 /* Do not change the signalling which is the channel types and indices.
2370 Just reorder and add channels. So first save the input signalling. */
2371 FDKmemcpy(inChTypes, channelType,
2372 numInChannels * sizeof(AUDIO_CHANNEL_TYPE));
2373 FDKmemclear(inChTypes + numInChannels,
2374 ((8) - numInChannels) * sizeof(AUDIO_CHANNEL_TYPE));
2375 FDKmemcpy(inChIndices, channelIndices, numInChannels * sizeof(UCHAR));
2376 FDKmemclear(inChIndices + numInChannels,
2377 ((8) - numInChannels) * sizeof(UCHAR));
2378
2379 /* Set this stages output stride and channel mode: */
2380 outStride = (fInterleaved) ? numOutChannels : 1;
2381 outChMode = outChModeTable[numOutChannels];
2382 FDK_ASSERT(outChMode != CH_MODE_UNDEFINED);
2383
2384 /* Check if input channel config can be easily mapped to the desired
2385 * output config. */
2386 for (chGrp = 0; chGrp < (4); chGrp += 1) {
2387 numChPerGrp[IN][chGrp] = (inChMode >> (chGrp * 4)) & 0xF;
2388 numChPerGrp[OUT][chGrp] = (outChMode >> (chGrp * 4)) & 0xF;
2389
2390 if (numChPerGrp[IN][chGrp] > numChPerGrp[OUT][chGrp]) {
2391 isCompatible = 0;
2392 break;
2393 }
2394 }
2395
2396 if (isCompatible) {
2397 /* Get new channel description and channel
2398 * mapping for the desired output channel mode. */
2399 getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
2400 outOffsetTable);
2401 /* If the input config has a back center channel but the output
2402 config has not, copy it to left and right (if available). */
2403 if ((numChPerGrp[IN][CH_GROUP_REAR] % 2) &&
2404 !(numChPerGrp[OUT][CH_GROUP_REAR] % 2)) {
2405 if (numChPerGrp[IN][CH_GROUP_REAR] == 1) {
2406 inOffsetTable[RIGHT_REAR_CHANNEL] =
2407 inOffsetTable[LEFT_REAR_CHANNEL];
2408 } else if (numChPerGrp[IN][CH_GROUP_REAR] == 3) {
2409 inOffsetTable[RIGHT_MULTIPRPS_CHANNEL] =
2410 inOffsetTable[LEFT_MULTIPRPS_CHANNEL];
2411 }
2412 }
2413 } else {
2414 /* Just copy and extend the original config */
2415 FDKmemcpy(outOffsetTable, inOffsetTable, (8) * sizeof(UCHAR));
2416 }
2417
2418 /* Set I/O channel pointer.
2419 Note: The following assignment algorithm clears the channel offset
2420 tables. Thus they can not be used afterwards. */
2421 for (ch = 0; ch < (8); ch += 1) {
2422 if ((outOffsetTable[ch] < 255) &&
2423 (inOffsetTable[ch] < 255)) { /* Set I/O pointer: */
2424 pIn[nContentCh] =
2425 &pPcmBuf[inOffsetTable[ch] * offset + (frameSize - 1) * inStride];
2426 pOut[nContentCh] = &pPcmBuf[outOffsetTable[ch] * offset +
2427 (frameSize - 1) * outStride];
2428 /* Update signalling */
2429 channelType[outOffsetTable[ch]] = inChTypes[inOffsetTable[ch]];
2430 channelIndices[outOffsetTable[ch]] = inChIndices[inOffsetTable[ch]];
2431 inOffsetTable[ch] = 255;
2432 outOffsetTable[ch] = 255;
2433 nContentCh += 1;
2434 }
2435 }
2436 if (isCompatible) {
2437 /* Assign the remaining input channels.
2438 This is just a safety appliance. We should never need it. */
2439 for (ch = 0; ch < (8); ch += 1) {
2440 if (inOffsetTable[ch] < 255) {
2441 int outCh;
2442 for (outCh = 0; outCh < (8); outCh += 1) {
2443 if (outOffsetTable[outCh] < 255) {
2444 break;
2445 }
2446 }
2447 if (outCh >= (8)) {
2448 FDK_ASSERT(0);
2449 break;
2450 }
2451 /* Set I/O pointer: */
2452 pIn[nContentCh] = &pPcmBuf[inOffsetTable[ch] * offset +
2453 (frameSize - 1) * inStride];
2454 pOut[nContentCh] = &pPcmBuf[outOffsetTable[outCh] * offset +
2455 (frameSize - 1) * outStride];
2456 /* Update signalling */
2457 FDK_ASSERT(inOffsetTable[outCh] < numInChannels);
2458 FDK_ASSERT(outOffsetTable[outCh] < numOutChannels);
2459 channelType[outOffsetTable[outCh]] = inChTypes[inOffsetTable[ch]];
2460 channelIndices[outOffsetTable[outCh]] =
2461 inChIndices[inOffsetTable[ch]];
2462 inOffsetTable[ch] = 255;
2463 outOffsetTable[outCh] = 255;
2464 nContentCh += 1;
2465 }
2466 }
2467 /* Set the remaining output channel pointer */
2468 for (ch = 0; ch < (8); ch += 1) {
2469 if (outOffsetTable[ch] < 255) {
2470 pOut[nContentCh + nEmptyCh] = &pPcmBuf[outOffsetTable[ch] * offset +
2471 (frameSize - 1) * outStride];
2472 /* Expand output signalling */
2473 channelType[outOffsetTable[ch]] = ACT_NONE;
2474 channelIndices[outOffsetTable[ch]] = (UCHAR)nEmptyCh;
2475 outOffsetTable[ch] = 255;
2476 nEmptyCh += 1;
2477 }
2478 }
2479 } else {
2480 /* Set the remaining output channel pointer */
2481 for (ch = nContentCh; ch < numOutChannels; ch += 1) {
2482 pOut[ch] = &pPcmBuf[ch * offset + (frameSize - 1) * outStride];
2483 /* Expand output signalling */
2484 channelType[ch] = ACT_NONE;
2485 channelIndices[ch] = (UCHAR)nEmptyCh;
2486 nEmptyCh += 1;
2487 }
2488 }
2489
2490 /* First copy the channels that have signal */
2491 for (sample = 0; sample < frameSize; sample += 1) {
2492 DMX_PCM tIn[(8)];
2493 /* Read all channel samples */
2494 for (ch = 0; ch < nContentCh; ch += 1) {
2495 tIn[ch] = *pIn[ch];
2496 pIn[ch] -= inStride;
2497 }
2498 /* Write all channel samples */
2499 for (ch = 0; ch < nContentCh; ch += 1) {
2500 *pOut[ch] = tIn[ch];
2501 pOut[ch] -= outStride;
2502 }
2503 }
2504
2505 /* Clear all the other channels */
2506 for (sample = 0; sample < frameSize; sample++) {
2507 for (ch = nContentCh; ch < numOutChannels; ch += 1) {
2508 *pOut[ch] = (DMX_PCM)0;
2509 pOut[ch] -= outStride;
2510 }
2511 }
2512 }
2513
2514 /* update the number of output channels */
2515 *nChannels = numOutChannels;
2516 } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2517 - - - - - - - - - - - - - - - - - - */
2518 else if (numInChannels == numOutChannels) {
2519 /* Don't need to change the channel description here */
2520
2521 switch (numInChannels) {
2522 case 2: { /* Set up channel pointer */
2523 DMX_PCM *pInPcm[(8)];
2524 DMX_PCM *pOutL, *pOutR;
2525 FIXP_DMX flev;
2526
2527 UINT sample;
2528
2529 if (fInterleaved) {
2530 inStride = numInChannels;
2531 outStride =
2532 2; /* fixed !!! (below stereo is donwmixed to mono if required */
2533 offset = 1; /* Channel specific offset factor */
2534 } else {
2535 inStride = 1;
2536 outStride = 1;
2537 offset = frameSize; /* Channel specific offset factor */
2538 }
2539
2540 /* Set input channel pointer */
2541 pInPcm[LEFT_FRONT_CHANNEL] =
2542 &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL] * offset];
2543 pInPcm[RIGHT_FRONT_CHANNEL] =
2544 &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL] * offset];
2545
2546 /* Set output channel pointer (same as input) */
2547 pOutL = pInPcm[LEFT_FRONT_CHANNEL];
2548 pOutR = pInPcm[RIGHT_FRONT_CHANNEL];
2549
2550 /* Set downmix levels: */
2551 flev = FL2FXCONST_DMX(0.70710678f);
2552 /* 2/0 input: */
2553 switch (dualChannelMode) {
2554 case CH1_MODE: /* L' = 0.707 * Ch1; R' = 0.707 * Ch1 */
2555 for (sample = 0; sample < frameSize; sample++) {
2556 *pOutL = *pOutR = (DMX_PCM)SATURATE_RIGHT_SHIFT(
2557 fMult((DMX_PCMF)*pInPcm[LEFT_FRONT_CHANNEL], flev),
2558 DFRACT_BITS - DMX_PCM_BITS, DMX_PCM_BITS);
2559
2560 pInPcm[LEFT_FRONT_CHANNEL] += inStride;
2561 pOutL += outStride;
2562 pOutR += outStride;
2563 }
2564 break;
2565 case CH2_MODE: /* L' = 0.707 * Ch2; R' = 0.707 * Ch2 */
2566 for (sample = 0; sample < frameSize; sample++) {
2567 *pOutL = *pOutR = (DMX_PCM)SATURATE_RIGHT_SHIFT(
2568 fMult((DMX_PCMF)*pInPcm[RIGHT_FRONT_CHANNEL], flev),
2569 DFRACT_BITS - DMX_PCM_BITS, DMX_PCM_BITS);
2570
2571 pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
2572 pOutL += outStride;
2573 pOutR += outStride;
2574 }
2575 break;
2576 case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2; R' = 0.5*Ch1 + 0.5*Ch2 */
2577 for (sample = 0; sample < frameSize; sample++) {
2578 *pOutL = *pOutR = (*pInPcm[LEFT_FRONT_CHANNEL] >> 1) +
2579 (*pInPcm[RIGHT_FRONT_CHANNEL] >> 1);
2580
2581 pInPcm[LEFT_FRONT_CHANNEL] += inStride;
2582 pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
2583 pOutL += outStride;
2584 pOutR += outStride;
2585 }
2586 break;
2587 default:
2588 case STEREO_MODE:
2589 /* nothing to do */
2590 break;
2591 }
2592 } break;
2593
2594 default:
2595 /* nothing to do */
2596 break;
2597 }
2598 }
2599
2600 return (errorStatus);
2601 }
2602
2603 /** Close an instance of the PCM downmix module.
2604 * @param [inout] Pointer to a buffer containing the handle of the instance.
2605 * @returns Returns an error code.
2606 **/
pcmDmx_Close(HANDLE_PCM_DOWNMIX * pSelf)2607 PCMDMX_ERROR pcmDmx_Close(HANDLE_PCM_DOWNMIX *pSelf) {
2608 if (pSelf == NULL) {
2609 return (PCMDMX_INVALID_HANDLE);
2610 }
2611
2612 FreePcmDmxInstance(pSelf);
2613 *pSelf = NULL;
2614
2615 return (PCMDMX_OK);
2616 }
2617
2618 /** Get library info for this module.
2619 * @param [out] Pointer to an allocated LIB_INFO structure.
2620 * @returns Returns an error code.
2621 */
pcmDmx_GetLibInfo(LIB_INFO * info)2622 PCMDMX_ERROR pcmDmx_GetLibInfo(LIB_INFO *info) {
2623 int i;
2624
2625 if (info == NULL) {
2626 return PCMDMX_INVALID_ARGUMENT;
2627 }
2628
2629 /* Search for next free tab */
2630 for (i = 0; i < FDK_MODULE_LAST; i++) {
2631 if (info[i].module_id == FDK_NONE) break;
2632 }
2633 if (i == FDK_MODULE_LAST) {
2634 return PCMDMX_INVALID_ARGUMENT;
2635 }
2636
2637 /* Add the library info */
2638 info[i].module_id = FDK_PCMDMX;
2639 info[i].version =
2640 LIB_VERSION(PCMUTIL_LIB_VL0, PCMUTIL_LIB_VL1, PCMUTIL_LIB_VL2);
2641 LIB_VERSION_STRING(info + i);
2642 info[i].build_date = PCMUTIL_LIB_BUILD_DATE;
2643 info[i].build_time = PCMUTIL_LIB_BUILD_TIME;
2644 info[i].title = PCMDMX_LIB_TITLE;
2645
2646 /* Set flags */
2647 info[i].flags = 0 | CAPF_DMX_BLIND /* At least blind downmixing is possible */
2648 | CAPF_DMX_PCE /* Guided downmix with data from MPEG-2/4
2649 Program Config Elements (PCE). */
2650 | CAPF_DMX_ARIB /* PCE guided downmix with slightly different
2651 equations and levels. */
2652 | CAPF_DMX_DVB /* Guided downmix with data from DVB ancillary
2653 data fields. */
2654 | CAPF_DMX_CH_EXP /* Simple upmixing by dublicating channels
2655 or adding zero channels. */
2656 | CAPF_DMX_6_CH | CAPF_DMX_8_CH;
2657
2658 /* Add lib info for FDK tools (if not yet done). */
2659 FDK_toolsGetLibInfo(info);
2660
2661 return PCMDMX_OK;
2662 }
2663