Imported Debian version 0.1.3.1
[deb_fdk-aac.git] / libPCMutils / src / pcmutils_lib.cpp
1
2 /* -----------------------------------------------------------------------------------------------------------
3 Software License for The Fraunhofer FDK AAC Codec Library for Android
4
5 © Copyright 1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
6 All rights reserved.
7
8 1. INTRODUCTION
9 The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
10 the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
11 This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
12
13 AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
14 audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
15 independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
16 of the MPEG specifications.
17
18 Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
19 may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
20 individually for the purpose of encoding or decoding bit streams in products that are compliant with
21 the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
22 these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
23 software may already be covered under those patent licenses when it is used for those licensed purposes only.
24
25 Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
26 are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
27 applications information and documentation.
28
29 2. COPYRIGHT LICENSE
30
31 Redistribution and use in source and binary forms, with or without modification, are permitted without
32 payment of copyright license fees provided that you satisfy the following conditions:
33
34 You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
35 your modifications thereto in source code form.
36
37 You must retain the complete text of this software license in the documentation and/or other materials
38 provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
39 You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
40 modifications thereto to recipients of copies in binary form.
41
42 The name of Fraunhofer may not be used to endorse or promote products derived from this library without
43 prior written permission.
44
45 You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
46 software or your modifications thereto.
47
48 Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
49 and the date of any change. For modified versions of the FDK AAC Codec, the term
50 "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
51 "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
52
53 3. NO PATENT LICENSE
54
55 NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
56 ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
57 respect to this software.
58
59 You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
60 by appropriate patent licenses.
61
62 4. DISCLAIMER
63
64 This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
65 "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
66 of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
67 CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
68 including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
69 or business interruption, however caused and on any theory of liability, whether in contract, strict
70 liability, or tort (including negligence), arising in any way out of the use of this software, even if
71 advised of the possibility of such damage.
72
73 5. CONTACT INFORMATION
74
75 Fraunhofer Institute for Integrated Circuits IIS
76 Attention: Audio and Multimedia Departments - FDK AAC LL
77 Am Wolfsmantel 33
78 91058 Erlangen, Germany
79
80 www.iis.fraunhofer.de/amm
81 amm-info@iis.fraunhofer.de
82 ----------------------------------------------------------------------------------------------------------- */
83
84 /**************************** FDK PCM utils module **************************
85
86 Author(s): Christian Griebel
87 Description: Defines functions to interface with the PCM post processing
88 module.
89
90 *******************************************************************************/
91
92 #include "pcmutils_lib.h"
93
94 #include "genericStds.h"
95 #include "fixpoint_math.h"
96
97 /* Decoder library info */
98 #define PCMDMX_LIB_VL0 2
99 #define PCMDMX_LIB_VL1 4
100 #define PCMDMX_LIB_VL2 0
101 #define PCMDMX_LIB_TITLE "PCM Downmix Lib"
102 #define PCMDMX_LIB_BUILD_DATE __DATE__
103 #define PCMDMX_LIB_BUILD_TIME __TIME__
104
105 /* Library settings */
106 #define PCM_DMX_MAX_DELAY_FRAMES ( 1 )
107 #define PCM_DMX_MAX_CHANNELS ( 8 )
108 #define PCM_DMX_MAX_CHANNEL_GROUPS ( 4 )
109 #define PCM_DMX_MAX_CHANNELS_PER_GROUP ( 3 ) /* The maximum over all groups */
110 #define PCMDMX_DFLT_EXPIRY_FRAME ( 50 ) /* At least 500ms (FL 960 @ 96kHz) */
111
112 /* Fixed and unique channel group indices.
113 * The last group index has to be smaller than PCM_DMX_MAX_CHANNEL_GROUPS. */
114 #define CH_GROUP_FRONT ( 0 )
115 #define CH_GROUP_SIDE ( 1 )
116 #define CH_GROUP_REAR ( 2 )
117 #define CH_GROUP_LFE ( 3 )
118
119 /* The ordering of the following fixed channel labels has to be in MPEG-4 style.
120 * From the center to the back with left and right channel interleaved (starting with left).
121 * The last channel label index has to be smaller than PCM_DMX_MAX_CHANNELS. */
122 #define CENTER_FRONT_CHANNEL ( 0 ) /* C */
123 #define LEFT_FRONT_CHANNEL ( 1 ) /* L */
124 #define RIGHT_FRONT_CHANNEL ( 2 ) /* R */
125 #define LEFT_OUTSIDE_CHANNEL ( 3 ) /* Lo */
126 #define RIGHT_OUTSIDE_CHANNEL ( 4 ) /* Ro */
127 #define LEFT_REAR_CHANNEL ( 5 ) /* Lr aka left back channel */
128 #define RIGHT_REAR_CHANNEL ( 6 ) /* Rr aka right back channel */
129 #define LOW_FREQUENCY_CHANNEL ( 7 ) /* Lf */
130
131 /* More constants */
132 #define ANC_DATA_SYNC_BYTE ( 0xBC ) /* ancillary data sync byte. */
133 #define ATTENUATION_FACTOR_1 ( FL2FXCONST_SGL(0.70710678f) )
134 #define TWO_CHANNEL ( 2 )
135
136 /* Sanity checks on library setting: */
137
138 /* List of packed channel modes */
139 typedef enum
140 { /* CH_MODE_<numFrontCh>_<numOutsideCh>_<numRearCh>_<numLfCh> */
141 CH_MODE_UNDEFINED = 0x0000,
142 /* 1 channel */
143 CH_MODE_1_0_0_0 = 0x0001, /* chCfg 1 */
144 /* 2 channels */
145 CH_MODE_2_0_0_0 = 0x0002, /* chCfg 2 */
146 /* 3 channels */
147 CH_MODE_3_0_0_0 = 0x0003, /* chCfg 3 */
148 CH_MODE_2_0_1_0 = 0x0102,
149 CH_MODE_2_0_0_1 = 0x1002,
150 /* 4 channels */
151 CH_MODE_3_0_1_0 = 0x0103, /* chCfg 4 */
152 CH_MODE_2_0_2_0 = 0x0202,
153 CH_MODE_2_0_1_1 = 0x1102,
154 /* 5 channels */
155 CH_MODE_3_0_2_0 = 0x0203, /* chCfg 5 */
156 CH_MODE_2_0_2_1 = 0x1202,
157 CH_MODE_3_0_1_1 = 0x1103,
158 CH_MODE_3_2_0_0 = 0x0023,
159 /* 6 channels */
160 CH_MODE_3_0_2_1 = 0x1203, /* chCfg 6 */
161 CH_MODE_3_2_1_0 = 0x0123,
162 /* 7 channels */
163 CH_MODE_2_2_2_1 = 0x1222,
164 CH_MODE_3_2_1_1 = 0x1123,
165 CH_MODE_3_2_2_0 = 0x0223,
166 /* 8 channels */
167 CH_MODE_3_2_2_1 = 0x1222, /* chCfg 7 */
168 CH_MODE_3_2_1_2 = 0x2123,
169 CH_MODE_2_2_2_2 = 0x2222
170
171 } PCM_DMX_CHANNEL_MODE;
172
173
174 /* These are the channel configurations linked to
175 the number of output channels give by the user: */
176 static const PCM_DMX_CHANNEL_MODE outChModeTable[PCM_DMX_MAX_CHANNELS] =
177 {
178 CH_MODE_1_0_0_0, /* 1 channel */
179 CH_MODE_2_0_0_0, /* 2 channels */
180 CH_MODE_3_0_0_0, /* 3 channels */
181 CH_MODE_3_0_1_0, /* 4 channels */
182 CH_MODE_3_0_2_0, /* 5 channels */
183 CH_MODE_3_0_2_1, /* 6 channels */
184 CH_MODE_3_2_2_0, /* 7 channels */
185 CH_MODE_3_2_2_1 /* 8 channels */
186 };
187
188 static const FIXP_SGL dvbDownmixFactors[8] =
189 {
190 FL2FXCONST_SGL(1.0f),
191 FL2FXCONST_SGL(0.841f),
192 FL2FXCONST_SGL(0.707f),
193 FL2FXCONST_SGL(0.596f),
194 FL2FXCONST_SGL(0.500f),
195 FL2FXCONST_SGL(0.422f),
196 FL2FXCONST_SGL(0.355f),
197 FL2FXCONST_SGL(0.0f)
198 };
199
200
201 /* MPEG matrix mixdown:
202 Set 1: L' = (1 + 2^-0.5 + A )^-1 * [L + C * 2^-0.5 + A * Ls];
203 R' = (1 + 2^-0.5 + A )^-1 * [R + C * 2^-0.5 + A * Rs];
204
205 Set 2: L' = (1 + 2^-0.5 + 2A )^-1 * [L + C * 2^-0.5 - A * (Ls + Rs)];
206 R' = (1 + 2^-0.5 + 2A )^-1 * [R + C * 2^-0.5 + A * (Ls + Rs)];
207
208 M = (3 + 2A)^-1 * [L + C + R + A*(Ls + Rs)];
209 */
210 static const FIXP_SGL mpegMixDownIdx2Coef[4] =
211 {
212 FL2FXCONST_SGL(0.70710678f),
213 FL2FXCONST_SGL(0.5f),
214 FL2FXCONST_SGL(0.35355339f),
215 FL2FXCONST_SGL(0.0f)
216 };
217
218 static const FIXP_SGL mpegMixDownIdx2PreFact[4] =
219 {
220 FL2FXCONST_SGL(0.4142135623730950f),
221 FL2FXCONST_SGL(0.4530818393219728f),
222 FL2FXCONST_SGL(0.4852813742385703f),
223 FL2FXCONST_SGL(0.5857864376269050f)
224 };
225
226 typedef struct
227 {
228 USHORT matrixMixdownIdx; /*!< MPEG mixdown index extracted from PCE. */
229 USHORT pseudoSurroundEnable; /*!< Pseudo surround enable flag extracted from PCE. */
230 USHORT mixdownAvailable; /*!< Will be set to 1 if we found a valid coefficient. */
231
232 } MPEG_MIXDOWN_INFO;
233
234
235 typedef struct
236 {
237 FIXP_SGL centerMixLevelValue; /*!< DVB mixdown level for the center channel extracted from anc data. */
238 FIXP_SGL surroundMixLevelValue; /*!< DVB mixdown level for back channels extracted from anc data. */
239
240 UCHAR mixLevelsAvail; /*!< Will be set to 1 if we found a valid coefficient. */
241
242 } DVB_MIXDOWN_LEVELS;
243
244
245 /* Modules main data structure: */
246 struct PCM_DMX_INSTANCE
247 {
248 DVB_MIXDOWN_LEVELS dvbMixDownLevels[PCM_DMX_MAX_DELAY_FRAMES+1];
249 MPEG_MIXDOWN_INFO mpegMixDownInfo[PCM_DMX_MAX_DELAY_FRAMES+1];
250 DUAL_CHANNEL_MODE dualChannelMode;
251 UINT expiryFrame;
252 UINT expiryCount;
253 SHORT numOutputChannels;
254 UCHAR applyProcessing;
255 UCHAR frameDelay;
256 };
257
258 /* Memory allocation macro */
259 C_ALLOC_MEM_STATIC(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1)
260
261
262 /** Evaluate a given channel configuration and extract a packed channel mode and generate a channel offset table
263 * This function is the inverse to the getChannelDescription() routine.
264 * @param [in] The total number of channels of the given configuration.
265 * @param [in] Array holding the corresponding channel types for each channel.
266 * @param [in] Array holding the corresponding channel type indices for each channel.
267 * @param [out] Array where the buffer offsets for each channel are stored into.
268 * @returns Returns the packed channel mode.
269 **/
270 static
271 PCM_DMX_CHANNEL_MODE getChannelMode (
272 const INT numChannels, /* in */
273 const AUDIO_CHANNEL_TYPE channelType[], /* in */
274 const UCHAR channelIndices[], /* in */
275 UCHAR offsetTable[PCM_DMX_MAX_CHANNELS] /* out */
276 )
277 {
278 UINT chMode = CH_MODE_UNDEFINED;
279 UCHAR chIdx[PCM_DMX_MAX_CHANNEL_GROUPS][PCM_DMX_MAX_CHANNELS_PER_GROUP];
280 UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS];
281 int ch, grpIdx, err = 0;
282
283 FDK_ASSERT(channelType != NULL);
284 FDK_ASSERT(channelIndices != NULL);
285 FDK_ASSERT(offsetTable != NULL);
286
287 /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */
288 FDKmemclear(numChInGrp, PCM_DMX_MAX_CHANNEL_GROUPS*sizeof(UCHAR));
289 FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
290 FDKmemset(chIdx, 255, PCM_DMX_MAX_CHANNEL_GROUPS*PCM_DMX_MAX_CHANNELS_PER_GROUP*sizeof(UCHAR));
291
292 /* Categorize channels */
293 for (ch = 0; ch < numChannels; ch += 1) {
294 int i = 0, j, chGrpIdx = channelIndices[ch];
295
296 switch (channelType[ch]) {
297 case ACT_FRONT:
298 case ACT_FRONT_TOP:
299 grpIdx = CH_GROUP_FRONT;
300 break;
301 case ACT_SIDE:
302 case ACT_SIDE_TOP:
303 grpIdx = CH_GROUP_SIDE;
304 break;
305 case ACT_BACK:
306 case ACT_BACK_TOP:
307 grpIdx = CH_GROUP_REAR;
308 break;
309 case ACT_LFE:
310 grpIdx = CH_GROUP_LFE;
311 break;
312 default:
313 err = -1;
314 continue;
315 }
316
317 if (numChInGrp[grpIdx] < PCM_DMX_MAX_CHANNELS_PER_GROUP) {
318 /* Sort channels by index */
319 while ( (i < numChInGrp[grpIdx]) && (chGrpIdx > channelIndices[chIdx[grpIdx][i]]) ) {
320 i += 1;
321 }
322 for (j = numChInGrp[grpIdx]; j > i; j -= 1) {
323 chIdx[grpIdx][j] = chIdx[grpIdx][j-1];
324 }
325 chIdx[grpIdx][i] = ch;
326 numChInGrp[grpIdx] += 1;
327 }
328 }
329
330 /* Compose channel offset table */
331
332 /* Non-symmetric channels */
333 if (numChInGrp[CH_GROUP_FRONT] & 0x1) {
334 /* Odd number of front channels -> we have a center channel.
335 In MPEG-4 the center has the index 0. */
336 offsetTable[CENTER_FRONT_CHANNEL] = chIdx[CH_GROUP_FRONT][0];
337 }
338
339 for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
340 int chMapPos, maxChannels = 0;
341 ch = 0;
342
343 switch (grpIdx) {
344 case CH_GROUP_FRONT:
345 chMapPos = LEFT_FRONT_CHANNEL;
346 maxChannels = 3;
347 ch = numChInGrp[grpIdx] & 0x1;
348 break;
349 case CH_GROUP_SIDE:
350 chMapPos = LEFT_OUTSIDE_CHANNEL;
351 maxChannels = 2;
352 break;
353 case CH_GROUP_REAR:
354 chMapPos = LEFT_REAR_CHANNEL;
355 maxChannels = 2;
356 break;
357 case CH_GROUP_LFE:
358 chMapPos = LOW_FREQUENCY_CHANNEL;
359 maxChannels = 1;
360 break;
361 default:
362 err = -1;
363 continue;
364 }
365
366 for ( ; ch < numChInGrp[grpIdx]; ch += 1) {
367 if (ch < maxChannels) {
368 offsetTable[chMapPos] = chIdx[grpIdx][ch];
369 chMapPos += 1;
370 } else {
371 err = -1;
372 }
373 }
374 }
375
376 if (err == 0) {
377 /* Compose the channel mode */
378 chMode = (numChInGrp[CH_GROUP_LFE] & 0xF) << 12
379 | (numChInGrp[CH_GROUP_REAR] & 0xF) << 8
380 | (numChInGrp[CH_GROUP_SIDE] & 0xF) << 4
381 | (numChInGrp[CH_GROUP_FRONT] & 0xF);
382 }
383
384 return (PCM_DMX_CHANNEL_MODE)chMode;
385 }
386
387
388 /** Generate a channel offset table and complete channel description for a given (packed) channel mode.
389 * This function is the inverse to the getChannelMode() routine.
390 * @param [in] The total number of channels of the given configuration.
391 * @param [in] Array containing the channel mapping to be used (From MPEG PCE ordering to whatever is required).
392 * @param [out] Array where corresponding channel types for each channels are stored into.
393 * @param [out] Array where corresponding channel type indices for each output channel are stored into.
394 * @param [out] Array where the buffer offsets for each channel are stored into.
395 * @returns None.
396 **/
397 void getChannelDescription (
398 const PCM_DMX_CHANNEL_MODE chMode, /* in */
399 const UCHAR channelMapping[][PCM_DMX_MAX_CHANNELS], /* in */
400 AUDIO_CHANNEL_TYPE channelType[], /* out */
401 UCHAR channelIndices[], /* out */
402 UCHAR offsetTable[PCM_DMX_MAX_CHANNELS] /* out */
403 )
404 {
405 const UCHAR *pChannelMap;
406 int grpIdx, ch = 0, numChannels = 0;
407 UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS];
408
409 FDK_ASSERT(channelType != NULL);
410 FDK_ASSERT(channelIndices != NULL);
411 FDK_ASSERT(channelMapping != NULL);
412 FDK_ASSERT(offsetTable != NULL);
413
414 /* Init output arrays */
415 FDKmemclear(channelType, PCM_DMX_MAX_CHANNELS*sizeof(AUDIO_CHANNEL_TYPE));
416 FDKmemclear(channelIndices, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
417 FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
418
419 /* Extract the number of channels per group */
420 numChInGrp[CH_GROUP_FRONT] = chMode & 0xF;
421 numChInGrp[CH_GROUP_SIDE] = (chMode >> 4) & 0xF;
422 numChInGrp[CH_GROUP_REAR] = (chMode >> 8) & 0xF;
423 numChInGrp[CH_GROUP_LFE] = (chMode >> 12) & 0xF;
424
425 /* Summerize to get the total number of channels */
426 for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
427 numChannels += numChInGrp[grpIdx];
428 }
429
430 /* Get the appropriate channel map */
431 pChannelMap = channelMapping[numChannels-1];
432
433 /* Compose channel offset table */
434
435 /* Non-symmetric channels */
436 if (numChInGrp[CH_GROUP_FRONT] & 0x1) {
437 /* Odd number of front channels -> we have a center channel.
438 In MPEG-4 the center has the index 0. */
439 offsetTable[CENTER_FRONT_CHANNEL] = pChannelMap[0];
440 channelType[0] = ACT_FRONT;
441 ch += 1;
442 }
443
444 for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) {
445 AUDIO_CHANNEL_TYPE type;
446 int chMapPos, maxChannels = 0;
447 int chIdx = 0;
448
449 switch (grpIdx) {
450 case CH_GROUP_FRONT:
451 type = ACT_FRONT;
452 chMapPos = LEFT_FRONT_CHANNEL;
453 maxChannels = 3;
454 chIdx = numChInGrp[grpIdx] & 0x1;
455 break;
456 case CH_GROUP_SIDE:
457 type = ACT_SIDE;
458 chMapPos = LEFT_OUTSIDE_CHANNEL;
459 maxChannels = 2;
460 break;
461 case CH_GROUP_REAR:
462 type = ACT_BACK;
463 chMapPos = LEFT_REAR_CHANNEL;
464 maxChannels = 2;
465 break;
466 case CH_GROUP_LFE:
467 type = ACT_LFE;
468 chMapPos = LOW_FREQUENCY_CHANNEL;
469 maxChannels = 1;
470 break;
471 default:
472 break;
473 }
474
475 for ( ; (chIdx < numChInGrp[grpIdx]) && (chIdx < maxChannels); chIdx += 1) {
476 offsetTable[chMapPos] = pChannelMap[ch];
477 channelType[ch] = type;
478 channelIndices[ch] = chIdx;
479 chMapPos += 1;
480 ch += 1;
481 }
482 }
483 }
484
485
486 /** Open and initialize an instance of the PCM downmix module
487 * @param [out] Pointer to a buffer receiving the handle of the new instance.
488 * @returns Returns an error code.
489 **/
490 PCMDMX_ERROR pcmDmx_Open (
491 HANDLE_PCM_DOWNMIX *pSelf
492 )
493 {
494 HANDLE_PCM_DOWNMIX self;
495
496 if (pSelf == NULL) {
497 return (PCMDMX_INVALID_HANDLE);
498 }
499
500 *pSelf = NULL;
501
502 self = (HANDLE_PCM_DOWNMIX) GetPcmDmxInstance( 0 );
503 if (self == NULL) {
504 return (PCMDMX_OUT_OF_MEMORY);
505 }
506
507 /* Reset the full instance */
508 pcmDmx_Reset( self, PCMDMX_RESET_FULL );
509
510 *pSelf = self;
511
512 return (PCMDMX_OK);
513 }
514
515
516 /** Reset all static values like e.g. mixdown coefficients.
517 * @param [in] Handle of PCM downmix module instance.
518 * @param [in] Flags telling which parts of the module shall be reset.
519 * @returns Returns an error code.
520 **/
521 PCMDMX_ERROR pcmDmx_Reset (
522 HANDLE_PCM_DOWNMIX self,
523 UINT flags
524 )
525 {
526 if (self == NULL) { return (PCMDMX_INVALID_HANDLE); }
527
528 if (flags & PCMDMX_RESET_PARAMS) {
529 self->dualChannelMode = STEREO_MODE;
530 self->numOutputChannels = 0;
531 self->applyProcessing = 0;
532 self->frameDelay = 0;
533 self->expiryFrame = PCMDMX_DFLT_EXPIRY_FRAME;
534 }
535
536 if (flags & PCMDMX_RESET_BS_DATA) {
537 int slot;
538 for (slot = 0; slot <= PCM_DMX_MAX_DELAY_FRAMES; slot += 1) {
539 self->dvbMixDownLevels[slot].centerMixLevelValue = dvbDownmixFactors[2]; /* 0.707 */
540 self->dvbMixDownLevels[slot].surroundMixLevelValue = dvbDownmixFactors[0]; /* 1.000 */
541 self->dvbMixDownLevels[slot].mixLevelsAvail = 0;
542
543 self->mpegMixDownInfo[slot].mixdownAvailable = 0;
544 }
545 /* Reset expiry counter */
546 self->expiryCount = 0;
547 }
548
549 return (PCMDMX_OK);
550 }
551
552
553 /** Set one parameter for one instance of the PCM downmix module.
554 * @param [in] Handle of PCM downmix module instance.
555 * @param [in] Parameter to be set.
556 * @param [in] Parameter value.
557 * @returns Returns an error code.
558 **/
559 PCMDMX_ERROR pcmDmx_SetParam (
560 HANDLE_PCM_DOWNMIX self,
561 PCMDMX_PARAM param,
562 UINT value
563 )
564 {
565 switch (param)
566 {
567 case DMX_BS_DATA_EXPIRY_FRAME:
568 if (self == NULL)
569 return (PCMDMX_INVALID_HANDLE);
570 self->expiryFrame = value;
571 break;
572
573 case DMX_BS_DATA_DELAY:
574 if (value > PCM_DMX_MAX_DELAY_FRAMES) {
575 return (PCMDMX_UNABLE_TO_SET_PARAM);
576 }
577 if (self == NULL) {
578 return (PCMDMX_INVALID_HANDLE);
579 }
580 self->frameDelay = value;
581 break;
582
583 case NUMBER_OF_OUTPUT_CHANNELS:
584 switch ((int)value) { /* supported output channels */
585 case -1: case 0: case 1: case 2:
586 case 6: case 8:
587 break;
588 default:
589 return (PCMDMX_UNABLE_TO_SET_PARAM);
590 }
591 if (self == NULL)
592 return (PCMDMX_INVALID_HANDLE);
593 if ((int)value > 0) {
594 self->numOutputChannels = (int)value;
595 self->applyProcessing = 1;
596 } else {
597 self->numOutputChannels = 0;
598 self->applyProcessing = 0;
599 }
600 break;
601
602 case DUAL_CHANNEL_DOWNMIX_MODE:
603 switch ((DUAL_CHANNEL_MODE)value) {
604 case STEREO_MODE:
605 case CH1_MODE:
606 case CH2_MODE:
607 case MIXED_MODE:
608 break;
609 default:
610 return (PCMDMX_UNABLE_TO_SET_PARAM);
611 }
612 if (self == NULL)
613 return (PCMDMX_INVALID_HANDLE);
614 self->dualChannelMode = (DUAL_CHANNEL_MODE)value;
615 self->applyProcessing = 1;
616 break;
617
618 default:
619 return (PCMDMX_UNKNOWN_PARAM);
620 }
621
622 return (PCMDMX_OK);
623 }
624
625
626 /** Read the ancillary data transported in DSEs of DVB streams with MPEG-4 content
627 * @param [in] Handle of PCM downmix module instance.
628 * @param [in] Pointer to ancillary data buffer.
629 * @param [in] Size of ancillary data.
630 * @param [in] Flag indicating wheter the DVB ancillary data is from an MPEG-1/2 or an MPEG-4 stream.
631 * @returns Returns an error code.
632 **/
633 PCMDMX_ERROR pcmDmx_ReadDvbAncData (
634 HANDLE_PCM_DOWNMIX self,
635 UCHAR *pAncDataBuf,
636 UINT ancDataBytes,
637 int isMpeg2
638 )
639 {
640 DVB_MIXDOWN_LEVELS *pDownmixLevels = &self->dvbMixDownLevels[0];
641
642 int offset = (isMpeg2) ? 2 : 0;
643 UCHAR ancDataStatus;
644
645 if (self == NULL) { return (PCMDMX_INVALID_HANDLE); }
646
647 /* sanity checks */
648 if (pAncDataBuf == NULL || ancDataBytes < (UCHAR)(3+offset)) {
649 return (PCMDMX_CORRUPT_ANC_DATA);
650 }
651
652 /* check sync word */
653 if (pAncDataBuf[offset] != ANC_DATA_SYNC_BYTE) {
654 return (PCMDMX_CORRUPT_ANC_DATA);
655 }
656
657 offset += 2;
658 ancDataStatus = pAncDataBuf[offset++];
659
660 if (isMpeg2) {
661 /* skip advanced_dynamic_range_control */
662 if (ancDataStatus & 0x80) offset += 3;
663 /* skip dialog_normalization */
664 if (ancDataStatus & 0x40) offset += 1;
665 /* skip reproduction_level */
666 if (ancDataStatus & 0x20) offset += 1;
667 }
668 else {
669 /* check reserved bits */
670 if (ancDataStatus & 0xE8) { return (PCMDMX_CORRUPT_ANC_DATA); }
671 }
672
673 /* downmix_levels_MPEGX */
674 if (ancDataStatus & 0x10)
675 {
676 int foundNewData = 0;
677 UCHAR downmixData = pAncDataBuf[offset++];
678
679 if (downmixData & 0x80) { /* center_mix_level_on */
680 pDownmixLevels->centerMixLevelValue =
681 dvbDownmixFactors[(downmixData >> 4) & 0x07];
682 foundNewData = 1;
683 } else {
684 pDownmixLevels->centerMixLevelValue = dvbDownmixFactors[0];
685 if (downmixData & 0x70) { return (PCMDMX_CORRUPT_ANC_DATA); }
686 }
687
688 if (downmixData & 0x08) { /* surround_mix_level_on */
689 pDownmixLevels->surroundMixLevelValue =
690 dvbDownmixFactors[downmixData & 0x07];
691 foundNewData = 1;
692 } else {
693 pDownmixLevels->surroundMixLevelValue = dvbDownmixFactors[0];
694 if (downmixData & 0x07) { return (PCMDMX_CORRUPT_ANC_DATA); }
695 }
696
697 pDownmixLevels->mixLevelsAvail = foundNewData;
698 }
699
700 /* Reset expiry counter */
701 self->expiryCount = 0;
702
703 return (PCMDMX_OK);
704 }
705
706 /** Set the matrix mixdown information extracted from the PCE of an AAC bitstream.
707 * Note: Call only if matrix_mixdown_idx_present is true.
708 * @param [in] Handle of PCM downmix module instance.
709 * @param [in] The 2 bit matrix mixdown index extracted from PCE.
710 * @param [in] The pseudo surround enable flag extracted from PCE.
711 * @returns Returns an error code.
712 **/
713 PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce (
714 HANDLE_PCM_DOWNMIX self,
715 int matrixMixdownPresent,
716 int matrixMixdownIdx,
717 int pseudoSurroundEnable
718 )
719 {
720 MPEG_MIXDOWN_INFO *pMpegMixDownInfo;
721
722 if (self == NULL) {
723 return (PCMDMX_INVALID_HANDLE);
724 }
725
726 pMpegMixDownInfo = &self->mpegMixDownInfo[0];
727
728 if (matrixMixdownPresent) {
729 pMpegMixDownInfo->matrixMixdownIdx = matrixMixdownIdx & 0x03;
730 pMpegMixDownInfo->pseudoSurroundEnable = pseudoSurroundEnable;
731 }
732
733 pMpegMixDownInfo->mixdownAvailable = matrixMixdownPresent;
734 /* Reset expiry counter */
735 self->expiryCount = 0;
736
737 return (PCMDMX_OK);
738 }
739
740
741 /** Apply down or up mixing.
742 * @param [in] Handle of PCM downmix module instance.
743 * @param [inout] Pointer to time buffer. Depending on interface configuration, the content of pTimeData is ignored,
744 * and the internal QMF buffer will be used as input data source. Otherwise, the MPEG Surround processing is
745 * applied to the timesignal pTimeData. For both variants, the resulting MPEG Surround signal is written into pTimeData.
746 * @param [in] Pointer where the amount of output samples is returned into.
747 * @param [inout] Pointer where the amount of output channels is returned into.
748 * @param [in] Flag which indicates if output time data are writtern interleaved or as subsequent blocks.
749 * @param [inout] Array where the corresponding channel type for each output audio channel is stored into.
750 * @param [inout] Array where the corresponding channel type index for each output audio channel is stored into.
751 * @param [in] Array containing the output channel mapping to be used (From MPEG PCE ordering to whatever is required).
752 * @returns Returns an error code.
753 **/
754 PCMDMX_ERROR pcmDmx_ApplyFrame (
755 HANDLE_PCM_DOWNMIX self,
756 INT_PCM *pPcmBuf,
757 UINT frameSize,
758 INT *nChannels,
759
760 int fInterleaved,
761 AUDIO_CHANNEL_TYPE channelType[],
762 UCHAR channelIndices[],
763 const UCHAR channelMapping[][8]
764 )
765 {
766 PCMDMX_ERROR errorStatus = PCMDMX_OK;
767 DUAL_CHANNEL_MODE dualChannelMode;
768 PCM_DMX_CHANNEL_MODE inChMode;
769 int numOutChannels;
770 int numInChannels = *nChannels;
771 int slot;
772 UCHAR inOffsetTable[PCM_DMX_MAX_CHANNELS];
773
774 MPEG_MIXDOWN_INFO mpegMixDownInfo;
775 DVB_MIXDOWN_LEVELS dvbMixDownLevels;
776
777 if (self == NULL) { return (PCMDMX_INVALID_HANDLE); }
778
779 if ( (self->expiryFrame > 0)
780 && (++self->expiryCount > self->expiryFrame) )
781 { /* The metadata read from bitstream is too old. */
782 errorStatus = pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA);
783 }
784
785 FDKmemcpy(&mpegMixDownInfo, &self->mpegMixDownInfo[self->frameDelay], sizeof(MPEG_MIXDOWN_INFO));
786 /* Maintain delay line */
787 for (slot = self->frameDelay; slot > 0; slot -= 1) {
788 FDKmemcpy(&self->mpegMixDownInfo[slot], &self->mpegMixDownInfo[slot-1], sizeof(MPEG_MIXDOWN_INFO));
789 }
790 FDKmemcpy(&dvbMixDownLevels, &self->dvbMixDownLevels[self->frameDelay], sizeof(DVB_MIXDOWN_LEVELS));
791 /* Maintain delay line */
792 for (slot = self->frameDelay; slot > 0; slot -= 1) {
793 FDKmemcpy(&self->dvbMixDownLevels[slot], &self->dvbMixDownLevels[slot-1], sizeof(DVB_MIXDOWN_LEVELS));
794 }
795
796 if (self->applyProcessing == 0) { return (errorStatus); }
797
798 if (pPcmBuf == NULL) { return (PCMDMX_INVALID_ARGUMENT); }
799 if (frameSize == 0) { return (PCMDMX_INVALID_ARGUMENT); }
800 if (numInChannels == 0) { return (PCMDMX_INVALID_ARGUMENT); }
801
802 if (self->numOutputChannels <= 0) {
803 numOutChannels = numInChannels;
804 } else {
805 numOutChannels = self->numOutputChannels;
806 }
807 dualChannelMode = self->dualChannelMode;
808
809 /* Analyse input channel configuration and get channel offset
810 * table that can be accessed with the fixed channel labels. */
811 inChMode = getChannelMode(
812 numInChannels,
813 channelType,
814 channelIndices,
815 inOffsetTable
816 );
817 if (inChMode == CH_MODE_UNDEFINED) {
818 /* We don't need to restore because the channel
819 configuration has not been changed. Just exit. */
820 return (PCMDMX_INVALID_CH_CONFIG);
821 }
822
823 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
824 if ( numInChannels > numOutChannels )
825 { /* Apply downmix */
826 INT_PCM *pInCF, *pInLF, *pInRF, *pInLO, *pInRO, *pInLR, *pInRR, *pOutL, *pOutR;
827 FIXP_SGL flev, clev, slev;
828
829 UINT sample;
830 int inStride, outStride, offset;
831 int useGuidedDownMix = 0;
832 UCHAR outOffsetTable[PCM_DMX_MAX_CHANNELS];
833
834 /* Set I/O strides and offsets */
835 if (fInterleaved) {
836 inStride = numInChannels;
837 outStride = TWO_CHANNEL; /* The output of STAGE ONE is always STEREO !!!
838 STAGE TWO creates a downmix to mono if required. */
839 offset = 1; /* Channel specific offset factor */
840 } else {
841 inStride = 1;
842 outStride = 1;
843 offset = frameSize; /* Channel specific offset factor */
844 }
845
846 /* Get channel description and channel mapping for this
847 * stages number of output channels (always STEREO). */
848 getChannelDescription(
849 CH_MODE_2_0_0_0,
850 channelMapping,
851 channelType,
852 channelIndices,
853 outOffsetTable
854 );
855 /* Now there is no way back because we modified the channel configuration! */
856
857 /* Set channel pointer for input */
858 pInCF = &pPcmBuf[inOffsetTable[CENTER_FRONT_CHANNEL]*offset];
859 pInLF = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset];
860 pInRF = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset];
861 pInLO = &pPcmBuf[inOffsetTable[LEFT_OUTSIDE_CHANNEL]*offset];
862 pInRO = &pPcmBuf[inOffsetTable[RIGHT_OUTSIDE_CHANNEL]*offset];
863 pInLR = &pPcmBuf[inOffsetTable[LEFT_REAR_CHANNEL]*offset];
864 pInRR = &pPcmBuf[inOffsetTable[RIGHT_REAR_CHANNEL]*offset];
865
866 /* Set channel pointer for output
867 Caution: Different channel mapping compared to input */
868 pOutL = &pPcmBuf[outOffsetTable[LEFT_FRONT_CHANNEL]*offset]; /* LEFT_FRONT_CHANNEL */
869 pOutR = &pPcmBuf[outOffsetTable[RIGHT_FRONT_CHANNEL]*offset]; /* RIGHT_FRONT_CHANNEL */
870
871 /* Set downmix levels: */
872 flev = ATTENUATION_FACTOR_1; /* 0.707 */
873 clev = ATTENUATION_FACTOR_1; /* 0.707 */
874 slev = ATTENUATION_FACTOR_1; /* 0.707 */
875
876 if ( dvbMixDownLevels.mixLevelsAvail ) {
877 clev = dvbMixDownLevels.centerMixLevelValue;
878 slev = dvbMixDownLevels.surroundMixLevelValue;
879 useGuidedDownMix = 1;
880 }
881
882 /* FIRST STAGE:
883 Always downmix to 2 channel output: */
884 switch ( inChMode )
885 {
886 case CH_MODE_2_0_0_0:
887 case CH_MODE_2_0_0_1:
888 /* 2/0 input: */
889 switch (dualChannelMode)
890 {
891 case CH1_MODE: /* L' = 0.707 * Ch1; R' = 0.707 * Ch1 */
892 for (sample = 0; sample < frameSize; sample++) {
893 *pOutL = *pOutR =
894 (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInLF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
895
896 pInLF += inStride;
897 pOutL += outStride; pOutR += outStride;
898 }
899 break;
900
901 case CH2_MODE: /* L' = 0.707 * Ch2; R' = 0.707 * Ch2 */
902 for (sample = 0; sample < frameSize; sample++) {
903 *pOutL = *pOutR =
904 (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInRF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
905
906 pInRF += inStride;
907 pOutL += outStride; pOutR += outStride;
908 }
909 break;
910 case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2; R' = 0.5*Ch1 + 0.5*Ch2 */
911 for (sample = 0; sample < frameSize; sample++) {
912 *pOutL = *pOutR = (*pInLF >> 1) + (*pInRF >> 1);
913
914 pInLF += inStride; pInRF += inStride;
915 pOutL += outStride; pOutR += outStride;
916 }
917 break;
918 default:
919 case STEREO_MODE:
920 /* nothing to do */
921 break;
922 }
923 break;
924
925 case CH_MODE_3_0_0_0:
926 /* 3/0 input: L' = L + 0.707*C; R' = R + 0.707*C; */
927 for (sample = 0; sample < frameSize; sample++)
928 {
929 FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev);
930 #if (SAMPLE_BITS == 32)
931 /* left channel */
932 *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>1)+tCF, 1, SAMPLE_BITS);
933 /* right channel */
934 *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>1)+tCF, 1, SAMPLE_BITS);
935 #else
936 /* left channel */
937 *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>1)+tCF, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS);
938 /* right channel */
939 *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>1)+tCF, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS);
940 #endif
941 pInLF += inStride; pInRF += inStride; pInCF += inStride;
942 pOutL += outStride; pOutR += outStride;
943 }
944 break;
945
946 /* 2/1 input: not supported!
947 case CH_MODE_2_0_1_0: */
948
949 case CH_MODE_3_0_1_0:
950 if (useGuidedDownMix) {
951 /* 3/1 input: L' = L + clev*C + 0.707*slev*S; R' = R + clev*C + 0.707*slev*S; */
952 slev = FX_DBL2FX_SGL(fMult(flev, slev)); /* 0.707*slef */
953
954 for (sample = 0; sample < frameSize; sample++)
955 {
956 FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 1;
957 FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 1;
958 #if (SAMPLE_BITS == 32)
959 /* left channel */
960 *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF+tLR, 2, SAMPLE_BITS);
961 /* right channel */
962 *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, 2, SAMPLE_BITS);
963 #else
964 /* left channel */
965 *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF-tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
966 /* right channel */
967 *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
968 #endif
969 pInLF += inStride; pInRF += inStride; pInCF += inStride; pInLR += inStride;
970 pOutL += outStride; pOutR += outStride;
971 }
972 } else {
973 /* 3/1 input: L' = L + 0.707*C - 0.707*S; R' = R + 0.707*C + 0.707*S */
974 for (sample = 0; sample < frameSize; sample++)
975 {
976 FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 1;
977 FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 1;
978 #if (SAMPLE_BITS == 32)
979 /* left channel */
980 *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF-tLR, 2, SAMPLE_BITS);
981 /* right channel */
982 *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, 2, SAMPLE_BITS);
983 #else
984 /* left channel */
985 *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF-tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
986 /* right channel */
987 *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
988 #endif
989 pInLF += inStride; pInRF += inStride; pInCF += inStride; pInLR += inStride;
990 pOutL += outStride; pOutR += outStride;
991 }
992 }
993 break;
994
995 /* 2/2 input: not supported!
996 case CH_MODE_2_0_2_0: */
997
998 case CH_MODE_3_0_2_0: /* 5.0ch input */
999 case CH_MODE_3_0_2_1: /* 5.1ch input */
1000 if (useGuidedDownMix) {
1001 /* 3/2 input: L' = L + clev*C + slev*Ls; R' = R + clev*C + slev*Rs; */
1002 for (sample = 0; sample < frameSize; sample++)
1003 {
1004 FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 1;
1005 FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 1;
1006 FIXP_DBL tRR = fMultDiv2((FIXP_PCM)*pInRR, slev) >> 1;
1007 #if (SAMPLE_BITS == 32)
1008 /* left channel */
1009 *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF+tLR, 2, SAMPLE_BITS);
1010 /* right channel */
1011 *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tRR, 2, SAMPLE_BITS);
1012 #else
1013 /* left channel */
1014 *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>2)+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
1015 /* right channel */
1016 *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>2)+tCF+tRR, DFRACT_BITS-SAMPLE_BITS-2, SAMPLE_BITS);
1017 #endif
1018 pInLF += inStride; pInRF += inStride; pInCF += inStride; pInLR += inStride; pInRR += inStride;
1019 pOutL += outStride; pOutR += outStride;
1020 }
1021 }
1022 else if (mpegMixDownInfo.mixdownAvailable) {
1023 /* 3/2 input: L' = (1.707+A)^-1 * [L+0.707*C+A*Ls]; R'= (1.707+A)^-1 * [R+0.707*C+A*Rs]; */
1024 FIXP_SGL mtrxMixDwnCoef = mpegMixDownIdx2Coef[mpegMixDownInfo.matrixMixdownIdx];
1025 FIXP_SGL mtrxMixDwnPreFact = mpegMixDownIdx2PreFact[mpegMixDownInfo.matrixMixdownIdx];
1026 clev = FX_DBL2FX_SGL(fMult(mtrxMixDwnPreFact, flev /* 0.707 */));
1027 flev = mtrxMixDwnPreFact;
1028 slev = FX_DBL2FX_SGL(fMult(mtrxMixDwnPreFact, mtrxMixDwnCoef));
1029
1030 for (sample = 0; sample < frameSize; sample++)
1031 {
1032 FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev);
1033 FIXP_DBL tLF = fMultDiv2((FIXP_PCM)*pInLF, flev);
1034 FIXP_DBL tRF = fMultDiv2((FIXP_PCM)*pInRF, flev);
1035 FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev);
1036 FIXP_DBL tRR = fMultDiv2((FIXP_PCM)*pInRR, slev);
1037
1038 #if (SAMPLE_BITS == 32)
1039 /* left channel */
1040 *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT(tLF+tCF+tLR, 1, SAMPLE_BITS);
1041 /* right channel */
1042 *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT(tRF+tCF+tRR, 1, SAMPLE_BITS);
1043 #else
1044 /* left channel */
1045 *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT(tLF+tCF+tLR, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS);
1046 /* right channel */
1047 *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT(tRF+tCF+tRR, DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS);
1048 #endif
1049
1050 pInLF += inStride; pInRF += inStride; pInCF += inStride; pInLR += inStride; pInRR += inStride;
1051 pOutL += outStride; pOutR += outStride;
1052 }
1053 }
1054 else {
1055 /* 3/2 input: L' = L + 0.707*C - 0.707*Ls - 0.707*Rs; R' = R + 0.707*C + 0.707*Ls + 0.707*Rs */
1056 for (sample = 0; sample < frameSize; sample++)
1057 {
1058 FIXP_DBL tCF = fMultDiv2((FIXP_PCM)*pInCF, clev) >> 2;
1059 FIXP_DBL tLR = fMultDiv2((FIXP_PCM)*pInLR, slev) >> 2;
1060 FIXP_DBL tRR = fMultDiv2((FIXP_PCM)*pInRR, slev) >> 2;
1061 #if (SAMPLE_BITS == 32)
1062 /* left channel */
1063 *pOutL = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>3)+tCF-tLR-tRR, 3, SAMPLE_BITS);
1064 /* right channel */
1065 *pOutR = (INT_PCM)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>3)+tCF+tLR+tRR, 3, SAMPLE_BITS);
1066 #else
1067 /* left channel */
1068 *pOutL = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInLF)>>3)+tCF-tLR-tRR, DFRACT_BITS-SAMPLE_BITS-3, SAMPLE_BITS);
1069 /* right channel */
1070 *pOutR = (INT_PCM)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM)*pInRF)>>3)+tCF+tLR+tRR, DFRACT_BITS-SAMPLE_BITS-3, SAMPLE_BITS);
1071 #endif
1072 pInLF += inStride; pInRF += inStride; pInCF += inStride; pInLR += inStride; pInRR += inStride;
1073 pOutL += outStride; pOutR += outStride;
1074 }
1075 }
1076 break;
1077
1078 default:
1079 errorStatus = PCMDMX_INVALID_MODE;
1080 break;
1081 }
1082
1083 /* SECOND STAGE:
1084 If desired create a mono donwmix:
1085 Note: Input are always two channels! */
1086 if (numOutChannels == 1)
1087 {
1088 INT_PCM *pOutC;
1089 FIXP_SGL mlev;
1090
1091 if (useGuidedDownMix) mlev = FL2FXCONST_SGL(1.0f); else mlev = flev;
1092
1093 /* Output of STAGE ONE = Input of STAGE TWO */
1094 FDKmemcpy(inOffsetTable, outOffsetTable, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR));
1095
1096 /* Set I/O strides and offsets */
1097 inStride = outStride; /* output from STAGE ONE */
1098 outStride = numOutChannels; /* final output */
1099
1100 /* Get channel description and channel mapping for this
1101 * stages number of output channels (always MONO). */
1102 getChannelDescription(
1103 CH_MODE_1_0_0_0,
1104 channelMapping,
1105 channelType,
1106 channelIndices,
1107 outOffsetTable
1108 );
1109
1110 /* Set input channel pointer. */
1111 pInLF = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset];
1112 pInRF = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset];
1113
1114 /* Set output channel pointer */
1115 pOutC = &pPcmBuf[outOffsetTable[CENTER_FRONT_CHANNEL]*offset];
1116
1117 /* C' = 0.707*L + 0.707*R */
1118 for (sample = 0; sample < frameSize; sample++) {
1119 #if (SAMPLE_BITS == 32)
1120 *pOutC =
1121 (INT_PCM)SATURATE_LEFT_SHIFT(fMultDiv2((FIXP_PCM)*pInLF,mlev)+fMultDiv2((FIXP_PCM)*pInRF,mlev), 1, SAMPLE_BITS);
1122 #else
1123 *pOutC =
1124 (INT_PCM)SATURATE_RIGHT_SHIFT(fMultDiv2((FIXP_PCM)*pInLF,mlev)+fMultDiv2((FIXP_PCM)*pInRF,mlev), DFRACT_BITS-SAMPLE_BITS-1, SAMPLE_BITS);
1125 #endif
1126
1127 pInLF += inStride; pInRF += inStride;
1128 pOutC += 1;
1129 }
1130 /* Finished STAGE TWO */
1131 }
1132
1133 /* Update the number of output channels */
1134 *nChannels = self->numOutputChannels;
1135
1136 } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1137 else
1138 if ( numInChannels == numOutChannels )
1139 {
1140 /* Don't need to change the channel description here */
1141
1142 switch (numInChannels)
1143 {
1144 case 2:
1145 { /* Set up channel pointer */
1146 INT_PCM *pInLF, *pInRF, *pOutL, *pOutR;
1147 FIXP_SGL flev;
1148
1149 UINT sample;
1150 int inStride, outStride, offset;
1151
1152 if (fInterleaved) {
1153 inStride = numInChannels;
1154 outStride = 2; /* fixed !!! (below stereo is donwmixed to mono if required */
1155 offset = 1; /* Channel specific offset factor */
1156 } else {
1157 inStride = 1;
1158 outStride = 1;
1159 offset = frameSize; /* Channel specific offset factor */
1160 }
1161
1162 /* Set input channel pointer */
1163 pInLF = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset];
1164 pInRF = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset];
1165
1166 /* Set output channel pointer (same as input) */
1167 pOutL = pInLF;
1168 pOutR = pInRF;
1169
1170 /* Set downmix levels: */
1171 flev = ATTENUATION_FACTOR_1; /* 0.707 */
1172 /* 2/0 input: */
1173 switch (dualChannelMode)
1174 {
1175 case CH1_MODE: /* L' = 0.707 * Ch1; R' = 0.707 * Ch1 */
1176 for (sample = 0; sample < frameSize; sample++) {
1177 *pOutL = *pOutR =
1178 (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInLF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
1179
1180 pInLF += inStride;
1181 pOutL += outStride; pOutR += outStride;
1182 }
1183 break;
1184 case CH2_MODE: /* L' = 0.707 * Ch2; R' = 0.707 * Ch2 */
1185 for (sample = 0; sample < frameSize; sample++) {
1186 *pOutL = *pOutR =
1187 (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInRF, flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS);
1188
1189 pInRF += inStride;
1190 pOutL += outStride; pOutR += outStride;
1191 }
1192 break;
1193 case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2; R' = 0.5*Ch1 + 0.5*Ch2 */
1194 for (sample = 0; sample < frameSize; sample++) {
1195 *pOutL = *pOutR = (*pInLF >> 1) + (*pInRF >> 1);
1196
1197 pInLF += inStride; pInRF += inStride;
1198 pOutL += outStride; pOutR += outStride;
1199 }
1200 break;
1201 default:
1202 case STEREO_MODE:
1203 /* nothing to do */
1204 break;
1205 }
1206 }
1207 break;
1208
1209 default:
1210 /* nothing to do */
1211 break;
1212 }
1213 }
1214
1215 return (errorStatus);
1216 }
1217
1218
1219 /** Close an instance of the PCM downmix module.
1220 * @param [inout] Pointer to a buffer containing the handle of the instance.
1221 * @returns Returns an error code.
1222 **/
1223 PCMDMX_ERROR pcmDmx_Close (
1224 HANDLE_PCM_DOWNMIX *pSelf
1225 )
1226 {
1227 if (pSelf == NULL) {
1228 return (PCMDMX_INVALID_HANDLE);
1229 }
1230
1231 FreePcmDmxInstance( pSelf );
1232 *pSelf = NULL;
1233
1234 return (PCMDMX_OK);
1235 }
1236
1237
1238 /** Get library info for this module.
1239 * @param [out] Pointer to an allocated LIB_INFO structure.
1240 * @returns Returns an error code.
1241 */
1242 PCMDMX_ERROR pcmDmx_GetLibInfo( LIB_INFO *info )
1243 {
1244 int i;
1245
1246 if (info == NULL) {
1247 return PCMDMX_INVALID_ARGUMENT;
1248 }
1249
1250 /* Search for next free tab */
1251 for (i = 0; i < FDK_MODULE_LAST; i++) {
1252 if (info[i].module_id == FDK_NONE) break;
1253 }
1254 if (i == FDK_MODULE_LAST) {
1255 return PCMDMX_UNKNOWN;
1256 }
1257 info += i;
1258
1259 /* Add the library info */
1260 info->module_id = FDK_PCMDMX;
1261 info->version = LIB_VERSION(PCMDMX_LIB_VL0, PCMDMX_LIB_VL1, PCMDMX_LIB_VL2);
1262 LIB_VERSION_STRING(info);
1263 info->build_date = PCMDMX_LIB_BUILD_DATE;
1264 info->build_time = PCMDMX_LIB_BUILD_TIME;
1265 info->title = PCMDMX_LIB_TITLE;
1266
1267 /* Set flags */
1268 info->flags = 0
1269 | CAPF_DMX_BLIND /* At least blind downmixing is possible */
1270 | CAPF_DMX_PCE /* Guided downmix with data from MPEG-2/4 Program Config Elements (PCE). */
1271 | CAPF_DMX_DVB /* Guided downmix with data from DVB ancillary data fields. */
1272 ;
1273
1274 return PCMDMX_OK;
1275 }
1276
1277
1278