Coverage Report

Created: 2025-07-18 06:08

/src/aac/libPCMutils/src/pcmdmx_lib.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -----------------------------------------------------------------------------
2
Software License for The Fraunhofer FDK AAC Codec Library for Android
3
4
© Copyright  1995 - 2021 Fraunhofer-Gesellschaft zur Förderung der angewandten
5
Forschung e.V. All rights reserved.
6
7
 1.    INTRODUCTION
8
The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9
that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10
scheme for digital audio. This FDK AAC Codec software is intended to be used on
11
a wide variety of Android devices.
12
13
AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14
general perceptual audio codecs. AAC-ELD is considered the best-performing
15
full-bandwidth communications codec by independent studies and is widely
16
deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17
specifications.
18
19
Patent licenses for necessary patent claims for the FDK AAC Codec (including
20
those of Fraunhofer) may be obtained through Via Licensing
21
(www.vialicensing.com) or through the respective patent owners individually for
22
the purpose of encoding or decoding bit streams in products that are compliant
23
with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24
Android devices already license these patent claims through Via Licensing or
25
directly from the patent owners, and therefore FDK AAC Codec software may
26
already be covered under those patent licenses when it is used for those
27
licensed purposes only.
28
29
Commercially-licensed AAC software libraries, including floating-point versions
30
with enhanced sound quality, are also available from Fraunhofer. Users are
31
encouraged to check the Fraunhofer website for additional applications
32
information and documentation.
33
34
2.    COPYRIGHT LICENSE
35
36
Redistribution and use in source and binary forms, with or without modification,
37
are permitted without payment of copyright license fees provided that you
38
satisfy the following conditions:
39
40
You must retain the complete text of this software license in redistributions of
41
the FDK AAC Codec or your modifications thereto in source code form.
42
43
You must retain the complete text of this software license in the documentation
44
and/or other materials provided with redistributions of the FDK AAC Codec or
45
your modifications thereto in binary form. You must make available free of
46
charge copies of the complete source code of the FDK AAC Codec and your
47
modifications thereto to recipients of copies in binary form.
48
49
The name of Fraunhofer may not be used to endorse or promote products derived
50
from this library without prior written permission.
51
52
You may not charge copyright license fees for anyone to use, copy or distribute
53
the FDK AAC Codec software or your modifications thereto.
54
55
Your modified versions of the FDK AAC Codec must carry prominent notices stating
56
that you changed the software and the date of any change. For modified versions
57
of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58
must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59
AAC Codec Library for Android."
60
61
3.    NO PATENT LICENSE
62
63
NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64
limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65
Fraunhofer provides no warranty of patent non-infringement with respect to this
66
software.
67
68
You may use this FDK AAC Codec software or modifications thereto only for
69
purposes that are authorized by appropriate patent licenses.
70
71
4.    DISCLAIMER
72
73
This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74
holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75
including but not limited to the implied warranties of merchantability and
76
fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77
CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78
or consequential damages, including but not limited to procurement of substitute
79
goods or services; loss of use, data, or profits, or business interruption,
80
however caused and on any theory of liability, whether in contract, strict
81
liability, or tort (including negligence), arising in any way out of the use of
82
this software, even if advised of the possibility of such damage.
83
84
5.    CONTACT INFORMATION
85
86
Fraunhofer Institute for Integrated Circuits IIS
87
Attention: Audio and Multimedia Departments - FDK AAC LL
88
Am Wolfsmantel 33
89
91058 Erlangen, Germany
90
91
www.iis.fraunhofer.de/amm
92
amm-info@iis.fraunhofer.de
93
----------------------------------------------------------------------------- */
94
95
/**************************** PCM utility library ******************************
96
97
   Author(s):   Christian Griebel
98
99
   Description: Defines functions that perform downmixing or a simple channel
100
                expansion in the PCM time domain.
101
102
*******************************************************************************/
103
104
#include "pcmdmx_lib.h"
105
106
#include "genericStds.h"
107
#include "fixpoint_math.h"
108
#include "FDK_core.h"
109
110
/* library version */
111
#include "version.h"
112
/* library title */
113
0
#define PCMDMX_LIB_TITLE "PCM Downmix Lib"
114
115
438k
#define FALSE 0
116
494k
#define TRUE 1
117
0
#define IN 0
118
0
#define OUT 1
119
120
/* Type definitions: */
121
56.3k
#define FIXP_DMX FIXP_SGL
122
#define FX_DMX2FX_DBL(x) FX_SGL2FX_DBL((FIXP_SGL)(x))
123
149k
#define FX_DBL2FX_DMX(x) FX_DBL2FX_SGL(x)
124
1.80M
#define FL2FXCONST_DMX(x) FL2FXCONST_SGL(x)
125
#define MAXVAL_DMX MAXVAL_SGL
126
1.33M
#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
111k
#define CH_GROUP_FRONT (0)
132
55.8k
#define CH_GROUP_SIDE (1)
133
55.8k
#define CH_GROUP_REAR (2)
134
55.8k
#define CH_GROUP_LFE (3)
135
136
/* Fixed and unique channel plain indices. */
137
83.7k
#define CH_PLAIN_NORMAL (0)
138
55.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
73.9k
#define CENTER_FRONT_CHANNEL (0) /* C  */
145
119k
#define LEFT_FRONT_CHANNEL (1)   /* L  */
146
91.5k
#define RIGHT_FRONT_CHANNEL (2)  /* R  */
147
#define LEFT_REAR_CHANNEL \
148
77.9k
  (3) /* Lr (aka left back channel) or center back channel */
149
49.9k
#define RIGHT_REAR_CHANNEL (4)      /* Rr (aka right back channel) */
150
84.7k
#define LOW_FREQUENCY_CHANNEL (5)   /* Lf */
151
96.4k
#define LEFT_MULTIPRPS_CHANNEL (6)  /* Left multipurpose channel */
152
64.3k
#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
27.9k
#define ONE_CHANNEL (1)
174
27.9k
#define TWO_CHANNEL (2)
175
55.8k
#define SIX_CHANNEL (6)
176
0
#define EIGHT_CHANNEL (8)
177
#define TWENTY_FOUR_CHANNEL (24)
178
179
219k
#define PCMDMX_THRESHOLD_MAP_HEAT_1 (0) /* Store only exact matches */
180
49.9k
#define PCMDMX_THRESHOLD_MAP_HEAT_2 (20)
181
#define PCMDMX_THRESHOLD_MAP_HEAT_3 \
182
51.7k
  (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
27.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
4.39k
#define TYPE_PCE_DATA (0x01)
328
29.6k
#define TYPE_DSE_CLEV_DATA (0x02)
329
28.5k
#define TYPE_DSE_SLEV_DATA (0x04)
330
1.13k
#define TYPE_DSE_DMIX_AB_DATA (0x08)
331
1.34k
#define TYPE_DSE_DMIX_LFE_DATA (0x10)
332
1.20k
#define TYPE_DSE_DMX_GAIN_DATA (0x20)
333
#define TYPE_DSE_DMX_CGL_DATA (0x40)
334
#define TYPE_DSE_DATA (0x7E)
335
336
typedef struct {
337
  UINT typeFlags;
338
  /* From DSE */
339
  UCHAR cLevIdx;
340
  UCHAR sLevIdx;
341
  UCHAR dmixIdxA;
342
  UCHAR dmixIdxB;
343
  UCHAR dmixIdxLfe;
344
  UCHAR dmxGainIdx2;
345
  UCHAR dmxGainIdx5;
346
  /* From PCE */
347
  UCHAR matrixMixdownIdx;
348
  /* Attributes: */
349
  SCHAR pseudoSurround; /*!< If set to 1 the signal is pseudo surround
350
                           compatible. The value 0 tells that it is not. If the
351
                           value is -1 the information is not available.  */
352
  UINT expiryCount; /*!< Counter to monitor the life time of a meta data set. */
353
354
} DMX_BS_META_DATA;
355
356
/* Default metadata */
357
static const DMX_BS_META_DATA dfltMetaData = {0, 2, 2, 2,  2, 15,
358
                                              0, 0, 0, -1, 0};
359
360
/* Dynamic (user) params:
361
     See the definition of PCMDMX_PARAM for details on the specific fields. */
362
typedef struct {
363
  DMX_PROFILE_TYPE dmxProfile; /*!< Linked to DMX_PRFL_STANDARD              */
364
  UINT expiryFrame;            /*!< Linked to DMX_BS_DATA_EXPIRY_FRAME       */
365
  DUAL_CHANNEL_MODE dualChannelMode; /*!< Linked to DMX_DUAL_CHANNEL_MODE */
366
  PSEUDO_SURROUND_MODE
367
  pseudoSurrMode;          /*!< Linked to DMX_PSEUDO_SURROUND_MODE       */
368
  SHORT numOutChannelsMin; /*!< Linked to MIN_NUMBER_OF_OUTPUT_CHANNELS  */
369
  SHORT numOutChannelsMax; /*!< Linked to MAX_NUMBER_OF_OUTPUT_CHANNELS  */
370
  UCHAR frameDelay;        /*!< Linked to DMX_BS_DATA_DELAY              */
371
372
} PCM_DMX_USER_PARAMS;
373
374
/* Modules main data structure: */
375
struct PCM_DMX_INSTANCE {
376
  /* Metadata */
377
  DMX_BS_META_DATA bsMetaData[(1) + 1];
378
  PCM_DMX_USER_PARAMS userParams;
379
380
  UCHAR applyProcessing; /*!< Flag to en-/disable modules processing.
381
                              The max channel limiting is done independently. */
382
};
383
384
/* Memory allocation macro */
385
C_ALLOC_MEM(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1)
386
387
static UINT getSpeakerDistance(PCM_DMX_SPEAKER_POSITION posA,
388
865k
                               PCM_DMX_SPEAKER_POSITION posB) {
389
865k
  PCM_DMX_SPEAKER_POSITION diff;
390
391
865k
  diff.x = posA.x - posB.x;
392
865k
  diff.y = posA.y - posB.y;
393
865k
  diff.z = posA.z - posB.z;
394
395
865k
  return ((diff.x * diff.x) + (diff.y * diff.y) + (diff.z * diff.z));
396
865k
}
397
398
static PCM_DMX_SPEAKER_POSITION getSpeakerPos(AUDIO_CHANNEL_TYPE chType,
399
219k
                                              UCHAR chIndex, UCHAR numChInGrp) {
400
219k
#define PCMDMX_SPKR_POS_X_MAX_WIDTH (3)
401
219k
#define PCMDMX_SPKR_POS_Y_SPREAD (2)
402
219k
#define PCMDMX_SPKR_POS_Z_SPREAD (2)
403
404
219k
  PCM_DMX_SPEAKER_POSITION spkrPos = {0, 0, 0};
405
219k
  AUDIO_CHANNEL_TYPE chGrp = (AUDIO_CHANNEL_TYPE)(chType & 0x0F);
406
219k
  unsigned fHasCenter = numChInGrp & 0x1;
407
219k
  unsigned chGrpWidth = numChInGrp >> 1;
408
219k
  unsigned fIsCenter = 0;
409
219k
  unsigned fIsLfe = (chType == ACT_LFE) ? 1 : 0;
410
219k
  int offset = 0;
411
412
219k
  FDK_ASSERT(chIndex < numChInGrp);
413
414
219k
  if ((chGrp == ACT_FRONT) && fHasCenter) {
415
100k
    if (chIndex == 0) fIsCenter = 1;
416
100k
    chIndex = (UCHAR)fMax(0, chIndex - 1);
417
118k
  } else if (fHasCenter && (chIndex == numChInGrp - 1)) {
418
32.0k
    fIsCenter = 1;
419
32.0k
  }
420
  /* now all even indices are left (-) */
421
219k
  if (!fIsCenter) {
422
159k
    offset = chIndex >> 1;
423
159k
    if ((chGrp > ACT_FRONT) && (chType != ACT_SIDE) && !fIsLfe) {
424
      /* the higher the index the lower the distance to the center position */
425
61.6k
      offset = chGrpWidth - fHasCenter - offset;
426
61.6k
    }
427
159k
    if ((chIndex & 0x1) == 0) { /* even */
428
79.6k
      offset = -(offset + 1);
429
79.6k
    } else {
430
79.6k
      offset += 1;
431
79.6k
    }
432
159k
  }
433
  /* apply the offset */
434
219k
  if (chType == ACT_SIDE) {
435
0
    spkrPos.x = (offset < 0) ? -PCMDMX_SPKR_POS_X_MAX_WIDTH
436
0
                             : PCMDMX_SPKR_POS_X_MAX_WIDTH;
437
0
    spkrPos.y = /* 1x */ PCMDMX_SPKR_POS_Y_SPREAD + (SCHAR)fAbs(offset) - 1;
438
0
    spkrPos.z = 0;
439
219k
  } else {
440
219k
    unsigned spread =
441
219k
        ((chGrpWidth == 1) && (!fIsLfe)) ? PCMDMX_SPKR_POS_X_MAX_WIDTH - 1 : 1;
442
219k
    spkrPos.x = (SCHAR)offset * (SCHAR)spread;
443
219k
    if (fIsLfe) {
444
27.9k
      spkrPos.y = 0;
445
27.9k
      spkrPos.z = SP_Z_LFE;
446
191k
    } else {
447
191k
      spkrPos.y = (SCHAR)fMax((SCHAR)chGrp - 1, 0) * PCMDMX_SPKR_POS_Y_SPREAD;
448
191k
      spkrPos.z = (SCHAR)chType >> 4;
449
191k
      if (spkrPos.z == 2) { /* ACT_BOTTOM */
450
0
        spkrPos.z = -1;
451
0
      }
452
191k
      spkrPos.z *= PCMDMX_SPKR_POS_Z_SPREAD;
453
191k
    }
454
219k
  }
455
219k
  return spkrPos;
456
219k
}
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
27.9k
    const int chCfg) {
471
27.9k
  PCM_DMX_CHANNEL_MODE plainChMode = totChMode;
472
473
27.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
27.9k
    default:
491
27.9k
      break;
492
27.9k
  }
493
494
27.9k
  return plainChMode;
495
27.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
96.0k
                            const UCHAR channelIndices[]) {
513
315k
  for (UINT reqValue = 0; reqValue < numChannelsPlaneAndGrp; reqValue++) {
514
219k
    int found = FALSE;
515
1.94M
    for (UINT i = 0; i < numChannels; i++) {
516
1.72M
      if (channelType[i] == aChType) {
517
632k
        if (channelIndices[i] == reqValue) {
518
219k
          if (found == TRUE) {
519
1
            return 0; /* Found channel index a second time */
520
219k
          } else {
521
219k
            found = TRUE; /* Found channel index */
522
219k
          }
523
219k
        }
524
632k
      }
525
1.72M
    }
526
219k
    if (found == FALSE) {
527
0
      return 0; /* Did not find channel index */
528
0
    }
529
219k
  }
530
96.0k
  return 1; /* Successfully validated channel indices */
531
96.0k
}
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
27.9k
) {
553
27.9k
  UCHAR numCh[(3)][(4)];
554
27.9k
  UCHAR mapped[(8)];
555
27.9k
  PCM_DMX_SPEAKER_POSITION spkrPos[(8)];
556
27.9k
  PCMDMX_ERROR err = PCMDMX_OK;
557
27.9k
  unsigned ch, numMappedInChs = 0;
558
27.9k
  unsigned startSlot;
559
27.9k
  unsigned stopSlot = LOW_FREQUENCY_CHANNEL;
560
561
27.9k
  FDK_ASSERT(channelType != NULL);
562
27.9k
  FDK_ASSERT(channelIndices != NULL);
563
27.9k
  FDK_ASSERT(offsetTable != NULL);
564
27.9k
  FDK_ASSERT(chMode != NULL);
565
566
  /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */
567
27.9k
  FDKmemclear(numCh, (3) * (4) * sizeof(UCHAR));
568
27.9k
  FDKmemclear(mapped, (8) * sizeof(UCHAR));
569
27.9k
  FDKmemclear(spkrPos, (8) * sizeof(PCM_DMX_SPEAKER_POSITION));
570
  /* Init output */
571
27.9k
  FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
572
27.9k
  *chMode = CH_MODE_UNDEFINED;
573
574
  /* Determine how many channels are assigned to each channels each group: */
575
247k
  for (ch = 0; ch < numChannels; ch += 1) {
576
219k
    unsigned chGrp = fMax(
577
219k
        (channelType[ch] & 0x0F) - 1,
578
219k
        0); /* Assign all undefined channels (ACT_NONE) to front channels. */
579
219k
    numCh[channelType[ch] >> 4][chGrp] += 1;
580
219k
  }
581
582
27.9k
  {
583
27.9k
    int chGrp;
584
    /* Sanity check on the indices */
585
139k
    for (chGrp = 0; chGrp < (4); chGrp += 1) {
586
111k
      int plane;
587
446k
      for (plane = 0; plane < (3); plane += 1) {
588
334k
        if (numCh[plane][chGrp] == 0) continue;
589
96.0k
        AUDIO_CHANNEL_TYPE aChType =
590
96.0k
            (AUDIO_CHANNEL_TYPE)((plane << 4) | ((chGrp + 1) & 0xF));
591
96.0k
        if (!validateIndices(numChannels, numCh[plane][chGrp], aChType,
592
96.0k
                             channelType, channelIndices)) {
593
1
          unsigned idxCnt = 0;
594
8
          for (ch = 0; ch < numChannels; ch += 1) {
595
7
            if (channelType[ch] == aChType) {
596
4
              channelIndices[ch] = idxCnt++;
597
4
            }
598
7
          }
599
1
          err = PCMDMX_INVALID_CH_CONFIG;
600
1
        }
601
96.0k
      }
602
111k
    }
603
27.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
247k
  for (ch = 0; ch < numChannels; ch += 1) {
608
219k
    UINT mapDist = (unsigned)-1;
609
219k
    unsigned mapCh, mapPos = (unsigned)-1;
610
219k
    unsigned chGrp = fMax(
611
219k
        (channelType[ch] & 0x0F) - 1,
612
219k
        0); /* Assign all undefined channels (ACT_NONE) to front channels. */
613
614
219k
    spkrPos[ch] = getSpeakerPos(channelType[ch], channelIndices[ch],
615
219k
                                numCh[channelType[ch] >> 4][chGrp]);
616
617
1.53M
    for (mapCh = 0; mapCh <= stopSlot; mapCh += 1) {
618
1.31M
      if (offsetTable[mapCh] == 255) {
619
714k
        UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
620
714k
        if (dist < mapDist) {
621
351k
          mapPos = mapCh;
622
351k
          mapDist = dist;
623
351k
        }
624
714k
      }
625
1.31M
    }
626
219k
    if (mapDist <= PCMDMX_THRESHOLD_MAP_HEAT_1) {
627
117k
      offsetTable[mapPos] = (UCHAR)ch;
628
117k
      mapped[ch] = 1;
629
117k
      numMappedInChs += 1;
630
117k
    }
631
219k
  }
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
27.9k
  startSlot =
638
27.9k
      ((numCh[CH_PLAIN_NORMAL][CH_GROUP_FRONT] & 0x1) || (numChannels >= (8)))
639
27.9k
          ? 0
640
27.9k
          : 1;
641
247k
  for (ch = 0; ch < (unsigned)numChannels; ch += 1) {
642
219k
    if (!mapped[ch]) {
643
101k
      UINT mapDist = (unsigned)-1;
644
101k
      unsigned mapCh, mapPos = (unsigned)-1;
645
646
711k
      for (mapCh = startSlot; mapCh <= stopSlot; mapCh += 1) {
647
610k
        if (offsetTable[mapCh] == 255) {
648
74.9k
          UINT dist = getSpeakerDistance(spkrPos[ch], spkrSlotPos[mapCh]);
649
74.9k
          if (dist < mapDist) {
650
49.9k
            mapPos = mapCh;
651
49.9k
            mapDist = dist;
652
49.9k
          }
653
74.9k
        }
654
610k
      }
655
101k
      if ((mapPos <= stopSlot) && (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_2) &&
656
101k
          (((spkrPos[ch].x != 0) && (spkrSlotPos[mapPos].x != 0)) /* XOR */
657
49.9k
           || ((spkrPos[ch].x == 0) &&
658
0
               (spkrSlotPos[mapPos].x ==
659
49.9k
                0)))) { /* Assign center channels to center slots only. */
660
49.9k
        offsetTable[mapPos] = (UCHAR)ch;
661
49.9k
        mapped[ch] = 1;
662
49.9k
        numMappedInChs += 1;
663
49.9k
      }
664
101k
    }
665
219k
  }
666
667
  /* Mapping HEAT 3:
668
   *   Assign the rest by searching for the nearest input channel for each
669
   * internal slot. */
670
247k
  for (ch = startSlot; (ch < (8)) && (numMappedInChs < numChannels); ch += 1) {
671
219k
    if (offsetTable[ch] == 255) {
672
51.7k
      UINT mapDist = (unsigned)-1;
673
51.7k
      unsigned mapCh, mapPos = (unsigned)-1;
674
675
461k
      for (mapCh = 0; mapCh < (unsigned)numChannels; mapCh += 1) {
676
409k
        if (!mapped[mapCh]) {
677
75.5k
          UINT dist = getSpeakerDistance(spkrPos[mapCh], spkrSlotPos[ch]);
678
75.5k
          if (dist < mapDist) {
679
51.7k
            mapPos = mapCh;
680
51.7k
            mapDist = dist;
681
51.7k
          }
682
75.5k
        }
683
409k
      }
684
51.7k
      if (mapDist < PCMDMX_THRESHOLD_MAP_HEAT_3) {
685
51.7k
        offsetTable[ch] = (UCHAR)mapPos;
686
51.7k
        mapped[mapPos] = 1;
687
51.7k
        numMappedInChs += 1;
688
51.7k
        if ((spkrPos[mapPos].x == 0) && (spkrSlotPos[ch].x != 0) &&
689
51.7k
            (numChannels <
690
4.09k
             (8))) { /* Skip the paired slot if we assigned a center channel. */
691
4.09k
          ch += 1;
692
4.09k
        }
693
51.7k
      }
694
51.7k
    }
695
219k
  }
696
697
  /* Finaly compose the channel mode */
698
139k
  for (ch = 0; ch < (4); ch += 1) {
699
111k
    int plane, numChInGrp = 0;
700
446k
    for (plane = 0; plane < (3); plane += 1) {
701
334k
      numChInGrp += numCh[plane][ch];
702
334k
    }
703
111k
    *chMode = (PCM_DMX_CHANNEL_MODE)(*chMode | (numChInGrp << (ch * 4)));
704
111k
  }
705
706
27.9k
  return err;
707
27.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
27.9k
) {
729
27.9k
  int grpIdx, plainIdx, numPlains = 1, numTotalChannels = 0;
730
27.9k
  int chCfg, ch = 0;
731
732
27.9k
  FDK_ASSERT(channelType != NULL);
733
27.9k
  FDK_ASSERT(channelIndices != NULL);
734
27.9k
  FDK_ASSERT(mapDescr != NULL);
735
27.9k
  FDK_ASSERT(offsetTable != NULL);
736
737
  /* Init output arrays */
738
27.9k
  FDKmemclear(channelType, (8) * sizeof(AUDIO_CHANNEL_TYPE));
739
27.9k
  FDKmemclear(channelIndices, (8) * sizeof(UCHAR));
740
27.9k
  FDKmemset(offsetTable, 255, (8) * sizeof(UCHAR));
741
742
  /* Summerize to get the total number of channels */
743
139k
  for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
744
111k
    numTotalChannels += (chMode >> (grpIdx * 4)) & 0xF;
745
111k
  }
746
747
  /* Get the appropriate channel map */
748
27.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
27.9k
    case CH_MODE_3_0_2_1:
755
27.9k
      chCfg = numTotalChannels;
756
27.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
27.9k
  }
771
772
  /* Compose channel offset table */
773
774
55.8k
  for (plainIdx = 0; plainIdx < numPlains; plainIdx += 1) {
775
27.9k
    PCM_DMX_CHANNEL_MODE plainChMode;
776
27.9k
    UCHAR numChInGrp[(4)];
777
778
27.9k
    plainChMode = getChMode4Plain(plainIdx, chMode, chCfg);
779
780
    /* Extract the number of channels per group */
781
27.9k
    numChInGrp[CH_GROUP_FRONT] = plainChMode & 0xF;
782
27.9k
    numChInGrp[CH_GROUP_SIDE] = (plainChMode >> 4) & 0xF;
783
27.9k
    numChInGrp[CH_GROUP_REAR] = (plainChMode >> 8) & 0xF;
784
27.9k
    numChInGrp[CH_GROUP_LFE] = (plainChMode >> 12) & 0xF;
785
786
    /* Non-symmetric channels */
787
27.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
27.9k
      int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
791
27.9k
      offsetTable[CENTER_FRONT_CHANNEL] = (UCHAR)mappedIdx;
792
27.9k
      channelType[mappedIdx] = ACT_FRONT;
793
27.9k
      channelIndices[mappedIdx] = 0;
794
27.9k
      ch += 1;
795
27.9k
    }
796
797
139k
    for (grpIdx = 0; grpIdx < (4); grpIdx += 1) {
798
111k
      AUDIO_CHANNEL_TYPE type = ACT_NONE;
799
111k
      int chMapPos = 0, maxChannels = 0;
800
111k
      int chIdx = 0; /* Index of channel within the specific group */
801
802
111k
      switch (grpIdx) {
803
27.9k
        case CH_GROUP_FRONT:
804
27.9k
          type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_FRONT);
805
27.9k
          switch (plainIdx) {
806
27.9k
            default:
807
27.9k
              chMapPos = LEFT_FRONT_CHANNEL;
808
27.9k
              chIdx = numChInGrp[grpIdx] & 0x1;
809
27.9k
              break;
810
27.9k
          }
811
27.9k
          maxChannels = 3;
812
27.9k
          break;
813
27.9k
        case CH_GROUP_SIDE:
814
          /* Always map side channels to the multipurpose group. */
815
27.9k
          type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_SIDE);
816
27.9k
          if (plainIdx == CH_PLAIN_TOP) {
817
0
            chMapPos = LEFT_SIDE_CHANNEL_TOP;
818
0
            maxChannels = 3;
819
27.9k
          } else {
820
27.9k
            chMapPos = LEFT_MULTIPRPS_CHANNEL;
821
27.9k
            maxChannels = 2;
822
27.9k
          }
823
27.9k
          break;
824
27.9k
        case CH_GROUP_REAR:
825
27.9k
          type = (AUDIO_CHANNEL_TYPE)((plainIdx << 4) | ACT_BACK);
826
27.9k
          if (plainIdx == CH_PLAIN_TOP) {
827
0
            chMapPos = LEFT_REAR_CHANNEL_TOP;
828
0
            maxChannels = 3;
829
27.9k
          } else {
830
27.9k
            chMapPos = LEFT_REAR_CHANNEL;
831
27.9k
            maxChannels = 2;
832
27.9k
          }
833
27.9k
          break;
834
27.9k
        case CH_GROUP_LFE:
835
27.9k
          if (plainIdx == CH_PLAIN_NORMAL) {
836
27.9k
            type = ACT_LFE;
837
27.9k
            chMapPos = LOW_FREQUENCY_CHANNEL;
838
27.9k
            maxChannels = 1;
839
27.9k
          }
840
27.9k
          break;
841
0
        default:
842
0
          break;
843
111k
      }
844
845
      /* Map all channels in this group */
846
251k
      for (; chIdx < numChInGrp[grpIdx]; chIdx += 1) {
847
139k
        int mappedIdx = FDK_chMapDescr_getMapValue(mapDescr, (UCHAR)ch, chCfg);
848
139k
        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
139k
        offsetTable[chMapPos] = (UCHAR)mappedIdx;
858
139k
        channelType[mappedIdx] = type;
859
139k
        channelIndices[mappedIdx] = (UCHAR)chIdx;
860
139k
        chMapPos += 1;
861
139k
        ch += 1;
862
139k
      }
863
111k
    }
864
27.9k
  }
865
27.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
223k
                           INT mixScales[(8)][(8)], const unsigned int outCh) {
877
223k
  unsigned int inCh;
878
2.00M
  for (inCh = 0; inCh < (8); inCh += 1) {
879
1.78M
    if (inCh == outCh) {
880
223k
      mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.5f);
881
223k
      mixScales[outCh][inCh] = 1;
882
1.56M
    } else {
883
1.56M
      mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.0f);
884
1.56M
      mixScales[outCh][inCh] = 0;
885
1.56M
    }
886
1.78M
  }
887
223k
}
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
4.09k
                            INT mixScales[(8)][(8)], const unsigned int outCh) {
899
4.09k
  FDK_ASSERT((outCh >= 0) && (outCh < (8)));
900
4.09k
  FDKmemclear(&mixFactors[outCh], (8) * sizeof(FIXP_DMX));
901
4.09k
  FDKmemclear(&mixScales[outCh], (8) * sizeof(INT));
902
4.09k
}
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
131k
                          const INT scale) {
921
131k
  int ch;
922
1.18M
  for (ch = 0; ch < (8); ch += 1) {
923
1.05M
    if (mixFactors[srcCh][ch] != (FIXP_DMX)0) {
924
148k
      mixFactors[dstCh][ch] =
925
148k
          FX_DBL2FX_DMX(fMult(mixFactors[srcCh][ch], factor));
926
148k
      mixScales[dstCh][ch] = mixScales[srcCh][ch] + scale;
927
148k
    }
928
1.05M
  }
929
131k
}
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
27.9k
                                  INT *pOutScale) {
991
27.9k
  PCMDMX_ERROR err = PCMDMX_OK;
992
27.9k
  INT mixScales[(8)][(8)];
993
27.9k
  INT maxScale = 0;
994
27.9k
  int numInChannel;
995
27.9k
  int numOutChannel;
996
27.9k
  int dmxMethod;
997
27.9k
  unsigned int outCh, inChCfg = 0;
998
27.9k
  unsigned int valid[(8)] = {0};
999
1000
27.9k
  FDK_ASSERT(pMetaData != NULL);
1001
27.9k
  FDK_ASSERT(mixFactors != NULL);
1002
  /* Check on a supported output configuration.
1003
     Add new one only after extensive testing! */
1004
27.9k
  if (!((outChMode == CH_MODE_1_0_0_0) || (outChMode == CH_MODE_2_0_0_0) ||
1005
27.9k
        (outChMode == CH_MODE_3_0_2_1) || (outChMode == CH_MODE_3_0_4_1) ||
1006
27.9k
        (outChMode == CH_MODE_5_0_2_1))) {
1007
0
    FDK_ASSERT(0);
1008
0
  }
1009
1010
27.9k
  if (inModeIsCfg) {
1011
    /* Convert channel config to channel mode: */
1012
27.9k
    inChCfg = (unsigned int)inChMode;
1013
27.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
4.09k
      case 11:
1023
4.09k
        inChMode = CH_MODE_3_0_3_1;
1024
4.09k
        break;
1025
2.93k
      case 12:
1026
2.93k
        inChMode = CH_MODE_3_0_4_1;
1027
2.93k
        break;
1028
8.57k
      case 7:
1029
20.8k
      case 14:
1030
20.8k
        inChMode = CH_MODE_5_0_2_1;
1031
20.8k
        break;
1032
0
      default:
1033
0
        FDK_ASSERT(0);
1034
27.9k
    }
1035
27.9k
  }
1036
1037
  /* Extract the total number of input channels */
1038
27.9k
  numInChannel = (inChMode & 0xF) + ((inChMode >> 4) & 0xF) +
1039
27.9k
                 ((inChMode >> 8) & 0xF) + ((inChMode >> 12) & 0xF);
1040
  /* Extract the total number of output channels */
1041
27.9k
  numOutChannel = (outChMode & 0xF) + ((outChMode >> 4) & 0xF) +
1042
27.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
251k
  for (outCh = 0; outCh < (8); outCh += 1) {
1048
223k
    dmxInitChannel(mixFactors, mixScales, outCh);
1049
223k
  }
1050
27.9k
  if (((inChMode >> 12) & 0xF) == 0) {
1051
    /* Clear empty or wrongly mapped input channel */
1052
1
    dmxClearChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL);
1053
1
  }
1054
1055
  /* FIRST STAGE: */
1056
27.9k
  if (numInChannel > SIX_CHANNEL) { /* Always use MPEG equations either with
1057
                                       meta data or with default values. */
1058
27.9k
    FIXP_DMX dMixFactA, dMixFactB;
1059
27.9k
    INT dMixScaleA, dMixScaleB;
1060
27.9k
    int isValidCfg = TRUE;
1061
1062
    /* Get factors from meta data */
1063
27.9k
    dMixFactA = abMixLvlValueTab[pMetaData->dmixIdxA];
1064
27.9k
    dMixScaleA = (pMetaData->dmixIdxA == 0) ? 1 : 0;
1065
27.9k
    dMixFactB = abMixLvlValueTab[pMetaData->dmixIdxB];
1066
27.9k
    dMixScaleB = (pMetaData->dmixIdxB == 0) ? 1 : 0;
1067
1068
    /* Check if input is in the list of supported configurations */
1069
27.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
4.09k
      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
4.09k
        dmxClearChannel(
1080
4.09k
            mixFactors, mixScales,
1081
4.09k
            RIGHT_MULTIPRPS_CHANNEL); /* clear empty input channel */
1082
4.09k
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1083
4.09k
                      LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1084
4.09k
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1085
4.09k
                      LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1086
4.09k
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1087
4.09k
                      RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1088
4.09k
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1089
4.09k
                      LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1090
4.09k
        break;
1091
2.93k
      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
2.93k
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1096
2.93k
                      LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1097
2.93k
        dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL,
1098
2.93k
                      LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1099
2.93k
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1100
2.93k
                      RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA);
1101
2.93k
        dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1102
2.93k
                      RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1103
2.93k
        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
20.8k
      case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */
1118
20.8k
        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
12.3k
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1123
12.3k
                        LEFT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
1124
12.3k
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1125
12.3k
                        LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1126
12.3k
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1127
12.3k
                        RIGHT_FRONT_CHANNEL, dMixFactA, dMixScaleA);
1128
12.3k
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1129
12.3k
                        RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1130
12.3k
        } 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
8.57k
          dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1136
8.57k
                        LEFT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
1137
8.57k
          dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1138
8.57k
                        RIGHT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA);
1139
8.57k
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1140
8.57k
                        LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1141
8.57k
          dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1142
8.57k
                        LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1143
8.57k
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1144
8.57k
                        RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB);
1145
8.57k
          dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1146
8.57k
                        RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 1);
1147
8.57k
        }
1148
20.8k
        break;
1149
1
      default:
1150
        /* Nothing to do. Just use the identity matrix. */
1151
1
        isValidCfg = FALSE;
1152
1
        err = PCMDMX_INVALID_MODE;
1153
1
        break;
1154
27.9k
    }
1155
1156
    /* Add additional DMX gain */
1157
27.9k
    if ((isValidCfg == TRUE) &&
1158
27.9k
        (pMetaData->dmxGainIdx5 != 0)) { /* Apply DMX gain 5 */
1159
502
      FIXP_DMX dmxGain;
1160
502
      INT dmxScale;
1161
502
      INT sign = (pMetaData->dmxGainIdx5 & 0x40) ? -1 : 1;
1162
502
      INT val = pMetaData->dmxGainIdx5 & 0x3F;
1163
1164
      /* 10^(dmx_gain_5/80) */
1165
502
      dmxGain = FX_DBL2FX_DMX(
1166
502
          fLdPow(FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */
1167
502
                 (FIXP_DBL)(sign * val * (LONG)FL2FXCONST_DBL(0.0125f)), 0,
1168
502
                 &dmxScale));
1169
      /* Currently only positive scale factors supported! */
1170
502
      if (dmxScale < 0) {
1171
263
        dmxGain >>= -dmxScale;
1172
263
        dmxScale = 0;
1173
263
      }
1174
1175
502
      dmxSetChannel(mixFactors, mixScales, CENTER_FRONT_CHANNEL,
1176
502
                    CENTER_FRONT_CHANNEL, dmxGain, dmxScale);
1177
502
      dmxSetChannel(mixFactors, mixScales, LEFT_FRONT_CHANNEL,
1178
502
                    LEFT_FRONT_CHANNEL, dmxGain, dmxScale);
1179
502
      dmxSetChannel(mixFactors, mixScales, RIGHT_FRONT_CHANNEL,
1180
502
                    RIGHT_FRONT_CHANNEL, dmxGain, dmxScale);
1181
502
      dmxSetChannel(mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL,
1182
502
                    dmxGain, dmxScale);
1183
502
      dmxSetChannel(mixFactors, mixScales, RIGHT_REAR_CHANNEL,
1184
502
                    RIGHT_REAR_CHANNEL, dmxGain, dmxScale);
1185
502
      dmxSetChannel(mixFactors, mixScales, LOW_FREQUENCY_CHANNEL,
1186
502
                    LOW_FREQUENCY_CHANNEL, dmxGain, dmxScale);
1187
502
    }
1188
1189
    /* Mark the output channels */
1190
27.9k
    valid[CENTER_FRONT_CHANNEL] = 1;
1191
27.9k
    valid[LEFT_FRONT_CHANNEL] = 1;
1192
27.9k
    valid[RIGHT_FRONT_CHANNEL] = 1;
1193
27.9k
    valid[LEFT_REAR_CHANNEL] = 1;
1194
27.9k
    valid[RIGHT_REAR_CHANNEL] = 1;
1195
27.9k
    valid[LOW_FREQUENCY_CHANNEL] = 1;
1196
1197
    /* Update channel mode for the next stage */
1198
27.9k
    inChMode = CH_MODE_3_0_2_1;
1199
27.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
27.9k
#define DMX_METHOD_MPEG_AMD4 1
1207
27.9k
#define DMX_METHOD_MPEG_LEGACY 2
1208
27.9k
#define DMX_METHOD_ARIB_JAPAN 4
1209
27.9k
#define DMX_METHOD_ITU_RECOM 8
1210
27.9k
#define DMX_METHOD_CUSTOM 16
1211
1212
27.9k
  dmxMethod = DMX_METHOD_MPEG_AMD4; /* default */
1213
1214
27.9k
  if ((pParams->dmxProfile == DMX_PRFL_FORCE_MATRIX_MIX) &&
1215
27.9k
      (pMetaData->typeFlags & TYPE_PCE_DATA)) {
1216
0
    dmxMethod = DMX_METHOD_MPEG_LEGACY;
1217
27.9k
  } else if (!(pMetaData->typeFlags &
1218
27.9k
               (TYPE_DSE_CLEV_DATA | TYPE_DSE_SLEV_DATA))) {
1219
27.4k
    switch (pParams->dmxProfile) {
1220
0
      default:
1221
27.4k
      case DMX_PRFL_STANDARD:
1222
        /* dmxMethod = DMX_METHOD_MPEG_AMD4; */
1223
27.4k
        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
27.4k
    }
1234
27.4k
  }
1235
1236
  /* SECOND STAGE: */
1237
27.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
27.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
251k
#define MAX_SEARCH_START_VAL (-7)
1535
1536
27.9k
  {
1537
27.9k
    LONG chSum[(8)];
1538
27.9k
    INT chSumMax = MAX_SEARCH_START_VAL;
1539
1540
    /* Determine the current maximum scale factor */
1541
251k
    for (outCh = 0; outCh < (8); outCh += 1) {
1542
223k
      if (valid[outCh] != 0) {
1543
167k
        unsigned int inCh;
1544
1.50M
        for (inCh = 0; inCh < (8); inCh += 1) {
1545
1.33M
          if (mixScales[outCh][inCh] > maxScale) { /* Store the new maximum */
1546
36.5k
            maxScale = mixScales[outCh][inCh];
1547
36.5k
          }
1548
1.33M
        }
1549
167k
      }
1550
223k
    }
1551
1552
    /* Individualy analyse output chanal levels */
1553
251k
    for (outCh = 0; outCh < (8); outCh += 1) {
1554
223k
      chSum[outCh] = MAX_SEARCH_START_VAL;
1555
223k
      if (valid[outCh] != 0) {
1556
167k
        int ovrflwProtScale = 0;
1557
167k
        unsigned int inCh;
1558
1559
        /* Accumulate all factors for each output channel */
1560
167k
        chSum[outCh] = 0;
1561
1.50M
        for (inCh = 0; inCh < (8); inCh += 1) {
1562
1.33M
          SHORT addFact = FX_DMX2SHRT(mixFactors[outCh][inCh]);
1563
1.33M
          if (mixScales[outCh][inCh] <= maxScale) {
1564
1.33M
            addFact >>= maxScale - mixScales[outCh][inCh];
1565
1.33M
          } else {
1566
0
            addFact <<= mixScales[outCh][inCh] - maxScale;
1567
0
          }
1568
1.33M
          chSum[outCh] += addFact;
1569
1.33M
        }
1570
167k
        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
167k
        } else if (chSum[outCh] > 0) {
1576
215k
          while ((chSum[outCh] << 1) <= (LONG)MAXVAL_SGL) {
1577
48.4k
            ovrflwProtScale -= 1;
1578
48.4k
            chSum[outCh] <<= 1;
1579
48.4k
          }
1580
166k
        }
1581
        /* Store the differential scaling in the same array */
1582
167k
        chSum[outCh] = ovrflwProtScale;
1583
167k
      }
1584
223k
    }
1585
1586
251k
    for (outCh = 0; outCh < (8); outCh += 1) {
1587
223k
      if ((valid[outCh] != 0) &&
1588
223k
          (chSum[outCh] > chSumMax)) { /* Store the new maximum */
1589
28.3k
        chSumMax = chSum[outCh];
1590
28.3k
      }
1591
223k
    }
1592
27.9k
    maxScale = fMax(maxScale + chSumMax, 0);
1593
1594
    /* Normalize all factors */
1595
251k
    for (outCh = 0; outCh < (8); outCh += 1) {
1596
223k
      if (valid[outCh] != 0) {
1597
167k
        unsigned int inCh;
1598
1.50M
        for (inCh = 0; inCh < (8); inCh += 1) {
1599
1.33M
          if (mixFactors[outCh][inCh] != (FIXP_DMX)0) {
1600
238k
            if (mixScales[outCh][inCh] <= maxScale) {
1601
238k
              mixFactors[outCh][inCh] >>= maxScale - mixScales[outCh][inCh];
1602
238k
            } else {
1603
912
              mixFactors[outCh][inCh] <<= mixScales[outCh][inCh] - maxScale;
1604
912
            }
1605
238k
            mixScales[outCh][inCh] = maxScale;
1606
238k
          }
1607
1.33M
        }
1608
167k
      }
1609
223k
    }
1610
27.9k
  }
1611
1612
  /* return the scale factor */
1613
27.9k
  *pOutScale = maxScale;
1614
1615
27.9k
  return (err);
1616
27.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
27.5k
PCMDMX_ERROR pcmDmx_Open(HANDLE_PCM_DOWNMIX *pSelf) {
1623
27.5k
  HANDLE_PCM_DOWNMIX self;
1624
1625
27.5k
  if (pSelf == NULL) {
1626
0
    return (PCMDMX_INVALID_HANDLE);
1627
0
  }
1628
1629
27.5k
  *pSelf = NULL;
1630
1631
27.5k
  self = (HANDLE_PCM_DOWNMIX)GetPcmDmxInstance(0);
1632
27.5k
  if (self == NULL) {
1633
0
    return (PCMDMX_OUT_OF_MEMORY);
1634
0
  }
1635
1636
  /* Reset the full instance */
1637
27.5k
  pcmDmx_Reset(self, PCMDMX_RESET_FULL);
1638
1639
27.5k
  *pSelf = self;
1640
1641
27.5k
  return (PCMDMX_OK);
1642
27.5k
}
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
746k
PCMDMX_ERROR pcmDmx_Reset(HANDLE_PCM_DOWNMIX self, UINT flags) {
1650
746k
  if (self == NULL) {
1651
0
    return (PCMDMX_INVALID_HANDLE);
1652
0
  }
1653
1654
746k
  if (flags & PCMDMX_RESET_PARAMS) {
1655
27.5k
    PCM_DMX_USER_PARAMS *pParams = &self->userParams;
1656
1657
27.5k
    pParams->dualChannelMode = STEREO_MODE;
1658
27.5k
    pParams->pseudoSurrMode = NEVER_DO_PS_DMX;
1659
27.5k
    pParams->numOutChannelsMax = (6);
1660
27.5k
    pParams->numOutChannelsMin = (0);
1661
27.5k
    pParams->frameDelay = 0;
1662
27.5k
    pParams->expiryFrame = (0);
1663
1664
27.5k
    self->applyProcessing = 0;
1665
27.5k
  }
1666
1667
746k
  if (flags & PCMDMX_RESET_BS_DATA) {
1668
746k
    int slot;
1669
    /* Init all slots with a default set */
1670
2.23M
    for (slot = 0; slot <= (1); slot += 1) {
1671
1.49M
      FDKmemcpy(&self->bsMetaData[slot], &dfltMetaData,
1672
1.49M
                sizeof(DMX_BS_META_DATA));
1673
1.49M
    }
1674
746k
  }
1675
1676
746k
  return (PCMDMX_OK);
1677
746k
}
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
554k
                             const INT value) {
1687
554k
  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
507k
    case DMX_BS_DATA_EXPIRY_FRAME:
1703
507k
      if (self == NULL) return (PCMDMX_INVALID_HANDLE);
1704
507k
      self->userParams.expiryFrame = (value > 0) ? (UINT)value : 0;
1705
507k
      break;
1706
1707
46.3k
    case DMX_BS_DATA_DELAY:
1708
46.3k
      if ((value > (1)) || (value < 0)) {
1709
0
        return (PCMDMX_UNABLE_TO_SET_PARAM);
1710
0
      }
1711
46.3k
      if (self == NULL) {
1712
0
        return (PCMDMX_INVALID_HANDLE);
1713
0
      }
1714
46.3k
      self->userParams.frameDelay = (UCHAR)value;
1715
46.3k
      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
554k
  }
1798
1799
554k
  return (PCMDMX_OK);
1800
554k
}
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
476k
                             INT *const pValue) {
1810
476k
  PCM_DMX_USER_PARAMS *pUsrParams;
1811
1812
476k
  if ((self == NULL) || (pValue == NULL)) {
1813
0
    return (PCMDMX_INVALID_HANDLE);
1814
0
  }
1815
476k
  pUsrParams = &self->userParams;
1816
1817
476k
  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
161k
    case MIN_NUMBER_OF_OUTPUT_CHANNELS:
1828
161k
      *pValue = (INT)pUsrParams->numOutChannelsMin;
1829
161k
      break;
1830
315k
    case MAX_NUMBER_OF_OUTPUT_CHANNELS:
1831
315k
      *pValue = (INT)pUsrParams->numOutChannelsMax;
1832
315k
      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
476k
  }
1842
1843
476k
  return (PCMDMX_OK);
1844
476k
}
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
11.2k
                          UINT ancDataBits, int isMpeg2) {
1851
11.2k
  PCMDMX_ERROR errorStatus = PCMDMX_OK;
1852
1853
11.2k
#define MAX_DSE_ANC_BYTES (16)    /* 15 bytes */
1854
11.2k
#define ANC_DATA_SYNC_BYTE (0xBC) /* ancillary data sync byte. */
1855
1856
11.2k
  DMX_BS_META_DATA *pBsMetaData;
1857
1858
11.2k
  int skip4Dmx = 0, skip4Ext = 0;
1859
11.2k
  int dmxLvlAvail = 0, extDataAvail = 0;
1860
11.2k
  UINT foundNewData = 0;
1861
11.2k
  UINT minAncBits = ((isMpeg2) ? 5 : 3) * 8;
1862
1863
11.2k
  if ((self == NULL) || (hBs == NULL)) {
1864
0
    return (PCMDMX_INVALID_HANDLE);
1865
0
  }
1866
1867
  /* sanity checks */
1868
11.2k
  if ((ancDataBits < minAncBits) || (ancDataBits > FDKgetValidBits(hBs))) {
1869
7.18k
    return (PCMDMX_CORRUPT_ANC_DATA);
1870
7.18k
  }
1871
1872
4.06k
  pBsMetaData = &self->bsMetaData[0];
1873
1874
4.06k
  if (isMpeg2) {
1875
    /* skip DVD ancillary data */
1876
0
    FDKpushFor(hBs, 16);
1877
0
  }
1878
1879
  /* check sync word */
1880
4.06k
  if (FDKreadBits(hBs, 8) != ANC_DATA_SYNC_BYTE) {
1881
902
    return (PCMDMX_CORRUPT_ANC_DATA);
1882
902
  }
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.22k
    if (FDKreadBit(hBs)) { /* center_mix_level_on */
1925
1.76k
      pBsMetaData->cLevIdx = (UCHAR)FDKreadBits(hBs, 3);
1926
1.76k
      foundNewData |= TYPE_DSE_CLEV_DATA;
1927
1.76k
    } else {
1928
467
      FDKreadBits(hBs, 3);
1929
467
    }
1930
2.22k
    if (FDKreadBit(hBs)) { /* surround_mix_level_on */
1931
675
      pBsMetaData->sLevIdx = (UCHAR)FDKreadBits(hBs, 3);
1932
675
      foundNewData |= TYPE_DSE_SLEV_DATA;
1933
1.55k
    } else {
1934
1.55k
      FDKreadBits(hBs, 3);
1935
1.55k
    }
1936
2.22k
  }
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.68k
    int extDmxLvlSt, extDmxGainSt, extDmxLfeSt;
1944
1945
2.68k
    FDKreadBit(hBs); /* reserved bit */
1946
2.68k
    extDmxLvlSt = FDKreadBit(hBs);
1947
2.68k
    extDmxGainSt = FDKreadBit(hBs);
1948
2.68k
    extDmxLfeSt = FDKreadBit(hBs);
1949
2.68k
    FDKreadBits(hBs, 4); /* reserved bits */
1950
1951
2.68k
    if (extDmxLvlSt) {
1952
1.13k
      pBsMetaData->dmixIdxA = (UCHAR)FDKreadBits(hBs, 3);
1953
1.13k
      pBsMetaData->dmixIdxB = (UCHAR)FDKreadBits(hBs, 3);
1954
1.13k
      FDKreadBits(hBs, 2); /* reserved bits */
1955
1.13k
      foundNewData |= TYPE_DSE_DMIX_AB_DATA;
1956
1.13k
    }
1957
2.68k
    if (extDmxGainSt) {
1958
1.20k
      pBsMetaData->dmxGainIdx5 = (UCHAR)FDKreadBits(hBs, 7);
1959
1.20k
      FDKreadBit(hBs); /* reserved bit */
1960
1.20k
      pBsMetaData->dmxGainIdx2 = (UCHAR)FDKreadBits(hBs, 7);
1961
1.20k
      FDKreadBit(hBs); /* reserved bit */
1962
1.20k
      foundNewData |= TYPE_DSE_DMX_GAIN_DATA;
1963
1.20k
    }
1964
2.68k
    if (extDmxLfeSt) {
1965
1.34k
      pBsMetaData->dmixIdxLfe = (UCHAR)FDKreadBits(hBs, 4);
1966
1.34k
      FDKreadBits(hBs, 4); /* reserved bits */
1967
1.34k
      foundNewData |= TYPE_DSE_DMIX_LFE_DATA;
1968
1.34k
    }
1969
2.68k
  }
1970
1971
  /* final sanity check on the amount of read data */
1972
3.15k
  if ((INT)FDKgetValidBits(hBs) < 0) {
1973
65
    errorStatus = PCMDMX_CORRUPT_ANC_DATA;
1974
65
  }
1975
1976
3.15k
  if ((errorStatus == PCMDMX_OK) && (foundNewData != 0)) {
1977
    /* announce new data */
1978
2.32k
    pBsMetaData->typeFlags |= foundNewData;
1979
    /* reset expiry counter */
1980
2.32k
    pBsMetaData->expiryCount = 0;
1981
2.32k
  }
1982
1983
3.15k
  return (errorStatus);
1984
4.06k
}
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
74.1k
                                            int pseudoSurroundEnable) {
2023
74.1k
  if (self == NULL) {
2024
0
    return (PCMDMX_INVALID_HANDLE);
2025
0
  }
2026
2027
74.1k
  {
2028
74.1k
    DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0];
2029
2030
74.1k
    if (matrixMixdownPresent) {
2031
4.39k
      pBsMetaData->pseudoSurround = (pseudoSurroundEnable) ? 1 : 0;
2032
4.39k
      pBsMetaData->matrixMixdownIdx = matrixMixdownIdx & 0x03;
2033
4.39k
      pBsMetaData->typeFlags |= TYPE_PCE_DATA;
2034
      /* Reset expiry counter */
2035
4.39k
      pBsMetaData->expiryCount = 0;
2036
4.39k
    }
2037
74.1k
  }
2038
2039
74.1k
  return (PCMDMX_OK);
2040
74.1k
}
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
439k
                               INT *pDmxOutScale) {
2067
439k
  PCM_DMX_USER_PARAMS *pParam = NULL;
2068
439k
  PCMDMX_ERROR errorStatus = PCMDMX_OK;
2069
439k
  DUAL_CHANNEL_MODE dualChannelMode;
2070
439k
  PCM_DMX_CHANNEL_MODE inChMode;
2071
439k
  PCM_DMX_CHANNEL_MODE outChMode;
2072
439k
  INT devNull; /* Just a dummy to avoid a lot of branches in the code */
2073
439k
  int numOutChannels, numInChannels;
2074
439k
  int inStride, outStride, offset;
2075
439k
  int dmxMaxScale, dmxScale;
2076
439k
  int slot;
2077
439k
  UCHAR inOffsetTable[(8)];
2078
2079
439k
  DMX_BS_META_DATA bsMetaData;
2080
2081
439k
  if ((self == NULL) || (nChannels == NULL) || (channelType == NULL) ||
2082
439k
      (channelIndices == NULL) || (!FDK_chMapDescr_isValid(mapDescr))) {
2083
0
    return (PCMDMX_INVALID_HANDLE);
2084
0
  }
2085
2086
  /* Init the output scaling */
2087
439k
  dmxScale = 0;
2088
439k
  if (pDmxOutScale != NULL) {
2089
    /* Avoid final scaling internally and hand it to the outside world. */
2090
439k
    *pDmxOutScale = 0;
2091
439k
    dmxMaxScale = (3);
2092
439k
  } else {
2093
    /* Apply the scaling internally. */
2094
0
    pDmxOutScale = &devNull; /* redirect to temporal stack memory */
2095
0
    dmxMaxScale = 0;
2096
0
  }
2097
2098
439k
  pParam = &self->userParams;
2099
439k
  numInChannels = *nChannels;
2100
2101
  /* Perform some input sanity checks */
2102
439k
  if (pPcmBuf == NULL) {
2103
0
    return (PCMDMX_INVALID_ARGUMENT);
2104
0
  }
2105
439k
  if (frameSize == 0) {
2106
0
    return (PCMDMX_INVALID_ARGUMENT);
2107
0
  }
2108
439k
  if (numInChannels == 0) {
2109
0
    return (PCMDMX_INVALID_ARGUMENT);
2110
0
  }
2111
439k
  if (numInChannels > (8)) {
2112
0
    return (PCMDMX_INVALID_CH_CONFIG);
2113
0
  }
2114
2115
  /* Check on misconfiguration */
2116
439k
  FDK_ASSERT((pParam->numOutChannelsMax <= 0) ||
2117
439k
             (pParam->numOutChannelsMax >= pParam->numOutChannelsMin));
2118
2119
  /* Determine if the module has to do processing */
2120
439k
  if ((self->applyProcessing == 0) &&
2121
439k
      ((pParam->numOutChannelsMax <= 0) ||
2122
439k
       (pParam->numOutChannelsMax >= numInChannels)) &&
2123
439k
      (pParam->numOutChannelsMin <= numInChannels)) {
2124
    /* Nothing to do */
2125
411k
    return (errorStatus);
2126
411k
  }
2127
2128
  /* Determine the number of output channels */
2129
27.9k
  if ((pParam->numOutChannelsMax > 0) &&
2130
27.9k
      (numInChannels > pParam->numOutChannelsMax)) {
2131
27.9k
    numOutChannels = pParam->numOutChannelsMax;
2132
27.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
27.9k
  if ((UINT)pcmBufSize < (UINT)numOutChannels * frameSize) {
2140
0
    return (PCMDMX_OUTPUT_BUFFER_TOO_SMALL);
2141
0
  }
2142
2143
27.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
27.9k
  errorStatus = getChannelMode(numInChannels, channelType, channelIndices,
2148
27.9k
                               inOffsetTable, &inChMode);
2149
27.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
27.9k
  if (fInterleaved) {
2157
18.4k
    inStride = numInChannels;
2158
18.4k
    offset = 1; /* Channel specific offset factor */
2159
18.4k
  } else {
2160
9.42k
    inStride = 1;
2161
9.42k
    offset = frameSize; /* Channel specific offset factor */
2162
9.42k
  }
2163
2164
  /* Reset downmix meta data if necessary */
2165
27.9k
  if ((pParam->expiryFrame > 0) &&
2166
27.9k
      (++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
27.9k
  FDKmemcpy(&bsMetaData, &self->bsMetaData[pParam->frameDelay],
2177
27.9k
            sizeof(DMX_BS_META_DATA));
2178
  /* Maintain delay line */
2179
28.4k
  for (slot = pParam->frameDelay; slot > 0; slot -= 1) {
2180
573
    FDKmemcpy(&self->bsMetaData[slot], &self->bsMetaData[slot - 1],
2181
573
              sizeof(DMX_BS_META_DATA));
2182
573
  }
2183
2184
  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2185
   * - - - - - - - - - - - - - - - - - - */
2186
27.9k
  if (numInChannels > numOutChannels) { /* Apply downmix */
2187
27.9k
    DMX_PCM *pInPcm[(8)] = {NULL};
2188
27.9k
    DMX_PCM *pOutPcm[(8)] = {NULL};
2189
27.9k
    FIXP_DMX mixFactors[(8)][(8)];
2190
27.9k
    UCHAR outOffsetTable[(8)];
2191
27.9k
    UINT sample;
2192
27.9k
    int chCfg = 0;
2193
27.9k
    int bypScale = 0;
2194
2195
27.9k
    if (numInChannels > SIX_CHANNEL) {
2196
27.9k
      AUDIO_CHANNEL_TYPE multiPurposeChType[2];
2197
2198
      /* Get the type of the multipurpose channels */
2199
27.9k
      multiPurposeChType[0] =
2200
27.9k
          channelType[inOffsetTable[LEFT_MULTIPRPS_CHANNEL]];
2201
27.9k
      multiPurposeChType[1] =
2202
27.9k
          channelType[inOffsetTable[RIGHT_MULTIPRPS_CHANNEL]];
2203
2204
      /* Check if the input configuration is one defined in the standard. */
2205
27.9k
      switch (inChMode) {
2206
20.8k
        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
20.8k
          if ((multiPurposeChType[0] == ACT_FRONT_TOP) &&
2210
20.8k
              (multiPurposeChType[1] == ACT_FRONT_TOP)) {
2211
12.3k
            chCfg = 14;
2212
12.3k
          } else {
2213
8.57k
            chCfg = 7;
2214
8.57k
          }
2215
20.8k
          break;
2216
4.09k
        case CH_MODE_3_0_3_1: /* chCfg 11 */
2217
4.09k
          chCfg = 11;
2218
4.09k
          break;
2219
2.93k
        case CH_MODE_3_0_4_1: /* chCfg 12 */
2220
2.93k
          chCfg = 12;
2221
2.93k
          break;
2222
1
        default:
2223
1
          chCfg = 0; /* Not a known config */
2224
1
          break;
2225
27.9k
      }
2226
27.9k
    }
2227
2228
    /* Set this stages output stride and channel mode: */
2229
27.9k
    outStride = (fInterleaved) ? numOutChannels : 1;
2230
27.9k
    outChMode = outChModeTable[numOutChannels];
2231
27.9k
    FDK_ASSERT(outChMode != CH_MODE_UNDEFINED);
2232
2233
    /* Get channel description and channel mapping for the desired output
2234
     * configuration. */
2235
27.9k
    getChannelDescription(outChMode, mapDescr, channelType, channelIndices,
2236
27.9k
                          outOffsetTable);
2237
    /* Now there is no way back because we modified the channel configuration!
2238
     */
2239
2240
    /* Create the DMX matrix */
2241
27.9k
    errorStatus =
2242
27.9k
        getMixFactors((chCfg > 0) ? 1 : 0,
2243
27.9k
                      (chCfg > 0) ? (PCM_DMX_CHANNEL_MODE)chCfg : inChMode,
2244
27.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
27.9k
    bypScale = fMin(dmxMaxScale, dmxScale);
2251
27.9k
    *pDmxOutScale += bypScale;
2252
27.9k
    dmxScale -= bypScale;
2253
2254
27.9k
    { /* Set channel pointer for input. Remove empty cols. */
2255
27.9k
      int inCh, outCh, map[(8)];
2256
27.9k
      int ch = 0;
2257
251k
      for (inCh = 0; inCh < (8); inCh += 1) {
2258
223k
        if (inOffsetTable[inCh] < (UCHAR)numInChannels) {
2259
219k
          pInPcm[ch] = &pPcmBuf[inOffsetTable[inCh] * offset];
2260
219k
          map[ch++] = inCh;
2261
219k
        }
2262
223k
      }
2263
32.0k
      for (; ch < (8); ch += 1) {
2264
4.09k
        map[ch] = ch;
2265
4.09k
      }
2266
2267
      /* Remove unused cols from factor matrix */
2268
247k
      for (inCh = 0; inCh < numInChannels; inCh += 1) {
2269
219k
        if (inCh != map[inCh]) {
2270
18
          for (outCh = 0; outCh < (8); outCh += 1) {
2271
16
            mixFactors[outCh][inCh] = mixFactors[outCh][map[inCh]];
2272
16
          }
2273
2
        }
2274
219k
      }
2275
2276
      /* Set channel pointer for output. Remove empty cols. */
2277
27.9k
      ch = 0;
2278
251k
      for (outCh = 0; outCh < (8); outCh += 1) {
2279
223k
        if (outOffsetTable[outCh] < (UCHAR)numOutChannels) {
2280
167k
          pOutPcm[ch] = &pPcmBuf[outOffsetTable[outCh] * offset];
2281
167k
          map[ch++] = outCh;
2282
167k
        }
2283
223k
      }
2284
83.7k
      for (; ch < (8); ch += 1) {
2285
55.8k
        map[ch] = ch;
2286
55.8k
      }
2287
2288
      /* Remove unused rows from factor matrix */
2289
195k
      for (outCh = 0; outCh < numOutChannels; outCh += 1) {
2290
167k
        if (outCh != map[outCh]) {
2291
0
          FDKmemcpy(&mixFactors[outCh], &mixFactors[map[outCh]],
2292
0
                    (8) * sizeof(FIXP_DMX));
2293
0
        }
2294
167k
      }
2295
27.9k
    }
2296
2297
    /* Sample processing loop */
2298
21.4M
    for (sample = 0; sample < frameSize; sample++) {
2299
21.3M
      DMX_PCM tIn[(8)] = {0};
2300
21.3M
      FIXP_DBL tOut[(8)] = {(FIXP_DBL)0};
2301
21.3M
      int inCh, outCh;
2302
2303
      /* Preload all input samples */
2304
189M
      for (inCh = 0; inCh < numInChannels; inCh += 1) {
2305
167M
        if (pInPcm[inCh] != NULL) {
2306
167M
          tIn[inCh] = *pInPcm[inCh];
2307
167M
          pInPcm[inCh] += inStride;
2308
167M
        } else {
2309
0
          tIn[inCh] = (DMX_PCM)0;
2310
0
        }
2311
167M
      }
2312
      /* Apply downmix coefficients to input samples and accumulate for output
2313
       */
2314
149M
      for (outCh = 0; outCh < numOutChannels; outCh += 1) {
2315
1.13G
        for (inCh = 0; inCh < numInChannels; inCh += 1) {
2316
1.00G
          tOut[outCh] += fMult((DMX_PCMF)tIn[inCh], mixFactors[outCh][inCh]);
2317
1.00G
        }
2318
128M
        FDK_ASSERT(pOutPcm[outCh] >= pPcmBuf);
2319
128M
        FDK_ASSERT(pOutPcm[outCh] < &pPcmBuf[pcmBufSize]);
2320
        /* Write sample */
2321
128M
        *pOutPcm[outCh] = (DMX_PCM)SATURATE_SHIFT(
2322
128M
            tOut[outCh], DFRACT_BITS - DMX_PCM_BITS - dmxScale, DMX_PCM_BITS);
2323
128M
        pOutPcm[outCh] += outStride;
2324
128M
      }
2325
21.3M
    }
2326
2327
    /* Update the number of output channels */
2328
27.9k
    *nChannels = numOutChannels;
2329
2330
27.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
27.9k
  return (errorStatus);
2629
27.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
27.5k
PCMDMX_ERROR pcmDmx_Close(HANDLE_PCM_DOWNMIX *pSelf) {
2636
27.5k
  if (pSelf == NULL) {
2637
0
    return (PCMDMX_INVALID_HANDLE);
2638
0
  }
2639
2640
27.5k
  FreePcmDmxInstance(pSelf);
2641
27.5k
  *pSelf = NULL;
2642
2643
27.5k
  return (PCMDMX_OK);
2644
27.5k
}
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
}