Coverage Report

Created: 2026-04-12 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aac/libPCMutils/src/pcmdmx_lib.cpp
Line
Count
Source
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
281k
#define FALSE 0
116
317k
#define TRUE 1
117
0
#define IN 0
118
0
#define OUT 1
119
120
/* Type definitions: */
121
36.1k
#define FIXP_DMX FIXP_SGL
122
#define FX_DMX2FX_DBL(x) FX_SGL2FX_DBL((FIXP_SGL)(x))
123
94.9k
#define FX_DBL2FX_DMX(x) FX_DBL2FX_SGL(x)
124
1.15M
#define FL2FXCONST_DMX(x) FL2FXCONST_SGL(x)
125
#define MAXVAL_DMX MAXVAL_SGL
126
860k
#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
71.6k
#define CH_GROUP_FRONT (0)
132
35.8k
#define CH_GROUP_SIDE (1)
133
35.8k
#define CH_GROUP_REAR (2)
134
35.8k
#define CH_GROUP_LFE (3)
135
136
/* Fixed and unique channel plain indices. */
137
53.7k
#define CH_PLAIN_NORMAL (0)
138
35.8k
#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
47.0k
#define CENTER_FRONT_CHANNEL (0) /* C  */
145
77.6k
#define LEFT_FRONT_CHANNEL (1)   /* L  */
146
59.6k
#define RIGHT_FRONT_CHANNEL (2)  /* R  */
147
#define LEFT_REAR_CHANNEL \
148
49.1k
  (3) /* Lr (aka left back channel) or center back channel */
149
31.2k
#define RIGHT_REAR_CHANNEL (4)      /* Rr (aka right back channel) */
150
54.4k
#define LOW_FREQUENCY_CHANNEL (5)   /* Lf */
151
61.3k
#define LEFT_MULTIPRPS_CHANNEL (6)  /* Left multipurpose channel */
152
41.0k
#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
17.9k
#define ONE_CHANNEL (1)
174
17.9k
#define TWO_CHANNEL (2)
175
35.8k
#define SIX_CHANNEL (6)
176
0
#define EIGHT_CHANNEL (8)
177
#define TWENTY_FOUR_CHANNEL (24)
178
179
140k
#define PCMDMX_THRESHOLD_MAP_HEAT_1 (0) /* Store only exact matches */
180
32.1k
#define PCMDMX_THRESHOLD_MAP_HEAT_2 (20)
181
#define PCMDMX_THRESHOLD_MAP_HEAT_3 \
182
33.4k
  (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
17.9k
#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
5.50k
#define TYPE_PCE_DATA (0x01)
328
19.9k
#define TYPE_DSE_CLEV_DATA (0x02)
329
18.6k
#define TYPE_DSE_SLEV_DATA (0x04)
330
1.00k
#define TYPE_DSE_DMIX_AB_DATA (0x08)
331
1.47k
#define TYPE_DSE_DMIX_LFE_DATA (0x10)
332
1.28k
#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
47.7k
C_ALLOC_MEM(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1)
GetPcmDmxInstance(int)
Line
Count
Source
385
C_ALLOC_MEM(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1)
FreePcmDmxInstance(PCM_DMX_INSTANCE**)
Line
Count
Source
385
C_ALLOC_MEM(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1)
386
387
static UINT getSpeakerDistance(PCM_DMX_SPEAKER_POSITION posA,
388
556k
                               PCM_DMX_SPEAKER_POSITION posB) {
389
556k
  PCM_DMX_SPEAKER_POSITION diff;
390
391
556k
  diff.x = posA.x - posB.x;
392
556k
  diff.y = posA.y - posB.y;
393
556k
  diff.z = posA.z - posB.z;
394
395
556k
  return ((diff.x * diff.x) + (diff.y * diff.y) + (diff.z * diff.z));
396
556k
}
397
398
static PCM_DMX_SPEAKER_POSITION getSpeakerPos(AUDIO_CHANNEL_TYPE chType,
399
140k
                                              UCHAR chIndex, UCHAR numChInGrp) {
400
140k
#define PCMDMX_SPKR_POS_X_MAX_WIDTH (3)
401
140k
#define PCMDMX_SPKR_POS_Y_SPREAD (2)
402
140k
#define PCMDMX_SPKR_POS_Z_SPREAD (2)
403
404
140k
  PCM_DMX_SPEAKER_POSITION spkrPos = {0, 0, 0};
405
140k
  AUDIO_CHANNEL_TYPE chGrp = (AUDIO_CHANNEL_TYPE)(chType & 0x0F);
406
140k
  unsigned fHasCenter = numChInGrp & 0x1;
407
140k
  unsigned chGrpWidth = numChInGrp >> 1;
408
140k
  unsigned fIsCenter = 0;
409
140k
  unsigned fIsLfe = (chType == ACT_LFE) ? 1 : 0;
410
140k
  int offset = 0;
411
412
140k
  FDK_ASSERT(chIndex < numChInGrp);
413
414
140k
  if ((chGrp == ACT_FRONT) && fHasCenter) {
415
64.2k
    if (chIndex == 0) fIsCenter = 1;
416
64.2k
    chIndex = (UCHAR)fMax(0, chIndex - 1);
417
76.6k
  } else if (fHasCenter && (chIndex == numChInGrp - 1)) {
418
20.3k
    fIsCenter = 1;
419
20.3k
  }
420
  /* now all even indices are left (-) */
421
140k
  if (!fIsCenter) {
422
102k
    offset = chIndex >> 1;
423
102k
    if ((chGrp > ACT_FRONT) && (chType != ACT_SIDE) && !fIsLfe) {
424
      /* the higher the index the lower the distance to the center position */
425
39.5k
      offset = chGrpWidth - fHasCenter - offset;
426
39.5k
    }
427
102k
    if ((chIndex & 0x1) == 0) { /* even */
428
51.3k
      offset = -(offset + 1);
429
51.3k
    } else {
430
51.3k
      offset += 1;
431
51.3k
    }
432
102k
  }
433
  /* apply the offset */
434
140k
  if (chType == ACT_SIDE) {
435
2
    spkrPos.x = (offset < 0) ? -PCMDMX_SPKR_POS_X_MAX_WIDTH
436
2
                             : PCMDMX_SPKR_POS_X_MAX_WIDTH;
437
2
    spkrPos.y = /* 1x */ PCMDMX_SPKR_POS_Y_SPREAD + (SCHAR)fAbs(offset) - 1;
438
2
    spkrPos.z = 0;
439
140k
  } else {
440
140k
    unsigned spread =
441
140k
        ((chGrpWidth == 1) && (!fIsLfe)) ? PCMDMX_SPKR_POS_X_MAX_WIDTH - 1 : 1;
442
140k
    spkrPos.x = (SCHAR)offset * (SCHAR)spread;
443
140k
    if (fIsLfe) {
444
17.9k
      spkrPos.y = 0;
445
17.9k
      spkrPos.z = SP_Z_LFE;
446
123k
    } else {
447
123k
      spkrPos.y = (SCHAR)fMax((SCHAR)chGrp - 1, 0) * PCMDMX_SPKR_POS_Y_SPREAD;
448
123k
      spkrPos.z = (SCHAR)chType >> 4;
449
123k
      if (spkrPos.z == 2) { /* ACT_BOTTOM */
450
0
        spkrPos.z = -1;
451
0
      }
452
123k
      spkrPos.z *= PCMDMX_SPKR_POS_Z_SPREAD;
453
123k
    }
454
140k
  }
455
140k
  return spkrPos;
456
140k
}
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
17.9k
    const int chCfg) {
471
17.9k
  PCM_DMX_CHANNEL_MODE plainChMode = totChMode;
472
473
17.9k
  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
17.9k
    default:
491
17.9k
      break;
492
17.9k
  }
493
494
17.9k
  return plainChMode;
495
17.9k
}
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
62.1k
                            const UCHAR channelIndices[]) {
513
203k
  for (UINT reqValue = 0; reqValue < numChannelsPlaneAndGrp; reqValue++) {
514
140k
    int found = FALSE;
515
1.25M
    for (UINT i = 0; i < numChannels; i++) {
516
1.11M
      if (channelType[i] == aChType) {
517
402k
        if (channelIndices[i] == reqValue) {
518
140k
          if (found == TRUE) {
519
1
            return 0; /* Found channel index a second time */
520
140k
          } else {
521
140k
            found = TRUE; /* Found channel index */
522
140k
          }
523
140k
        }
524
402k
      }
525
1.11M
    }
526
140k
    if (found == FALSE) {
527
1
      return 0; /* Did not find channel index */
528
1
    }
529
140k
  }
530
62.1k
  return 1; /* Successfully validated channel indices */
531
62.1k
}
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
17.9k
) {
553
17.9k
  UCHAR numCh[(3)][(4)];
554
17.9k
  UCHAR mapped[(8)];
555
17.9k
  PCM_DMX_SPEAKER_POSITION spkrPos[(8)];
556
17.9k
  PCMDMX_ERROR err = PCMDMX_OK;
557
17.9k
  unsigned ch, numMappedInChs = 0;
558
17.9k
  unsigned startSlot;
559
17.9k
  unsigned stopSlot = LOW_FREQUENCY_CHANNEL;
560
561
17.9k
  FDK_ASSERT(channelType != NULL);
562
17.9k
  FDK_ASSERT(channelIndices != NULL);
563
17.9k
  FDK_ASSERT(offsetTable != NULL);
564
17.9k
  FDK_ASSERT(chMode != NULL);
565
566
  /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */
567
17.9k
  FDKmemclear(numCh, (3) * (4) * sizeof(UCHAR));
568
17.9k
  FDKmemclear(mapped, (8) * sizeof(UCHAR));
569
17.9k
  FDKmemclear(spkrPos, (8) * sizeof(PCM_DMX_SPEAKER_POSITION));
570
  /* Init output */
571
17.9k
  FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
572
17.9k
  *chMode = CH_MODE_UNDEFINED;
573
574
  /* Determine how many channels are assigned to each channels each group: */
575
158k
  for (ch = 0; ch < numChannels; ch += 1) {
576
140k
    unsigned chGrp = fMax(
577
140k
        (channelType[ch] & 0x0F) - 1,
578
140k
        0); /* Assign all undefined channels (ACT_NONE) to front channels. */
579
140k
    numCh[channelType[ch] >> 4][chGrp] += 1;
580
140k
  }
581
582
17.9k
  {
583
17.9k
    int chGrp;
584
    /* Sanity check on the indices */
585
89.5k
    for (chGrp = 0; chGrp < (4); chGrp += 1) {
586
71.6k
      int plane;
587
286k
      for (plane = 0; plane < (3); plane += 1) {
588
215k
        if (numCh[plane][chGrp] == 0) continue;
589
62.1k
        AUDIO_CHANNEL_TYPE aChType =
590
62.1k
            (AUDIO_CHANNEL_TYPE)((plane << 4) | ((chGrp + 1) & 0xF));
591
62.1k
        if (!validateIndices(numChannels, numCh[plane][chGrp], aChType,
592
62.1k
                             channelType, channelIndices)) {
593
2
          unsigned idxCnt = 0;
594
16
          for (ch = 0; ch < numChannels; ch += 1) {
595
14
            if (channelType[ch] == aChType) {
596
9
              channelIndices[ch] = idxCnt++;
597
9
            }
598
14
          }
599
2
          err = PCMDMX_INVALID_CH_CONFIG;
600
2
        }
601
62.1k
      }
602
71.6k
    }
603
17.9k
  }
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
158k
  for (ch = 0; ch < numChannels; ch += 1) {
608
140k
    UINT mapDist = (unsigned)-1;
609
140k
    unsigned mapCh, mapPos = (unsigned)-1;
610
140k
    unsigned chGrp = fMax(
611
140k
        (channelType[ch] & 0x0F) - 1,
612
140k
        0); /* Assign all undefined channels (ACT_NONE) to front channels. */
613
614
140k
    spkrPos[ch] = getSpeakerPos(channelType[ch], channelIndices[ch],
615
140k
                                numCh[channelType[ch] >> 4][chGrp]);
616
617
986k
    for (mapCh = 0; mapCh <= stopSlot; mapCh += 1) {
618
845k
      if (offsetTable[mapCh] == 255) {
619
459k
        UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
620
459k
        if (dist < mapDist) {
621
226k
          mapPos = mapCh;
622
226k
          mapDist = dist;
623
226k
        }
624
459k
      }
625
845k
    }
626
140k
    if (mapDist <= PCMDMX_THRESHOLD_MAP_HEAT_1) {
627
75.3k
      offsetTable[mapPos] = (UCHAR)ch;
628
75.3k
      mapped[ch] = 1;
629
75.3k
      numMappedInChs += 1;
630
75.3k
    }
631
140k
  }
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
17.9k
  startSlot =
638
17.9k
      ((numCh[CH_PLAIN_NORMAL][CH_GROUP_FRONT] & 0x1) || (numChannels >= (8)))
639
17.9k
          ? 0
640
17.9k
          : 1;
641
158k
  for (ch = 0; ch < (unsigned)numChannels; ch += 1) {
642
140k
    if (!mapped[ch]) {
643
65.6k
      UINT mapDist = (unsigned)-1;
644
65.6k
      unsigned mapCh, mapPos = (unsigned)-1;
645
646
459k
      for (mapCh = startSlot; mapCh <= stopSlot; mapCh += 1) {
647
393k
        if (offsetTable[mapCh] == 255) {
648
48.2k
          UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
649
48.2k
          if (dist < mapDist) {
650
32.1k
            mapPos = mapCh;
651
32.1k
            mapDist = dist;
652
32.1k
          }
653
48.2k
        }
654
393k
      }
655
65.6k
      if ((mapPos <= stopSlot) && (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_2) &&
656
32.1k
          (((spkrPos[ch].x != 0) && (spkrSlotPos[mapPos].x != 0)) /* XOR */
657
0
           || ((spkrPos[ch].x == 0) &&
658
0
               (spkrSlotPos[mapPos].x ==
659
32.1k
                0)))) { /* Assign center channels to center slots only. */
660
32.1k
        offsetTable[mapPos] = (UCHAR)ch;
661
32.1k
        mapped[ch] = 1;
662
32.1k
        numMappedInChs += 1;
663
32.1k
      }
664
65.6k
    }
665
140k
  }
666
667
  /* Mapping HEAT 3:
668
   *   Assign the rest by searching for the nearest input channel for each
669
   * internal slot. */
670
158k
  for (ch = startSlot; (ch < (8)) && (numMappedInChs < numChannels); ch += 1) {
671
140k
    if (offsetTable[ch] == 255) {
672
33.4k
      UINT mapDist = (unsigned)-1;
673
33.4k
      unsigned mapCh, mapPos = (unsigned)-1;
674
675
298k
      for (mapCh = 0; mapCh < (unsigned)numChannels; mapCh += 1) {
676
265k
        if (!mapped[mapCh]) {
677
48.9k
          UINT dist = getSpeakerDistance(spkrPos[mapCh], spkrSlotPos[ch]);
678
48.9k
          if (dist < mapDist) {
679
33.4k
            mapPos = mapCh;
680
33.4k
            mapDist = dist;
681
33.4k
          }
682
48.9k
        }
683
265k
      }
684
33.4k
      if (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_3) {
685
33.4k
        offsetTable[ch] = (UCHAR)mapPos;
686
33.4k
        mapped[mapPos] = 1;
687
33.4k
        numMappedInChs += 1;
688
33.4k
        if ((spkrPos[mapPos].x == 0) && (spkrSlotPos[ch].x != 0) &&
689
2.38k
            (numChannels <
690
2.38k
             (8))) { /* Skip the paired slot if we assigned a center channel. */
691
2.38k
          ch += 1;
692
2.38k
        }
693
33.4k
      }
694
33.4k
    }
695
140k
  }
696
697
  /* Finaly compose the channel mode */
698
89.5k
  for (ch = 0; ch < (4); ch += 1) {
699
71.6k
    int plane, numChInGrp = 0;
700
286k
    for (plane = 0; plane < (3); plane += 1) {
701
215k
      numChInGrp += numCh[plane][ch];
702
215k
    }
703
71.6k
    *chMode = (PCM_DMX_CHANNEL_MODE)(*chMode | (numChInGrp << (ch * 4)));
704
71.6k
  }
705
706
17.9k
  return err;
707
17.9k
}
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
17.9k
) {
729
17.9k
  int grpIdx, plainIdx, numPlains = 1, numTotalChannels = 0;
730
17.9k
  int chCfg, ch = 0;
731
732
17.9k
  FDK_ASSERT(channelType != NULL);
733
17.9k
  FDK_ASSERT(channelIndices != NULL);
734
17.9k
  FDK_ASSERT(mapDescr != NULL);
735
17.9k
  FDK_ASSERT(offsetTable != NULL);
736
737
  /* Init output arrays */
738
17.9k
  FDKmemclear(channelType, (8) * sizeof(AUDIO_CHANNEL_TYPE));
739
17.9k
  FDKmemclear(channelIndices, (8) * sizeof(UCHAR));
740
17.9k
  FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
741
742
  /* Summerize to get the total number of channels */
743
89.5k
  for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
744
71.6k
    numTotalChannels += (chMode >> (grpIdx * 4)) & 0xF;
745
71.6k
  }
746
747
  /* Get the appropriate channel map */
748
17.9k
  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
17.9k
    case CH_MODE_3_0_2_1:
755
17.9k
      chCfg = numTotalChannels;
756
17.9k
      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
17.9k
  }
771
772
  /* Compose channel offset table */
773
774
35.8k
  for (plainIdx = 0; plainIdx < numPlains; plainIdx += 1) {
775
17.9k
    PCM_DMX_CHANNEL_MODE plainChMode;
776
17.9k
    UCHAR numChInGrp[(4)];
777
778
17.9k
    plainChMode = getChMode4Plain(plainIdx, chMode, chCfg);
779
780
    /* Extract the number of channels per group */
781
17.9k
    numChInGrp[CH_GROUP_FRONT] = plainChMode & 0xF;
782
17.9k
    numChInGrp[CH_GROUP_SIDE] = (plainChMode >> 4) & 0xF;
783
17.9k
    numChInGrp[CH_GROUP_REAR] = (plainChMode >> 8) & 0xF;
784
17.9k
    numChInGrp[CH_GROUP_LFE] = (plainChMode >> 12) & 0xF;
785
786
    /* Non-symmetric channels */
787
17.9k
    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
17.9k
      int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
791
17.9k
      offsetTable[CENTER_FRONT_CHANNEL] = (UCHAR)mappedIdx;
792
17.9k
      channelType[mappedIdx] = ACT_FRONT;
793
17.9k
      channelIndices[mappedIdx] = 0;
794
17.9k
      ch += 1;
795
17.9k
    }
796
797
89.5k
    for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
798
71.6k
      AUDIO_CHANNEL_TYPE type = ACT_NONE;
799
71.6k
      int chMapPos = 0, maxChannels = 0;
800
71.6k
      int chIdx = 0; /* Index of channel within the specific group */
801
802
71.6k
      switch (grpIdx) {
803
17.9k
        case CH_GROUP_FRONT:
804
17.9k
          type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_FRONT);
805
17.9k
          switch (plainIdx) {
806
17.9k
            default:
807
17.9k
              chMapPos = LEFT_FRONT_CHANNEL;
808
17.9k
              chIdx = numChInGrp[grpIdx] & 0x1;
809
17.9k
              break;
810
17.9k
          }
811
17.9k
          maxChannels = 3;
812
17.9k
          break;
813
17.9k
        case CH_GROUP_SIDE:
814
          /* Always map side channels to the multipurpose group. */
815
17.9k
          type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_SIDE);
816
17.9k
          if (plainIdx == CH_PLAIN_TOP) {
817
0
            chMapPos = LEFT_SIDE_CHANNEL_TOP;
818
0
            maxChannels = 3;
819
17.9k
          } else {
820
17.9k
            chMapPos = LEFT_MULTIPRPS_CHANNEL;
821
17.9k
            maxChannels = 2;
822
17.9k
          }
823
17.9k
          break;
824
17.9k
        case CH_GROUP_REAR:
825
17.9k
          type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_BACK);
826
17.9k
          if (plainIdx == CH_PLAIN_TOP) {
827
0
            chMapPos = LEFT_REAR_CHANNEL_TOP;
828
0
            maxChannels = 3;
829
17.9k
          } else {
830
17.9k
            chMapPos = LEFT_REAR_CHANNEL;
831
17.9k
            maxChannels = 2;
832
17.9k
          }
833
17.9k
          break;
834
17.9k
        case CH_GROUP_LFE:
835
17.9k
          if (plainIdx == CH_PLAIN_NORMAL) {
836
17.9k
            type = ACT_LFE;
837
17.9k
            chMapPos = LOW_FREQUENCY_CHANNEL;
838
17.9k
            maxChannels = 1;
839
17.9k
          }
840
17.9k
          break;
841
0
        default:
842
0
          break;
843
71.6k
      }
844
845
      /* Map all channels in this group */
846
161k
      for (; chIdx < numChInGrp[grpIdx]; chIdx += 1) {
847
89.5k
        int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
848
89.5k
        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
89.5k
        offsetTable[chMapPos] = (UCHAR)mappedIdx;
858
89.5k
        channelType[mappedIdx] = type;
859
89.5k
        channelIndices[mappedIdx] = (UCHAR)chIdx;
860
89.5k
        chMapPos += 1;
861
89.5k
        ch += 1;
862
89.5k
      }
863
71.6k
    }
864
17.9k
  }
865
17.9k
}
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
143k
                           INT mixScales[(8)][(8)], const unsigned int outCh) {
877
143k
  unsigned int inCh;
878
1.29M
  for (inCh = 0; inCh < (8); inCh += 1) {
879
1.14M
    if (inCh == outCh) {
880
143k
      mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.5f);
881
143k
      mixScales[outCh][inCh] = 1;
882
1.00M
    } else {
883
1.00M
      mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.0f);
884
1.00M
      mixScales[outCh][inCh] = 0;
885
1.00M
    }
886
1.14M
  }
887
143k
}
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
2.39k
                            INT mixScales[(8)][(8)], const unsigned int outCh) {
899
2.39k
  FDK_ASSERT((outCh >= 0) && (outCh < (8)));
900
2.39k
  FDKmemclear(&mixFactors[outCh], (8) * sizeof(FIXP_DMX));
901
2.39k
  FDKmemclear(&mixScales[outCh], (8) * sizeof(INT));
902
2.39k
}
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
84.2k
                          const INT scale) {
921
84.2k
  int ch;
922
758k
  for (ch = 0; ch < (8); ch += 1) {
923
673k
    if (mixFactors[srcCh][ch] != (FIXP_DMX)0) {
924
94.5k
      mixFactors[dstCh][ch] =
925
94.5k
          FX_DBL2FX_DMX(fMult(mixFactors[srcCh][ch], factor));
926
94.5k
      mixScales[dstCh][ch] = mixScales[srcCh][ch] + scale;
927
94.5k
    }
928
673k
  }
929
84.2k
}
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
17.9k
                                  INT *pOutScale) {
991
17.9k
  PCMDMX_ERROR err = PCMDMX_OK;
992
17.9k
  INT mixScales[(8)][(8)];
993
17.9k
  INT maxScale = 0;
994
17.9k
  int numInChannel;
995
17.9k
  int numOutChannel;
996
17.9k
  int dmxMethod;
997
17.9k
  unsigned int outCh, inChCfg = 0;
998
17.9k
  unsigned int valid[(8)] = {0};
999
1000
17.9k
  FDK_ASSERT(pMetaData != NULL);
1001
17.9k
  FDK_ASSERT(mixFactors != NULL);
1002
  /* Check on a supported output configuration.
1003
     Add new one only after extensive testing! */
1004
17.9k
  if (!((outChMode == CH_MODE_1_0_0_0) || (outChMode == CH_MODE_2_0_0_0) ||
1005
17.9k
        (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
17.9k
  if (inModeIsCfg) {
1011
    /* Convert channel config to channel mode: */
1012
17.9k
    inChCfg = (unsigned int)inChMode;
1013
17.9k
    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
2.38k
      case 11:
1023
2.38k
        inChMode = CH_MODE_3_0_3_1;
1024
2.38k
        break;
1025
1.82k
      case 12:
1026
1.82k
        inChMode = CH_MODE_3_0_4_1;
1027
1.82k
        break;
1028
5.25k
      case 7:
1029
13.6k
      case 14:
1030
13.6k
        inChMode = CH_MODE_5_0_2_1;
1031
13.6k
        break;
1032
0
      default:
1033
0
        FDK_ASSERT(0);
1034
17.9k
    }
1035
17.9k
  }
1036
1037
  /* Extract the total number of input channels */
1038
17.9k
  numInChannel = (inChMode & 0xF) + ((inChMode >> 4) & 0xF) +
1039
17.9k
                 ((inChMode >> 8) & 0xF) + ((inChMode >> 12) & 0xF);
1040
  /* Extract the total number of output channels */
1041
17.9k
  numOutChannel = (outChMode & 0xF) + ((outChMode >> 4) & 0xF) +
1042
17.9k
                  ((outChMode >> 8) & 0xF) + ((outChMode >> 12) & 0xF);
1043
1044
  /* MPEG ammendment 4 aka ETSI metadata and fallback mode: */
1045
1046
  /* Create identity DMX matrix: */
1047
161k
  for (outCh = 0; outCh < (8); outCh += 1) {
1048
143k
    dmxInitChannel(mixFactors, mixScales, outCh);
1049
143k
  }
1050
17.9k
  if (((inChMode >> 12) & 0xF) == 0) {
1051
    /* Clear empty or wrongly mapped input channel */
1052
5
    dmxClearChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL);
1053
5
  }
1054
1055
  /* FIRST STAGE: */
1056
17.9k
  if (numInChannel > SIX_CHANNEL) { /* Always use MPEG equations either with
1057
                                       meta data or with default values. */
1058
17.9k
    FIXP_DMX dMixFactA, dMixFactB;
1059
17.9k
    INT dMixScaleA, dMixScaleB;
1060
17.9k
    int isValidCfg = TRUE;
1061
1062
    /* Get factors from meta data */
1063
17.9k
    dMixFactA = abMixLvlValueTab[pMetaData->dmixIdxA];
1064
17.9k
    dMixScaleA = (pMetaData->dmixIdxA == 0) ? 1 : 0;
1065
17.9k
    dMixFactB = abMixLvlValueTab[pMetaData->dmixIdxB];
1066
17.9k
    dMixScaleB = (pMetaData->dmixIdxB == 0) ? 1 : 0;
1067
1068
    /* Check if input is in the list of supported configurations */
1069
17.9k
    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
2.38k
      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
2.38k
        dmxClearChannel(
1080
2.38k
            mixFactors, mixScales,
1081
2.38k
            RIGHT_MULTIPRPS_CHANNEL); /* clear empty input channel */
1082
2.38k
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1083
2.38k
                      LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1084
2.38k
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1085
2.38k
                      LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1086
2.38k
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1087
2.38k
                      RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1088
2.38k
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1089
2.38k
                      LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1090
2.38k
        break;
1091
1.82k
      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
1.82k
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1096
1.82k
                      LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1097
1.82k
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1098
1.82k
                      LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1099
1.82k
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1100
1.82k
                      RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1101
1.82k
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1102
1.82k
                      RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1103
1.82k
        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
13.6k
      case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */
1118
13.6k
        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
8.44k
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1123
8.44k
                        LEFT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
1124
8.44k
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1125
8.44k
                        LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1126
8.44k
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1127
8.44k
                        RIGHT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
1128
8.44k
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1129
8.44k
                        RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1130
8.44k
        } 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
5.25k
          dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1136
5.25k
                        LEFT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
1137
5.25k
          dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1138
5.25k
                        RIGHT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
1139
5.25k
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1140
5.25k
                        LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1141
5.25k
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1142
5.25k
                        LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1143
5.25k
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1144
5.25k
                        RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1145
5.25k
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1146
5.25k
                        RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1147
5.25k
        }
1148
13.6k
        break;
1149
5
      default:
1150
        /* Nothing to do. Just use the identity matrix. */
1151
5
        isValidCfg = FALSE;
1152
5
        err = PCMDMX_INVALID_MODE;
1153
5
        break;
1154
17.9k
    }
1155
1156
    /* Add additional DMX gain */
1157
17.9k
    if ((isValidCfg == TRUE) &&
1158
17.9k
        (pMetaData->dmxGainIdx5 != 0)) { /* Apply DMX gain 5 */
1159
347
      FIXP_DMX dmxGain;
1160
347
      INT dmxScale;
1161
347
      INT sign = (pMetaData->dmxGainIdx5 & 0x40) ? -1 : 1;
1162
347
      INT val = pMetaData->dmxGainIdx5 & 0x3F;
1163
1164
      /* 10^(dmx_gain_5/80) */
1165
347
      dmxGain = FX_DBL2FX_DMX(
1166
347
          fLdPow(FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
1167
347
                 (FIXP_DBL)(sign * val * (LONG)FL2FXCONST_DBL(0.0125f)), 0,
1168
347
                 &dmxScale));
1169
      /* Currently only positive scale factors supported! */
1170
347
      if (dmxScale < 0) {
1171
163
        dmxGain >>= -dmxScale;
1172
163
        dmxScale = 0;
1173
163
      }
1174
1175
347
      dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1176
347
                    CENTER_FRONT_CHANNEL, dmxGain, dmxScale);
1177
347
      dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1178
347
                    LEFT_FRONT_CHANNEL, dmxGain, dmxScale);
1179
347
      dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1180
347
                    RIGHT_FRONT_CHANNEL, dmxGain, dmxScale);
1181
347
      dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL,
1182
347
                    dmxGain, dmxScale);
1183
347
      dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1184
347
                    RIGHT_REAR_CHANNEL, dmxGain, dmxScale);
1185
347
      dmxSetChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL,
1186
347
                    LOW_FREQUENCY_CHANNEL, dmxGain, dmxScale);
1187
347
    }
1188
1189
    /* Mark the output channels */
1190
17.9k
    valid[CENTER_FRONT_CHANNEL] = 1;
1191
17.9k
    valid[LEFT_FRONT_CHANNEL] = 1;
1192
17.9k
    valid[RIGHT_FRONT_CHANNEL] = 1;
1193
17.9k
    valid[LEFT_REAR_CHANNEL] = 1;
1194
17.9k
    valid[RIGHT_REAR_CHANNEL] = 1;
1195
17.9k
    valid[LOW_FREQUENCY_CHANNEL] = 1;
1196
1197
    /* Update channel mode for the next stage */
1198
17.9k
    inChMode = CH_MODE_3_0_2_1;
1199
17.9k
  }
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
17.9k
#define DMX_METHOD_MPEG_AMD4 1
1207
17.9k
#define DMX_METHOD_MPEG_LEGACY 2
1208
17.9k
#define DMX_METHOD_ARIB_JAPAN 4
1209
17.9k
#define DMX_METHOD_ITU_RECOM 8
1210
17.9k
#define DMX_METHOD_CUSTOM 16
1211
1212
17.9k
  dmxMethod = DMX_METHOD_MPEG_AMD4; /* default */
1213
1214
17.9k
  if ((pParams->dmxProfile == DMX_PRFL_FORCE_MATRIX_MIX) &&
1215
0
      (pMetaData->typeFlags & TYPE_PCE_DATA)) {
1216
0
    dmxMethod = DMX_METHOD_MPEG_LEGACY;
1217
17.9k
  } else if (!(pMetaData->typeFlags &
1218
17.9k
               (TYPE_DSE_CLEV_DATA | TYPE_DSE_SLEV_DATA))) {
1219
17.5k
    switch (pParams->dmxProfile) {
1220
0
      default:
1221
17.5k
      case DMX_PRFL_STANDARD:
1222
        /* dmxMethod = DMX_METHOD_MPEG_AMD4; */
1223
17.5k
        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
17.5k
    }
1234
17.5k
  }
1235
1236
  /* SECOND STAGE: */
1237
17.9k
  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
17.9k
  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
161k
#define MAX_SEARCH_START_VAL (-7)
1535
1536
17.9k
  {
1537
17.9k
    LONG chSum[(8)];
1538
17.9k
    INT chSumMax = MAX_SEARCH_START_VAL;
1539
1540
    /* Determine the current maximum scale factor */
1541
161k
    for (outCh = 0; outCh < (8); outCh += 1) {
1542
143k
      if (valid[outCh] != 0) {
1543
107k
        unsigned int inCh;
1544
967k
        for (inCh = 0; inCh < (8); inCh += 1) {
1545
860k
          if (mixScales[outCh][inCh] > maxScale) { /* Store the new maximum */
1546
23.2k
            maxScale = mixScales[outCh][inCh];
1547
23.2k
          }
1548
860k
        }
1549
107k
      }
1550
143k
    }
1551
1552
    /* Individualy analyse output chanal levels */
1553
161k
    for (outCh = 0; outCh < (8); outCh += 1) {
1554
143k
      chSum[outCh] = MAX_SEARCH_START_VAL;
1555
143k
      if (valid[outCh] != 0) {
1556
107k
        int ovrflwProtScale = 0;
1557
107k
        unsigned int inCh;
1558
1559
        /* Accumulate all factors for each output channel */
1560
107k
        chSum[outCh] = 0;
1561
967k
        for (inCh = 0; inCh < (8); inCh += 1) {
1562
860k
          SHORT addFact = FX_DMX2SHRT(mixFactors[outCh][inCh]);
1563
860k
          if (mixScales[outCh][inCh] <= maxScale) {
1564
860k
            addFact >>= maxScale - mixScales[outCh][inCh];
1565
860k
          } else {
1566
0
            addFact <<= mixScales[outCh][inCh] - maxScale;
1567
0
          }
1568
860k
          chSum[outCh] += addFact;
1569
860k
        }
1570
107k
        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
107k
        } else if (chSum[outCh] > 0) {
1576
137k
          while ((chSum[outCh] << 1) <= (LONG)MAXVAL_SGL) {
1577
30.3k
            ovrflwProtScale -= 1;
1578
30.3k
            chSum[outCh] <<= 1;
1579
30.3k
          }
1580
107k
        }
1581
        /* Store the differential scaling in the same array */
1582
107k
        chSum[outCh] = ovrflwProtScale;
1583
107k
      }
1584
143k
    }
1585
1586
161k
    for (outCh = 0; outCh < (8); outCh += 1) {
1587
143k
      if ((valid[outCh] != 0) &&
1588
107k
          (chSum[outCh] > chSumMax)) { /* Store the new maximum */
1589
18.2k
        chSumMax = chSum[outCh];
1590
18.2k
      }
1591
143k
    }
1592
17.9k
    maxScale = fMax(maxScale + chSumMax, 0);
1593
1594
    /* Normalize all factors */
1595
161k
    for (outCh = 0; outCh < (8); outCh += 1) {
1596
143k
      if (valid[outCh] != 0) {
1597
107k
        unsigned int inCh;
1598
967k
        for (inCh = 0; inCh < (8); inCh += 1) {
1599
860k
          if (mixFactors[outCh][inCh] != (FIXP_DMX)0) {
1600
152k
            if (mixScales[outCh][inCh] <= maxScale) {
1601
152k
              mixFactors[outCh][inCh] >>= maxScale - mixScales[outCh][inCh];
1602
152k
            } else {
1603
774
              mixFactors[outCh][inCh] <<= mixScales[outCh][inCh] - maxScale;
1604
774
            }
1605
152k
            mixScales[outCh][inCh] = maxScale;
1606
152k
          }
1607
860k
        }
1608
107k
      }
1609
143k
    }
1610
17.9k
  }
1611
1612
  /* return the scale factor */
1613
17.9k
  *pOutScale = maxScale;
1614
1615
17.9k
  return (err);
1616
17.9k
}
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
23.8k
PCMDMX_ERROR pcmDmx_Open(HANDLE_PCM_DOWNMIX *pSelf) {
1623
23.8k
  HANDLE_PCM_DOWNMIX self;
1624
1625
23.8k
  if (pSelf == NULL) {
1626
0
    return (PCMDMX_INVALID_HANDLE);
1627
0
  }
1628
1629
23.8k
  *pSelf = NULL;
1630
1631
23.8k
  self = (HANDLE_PCM_DOWNMIX)GetPcmDmxInstance(0);
1632
23.8k
  if (self == NULL) {
1633
0
    return (PCMDMX_OUT_OF_MEMORY);
1634
0
  }
1635
1636
  /* Reset the full instance */
1637
23.8k
  pcmDmx_Reset(self, PCMDMX_RESET_FULL);
1638
1639
23.8k
  *pSelf = self;
1640
1641
23.8k
  return (PCMDMX_OK);
1642
23.8k
}
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
666k
PCMDMX_ERROR pcmDmx_Reset(HANDLE_PCM_DOWNMIX self, UINT flags) {
1650
666k
  if (self == NULL) {
1651
0
    return (PCMDMX_INVALID_HANDLE);
1652
0
  }
1653
1654
666k
  if (flags & PCMDMX_RESET_PARAMS) {
1655
23.8k
    PCM_DMX_USER_PARAMS *pParams = &self->userParams;
1656
1657
23.8k
    pParams->dualChannelMode = STEREO_MODE;
1658
23.8k
    pParams->pseudoSurrMode = NEVER_DO_PS_DMX;
1659
23.8k
    pParams->numOutChannelsMax = (6);
1660
23.8k
    pParams->numOutChannelsMin = (0);
1661
23.8k
    pParams->frameDelay = 0;
1662
23.8k
    pParams->expiryFrame = (0);
1663
1664
23.8k
    self->applyProcessing = 0;
1665
23.8k
  }
1666
1667
666k
  if (flags & PCMDMX_RESET_BS_DATA) {
1668
666k
    int slot;
1669
    /* Init all slots with a default set */
1670
1.99M
    for (slot = 0; slot <= (1); slot += 1) {
1671
1.33M
      FDKmemcpy(&self->bsMetaData[slot], &dfltMetaData,
1672
1.33M
                sizeof(DMX_BS_META_DATA));
1673
1.33M
    }
1674
666k
  }
1675
1676
666k
  return (PCMDMX_OK);
1677
666k
}
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
462k
                             const INT value) {
1687
462k
  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
423k
    case DMX_BS_DATA_EXPIRY_FRAME:
1703
423k
      if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1704
423k
      self->userParams.expiryFrame = (value > 0) ? (UINT)value : 0;
1705
423k
      break;
1706
1707
39.9k
    case DMX_BS_DATA_DELAY:
1708
39.9k
      if ((value > (1)) || (value < 0)) {
1709
0
        return (PCMDMX_UNABLE_TO_SET_PARAM);
1710
0
      }
1711
39.9k
      if (self == NULL) {
1712
0
        return (PCMDMX_INVALID_HANDLE);
1713
0
      }
1714
39.9k
      self->userParams.frameDelay = (UCHAR)value;
1715
39.9k
      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
462k
  }
1798
1799
462k
  return (PCMDMX_OK);
1800
462k
}
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
383k
                             INT *const pValue) {
1810
383k
  PCM_DMX_USER_PARAMS *pUsrParams;
1811
1812
383k
  if ((self == NULL) || (pValue == NULL)) {
1813
0
    return (PCMDMX_INVALID_HANDLE);
1814
0
  }
1815
383k
  pUsrParams = &self->userParams;
1816
1817
383k
  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
139k
    case MIN_NUMBER_OF_OUTPUT_CHANNELS:
1828
139k
      *pValue = (INT)pUsrParams->numOutChannelsMin;
1829
139k
      break;
1830
243k
    case MAX_NUMBER_OF_OUTPUT_CHANNELS:
1831
243k
      *pValue = (INT)pUsrParams->numOutChannelsMax;
1832
243k
      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
383k
  }
1842
1843
383k
  return (PCMDMX_OK);
1844
383k
}
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
9.43k
                          UINT ancDataBits, int isMpeg2) {
1851
9.43k
  PCMDMX_ERROR errorStatus = PCMDMX_OK;
1852
1853
9.43k
#define MAX_DSE_ANC_BYTES (16)    /* 15 bytes */
1854
9.43k
#define ANC_DATA_SYNC_BYTE (0xBC) /* ancillary data sync byte. */
1855
1856
9.43k
  DMX_BS_META_DATA *pBsMetaData;
1857
1858
9.43k
  int skip4Dmx = 0, skip4Ext = 0;
1859
9.43k
  int dmxLvlAvail = 0, extDataAvail = 0;
1860
9.43k
  UINT foundNewData = 0;
1861
9.43k
  UINT minAncBits = ((isMpeg2) ? 5 : 3) * 8;
1862
1863
9.43k
  if ((self == NULL) || (hBs == NULL)) {
1864
0
    return (PCMDMX_INVALID_HANDLE);
1865
0
  }
1866
1867
  /* sanity checks */
1868
9.43k
  if ((ancDataBits < minAncBits) || (ancDataBits > FDKgetValidBits(hBs))) {
1869
5.52k
    return (PCMDMX_CORRUPT_ANC_DATA);
1870
5.52k
  }
1871
1872
3.91k
  pBsMetaData = &self->bsMetaData[0];
1873
1874
3.91k
  if (isMpeg2) {
1875
    /* skip DVD ancillary data */
1876
0
    FDKpushFor(hBs, 16);
1877
0
  }
1878
1879
  /* check sync word */
1880
3.91k
  if (FDKreadBits(hBs, 8) != ANC_DATA_SYNC_BYTE) {
1881
754
    return (PCMDMX_CORRUPT_ANC_DATA);
1882
754
  }
1883
1884
  /* skip MPEG audio type and Dolby surround mode */
1885
3.15k
  FDKpushFor(hBs, 4);
1886
1887
3.15k
  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
3.15k
  } else {
1896
3.15k
    FDKpushFor(hBs, 2); /* drc presentation mode */
1897
3.15k
    pBsMetaData->pseudoSurround = (SCHAR)FDKreadBit(hBs);
1898
3.15k
    FDKpushFor(hBs, 4); /* reserved bits */
1899
3.15k
  }
1900
1901
  /* downmixing levels MPEGx status */
1902
3.15k
  dmxLvlAvail = FDKreadBit(hBs);
1903
1904
3.15k
  if (isMpeg2) {
1905
    /* scale factor CRC status */
1906
0
    if (FDKreadBit(hBs)) skip4Ext += 16;
1907
3.15k
  } else {
1908
    /* ancillary data extension status */
1909
3.15k
    extDataAvail = FDKreadBit(hBs);
1910
3.15k
  }
1911
1912
  /* audio coding and compression status */
1913
3.15k
  if (FDKreadBit(hBs)) skip4Ext += 16;
1914
  /* coarse grain timecode status */
1915
3.15k
  if (FDKreadBit(hBs)) skip4Ext += 16;
1916
  /* fine grain timecode status */
1917
3.15k
  if (FDKreadBit(hBs)) skip4Ext += 16;
1918
1919
  /* skip the useless data to get to the DMX levels */
1920
3.15k
  FDKpushFor(hBs, skip4Dmx);
1921
1922
  /* downmix_levels_MPEGX */
1923
3.15k
  if (dmxLvlAvail) {
1924
2.46k
    if (FDKreadBit(hBs)) { /* center_mix_level_on */
1925
2.00k
      pBsMetaData->cLevIdx = (UCHAR)FDKreadBits(hBs, 3);
1926
2.00k
      foundNewData |= TYPE_DSE_CLEV_DATA;
1927
2.00k
    } else {
1928
459
      FDKreadBits(hBs, 3);
1929
459
    }
1930
2.46k
    if (FDKreadBit(hBs)) { /* surround_mix_level_on */
1931
695
      pBsMetaData->sLevIdx = (UCHAR)FDKreadBits(hBs, 3);
1932
695
      foundNewData |= TYPE_DSE_SLEV_DATA;
1933
1.76k
    } else {
1934
1.76k
      FDKreadBits(hBs, 3);
1935
1.76k
    }
1936
2.46k
  }
1937
1938
  /* skip the useless data to get to the ancillary data extension */
1939
3.15k
  FDKpushFor(hBs, skip4Ext);
1940
1941
  /* anc data extension (MPEG-4 only) */
1942
3.15k
  if (extDataAvail) {
1943
2.49k
    int extDmxLvlSt, extDmxGainSt, extDmxLfeSt;
1944
1945
2.49k
    FDKreadBit(hBs); /* reserved bit */
1946
2.49k
    extDmxLvlSt = FDKreadBit(hBs);
1947
2.49k
    extDmxGainSt = FDKreadBit(hBs);
1948
2.49k
    extDmxLfeSt = FDKreadBit(hBs);
1949
2.49k
    FDKreadBits(hBs, 4); /* reserved bits */
1950
1951
2.49k
    if (extDmxLvlSt) {
1952
1.00k
      pBsMetaData->dmixIdxA = (UCHAR)FDKreadBits(hBs, 3);
1953
1.00k
      pBsMetaData->dmixIdxB = (UCHAR)FDKreadBits(hBs, 3);
1954
1.00k
      FDKreadBits(hBs, 2); /* reserved bits */
1955
1.00k
      foundNewData |= TYPE_DSE_DMIX_AB_DATA;
1956
1.00k
    }
1957
2.49k
    if (extDmxGainSt) {
1958
1.28k
      pBsMetaData->dmxGainIdx5 = (UCHAR)FDKreadBits(hBs, 7);
1959
1.28k
      FDKreadBit(hBs); /* reserved bit */
1960
1.28k
      pBsMetaData->dmxGainIdx2 = (UCHAR)FDKreadBits(hBs, 7);
1961
1.28k
      FDKreadBit(hBs); /* reserved bit */
1962
1.28k
      foundNewData |= TYPE_DSE_DMX_GAIN_DATA;
1963
1.28k
    }
1964
2.49k
    if (extDmxLfeSt) {
1965
1.47k
      pBsMetaData->dmixIdxLfe = (UCHAR)FDKreadBits(hBs, 4);
1966
1.47k
      FDKreadBits(hBs, 4); /* reserved bits */
1967
1.47k
      foundNewData |= TYPE_DSE_DMIX_LFE_DATA;
1968
1.47k
    }
1969
2.49k
  }
1970
1971
  /* final sanity check on the amount of read data */
1972
3.15k
  if ((INT)FDKgetValidBits(hBs) < 0) {
1973
74
    errorStatus = PCMDMX_CORRUPT_ANC_DATA;
1974
74
  }
1975
1976
3.15k
  if ((errorStatus == PCMDMX_OK) && (foundNewData != 0)) {
1977
    /* announce new data */
1978
2.52k
    pBsMetaData->typeFlags |= foundNewData;
1979
    /* reset expiry counter */
1980
2.52k
    pBsMetaData->expiryCount = 0;
1981
2.52k
  }
1982
1983
3.15k
  return (errorStatus);
1984
3.91k
}
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
66.6k
                                            int pseudoSurroundEnable) {
2023
66.6k
  if (self == NULL) {
2024
0
    return (PCMDMX_INVALID_HANDLE);
2025
0
  }
2026
2027
66.6k
  {
2028
66.6k
    DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0];
2029
2030
66.6k
    if (matrixMixdownPresent) {
2031
5.50k
      pBsMetaData->pseudoSurround = (pseudoSurroundEnable) ? 1 : 0;
2032
5.50k
      pBsMetaData->matrixMixdownIdx = matrixMixdownIdx & 0x03;
2033
5.50k
      pBsMetaData->typeFlags |= TYPE_PCE_DATA;
2034
      /* Reset expiry counter */
2035
5.50k
      pBsMetaData->expiryCount = 0;
2036
5.50k
    }
2037
66.6k
  }
2038
2039
66.6k
  return (PCMDMX_OK);
2040
66.6k
}
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
354k
                               INT *pDmxOutScale) {
2067
354k
  PCM_DMX_USER_PARAMS *pParam = NULL;
2068
354k
  PCMDMX_ERROR errorStatus = PCMDMX_OK;
2069
354k
  DUAL_CHANNEL_MODE dualChannelMode;
2070
354k
  PCM_DMX_CHANNEL_MODE inChMode;
2071
354k
  PCM_DMX_CHANNEL_MODE outChMode;
2072
354k
  INT devNull; /* Just a dummy to avoid a lot of branches in the code */
2073
354k
  int numOutChannels, numInChannels;
2074
354k
  int inStride, outStride, offset;
2075
354k
  int dmxMaxScale, dmxScale;
2076
354k
  int slot;
2077
354k
  UCHAR inOffsetTable[(8)];
2078
2079
354k
  DMX_BS_META_DATA bsMetaData;
2080
2081
354k
  if ((self == NULL) || (nChannels == NULL) || (channelType == NULL) ||
2082
354k
      (channelIndices == NULL) || (!FDK_chMapDescr_isValid(mapDescr))) {
2083
0
    return (PCMDMX_INVALID_HANDLE);
2084
0
  }
2085
2086
  /* Init the output scaling */
2087
354k
  dmxScale = 0;
2088
354k
  if (pDmxOutScale != NULL) {
2089
    /* Avoid final scaling internally and hand it to the outside world. */
2090
354k
    *pDmxOutScale = 0;
2091
354k
    dmxMaxScale = (3);
2092
354k
  } else {
2093
    /* Apply the scaling internally. */
2094
0
    pDmxOutScale = &devNull; /* redirect to temporal stack memory */
2095
0
    dmxMaxScale = 0;
2096
0
  }
2097
2098
354k
  pParam = &self->userParams;
2099
354k
  numInChannels = *nChannels;
2100
2101
  /* Perform some input sanity checks */
2102
354k
  if (pPcmBuf == NULL) {
2103
0
    return (PCMDMX_INVALID_ARGUMENT);
2104
0
  }
2105
354k
  if (frameSize == 0) {
2106
0
    return (PCMDMX_INVALID_ARGUMENT);
2107
0
  }
2108
354k
  if (numInChannels == 0) {
2109
0
    return (PCMDMX_INVALID_ARGUMENT);
2110
0
  }
2111
354k
  if (numInChannels > (8)) {
2112
0
    return (PCMDMX_INVALID_CH_CONFIG);
2113
0
  }
2114
2115
  /* Check on misconfiguration */
2116
354k
  FDK_ASSERT((pParam->numOutChannelsMax <= 0) ||
2117
354k
             (pParam->numOutChannelsMax >= pParam->numOutChannelsMin));
2118
2119
  /* Determine if the module has to do processing */
2120
354k
  if ((self->applyProcessing == 0) &&
2121
354k
      ((pParam->numOutChannelsMax <= 0) ||
2122
354k
       (pParam->numOutChannelsMax >= numInChannels)) &&
2123
336k
      (pParam->numOutChannelsMin <= numInChannels)) {
2124
    /* Nothing to do */
2125
336k
    return (errorStatus);
2126
336k
  }
2127
2128
  /* Determine the number of output channels */
2129
17.9k
  if ((pParam->numOutChannelsMax > 0) &&
2130
17.9k
      (numInChannels > pParam->numOutChannelsMax)) {
2131
17.9k
    numOutChannels = pParam->numOutChannelsMax;
2132
17.9k
  } 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
17.9k
  if ((UINT)pcmBufSize < (UINT)numOutChannels * frameSize) {
2140
0
    return (PCMDMX_OUTPUT_BUFFER_TOO_SMALL);
2141
0
  }
2142
2143
17.9k
  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
17.9k
  errorStatus = getChannelMode(numInChannels, channelType, channelIndices,
2148
17.9k
                               inOffsetTable, &inChMode);
2149
17.9k
  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
17.9k
  if (fInterleaved) {
2157
12.0k
    inStride = numInChannels;
2158
12.0k
    offset = 1; /* Channel specific offset factor */
2159
12.0k
  } else {
2160
5.90k
    inStride = 1;
2161
5.90k
    offset = frameSize; /* Channel specific offset factor */
2162
5.90k
  }
2163
2164
  /* Reset downmix meta data if necessary */
2165
17.9k
  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
17.9k
  FDKmemcpy(&bsMetaData, &self->bsMetaData[pParam->frameDelay],
2177
17.9k
            sizeof(DMX_BS_META_DATA));
2178
  /* Maintain delay line */
2179
18.3k
  for (slot = pParam->frameDelay; slot > 0; slot -= 1) {
2180
405
    FDKmemcpy(&self->bsMetaData[slot], &self->bsMetaData[slot - 1],
2181
405
              sizeof(DMX_BS_META_DATA));
2182
405
  }
2183
2184
  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2185
   * - - - - - - - - - - - - - - - - - - */
2186
17.9k
  if (numInChannels > numOutChannels) { /* Apply downmix */
2187
17.9k
    DMX_PCM *pInPcm[(8)] = {NULL};
2188
17.9k
    DMX_PCM *pOutPcm[(8)] = {NULL};
2189
17.9k
    FIXP_DMX mixFactors[(8)][(8)];
2190
17.9k
    UCHAR outOffsetTable[(8)];
2191
17.9k
    UINT sample;
2192
17.9k
    int chCfg = 0;
2193
17.9k
    int bypScale = 0;
2194
2195
17.9k
    if (numInChannels > SIX_CHANNEL) {
2196
17.9k
      AUDIO_CHANNEL_TYPE multiPurposeChType[2];
2197
2198
      /* Get the type of the multipurpose channels */
2199
17.9k
      multiPurposeChType[0] =
2200
17.9k
          channelType[inOffsetTable[LEFT_MULTIPRPS_CHANNEL]];
2201
17.9k
      multiPurposeChType[1] =
2202
17.9k
          channelType[inOffsetTable[RIGHT_MULTIPRPS_CHANNEL]];
2203
2204
      /* Check if the input configuration is one defined in the standard. */
2205
17.9k
      switch (inChMode) {
2206
13.6k
        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
13.6k
          if ((multiPurposeChType[0] == ACT_FRONT_TOP) &&
2210
8.44k
              (multiPurposeChType[1] == ACT_FRONT_TOP)) {
2211
8.44k
            chCfg = 14;
2212
8.44k
          } else {
2213
5.25k
            chCfg = 7;
2214
5.25k
          }
2215
13.6k
          break;
2216
2.38k
        case CH_MODE_3_0_3_1: /* chCfg 11 */
2217
2.38k
          chCfg = 11;
2218
2.38k
          break;
2219
1.82k
        case CH_MODE_3_0_4_1: /* chCfg 12 */
2220
1.82k
          chCfg = 12;
2221
1.82k
          break;
2222
5
        default:
2223
5
          chCfg = 0; /* Not a known config */
2224
5
          break;
2225
17.9k
      }
2226
17.9k
    }
2227
2228
    /* Set this stages output stride and channel mode: */
2229
17.9k
    outStride = (fInterleaved) ? numOutChannels : 1;
2230
17.9k
    outChMode = outChModeTable[numOutChannels];
2231
17.9k
    FDK_ASSERT(outChMode != CH_MODE_UNDEFINED);
2232
2233
    /* Get channel description and channel mapping for the desired output
2234
     * configuration. */
2235
17.9k
    getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
2236
17.9k
                          outOffsetTable);
2237
    /* Now there is no way back because we modified the channel configuration!
2238
     */
2239
2240
    /* Create the DMX matrix */
2241
17.9k
    errorStatus =
2242
17.9k
        getMixFactors((chCfg > 0) ? 1 : 0,
2243
17.9k
                      (chCfg > 0) ? (PCM_DMX_CHANNEL_MODE)chCfg : inChMode,
2244
17.9k
                      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
17.9k
    bypScale = fMin(dmxMaxScale, dmxScale);
2251
17.9k
    *pDmxOutScale += bypScale;
2252
17.9k
    dmxScale -= bypScale;
2253
2254
17.9k
    { /* Set channel pointer for input. Remove empty cols. */
2255
17.9k
      int inCh, outCh, map[(8)];
2256
17.9k
      int ch = 0;
2257
161k
      for (inCh = 0; inCh < (8); inCh += 1) {
2258
143k
        if (inOffsetTable[inCh] < (UCHAR)numInChannels) {
2259
140k
          pInPcm[ch] = &pPcmBuf[inOffsetTable[inCh] * offset];
2260
140k
          map[ch++] = inCh;
2261
140k
        }
2262
143k
      }
2263
20.3k
      for (; ch < (8); ch += 1) {
2264
2.39k
        map[ch] = ch;
2265
2.39k
      }
2266
2267
      /* Remove unused cols from factor matrix */
2268
158k
      for (inCh = 0; inCh < numInChannels; inCh += 1) {
2269
140k
        if (inCh != map[inCh]) {
2270
198
          for (outCh = 0; outCh < (8); outCh += 1) {
2271
176
            mixFactors[outCh][inCh] = mixFactors[outCh][map[inCh]];
2272
176
          }
2273
22
        }
2274
140k
      }
2275
2276
      /* Set channel pointer for output. Remove empty cols. */
2277
17.9k
      ch = 0;
2278
161k
      for (outCh = 0; outCh < (8); outCh += 1) {
2279
143k
        if (outOffsetTable[outCh] < (UCHAR)numOutChannels) {
2280
107k
          pOutPcm[ch] = &pPcmBuf[outOffsetTable[outCh] * offset];
2281
107k
          map[ch++] = outCh;
2282
107k
        }
2283
143k
      }
2284
53.7k
      for (; ch < (8); ch += 1) {
2285
35.8k
        map[ch] = ch;
2286
35.8k
      }
2287
2288
      /* Remove unused rows from factor matrix */
2289
125k
      for (outCh = 0; outCh < numOutChannels; outCh += 1) {
2290
107k
        if (outCh != map[outCh]) {
2291
0
          FDKmemcpy(&mixFactors[outCh], &mixFactors[map[outCh]],
2292
0
                    (8) * sizeof(FIXP_DMX));
2293
0
        }
2294
107k
      }
2295
17.9k
    }
2296
2297
    /* Sample processing loop */
2298
13.8M
    for (sample = 0; sample < frameSize; sample++) {
2299
13.8M
      DMX_PCM tIn[(8)] = {0};
2300
13.8M
      FIXP_DBL tOut[(8)] = {(FIXP_DBL)0};
2301
13.8M
      int inCh, outCh;
2302
2303
      /* Preload all input samples */
2304
122M
      for (inCh = 0; inCh < numInChannels; inCh += 1) {
2305
108M
        if (pInPcm[inCh] != NULL) {
2306
108M
          tIn[inCh] = *pInPcm[inCh];
2307
108M
          pInPcm[inCh] += inStride;
2308
108M
        } else {
2309
3.00k
          tIn[inCh] = (DMX_PCM)0;
2310
3.00k
        }
2311
108M
      }
2312
      /* Apply downmix coefficients to input samples and accumulate for output
2313
       */
2314
96.7M
      for (outCh = 0; outCh < numOutChannels; outCh += 1) {
2315
735M
        for (inCh = 0; inCh < numInChannels; inCh += 1) {
2316
652M
          tOut[outCh] += fMult((DMX_PCMF)tIn[inCh], mixFactors[outCh][inCh]);
2317
652M
        }
2318
82.9M
        FDK_ASSERT(pOutPcm[outCh] >= pPcmBuf);
2319
82.9M
        FDK_ASSERT(pOutPcm[outCh] < &pPcmBuf[pcmBufSize]);
2320
        /* Write sample */
2321
82.9M
        *pOutPcm[outCh] = (DMX_PCM)SATURATE_SHIFT(
2322
82.9M
            tOut[outCh], DFRACT_BITS - DMX_PCM_BITS - dmxScale, DMX_PCM_BITS);
2323
82.9M
        pOutPcm[outCh] += outStride;
2324
82.9M
      }
2325
13.8M
    }
2326
2327
    /* Update the number of output channels */
2328
17.9k
    *nChannels = numOutChannels;
2329
2330
17.9k
  } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
17.9k
  return (errorStatus);
2629
17.9k
}
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
23.8k
PCMDMX_ERROR pcmDmx_Close(HANDLE_PCM_DOWNMIX *pSelf) {
2636
23.8k
  if (pSelf == NULL) {
2637
0
    return (PCMDMX_INVALID_HANDLE);
2638
0
  }
2639
2640
23.8k
  FreePcmDmxInstance(pSelf);
2641
23.8k
  *pSelf = NULL;
2642
2643
23.8k
  return (PCMDMX_OK);
2644
23.8k
}
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
}