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