Coverage Report

Created: 2025-07-23 06:37

/src/aac/libPCMutils/src/pcmdmx_lib.cpp
Line
Count
Source (jump to first uncovered line)
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
0
#define PCMDMX_LIB_TITLE "PCM Downmix Lib"
114
115
0
#define FALSE 0
116
0
#define TRUE 1
117
0
#define IN 0
118
0
#define OUT 1
119
120
/* Type definitions: */
121
0
#define FIXP_DMX FIXP_SGL
122
#define FX_DMX2FX_DBL(x) FX_SGL2FX_DBL((FIXP_SGL)(x))
123
0
#define FX_DBL2FX_DMX(x) FX_DBL2FX_SGL(x)
124
0
#define FL2FXCONST_DMX(x) FL2FXCONST_SGL(x)
125
#define MAXVAL_DMX MAXVAL_SGL
126
0
#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
0
#define CH_GROUP_FRONT (0)
132
0
#define CH_GROUP_SIDE (1)
133
0
#define CH_GROUP_REAR (2)
134
0
#define CH_GROUP_LFE (3)
135
136
/* Fixed and unique channel plain indices. */
137
0
#define CH_PLAIN_NORMAL (0)
138
0
#define CH_PLAIN_TOP (1)
139
0
#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
0
#define CENTER_FRONT_CHANNEL (0) /* C  */
145
0
#define LEFT_FRONT_CHANNEL (1)   /* L  */
146
0
#define RIGHT_FRONT_CHANNEL (2)  /* R  */
147
#define LEFT_REAR_CHANNEL \
148
0
  (3) /* Lr (aka left back channel) or center back channel */
149
0
#define RIGHT_REAR_CHANNEL (4)      /* Rr (aka right back channel) */
150
0
#define LOW_FREQUENCY_CHANNEL (5)   /* Lf */
151
0
#define LEFT_MULTIPRPS_CHANNEL (6)  /* Left multipurpose channel */
152
0
#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
0
#define LEFT_SIDE_CHANNEL_TOP (14)       /* Lvss */
162
#define RIGHT_SIDE_CHANNEL_TOP (15)      /* Rvss */
163
#define CENTER_SIDE_CHANNEL_TOP (16)     /* Ts   */
164
0
#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
0
#define ONE_CHANNEL (1)
174
0
#define TWO_CHANNEL (2)
175
0
#define SIX_CHANNEL (6)
176
0
#define EIGHT_CHANNEL (8)
177
#define TWENTY_FOUR_CHANNEL (24)
178
179
0
#define PCMDMX_THRESHOLD_MAP_HEAT_1 (0) /* Store only exact matches */
180
0
#define PCMDMX_THRESHOLD_MAP_HEAT_2 (20)
181
#define PCMDMX_THRESHOLD_MAP_HEAT_3 \
182
0
  (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
0
#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
47
#define TYPE_PCE_DATA (0x01)
328
0
#define TYPE_DSE_CLEV_DATA (0x02)
329
0
#define TYPE_DSE_SLEV_DATA (0x04)
330
0
#define TYPE_DSE_DMIX_AB_DATA (0x08)
331
0
#define TYPE_DSE_DMIX_LFE_DATA (0x10)
332
0
#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
387
static UINT getSpeakerDistance(PCM_DMX_SPEAKER_POSITION posA,
388
0
                               PCM_DMX_SPEAKER_POSITION posB) {
389
0
  PCM_DMX_SPEAKER_POSITION diff;
390
391
0
  diff.x = posA.x - posB.x;
392
0
  diff.y = posA.y - posB.y;
393
0
  diff.z = posA.z - posB.z;
394
395
0
  return ((diff.x * diff.x) + (diff.y * diff.y) + (diff.z * diff.z));
396
0
}
397
398
static PCM_DMX_SPEAKER_POSITION getSpeakerPos(AUDIO_CHANNEL_TYPE chType,
399
0
                                              UCHAR chIndex, UCHAR numChInGrp) {
400
0
#define PCMDMX_SPKR_POS_X_MAX_WIDTH (3)
401
0
#define PCMDMX_SPKR_POS_Y_SPREAD (2)
402
0
#define PCMDMX_SPKR_POS_Z_SPREAD (2)
403
404
0
  PCM_DMX_SPEAKER_POSITION spkrPos = {0, 0, 0};
405
0
  AUDIO_CHANNEL_TYPE chGrp = (AUDIO_CHANNEL_TYPE)(chType & 0x0F);
406
0
  unsigned fHasCenter = numChInGrp & 0x1;
407
0
  unsigned chGrpWidth = numChInGrp >> 1;
408
0
  unsigned fIsCenter = 0;
409
0
  unsigned fIsLfe = (chType == ACT_LFE) ? 1 : 0;
410
0
  int offset = 0;
411
412
0
  FDK_ASSERT(chIndex < numChInGrp);
413
414
0
  if ((chGrp == ACT_FRONT) && fHasCenter) {
415
0
    if (chIndex == 0) fIsCenter = 1;
416
0
    chIndex = (UCHAR)fMax(0, chIndex - 1);
417
0
  } else if (fHasCenter && (chIndex == numChInGrp - 1)) {
418
0
    fIsCenter = 1;
419
0
  }
420
  /* now all even indices are left (-) */
421
0
  if (!fIsCenter) {
422
0
    offset = chIndex >> 1;
423
0
    if ((chGrp > ACT_FRONT) && (chType != ACT_SIDE) && !fIsLfe) {
424
      /* the higher the index the lower the distance to the center position */
425
0
      offset = chGrpWidth - fHasCenter - offset;
426
0
    }
427
0
    if ((chIndex & 0x1) == 0) { /* even */
428
0
      offset = -(offset + 1);
429
0
    } else {
430
0
      offset += 1;
431
0
    }
432
0
  }
433
  /* apply the offset */
434
0
  if (chType == ACT_SIDE) {
435
0
    spkrPos.x = (offset < 0) ? -PCMDMX_SPKR_POS_X_MAX_WIDTH
436
0
                             : PCMDMX_SPKR_POS_X_MAX_WIDTH;
437
0
    spkrPos.y = /* 1x */ PCMDMX_SPKR_POS_Y_SPREAD + (SCHAR)fAbs(offset) - 1;
438
0
    spkrPos.z = 0;
439
0
  } else {
440
0
    unsigned spread =
441
0
        ((chGrpWidth == 1) && (!fIsLfe)) ? PCMDMX_SPKR_POS_X_MAX_WIDTH - 1 : 1;
442
0
    spkrPos.x = (SCHAR)offset * (SCHAR)spread;
443
0
    if (fIsLfe) {
444
0
      spkrPos.y = 0;
445
0
      spkrPos.z = SP_Z_LFE;
446
0
    } else {
447
0
      spkrPos.y = (SCHAR)fMax((SCHAR)chGrp - 1, 0) * PCMDMX_SPKR_POS_Y_SPREAD;
448
0
      spkrPos.z = (SCHAR)chType >> 4;
449
0
      if (spkrPos.z == 2) { /* ACT_BOTTOM */
450
0
        spkrPos.z = -1;
451
0
      }
452
0
      spkrPos.z *= PCMDMX_SPKR_POS_Z_SPREAD;
453
0
    }
454
0
  }
455
0
  return spkrPos;
456
0
}
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
 **/
468
static PCM_DMX_CHANNEL_MODE getChMode4Plain(
469
    const int plainIndex, const PCM_DMX_CHANNEL_MODE totChMode,
470
0
    const int chCfg) {
471
0
  PCM_DMX_CHANNEL_MODE plainChMode = totChMode;
472
473
0
  switch (totChMode) {
474
0
    case CH_MODE_5_0_2_1:
475
0
      if (chCfg == 14) {
476
0
        switch (plainIndex) {
477
0
          case CH_PLAIN_BOTTOM:
478
0
            plainChMode = (PCM_DMX_CHANNEL_MODE)0x0000;
479
0
            break;
480
0
          case CH_PLAIN_TOP:
481
0
            plainChMode = CH_MODE_2_0_0_0;
482
0
            break;
483
0
          case CH_PLAIN_NORMAL:
484
0
          default:
485
0
            plainChMode = CH_MODE_3_0_2_1;
486
0
            break;
487
0
        }
488
0
      }
489
0
      break;
490
0
    default:
491
0
      break;
492
0
  }
493
494
0
  return plainChMode;
495
0
}
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
 **/
509
static UINT validateIndices(UINT numChannels, UINT numChannelsPlaneAndGrp,
510
                            AUDIO_CHANNEL_TYPE aChType,
511
                            const AUDIO_CHANNEL_TYPE channelType[],
512
0
                            const UCHAR channelIndices[]) {
513
0
  for (UINT reqValue = 0; reqValue < numChannelsPlaneAndGrp; reqValue++) {
514
0
    int found = FALSE;
515
0
    for (UINT i = 0; i < numChannels; i++) {
516
0
      if (channelType[i] == aChType) {
517
0
        if (channelIndices[i] == reqValue) {
518
0
          if (found == TRUE) {
519
0
            return 0; /* Found channel index a second time */
520
0
          } else {
521
0
            found = TRUE; /* Found channel index */
522
0
          }
523
0
        }
524
0
      }
525
0
    }
526
0
    if (found == FALSE) {
527
0
      return 0; /* Did not find channel index */
528
0
    }
529
0
  }
530
0
  return 1; /* Successfully validated channel indices */
531
0
}
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
 **/
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
0
) {
553
0
  UCHAR numCh[(3)][(4)];
554
0
  UCHAR mapped[(8)];
555
0
  PCM_DMX_SPEAKER_POSITION spkrPos[(8)];
556
0
  PCMDMX_ERROR err = PCMDMX_OK;
557
0
  unsigned ch, numMappedInChs = 0;
558
0
  unsigned startSlot;
559
0
  unsigned stopSlot = LOW_FREQUENCY_CHANNEL;
560
561
0
  FDK_ASSERT(channelType != NULL);
562
0
  FDK_ASSERT(channelIndices != NULL);
563
0
  FDK_ASSERT(offsetTable != NULL);
564
0
  FDK_ASSERT(chMode != NULL);
565
566
  /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */
567
0
  FDKmemclear(numCh, (3) * (4) * sizeof(UCHAR));
568
0
  FDKmemclear(mapped, (8) * sizeof(UCHAR));
569
0
  FDKmemclear(spkrPos, (8) * sizeof(PCM_DMX_SPEAKER_POSITION));
570
  /* Init output */
571
0
  FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
572
0
  *chMode = CH_MODE_UNDEFINED;
573
574
  /* Determine how many channels are assigned to each channels each group: */
575
0
  for (ch = 0; ch < numChannels; ch += 1) {
576
0
    unsigned chGrp = fMax(
577
0
        (channelType[ch] & 0x0F) - 1,
578
0
        0); /* Assign all undefined channels (ACT_NONE) to front channels. */
579
0
    numCh[channelType[ch] >> 4][chGrp] += 1;
580
0
  }
581
582
0
  {
583
0
    int chGrp;
584
    /* Sanity check on the indices */
585
0
    for (chGrp = 0; chGrp < (4); chGrp += 1) {
586
0
      int plane;
587
0
      for (plane = 0; plane < (3); plane += 1) {
588
0
        if (numCh[plane][chGrp] == 0) continue;
589
0
        AUDIO_CHANNEL_TYPE aChType =
590
0
            (AUDIO_CHANNEL_TYPE)((plane << 4) | ((chGrp + 1) & 0xF));
591
0
        if (!validateIndices(numChannels, numCh[plane][chGrp], aChType,
592
0
                             channelType, channelIndices)) {
593
0
          unsigned idxCnt = 0;
594
0
          for (ch = 0; ch < numChannels; ch += 1) {
595
0
            if (channelType[ch] == aChType) {
596
0
              channelIndices[ch] = idxCnt++;
597
0
            }
598
0
          }
599
0
          err = PCMDMX_INVALID_CH_CONFIG;
600
0
        }
601
0
      }
602
0
    }
603
0
  }
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
0
  for (ch = 0; ch < numChannels; ch += 1) {
608
0
    UINT mapDist = (unsigned)-1;
609
0
    unsigned mapCh, mapPos = (unsigned)-1;
610
0
    unsigned chGrp = fMax(
611
0
        (channelType[ch] & 0x0F) - 1,
612
0
        0); /* Assign all undefined channels (ACT_NONE) to front channels. */
613
614
0
    spkrPos[ch] = getSpeakerPos(channelType[ch], channelIndices[ch],
615
0
                                numCh[channelType[ch] >> 4][chGrp]);
616
617
0
    for (mapCh = 0; mapCh <= stopSlot; mapCh += 1) {
618
0
      if (offsetTable[mapCh] == 255) {
619
0
        UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
620
0
        if (dist < mapDist) {
621
0
          mapPos = mapCh;
622
0
          mapDist = dist;
623
0
        }
624
0
      }
625
0
    }
626
0
    if (mapDist <= PCMDMX_THRESHOLD_MAP_HEAT_1) {
627
0
      offsetTable[mapPos] = (UCHAR)ch;
628
0
      mapped[ch] = 1;
629
0
      numMappedInChs += 1;
630
0
    }
631
0
  }
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
0
  startSlot =
638
0
      ((numCh[CH_PLAIN_NORMAL][CH_GROUP_FRONT] & 0x1) || (numChannels >= (8)))
639
0
          ? 0
640
0
          : 1;
641
0
  for (ch = 0; ch < (unsigned)numChannels; ch += 1) {
642
0
    if (!mapped[ch]) {
643
0
      UINT mapDist = (unsigned)-1;
644
0
      unsigned mapCh, mapPos = (unsigned)-1;
645
646
0
      for (mapCh = startSlot; mapCh <= stopSlot; mapCh += 1) {
647
0
        if (offsetTable[mapCh] == 255) {
648
0
          UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
649
0
          if (dist < mapDist) {
650
0
            mapPos = mapCh;
651
0
            mapDist = dist;
652
0
          }
653
0
        }
654
0
      }
655
0
      if ((mapPos <= stopSlot) && (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_2) &&
656
0
          (((spkrPos[ch].x != 0) && (spkrSlotPos[mapPos].x != 0)) /* XOR */
657
0
           || ((spkrPos[ch].x == 0) &&
658
0
               (spkrSlotPos[mapPos].x ==
659
0
                0)))) { /* Assign center channels to center slots only. */
660
0
        offsetTable[mapPos] = (UCHAR)ch;
661
0
        mapped[ch] = 1;
662
0
        numMappedInChs += 1;
663
0
      }
664
0
    }
665
0
  }
666
667
  /* Mapping HEAT 3:
668
   *   Assign the rest by searching for the nearest input channel for each
669
   * internal slot. */
670
0
  for (ch = startSlot; (ch < (8)) && (numMappedInChs < numChannels); ch += 1) {
671
0
    if (offsetTable[ch] == 255) {
672
0
      UINT mapDist = (unsigned)-1;
673
0
      unsigned mapCh, mapPos = (unsigned)-1;
674
675
0
      for (mapCh = 0; mapCh < (unsigned)numChannels; mapCh += 1) {
676
0
        if (!mapped[mapCh]) {
677
0
          UINT dist = getSpeakerDistance(spkrPos[mapCh], spkrSlotPos[ch]);
678
0
          if (dist < mapDist) {
679
0
            mapPos = mapCh;
680
0
            mapDist = dist;
681
0
          }
682
0
        }
683
0
      }
684
0
      if (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_3) {
685
0
        offsetTable[ch] = (UCHAR)mapPos;
686
0
        mapped[mapPos] = 1;
687
0
        numMappedInChs += 1;
688
0
        if ((spkrPos[mapPos].x == 0) && (spkrSlotPos[ch].x != 0) &&
689
0
            (numChannels <
690
0
             (8))) { /* Skip the paired slot if we assigned a center channel. */
691
0
          ch += 1;
692
0
        }
693
0
      }
694
0
    }
695
0
  }
696
697
  /* Finaly compose the channel mode */
698
0
  for (ch = 0; ch < (4); ch += 1) {
699
0
    int plane, numChInGrp = 0;
700
0
    for (plane = 0; plane < (3); plane += 1) {
701
0
      numChInGrp += numCh[plane][ch];
702
0
    }
703
0
    *chMode = (PCM_DMX_CHANNEL_MODE)(*chMode | (numChInGrp << (ch * 4)));
704
0
  }
705
706
0
  return err;
707
0
}
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
 **/
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
0
) {
729
0
  int grpIdx, plainIdx, numPlains = 1, numTotalChannels = 0;
730
0
  int chCfg, ch = 0;
731
732
0
  FDK_ASSERT(channelType != NULL);
733
0
  FDK_ASSERT(channelIndices != NULL);
734
0
  FDK_ASSERT(mapDescr != NULL);
735
0
  FDK_ASSERT(offsetTable != NULL);
736
737
  /* Init output arrays */
738
0
  FDKmemclear(channelType, (8) * sizeof(AUDIO_CHANNEL_TYPE));
739
0
  FDKmemclear(channelIndices, (8) * sizeof(UCHAR));
740
0
  FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
741
742
  /* Summerize to get the total number of channels */
743
0
  for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
744
0
    numTotalChannels += (chMode >> (grpIdx * 4)) & 0xF;
745
0
  }
746
747
  /* Get the appropriate channel map */
748
0
  switch (chMode) {
749
0
    case CH_MODE_1_0_0_0:
750
0
    case CH_MODE_2_0_0_0:
751
0
    case CH_MODE_3_0_0_0:
752
0
    case CH_MODE_3_0_1_0:
753
0
    case CH_MODE_3_0_2_0:
754
0
    case CH_MODE_3_0_2_1:
755
0
      chCfg = numTotalChannels;
756
0
      break;
757
0
    case CH_MODE_3_0_3_1:
758
0
      chCfg = 11;
759
0
      break;
760
0
    case CH_MODE_3_0_4_1:
761
0
      chCfg = 12;
762
0
      break;
763
0
    case CH_MODE_5_0_2_1:
764
0
      chCfg = 7;
765
0
      break;
766
0
    default:
767
      /* fallback */
768
0
      chCfg = 0;
769
0
      break;
770
0
  }
771
772
  /* Compose channel offset table */
773
774
0
  for (plainIdx = 0; plainIdx < numPlains; plainIdx += 1) {
775
0
    PCM_DMX_CHANNEL_MODE plainChMode;
776
0
    UCHAR numChInGrp[(4)];
777
778
0
    plainChMode = getChMode4Plain(plainIdx, chMode, chCfg);
779
780
    /* Extract the number of channels per group */
781
0
    numChInGrp[CH_GROUP_FRONT] = plainChMode & 0xF;
782
0
    numChInGrp[CH_GROUP_SIDE] = (plainChMode >> 4) & 0xF;
783
0
    numChInGrp[CH_GROUP_REAR] = (plainChMode >> 8) & 0xF;
784
0
    numChInGrp[CH_GROUP_LFE] = (plainChMode >> 12) & 0xF;
785
786
    /* Non-symmetric channels */
787
0
    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
0
      int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
791
0
      offsetTable[CENTER_FRONT_CHANNEL] = (UCHAR)mappedIdx;
792
0
      channelType[mappedIdx] = ACT_FRONT;
793
0
      channelIndices[mappedIdx] = 0;
794
0
      ch += 1;
795
0
    }
796
797
0
    for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
798
0
      AUDIO_CHANNEL_TYPE type = ACT_NONE;
799
0
      int chMapPos = 0, maxChannels = 0;
800
0
      int chIdx = 0; /* Index of channel within the specific group */
801
802
0
      switch (grpIdx) {
803
0
        case CH_GROUP_FRONT:
804
0
          type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_FRONT);
805
0
          switch (plainIdx) {
806
0
            default:
807
0
              chMapPos = LEFT_FRONT_CHANNEL;
808
0
              chIdx = numChInGrp[grpIdx] & 0x1;
809
0
              break;
810
0
          }
811
0
          maxChannels = 3;
812
0
          break;
813
0
        case CH_GROUP_SIDE:
814
          /* Always map side channels to the multipurpose group. */
815
0
          type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_SIDE);
816
0
          if (plainIdx == CH_PLAIN_TOP) {
817
0
            chMapPos = LEFT_SIDE_CHANNEL_TOP;
818
0
            maxChannels = 3;
819
0
          } else {
820
0
            chMapPos = LEFT_MULTIPRPS_CHANNEL;
821
0
            maxChannels = 2;
822
0
          }
823
0
          break;
824
0
        case CH_GROUP_REAR:
825
0
          type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_BACK);
826
0
          if (plainIdx == CH_PLAIN_TOP) {
827
0
            chMapPos = LEFT_REAR_CHANNEL_TOP;
828
0
            maxChannels = 3;
829
0
          } else {
830
0
            chMapPos = LEFT_REAR_CHANNEL;
831
0
            maxChannels = 2;
832
0
          }
833
0
          break;
834
0
        case CH_GROUP_LFE:
835
0
          if (plainIdx == CH_PLAIN_NORMAL) {
836
0
            type = ACT_LFE;
837
0
            chMapPos = LOW_FREQUENCY_CHANNEL;
838
0
            maxChannels = 1;
839
0
          }
840
0
          break;
841
0
        default:
842
0
          break;
843
0
      }
844
845
      /* Map all channels in this group */
846
0
      for (; chIdx < numChInGrp[grpIdx]; chIdx += 1) {
847
0
        int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
848
0
        if ((chIdx == maxChannels) || (offsetTable[chMapPos] < 255)) {
849
          /* No space left in this channel group! */
850
0
          if (offsetTable[LEFT_MULTIPRPS_CHANNEL] ==
851
0
              255) { /* Use the multipurpose group: */
852
0
            chMapPos = LEFT_MULTIPRPS_CHANNEL;
853
0
          } else {
854
0
            FDK_ASSERT(0);
855
0
          }
856
0
        }
857
0
        offsetTable[chMapPos] = (UCHAR)mappedIdx;
858
0
        channelType[mappedIdx] = type;
859
0
        channelIndices[mappedIdx] = (UCHAR)chIdx;
860
0
        chMapPos += 1;
861
0
        ch += 1;
862
0
      }
863
0
    }
864
0
  }
865
0
}
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
 **/
875
static void dmxInitChannel(FIXP_DMX mixFactors[(8)][(8)],
876
0
                           INT mixScales[(8)][(8)], const unsigned int outCh) {
877
0
  unsigned int inCh;
878
0
  for (inCh = 0; inCh < (8); inCh += 1) {
879
0
    if (inCh == outCh) {
880
0
      mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.5f);
881
0
      mixScales[outCh][inCh] = 1;
882
0
    } else {
883
0
      mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.0f);
884
0
      mixScales[outCh][inCh] = 0;
885
0
    }
886
0
  }
887
0
}
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
 **/
897
static void dmxClearChannel(FIXP_DMX mixFactors[(8)][(8)],
898
0
                            INT mixScales[(8)][(8)], const unsigned int outCh) {
899
0
  FDK_ASSERT((outCh >= 0) && (outCh < (8)));
900
0
  FDKmemclear(&mixFactors[outCh], (8) * sizeof(FIXP_DMX));
901
0
  FDKmemclear(&mixScales[outCh], (8) * sizeof(INT));
902
0
}
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
 **/
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
0
                          const INT scale) {
921
0
  int ch;
922
0
  for (ch = 0; ch < (8); ch += 1) {
923
0
    if (mixFactors[srcCh][ch] != (FIXP_DMX)0) {
924
0
      mixFactors[dstCh][ch] =
925
0
          FX_DBL2FX_DMX(fMult(mixFactors[srcCh][ch], factor));
926
0
      mixScales[dstCh][ch] = mixScales[srcCh][ch] + scale;
927
0
    }
928
0
  }
929
0
}
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
 **/
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
0
                          const INT scale) {
947
0
  int ch;
948
0
  for (ch = 0; ch < (8); ch += 1) {
949
0
    FIXP_DBL addFact = fMult(mixFactors[srcCh][ch], factor);
950
0
    if (addFact != (FIXP_DMX)0) {
951
0
      INT newScale = mixScales[srcCh][ch] + scale;
952
0
      if (mixFactors[dstCh][ch] != (FIXP_DMX)0) {
953
0
        if (newScale > mixScales[dstCh][ch]) {
954
0
          mixFactors[dstCh][ch] >>= newScale - mixScales[dstCh][ch];
955
0
        } else {
956
0
          addFact >>= mixScales[dstCh][ch] - newScale;
957
0
          newScale = mixScales[dstCh][ch];
958
0
        }
959
0
      }
960
0
      mixFactors[dstCh][ch] += FX_DBL2FX_DMX(addFact);
961
0
      mixScales[dstCh][ch] = newScale;
962
0
    }
963
0
  }
964
0
}
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
 **/
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
0
                                  INT *pOutScale) {
991
0
  PCMDMX_ERROR err = PCMDMX_OK;
992
0
  INT mixScales[(8)][(8)];
993
0
  INT maxScale = 0;
994
0
  int numInChannel;
995
0
  int numOutChannel;
996
0
  int dmxMethod;
997
0
  unsigned int outCh, inChCfg = 0;
998
0
  unsigned int valid[(8)] = {0};
999
1000
0
  FDK_ASSERT(pMetaData != NULL);
1001
0
  FDK_ASSERT(mixFactors != NULL);
1002
  /* Check on a supported output configuration.
1003
     Add new one only after extensive testing! */
1004
0
  if (!((outChMode == CH_MODE_1_0_0_0) || (outChMode == CH_MODE_2_0_0_0) ||
1005
0
        (outChMode == CH_MODE_3_0_2_1) || (outChMode == CH_MODE_3_0_4_1) ||
1006
0
        (outChMode == CH_MODE_5_0_2_1))) {
1007
0
    FDK_ASSERT(0);
1008
0
  }
1009
1010
0
  if (inModeIsCfg) {
1011
    /* Convert channel config to channel mode: */
1012
0
    inChCfg = (unsigned int)inChMode;
1013
0
    switch (inChCfg) {
1014
0
      case 1:
1015
0
      case 2:
1016
0
      case 3:
1017
0
      case 4:
1018
0
      case 5:
1019
0
      case 6:
1020
0
        inChMode = outChModeTable[inChCfg];
1021
0
        break;
1022
0
      case 11:
1023
0
        inChMode = CH_MODE_3_0_3_1;
1024
0
        break;
1025
0
      case 12:
1026
0
        inChMode = CH_MODE_3_0_4_1;
1027
0
        break;
1028
0
      case 7:
1029
0
      case 14:
1030
0
        inChMode = CH_MODE_5_0_2_1;
1031
0
        break;
1032
0
      default:
1033
0
        FDK_ASSERT(0);
1034
0
    }
1035
0
  }
1036
1037
  /* Extract the total number of input channels */
1038
0
  numInChannel = (inChMode & 0xF) + ((inChMode >> 4) & 0xF) +
1039
0
                 ((inChMode >> 8) & 0xF) + ((inChMode >> 12) & 0xF);
1040
  /* Extract the total number of output channels */
1041
0
  numOutChannel = (outChMode & 0xF) + ((outChMode >> 4) & 0xF) +
1042
0
                  ((outChMode >> 8) & 0xF) + ((outChMode >> 12) & 0xF);
1043
1044
  /* MPEG ammendment 4 aka ETSI metadata and fallback mode: */
1045
1046
  /* Create identity DMX matrix: */
1047
0
  for (outCh = 0; outCh < (8); outCh += 1) {
1048
0
    dmxInitChannel(mixFactors, mixScales, outCh);
1049
0
  }
1050
0
  if (((inChMode >> 12) & 0xF) == 0) {
1051
    /* Clear empty or wrongly mapped input channel */
1052
0
    dmxClearChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL);
1053
0
  }
1054
1055
  /* FIRST STAGE: */
1056
0
  if (numInChannel > SIX_CHANNEL) { /* Always use MPEG equations either with
1057
                                       meta data or with default values. */
1058
0
    FIXP_DMX dMixFactA, dMixFactB;
1059
0
    INT dMixScaleA, dMixScaleB;
1060
0
    int isValidCfg = TRUE;
1061
1062
    /* Get factors from meta data */
1063
0
    dMixFactA = abMixLvlValueTab[pMetaData->dmixIdxA];
1064
0
    dMixScaleA = (pMetaData->dmixIdxA == 0) ? 1 : 0;
1065
0
    dMixFactB = abMixLvlValueTab[pMetaData->dmixIdxB];
1066
0
    dMixScaleB = (pMetaData->dmixIdxB == 0) ? 1 : 0;
1067
1068
    /* Check if input is in the list of supported configurations */
1069
0
    switch (inChMode) {
1070
0
      case CH_MODE_3_2_1_1: /* chCfg 11 but with side channels */
1071
0
      case CH_MODE_3_2_1_0:
1072
0
        isValidCfg = FALSE;
1073
0
        err = PCMDMX_INVALID_MODE;
1074
0
        FDK_FALLTHROUGH;
1075
0
      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
0
        dmxClearChannel(
1080
0
            mixFactors, mixScales,
1081
0
            RIGHT_MULTIPRPS_CHANNEL); /* clear empty input channel */
1082
0
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1083
0
                      LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1084
0
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1085
0
                      LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1086
0
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1087
0
                      RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1088
0
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1089
0
                      LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1090
0
        break;
1091
0
      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
0
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1096
0
                      LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1097
0
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1098
0
                      LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1099
0
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1100
0
                      RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1101
0
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1102
0
                      RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1103
0
        break;
1104
0
      case CH_MODE_5_0_1_0:
1105
0
      case CH_MODE_5_0_1_1:
1106
0
        dmxClearChannel(mixFactors, mixScales,
1107
0
                        RIGHT_REAR_CHANNEL); /* clear empty input channel */
1108
0
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1109
0
                      LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1110
0
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1111
0
                      LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1112
0
        FDK_FALLTHROUGH;
1113
0
      case CH_MODE_5_2_1_0:
1114
0
        isValidCfg = FALSE;
1115
0
        err = PCMDMX_INVALID_MODE;
1116
0
        FDK_FALLTHROUGH;
1117
0
      case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */
1118
0
        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
0
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1123
0
                        LEFT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
1124
0
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1125
0
                        LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1126
0
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1127
0
                        RIGHT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
1128
0
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1129
0
                        RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1130
0
        } 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
0
          dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1136
0
                        LEFT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
1137
0
          dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1138
0
                        RIGHT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
1139
0
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1140
0
                        LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1141
0
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1142
0
                        LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1143
0
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1144
0
                        RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1145
0
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1146
0
                        RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1147
0
        }
1148
0
        break;
1149
0
      default:
1150
        /* Nothing to do. Just use the identity matrix. */
1151
0
        isValidCfg = FALSE;
1152
0
        err = PCMDMX_INVALID_MODE;
1153
0
        break;
1154
0
    }
1155
1156
    /* Add additional DMX gain */
1157
0
    if ((isValidCfg == TRUE) &&
1158
0
        (pMetaData->dmxGainIdx5 != 0)) { /* Apply DMX gain 5 */
1159
0
      FIXP_DMX dmxGain;
1160
0
      INT dmxScale;
1161
0
      INT sign = (pMetaData->dmxGainIdx5 & 0x40) ? -1 : 1;
1162
0
      INT val = pMetaData->dmxGainIdx5 & 0x3F;
1163
1164
      /* 10^(dmx_gain_5/80) */
1165
0
      dmxGain = FX_DBL2FX_DMX(
1166
0
          fLdPow(FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
1167
0
                 (FIXP_DBL)(sign * val * (LONG)FL2FXCONST_DBL(0.0125f)), 0,
1168
0
                 &dmxScale));
1169
      /* Currently only positive scale factors supported! */
1170
0
      if (dmxScale < 0) {
1171
0
        dmxGain >>= -dmxScale;
1172
0
        dmxScale = 0;
1173
0
      }
1174
1175
0
      dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1176
0
                    CENTER_FRONT_CHANNEL, dmxGain, dmxScale);
1177
0
      dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1178
0
                    LEFT_FRONT_CHANNEL, dmxGain, dmxScale);
1179
0
      dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1180
0
                    RIGHT_FRONT_CHANNEL, dmxGain, dmxScale);
1181
0
      dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL,
1182
0
                    dmxGain, dmxScale);
1183
0
      dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1184
0
                    RIGHT_REAR_CHANNEL, dmxGain, dmxScale);
1185
0
      dmxSetChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL,
1186
0
                    LOW_FREQUENCY_CHANNEL, dmxGain, dmxScale);
1187
0
    }
1188
1189
    /* Mark the output channels */
1190
0
    valid[CENTER_FRONT_CHANNEL] = 1;
1191
0
    valid[LEFT_FRONT_CHANNEL] = 1;
1192
0
    valid[RIGHT_FRONT_CHANNEL] = 1;
1193
0
    valid[LEFT_REAR_CHANNEL] = 1;
1194
0
    valid[RIGHT_REAR_CHANNEL] = 1;
1195
0
    valid[LOW_FREQUENCY_CHANNEL] = 1;
1196
1197
    /* Update channel mode for the next stage */
1198
0
    inChMode = CH_MODE_3_0_2_1;
1199
0
  }
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
0
#define DMX_METHOD_MPEG_AMD4 1
1207
0
#define DMX_METHOD_MPEG_LEGACY 2
1208
0
#define DMX_METHOD_ARIB_JAPAN 4
1209
0
#define DMX_METHOD_ITU_RECOM 8
1210
0
#define DMX_METHOD_CUSTOM 16
1211
1212
0
  dmxMethod = DMX_METHOD_MPEG_AMD4; /* default */
1213
1214
0
  if ((pParams->dmxProfile == DMX_PRFL_FORCE_MATRIX_MIX) &&
1215
0
      (pMetaData->typeFlags & TYPE_PCE_DATA)) {
1216
0
    dmxMethod = DMX_METHOD_MPEG_LEGACY;
1217
0
  } else if (!(pMetaData->typeFlags &
1218
0
               (TYPE_DSE_CLEV_DATA | TYPE_DSE_SLEV_DATA))) {
1219
0
    switch (pParams->dmxProfile) {
1220
0
      default:
1221
0
      case DMX_PRFL_STANDARD:
1222
        /* dmxMethod = DMX_METHOD_MPEG_AMD4; */
1223
0
        break;
1224
0
      case DMX_PRFL_MATRIX_MIX:
1225
0
      case DMX_PRFL_FORCE_MATRIX_MIX:
1226
0
        if (pMetaData->typeFlags & TYPE_PCE_DATA) {
1227
0
          dmxMethod = DMX_METHOD_MPEG_LEGACY;
1228
0
        }
1229
0
        break;
1230
0
      case DMX_PRFL_ARIB_JAPAN:
1231
0
        dmxMethod = DMX_METHOD_ARIB_JAPAN;
1232
0
        break;
1233
0
    }
1234
0
  }
1235
1236
  /* SECOND STAGE: */
1237
0
  if (numOutChannel <= TWO_CHANNEL) {
1238
    /* Create DMX matrix according to input configuration */
1239
0
    switch (inChMode) {
1240
0
      case CH_MODE_2_0_0_0: /* chCfg 2 */
1241
        /* Apply the dual channel mode. */
1242
0
        switch (pParams->dualChannelMode) {
1243
0
          case CH1_MODE: /* L' = 0.707 * Ch1;
1244
                            R' = 0.707 * Ch1; */
1245
0
            dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1246
0
                          LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1247
0
            dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1248
0
                          LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1249
0
            break;
1250
0
          case CH2_MODE: /* L' = 0.707 * Ch2;
1251
                            R' = 0.707 * Ch2; */
1252
0
            dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1253
0
                          RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1254
0
            dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1255
0
                          RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1256
0
            break;
1257
0
          case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2;
1258
                              R' = 0.5*Ch1 + 0.5*Ch2; */
1259
0
            dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1260
0
                          LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1261
0
            dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1262
0
                          RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1263
0
            dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1264
0
                          LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1265
0
            dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1266
0
                          RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0);
1267
0
            break;
1268
0
          default:
1269
0
          case STEREO_MODE:
1270
            /* Nothing to do */
1271
0
            break;
1272
0
        }
1273
0
        break;
1274
      /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1275
       * - - - - - - - - - - - - - - - - - - - */
1276
0
      case CH_MODE_2_0_1_0: {
1277
0
        FIXP_DMX sMixLvl;
1278
0
        if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1279
          /* L' = 0.707*L + 0.5*S;  R' = 0.707*R + 0.5*S; */
1280
0
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1281
0
                        LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1282
0
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1283
0
                        RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1284
0
          sMixLvl = FL2FXCONST_DMX(0.5f);
1285
0
        } else { /* L' = L + 0.707*S;  R' = R + 0.707*S; */
1286
0
          sMixLvl = FL2FXCONST_DMX(0.707f);
1287
0
        }
1288
0
        dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1289
0
                      LEFT_REAR_CHANNEL, sMixLvl, 0);
1290
0
        dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1291
0
                      LEFT_REAR_CHANNEL, sMixLvl, 0);
1292
0
      } break;
1293
      /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1294
       * - - - - - - - - - - - - - - - - - - - */
1295
0
      case CH_MODE_3_0_0_0: /* chCfg 3 */
1296
0
      {
1297
0
        FIXP_DMX cMixLvl;
1298
0
        if (dmxMethod == DMX_METHOD_ARIB_JAPAN) {
1299
          /* L' = 0.707*L + 0.5*C;  R' = 0.707*R + 0.5*C; */
1300
0
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1301
0
                        LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1302
0
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1303
0
                        RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1304
0
          cMixLvl = FL2FXCONST_DMX(0.5f);
1305
0
        } else { /* L' = L + 0.707*C;  R' = R + 0.707*C; */
1306
0
          cMixLvl = FL2FXCONST_DMX(0.707f);
1307
0
        }
1308
0
        dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1309
0
                      CENTER_FRONT_CHANNEL, cMixLvl, 0);
1310
0
        dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1311
0
                      CENTER_FRONT_CHANNEL, cMixLvl, 0);
1312
0
      } break;
1313
      /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1314
       * - - - - - - - - - - - - - - - - - - - */
1315
0
      case CH_MODE_3_0_1_0: /* chCfg 4 */
1316
0
      {
1317
0
        FIXP_DMX csMixLvl;
1318
0
        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
0
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1321
0
                        LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1322
0
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1323
0
                        RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0);
1324
0
          csMixLvl = FL2FXCONST_DMX(0.5f);
1325
0
        } else { /* L' = L + 0.707*C + 0.707*S;
1326
                    R' = R + 0.707*C + 0.707*S; */
1327
0
          csMixLvl = FL2FXCONST_DMX(0.707f);
1328
0
        }
1329
0
        dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1330
0
                      CENTER_FRONT_CHANNEL, csMixLvl, 0);
1331
0
        dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1332
0
                      LEFT_REAR_CHANNEL, csMixLvl, 0);
1333
0
        dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1334
0
                      CENTER_FRONT_CHANNEL, csMixLvl, 0);
1335
0
        dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1336
0
                      LEFT_REAR_CHANNEL, csMixLvl, 0);
1337
0
      } break;
1338
      /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1339
       * - - - - - - - - - - - - - - - - - - - */
1340
0
      case CH_MODE_3_0_2_0: /* chCfg 5 */
1341
0
      case CH_MODE_3_0_2_1: /* chCfg 6 */
1342
0
      {
1343
0
        switch (dmxMethod) {
1344
0
          default:
1345
0
          case DMX_METHOD_MPEG_AMD4: {
1346
0
            FIXP_DMX cMixLvl, sMixLvl, lMixLvl;
1347
0
            INT cMixScale, sMixScale, lMixScale;
1348
1349
            /* Get factors from meta data */
1350
0
            cMixLvl = abMixLvlValueTab[pMetaData->cLevIdx];
1351
0
            cMixScale = (pMetaData->cLevIdx == 0) ? 1 : 0;
1352
0
            sMixLvl = abMixLvlValueTab[pMetaData->sLevIdx];
1353
0
            sMixScale = (pMetaData->sLevIdx == 0) ? 1 : 0;
1354
0
            lMixLvl = lfeMixLvlValueTab[pMetaData->dmixIdxLfe];
1355
0
            if (pMetaData->dmixIdxLfe <= 1) {
1356
0
              lMixScale = 2;
1357
0
            } else if (pMetaData->dmixIdxLfe <= 5) {
1358
0
              lMixScale = 1;
1359
0
            } else {
1360
0
              lMixScale = 0;
1361
0
            }
1362
            /* Setup the DMX matrix */
1363
0
            if ((pParams->pseudoSurrMode == FORCE_PS_DMX) ||
1364
0
                ((pParams->pseudoSurrMode == AUTO_PS_DMX) &&
1365
0
                 (pMetaData->pseudoSurround ==
1366
0
                  1))) { /* L' = L + C*clev - (Ls+Rs)*slev + LFE*lflev;
1367
                            R' = R + C*clev + (Ls+Rs)*slev + LFE*lflev; */
1368
0
              dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1369
0
                            CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1370
0
              dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1371
0
                            LEFT_REAR_CHANNEL, -sMixLvl, sMixScale);
1372
0
              dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1373
0
                            RIGHT_REAR_CHANNEL, -sMixLvl, sMixScale);
1374
0
              dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1375
0
                            LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1376
0
              dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1377
0
                            CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1378
0
              dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1379
0
                            LEFT_REAR_CHANNEL, sMixLvl, sMixScale);
1380
0
              dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1381
0
                            RIGHT_REAR_CHANNEL, sMixLvl, sMixScale);
1382
0
              dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1383
0
                            LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1384
0
            } else { /* L' = L + C*clev + Ls*slev + LFE*llev;
1385
                        R' = R + C*clev + Rs*slev + LFE*llev; */
1386
0
              dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1387
0
                            CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1388
0
              dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1389
0
                            LEFT_REAR_CHANNEL, sMixLvl, sMixScale);
1390
0
              dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1391
0
                            LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1392
0
              dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1393
0
                            CENTER_FRONT_CHANNEL, cMixLvl, cMixScale);
1394
0
              dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1395
0
                            RIGHT_REAR_CHANNEL, sMixLvl, sMixScale);
1396
0
              dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1397
0
                            LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale);
1398
0
            }
1399
1400
            /* Add additional DMX gain */
1401
0
            if (pMetaData->dmxGainIdx2 != 0) { /* Apply DMX gain 2 */
1402
0
              FIXP_DMX dmxGain;
1403
0
              INT dmxScale;
1404
0
              INT sign = (pMetaData->dmxGainIdx2 & 0x40) ? -1 : 1;
1405
0
              INT val = pMetaData->dmxGainIdx2 & 0x3F;
1406
1407
              /* 10^(dmx_gain_2/80) */
1408
0
              dmxGain = FX_DBL2FX_DMX(
1409
0
                  fLdPow(FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
1410
0
                         (FIXP_DBL)(sign * val * (LONG)FL2FXCONST_DBL(0.0125f)),
1411
0
                         0, &dmxScale));
1412
              /* Currently only positive scale factors supported! */
1413
0
              if (dmxScale < 0) {
1414
0
                dmxGain >>= -dmxScale;
1415
0
                dmxScale = 0;
1416
0
              }
1417
1418
0
              dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1419
0
                            LEFT_FRONT_CHANNEL, dmxGain, dmxScale);
1420
0
              dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1421
0
                            RIGHT_FRONT_CHANNEL, dmxGain, dmxScale);
1422
0
            }
1423
0
          } break;
1424
0
          case DMX_METHOD_ARIB_JAPAN:
1425
0
          case DMX_METHOD_MPEG_LEGACY: {
1426
0
            FIXP_DMX flev, clev, slevLL, slevLR, slevRL, slevRR;
1427
0
            FIXP_DMX mtrxMixDwnCoef =
1428
0
                mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx];
1429
1430
0
            if ((pParams->pseudoSurrMode == FORCE_PS_DMX) ||
1431
0
                ((pParams->pseudoSurrMode == AUTO_PS_DMX) &&
1432
0
                 (pMetaData->pseudoSurround == 1))) {
1433
0
              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
0
                flev = mpegMixDownIdx2Coef[0]; /* a = 0.707 */
1437
0
              } 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
0
                flev = mpegMixDownIdx2PreFact[1][pMetaData->matrixMixdownIdx];
1441
0
              }
1442
0
              slevRR = slevRL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
1443
0
              slevLL = slevLR = -slevRL;
1444
0
            } else {
1445
0
              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
0
                flev = mpegMixDownIdx2Coef[0]; /* a = 0.707 */
1449
0
              } 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
0
                flev = mpegMixDownIdx2PreFact[0][pMetaData->matrixMixdownIdx];
1452
0
              }
1453
0
              slevRR = slevLL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef));
1454
0
              slevLR = slevRL = (FIXP_DMX)0;
1455
0
            }
1456
            /* common factor */
1457
0
            clev =
1458
0
                FX_DBL2FX_DMX(fMult(flev, mpegMixDownIdx2Coef[0] /* 0.707 */));
1459
1460
0
            dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1461
0
                          LEFT_FRONT_CHANNEL, flev, 0);
1462
0
            dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1463
0
                          CENTER_FRONT_CHANNEL, clev, 0);
1464
0
            dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1465
0
                          LEFT_REAR_CHANNEL, slevLL, 0);
1466
0
            dmxAddChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1467
0
                          RIGHT_REAR_CHANNEL, slevLR, 0);
1468
1469
0
            dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1470
0
                          RIGHT_FRONT_CHANNEL, flev, 0);
1471
0
            dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1472
0
                          CENTER_FRONT_CHANNEL, clev, 0);
1473
0
            dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1474
0
                          LEFT_REAR_CHANNEL, slevRL, 0);
1475
0
            dmxAddChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1476
0
                          RIGHT_REAR_CHANNEL, slevRR, 0);
1477
0
          } break;
1478
0
        } /* switch (dmxMethod) */
1479
0
      } break;
1480
0
      default:
1481
        /* This configuration does not fit to any known downmix equation! */
1482
0
        err = PCMDMX_INVALID_MODE;
1483
0
        break;
1484
0
    } /* switch (inChMode) */
1485
1486
    /* Mark the output channels */
1487
0
    FDKmemclear(valid, (8) * sizeof(unsigned int));
1488
0
    valid[LEFT_FRONT_CHANNEL] = 1;
1489
0
    valid[RIGHT_FRONT_CHANNEL] = 1;
1490
0
  }
1491
1492
0
  if (numOutChannel == ONE_CHANNEL) {
1493
0
    FIXP_DMX monoMixLevel;
1494
0
    INT monoMixScale = 0;
1495
1496
0
    dmxClearChannel(mixFactors, mixScales,
1497
0
                    CENTER_FRONT_CHANNEL); /* C is not in the mix */
1498
1499
0
    if (dmxMethod ==
1500
0
        DMX_METHOD_MPEG_LEGACY) { /* C' = (3+2*A)^-1 * [C+L+R+A*Ls+A+Rs]; */
1501
0
      monoMixLevel = mpegMixDownIdx2PreFact[2][pMetaData->matrixMixdownIdx];
1502
1503
0
      mixFactors[CENTER_FRONT_CHANNEL][CENTER_FRONT_CHANNEL] = monoMixLevel;
1504
0
      mixFactors[CENTER_FRONT_CHANNEL][LEFT_FRONT_CHANNEL] = monoMixLevel;
1505
0
      mixFactors[CENTER_FRONT_CHANNEL][RIGHT_FRONT_CHANNEL] = monoMixLevel;
1506
0
      monoMixLevel = FX_DBL2FX_DMX(fMult(
1507
0
          monoMixLevel, mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx]));
1508
0
      mixFactors[CENTER_FRONT_CHANNEL][LEFT_REAR_CHANNEL] = monoMixLevel;
1509
0
      mixFactors[CENTER_FRONT_CHANNEL][RIGHT_REAR_CHANNEL] = monoMixLevel;
1510
0
    } else {
1511
0
      switch (dmxMethod) {
1512
0
        case DMX_METHOD_MPEG_AMD4:
1513
          /* C' = L + R; */
1514
0
          monoMixLevel = FL2FXCONST_DMX(0.5f);
1515
0
          monoMixScale = 1;
1516
0
          break;
1517
0
        default:
1518
          /* C' = 0.5*L + 0.5*R; */
1519
0
          monoMixLevel = FL2FXCONST_DMX(0.5f);
1520
0
          monoMixScale = 0;
1521
0
          break;
1522
0
      }
1523
0
      dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1524
0
                    LEFT_FRONT_CHANNEL, monoMixLevel, monoMixScale);
1525
0
      dmxAddChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1526
0
                    RIGHT_FRONT_CHANNEL, monoMixLevel, monoMixScale);
1527
0
    }
1528
1529
    /* Mark the output channel */
1530
0
    FDKmemclear(valid, (8) * sizeof(unsigned int));
1531
0
    valid[CENTER_FRONT_CHANNEL] = 1;
1532
0
  }
1533
1534
0
#define MAX_SEARCH_START_VAL (-7)
1535
1536
0
  {
1537
0
    LONG chSum[(8)];
1538
0
    INT chSumMax = MAX_SEARCH_START_VAL;
1539
1540
    /* Determine the current maximum scale factor */
1541
0
    for (outCh = 0; outCh < (8); outCh += 1) {
1542
0
      if (valid[outCh] != 0) {
1543
0
        unsigned int inCh;
1544
0
        for (inCh = 0; inCh < (8); inCh += 1) {
1545
0
          if (mixScales[outCh][inCh] > maxScale) { /* Store the new maximum */
1546
0
            maxScale = mixScales[outCh][inCh];
1547
0
          }
1548
0
        }
1549
0
      }
1550
0
    }
1551
1552
    /* Individualy analyse output chanal levels */
1553
0
    for (outCh = 0; outCh < (8); outCh += 1) {
1554
0
      chSum[outCh] = MAX_SEARCH_START_VAL;
1555
0
      if (valid[outCh] != 0) {
1556
0
        int ovrflwProtScale = 0;
1557
0
        unsigned int inCh;
1558
1559
        /* Accumulate all factors for each output channel */
1560
0
        chSum[outCh] = 0;
1561
0
        for (inCh = 0; inCh < (8); inCh += 1) {
1562
0
          SHORT addFact = FX_DMX2SHRT(mixFactors[outCh][inCh]);
1563
0
          if (mixScales[outCh][inCh] <= maxScale) {
1564
0
            addFact >>= maxScale - mixScales[outCh][inCh];
1565
0
          } else {
1566
0
            addFact <<= mixScales[outCh][inCh] - maxScale;
1567
0
          }
1568
0
          chSum[outCh] += addFact;
1569
0
        }
1570
0
        if (chSum[outCh] > (LONG)MAXVAL_SGL) {
1571
0
          while (chSum[outCh] > (LONG)MAXVAL_SGL) {
1572
0
            ovrflwProtScale += 1;
1573
0
            chSum[outCh] >>= 1;
1574
0
          }
1575
0
        } else if (chSum[outCh] > 0) {
1576
0
          while ((chSum[outCh] << 1) <= (LONG)MAXVAL_SGL) {
1577
0
            ovrflwProtScale -= 1;
1578
0
            chSum[outCh] <<= 1;
1579
0
          }
1580
0
        }
1581
        /* Store the differential scaling in the same array */
1582
0
        chSum[outCh] = ovrflwProtScale;
1583
0
      }
1584
0
    }
1585
1586
0
    for (outCh = 0; outCh < (8); outCh += 1) {
1587
0
      if ((valid[outCh] != 0) &&
1588
0
          (chSum[outCh] > chSumMax)) { /* Store the new maximum */
1589
0
        chSumMax = chSum[outCh];
1590
0
      }
1591
0
    }
1592
0
    maxScale = fMax(maxScale + chSumMax, 0);
1593
1594
    /* Normalize all factors */
1595
0
    for (outCh = 0; outCh < (8); outCh += 1) {
1596
0
      if (valid[outCh] != 0) {
1597
0
        unsigned int inCh;
1598
0
        for (inCh = 0; inCh < (8); inCh += 1) {
1599
0
          if (mixFactors[outCh][inCh] != (FIXP_DMX)0) {
1600
0
            if (mixScales[outCh][inCh] <= maxScale) {
1601
0
              mixFactors[outCh][inCh] >>= maxScale - mixScales[outCh][inCh];
1602
0
            } else {
1603
0
              mixFactors[outCh][inCh] <<= mixScales[outCh][inCh] - maxScale;
1604
0
            }
1605
0
            mixScales[outCh][inCh] = maxScale;
1606
0
          }
1607
0
        }
1608
0
      }
1609
0
    }
1610
0
  }
1611
1612
  /* return the scale factor */
1613
0
  *pOutScale = maxScale;
1614
1615
0
  return (err);
1616
0
}
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
 **/
1622
7.15k
PCMDMX_ERROR pcmDmx_Open(HANDLE_PCM_DOWNMIX *pSelf) {
1623
7.15k
  HANDLE_PCM_DOWNMIX self;
1624
1625
7.15k
  if (pSelf == NULL) {
1626
0
    return (PCMDMX_INVALID_HANDLE);
1627
0
  }
1628
1629
7.15k
  *pSelf = NULL;
1630
1631
7.15k
  self = (HANDLE_PCM_DOWNMIX)GetPcmDmxInstance(0);
1632
7.15k
  if (self == NULL) {
1633
0
    return (PCMDMX_OUT_OF_MEMORY);
1634
0
  }
1635
1636
  /* Reset the full instance */
1637
7.15k
  pcmDmx_Reset(self, PCMDMX_RESET_FULL);
1638
1639
7.15k
  *pSelf = self;
1640
1641
7.15k
  return (PCMDMX_OK);
1642
7.15k
}
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
 **/
1649
12.9k
PCMDMX_ERROR pcmDmx_Reset(HANDLE_PCM_DOWNMIX self, UINT flags) {
1650
12.9k
  if (self == NULL) {
1651
0
    return (PCMDMX_INVALID_HANDLE);
1652
0
  }
1653
1654
12.9k
  if (flags & PCMDMX_RESET_PARAMS) {
1655
7.15k
    PCM_DMX_USER_PARAMS *pParams = &self->userParams;
1656
1657
7.15k
    pParams->dualChannelMode = STEREO_MODE;
1658
7.15k
    pParams->pseudoSurrMode = NEVER_DO_PS_DMX;
1659
7.15k
    pParams->numOutChannelsMax = (6);
1660
7.15k
    pParams->numOutChannelsMin = (0);
1661
7.15k
    pParams->frameDelay = 0;
1662
7.15k
    pParams->expiryFrame = (0);
1663
1664
7.15k
    self->applyProcessing = 0;
1665
7.15k
  }
1666
1667
12.9k
  if (flags & PCMDMX_RESET_BS_DATA) {
1668
12.9k
    int slot;
1669
    /* Init all slots with a default set */
1670
38.9k
    for (slot = 0; slot <= (1); slot += 1) {
1671
25.9k
      FDKmemcpy(&self->bsMetaData[slot], &dfltMetaData,
1672
25.9k
                sizeof(DMX_BS_META_DATA));
1673
25.9k
    }
1674
12.9k
  }
1675
1676
12.9k
  return (PCMDMX_OK);
1677
12.9k
}
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
 **/
1685
PCMDMX_ERROR pcmDmx_SetParam(HANDLE_PCM_DOWNMIX self, const PCMDMX_PARAM param,
1686
15.3k
                             const INT value) {
1687
15.3k
  switch (param) {
1688
0
    case DMX_PROFILE_SETTING:
1689
0
      switch ((DMX_PROFILE_TYPE)value) {
1690
0
        case DMX_PRFL_STANDARD:
1691
0
        case DMX_PRFL_MATRIX_MIX:
1692
0
        case DMX_PRFL_FORCE_MATRIX_MIX:
1693
0
        case DMX_PRFL_ARIB_JAPAN:
1694
0
          break;
1695
0
        default:
1696
0
          return (PCMDMX_UNABLE_TO_SET_PARAM);
1697
0
      }
1698
0
      if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1699
0
      self->userParams.dmxProfile = (DMX_PROFILE_TYPE)value;
1700
0
      break;
1701
1702
5.73k
    case DMX_BS_DATA_EXPIRY_FRAME:
1703
5.73k
      if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1704
5.73k
      self->userParams.expiryFrame = (value > 0) ? (UINT)value : 0;
1705
5.73k
      break;
1706
1707
9.59k
    case DMX_BS_DATA_DELAY:
1708
9.59k
      if ((value > (1)) || (value < 0)) {
1709
0
        return (PCMDMX_UNABLE_TO_SET_PARAM);
1710
0
      }
1711
9.59k
      if (self == NULL) {
1712
0
        return (PCMDMX_INVALID_HANDLE);
1713
0
      }
1714
9.59k
      self->userParams.frameDelay = (UCHAR)value;
1715
9.59k
      break;
1716
1717
0
    case MIN_NUMBER_OF_OUTPUT_CHANNELS:
1718
0
      switch (value) { /* supported output channels */
1719
0
        case -1:
1720
0
        case 0:
1721
0
        case ONE_CHANNEL:
1722
0
        case TWO_CHANNEL:
1723
0
        case SIX_CHANNEL:
1724
0
        case EIGHT_CHANNEL:
1725
0
          break;
1726
0
        default:
1727
0
          return (PCMDMX_UNABLE_TO_SET_PARAM);
1728
0
      }
1729
0
      if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1730
      /* Store the new value */
1731
0
      self->userParams.numOutChannelsMin = (value > 0) ? (SHORT)value : -1;
1732
0
      if ((value > 0) && (self->userParams.numOutChannelsMax > 0) &&
1733
0
          (value > self->userParams
1734
0
                       .numOutChannelsMax)) { /* MIN > MAX would be an invalid
1735
                                                 state. Thus set MAX = MIN in
1736
                                                 this case. */
1737
0
        self->userParams.numOutChannelsMax = self->userParams.numOutChannelsMin;
1738
0
      }
1739
0
      break;
1740
1741
0
    case MAX_NUMBER_OF_OUTPUT_CHANNELS:
1742
0
      switch (value) { /* supported output channels */
1743
0
        case -1:
1744
0
        case 0:
1745
0
        case ONE_CHANNEL:
1746
0
        case TWO_CHANNEL:
1747
0
        case SIX_CHANNEL:
1748
0
        case EIGHT_CHANNEL:
1749
0
          break;
1750
0
        default:
1751
0
          return (PCMDMX_UNABLE_TO_SET_PARAM);
1752
0
      }
1753
0
      if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1754
      /* Store the new value */
1755
0
      self->userParams.numOutChannelsMax = (value > 0) ? (SHORT)value : -1;
1756
0
      if ((value > 0) &&
1757
0
          (value < self->userParams
1758
0
                       .numOutChannelsMin)) { /* MAX < MIN would be an invalid
1759
                                                 state. Thus set MIN = MAX in
1760
                                                 this case. */
1761
0
        self->userParams.numOutChannelsMin = self->userParams.numOutChannelsMax;
1762
0
      }
1763
0
      break;
1764
1765
0
    case DMX_DUAL_CHANNEL_MODE:
1766
0
      switch ((DUAL_CHANNEL_MODE)value) {
1767
0
        case STEREO_MODE:
1768
0
        case CH1_MODE:
1769
0
        case CH2_MODE:
1770
0
        case MIXED_MODE:
1771
0
          break;
1772
0
        default:
1773
0
          return (PCMDMX_UNABLE_TO_SET_PARAM);
1774
0
      }
1775
0
      if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1776
0
      self->userParams.dualChannelMode = (DUAL_CHANNEL_MODE)value;
1777
0
      self->applyProcessing = ((DUAL_CHANNEL_MODE)value != STEREO_MODE)
1778
0
                                  ? 1
1779
0
                                  : 0; /* Force processing if necessary. */
1780
0
      break;
1781
1782
0
    case DMX_PSEUDO_SURROUND_MODE:
1783
0
      switch ((PSEUDO_SURROUND_MODE)value) {
1784
0
        case NEVER_DO_PS_DMX:
1785
0
        case AUTO_PS_DMX:
1786
0
        case FORCE_PS_DMX:
1787
0
          break;
1788
0
        default:
1789
0
          return (PCMDMX_UNABLE_TO_SET_PARAM);
1790
0
      }
1791
0
      if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1792
0
      self->userParams.pseudoSurrMode = (PSEUDO_SURROUND_MODE)value;
1793
0
      break;
1794
1795
0
    default:
1796
0
      return (PCMDMX_UNKNOWN_PARAM);
1797
15.3k
  }
1798
1799
15.3k
  return (PCMDMX_OK);
1800
15.3k
}
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
 **/
1808
PCMDMX_ERROR pcmDmx_GetParam(HANDLE_PCM_DOWNMIX self, const PCMDMX_PARAM param,
1809
3.76k
                             INT *const pValue) {
1810
3.76k
  PCM_DMX_USER_PARAMS *pUsrParams;
1811
1812
3.76k
  if ((self == NULL) || (pValue == NULL)) {
1813
0
    return (PCMDMX_INVALID_HANDLE);
1814
0
  }
1815
3.76k
  pUsrParams = &self->userParams;
1816
1817
3.76k
  switch (param) {
1818
0
    case DMX_PROFILE_SETTING:
1819
0
      *pValue = (INT)pUsrParams->dmxProfile;
1820
0
      break;
1821
0
    case DMX_BS_DATA_EXPIRY_FRAME:
1822
0
      *pValue = (INT)pUsrParams->expiryFrame;
1823
0
      break;
1824
0
    case DMX_BS_DATA_DELAY:
1825
0
      *pValue = (INT)pUsrParams->frameDelay;
1826
0
      break;
1827
3.76k
    case MIN_NUMBER_OF_OUTPUT_CHANNELS:
1828
3.76k
      *pValue = (INT)pUsrParams->numOutChannelsMin;
1829
3.76k
      break;
1830
0
    case MAX_NUMBER_OF_OUTPUT_CHANNELS:
1831
0
      *pValue = (INT)pUsrParams->numOutChannelsMax;
1832
0
      break;
1833
0
    case DMX_DUAL_CHANNEL_MODE:
1834
0
      *pValue = (INT)pUsrParams->dualChannelMode;
1835
0
      break;
1836
0
    case DMX_PSEUDO_SURROUND_MODE:
1837
0
      *pValue = (INT)pUsrParams->pseudoSurrMode;
1838
0
      break;
1839
0
    default:
1840
0
      return (PCMDMX_UNKNOWN_PARAM);
1841
3.76k
  }
1842
1843
3.76k
  return (PCMDMX_OK);
1844
3.76k
}
1845
1846
/*
1847
 * Read DMX meta-data from a data stream element.
1848
 */
1849
PCMDMX_ERROR pcmDmx_Parse(HANDLE_PCM_DOWNMIX self, HANDLE_FDK_BITSTREAM hBs,
1850
0
                          UINT ancDataBits, int isMpeg2) {
1851
0
  PCMDMX_ERROR errorStatus = PCMDMX_OK;
1852
1853
0
#define MAX_DSE_ANC_BYTES (16)    /* 15 bytes */
1854
0
#define ANC_DATA_SYNC_BYTE (0xBC) /* ancillary data sync byte. */
1855
1856
0
  DMX_BS_META_DATA *pBsMetaData;
1857
1858
0
  int skip4Dmx = 0, skip4Ext = 0;
1859
0
  int dmxLvlAvail = 0, extDataAvail = 0;
1860
0
  UINT foundNewData = 0;
1861
0
  UINT minAncBits = ((isMpeg2) ? 5 : 3) * 8;
1862
1863
0
  if ((self == NULL) || (hBs == NULL)) {
1864
0
    return (PCMDMX_INVALID_HANDLE);
1865
0
  }
1866
1867
  /* sanity checks */
1868
0
  if ((ancDataBits < minAncBits) || (ancDataBits > FDKgetValidBits(hBs))) {
1869
0
    return (PCMDMX_CORRUPT_ANC_DATA);
1870
0
  }
1871
1872
0
  pBsMetaData = &self->bsMetaData[0];
1873
1874
0
  if (isMpeg2) {
1875
    /* skip DVD ancillary data */
1876
0
    FDKpushFor(hBs, 16);
1877
0
  }
1878
1879
  /* check sync word */
1880
0
  if (FDKreadBits(hBs, 8) != ANC_DATA_SYNC_BYTE) {
1881
0
    return (PCMDMX_CORRUPT_ANC_DATA);
1882
0
  }
1883
1884
  /* skip MPEG audio type and Dolby surround mode */
1885
0
  FDKpushFor(hBs, 4);
1886
1887
0
  if (isMpeg2) {
1888
0
    /* int numAncBytes = */ FDKreadBits(hBs, 4);
1889
    /* advanced dynamic range control */
1890
0
    if (FDKreadBit(hBs)) skip4Dmx += 24;
1891
    /* dialog normalization */
1892
0
    if (FDKreadBit(hBs)) skip4Dmx += 8;
1893
    /* reproduction_level */
1894
0
    if (FDKreadBit(hBs)) skip4Dmx += 8;
1895
0
  } else {
1896
0
    FDKpushFor(hBs, 2); /* drc presentation mode */
1897
0
    pBsMetaData->pseudoSurround = (SCHAR)FDKreadBit(hBs);
1898
0
    FDKpushFor(hBs, 4); /* reserved bits */
1899
0
  }
1900
1901
  /* downmixing levels MPEGx status */
1902
0
  dmxLvlAvail = FDKreadBit(hBs);
1903
1904
0
  if (isMpeg2) {
1905
    /* scale factor CRC status */
1906
0
    if (FDKreadBit(hBs)) skip4Ext += 16;
1907
0
  } else {
1908
    /* ancillary data extension status */
1909
0
    extDataAvail = FDKreadBit(hBs);
1910
0
  }
1911
1912
  /* audio coding and compression status */
1913
0
  if (FDKreadBit(hBs)) skip4Ext += 16;
1914
  /* coarse grain timecode status */
1915
0
  if (FDKreadBit(hBs)) skip4Ext += 16;
1916
  /* fine grain timecode status */
1917
0
  if (FDKreadBit(hBs)) skip4Ext += 16;
1918
1919
  /* skip the useless data to get to the DMX levels */
1920
0
  FDKpushFor(hBs, skip4Dmx);
1921
1922
  /* downmix_levels_MPEGX */
1923
0
  if (dmxLvlAvail) {
1924
0
    if (FDKreadBit(hBs)) { /* center_mix_level_on */
1925
0
      pBsMetaData->cLevIdx = (UCHAR)FDKreadBits(hBs, 3);
1926
0
      foundNewData |= TYPE_DSE_CLEV_DATA;
1927
0
    } else {
1928
0
      FDKreadBits(hBs, 3);
1929
0
    }
1930
0
    if (FDKreadBit(hBs)) { /* surround_mix_level_on */
1931
0
      pBsMetaData->sLevIdx = (UCHAR)FDKreadBits(hBs, 3);
1932
0
      foundNewData |= TYPE_DSE_SLEV_DATA;
1933
0
    } else {
1934
0
      FDKreadBits(hBs, 3);
1935
0
    }
1936
0
  }
1937
1938
  /* skip the useless data to get to the ancillary data extension */
1939
0
  FDKpushFor(hBs, skip4Ext);
1940
1941
  /* anc data extension (MPEG-4 only) */
1942
0
  if (extDataAvail) {
1943
0
    int extDmxLvlSt, extDmxGainSt, extDmxLfeSt;
1944
1945
0
    FDKreadBit(hBs); /* reserved bit */
1946
0
    extDmxLvlSt = FDKreadBit(hBs);
1947
0
    extDmxGainSt = FDKreadBit(hBs);
1948
0
    extDmxLfeSt = FDKreadBit(hBs);
1949
0
    FDKreadBits(hBs, 4); /* reserved bits */
1950
1951
0
    if (extDmxLvlSt) {
1952
0
      pBsMetaData->dmixIdxA = (UCHAR)FDKreadBits(hBs, 3);
1953
0
      pBsMetaData->dmixIdxB = (UCHAR)FDKreadBits(hBs, 3);
1954
0
      FDKreadBits(hBs, 2); /* reserved bits */
1955
0
      foundNewData |= TYPE_DSE_DMIX_AB_DATA;
1956
0
    }
1957
0
    if (extDmxGainSt) {
1958
0
      pBsMetaData->dmxGainIdx5 = (UCHAR)FDKreadBits(hBs, 7);
1959
0
      FDKreadBit(hBs); /* reserved bit */
1960
0
      pBsMetaData->dmxGainIdx2 = (UCHAR)FDKreadBits(hBs, 7);
1961
0
      FDKreadBit(hBs); /* reserved bit */
1962
0
      foundNewData |= TYPE_DSE_DMX_GAIN_DATA;
1963
0
    }
1964
0
    if (extDmxLfeSt) {
1965
0
      pBsMetaData->dmixIdxLfe = (UCHAR)FDKreadBits(hBs, 4);
1966
0
      FDKreadBits(hBs, 4); /* reserved bits */
1967
0
      foundNewData |= TYPE_DSE_DMIX_LFE_DATA;
1968
0
    }
1969
0
  }
1970
1971
  /* final sanity check on the amount of read data */
1972
0
  if ((INT)FDKgetValidBits(hBs) < 0) {
1973
0
    errorStatus = PCMDMX_CORRUPT_ANC_DATA;
1974
0
  }
1975
1976
0
  if ((errorStatus == PCMDMX_OK) && (foundNewData != 0)) {
1977
    /* announce new data */
1978
0
    pBsMetaData->typeFlags |= foundNewData;
1979
    /* reset expiry counter */
1980
0
    pBsMetaData->expiryCount = 0;
1981
0
  }
1982
1983
0
  return (errorStatus);
1984
0
}
1985
1986
/*
1987
 * Read DMX meta-data from a data stream element.
1988
 */
1989
PCMDMX_ERROR pcmDmx_ReadDvbAncData(HANDLE_PCM_DOWNMIX self, UCHAR *pAncDataBuf,
1990
0
                                   UINT ancDataBytes, int isMpeg2) {
1991
0
  PCMDMX_ERROR errorStatus = PCMDMX_OK;
1992
0
  FDK_BITSTREAM bs;
1993
0
  HANDLE_FDK_BITSTREAM hBs = &bs;
1994
1995
0
  if (self == NULL) {
1996
0
    return (PCMDMX_INVALID_HANDLE);
1997
0
  }
1998
1999
  /* sanity checks */
2000
0
  if ((pAncDataBuf == NULL) || (ancDataBytes == 0)) {
2001
0
    return (PCMDMX_CORRUPT_ANC_DATA);
2002
0
  }
2003
2004
0
  FDKinitBitStream(hBs, pAncDataBuf, MAX_DSE_ANC_BYTES, ancDataBytes * 8,
2005
0
                   BS_READER);
2006
2007
0
  errorStatus = pcmDmx_Parse(self, hBs, ancDataBytes * 8, isMpeg2);
2008
2009
0
  return (errorStatus);
2010
0
}
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
 **/
2019
PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce(HANDLE_PCM_DOWNMIX self,
2020
                                            int matrixMixdownPresent,
2021
                                            int matrixMixdownIdx,
2022
323
                                            int pseudoSurroundEnable) {
2023
323
  if (self == NULL) {
2024
0
    return (PCMDMX_INVALID_HANDLE);
2025
0
  }
2026
2027
323
  {
2028
323
    DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0];
2029
2030
323
    if (matrixMixdownPresent) {
2031
47
      pBsMetaData->pseudoSurround = (pseudoSurroundEnable) ? 1 : 0;
2032
47
      pBsMetaData->matrixMixdownIdx = matrixMixdownIdx & 0x03;
2033
47
      pBsMetaData->typeFlags |= TYPE_PCE_DATA;
2034
      /* Reset expiry counter */
2035
47
      pBsMetaData->expiryCount = 0;
2036
47
    }
2037
323
  }
2038
2039
323
  return (PCMDMX_OK);
2040
323
}
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
 **/
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
0
                               INT *pDmxOutScale) {
2067
0
  PCM_DMX_USER_PARAMS *pParam = NULL;
2068
0
  PCMDMX_ERROR errorStatus = PCMDMX_OK;
2069
0
  DUAL_CHANNEL_MODE dualChannelMode;
2070
0
  PCM_DMX_CHANNEL_MODE inChMode;
2071
0
  PCM_DMX_CHANNEL_MODE outChMode;
2072
0
  INT devNull; /* Just a dummy to avoid a lot of branches in the code */
2073
0
  int numOutChannels, numInChannels;
2074
0
  int inStride, outStride, offset;
2075
0
  int dmxMaxScale, dmxScale;
2076
0
  int slot;
2077
0
  UCHAR inOffsetTable[(8)];
2078
2079
0
  DMX_BS_META_DATA bsMetaData;
2080
2081
0
  if ((self == NULL) || (nChannels == NULL) || (channelType == NULL) ||
2082
0
      (channelIndices == NULL) || (!FDK_chMapDescr_isValid(mapDescr))) {
2083
0
    return (PCMDMX_INVALID_HANDLE);
2084
0
  }
2085
2086
  /* Init the output scaling */
2087
0
  dmxScale = 0;
2088
0
  if (pDmxOutScale != NULL) {
2089
    /* Avoid final scaling internally and hand it to the outside world. */
2090
0
    *pDmxOutScale = 0;
2091
0
    dmxMaxScale = (3);
2092
0
  } else {
2093
    /* Apply the scaling internally. */
2094
0
    pDmxOutScale = &devNull; /* redirect to temporal stack memory */
2095
0
    dmxMaxScale = 0;
2096
0
  }
2097
2098
0
  pParam = &self->userParams;
2099
0
  numInChannels = *nChannels;
2100
2101
  /* Perform some input sanity checks */
2102
0
  if (pPcmBuf == NULL) {
2103
0
    return (PCMDMX_INVALID_ARGUMENT);
2104
0
  }
2105
0
  if (frameSize == 0) {
2106
0
    return (PCMDMX_INVALID_ARGUMENT);
2107
0
  }
2108
0
  if (numInChannels == 0) {
2109
0
    return (PCMDMX_INVALID_ARGUMENT);
2110
0
  }
2111
0
  if (numInChannels > (8)) {
2112
0
    return (PCMDMX_INVALID_CH_CONFIG);
2113
0
  }
2114
2115
  /* Check on misconfiguration */
2116
0
  FDK_ASSERT((pParam->numOutChannelsMax <= 0) ||
2117
0
             (pParam->numOutChannelsMax >= pParam->numOutChannelsMin));
2118
2119
  /* Determine if the module has to do processing */
2120
0
  if ((self->applyProcessing == 0) &&
2121
0
      ((pParam->numOutChannelsMax <= 0) ||
2122
0
       (pParam->numOutChannelsMax >= numInChannels)) &&
2123
0
      (pParam->numOutChannelsMin <= numInChannels)) {
2124
    /* Nothing to do */
2125
0
    return (errorStatus);
2126
0
  }
2127
2128
  /* Determine the number of output channels */
2129
0
  if ((pParam->numOutChannelsMax > 0) &&
2130
0
      (numInChannels > pParam->numOutChannelsMax)) {
2131
0
    numOutChannels = pParam->numOutChannelsMax;
2132
0
  } else if (numInChannels < pParam->numOutChannelsMin) {
2133
0
    numOutChannels = pParam->numOutChannelsMin;
2134
0
  } else {
2135
0
    numOutChannels = numInChannels;
2136
0
  }
2137
2138
  /* Check I/O buffer size */
2139
0
  if ((UINT)pcmBufSize < (UINT)numOutChannels * frameSize) {
2140
0
    return (PCMDMX_OUTPUT_BUFFER_TOO_SMALL);
2141
0
  }
2142
2143
0
  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
0
  errorStatus = getChannelMode(numInChannels, channelType, channelIndices,
2148
0
                               inOffsetTable, &inChMode);
2149
0
  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
0
    return (PCMDMX_INVALID_CH_CONFIG);
2153
0
  }
2154
2155
  /* Set input stride and offset */
2156
0
  if (fInterleaved) {
2157
0
    inStride = numInChannels;
2158
0
    offset = 1; /* Channel specific offset factor */
2159
0
  } else {
2160
0
    inStride = 1;
2161
0
    offset = frameSize; /* Channel specific offset factor */
2162
0
  }
2163
2164
  /* Reset downmix meta data if necessary */
2165
0
  if ((pParam->expiryFrame > 0) &&
2166
0
      (++self->bsMetaData[0].expiryCount >
2167
0
       pParam
2168
0
           ->expiryFrame)) { /* The metadata read from bitstream is too old. */
2169
0
#ifdef FDK_ASSERT_ENABLE
2170
0
    PCMDMX_ERROR err = pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
2171
0
    FDK_ASSERT(err == PCMDMX_OK);
2172
#else
2173
    pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
2174
#endif
2175
0
  }
2176
0
  FDKmemcpy(&bsMetaData, &self->bsMetaData[pParam->frameDelay],
2177
0
            sizeof(DMX_BS_META_DATA));
2178
  /* Maintain delay line */
2179
0
  for (slot = pParam->frameDelay; slot > 0; slot -= 1) {
2180
0
    FDKmemcpy(&self->bsMetaData[slot], &self->bsMetaData[slot - 1],
2181
0
              sizeof(DMX_BS_META_DATA));
2182
0
  }
2183
2184
  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2185
   * - - - - - - - - - - - - - - - - - - */
2186
0
  if (numInChannels > numOutChannels) { /* Apply downmix */
2187
0
    DMX_PCM *pInPcm[(8)] = {NULL};
2188
0
    DMX_PCM *pOutPcm[(8)] = {NULL};
2189
0
    FIXP_DMX mixFactors[(8)][(8)];
2190
0
    UCHAR outOffsetTable[(8)];
2191
0
    UINT sample;
2192
0
    int chCfg = 0;
2193
0
    int bypScale = 0;
2194
2195
0
    if (numInChannels > SIX_CHANNEL) {
2196
0
      AUDIO_CHANNEL_TYPE multiPurposeChType[2];
2197
2198
      /* Get the type of the multipurpose channels */
2199
0
      multiPurposeChType[0] =
2200
0
          channelType[inOffsetTable[LEFT_MULTIPRPS_CHANNEL]];
2201
0
      multiPurposeChType[1] =
2202
0
          channelType[inOffsetTable[RIGHT_MULTIPRPS_CHANNEL]];
2203
2204
      /* Check if the input configuration is one defined in the standard. */
2205
0
      switch (inChMode) {
2206
0
        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
0
          if ((multiPurposeChType[0] == ACT_FRONT_TOP) &&
2210
0
              (multiPurposeChType[1] == ACT_FRONT_TOP)) {
2211
0
            chCfg = 14;
2212
0
          } else {
2213
0
            chCfg = 7;
2214
0
          }
2215
0
          break;
2216
0
        case CH_MODE_3_0_3_1: /* chCfg 11 */
2217
0
          chCfg = 11;
2218
0
          break;
2219
0
        case CH_MODE_3_0_4_1: /* chCfg 12 */
2220
0
          chCfg = 12;
2221
0
          break;
2222
0
        default:
2223
0
          chCfg = 0; /* Not a known config */
2224
0
          break;
2225
0
      }
2226
0
    }
2227
2228
    /* Set this stages output stride and channel mode: */
2229
0
    outStride = (fInterleaved) ? numOutChannels : 1;
2230
0
    outChMode = outChModeTable[numOutChannels];
2231
0
    FDK_ASSERT(outChMode != CH_MODE_UNDEFINED);
2232
2233
    /* Get channel description and channel mapping for the desired output
2234
     * configuration. */
2235
0
    getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
2236
0
                          outOffsetTable);
2237
    /* Now there is no way back because we modified the channel configuration!
2238
     */
2239
2240
    /* Create the DMX matrix */
2241
0
    errorStatus =
2242
0
        getMixFactors((chCfg > 0) ? 1 : 0,
2243
0
                      (chCfg > 0) ? (PCM_DMX_CHANNEL_MODE)chCfg : inChMode,
2244
0
                      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
0
    bypScale = fMin(dmxMaxScale, dmxScale);
2251
0
    *pDmxOutScale += bypScale;
2252
0
    dmxScale -= bypScale;
2253
2254
0
    { /* Set channel pointer for input. Remove empty cols. */
2255
0
      int inCh, outCh, map[(8)];
2256
0
      int ch = 0;
2257
0
      for (inCh = 0; inCh < (8); inCh += 1) {
2258
0
        if (inOffsetTable[inCh] < (UCHAR)numInChannels) {
2259
0
          pInPcm[ch] = &pPcmBuf[inOffsetTable[inCh] * offset];
2260
0
          map[ch++] = inCh;
2261
0
        }
2262
0
      }
2263
0
      for (; ch < (8); ch += 1) {
2264
0
        map[ch] = ch;
2265
0
      }
2266
2267
      /* Remove unused cols from factor matrix */
2268
0
      for (inCh = 0; inCh < numInChannels; inCh += 1) {
2269
0
        if (inCh != map[inCh]) {
2270
0
          for (outCh = 0; outCh < (8); outCh += 1) {
2271
0
            mixFactors[outCh][inCh] = mixFactors[outCh][map[inCh]];
2272
0
          }
2273
0
        }
2274
0
      }
2275
2276
      /* Set channel pointer for output. Remove empty cols. */
2277
0
      ch = 0;
2278
0
      for (outCh = 0; outCh < (8); outCh += 1) {
2279
0
        if (outOffsetTable[outCh] < (UCHAR)numOutChannels) {
2280
0
          pOutPcm[ch] = &pPcmBuf[outOffsetTable[outCh] * offset];
2281
0
          map[ch++] = outCh;
2282
0
        }
2283
0
      }
2284
0
      for (; ch < (8); ch += 1) {
2285
0
        map[ch] = ch;
2286
0
      }
2287
2288
      /* Remove unused rows from factor matrix */
2289
0
      for (outCh = 0; outCh < numOutChannels; outCh += 1) {
2290
0
        if (outCh != map[outCh]) {
2291
0
          FDKmemcpy(&mixFactors[outCh], &mixFactors[map[outCh]],
2292
0
                    (8) * sizeof(FIXP_DMX));
2293
0
        }
2294
0
      }
2295
0
    }
2296
2297
    /* Sample processing loop */
2298
0
    for (sample = 0; sample < frameSize; sample++) {
2299
0
      DMX_PCM tIn[(8)] = {0};
2300
0
      FIXP_DBL tOut[(8)] = {(FIXP_DBL)0};
2301
0
      int inCh, outCh;
2302
2303
      /* Preload all input samples */
2304
0
      for (inCh = 0; inCh < numInChannels; inCh += 1) {
2305
0
        if (pInPcm[inCh] != NULL) {
2306
0
          tIn[inCh] = *pInPcm[inCh];
2307
0
          pInPcm[inCh] += inStride;
2308
0
        } else {
2309
0
          tIn[inCh] = (DMX_PCM)0;
2310
0
        }
2311
0
      }
2312
      /* Apply downmix coefficients to input samples and accumulate for output
2313
       */
2314
0
      for (outCh = 0; outCh < numOutChannels; outCh += 1) {
2315
0
        for (inCh = 0; inCh < numInChannels; inCh += 1) {
2316
0
          tOut[outCh] += fMult((DMX_PCMF)tIn[inCh], mixFactors[outCh][inCh]);
2317
0
        }
2318
0
        FDK_ASSERT(pOutPcm[outCh] >= pPcmBuf);
2319
0
        FDK_ASSERT(pOutPcm[outCh] < &pPcmBuf[pcmBufSize]);
2320
        /* Write sample */
2321
0
        *pOutPcm[outCh] = (DMX_PCM)SATURATE_SHIFT(
2322
0
            tOut[outCh], DFRACT_BITS - DMX_PCM_BITS - dmxScale, DMX_PCM_BITS);
2323
0
        pOutPcm[outCh] += outStride;
2324
0
      }
2325
0
    }
2326
2327
    /* Update the number of output channels */
2328
0
    *nChannels = numOutChannels;
2329
2330
0
  } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2331
       - - - - - - - - - - - - - - - - - - */
2332
0
  else if (numInChannels < numOutChannels) { /* Apply rudimentary upmix */
2333
    /* Set up channel pointer */
2334
0
    UCHAR outOffsetTable[(8)];
2335
2336
    /* FIRST STAGE
2337
         Create a stereo/dual channel signal */
2338
0
    if (numInChannels == ONE_CHANNEL) {
2339
0
      DMX_PCM *pInPcm[(8)];
2340
0
      DMX_PCM *pOutLF, *pOutRF;
2341
0
      UINT sample;
2342
2343
      /* Set this stages output stride and channel mode: */
2344
0
      outStride = (fInterleaved) ? TWO_CHANNEL : 1;
2345
0
      outChMode = outChModeTable[TWO_CHANNEL];
2346
2347
      /* Get channel description and channel mapping for this
2348
       * stages number of output channels (always STEREO). */
2349
0
      getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
2350
0
                            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
0
      pInPcm[CENTER_FRONT_CHANNEL] =
2356
0
          &pPcmBuf[(frameSize - 1) *
2357
0
                   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
0
      pOutLF = &pPcmBuf[outOffsetTable[LEFT_FRONT_CHANNEL] * offset +
2363
0
                        (frameSize - 1) * outStride];
2364
0
      pOutRF = &pPcmBuf[outOffsetTable[RIGHT_FRONT_CHANNEL] * offset +
2365
0
                        (frameSize - 1) * outStride];
2366
2367
      /* 1/0 input: */
2368
0
      for (sample = 0; sample < frameSize; sample++) {
2369
        /* L' = C;  R' = C; */
2370
0
        *pOutLF = *pOutRF = *pInPcm[CENTER_FRONT_CHANNEL];
2371
2372
0
        pInPcm[CENTER_FRONT_CHANNEL] -= inStride;
2373
0
        pOutLF -= outStride;
2374
0
        pOutRF -= outStride;
2375
0
      }
2376
2377
      /* Prepare for next stage: */
2378
0
      inStride = outStride;
2379
0
      inChMode = outChMode;
2380
0
      FDKmemcpy(inOffsetTable, outOffsetTable, (8) * sizeof(UCHAR));
2381
0
    }
2382
2383
    /* SECOND STAGE
2384
         Extend with zero channels to achieved the desired number of output
2385
       channels. */
2386
0
    if (numOutChannels > TWO_CHANNEL) {
2387
0
      DMX_PCM *pIn[(8)] = {NULL};
2388
0
      DMX_PCM *pOut[(8)] = {NULL};
2389
0
      UINT sample;
2390
0
      AUDIO_CHANNEL_TYPE inChTypes[(8)];
2391
0
      UCHAR inChIndices[(8)];
2392
0
      UCHAR numChPerGrp[2][(4)];
2393
0
      int nContentCh = 0; /* Number of channels with content */
2394
0
      int nEmptyCh = 0;   /* Number of channels with content */
2395
0
      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
0
      FDKmemcpy(inChTypes, channelType,
2400
0
                numInChannels * sizeof(AUDIO_CHANNEL_TYPE));
2401
0
      FDKmemclear(inChTypes + numInChannels,
2402
0
                  ((8) - numInChannels) * sizeof(AUDIO_CHANNEL_TYPE));
2403
0
      FDKmemcpy(inChIndices, channelIndices, numInChannels * sizeof(UCHAR));
2404
0
      FDKmemclear(inChIndices + numInChannels,
2405
0
                  ((8) - numInChannels) * sizeof(UCHAR));
2406
2407
      /* Set this stages output stride and channel mode: */
2408
0
      outStride = (fInterleaved) ? numOutChannels : 1;
2409
0
      outChMode = outChModeTable[numOutChannels];
2410
0
      FDK_ASSERT(outChMode != CH_MODE_UNDEFINED);
2411
2412
      /* Check if input channel config can be easily mapped to the desired
2413
       * output config. */
2414
0
      for (chGrp = 0; chGrp < (4); chGrp += 1) {
2415
0
        numChPerGrp[IN][chGrp] = (inChMode >> (chGrp * 4)) & 0xF;
2416
0
        numChPerGrp[OUT][chGrp] = (outChMode >> (chGrp * 4)) & 0xF;
2417
2418
0
        if (numChPerGrp[IN][chGrp] > numChPerGrp[OUT][chGrp]) {
2419
0
          isCompatible = 0;
2420
0
          break;
2421
0
        }
2422
0
      }
2423
2424
0
      if (isCompatible) {
2425
        /* Get new channel description and channel
2426
         * mapping for the desired output channel mode. */
2427
0
        getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
2428
0
                              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
0
        if ((numChPerGrp[IN][CH_GROUP_REAR] % 2) &&
2432
0
            !(numChPerGrp[OUT][CH_GROUP_REAR] % 2)) {
2433
0
          if (numChPerGrp[IN][CH_GROUP_REAR] == 1) {
2434
0
            inOffsetTable[RIGHT_REAR_CHANNEL] =
2435
0
                inOffsetTable[LEFT_REAR_CHANNEL];
2436
0
          } else if (numChPerGrp[IN][CH_GROUP_REAR] == 3) {
2437
0
            inOffsetTable[RIGHT_MULTIPRPS_CHANNEL] =
2438
0
                inOffsetTable[LEFT_MULTIPRPS_CHANNEL];
2439
0
          }
2440
0
        }
2441
0
      } else {
2442
        /* Just copy and extend the original config */
2443
0
        FDKmemcpy(outOffsetTable, inOffsetTable, (8) * sizeof(UCHAR));
2444
0
      }
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
0
      for (ch = 0; ch < (8); ch += 1) {
2450
0
        if ((outOffsetTable[ch] < 255) &&
2451
0
            (inOffsetTable[ch] < 255)) { /* Set I/O pointer: */
2452
0
          pIn[nContentCh] =
2453
0
              &pPcmBuf[inOffsetTable[ch] * offset + (frameSize - 1) * inStride];
2454
0
          pOut[nContentCh] = &pPcmBuf[outOffsetTable[ch] * offset +
2455
0
                                      (frameSize - 1) * outStride];
2456
          /* Update signalling */
2457
0
          channelType[outOffsetTable[ch]] = inChTypes[inOffsetTable[ch]];
2458
0
          channelIndices[outOffsetTable[ch]] = inChIndices[inOffsetTable[ch]];
2459
0
          inOffsetTable[ch] = 255;
2460
0
          outOffsetTable[ch] = 255;
2461
0
          nContentCh += 1;
2462
0
        }
2463
0
      }
2464
0
      if (isCompatible) {
2465
        /* Assign the remaining input channels.
2466
           This is just a safety appliance. We should never need it. */
2467
0
        for (ch = 0; ch < (8); ch += 1) {
2468
0
          if (inOffsetTable[ch] < 255) {
2469
0
            int outCh;
2470
0
            for (outCh = 0; outCh < (8); outCh += 1) {
2471
0
              if (outOffsetTable[outCh] < 255) {
2472
0
                break;
2473
0
              }
2474
0
            }
2475
0
            if (outCh >= (8)) {
2476
0
              FDK_ASSERT(0);
2477
0
              break;
2478
0
            }
2479
            /* Set I/O pointer: */
2480
0
            pIn[nContentCh] = &pPcmBuf[inOffsetTable[ch] * offset +
2481
0
                                       (frameSize - 1) * inStride];
2482
0
            pOut[nContentCh] = &pPcmBuf[outOffsetTable[outCh] * offset +
2483
0
                                        (frameSize - 1) * outStride];
2484
            /* Update signalling */
2485
0
            FDK_ASSERT(inOffsetTable[outCh] < numInChannels);
2486
0
            FDK_ASSERT(outOffsetTable[outCh] < numOutChannels);
2487
0
            channelType[outOffsetTable[outCh]] = inChTypes[inOffsetTable[ch]];
2488
0
            channelIndices[outOffsetTable[outCh]] =
2489
0
                inChIndices[inOffsetTable[ch]];
2490
0
            inOffsetTable[ch] = 255;
2491
0
            outOffsetTable[outCh] = 255;
2492
0
            nContentCh += 1;
2493
0
          }
2494
0
        }
2495
        /* Set the remaining output channel pointer */
2496
0
        for (ch = 0; ch < (8); ch += 1) {
2497
0
          if (outOffsetTable[ch] < 255) {
2498
0
            pOut[nContentCh + nEmptyCh] = &pPcmBuf[outOffsetTable[ch] * offset +
2499
0
                                                   (frameSize - 1) * outStride];
2500
            /* Expand output signalling */
2501
0
            channelType[outOffsetTable[ch]] = ACT_NONE;
2502
0
            channelIndices[outOffsetTable[ch]] = (UCHAR)nEmptyCh;
2503
0
            outOffsetTable[ch] = 255;
2504
0
            nEmptyCh += 1;
2505
0
          }
2506
0
        }
2507
0
      } else {
2508
        /* Set the remaining output channel pointer */
2509
0
        for (ch = nContentCh; ch < numOutChannels; ch += 1) {
2510
0
          pOut[ch] = &pPcmBuf[ch * offset + (frameSize - 1) * outStride];
2511
          /* Expand output signalling */
2512
0
          channelType[ch] = ACT_NONE;
2513
0
          channelIndices[ch] = (UCHAR)nEmptyCh;
2514
0
          nEmptyCh += 1;
2515
0
        }
2516
0
      }
2517
2518
      /* First copy the channels that have signal */
2519
0
      for (sample = 0; sample < frameSize; sample += 1) {
2520
0
        DMX_PCM tIn[(8)];
2521
        /* Read all channel samples */
2522
0
        for (ch = 0; ch < nContentCh; ch += 1) {
2523
0
          tIn[ch] = *pIn[ch];
2524
0
          pIn[ch] -= inStride;
2525
0
        }
2526
        /* Write all channel samples */
2527
0
        for (ch = 0; ch < nContentCh; ch += 1) {
2528
0
          *pOut[ch] = tIn[ch];
2529
0
          pOut[ch] -= outStride;
2530
0
        }
2531
0
      }
2532
2533
      /* Clear all the other channels */
2534
0
      for (sample = 0; sample < frameSize; sample++) {
2535
0
        for (ch = nContentCh; ch < numOutChannels; ch += 1) {
2536
0
          *pOut[ch] = (DMX_PCM)0;
2537
0
          pOut[ch] -= outStride;
2538
0
        }
2539
0
      }
2540
0
    }
2541
2542
    /* update the number of output channels */
2543
0
    *nChannels = numOutChannels;
2544
0
  } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2545
       - - - - - - - - - - - - - - - - - - */
2546
0
  else if (numInChannels == numOutChannels) {
2547
    /* Don't need to change the channel description here */
2548
2549
0
    switch (numInChannels) {
2550
0
      case 2: { /* Set up channel pointer */
2551
0
        DMX_PCM *pInPcm[(8)];
2552
0
        DMX_PCM *pOutL, *pOutR;
2553
0
        FIXP_DMX flev;
2554
2555
0
        UINT sample;
2556
2557
0
        if (fInterleaved) {
2558
0
          inStride = numInChannels;
2559
0
          outStride =
2560
0
              2; /* fixed !!! (below stereo is donwmixed to mono if required */
2561
0
          offset = 1; /* Channel specific offset factor */
2562
0
        } else {
2563
0
          inStride = 1;
2564
0
          outStride = 1;
2565
0
          offset = frameSize; /* Channel specific offset factor */
2566
0
        }
2567
2568
        /* Set input channel pointer */
2569
0
        pInPcm[LEFT_FRONT_CHANNEL] =
2570
0
            &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL] * offset];
2571
0
        pInPcm[RIGHT_FRONT_CHANNEL] =
2572
0
            &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL] * offset];
2573
2574
        /* Set output channel pointer (same as input) */
2575
0
        pOutL = pInPcm[LEFT_FRONT_CHANNEL];
2576
0
        pOutR = pInPcm[RIGHT_FRONT_CHANNEL];
2577
2578
        /* Set downmix levels: */
2579
0
        flev = FL2FXCONST_DMX(0.70710678f);
2580
        /* 2/0 input: */
2581
0
        switch (dualChannelMode) {
2582
0
          case CH1_MODE: /* L' = 0.707 * Ch1;  R' = 0.707 * Ch1 */
2583
0
            for (sample = 0; sample < frameSize; sample++) {
2584
0
              *pOutL = *pOutR = (DMX_PCM)SATURATE_RIGHT_SHIFT(
2585
0
                  fMult((DMX_PCMF)*pInPcm[LEFT_FRONT_CHANNEL], flev),
2586
0
                  DFRACT_BITS - DMX_PCM_BITS, DMX_PCM_BITS);
2587
2588
0
              pInPcm[LEFT_FRONT_CHANNEL] += inStride;
2589
0
              pOutL += outStride;
2590
0
              pOutR += outStride;
2591
0
            }
2592
0
            break;
2593
0
          case CH2_MODE: /* L' = 0.707 * Ch2;  R' = 0.707 * Ch2 */
2594
0
            for (sample = 0; sample < frameSize; sample++) {
2595
0
              *pOutL = *pOutR = (DMX_PCM)SATURATE_RIGHT_SHIFT(
2596
0
                  fMult((DMX_PCMF)*pInPcm[RIGHT_FRONT_CHANNEL], flev),
2597
0
                  DFRACT_BITS - DMX_PCM_BITS, DMX_PCM_BITS);
2598
2599
0
              pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
2600
0
              pOutL += outStride;
2601
0
              pOutR += outStride;
2602
0
            }
2603
0
            break;
2604
0
          case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2;  R' = 0.5*Ch1 + 0.5*Ch2 */
2605
0
            for (sample = 0; sample < frameSize; sample++) {
2606
0
              *pOutL = *pOutR = (*pInPcm[LEFT_FRONT_CHANNEL] >> 1) +
2607
0
                                (*pInPcm[RIGHT_FRONT_CHANNEL] >> 1);
2608
2609
0
              pInPcm[LEFT_FRONT_CHANNEL] += inStride;
2610
0
              pInPcm[RIGHT_FRONT_CHANNEL] += inStride;
2611
0
              pOutL += outStride;
2612
0
              pOutR += outStride;
2613
0
            }
2614
0
            break;
2615
0
          default:
2616
0
          case STEREO_MODE:
2617
            /* nothing to do */
2618
0
            break;
2619
0
        }
2620
0
      } break;
2621
2622
0
      default:
2623
        /* nothing to do */
2624
0
        break;
2625
0
    }
2626
0
  }
2627
2628
0
  return (errorStatus);
2629
0
}
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
 **/
2635
7.15k
PCMDMX_ERROR pcmDmx_Close(HANDLE_PCM_DOWNMIX *pSelf) {
2636
7.15k
  if (pSelf == NULL) {
2637
0
    return (PCMDMX_INVALID_HANDLE);
2638
0
  }
2639
2640
7.15k
  FreePcmDmxInstance(pSelf);
2641
7.15k
  *pSelf = NULL;
2642
2643
7.15k
  return (PCMDMX_OK);
2644
7.15k
}
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
 */
2650
0
PCMDMX_ERROR pcmDmx_GetLibInfo(LIB_INFO *info) {
2651
0
  int i;
2652
2653
0
  if (info == NULL) {
2654
0
    return PCMDMX_INVALID_ARGUMENT;
2655
0
  }
2656
2657
  /* Search for next free tab */
2658
0
  for (i = 0; i < FDK_MODULE_LAST; i++) {
2659
0
    if (info[i].module_id == FDK_NONE) break;
2660
0
  }
2661
0
  if (i == FDK_MODULE_LAST) {
2662
0
    return PCMDMX_INVALID_ARGUMENT;
2663
0
  }
2664
2665
  /* Add the library info */
2666
0
  info[i].module_id = FDK_PCMDMX;
2667
0
  info[i].version =
2668
0
      LIB_VERSION(PCMUTIL_LIB_VL0, PCMUTIL_LIB_VL1, PCMUTIL_LIB_VL2);
2669
0
  LIB_VERSION_STRING(info + i);
2670
0
  info[i].build_date = PCMUTIL_LIB_BUILD_DATE;
2671
0
  info[i].build_time = PCMUTIL_LIB_BUILD_TIME;
2672
0
  info[i].title = PCMDMX_LIB_TITLE;
2673
2674
  /* Set flags */
2675
0
  info[i].flags = 0 | CAPF_DMX_BLIND /* At least blind downmixing is possible */
2676
0
                  | CAPF_DMX_PCE     /* Guided downmix with data from MPEG-2/4
2677
                                        Program Config Elements (PCE). */
2678
0
                  | CAPF_DMX_ARIB /* PCE guided downmix with slightly different
2679
                                     equations and levels. */
2680
0
                  | CAPF_DMX_DVB  /* Guided downmix with data from DVB ancillary
2681
                                     data fields. */
2682
0
                  | CAPF_DMX_CH_EXP /* Simple upmixing by dublicating channels
2683
                                       or adding zero channels. */
2684
0
                  | CAPF_DMX_6_CH | CAPF_DMX_8_CH;
2685
2686
  /* Add lib info for FDK tools (if not yet done). */
2687
0
  FDK_toolsGetLibInfo(info);
2688
2689
0
  return PCMDMX_OK;
2690
0
}