Coverage Report

Created: 2025-10-28 06:45

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