2 /* -----------------------------------------------------------------------------------------------------------
3 Software License for The Fraunhofer FDK AAC Codec Library for Android
5 © Copyright 1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
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.
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.
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.
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.
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:
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.
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.
42 The name of Fraunhofer may not be used to endorse or promote products derived from this library without
43 prior written permission.
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.
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."
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.
59 You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
60 by appropriate patent licenses.
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.
73 5. CONTACT INFORMATION
75 Fraunhofer Institute for Integrated Circuits IIS
76 Attention: Audio and Multimedia Departments - FDK AAC LL
78 91058 Erlangen, Germany
80 www.iis.fraunhofer.de/amm
81 amm-info@iis.fraunhofer.de
82 ----------------------------------------------------------------------------------------------------------- */
84 /**************************** FDK PCM utils module **************************
86 Author(s): Christian Griebel
87 Description: Defines functions to interface with the PCM post processing
90 *******************************************************************************/
92 #include "pcmutils_lib.h"
94 #include "genericStds.h"
95 #include "fixpoint_math.h"
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__
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) */
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 )
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 */
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 )
136 /* Sanity checks on library setting: */
138 /* List of packed channel modes */
140 { /* CH_MODE_<numFrontCh>_<numOutsideCh>_<numRearCh>_<numLfCh> */
141 CH_MODE_UNDEFINED
= 0x0000,
143 CH_MODE_1_0_0_0
= 0x0001, /* chCfg 1 */
145 CH_MODE_2_0_0_0
= 0x0002, /* chCfg 2 */
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,
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,
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,
160 CH_MODE_3_0_2_1
= 0x1203, /* chCfg 6 */
161 CH_MODE_3_2_1_0
= 0x0123,
163 CH_MODE_2_2_2_1
= 0x1222,
164 CH_MODE_3_2_1_1
= 0x1123,
165 CH_MODE_3_2_2_0
= 0x0223,
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
171 } PCM_DMX_CHANNEL_MODE
;
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
] =
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 */
188 static const FIXP_SGL dvbDownmixFactors
[8] =
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
),
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];
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)];
208 M = (3 + 2A)^-1 * [L + C + R + A*(Ls + Rs)];
210 static const FIXP_SGL mpegMixDownIdx2Coef
[4] =
212 FL2FXCONST_SGL(0.70710678f
),
213 FL2FXCONST_SGL(0.5f
),
214 FL2FXCONST_SGL(0.35355339f
),
218 static const FIXP_SGL mpegMixDownIdx2PreFact
[4] =
220 FL2FXCONST_SGL(0.4142135623730950f
),
221 FL2FXCONST_SGL(0.4530818393219728f
),
222 FL2FXCONST_SGL(0.4852813742385703f
),
223 FL2FXCONST_SGL(0.5857864376269050f
)
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. */
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. */
240 UCHAR mixLevelsAvail
; /*!< Will be set to 1 if we found a valid coefficient. */
242 } DVB_MIXDOWN_LEVELS
;
245 /* Modules main data structure: */
246 struct PCM_DMX_INSTANCE
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
;
253 SHORT numOutputChannels
;
254 UCHAR applyProcessing
;
258 /* Memory allocation macro */
259 C_ALLOC_MEM_STATIC(PcmDmxInstance
, struct PCM_DMX_INSTANCE
, 1)
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.
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 */
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;
283 FDK_ASSERT(channelType
!= NULL
);
284 FDK_ASSERT(channelIndices
!= NULL
);
285 FDK_ASSERT(offsetTable
!= NULL
);
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
));
292 /* Categorize channels */
293 for (ch
= 0; ch
< numChannels
; ch
+= 1) {
294 int i
= 0, j
, chGrpIdx
= channelIndices
[ch
];
296 switch (channelType
[ch
]) {
299 grpIdx
= CH_GROUP_FRONT
;
303 grpIdx
= CH_GROUP_SIDE
;
307 grpIdx
= CH_GROUP_REAR
;
310 grpIdx
= CH_GROUP_LFE
;
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
]]) ) {
322 for (j
= numChInGrp
[grpIdx
]; j
> i
; j
-= 1) {
323 chIdx
[grpIdx
][j
] = chIdx
[grpIdx
][j
-1];
325 chIdx
[grpIdx
][i
] = ch
;
326 numChInGrp
[grpIdx
] += 1;
330 /* Compose channel offset table */
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];
339 for (grpIdx
= 0; grpIdx
< PCM_DMX_MAX_CHANNEL_GROUPS
; grpIdx
+= 1) {
340 int chMapPos
, maxChannels
= 0;
345 chMapPos
= LEFT_FRONT_CHANNEL
;
347 ch
= numChInGrp
[grpIdx
] & 0x1;
350 chMapPos
= LEFT_OUTSIDE_CHANNEL
;
354 chMapPos
= LEFT_REAR_CHANNEL
;
358 chMapPos
= LOW_FREQUENCY_CHANNEL
;
366 for ( ; ch
< numChInGrp
[grpIdx
]; ch
+= 1) {
367 if (ch
< maxChannels
) {
368 offsetTable
[chMapPos
] = chIdx
[grpIdx
][ch
];
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);
384 return (PCM_DMX_CHANNEL_MODE
)chMode
;
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.
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 */
405 const UCHAR
*pChannelMap
;
406 int grpIdx
, ch
= 0, numChannels
= 0;
407 UCHAR numChInGrp
[PCM_DMX_MAX_CHANNEL_GROUPS
];
409 FDK_ASSERT(channelType
!= NULL
);
410 FDK_ASSERT(channelIndices
!= NULL
);
411 FDK_ASSERT(channelMapping
!= NULL
);
412 FDK_ASSERT(offsetTable
!= NULL
);
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
));
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;
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
];
430 /* Get the appropriate channel map */
431 pChannelMap
= channelMapping
[numChannels
-1];
433 /* Compose channel offset table */
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
;
444 for (grpIdx
= 0; grpIdx
< PCM_DMX_MAX_CHANNEL_GROUPS
; grpIdx
+= 1) {
445 AUDIO_CHANNEL_TYPE type
;
446 int chMapPos
, maxChannels
= 0;
452 chMapPos
= LEFT_FRONT_CHANNEL
;
454 chIdx
= numChInGrp
[grpIdx
] & 0x1;
458 chMapPos
= LEFT_OUTSIDE_CHANNEL
;
463 chMapPos
= LEFT_REAR_CHANNEL
;
468 chMapPos
= LOW_FREQUENCY_CHANNEL
;
475 for ( ; (chIdx
< numChInGrp
[grpIdx
]) && (chIdx
< maxChannels
); chIdx
+= 1) {
476 offsetTable
[chMapPos
] = pChannelMap
[ch
];
477 channelType
[ch
] = type
;
478 channelIndices
[ch
] = chIdx
;
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.
490 PCMDMX_ERROR
pcmDmx_Open (
491 HANDLE_PCM_DOWNMIX
*pSelf
494 HANDLE_PCM_DOWNMIX self
;
497 return (PCMDMX_INVALID_HANDLE
);
502 self
= (HANDLE_PCM_DOWNMIX
) GetPcmDmxInstance( 0 );
504 return (PCMDMX_OUT_OF_MEMORY
);
507 /* Reset the full instance */
508 pcmDmx_Reset( self
, PCMDMX_RESET_FULL
);
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.
521 PCMDMX_ERROR
pcmDmx_Reset (
522 HANDLE_PCM_DOWNMIX self
,
526 if (self
== NULL
) { return (PCMDMX_INVALID_HANDLE
); }
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
;
536 if (flags
& PCMDMX_RESET_BS_DATA
) {
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;
543 self
->mpegMixDownInfo
[slot
].mixdownAvailable
= 0;
545 /* Reset expiry counter */
546 self
->expiryCount
= 0;
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.
559 PCMDMX_ERROR
pcmDmx_SetParam (
560 HANDLE_PCM_DOWNMIX self
,
567 case DMX_BS_DATA_EXPIRY_FRAME
:
569 return (PCMDMX_INVALID_HANDLE
);
570 self
->expiryFrame
= value
;
573 case DMX_BS_DATA_DELAY
:
574 if (value
> PCM_DMX_MAX_DELAY_FRAMES
) {
575 return (PCMDMX_UNABLE_TO_SET_PARAM
);
578 return (PCMDMX_INVALID_HANDLE
);
580 self
->frameDelay
= value
;
583 case NUMBER_OF_OUTPUT_CHANNELS
:
584 switch ((int)value
) { /* supported output channels */
585 case -1: case 0: case 1: case 2:
589 return (PCMDMX_UNABLE_TO_SET_PARAM
);
592 return (PCMDMX_INVALID_HANDLE
);
593 if ((int)value
> 0) {
594 self
->numOutputChannels
= (int)value
;
595 self
->applyProcessing
= 1;
597 self
->numOutputChannels
= 0;
598 self
->applyProcessing
= 0;
602 case DUAL_CHANNEL_DOWNMIX_MODE
:
603 switch ((DUAL_CHANNEL_MODE
)value
) {
610 return (PCMDMX_UNABLE_TO_SET_PARAM
);
613 return (PCMDMX_INVALID_HANDLE
);
614 self
->dualChannelMode
= (DUAL_CHANNEL_MODE
)value
;
615 self
->applyProcessing
= 1;
619 return (PCMDMX_UNKNOWN_PARAM
);
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.
633 PCMDMX_ERROR
pcmDmx_ReadDvbAncData (
634 HANDLE_PCM_DOWNMIX self
,
640 DVB_MIXDOWN_LEVELS
*pDownmixLevels
= &self
->dvbMixDownLevels
[0];
642 int offset
= (isMpeg2
) ? 2 : 0;
645 if (self
== NULL
) { return (PCMDMX_INVALID_HANDLE
); }
648 if (pAncDataBuf
== NULL
|| ancDataBytes
< (UCHAR
)(3+offset
)) {
649 return (PCMDMX_CORRUPT_ANC_DATA
);
652 /* check sync word */
653 if (pAncDataBuf
[offset
] != ANC_DATA_SYNC_BYTE
) {
654 return (PCMDMX_CORRUPT_ANC_DATA
);
658 ancDataStatus
= pAncDataBuf
[offset
++];
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;
669 /* check reserved bits */
670 if (ancDataStatus
& 0xE8) { return (PCMDMX_CORRUPT_ANC_DATA
); }
673 /* downmix_levels_MPEGX */
674 if (ancDataStatus
& 0x10)
676 int foundNewData
= 0;
677 UCHAR downmixData
= pAncDataBuf
[offset
++];
679 if (downmixData
& 0x80) { /* center_mix_level_on */
680 pDownmixLevels
->centerMixLevelValue
=
681 dvbDownmixFactors
[(downmixData
>> 4) & 0x07];
684 pDownmixLevels
->centerMixLevelValue
= dvbDownmixFactors
[0];
685 if (downmixData
& 0x70) { return (PCMDMX_CORRUPT_ANC_DATA
); }
688 if (downmixData
& 0x08) { /* surround_mix_level_on */
689 pDownmixLevels
->surroundMixLevelValue
=
690 dvbDownmixFactors
[downmixData
& 0x07];
693 pDownmixLevels
->surroundMixLevelValue
= dvbDownmixFactors
[0];
694 if (downmixData
& 0x07) { return (PCMDMX_CORRUPT_ANC_DATA
); }
697 pDownmixLevels
->mixLevelsAvail
= foundNewData
;
700 /* Reset expiry counter */
701 self
->expiryCount
= 0;
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.
713 PCMDMX_ERROR
pcmDmx_SetMatrixMixdownFromPce (
714 HANDLE_PCM_DOWNMIX self
,
715 int matrixMixdownPresent
,
716 int matrixMixdownIdx
,
717 int pseudoSurroundEnable
720 MPEG_MIXDOWN_INFO
*pMpegMixDownInfo
;
723 return (PCMDMX_INVALID_HANDLE
);
726 pMpegMixDownInfo
= &self
->mpegMixDownInfo
[0];
728 if (matrixMixdownPresent
) {
729 pMpegMixDownInfo
->matrixMixdownIdx
= matrixMixdownIdx
& 0x03;
730 pMpegMixDownInfo
->pseudoSurroundEnable
= pseudoSurroundEnable
;
733 pMpegMixDownInfo
->mixdownAvailable
= matrixMixdownPresent
;
734 /* Reset expiry counter */
735 self
->expiryCount
= 0;
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.
754 PCMDMX_ERROR
pcmDmx_ApplyFrame (
755 HANDLE_PCM_DOWNMIX self
,
761 AUDIO_CHANNEL_TYPE channelType
[],
762 UCHAR channelIndices
[],
763 const UCHAR channelMapping
[][8]
766 PCMDMX_ERROR errorStatus
= PCMDMX_OK
;
767 DUAL_CHANNEL_MODE dualChannelMode
;
768 PCM_DMX_CHANNEL_MODE inChMode
;
770 int numInChannels
= *nChannels
;
772 UCHAR inOffsetTable
[PCM_DMX_MAX_CHANNELS
];
774 MPEG_MIXDOWN_INFO mpegMixDownInfo
;
775 DVB_MIXDOWN_LEVELS dvbMixDownLevels
;
777 if (self
== NULL
) { return (PCMDMX_INVALID_HANDLE
); }
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
);
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
));
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
));
796 if (self
->applyProcessing
== 0) { return (errorStatus
); }
798 if (pPcmBuf
== NULL
) { return (PCMDMX_INVALID_ARGUMENT
); }
799 if (frameSize
== 0) { return (PCMDMX_INVALID_ARGUMENT
); }
800 if (numInChannels
== 0) { return (PCMDMX_INVALID_ARGUMENT
); }
802 if (self
->numOutputChannels
<= 0) {
803 numOutChannels
= numInChannels
;
805 numOutChannels
= self
->numOutputChannels
;
807 dualChannelMode
= self
->dualChannelMode
;
809 /* Analyse input channel configuration and get channel offset
810 * table that can be accessed with the fixed channel labels. */
811 inChMode
= getChannelMode(
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
);
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
;
830 int inStride
, outStride
, offset
;
831 int useGuidedDownMix
= 0;
832 UCHAR outOffsetTable
[PCM_DMX_MAX_CHANNELS
];
834 /* Set I/O strides and offsets */
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 */
843 offset
= frameSize
; /* Channel specific offset factor */
846 /* Get channel description and channel mapping for this
847 * stages number of output channels (always STEREO). */
848 getChannelDescription(
855 /* Now there is no way back because we modified the channel configuration! */
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
];
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 */
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 */
876 if ( dvbMixDownLevels
.mixLevelsAvail
) {
877 clev
= dvbMixDownLevels
.centerMixLevelValue
;
878 slev
= dvbMixDownLevels
.surroundMixLevelValue
;
879 useGuidedDownMix
= 1;
883 Always downmix to 2 channel output: */
886 case CH_MODE_2_0_0_0
:
887 case CH_MODE_2_0_0_1
:
889 switch (dualChannelMode
)
891 case CH1_MODE
: /* L' = 0.707 * Ch1; R' = 0.707 * Ch1 */
892 for (sample
= 0; sample
< frameSize
; sample
++) {
894 (INT_PCM
)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM
)*pInLF
, flev
), DFRACT_BITS
-SAMPLE_BITS
, SAMPLE_BITS
);
897 pOutL
+= outStride
; pOutR
+= outStride
;
901 case CH2_MODE
: /* L' = 0.707 * Ch2; R' = 0.707 * Ch2 */
902 for (sample
= 0; sample
< frameSize
; sample
++) {
904 (INT_PCM
)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM
)*pInRF
, flev
), DFRACT_BITS
-SAMPLE_BITS
, SAMPLE_BITS
);
907 pOutL
+= outStride
; pOutR
+= outStride
;
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);
914 pInLF
+= inStride
; pInRF
+= inStride
;
915 pOutL
+= outStride
; pOutR
+= outStride
;
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
++)
929 FIXP_DBL tCF
= fMultDiv2((FIXP_PCM
)*pInCF
, clev
);
930 #if (SAMPLE_BITS == 32)
932 *pOutL
= (INT_PCM
)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInLF
)>>1)+tCF
, 1, SAMPLE_BITS
);
934 *pOutR
= (INT_PCM
)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInRF
)>>1)+tCF
, 1, SAMPLE_BITS
);
937 *pOutL
= (INT_PCM
)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInLF
)>>1)+tCF
, DFRACT_BITS
-SAMPLE_BITS
-1, SAMPLE_BITS
);
939 *pOutR
= (INT_PCM
)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInRF
)>>1)+tCF
, DFRACT_BITS
-SAMPLE_BITS
-1, SAMPLE_BITS
);
941 pInLF
+= inStride
; pInRF
+= inStride
; pInCF
+= inStride
;
942 pOutL
+= outStride
; pOutR
+= outStride
;
946 /* 2/1 input: not supported!
947 case CH_MODE_2_0_1_0: */
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 */
954 for (sample
= 0; sample
< frameSize
; sample
++)
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)
960 *pOutL
= (INT_PCM
)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInLF
)>>2)+tCF
+tLR
, 2, SAMPLE_BITS
);
962 *pOutR
= (INT_PCM
)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInRF
)>>2)+tCF
+tLR
, 2, SAMPLE_BITS
);
965 *pOutL
= (INT_PCM
)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInLF
)>>2)+tCF
-tLR
, DFRACT_BITS
-SAMPLE_BITS
-2, SAMPLE_BITS
);
967 *pOutR
= (INT_PCM
)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInRF
)>>2)+tCF
+tLR
, DFRACT_BITS
-SAMPLE_BITS
-2, SAMPLE_BITS
);
969 pInLF
+= inStride
; pInRF
+= inStride
; pInCF
+= inStride
; pInLR
+= inStride
;
970 pOutL
+= outStride
; pOutR
+= outStride
;
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
++)
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)
980 *pOutL
= (INT_PCM
)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInLF
)>>2)+tCF
-tLR
, 2, SAMPLE_BITS
);
982 *pOutR
= (INT_PCM
)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInRF
)>>2)+tCF
+tLR
, 2, SAMPLE_BITS
);
985 *pOutL
= (INT_PCM
)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInLF
)>>2)+tCF
-tLR
, DFRACT_BITS
-SAMPLE_BITS
-2, SAMPLE_BITS
);
987 *pOutR
= (INT_PCM
)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInRF
)>>2)+tCF
+tLR
, DFRACT_BITS
-SAMPLE_BITS
-2, SAMPLE_BITS
);
989 pInLF
+= inStride
; pInRF
+= inStride
; pInCF
+= inStride
; pInLR
+= inStride
;
990 pOutL
+= outStride
; pOutR
+= outStride
;
995 /* 2/2 input: not supported!
996 case CH_MODE_2_0_2_0: */
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
++)
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)
1009 *pOutL
= (INT_PCM
)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInLF
)>>2)+tCF
+tLR
, 2, SAMPLE_BITS
);
1011 *pOutR
= (INT_PCM
)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInRF
)>>2)+tCF
+tRR
, 2, SAMPLE_BITS
);
1014 *pOutL
= (INT_PCM
)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInLF
)>>2)+tCF
+tLR
, DFRACT_BITS
-SAMPLE_BITS
-2, SAMPLE_BITS
);
1016 *pOutR
= (INT_PCM
)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInRF
)>>2)+tCF
+tRR
, DFRACT_BITS
-SAMPLE_BITS
-2, SAMPLE_BITS
);
1018 pInLF
+= inStride
; pInRF
+= inStride
; pInCF
+= inStride
; pInLR
+= inStride
; pInRR
+= inStride
;
1019 pOutL
+= outStride
; pOutR
+= outStride
;
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
));
1030 for (sample
= 0; sample
< frameSize
; sample
++)
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
);
1038 #if (SAMPLE_BITS == 32)
1040 *pOutL
= (INT_PCM
)SATURATE_LEFT_SHIFT(tLF
+tCF
+tLR
, 1, SAMPLE_BITS
);
1042 *pOutR
= (INT_PCM
)SATURATE_LEFT_SHIFT(tRF
+tCF
+tRR
, 1, SAMPLE_BITS
);
1045 *pOutL
= (INT_PCM
)SATURATE_RIGHT_SHIFT(tLF
+tCF
+tLR
, DFRACT_BITS
-SAMPLE_BITS
-1, SAMPLE_BITS
);
1047 *pOutR
= (INT_PCM
)SATURATE_RIGHT_SHIFT(tRF
+tCF
+tRR
, DFRACT_BITS
-SAMPLE_BITS
-1, SAMPLE_BITS
);
1050 pInLF
+= inStride
; pInRF
+= inStride
; pInCF
+= inStride
; pInLR
+= inStride
; pInRR
+= inStride
;
1051 pOutL
+= outStride
; pOutR
+= outStride
;
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
++)
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)
1063 *pOutL
= (INT_PCM
)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInLF
)>>3)+tCF
-tLR
-tRR
, 3, SAMPLE_BITS
);
1065 *pOutR
= (INT_PCM
)SATURATE_LEFT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInRF
)>>3)+tCF
+tLR
+tRR
, 3, SAMPLE_BITS
);
1068 *pOutL
= (INT_PCM
)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInLF
)>>3)+tCF
-tLR
-tRR
, DFRACT_BITS
-SAMPLE_BITS
-3, SAMPLE_BITS
);
1070 *pOutR
= (INT_PCM
)SATURATE_RIGHT_SHIFT((FX_PCM2FX_DBL((FIXP_PCM
)*pInRF
)>>3)+tCF
+tLR
+tRR
, DFRACT_BITS
-SAMPLE_BITS
-3, SAMPLE_BITS
);
1072 pInLF
+= inStride
; pInRF
+= inStride
; pInCF
+= inStride
; pInLR
+= inStride
; pInRR
+= inStride
;
1073 pOutL
+= outStride
; pOutR
+= outStride
;
1079 errorStatus
= PCMDMX_INVALID_MODE
;
1084 If desired create a mono donwmix:
1085 Note: Input are always two channels! */
1086 if (numOutChannels
== 1)
1091 if (useGuidedDownMix
) mlev
= FL2FXCONST_SGL(1.0f
); else mlev
= flev
;
1093 /* Output of STAGE ONE = Input of STAGE TWO */
1094 FDKmemcpy(inOffsetTable
, outOffsetTable
, PCM_DMX_MAX_CHANNELS
*sizeof(UCHAR
));
1096 /* Set I/O strides and offsets */
1097 inStride
= outStride
; /* output from STAGE ONE */
1098 outStride
= numOutChannels
; /* final output */
1100 /* Get channel description and channel mapping for this
1101 * stages number of output channels (always MONO). */
1102 getChannelDescription(
1110 /* Set input channel pointer. */
1111 pInLF
= &pPcmBuf
[inOffsetTable
[LEFT_FRONT_CHANNEL
]*offset
];
1112 pInRF
= &pPcmBuf
[inOffsetTable
[RIGHT_FRONT_CHANNEL
]*offset
];
1114 /* Set output channel pointer */
1115 pOutC
= &pPcmBuf
[outOffsetTable
[CENTER_FRONT_CHANNEL
]*offset
];
1117 /* C' = 0.707*L + 0.707*R */
1118 for (sample
= 0; sample
< frameSize
; sample
++) {
1119 #if (SAMPLE_BITS == 32)
1121 (INT_PCM
)SATURATE_LEFT_SHIFT(fMultDiv2((FIXP_PCM
)*pInLF
,mlev
)+fMultDiv2((FIXP_PCM
)*pInRF
,mlev
), 1, SAMPLE_BITS
);
1124 (INT_PCM
)SATURATE_RIGHT_SHIFT(fMultDiv2((FIXP_PCM
)*pInLF
,mlev
)+fMultDiv2((FIXP_PCM
)*pInRF
,mlev
), DFRACT_BITS
-SAMPLE_BITS
-1, SAMPLE_BITS
);
1127 pInLF
+= inStride
; pInRF
+= inStride
;
1130 /* Finished STAGE TWO */
1133 /* Update the number of output channels */
1134 *nChannels
= self
->numOutputChannels
;
1136 } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1138 if ( numInChannels
== numOutChannels
)
1140 /* Don't need to change the channel description here */
1142 switch (numInChannels
)
1145 { /* Set up channel pointer */
1146 INT_PCM
*pInLF
, *pInRF
, *pOutL
, *pOutR
;
1150 int inStride
, outStride
, offset
;
1153 inStride
= numInChannels
;
1154 outStride
= 2; /* fixed !!! (below stereo is donwmixed to mono if required */
1155 offset
= 1; /* Channel specific offset factor */
1159 offset
= frameSize
; /* Channel specific offset factor */
1162 /* Set input channel pointer */
1163 pInLF
= &pPcmBuf
[inOffsetTable
[LEFT_FRONT_CHANNEL
]*offset
];
1164 pInRF
= &pPcmBuf
[inOffsetTable
[RIGHT_FRONT_CHANNEL
]*offset
];
1166 /* Set output channel pointer (same as input) */
1170 /* Set downmix levels: */
1171 flev
= ATTENUATION_FACTOR_1
; /* 0.707 */
1173 switch (dualChannelMode
)
1175 case CH1_MODE
: /* L' = 0.707 * Ch1; R' = 0.707 * Ch1 */
1176 for (sample
= 0; sample
< frameSize
; sample
++) {
1178 (INT_PCM
)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM
)*pInLF
, flev
), DFRACT_BITS
-SAMPLE_BITS
, SAMPLE_BITS
);
1181 pOutL
+= outStride
; pOutR
+= outStride
;
1184 case CH2_MODE
: /* L' = 0.707 * Ch2; R' = 0.707 * Ch2 */
1185 for (sample
= 0; sample
< frameSize
; sample
++) {
1187 (INT_PCM
)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM
)*pInRF
, flev
), DFRACT_BITS
-SAMPLE_BITS
, SAMPLE_BITS
);
1190 pOutL
+= outStride
; pOutR
+= outStride
;
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);
1197 pInLF
+= inStride
; pInRF
+= inStride
;
1198 pOutL
+= outStride
; pOutR
+= outStride
;
1215 return (errorStatus
);
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.
1223 PCMDMX_ERROR
pcmDmx_Close (
1224 HANDLE_PCM_DOWNMIX
*pSelf
1227 if (pSelf
== NULL
) {
1228 return (PCMDMX_INVALID_HANDLE
);
1231 FreePcmDmxInstance( pSelf
);
1238 /** Get library info for this module.
1239 * @param [out] Pointer to an allocated LIB_INFO structure.
1240 * @returns Returns an error code.
1242 PCMDMX_ERROR
pcmDmx_GetLibInfo( LIB_INFO
*info
)
1247 return PCMDMX_INVALID_ARGUMENT
;
1250 /* Search for next free tab */
1251 for (i
= 0; i
< FDK_MODULE_LAST
; i
++) {
1252 if (info
[i
].module_id
== FDK_NONE
) break;
1254 if (i
== FDK_MODULE_LAST
) {
1255 return PCMDMX_UNKNOWN
;
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
;
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. */