1 2 /* ----------------------------------------------------------------------------------------------------------- 3 Software License for The Fraunhofer FDK AAC Codec Library for Android 4 5 Copyright 1995 - 2013 Fraunhofer-Gesellschaft zur Frderung 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 (at) iis.fraunhofer.de 82 ----------------------------------------------------------------------------------------------------------- */ 83 84 /**************************** FDK PCM utils module ************************** 85 86 Author(s): Christian Griebel 87 Description: Defines functions that perform downmixing or a simple channel 88 expansion in the PCM time domain. 89 90 *******************************************************************************/ 91 92 #include "pcmutils_lib.h" 93 94 #include "genericStds.h" 95 #include "fixpoint_math.h" 96 #include "FDK_core.h" 97 98 99 /* ------------------------ * 100 * GLOBAL SETTINGS (GFR): * 101 * ------------------------ */ 102 #define DSE_METADATA_ENABLE /*!< Enable this to support MPEG/ETSI DVB ancillary data for 103 encoder assisted downmixing of MPEG-4 AAC and 104 MPEG-1/2 layer 2 streams. */ 105 #define PCE_METADATA_ENABLE /*!< Enable this to support MPEG matrix mixdown with a 106 coefficient carried in the PCE. */ 107 108 #define PCM_DMX_MAX_IN_CHANNELS ( 8 ) /* Neither the maximum number of input nor the maximum number of output channels ... */ 109 #define PCM_DMX_MAX_OUT_CHANNELS ( 8 ) /* ... must exceed the maximum number of channels that the framework can handle. */ 110 111 /* ------------------------ * 112 * SPECIFIC SETTINGS: * 113 * ------------------------ */ 114 #define PCM_CHANNEL_EXTENSION_ENABLE /*!< Allow module to duplicate mono signals or add zero channels to achieve the 115 desired number of output channels. */ 116 117 #define PCM_DMX_DFLT_MAX_OUT_CHANNELS ( 6 ) /*!< The maximum number of output channels. If the value is greater than 0 the module 118 will automatically create a mixdown for all input signals with more channels 119 than specified. */ 120 #define PCM_DMX_DFLT_MIN_OUT_CHANNELS ( 0 ) /*!< The minimum number of output channels. If the value is greater than 0 the module 121 will do channel extension automatically for all input signals with less channels 122 than specified. */ 123 #define PCM_DMX_MAX_DELAY_FRAMES ( 1 ) /*!< The maximum delay frames to align the bitstreams payload with the PCM output. */ 124 #define PCM_DMX_DFLT_EXPIRY_FRAME ( 50 ) /*!< If value is greater than 0 the mixdown coefficients will expire by default after the 125 given number of frames. The value 50 corresponds to at least 500ms (FL 960 @ 96kHz) */ 126 /* #define PCMDMX_DEBUG */ 127 128 /* Derived setting: 129 * No need to edit beyond this line. */ 130 #if defined(DSE_METADATA_ENABLE) || defined(PCE_METADATA_ENABLE) || defined(ARIB_MIXDOWN_ENABLE) 131 #define PCM_DOWNMIX_ENABLE /*!< Generally enable down mixing. */ 132 #endif 133 #if (PCM_DMX_MAX_IN_CHANNELS > 2) || (PCM_DMX_MAX_OUT_CHANNELS > 2) 134 #define PCM_DMX_MAX_CHANNELS ( 8 ) 135 #define PCM_DMX_MAX_CHANNEL_GROUPS ( 4 ) 136 #define PCM_DMX_MAX_CHANNELS_PER_GROUP PCM_DMX_MAX_CHANNELS /* All channels can be in one group */ 137 #else 138 #define PCM_DMX_MAX_CHANNELS ( 3 ) /* Need to add 1 because there are three channel positions in first channel group. */ 139 #define PCM_DMX_MAX_CHANNEL_GROUPS ( 1 ) /* Only front channels supported. */ 140 #define PCM_DMX_MAX_CHANNELS_PER_GROUP ( 2 ) /* The maximum over all channel groups */ 141 #endif 142 #if (PCM_DMX_MAX_IN_CHANNELS > PCM_DMX_MAX_OUT_CHANNELS) 143 #define PCM_DMX_MAX_IO_CHANNELS PCM_DMX_MAX_IN_CHANNELS 144 #else 145 #define PCM_DMX_MAX_IO_CHANNELS PCM_DMX_MAX_OUT_CHANNELS 146 #endif 147 148 /* Decoder library info */ 149 #define PCMDMX_LIB_VL0 2 150 #define PCMDMX_LIB_VL1 4 151 #define PCMDMX_LIB_VL2 2 152 #define PCMDMX_LIB_TITLE "PCM Downmix Lib" 153 #define PCMDMX_LIB_BUILD_DATE __DATE__ 154 #define PCMDMX_LIB_BUILD_TIME __TIME__ 155 156 157 /* Fixed and unique channel group indices. 158 * The last group index has to be smaller than PCM_DMX_MAX_CHANNEL_GROUPS. */ 159 #define CH_GROUP_FRONT ( 0 ) 160 #define CH_GROUP_SIDE ( 1 ) 161 #define CH_GROUP_REAR ( 2 ) 162 #define CH_GROUP_LFE ( 3 ) 163 164 /* The ordering of the following fixed channel labels has to be in MPEG-4 style. 165 * From the center to the back with left and right channel interleaved (starting with left). 166 * The last channel label index has to be smaller than PCM_DMX_MAX_CHANNELS. */ 167 #define CENTER_FRONT_CHANNEL ( 0 ) /* C */ 168 #define LEFT_FRONT_CHANNEL ( 1 ) /* L */ 169 #define RIGHT_FRONT_CHANNEL ( 2 ) /* R */ 170 #define LEFT_REAR_CHANNEL ( 3 ) /* Lr (aka left back channel) or center back channel */ 171 #define RIGHT_REAR_CHANNEL ( 4 ) /* Rr (aka right back channel) */ 172 #define LOW_FREQUENCY_CHANNEL ( 5 ) /* Lf */ 173 #define LEFT_MULTIPRPS_CHANNEL ( 6 ) /* Left multipurpose channel */ 174 #define RIGHT_MULTIPRPS_CHANNEL ( 7 ) /* Right multipurpose channel */ 175 176 /* More constants */ 177 #define ONE_CHANNEL ( 1 ) 178 #define TWO_CHANNEL ( 2 ) 179 #define SIX_CHANNEL ( 6 ) 180 #define EIGHT_CHANNEL ( 8 ) 181 182 #define PCMDMX_A_IDX_DEFAULT ( 2 ) 183 #define PCMDMX_B_IDX_DEFAULT ( 2 ) 184 #define PCMDMX_LFE_IDX_DEFAULT ( 15 ) 185 #define PCMDMX_GAIN_5_DEFAULT ( 0 ) 186 #define PCMDMX_GAIN_2_DEFAULT ( 0 ) 187 188 #define PCMDMX_MAX_HEADROOM ( 3 ) /* Defines the maximum PCM scaling headroom that can be done by a 189 postprocessing step. This value must be greater or equal to 0. */ 190 191 #define FALSE 0 192 #define TRUE 1 193 #define IN 0 194 #define OUT 1 195 196 /* Type definitions: */ 197 #ifndef DMX_HIGH_PRECISION_ENABLE 198 #define FIXP_DMX FIXP_SGL 199 #define FX_DMX2FX_DBL(x) FX_SGL2FX_DBL((FIXP_SGL)(x)) 200 #define FX_DBL2FX_DMX(x) FX_DBL2FX_SGL(x) 201 #define FL2FXCONST_DMX(x) FL2FXCONST_SGL(x) 202 #define MAXVAL_DMX MAXVAL_SGL 203 #define FX_DMX2SHRT(x) ((SHORT)(x)) 204 #define FX_DMX2FL(x) FX_DBL2FL(FX_DMX2FX_DBL(x)) 205 #else 206 #define FIXP_DMX FIXP_DBL 207 #define FX_DMX2FX_DBL(x) ((FIXP_DBL)(x)) 208 #define FX_DBL2FX_DMX(x) ((FIXP_DBL)(x) 209 #define FL2FXCONST_DMX(x) FL2FXCONST_DBL(x) 210 #define MAXVAL_DMX MAXVAL_DBL 211 #define FX_DMX2SHRT(x) ((SHORT)((x)>>FRACT_BITS)) 212 #define FX_DMX2FL(x) FX_DBL2FL(x) 213 #endif 214 215 /* The number of channels positions for each group in the internal representation. 216 * See the channel labels above. */ 217 static const UCHAR maxChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS] = { 218 #if (PCM_DMX_MAX_CHANNELS > 3) 219 3, 0, 2, 1 220 #else 221 PCM_DMX_MAX_CHANNELS_PER_GROUP 222 #endif 223 }; 224 225 /* List of packed channel modes */ 226 typedef enum 227 { /* CH_MODE_<numFrontCh>_<numSideCh>_<numBackCh>_<numLfCh> */ 228 CH_MODE_UNDEFINED = 0x0000, 229 /* 1 channel */ 230 CH_MODE_1_0_0_0 = 0x0001, /* chCfg 1 */ 231 /* 2 channels */ 232 CH_MODE_2_0_0_0 = 0x0002, /* chCfg 2 */ 233 /* 3 channels */ 234 CH_MODE_3_0_0_0 = 0x0003, /* chCfg 3 */ 235 CH_MODE_2_0_1_0 = 0x0102, 236 CH_MODE_2_0_0_1 = 0x1002, 237 /* 4 channels */ 238 CH_MODE_3_0_1_0 = 0x0103, /* chCfg 4 */ 239 CH_MODE_2_0_2_0 = 0x0202, 240 CH_MODE_2_0_1_1 = 0x1102, 241 CH_MODE_4_0_0_0 = 0x0004, 242 /* 5 channels */ 243 CH_MODE_3_0_2_0 = 0x0203, /* chCfg 5 */ 244 CH_MODE_2_0_2_1 = 0x1202, 245 CH_MODE_3_0_1_1 = 0x1103, 246 CH_MODE_3_2_0_0 = 0x0023, 247 CH_MODE_5_0_0_0 = 0x0005, 248 /* 6 channels */ 249 CH_MODE_3_0_2_1 = 0x1203, /* chCfg 6 */ 250 CH_MODE_3_2_0_1 = 0x1023, 251 CH_MODE_3_2_1_0 = 0x0123, 252 CH_MODE_5_0_1_0 = 0x0105, 253 CH_MODE_6_0_0_0 = 0x0006, 254 /* 7 channels */ 255 CH_MODE_2_2_2_1 = 0x1222, 256 CH_MODE_3_0_3_1 = 0x1303, /* chCfg 11 */ 257 CH_MODE_3_2_1_1 = 0x1123, 258 CH_MODE_3_2_2_0 = 0x0223, 259 CH_MODE_3_0_2_2 = 0x2203, 260 CH_MODE_5_0_2_0 = 0x0205, 261 CH_MODE_5_0_1_1 = 0x1105, 262 CH_MODE_7_0_0_0 = 0x0007, 263 /* 8 channels */ 264 CH_MODE_3_2_2_1 = 0x1223, 265 CH_MODE_3_0_4_1 = 0x1403, /* chCfg 12 */ 266 CH_MODE_5_0_2_1 = 0x1205, /* chCfg 7 + 14 */ 267 CH_MODE_5_2_1_0 = 0x0125, 268 CH_MODE_3_2_1_2 = 0x2123, 269 CH_MODE_2_2_2_2 = 0x2222, 270 CH_MODE_3_0_3_2 = 0x2303, 271 CH_MODE_8_0_0_0 = 0x0008 272 273 } PCM_DMX_CHANNEL_MODE; 274 275 276 /* These are the channel configurations linked to 277 the number of output channels give by the user: */ 278 static const PCM_DMX_CHANNEL_MODE outChModeTable[PCM_DMX_MAX_CHANNELS+1] = 279 { 280 CH_MODE_UNDEFINED, 281 CH_MODE_1_0_0_0, /* 1 channel */ 282 CH_MODE_2_0_0_0, /* 2 channels */ 283 CH_MODE_3_0_0_0 /* 3 channels */ 284 #if (PCM_DMX_MAX_CHANNELS > 3) 285 ,CH_MODE_3_0_1_0, /* 4 channels */ 286 CH_MODE_3_0_2_0, /* 5 channels */ 287 CH_MODE_3_0_2_1, /* 6 channels */ 288 CH_MODE_3_0_3_1, /* 7 channels */ 289 CH_MODE_3_0_4_1 /* 8 channels */ 290 #endif 291 }; 292 293 static const FIXP_DMX abMixLvlValueTab[8] = 294 { 295 FL2FXCONST_DMX(0.500f), /* scaled by 1 */ 296 FL2FXCONST_DMX(0.841f), 297 FL2FXCONST_DMX(0.707f), 298 FL2FXCONST_DMX(0.596f), 299 FL2FXCONST_DMX(0.500f), 300 FL2FXCONST_DMX(0.422f), 301 FL2FXCONST_DMX(0.355f), 302 FL2FXCONST_DMX(0.0f) 303 }; 304 305 static const FIXP_DMX lfeMixLvlValueTab[16] = 306 { /* value, scale */ 307 FL2FXCONST_DMX(0.7905f), /* 2 */ 308 FL2FXCONST_DMX(0.5000f), /* 2 */ 309 FL2FXCONST_DMX(0.8395f), /* 1 */ 310 FL2FXCONST_DMX(0.7065f), /* 1 */ 311 FL2FXCONST_DMX(0.5945f), /* 1 */ 312 FL2FXCONST_DMX(0.500f), /* 1 */ 313 FL2FXCONST_DMX(0.841f), /* 0 */ 314 FL2FXCONST_DMX(0.707f), /* 0 */ 315 FL2FXCONST_DMX(0.596f), /* 0 */ 316 FL2FXCONST_DMX(0.500f), /* 0 */ 317 FL2FXCONST_DMX(0.316f), /* 0 */ 318 FL2FXCONST_DMX(0.178f), /* 0 */ 319 FL2FXCONST_DMX(0.100f), /* 0 */ 320 FL2FXCONST_DMX(0.032f), /* 0 */ 321 FL2FXCONST_DMX(0.010f), /* 0 */ 322 FL2FXCONST_DMX(0.000f) /* 0 */ 323 }; 324 325 326 327 #ifdef PCE_METADATA_ENABLE 328 /* MPEG matrix mixdown: 329 Set 1: L' = (1 + 2^-0.5 + A )^-1 * [L + C * 2^-0.5 + A * Ls]; 330 R' = (1 + 2^-0.5 + A )^-1 * [R + C * 2^-0.5 + A * Rs]; 331 332 Set 2: L' = (1 + 2^-0.5 + 2A )^-1 * [L + C * 2^-0.5 - A * (Ls + Rs)]; 333 R' = (1 + 2^-0.5 + 2A )^-1 * [R + C * 2^-0.5 + A * (Ls + Rs)]; 334 335 M = (3 + 2A)^-1 * [L + C + R + A*(Ls + Rs)]; 336 */ 337 static const FIXP_DMX mpegMixDownIdx2Coef[4] = 338 { 339 FL2FXCONST_DMX(0.70710678f), 340 FL2FXCONST_DMX(0.5f), 341 FL2FXCONST_DMX(0.35355339f), 342 FL2FXCONST_DMX(0.0f) 343 }; 344 345 static const FIXP_SGL mpegMixDownIdx2PreFact[3][4] = 346 { { /* Set 1: */ 347 FL2FXCONST_DMX(0.4142135623730950f), 348 FL2FXCONST_DMX(0.4530818393219728f), 349 FL2FXCONST_DMX(0.4852813742385703f), 350 FL2FXCONST_DMX(0.5857864376269050f) 351 },{ /* Set 2: */ 352 FL2FXCONST_DMX(0.3203772410170407f), 353 FL2FXCONST_DMX(0.3693980625181293f), 354 FL2FXCONST_DMX(0.4142135623730950f), 355 FL2FXCONST_DMX(0.5857864376269050f) 356 },{ /* Mono DMX set: */ 357 FL2FXCONST_DMX(0.2265409196609864f), 358 FL2FXCONST_DMX(0.25f), 359 FL2FXCONST_DMX(0.2697521433898179f), 360 FL2FXCONST_DMX(0.3333333333333333f) } 361 }; 362 #endif /* PCE_METADATA_ENABLE */ 363 364 365 #define TYPE_NONE ( 0x0 ) 366 #define TYPE_DSE_DATA ( 0x1 ) 367 #define TYPE_PCE_DATA ( 0x2 ) 368 369 typedef struct 370 { 371 UINT typeFlags; 372 /* From DSE */ 373 UCHAR cLevIdx; 374 UCHAR sLevIdx; 375 UCHAR dmixIdxA; 376 UCHAR dmixIdxB; 377 UCHAR dmixIdxLfe; 378 UCHAR dmxGainIdx2; 379 UCHAR dmxGainIdx5; 380 #ifdef PCE_METADATA_ENABLE 381 /* From PCE */ 382 UCHAR matrixMixdownIdx; 383 #endif 384 /* Attributes: */ 385 SCHAR pseudoSurround; /*!< If set to 1 the signal is pseudo surround compatible. The value 0 tells 386 that it is not. If the value is -1 the information is not available. */ 387 UINT expiryCount; /*!< Counter to monitor the life time of a meta data set. */ 388 389 } DMX_BS_META_DATA; 390 391 /* Default metadata */ 392 static const DMX_BS_META_DATA dfltMetaData = { 393 0, 2, 2, 2, 2, 15, 0, 0, 394 #ifdef PCE_METADATA_ENABLE 395 0, 396 #endif 397 -1, 0 398 }; 399 400 /* Dynamic (user) params: 401 See the definition of PCMDMX_PARAM for details on the specific fields. */ 402 typedef struct 403 { 404 UINT expiryFrame; /*!< Linked to DMX_BS_DATA_EXPIRY_FRAME */ 405 DUAL_CHANNEL_MODE dualChannelMode; /*!< Linked to DMX_DUAL_CHANNEL_MODE */ 406 PSEUDO_SURROUND_MODE pseudoSurrMode; /*!< Linked to DMX_PSEUDO_SURROUND_MODE */ 407 SHORT numOutChannelsMin; /*!< Linked to MIN_NUMBER_OF_OUTPUT_CHANNELS */ 408 SHORT numOutChannelsMax; /*!< Linked to MAX_NUMBER_OF_OUTPUT_CHANNELS */ 409 UCHAR frameDelay; /*!< Linked to DMX_BS_DATA_DELAY */ 410 411 } PCM_DMX_USER_PARAMS; 412 413 /* Modules main data structure: */ 414 struct PCM_DMX_INSTANCE 415 { 416 /* Metadata */ 417 DMX_BS_META_DATA bsMetaData[PCM_DMX_MAX_DELAY_FRAMES+1]; 418 PCM_DMX_USER_PARAMS userParams; 419 420 UCHAR applyProcessing; /*!< Flag to en-/disable modules processing. 421 The max channel limiting is done independently. */ 422 }; 423 424 /* Memory allocation macro */ 425 C_ALLOC_MEM_STATIC(PcmDmxInstance, struct PCM_DMX_INSTANCE, 1) 426 427 428 /** Evaluate a given channel configuration and extract a packed channel mode. In addition the 429 * function generates a channel offset table for the mapping to the internal representation. 430 * This function is the inverse to the getChannelDescription() routine. 431 * @param [in] The total number of channels of the given configuration. 432 * @param [in] Array holding the corresponding channel types for each channel. 433 * @param [in] Array holding the corresponding channel type indices for each channel. 434 * @param [out] Array where the buffer offsets for each channel are stored into. 435 * @param [out] The generated packed channel mode that represents the given input configuration. 436 * @returns Returns an error code. 437 **/ 438 static 439 PCMDMX_ERROR getChannelMode ( 440 const INT numChannels, /* in */ 441 const AUDIO_CHANNEL_TYPE channelType[], /* in */ 442 const UCHAR channelIndices[], /* in */ 443 UCHAR offsetTable[PCM_DMX_MAX_CHANNELS], /* out */ 444 PCM_DMX_CHANNEL_MODE *chMode /* out */ 445 ) 446 { 447 UCHAR chIdx[PCM_DMX_MAX_CHANNEL_GROUPS][PCM_DMX_MAX_CHANNELS_PER_GROUP]; 448 UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS]; /* Total num of channels per group of the input config */ 449 UCHAR numChFree[PCM_DMX_MAX_CHANNEL_GROUPS]; /* Number of free slots per group in the internal repr. */ 450 UCHAR hardToPlace[PCM_DMX_MAX_CHANNELS]; /* List of channels not matching the internal repr. */ 451 UCHAR h2pSortIdx[PCM_DMX_MAX_CHANNELS]; 452 PCMDMX_ERROR err = PCMDMX_OK; 453 int ch, grpIdx; 454 int numChToPlace = 0; 455 456 FDK_ASSERT(channelType != NULL); 457 FDK_ASSERT(channelIndices != NULL); 458 FDK_ASSERT(offsetTable != NULL); 459 FDK_ASSERT(chMode != NULL); 460 461 /* For details see ISO/IEC 13818-7:2005(E), 8.5.3 Channel configuration */ 462 FDKmemclear(numChInGrp, PCM_DMX_MAX_CHANNEL_GROUPS*sizeof(UCHAR)); 463 FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR)); 464 FDKmemset(chIdx, 255, PCM_DMX_MAX_CHANNEL_GROUPS*PCM_DMX_MAX_CHANNELS_PER_GROUP*sizeof(UCHAR)); 465 FDKmemset(hardToPlace, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR)); 466 FDKmemset(h2pSortIdx, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR)); 467 /* Get the restrictions of the internal representation */ 468 FDKmemcpy(numChFree, maxChInGrp, PCM_DMX_MAX_CHANNEL_GROUPS*sizeof(UCHAR)); 469 470 *chMode = CH_MODE_UNDEFINED; 471 472 /* Categorize channels */ 473 for (ch = 0; ch < numChannels; ch += 1) { 474 UCHAR chGrpIdx = channelIndices[ch]; 475 int i = 0, j; 476 477 switch (channelType[ch]) { 478 case ACT_FRONT_TOP: 479 chGrpIdx += numChInGrp[CH_GROUP_FRONT]; /* Append after normal plain */ 480 case ACT_FRONT: 481 grpIdx = CH_GROUP_FRONT; 482 break; 483 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1) 484 case ACT_SIDE_TOP: 485 chGrpIdx += numChInGrp[CH_GROUP_SIDE]; /* Append after normal plain */ 486 case ACT_SIDE: 487 grpIdx = CH_GROUP_SIDE; 488 break; 489 case ACT_BACK_TOP: 490 chGrpIdx += numChInGrp[CH_GROUP_REAR]; /* Append after normal plain */ 491 case ACT_BACK: 492 grpIdx = CH_GROUP_REAR; 493 break; 494 case ACT_LFE: 495 grpIdx = CH_GROUP_LFE; 496 break; 497 #endif 498 default: 499 /* Found a channel that can not be categorized! Most likely due to corrupt input signalling. 500 The rescue strategy is to append it to the front channels (=> ignore index). 501 This could cause strange behaviour so return an error to signal it. */ 502 err = PCMDMX_INVALID_MODE; 503 grpIdx = CH_GROUP_FRONT; 504 chGrpIdx = numChannels + numChToPlace; 505 numChToPlace += 1; 506 break; 507 } 508 509 if (numChInGrp[grpIdx] < PCM_DMX_MAX_CHANNELS_PER_GROUP) { 510 /* Sort channels by index */ 511 while ( (i < numChInGrp[grpIdx]) && (chGrpIdx > channelIndices[chIdx[grpIdx][i]]) ) { 512 i += 1; 513 } 514 for (j = numChInGrp[grpIdx]; j > i; j -= 1) { 515 chIdx[grpIdx][j] = chIdx[grpIdx][j-1]; 516 } 517 chIdx[grpIdx][i] = ch; 518 numChInGrp[grpIdx] += 1; 519 } 520 } 521 522 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1) 523 FDK_ASSERT( (numChInGrp[CH_GROUP_FRONT]+numChInGrp[CH_GROUP_SIDE] 524 +numChInGrp[CH_GROUP_REAR]+numChInGrp[CH_GROUP_LFE]) == numChannels); 525 #else 526 FDK_ASSERT( numChInGrp[CH_GROUP_FRONT] == numChannels ); 527 #endif 528 529 /* Compose channel offset table: 530 * Map all channels to the internal representation. */ 531 numChToPlace = 0; 532 533 /* Non-symmetric channels */ 534 if (numChInGrp[CH_GROUP_FRONT] & 0x1) { 535 /* Odd number of front channels -> we have a center channel. 536 In MPEG-4 the center has the index 0. */ 537 offsetTable[CENTER_FRONT_CHANNEL] = chIdx[CH_GROUP_FRONT][0]; 538 numChFree[CH_GROUP_FRONT] -= 1; 539 } 540 541 for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) { 542 int chMapPos = 0; 543 ch = 0; /* Index of channel within the specific group */ 544 545 switch (grpIdx) { 546 case CH_GROUP_FRONT: 547 chMapPos = LEFT_FRONT_CHANNEL; 548 ch = numChInGrp[grpIdx] & 0x1; 549 break; 550 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1) 551 case CH_GROUP_SIDE: 552 break; 553 case CH_GROUP_REAR: 554 chMapPos = LEFT_REAR_CHANNEL; 555 break; 556 case CH_GROUP_LFE: 557 chMapPos = LOW_FREQUENCY_CHANNEL; 558 break; 559 #endif 560 default: 561 FDK_ASSERT(0); 562 continue; 563 } 564 565 /* Map all channels of the group */ 566 for ( ; ch < numChInGrp[grpIdx]; ch += 1) { 567 if (numChFree[grpIdx] > 0) { 568 offsetTable[chMapPos] = chIdx[grpIdx][ch]; 569 chMapPos += 1; 570 numChFree[grpIdx] -= 1; 571 } else { 572 /* Add to the list of hardship cases considering a MPEG-like sorting order: */ 573 int pos, sortIdx = grpIdx*PCM_DMX_MAX_CHANNELS_PER_GROUP + channelIndices[chIdx[grpIdx][ch]]; 574 for (pos = numChToPlace; pos > 0; pos -= 1) { 575 if (h2pSortIdx[pos-1] > sortIdx) { 576 hardToPlace[pos] = hardToPlace[pos-1]; 577 h2pSortIdx[pos] = h2pSortIdx[pos-1]; 578 } else { 579 /* Insert channel at the current index/position */ 580 break; 581 } 582 } 583 hardToPlace[pos] = chIdx[grpIdx][ch]; 584 h2pSortIdx[pos] = sortIdx; 585 numChToPlace += 1; 586 } 587 } 588 } 589 590 { /* Assign the hardship cases */ 591 int chMapPos = 0; 592 int mappingHeat = 0; 593 for (ch = 0; ch < numChToPlace; ch+=1) { 594 int chAssigned = 0; 595 596 /* Just assigning the channels to the next best slot can lead to undesired results (especially for x/x/1.x 597 configurations). Thus use the MPEG-like sorting index to find the best fitting slot for each channel. 598 If this is not possible the sorting index will be ignored (mappingHeat >= 2). */ 599 for ( ; chMapPos < PCM_DMX_MAX_CHANNELS; chMapPos+=1) { 600 if (offsetTable[chMapPos] == 255) { 601 int prvSortIdx = 0; 602 int nxtSortIdx = (CH_GROUP_LFE+1)*PCM_DMX_MAX_CHANNELS_PER_GROUP; 603 604 if (mappingHeat < 2) { 605 if (chMapPos < LEFT_REAR_CHANNEL) { 606 /* Got front channel slot */ 607 prvSortIdx = CH_GROUP_FRONT*PCM_DMX_MAX_CHANNELS_PER_GROUP + chMapPos - CENTER_FRONT_CHANNEL; 608 nxtSortIdx = CH_GROUP_SIDE *PCM_DMX_MAX_CHANNELS_PER_GROUP; 609 } 610 else if (chMapPos < LOW_FREQUENCY_CHANNEL) { 611 /* Got back channel slot */ 612 prvSortIdx = CH_GROUP_REAR*PCM_DMX_MAX_CHANNELS_PER_GROUP + chMapPos - LEFT_REAR_CHANNEL; 613 nxtSortIdx = CH_GROUP_LFE *PCM_DMX_MAX_CHANNELS_PER_GROUP; 614 } 615 else if (chMapPos < LEFT_MULTIPRPS_CHANNEL) { 616 /* Got lfe channel slot */ 617 prvSortIdx = CH_GROUP_LFE *PCM_DMX_MAX_CHANNELS_PER_GROUP + chMapPos - LOW_FREQUENCY_CHANNEL; 618 nxtSortIdx = (CH_GROUP_LFE+1)*PCM_DMX_MAX_CHANNELS_PER_GROUP; 619 } 620 } 621 622 /* Assign the channel only if its sort index is within the range */ 623 if ( (h2pSortIdx[ch] >= prvSortIdx) 624 && (h2pSortIdx[ch] < nxtSortIdx) ) { 625 offsetTable[chMapPos++] = hardToPlace[ch]; 626 chAssigned = 1; 627 break; 628 } 629 } 630 } 631 if (chAssigned == 0) { 632 chMapPos = 0; 633 ch -= 1; 634 mappingHeat += 1; 635 continue; 636 } 637 } 638 } 639 640 /* Compose the channel mode */ 641 *chMode = (PCM_DMX_CHANNEL_MODE)( (numChInGrp[CH_GROUP_FRONT] & 0xF) 642 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1) 643 | (numChInGrp[CH_GROUP_SIDE] & 0xF) << 4 644 | (numChInGrp[CH_GROUP_REAR] & 0xF) << 8 645 | (numChInGrp[CH_GROUP_LFE] & 0xF) << 12 646 #endif 647 ); 648 649 return err; 650 } 651 652 653 /** Generate a channel offset table and complete channel description for a given (packed) channel mode. 654 * This function is the inverse to the getChannelMode() routine but does not support weird channel 655 * configurations. All channels have to be in the normal height layer and there must not be more 656 * channels in each group than given by maxChInGrp. 657 * @param [in] The packed channel mode of the configuration to be processed. 658 * @param [in] Array containing the channel mapping to be used (From MPEG PCE ordering to whatever is required). 659 * @param [out] Array where corresponding channel types for each channels are stored into. 660 * @param [out] Array where corresponding channel type indices for each output channel are stored into. 661 * @param [out] Array where the buffer offsets for each channel are stored into. 662 * @returns None. 663 **/ 664 static 665 void getChannelDescription ( 666 const PCM_DMX_CHANNEL_MODE chMode, /* in */ 667 const UCHAR channelMapping[][8], /* in */ 668 AUDIO_CHANNEL_TYPE channelType[], /* out */ 669 UCHAR channelIndices[], /* out */ 670 UCHAR offsetTable[PCM_DMX_MAX_CHANNELS] /* out */ 671 ) 672 { 673 const UCHAR *pChannelMap; 674 int grpIdx, ch = 0, numChannels = 0; 675 UCHAR numChInGrp[PCM_DMX_MAX_CHANNEL_GROUPS]; 676 677 FDK_ASSERT(channelType != NULL); 678 FDK_ASSERT(channelIndices != NULL); 679 FDK_ASSERT(channelMapping != NULL); 680 FDK_ASSERT(offsetTable != NULL); 681 682 /* Init output arrays */ 683 FDKmemclear(channelType, PCM_DMX_MAX_IO_CHANNELS*sizeof(AUDIO_CHANNEL_TYPE)); 684 FDKmemclear(channelIndices, PCM_DMX_MAX_IO_CHANNELS*sizeof(UCHAR)); 685 FDKmemset(offsetTable, 255, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR)); 686 687 /* Extract the number of channels per group */ 688 numChInGrp[CH_GROUP_FRONT] = chMode & 0xF; 689 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1) 690 numChInGrp[CH_GROUP_SIDE] = (chMode >> 4) & 0xF; 691 numChInGrp[CH_GROUP_REAR] = (chMode >> 8) & 0xF; 692 numChInGrp[CH_GROUP_LFE] = (chMode >> 12) & 0xF; 693 #endif 694 695 /* Summerize to get the total number of channels */ 696 for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) { 697 numChannels += numChInGrp[grpIdx]; 698 } 699 700 /* Get the appropriate channel map */ 701 switch (chMode) { 702 case CH_MODE_1_0_0_0: 703 case CH_MODE_2_0_0_0: 704 case CH_MODE_3_0_0_0: 705 case CH_MODE_3_0_1_0: 706 case CH_MODE_3_0_2_0: 707 case CH_MODE_3_0_2_1: 708 pChannelMap = channelMapping[numChannels]; 709 break; 710 case CH_MODE_3_0_3_1: 711 pChannelMap = channelMapping[11]; 712 break; 713 case CH_MODE_3_0_4_1: 714 pChannelMap = channelMapping[12]; 715 break; 716 case CH_MODE_5_0_2_1: 717 pChannelMap = channelMapping[7]; 718 break; 719 default: 720 /* fallback */ 721 pChannelMap = channelMapping[0]; 722 break; 723 } 724 725 /* Compose channel offset table */ 726 727 /* Non-symmetric channels */ 728 if (numChInGrp[CH_GROUP_FRONT] & 0x1) { 729 /* Odd number of front channels -> we have a center channel. 730 In MPEG-4 the center has the index 0. */ 731 int mappedIdx = pChannelMap[ch]; 732 offsetTable[CENTER_FRONT_CHANNEL] = mappedIdx; 733 channelType[mappedIdx] = ACT_FRONT; 734 channelIndices[mappedIdx] = 0; 735 ch += 1; 736 } 737 738 for (grpIdx = 0; grpIdx < PCM_DMX_MAX_CHANNEL_GROUPS; grpIdx += 1) { 739 AUDIO_CHANNEL_TYPE type = ACT_NONE; 740 int chMapPos = 0, maxChannels = 0; 741 int chIdx = 0; /* Index of channel within the specific group */ 742 743 switch (grpIdx) { 744 case CH_GROUP_FRONT: 745 type = ACT_FRONT; 746 chMapPos = LEFT_FRONT_CHANNEL; 747 maxChannels = 3; 748 chIdx = numChInGrp[grpIdx] & 0x1; 749 break; 750 #if (PCM_DMX_MAX_CHANNEL_GROUPS > 1) 751 case CH_GROUP_SIDE: 752 /* Always map side channels to the multipurpose group. */ 753 type = ACT_SIDE; 754 chMapPos = LEFT_MULTIPRPS_CHANNEL; 755 break; 756 case CH_GROUP_REAR: 757 type = ACT_BACK; 758 chMapPos = LEFT_REAR_CHANNEL; 759 maxChannels = 2; 760 break; 761 case CH_GROUP_LFE: 762 type = ACT_LFE; 763 chMapPos = LOW_FREQUENCY_CHANNEL; 764 maxChannels = 1; 765 break; 766 #endif 767 default: 768 break; 769 } 770 771 /* Map all channels in this group */ 772 for ( ; chIdx < numChInGrp[grpIdx]; chIdx += 1) { 773 int mappedIdx = pChannelMap[ch]; 774 if (chIdx == maxChannels) { 775 /* No space left in this channel group! 776 Use the multipurpose group instead: */ 777 chMapPos = LEFT_MULTIPRPS_CHANNEL; 778 } 779 offsetTable[chMapPos] = mappedIdx; 780 channelType[mappedIdx] = type; 781 channelIndices[mappedIdx] = chIdx; 782 chMapPos += 1; 783 ch += 1; 784 } 785 } 786 } 787 788 /** Private helper function for downmix matrix manipulation that initializes 789 * one row in a given downmix matrix (corresponding to one output channel). 790 * @param [inout] Pointer to fixed-point parts of the downmix matrix. 791 * @param [inout] Pointer to scale factor matrix associated to the downmix factors. 792 * @param [in] Index of channel (row) to be initialized. 793 * @returns Nothing to return. 794 **/ 795 static 796 void dmxInitChannel( 797 FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS], 798 INT mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS], 799 const unsigned int outCh 800 ) 801 { 802 unsigned int inCh; 803 for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) { 804 if (inCh == outCh) { 805 mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.5f); 806 mixScales[outCh][inCh] = 1; 807 } else { 808 mixFactors[outCh][inCh] = FL2FXCONST_DMX(0.0f); 809 mixScales[outCh][inCh] = 0; 810 } 811 } 812 } 813 814 /** Private helper function for downmix matrix manipulation that does a reset 815 * of one row in a given downmix matrix (corresponding to one output channel). 816 * @param [inout] Pointer to fixed-point parts of the downmix matrix. 817 * @param [inout] Pointer to scale factor matrix associated to the downmix factors. 818 * @param [in] Index of channel (row) to be cleared/reset. 819 * @returns Nothing to return. 820 **/ 821 static 822 void dmxClearChannel( 823 FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS], 824 INT mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS], 825 const unsigned int outCh 826 ) 827 { 828 FDKmemclear(&mixFactors[outCh], PCM_DMX_MAX_CHANNELS*sizeof(FIXP_DMX)); 829 FDKmemclear(&mixScales[outCh], PCM_DMX_MAX_CHANNELS*sizeof(INT)); 830 } 831 832 /** Private helper function for downmix matrix manipulation that applies a source channel (row) 833 * scaled by a given mix factor to a destination channel (row) in a given downmix matrix. 834 * Existing mix factors of the destination channel (row) will get overwritten. 835 * @param [inout] Pointer to fixed-point parts of the downmix matrix. 836 * @param [inout] Pointer to scale factor matrix associated to the downmix factors. 837 * @param [in] Index of source channel (row). 838 * @param [in] Index of destination channel (row). 839 * @param [in] Fixed-point part of mix factor to be applied. 840 * @param [in] Scale factor of mix factor to be applied. 841 * @returns Nothing to return. 842 **/ 843 static 844 void dmxSetChannel( 845 FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS], 846 INT mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS], 847 const unsigned int dstCh, 848 const unsigned int srcCh, 849 const FIXP_DMX factor, 850 const INT scale 851 ) 852 { 853 int ch; 854 for (ch=0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) { 855 if (mixFactors[srcCh][ch] != (FIXP_DMX)0) { 856 mixFactors[dstCh][ch] = FX_DBL2FX_DMX(fMult(mixFactors[srcCh][ch], factor)); 857 mixScales[dstCh][ch] = mixScales[srcCh][ch] + scale; 858 } 859 } 860 } 861 862 /** Private helper function for downmix matrix manipulation that adds a source channel (row) 863 * scaled by a given mix factor to a destination channel (row) in a given downmix matrix. 864 * @param [inout] Pointer to fixed-point parts of the downmix matrix. 865 * @param [inout] Pointer to scale factor matrix associated to the downmix factors. 866 * @param [in] Index of source channel (row). 867 * @param [in] Index of destination channel (row). 868 * @param [in] Fixed-point part of mix factor to be applied. 869 * @param [in] Scale factor of mix factor to be applied. 870 * @returns Nothing to return. 871 **/ 872 static 873 void dmxAddChannel( 874 FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS], 875 INT mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS], 876 const unsigned int dstCh, 877 const unsigned int srcCh, 878 const FIXP_DMX factor, 879 const INT scale 880 ) 881 { 882 int ch; 883 for (ch=0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) { 884 FIXP_DBL addFact = fMult(mixFactors[srcCh][ch], factor); 885 if (addFact != (FIXP_DMX)0) { 886 INT newScale = mixScales[srcCh][ch] + scale; 887 if (mixFactors[dstCh][ch] != (FIXP_DMX)0) { 888 if (newScale > mixScales[dstCh][ch]) { 889 mixFactors[dstCh][ch] >>= newScale - mixScales[dstCh][ch]; 890 } else { 891 addFact >>= mixScales[dstCh][ch] - newScale; 892 newScale = mixScales[dstCh][ch]; 893 } 894 } 895 mixFactors[dstCh][ch] += FX_DBL2FX_DMX(addFact); 896 mixScales[dstCh][ch] = newScale; 897 } 898 } 899 } 900 901 902 /** Private function that creates a downmix factor matrix depending on the input and output 903 * configuration, the user parameters as well as the given metadata. This function is the modules 904 * brain and hold all downmix algorithms. 905 * @param [in] Flag that indicates if inChMode holds a real (packed) channel mode or has been 906 converted to a MPEG-4 channel configuration index. 907 * @param [in] Dependent on the inModeIsCfg flag this field hands in a (packed) channel mode or 908 the corresponding MPEG-4 channel configuration index.of the input configuration. 909 * @param [in] The (packed) channel mode of the output configuration. 910 * @param [in] Pointer to structure holding all current user parameter. 911 * @param [in] Pointer to field holding all current meta data. 912 * @param [out] Pointer to fixed-point parts of the downmix matrix. Normalized to one scale factor. 913 * @param [out] The common scale factor of the downmix matrix. 914 * @returns An error code. 915 **/ 916 static 917 PCMDMX_ERROR getMixFactors ( 918 const UCHAR inModeIsCfg, 919 PCM_DMX_CHANNEL_MODE inChMode, 920 const PCM_DMX_CHANNEL_MODE outChMode, 921 const PCM_DMX_USER_PARAMS *pParams, 922 const DMX_BS_META_DATA *pMetaData, 923 FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS], 924 INT *pOutScale 925 ) 926 { 927 PCMDMX_ERROR err = PCMDMX_OK; 928 INT mixScales[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS]; 929 INT maxScale = 0; 930 int numInChannel, numOutChannel; 931 unsigned int outCh, inCh, inChCfg = 0; 932 unsigned int valid[PCM_DMX_MAX_CHANNELS] = { 0 }; 933 934 FDK_ASSERT(pMetaData != NULL); 935 FDK_ASSERT(mixFactors != NULL); 936 /* Check on a supported output configuration */ 937 FDK_ASSERT( (outChMode == CH_MODE_1_0_0_0) 938 || (outChMode == CH_MODE_2_0_0_0) 939 || (outChMode == CH_MODE_3_0_2_1) ); 940 941 if (inModeIsCfg) { 942 /* Workaround for the ambiguity of the internal channel modes. 943 Convert channel config to channel mode: */ 944 inChCfg = (unsigned int)inChMode; 945 switch (inChCfg) { 946 case 1: case 2: case 3: 947 #if (PCM_DMX_MAX_CHANNELS > 3) 948 case 4: case 5: case 6: 949 #endif 950 inChMode = outChModeTable[inChCfg]; 951 break; 952 case 11: 953 inChMode = CH_MODE_3_0_3_1; 954 break; 955 case 12: 956 inChMode = CH_MODE_3_0_4_1; 957 break; 958 case 7: case 14: 959 inChMode = CH_MODE_5_0_2_1; 960 break; 961 default: 962 FDK_ASSERT(0); 963 } 964 } 965 966 /* Extract the total number of input channels */ 967 numInChannel = (inChMode&0xF) 968 + ((inChMode>> 4)&0xF) 969 + ((inChMode>> 8)&0xF) 970 + ((inChMode>>12)&0xF); 971 /* Extract the total number of output channels */ 972 numOutChannel = (outChMode&0xF) 973 + ((outChMode>> 4)&0xF) 974 + ((outChMode>> 8)&0xF) 975 + ((outChMode>>12)&0xF); 976 977 /* MPEG ammendment 4 aka ETSI metadata and fallback mode: */ 978 979 980 /* Create identity DMX matrix: */ 981 for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) { 982 dmxInitChannel( mixFactors, mixScales, outCh ); 983 } 984 if (((inChMode>>12)&0xF) == 0) { 985 /* Clear empty or wrongly mapped input channel */ 986 dmxClearChannel( mixFactors, mixScales, LOW_FREQUENCY_CHANNEL ); 987 } 988 989 /* FIRST STAGE: */ 990 if (numInChannel > SIX_CHANNEL) 991 { /* Always use MPEG equations either with meta data or with default values. */ 992 FIXP_DMX dMixFactA, dMixFactB; 993 INT dMixScaleA, dMixScaleB; 994 int isValidCfg = TRUE; 995 996 /* Get factors from meta data */ 997 dMixFactA = abMixLvlValueTab[pMetaData->dmixIdxA]; 998 dMixScaleA = (pMetaData->dmixIdxA==0) ? 1 : 0; 999 dMixFactB = abMixLvlValueTab[pMetaData->dmixIdxB]; 1000 dMixScaleB = (pMetaData->dmixIdxB==0) ? 1 : 0; 1001 1002 /* Check if input is in the list of supported configurations */ 1003 switch (inChMode) { 1004 case CH_MODE_3_0_3_1: /* chCfg 11 */ 1005 /* 6.1ch: C' = C; L' = L; R' = R; LFE' = LFE; 1006 Ls' = Ls*dmix_a_idx + Cs*dmix_b_idx; 1007 Rs' = Rs*dmix_a_idx + Cs*dmix_b_idx; */ 1008 dmxClearChannel( mixFactors, mixScales, RIGHT_MULTIPRPS_CHANNEL ); /* clear empty input channel */ 1009 dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA ); 1010 dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB ); 1011 dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA ); 1012 dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB ); 1013 break; 1014 case CH_MODE_3_2_1_0: 1015 case CH_MODE_3_2_1_1: /* chCfg 11 but with side channels */ 1016 /* 6.1ch: C' = C; L' = L; R' = R; LFE' = LFE; 1017 Ls' = Ls*dmix_a_idx + Cs*dmix_b_idx; 1018 Rs' = Rs*dmix_a_idx + Cs*dmix_b_idx; */ 1019 dmxClearChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL ); /* clear empty input channel */ 1020 dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactB, dMixScaleB ); 1021 dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA ); 1022 dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactB, dMixScaleB ); 1023 dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_MULTIPRPS_CHANNEL, dMixFactA, dMixScaleA ); 1024 isValidCfg = FALSE; 1025 err = PCMDMX_INVALID_MODE; 1026 break; 1027 case CH_MODE_5_2_1_0: 1028 case CH_MODE_5_0_1_0: 1029 case CH_MODE_5_0_1_1: 1030 /* Ls' = Cs*dmix_a_idx; 1031 Rs' = Cs*dmix_a_idx; */ 1032 dmxClearChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL ); /* clear empty input channel */ 1033 dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA ); 1034 dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA ); 1035 isValidCfg = FALSE; 1036 err = PCMDMX_INVALID_MODE; 1037 break; 1038 case CH_MODE_3_0_4_1: /* chCfg 12 */ 1039 /* 7.1ch Surround Back: C' = C; L' = L; R' = R; LFE' = LFE; 1040 Ls' = Ls*dmix_a_idx + Lsr*dmix_b_idx; 1041 Rs' = Rs*dmix_a_idx + Rsr*dmix_b_idx; */ 1042 dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dMixFactA, dMixScaleA ); 1043 dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB ); 1044 dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_REAR_CHANNEL, dMixFactA, dMixScaleA ); 1045 dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB ); 1046 break; 1047 case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */ 1048 if (inChCfg == 14) { 1049 /* 7.1ch Front Height: C' = C; Ls' = Ls; Rs' = Rs; LFE' = LFE; 1050 L' = L*dmix_a_idx + Lv*dmix_b_idx; 1051 R' = R*dmix_a_idx + Rv*dmix_b_idx; */ 1052 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, dMixFactA, dMixScaleA ); 1053 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB ); 1054 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, dMixFactA, dMixScaleA ); 1055 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_MULTIPRPS_CHANNEL, dMixFactB, dMixScaleB ); 1056 } else { 1057 /* 7.1ch Front: Ls' = Ls; Rs' = Rs; LFE' = LFE; 1058 C' = C + (Lc+Rc)*dmix_a_idx; 1059 L' = L + Lc*dmix_b_idx; 1060 R' = R + Rc*dmix_b_idx; 1061 CAUTION: L+R are not at (MPEG) index 1+2. */ 1062 dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, dMixFactA, dMixScaleA ); 1063 dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, dMixFactA, dMixScaleA ); 1064 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, dMixFactB, dMixScaleB ); 1065 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_MULTIPRPS_CHANNEL, FL2FXCONST_DMX(0.5f), 1 ); 1066 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, dMixFactB, dMixScaleB ); 1067 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_MULTIPRPS_CHANNEL, FL2FXCONST_DMX(0.5f), 1 ); 1068 } 1069 break; 1070 default: 1071 /* Nothing to do. Just use the identity matrix. */ 1072 isValidCfg = FALSE; 1073 err = PCMDMX_INVALID_MODE; 1074 break; 1075 } 1076 1077 /* Add additional DMX gain */ 1078 if ( (isValidCfg == TRUE) 1079 && (pMetaData->dmxGainIdx5 != 0)) 1080 { /* Apply DMX gain 5 */ 1081 FIXP_DMX dmxGain; 1082 INT dmxScale; 1083 INT sign = (pMetaData->dmxGainIdx5 & 0x40) ? -1 : 1; 1084 INT val = pMetaData->dmxGainIdx5 & 0x3F; 1085 1086 /* 10^(dmx_gain_5/80) */ 1087 dmxGain = FX_DBL2FX_DMX( fLdPow( 1088 FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */ 1089 (FIXP_DBL)(sign*val*(LONG)FL2FXCONST_DBL(0.0125f)), 0, 1090 &dmxScale ) 1091 ); 1092 /* Currently only positive scale factors supported! */ 1093 if (dmxScale < 0) { 1094 dmxGain >>= -dmxScale; 1095 dmxScale = 0; 1096 } 1097 1098 dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, dmxGain, dmxScale ); 1099 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, dmxGain, dmxScale ); 1100 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, dmxGain, dmxScale ); 1101 dmxSetChannel( mixFactors, mixScales, LEFT_REAR_CHANNEL, LEFT_REAR_CHANNEL, dmxGain, dmxScale ); 1102 dmxSetChannel( mixFactors, mixScales, RIGHT_REAR_CHANNEL, RIGHT_REAR_CHANNEL, dmxGain, dmxScale ); 1103 dmxSetChannel( mixFactors, mixScales, LOW_FREQUENCY_CHANNEL, LOW_FREQUENCY_CHANNEL, dmxGain, dmxScale ); 1104 } 1105 1106 /* Mark the output channels */ 1107 valid[CENTER_FRONT_CHANNEL] = 1; 1108 valid[LEFT_FRONT_CHANNEL] = 1; 1109 valid[RIGHT_FRONT_CHANNEL] = 1; 1110 valid[LEFT_REAR_CHANNEL] = 1; 1111 valid[RIGHT_REAR_CHANNEL] = 1; 1112 valid[LOW_FREQUENCY_CHANNEL] = 1; 1113 1114 /* Update channel mode for the next stage */ 1115 inChMode = CH_MODE_3_0_2_1; 1116 } 1117 1118 /* SECOND STAGE: */ 1119 if (numOutChannel <= TWO_CHANNEL) { 1120 /* Create DMX matrix according to input configuration */ 1121 switch (inChMode) { 1122 case CH_MODE_2_0_0_0: /* chCfg 2 */ 1123 /* Apply the dual channel mode. */ 1124 switch (pParams->dualChannelMode) { 1125 case CH1_MODE: /* L' = 0.707 * Ch1; 1126 R' = 0.707 * Ch1; */ 1127 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1128 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1129 break; 1130 case CH2_MODE: /* L' = 0.707 * Ch2; 1131 R' = 0.707 * Ch2; */ 1132 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1133 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1134 break; 1135 case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2; 1136 R' = 0.5*Ch1 + 0.5*Ch2; */ 1137 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0 ); 1138 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0 ); 1139 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0 ); 1140 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, FL2FXCONST_DMX(0.5f), 0 ); 1141 break; 1142 default: 1143 case STEREO_MODE: 1144 /* Nothing to do */ 1145 break; 1146 } 1147 break; 1148 case CH_MODE_2_0_1_0: 1149 /* L' = L + 0.707*S; 1150 R' = R + 0.707*S; */ 1151 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1152 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1153 break; 1154 case CH_MODE_3_0_0_0: /* chCfg 3 */ 1155 /* L' = L + 0.707*C; 1156 R' = R + 0.707*C; */ 1157 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1158 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1159 break; 1160 case CH_MODE_3_0_1_0: /* chCfg 4 */ 1161 /* L' = L + 0.707*C + 0.707*S; 1162 R' = R + 0.707*C + 0.707*S; */ 1163 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1164 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1165 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1166 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, FL2FXCONST_DMX(0.707f), 0 ); 1167 break; 1168 case CH_MODE_3_0_2_0: /* chCfg 5 */ 1169 case CH_MODE_3_0_2_1: /* chCfg 6 */ 1170 /* MPEG + ITU + DLB 1171 But because the default downmix equations and coefficients are equal we stick to MPEG. */ 1172 if ( (pMetaData->typeFlags & TYPE_DSE_DATA) 1173 || !(pMetaData->typeFlags & TYPE_PCE_DATA) ) 1174 { 1175 FIXP_DMX cMixLvl, sMixLvl, lMixLvl; 1176 INT cMixScale, sMixScale, lMixScale; 1177 1178 /* Get factors from meta data */ 1179 cMixLvl = abMixLvlValueTab[pMetaData->cLevIdx]; 1180 cMixScale = (pMetaData->cLevIdx==0) ? 1 : 0; 1181 sMixLvl = abMixLvlValueTab[pMetaData->sLevIdx]; 1182 sMixScale = (pMetaData->sLevIdx==0) ? 1 : 0; 1183 lMixLvl = lfeMixLvlValueTab[pMetaData->dmixIdxLfe]; 1184 if (pMetaData->dmixIdxLfe <= 1) { 1185 lMixScale = 2; 1186 } else if (pMetaData->dmixIdxLfe <= 5) { 1187 lMixScale = 1; 1188 } else { 1189 lMixScale = 0; 1190 } 1191 /* Setup the DMX matrix */ 1192 if ( (pParams->pseudoSurrMode == FORCE_PS_DMX) 1193 || ((pParams->pseudoSurrMode == AUTO_PS_DMX) && (pMetaData->pseudoSurround==1))) 1194 { /* L' = L + C*clev - (Ls+Rs)*slev + LFE*lflev; 1195 R' = R + C*clev + (Ls+Rs)*slev + LFE*lflev; */ 1196 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, cMixLvl, cMixScale ); 1197 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, -sMixLvl, sMixScale ); 1198 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL, -sMixLvl, sMixScale ); 1199 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale ); 1200 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, cMixLvl, cMixScale ); 1201 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, sMixLvl, sMixScale ); 1202 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL, sMixLvl, sMixScale ); 1203 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale ); 1204 } 1205 else 1206 { /* L' = L + C*clev + Ls*slev + LFE*llev; 1207 R' = R + C*clev + Rs*slev + LFE*llev; */ 1208 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, cMixLvl, cMixScale ); 1209 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, sMixLvl, sMixScale ); 1210 dmxAddChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale ); 1211 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, cMixLvl, cMixScale ); 1212 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL, sMixLvl, sMixScale ); 1213 dmxAddChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LOW_FREQUENCY_CHANNEL, lMixLvl, lMixScale ); 1214 } 1215 1216 /* Add additional DMX gain */ 1217 if ( pMetaData->dmxGainIdx2 != 0 ) 1218 { /* Apply DMX gain 2 */ 1219 FIXP_DMX dmxGain; 1220 INT dmxScale; 1221 INT sign = (pMetaData->dmxGainIdx2 & 0x40) ? -1 : 1; 1222 INT val = pMetaData->dmxGainIdx2 & 0x3F; 1223 1224 /* 10^(dmx_gain_2/80) */ 1225 dmxGain = FX_DBL2FX_DMX( fLdPow( 1226 FL2FXCONST_DBL(0.830482023721841f), 2, /* log2(10) */ 1227 (FIXP_DBL)(sign*val*(LONG)FL2FXCONST_DBL(0.0125f)), 0, 1228 &dmxScale ) 1229 ); 1230 /* Currently only positive scale factors supported! */ 1231 if (dmxScale < 0) { 1232 dmxGain >>= -dmxScale; 1233 dmxScale = 0; 1234 } 1235 1236 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, dmxGain, dmxScale ); 1237 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, dmxGain, dmxScale ); 1238 } 1239 } 1240 #ifdef PCE_METADATA_ENABLE 1241 else { 1242 FIXP_DMX flev, clev, slevLL, slevLR, slevRL, slevRR; 1243 FIXP_DMX mtrxMixDwnCoef = mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx]; 1244 1245 if ( (pParams->pseudoSurrMode == FORCE_PS_DMX) 1246 || ((pParams->pseudoSurrMode == AUTO_PS_DMX) && (pMetaData->pseudoSurround==1))) 1247 { /* 3/2 input: L' = (1.707+2*A)^-1 * [L+0.707*C-A*Ls-A*Rs]; 1248 R' = (1.707+2*A)^-1 * [R+0.707*C+A*Ls+A*Rs]; */ 1249 flev = mpegMixDownIdx2PreFact[1][pMetaData->matrixMixdownIdx]; 1250 slevRR = slevRL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef)); 1251 slevLL = slevLR = -slevRL; 1252 } 1253 else { 1254 /* 3/2 input: L' = (1.707+A)^-1 * [L+0.707*C+A*Ls]; 1255 R' = (1.707+A)^-1 * [R+0.707*C+A*Rs]; */ 1256 flev = mpegMixDownIdx2PreFact[0][pMetaData->matrixMixdownIdx]; 1257 slevRR = slevLL = FX_DBL2FX_DMX(fMult(flev, mtrxMixDwnCoef)); 1258 slevLR = slevRL = (FIXP_SGL)0; 1259 } 1260 /* common factor */ 1261 clev = FX_DBL2FX_DMX(fMult(flev, mpegMixDownIdx2Coef[0] /* 0.707 */)); 1262 1263 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, flev, 0 ); 1264 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, clev, 0 ); 1265 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, slevLL, 0 ); 1266 dmxSetChannel( mixFactors, mixScales, LEFT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL, slevLR, 0 ); 1267 1268 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, flev, 0 ); 1269 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, CENTER_FRONT_CHANNEL, clev, 0 ); 1270 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, LEFT_REAR_CHANNEL, slevRL, 0 ); 1271 dmxSetChannel( mixFactors, mixScales, RIGHT_FRONT_CHANNEL, RIGHT_REAR_CHANNEL, slevRR, 0 ); 1272 } 1273 #endif /* PCE_METADATA_ENABLE */ 1274 break; 1275 default: 1276 /* This configuration does not fit to any known downmix equation! */ 1277 err = PCMDMX_INVALID_MODE; 1278 break; 1279 } 1280 /* Mark the output channels */ 1281 FDKmemclear(valid, PCM_DMX_MAX_CHANNELS*sizeof(unsigned int)); 1282 valid[LEFT_FRONT_CHANNEL] = 1; 1283 valid[RIGHT_FRONT_CHANNEL] = 1; 1284 /* Update channel mode for the next stage */ 1285 inChMode = CH_MODE_2_0_0_0; 1286 } 1287 1288 if (numOutChannel == ONE_CHANNEL) { 1289 FIXP_DMX monoMixLevel; 1290 INT monoMixScale; 1291 1292 #ifdef PCE_METADATA_ENABLE 1293 if ( (pMetaData->typeFlags & TYPE_PCE_DATA) 1294 && !(pMetaData->typeFlags & TYPE_DSE_DATA) ) 1295 { /* C' = (3+2*A)^-1 * [C+L+R+A*Ls+A+Rs]; */ 1296 monoMixLevel = mpegMixDownIdx2PreFact[2][pMetaData->matrixMixdownIdx]; 1297 monoMixScale = 0; 1298 1299 dmxClearChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL ); 1300 mixFactors[CENTER_FRONT_CHANNEL][CENTER_FRONT_CHANNEL] = monoMixLevel; 1301 mixFactors[CENTER_FRONT_CHANNEL][LEFT_FRONT_CHANNEL] = monoMixLevel; 1302 mixFactors[CENTER_FRONT_CHANNEL][RIGHT_FRONT_CHANNEL] = monoMixLevel; 1303 monoMixLevel = FX_DBL2FX_DMX(fMult(monoMixLevel, mpegMixDownIdx2Coef[pMetaData->matrixMixdownIdx])); 1304 mixFactors[CENTER_FRONT_CHANNEL][LEFT_REAR_CHANNEL] = monoMixLevel; 1305 mixFactors[CENTER_FRONT_CHANNEL][RIGHT_REAR_CHANNEL] = monoMixLevel; 1306 } 1307 else 1308 #endif 1309 { /* C' = L + R; [default] */ 1310 monoMixLevel = FL2FXCONST_DMX(0.5f); 1311 monoMixScale = 1; 1312 dmxClearChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL ); /* C is not in the mix */ 1313 dmxSetChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, LEFT_FRONT_CHANNEL, monoMixLevel, monoMixScale ); 1314 dmxAddChannel( mixFactors, mixScales, CENTER_FRONT_CHANNEL, RIGHT_FRONT_CHANNEL, monoMixLevel, monoMixScale ); 1315 } 1316 1317 /* Mark the output channel */ 1318 FDKmemclear(valid, PCM_DMX_MAX_CHANNELS*sizeof(unsigned int)); 1319 valid[CENTER_FRONT_CHANNEL] = 1; 1320 } 1321 1322 #define MAX_SEARCH_START_VAL ( -7 ) 1323 1324 { 1325 LONG chSum[PCM_DMX_MAX_CHANNELS]; 1326 INT chSumMax = MAX_SEARCH_START_VAL; 1327 1328 /* Determine the current maximum scale factor */ 1329 for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) { 1330 if (valid[outCh]!=0) { 1331 for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) { 1332 if (mixScales[outCh][inCh] > maxScale) 1333 { /* Store the new maximum */ 1334 maxScale = mixScales[outCh][inCh]; 1335 } 1336 } 1337 } 1338 } 1339 1340 /* Individualy analyse output chanal levels */ 1341 for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) { 1342 chSum[outCh] = MAX_SEARCH_START_VAL; 1343 if (valid[outCh]!=0) { 1344 int ovrflwProtScale = 0; 1345 1346 /* Accumulate all factors for each output channel */ 1347 chSum[outCh] = 0; 1348 for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) { 1349 SHORT addFact = FX_DMX2SHRT(mixFactors[outCh][inCh]); 1350 if ( mixScales[outCh][inCh] <= maxScale ) { 1351 addFact >>= maxScale - mixScales[outCh][inCh]; 1352 } else { 1353 addFact <<= mixScales[outCh][inCh] - maxScale; 1354 } 1355 chSum[outCh] += addFact; 1356 } 1357 if (chSum[outCh] > (LONG)MAXVAL_SGL) { 1358 while (chSum[outCh] > (LONG)MAXVAL_SGL) { 1359 ovrflwProtScale += 1; 1360 chSum[outCh] >>= 1; 1361 } 1362 } else if (chSum[outCh] > 0) { 1363 while ((chSum[outCh]<<1) <= (LONG)MAXVAL_SGL) { 1364 ovrflwProtScale -= 1; 1365 chSum[outCh] <<= 1; 1366 } 1367 } 1368 /* Store the differential scaling in the same array */ 1369 chSum[outCh] = ovrflwProtScale; 1370 } 1371 } 1372 1373 for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) { 1374 if ( (valid[outCh] != 0) 1375 && (chSum[outCh] > chSumMax) ) 1376 { /* Store the new maximum */ 1377 chSumMax = chSum[outCh]; 1378 } 1379 } 1380 maxScale = FDKmax(maxScale+chSumMax, 0); 1381 1382 /* Normalize all factors */ 1383 for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) { 1384 if (valid[outCh]!=0) { 1385 for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) { 1386 if (mixFactors[outCh][inCh] != (FIXP_DMX)0) { 1387 if ( mixScales[outCh][inCh] <= maxScale ) { 1388 mixFactors[outCh][inCh] >>= maxScale - mixScales[outCh][inCh]; 1389 } else { 1390 mixFactors[outCh][inCh] <<= mixScales[outCh][inCh] - maxScale; 1391 } 1392 mixScales[outCh][inCh] = maxScale; 1393 } 1394 } 1395 } 1396 } 1397 } 1398 1399 1400 /* return the scale factor */ 1401 *pOutScale = maxScale; 1402 1403 return (err); 1404 } 1405 1406 1407 /** Open and initialize an instance of the PCM downmix module 1408 * @param [out] Pointer to a buffer receiving the handle of the new instance. 1409 * @returns Returns an error code. 1410 **/ 1411 PCMDMX_ERROR pcmDmx_Open ( 1412 HANDLE_PCM_DOWNMIX *pSelf 1413 ) 1414 { 1415 HANDLE_PCM_DOWNMIX self; 1416 1417 if (pSelf == NULL) { 1418 return (PCMDMX_INVALID_HANDLE); 1419 } 1420 1421 *pSelf = NULL; 1422 1423 self = (HANDLE_PCM_DOWNMIX) GetPcmDmxInstance( 0 ); 1424 if (self == NULL) { 1425 return (PCMDMX_OUT_OF_MEMORY); 1426 } 1427 1428 /* Reset the full instance */ 1429 pcmDmx_Reset( self, PCMDMX_RESET_FULL ); 1430 1431 *pSelf = self; 1432 1433 return (PCMDMX_OK); 1434 } 1435 1436 1437 /** Reset all static values like e.g. mixdown coefficients. 1438 * @param [in] Handle of PCM downmix module instance. 1439 * @param [in] Flags telling which parts of the module shall be reset. 1440 * @returns Returns an error code. 1441 **/ 1442 PCMDMX_ERROR pcmDmx_Reset ( 1443 HANDLE_PCM_DOWNMIX self, 1444 UINT flags 1445 ) 1446 { 1447 if (self == NULL) { return (PCMDMX_INVALID_HANDLE); } 1448 1449 if (flags & PCMDMX_RESET_PARAMS) { 1450 PCM_DMX_USER_PARAMS *pParams = &self->userParams; 1451 1452 pParams->dualChannelMode = STEREO_MODE; 1453 pParams->pseudoSurrMode = NEVER_DO_PS_DMX; 1454 pParams->numOutChannelsMax = PCM_DMX_DFLT_MAX_OUT_CHANNELS; 1455 pParams->numOutChannelsMin = PCM_DMX_DFLT_MIN_OUT_CHANNELS; 1456 pParams->frameDelay = 0; 1457 pParams->expiryFrame = PCM_DMX_DFLT_EXPIRY_FRAME; 1458 1459 self->applyProcessing = 0; 1460 } 1461 1462 if (flags & PCMDMX_RESET_BS_DATA) { 1463 int slot; 1464 /* Init all slots with a default set */ 1465 for (slot = 0; slot <= PCM_DMX_MAX_DELAY_FRAMES; slot += 1) { 1466 FDKmemcpy(&self->bsMetaData[slot], &dfltMetaData, sizeof(DMX_BS_META_DATA)); 1467 } 1468 } 1469 1470 return (PCMDMX_OK); 1471 } 1472 1473 1474 /** Set one parameter for one instance of the PCM downmix module. 1475 * @param [in] Handle of PCM downmix module instance. 1476 * @param [in] Parameter to be set. 1477 * @param [in] Parameter value. 1478 * @returns Returns an error code. 1479 **/ 1480 PCMDMX_ERROR pcmDmx_SetParam ( 1481 HANDLE_PCM_DOWNMIX self, 1482 const PCMDMX_PARAM param, 1483 const INT value 1484 ) 1485 { 1486 switch (param) 1487 { 1488 case DMX_BS_DATA_EXPIRY_FRAME: 1489 if (self == NULL) 1490 return (PCMDMX_INVALID_HANDLE); 1491 self->userParams.expiryFrame = (value > 0) ? (UINT)value : 0; 1492 break; 1493 1494 case DMX_BS_DATA_DELAY: 1495 if ( (value > PCM_DMX_MAX_DELAY_FRAMES) 1496 || (value < 0) ) { 1497 return (PCMDMX_UNABLE_TO_SET_PARAM); 1498 } 1499 if (self == NULL) { 1500 return (PCMDMX_INVALID_HANDLE); 1501 } 1502 self->userParams.frameDelay = (UCHAR)value; 1503 break; 1504 1505 case MIN_NUMBER_OF_OUTPUT_CHANNELS: 1506 switch (value) { /* supported output channels */ 1507 case -1: case 0: case ONE_CHANNEL: case TWO_CHANNEL: 1508 #if (PCM_DMX_MAX_OUT_CHANNELS >= 6) 1509 case SIX_CHANNEL: 1510 #endif 1511 #if (PCM_DMX_MAX_OUT_CHANNELS >= 8) 1512 case EIGHT_CHANNEL: 1513 #endif 1514 break; 1515 default: 1516 return (PCMDMX_UNABLE_TO_SET_PARAM); 1517 } 1518 if (self == NULL) 1519 return (PCMDMX_INVALID_HANDLE); 1520 /* Store the new value */ 1521 self->userParams.numOutChannelsMin = (value > 0) ? value : -1; 1522 if ( (value > 0) 1523 && (self->userParams.numOutChannelsMax > 0) 1524 && (value > self->userParams.numOutChannelsMax) ) 1525 { /* MIN > MAX would be an invalid state. Thus set MAX = MIN in this case. */ 1526 self->userParams.numOutChannelsMax = self->userParams.numOutChannelsMin; 1527 } 1528 break; 1529 1530 case MAX_NUMBER_OF_OUTPUT_CHANNELS: 1531 switch (value) { /* supported output channels */ 1532 case -1: case 0: case ONE_CHANNEL: case TWO_CHANNEL: 1533 #if (PCM_DMX_MAX_OUT_CHANNELS >= 6) 1534 case SIX_CHANNEL: 1535 #endif 1536 #if (PCM_DMX_MAX_OUT_CHANNELS >= 8) 1537 case EIGHT_CHANNEL: 1538 #endif 1539 break; 1540 default: 1541 return (PCMDMX_UNABLE_TO_SET_PARAM); 1542 } 1543 if (self == NULL) 1544 return (PCMDMX_INVALID_HANDLE); 1545 /* Store the new value */ 1546 self->userParams.numOutChannelsMax = (value > 0) ? value : -1; 1547 if ( (value > 0) 1548 && (value < self->userParams.numOutChannelsMin) ) 1549 { /* MAX < MIN would be an invalid state. Thus set MIN = MAX in this case. */ 1550 self->userParams.numOutChannelsMin = self->userParams.numOutChannelsMax; 1551 } 1552 break; 1553 1554 case DMX_DUAL_CHANNEL_MODE: 1555 switch ((DUAL_CHANNEL_MODE)value) { 1556 case STEREO_MODE: 1557 case CH1_MODE: 1558 case CH2_MODE: 1559 case MIXED_MODE: 1560 break; 1561 default: 1562 return (PCMDMX_UNABLE_TO_SET_PARAM); 1563 } 1564 if (self == NULL) 1565 return (PCMDMX_INVALID_HANDLE); 1566 self->userParams.dualChannelMode = (DUAL_CHANNEL_MODE)value; 1567 self->applyProcessing = 1; /* Force processing */ 1568 break; 1569 1570 case DMX_PSEUDO_SURROUND_MODE: 1571 switch ((PSEUDO_SURROUND_MODE)value) { 1572 case NEVER_DO_PS_DMX: 1573 case AUTO_PS_DMX: 1574 case FORCE_PS_DMX: 1575 break; 1576 default: 1577 return (PCMDMX_UNABLE_TO_SET_PARAM); 1578 } 1579 if (self == NULL) 1580 return (PCMDMX_INVALID_HANDLE); 1581 self->userParams.pseudoSurrMode = (PSEUDO_SURROUND_MODE)value; 1582 break; 1583 1584 default: 1585 return (PCMDMX_UNKNOWN_PARAM); 1586 } 1587 1588 return (PCMDMX_OK); 1589 } 1590 1591 /** Get one parameter value of one PCM downmix module instance. 1592 * @param [in] Handle of PCM downmix module instance. 1593 * @param [in] Parameter to be set. 1594 * @param [out] Pointer to buffer receiving the parameter value. 1595 * @returns Returns an error code. 1596 **/ 1597 PCMDMX_ERROR pcmDmx_GetParam ( 1598 HANDLE_PCM_DOWNMIX self, 1599 const PCMDMX_PARAM param, 1600 INT * const pValue 1601 ) 1602 { 1603 PCM_DMX_USER_PARAMS *pUsrParams; 1604 1605 if ( (self == NULL) 1606 || (pValue == NULL) ) { 1607 return (PCMDMX_INVALID_HANDLE); 1608 } 1609 pUsrParams = &self->userParams; 1610 1611 switch (param) 1612 { 1613 case DMX_BS_DATA_EXPIRY_FRAME: 1614 *pValue = (INT)pUsrParams->expiryFrame; 1615 break; 1616 case DMX_BS_DATA_DELAY: 1617 *pValue = (INT)pUsrParams->frameDelay; 1618 break; 1619 case MIN_NUMBER_OF_OUTPUT_CHANNELS: 1620 *pValue = (INT)pUsrParams->numOutChannelsMin; 1621 break; 1622 case MAX_NUMBER_OF_OUTPUT_CHANNELS: 1623 *pValue = (INT)pUsrParams->numOutChannelsMax; 1624 break; 1625 case DMX_DUAL_CHANNEL_MODE: 1626 *pValue = (INT)pUsrParams->dualChannelMode; 1627 break; 1628 case DMX_PSEUDO_SURROUND_MODE: 1629 *pValue = (INT)pUsrParams->pseudoSurrMode; 1630 break; 1631 default: 1632 return (PCMDMX_UNKNOWN_PARAM); 1633 } 1634 1635 return (PCMDMX_OK); 1636 } 1637 1638 1639 #ifdef DSE_METADATA_ENABLE 1640 1641 #define MAX_DSE_ANC_BYTES ( 16 ) /* 15 bytes */ 1642 #define ANC_DATA_SYNC_BYTE ( 0xBC ) /* ancillary data sync byte. */ 1643 1644 /* 1645 * Read DMX meta-data from a data stream element. 1646 */ 1647 PCMDMX_ERROR pcmDmx_Parse ( 1648 HANDLE_PCM_DOWNMIX self, 1649 HANDLE_FDK_BITSTREAM hBs, 1650 UINT ancDataBits, 1651 int isMpeg2 1652 ) 1653 { 1654 PCMDMX_ERROR errorStatus = PCMDMX_OK; 1655 DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0]; 1656 1657 int skip4Dmx = 0, skip4Ext = 0; 1658 int dmxLvlAvail = 0, extDataAvail = 0; 1659 int foundNewData = 0; 1660 UINT minAncBits = ((isMpeg2) ? 5 : 3)*8; 1661 1662 if ( (self == NULL) 1663 || (hBs == NULL) ) { return (PCMDMX_INVALID_HANDLE); } 1664 1665 ancDataBits = FDKgetValidBits(hBs); 1666 1667 /* sanity checks */ 1668 if ( (ancDataBits < minAncBits) 1669 || (ancDataBits > FDKgetValidBits(hBs)) ) { 1670 return (PCMDMX_CORRUPT_ANC_DATA); 1671 } 1672 1673 pBsMetaData = &self->bsMetaData[0]; 1674 1675 if (isMpeg2) { 1676 /* skip DVD ancillary data */ 1677 FDKpushFor(hBs, 16); 1678 } 1679 1680 /* check sync word */ 1681 if (FDKreadBits(hBs,8) != ANC_DATA_SYNC_BYTE) { 1682 return (PCMDMX_CORRUPT_ANC_DATA); 1683 } 1684 1685 /* skip MPEG audio type and Dolby surround mode */ 1686 FDKpushFor(hBs, 4); 1687 1688 if (isMpeg2) { 1689 /* int numAncBytes = */ FDKreadBits(hBs, 4); 1690 /* advanced dynamic range control */ 1691 if (FDKreadBit(hBs)) skip4Dmx += 24; 1692 /* dialog normalization */ 1693 if (FDKreadBit(hBs)) skip4Dmx += 8; 1694 /* reproduction_level */ 1695 if (FDKreadBit(hBs)) skip4Dmx += 8; 1696 } else { 1697 FDKpushFor(hBs, 2); /* drc presentation mode */ 1698 pBsMetaData->pseudoSurround = FDKreadBit(hBs); 1699 FDKpushFor(hBs, 4); /* reserved bits */ 1700 } 1701 1702 /* downmixing levels MPEGx status */ 1703 dmxLvlAvail = FDKreadBit(hBs); 1704 1705 if (isMpeg2) { 1706 /* scale factor CRC status */ 1707 if (FDKreadBit(hBs)) skip4Ext += 16; 1708 } else { 1709 /* ancillary data extension status */ 1710 extDataAvail = FDKreadBit(hBs); 1711 } 1712 1713 /* audio coding and compression status */ 1714 if (FDKreadBit(hBs)) skip4Ext += 16; 1715 /* coarse grain timecode status */ 1716 if (FDKreadBit(hBs)) skip4Ext += 16; 1717 /* fine grain timecode status */ 1718 if (FDKreadBit(hBs)) skip4Ext += 16; 1719 1720 /* skip the useless data to get to the DMX levels */ 1721 FDKpushFor(hBs, skip4Dmx); 1722 1723 /* downmix_levels_MPEGX */ 1724 if (dmxLvlAvail) 1725 { 1726 if (FDKreadBit(hBs)) { /* center_mix_level_on */ 1727 pBsMetaData->cLevIdx = FDKreadBits(hBs, 3); 1728 foundNewData = 1; 1729 } else { 1730 FDKreadBits(hBs, 3); 1731 } 1732 if (FDKreadBit(hBs)) { /* surround_mix_level_on */ 1733 pBsMetaData->sLevIdx = FDKreadBits(hBs, 3); 1734 foundNewData = 1; 1735 } else { 1736 FDKreadBits(hBs, 3); 1737 } 1738 } 1739 1740 /* skip the useless data to get to the ancillary data extension */ 1741 FDKpushFor(hBs, skip4Ext); 1742 1743 /* anc data extension (MPEG-4 only) */ 1744 if (extDataAvail) { 1745 int extDmxLvlSt, extDmxGainSt, extDmxLfeSt; 1746 1747 FDKreadBit(hBs); /* reserved bit */ 1748 extDmxLvlSt = FDKreadBit(hBs); 1749 extDmxGainSt = FDKreadBit(hBs); 1750 extDmxLfeSt = FDKreadBit(hBs); 1751 FDKreadBits(hBs, 4); /* reserved bits */ 1752 1753 if (extDmxLvlSt) { 1754 pBsMetaData->dmixIdxA = FDKreadBits(hBs, 3); 1755 pBsMetaData->dmixIdxB = FDKreadBits(hBs, 3); 1756 FDKreadBits(hBs, 2); /* reserved bits */ 1757 foundNewData = 1; 1758 } 1759 if (extDmxGainSt) { 1760 pBsMetaData->dmxGainIdx5 = FDKreadBits(hBs, 7); 1761 FDKreadBit(hBs); /* reserved bit */ 1762 pBsMetaData->dmxGainIdx2 = FDKreadBits(hBs, 7); 1763 FDKreadBit(hBs); /* reserved bit */ 1764 foundNewData = 1; 1765 } 1766 if (extDmxLfeSt) { 1767 pBsMetaData->dmixIdxLfe = FDKreadBits(hBs, 4); 1768 FDKreadBits(hBs, 4); /* reserved bits */ 1769 foundNewData = 1; 1770 } 1771 } 1772 1773 /* final sanity check on the amount of read data */ 1774 if ((INT)FDKgetValidBits(hBs) < 0) { 1775 errorStatus = PCMDMX_CORRUPT_ANC_DATA; 1776 } 1777 1778 if ( (errorStatus == PCMDMX_OK) 1779 && (foundNewData == 1) ) { 1780 /* announce new data */ 1781 pBsMetaData->typeFlags |= TYPE_DSE_DATA; 1782 /* reset expiry counter */ 1783 pBsMetaData->expiryCount = 0; 1784 } 1785 1786 return (errorStatus); 1787 } 1788 1789 /* 1790 * Read DMX meta-data from a data stream element. 1791 */ 1792 PCMDMX_ERROR pcmDmx_ReadDvbAncData ( 1793 HANDLE_PCM_DOWNMIX self, 1794 UCHAR *pAncDataBuf, 1795 UINT ancDataBytes, 1796 int isMpeg2 1797 ) 1798 { 1799 FDK_BITSTREAM bs; 1800 HANDLE_FDK_BITSTREAM hBs = &bs; 1801 PCMDMX_ERROR errorStatus = PCMDMX_OK; 1802 1803 if (self == NULL) { return (PCMDMX_INVALID_HANDLE); } 1804 1805 /* sanity checks */ 1806 if ( (pAncDataBuf == NULL) 1807 || (ancDataBytes == 0) ) { 1808 return (PCMDMX_CORRUPT_ANC_DATA); 1809 } 1810 1811 FDKinitBitStream (hBs, pAncDataBuf, MAX_DSE_ANC_BYTES, ancDataBytes*8, BS_READER); 1812 1813 errorStatus = pcmDmx_Parse ( 1814 self, 1815 hBs, 1816 ancDataBytes*8, 1817 isMpeg2 ); 1818 1819 return (errorStatus); 1820 } 1821 #endif /* DSE_METADATA_ENABLE */ 1822 1823 #ifdef PCE_METADATA_ENABLE 1824 /** Set the matrix mixdown information extracted from the PCE of an AAC bitstream. 1825 * Note: Call only if matrix_mixdown_idx_present is true. 1826 * @param [in] Handle of PCM downmix module instance. 1827 * @param [in] The 2 bit matrix mixdown index extracted from PCE. 1828 * @param [in] The pseudo surround enable flag extracted from PCE. 1829 * @returns Returns an error code. 1830 **/ 1831 PCMDMX_ERROR pcmDmx_SetMatrixMixdownFromPce ( 1832 HANDLE_PCM_DOWNMIX self, 1833 int matrixMixdownPresent, 1834 int matrixMixdownIdx, 1835 int pseudoSurroundEnable 1836 ) 1837 { 1838 DMX_BS_META_DATA *pBsMetaData = &self->bsMetaData[0]; 1839 1840 if (self == NULL) { 1841 return (PCMDMX_INVALID_HANDLE); 1842 } 1843 1844 if (matrixMixdownPresent) { 1845 pBsMetaData->pseudoSurround = pseudoSurroundEnable; 1846 pBsMetaData->matrixMixdownIdx = matrixMixdownIdx & 0x03; 1847 pBsMetaData->typeFlags |= TYPE_PCE_DATA; 1848 /* Reset expiry counter */ 1849 pBsMetaData->expiryCount = 0; 1850 } 1851 1852 return (PCMDMX_OK); 1853 } 1854 #endif /* PCE_METADATA_ENABLE */ 1855 1856 1857 /** Apply down or up mixing. 1858 * @param [in] Handle of PCM downmix module instance. 1859 * @param [inout] Pointer to buffer that hold the time domain signal. 1860 * @param [in] Pointer where the amount of output samples is returned into. 1861 * @param [inout] Pointer where the amount of output channels is returned into. 1862 * @param [in] Flag which indicates if output time data are writtern interleaved or as subsequent blocks. 1863 * @param [inout] Array where the corresponding channel type for each output audio channel is stored into. 1864 * @param [inout] Array where the corresponding channel type index for each output audio channel is stored into. 1865 * @param [in] Array containing the out channel mapping to be used (From MPEG PCE ordering to whatever is required). 1866 * @param [out] Pointer on a field receiving the scale factor that has to be applied on all samples afterwards. 1867 * If the handed pointer is NULL scaling is done internally. 1868 * @returns Returns an error code. 1869 **/ 1870 PCMDMX_ERROR pcmDmx_ApplyFrame ( 1871 HANDLE_PCM_DOWNMIX self, 1872 INT_PCM *pPcmBuf, 1873 UINT frameSize, 1874 INT *nChannels, 1875 int fInterleaved, 1876 AUDIO_CHANNEL_TYPE channelType[], 1877 UCHAR channelIndices[], 1878 const UCHAR channelMapping[][8], 1879 INT *pDmxOutScale 1880 ) 1881 { 1882 PCM_DMX_USER_PARAMS *pParam = NULL; 1883 PCMDMX_ERROR errorStatus = PCMDMX_OK; 1884 DUAL_CHANNEL_MODE dualChannelMode; 1885 PCM_DMX_CHANNEL_MODE inChMode; 1886 PCM_DMX_CHANNEL_MODE outChMode; 1887 INT devNull; /* Just a dummy to avoid a lot of branches in the code */ 1888 int numOutChannels, numInChannels; 1889 int inStride, outStride, offset; 1890 int dmxMaxScale, dmxScale; 1891 int ch, slot; 1892 UCHAR inOffsetTable[PCM_DMX_MAX_CHANNELS]; 1893 1894 DMX_BS_META_DATA bsMetaData; 1895 1896 if ( (self == NULL) 1897 || (nChannels == NULL) 1898 || (channelType == NULL) 1899 || (channelIndices == NULL) 1900 || (channelMapping == NULL) ) { 1901 return (PCMDMX_INVALID_HANDLE); 1902 } 1903 1904 /* Init the output scaling */ 1905 dmxScale = 0; 1906 if (pDmxOutScale != NULL) { 1907 /* Avoid final scaling internally and hand it to the outside world. */ 1908 *pDmxOutScale = 0; 1909 dmxMaxScale = PCMDMX_MAX_HEADROOM; 1910 } else { 1911 /* Apply the scaling internally. */ 1912 pDmxOutScale = &devNull; /* redirect to temporal stack memory */ 1913 dmxMaxScale = 0; 1914 } 1915 1916 pParam = &self->userParams; 1917 numInChannels = *nChannels; 1918 1919 /* Perform some input sanity checks */ 1920 if (pPcmBuf == NULL) { return (PCMDMX_INVALID_ARGUMENT); } 1921 if (frameSize == 0) { return (PCMDMX_INVALID_ARGUMENT); } 1922 if ( (numInChannels == 0) 1923 || (numInChannels > PCM_DMX_MAX_IN_CHANNELS) ) 1924 { return (PCMDMX_INVALID_ARGUMENT); } 1925 1926 /* Check on misconfiguration */ 1927 FDK_ASSERT( (pParam->numOutChannelsMax <= 0) \ 1928 || (pParam->numOutChannelsMax >= pParam->numOutChannelsMin)); 1929 1930 /* Determine if the module has to do processing */ 1931 if ( (self->applyProcessing == 0) 1932 && ((pParam->numOutChannelsMax <= 0) 1933 || (pParam->numOutChannelsMax >= numInChannels)) 1934 && (pParam->numOutChannelsMin <= numInChannels) ) { 1935 /* Nothing to do */ 1936 return (errorStatus); 1937 } 1938 1939 /* Determine the number of output channels */ 1940 if ( (pParam->numOutChannelsMax > 0) 1941 && (numInChannels > pParam->numOutChannelsMax) ) { 1942 numOutChannels = pParam->numOutChannelsMax; 1943 } 1944 else if (numInChannels < pParam->numOutChannelsMin) { 1945 numOutChannels = pParam->numOutChannelsMin; 1946 } 1947 else { 1948 numOutChannels = numInChannels; 1949 } 1950 1951 dualChannelMode = pParam->dualChannelMode; 1952 1953 /* Analyse input channel configuration and get channel offset 1954 * table that can be accessed with the fixed channel labels. */ 1955 errorStatus = getChannelMode( 1956 numInChannels, 1957 channelType, 1958 channelIndices, 1959 inOffsetTable, 1960 &inChMode 1961 ); 1962 if ( PCMDMX_IS_FATAL_ERROR(errorStatus) 1963 || (inChMode == CH_MODE_UNDEFINED) ) { 1964 /* We don't need to restore because the channel 1965 configuration has not been changed. Just exit. */ 1966 return (PCMDMX_INVALID_CH_CONFIG); 1967 } 1968 1969 /* Set input stride and offset */ 1970 if (fInterleaved) { 1971 inStride = numInChannels; 1972 offset = 1; /* Channel specific offset factor */ 1973 } else { 1974 inStride = 1; 1975 offset = frameSize; /* Channel specific offset factor */ 1976 } 1977 1978 /* Reset downmix meta data if necessary */ 1979 if ( (pParam->expiryFrame > 0) 1980 && (++self->bsMetaData[0].expiryCount > pParam->expiryFrame) ) 1981 { /* The metadata read from bitstream is too old. */ 1982 PCMDMX_ERROR err = pcmDmx_Reset(self, PCMDMX_RESET_BS_DATA); 1983 FDK_ASSERT(err == PCMDMX_OK); 1984 } 1985 FDKmemcpy(&bsMetaData, &self->bsMetaData[pParam->frameDelay], sizeof(DMX_BS_META_DATA)); 1986 /* Maintain delay line */ 1987 for (slot = pParam->frameDelay; slot > 0; slot -= 1) { 1988 FDKmemcpy(&self->bsMetaData[slot], &self->bsMetaData[slot-1], sizeof(DMX_BS_META_DATA)); 1989 } 1990 1991 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 1992 #ifdef PCM_DOWNMIX_ENABLE 1993 if ( numInChannels > numOutChannels ) 1994 { /* Apply downmix */ 1995 INT_PCM *pInPcm[PCM_DMX_MAX_IN_CHANNELS] = { NULL }; 1996 INT_PCM *pOutPcm[PCM_DMX_MAX_OUT_CHANNELS] = { NULL }; 1997 FIXP_DMX mixFactors[PCM_DMX_MAX_CHANNELS][PCM_DMX_MAX_CHANNELS]; 1998 UCHAR outOffsetTable[PCM_DMX_MAX_CHANNELS]; 1999 UINT sample; 2000 int chCfg = 0; 2001 int bypScale = 0; 2002 2003 #if (PCM_DMX_MAX_IN_CHANNELS >= 7) 2004 if (numInChannels > SIX_CHANNEL) { 2005 AUDIO_CHANNEL_TYPE multiPurposeChType[2]; 2006 2007 /* Get the type of the multipurpose channels */ 2008 multiPurposeChType[0] = channelType[inOffsetTable[LEFT_MULTIPRPS_CHANNEL]]; 2009 multiPurposeChType[1] = channelType[inOffsetTable[RIGHT_MULTIPRPS_CHANNEL]]; 2010 2011 /* Check if the input configuration is one defined in the standard. */ 2012 switch (inChMode) { 2013 case CH_MODE_5_0_2_1: /* chCfg 7 || 14 */ 2014 /* Further analyse the input config to distinguish the two CH_MODE_5_0_2_1 configs. */ 2015 if ( (multiPurposeChType[0] == ACT_FRONT_TOP) 2016 && (multiPurposeChType[1] == ACT_FRONT_TOP) ) { 2017 chCfg = 14; 2018 } else { 2019 chCfg = 7; 2020 } 2021 break; 2022 case CH_MODE_3_0_3_1: /* chCfg 11 */ 2023 chCfg = 11; 2024 break; 2025 case CH_MODE_3_0_4_1: /* chCfg 12 */ 2026 chCfg = 12; 2027 break; 2028 default: 2029 chCfg = 0; /* Not a known config */ 2030 break; 2031 } 2032 } 2033 #endif 2034 2035 /* Set this stages output stride and channel mode: */ 2036 outStride = (fInterleaved) ? numOutChannels : 1; 2037 outChMode = outChModeTable[numOutChannels]; 2038 2039 /* Get channel description and channel mapping for the desired output configuration. */ 2040 getChannelDescription( 2041 outChMode, 2042 channelMapping, 2043 channelType, 2044 channelIndices, 2045 outOffsetTable 2046 ); 2047 /* Now there is no way back because we modified the channel configuration! */ 2048 2049 /* Create the DMX matrix */ 2050 errorStatus = getMixFactors ( 2051 (chCfg>0) ? 1 : 0, 2052 (chCfg>0) ? (PCM_DMX_CHANNEL_MODE)chCfg : inChMode, 2053 outChMode, 2054 pParam, 2055 &bsMetaData, 2056 mixFactors, 2057 &dmxScale 2058 ); 2059 /* No fatal errors can occur here. The function is designed to always return a valid matrix. 2060 The error code is used to signal configurations and matrices that are not conform to any standard. */ 2061 2062 /* Determine the final scaling */ 2063 bypScale = FDKmin(dmxMaxScale, dmxScale); 2064 *pDmxOutScale += bypScale; 2065 dmxScale -= bypScale; 2066 2067 { /* Set channel pointer for input. Remove empty cols. */ 2068 int inCh, outCh, map[PCM_DMX_MAX_CHANNELS]; 2069 ch = 0; 2070 for (inCh=0; inCh < PCM_DMX_MAX_CHANNELS; inCh+=1) { 2071 if (inOffsetTable[inCh] != 255) { 2072 pInPcm[ch] = &pPcmBuf[inOffsetTable[inCh]*offset]; 2073 map[ch++] = inCh; 2074 } 2075 } 2076 FDK_ASSERT(ch == numInChannels); 2077 2078 /* Remove unused cols from factor matrix */ 2079 for (inCh=0; inCh < numInChannels; inCh+=1) { 2080 if (inCh != map[inCh]) { 2081 int outCh; 2082 for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) { 2083 mixFactors[outCh][inCh] = mixFactors[outCh][map[inCh]]; 2084 } 2085 } 2086 } 2087 2088 /* Set channel pointer for output. Remove empty cols. */ 2089 ch = 0; 2090 for (outCh=0; outCh < PCM_DMX_MAX_CHANNELS; outCh+=1) { 2091 if (outOffsetTable[outCh] != 255) { 2092 pOutPcm[ch] = &pPcmBuf[outOffsetTable[outCh]*offset]; 2093 map[ch++] = outCh; 2094 } 2095 } 2096 FDK_ASSERT(ch == numOutChannels); 2097 2098 /* Remove unused rows from factor matrix */ 2099 for (outCh=0; outCh < numOutChannels; outCh+=1) { 2100 if (outCh != map[outCh]) { 2101 FDKmemcpy(&mixFactors[outCh], &mixFactors[map[outCh]], PCM_DMX_MAX_CHANNELS*sizeof(FIXP_DMX)); 2102 } 2103 } 2104 } 2105 2106 /* Sample processing loop */ 2107 for (sample = 0; sample < frameSize; sample++) 2108 { 2109 FIXP_PCM tIn[PCM_DMX_MAX_IN_CHANNELS]; 2110 FIXP_DBL tOut[PCM_DMX_MAX_OUT_CHANNELS] = { (FIXP_DBL)0 }; 2111 int inCh, outCh; 2112 2113 /* Preload all input samples */ 2114 for (inCh=0; inCh < numInChannels; inCh+=1) { 2115 tIn[inCh] = (FIXP_PCM)*pInPcm[inCh]; 2116 pInPcm[inCh] += inStride; 2117 } 2118 /* Apply downmix coefficients to input samples and accumulate for output */ 2119 for (outCh=0; outCh < numOutChannels; outCh+=1) { 2120 for (inCh=0; inCh < numInChannels; inCh+=1) { 2121 tOut[outCh] += fMult(tIn[inCh], mixFactors[outCh][inCh]); 2122 } 2123 /* Write sample */ 2124 #if (SAMPLE_BITS == DFRACT_BITS) 2125 *pOutPcm[outCh] = (INT_PCM)SATURATE_LEFT_SHIFT(tOut[outCh], dmxScale, SAMPLE_BITS); 2126 #else 2127 *pOutPcm[outCh] = (INT_PCM)SATURATE_RIGHT_SHIFT(tOut[outCh], DFRACT_BITS-SAMPLE_BITS-dmxScale, SAMPLE_BITS); 2128 #endif 2129 pOutPcm[outCh] += outStride; 2130 } 2131 } 2132 2133 /* Update the number of output channels */ 2134 *nChannels = numOutChannels; 2135 2136 } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 2137 else 2138 #endif /* PCM_DOWNMIX_ENABLE */ 2139 #ifdef PCM_CHANNEL_EXTENSION_ENABLE 2140 if ( numInChannels < numOutChannels ) 2141 { /* Apply rudimentary upmix */ 2142 /* Set up channel pointer */ 2143 UINT sample; 2144 UCHAR outOffsetTable[PCM_DMX_MAX_CHANNELS]; 2145 2146 /* FIRST STAGE 2147 Create a stereo/dual channel signal */ 2148 if (numInChannels == ONE_CHANNEL) 2149 { 2150 INT_PCM *pInPcm[PCM_DMX_MAX_CHANNELS]; 2151 INT_PCM *pOutLF, *pOutRF; 2152 2153 /* Set this stages output stride and channel mode: */ 2154 outStride = (fInterleaved) ? TWO_CHANNEL : 1; 2155 outChMode = outChModeTable[TWO_CHANNEL]; 2156 2157 /* Get channel description and channel mapping for this 2158 * stages number of output channels (always STEREO). */ 2159 getChannelDescription( 2160 outChMode, 2161 channelMapping, 2162 channelType, 2163 channelIndices, 2164 outOffsetTable 2165 ); 2166 /* Now there is no way back because we modified the channel configuration! */ 2167 2168 /* Set input channel pointer. The first channel is always at index 0. */ 2169 pInPcm[CENTER_FRONT_CHANNEL] = &pPcmBuf[(frameSize-1)*inStride]; /* Considering input mapping could lead to a invalid pointer 2170 here if the channel is not declared to be a front channel. */ 2171 2172 /* Set output channel pointer (for this stage). */ 2173 pOutLF = &pPcmBuf[outOffsetTable[LEFT_FRONT_CHANNEL]*offset+(frameSize-1)*outStride]; 2174 pOutRF = &pPcmBuf[outOffsetTable[RIGHT_FRONT_CHANNEL]*offset+(frameSize-1)*outStride]; 2175 2176 /* 1/0 input: */ 2177 for (sample = 0; sample < frameSize; sample++) { 2178 /* L' = C; R' = C; */ 2179 *pOutLF = *pOutRF = *pInPcm[CENTER_FRONT_CHANNEL]; 2180 2181 pInPcm[CENTER_FRONT_CHANNEL] -= inStride; 2182 pOutLF -= outStride; pOutRF -= outStride; 2183 } 2184 2185 /* Prepare for next stage: */ 2186 inStride = outStride; 2187 inChMode = outChMode; 2188 FDKmemcpy(inOffsetTable, outOffsetTable, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR)); 2189 } 2190 2191 #if (PCM_DMX_MAX_OUT_CHANNELS > 2) 2192 /* SECOND STAGE 2193 Extend with zero channels to achieved the desired number of output channels. */ 2194 if (numOutChannels > TWO_CHANNEL) 2195 { 2196 INT_PCM *pIn[PCM_DMX_MAX_CHANNELS] = { NULL }; 2197 INT_PCM *pOut[PCM_DMX_MAX_CHANNELS] = { NULL }; 2198 AUDIO_CHANNEL_TYPE inChTypes[PCM_DMX_MAX_CHANNELS]; 2199 UCHAR inChIndices[PCM_DMX_MAX_CHANNELS]; 2200 UCHAR numChPerGrp[2][PCM_DMX_MAX_CHANNEL_GROUPS]; 2201 int nContentCh = 0; /* Number of channels with content */ 2202 int nEmptyCh = 0; /* Number of channels with content */ 2203 int ch, chGrp, isCompatible = 1; 2204 2205 /* Do not change the signalling which is the channel types and indices. 2206 Just reorder and add channels. So first save the input signalling. */ 2207 FDKmemcpy(inChTypes, channelType, PCM_DMX_MAX_CHANNELS*sizeof(AUDIO_CHANNEL_TYPE)); 2208 FDKmemcpy(inChIndices, channelIndices, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR)); 2209 2210 /* Set this stages output stride and channel mode: */ 2211 outStride = (fInterleaved) ? numOutChannels : 1; 2212 outChMode = outChModeTable[numOutChannels]; 2213 2214 /* Check if input channel config can be easily mapped to the desired output config. */ 2215 for (chGrp = 0; chGrp < PCM_DMX_MAX_CHANNEL_GROUPS; chGrp += 1) { 2216 numChPerGrp[IN][chGrp] = (inChMode >> (chGrp*4)) & 0xF; 2217 numChPerGrp[OUT][chGrp] = (outChMode >> (chGrp*4)) & 0xF; 2218 2219 if (numChPerGrp[IN][chGrp] > numChPerGrp[OUT][chGrp]) { 2220 isCompatible = 0; 2221 break; 2222 } 2223 } 2224 2225 if ( isCompatible ) { 2226 /* Get new channel description and channel 2227 * mapping for the desired output channel mode. */ 2228 getChannelDescription( 2229 outChMode, 2230 channelMapping, 2231 channelType, 2232 channelIndices, 2233 outOffsetTable 2234 ); 2235 /* If the input config has a back center channel but the output 2236 config has not, copy it to left and right (if available). */ 2237 if ( (numChPerGrp[IN][CH_GROUP_REAR]%2) 2238 && !(numChPerGrp[OUT][CH_GROUP_REAR]%2) ) { 2239 if (numChPerGrp[IN][CH_GROUP_REAR] == 1) { 2240 inOffsetTable[RIGHT_REAR_CHANNEL] = inOffsetTable[LEFT_REAR_CHANNEL]; 2241 } else if (numChPerGrp[IN][CH_GROUP_REAR] == 3) { 2242 inOffsetTable[RIGHT_MULTIPRPS_CHANNEL] = inOffsetTable[LEFT_MULTIPRPS_CHANNEL]; 2243 } 2244 } 2245 } 2246 else { 2247 /* Just copy and extend the original config */ 2248 FDKmemcpy(outOffsetTable, inOffsetTable, PCM_DMX_MAX_CHANNELS*sizeof(UCHAR)); 2249 } 2250 2251 /* Set I/O channel pointer. 2252 Note: The following assignment algorithm clears the channel offset tables. 2253 Thus they can not be used afterwards. */ 2254 for (ch = 0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) { 2255 if ( (outOffsetTable[ch] < 255) 2256 && (inOffsetTable[ch] < 255) ) 2257 { /* Set I/O pointer: */ 2258 pIn[nContentCh] = &pPcmBuf[inOffsetTable[ch]*offset+(frameSize-1)*inStride]; 2259 pOut[nContentCh] = &pPcmBuf[outOffsetTable[ch]*offset+(frameSize-1)*outStride]; 2260 /* Update signalling */ 2261 channelType[outOffsetTable[ch]] = inChTypes[inOffsetTable[ch]]; 2262 channelIndices[outOffsetTable[ch]] = inChIndices[inOffsetTable[ch]]; 2263 inOffsetTable[ch] = 255; 2264 outOffsetTable[ch] = 255; 2265 nContentCh += 1; 2266 } 2267 } 2268 if ( isCompatible ) { 2269 /* Assign the remaining input channels. 2270 This is just a safety appliance. We should never need it. */ 2271 for (ch = 0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) { 2272 if (inOffsetTable[ch] < 255) { 2273 int outCh; 2274 for (outCh = 0 ; outCh < PCM_DMX_MAX_CHANNELS; outCh += 1) { 2275 if (outOffsetTable[outCh] < 255) { 2276 break; 2277 } 2278 } 2279 /* Set I/O pointer: */ 2280 pIn[nContentCh] = &pPcmBuf[inOffsetTable[ch]*offset+(frameSize-1)*inStride]; 2281 pOut[nContentCh] = &pPcmBuf[outOffsetTable[outCh]*offset+(frameSize-1)*outStride]; 2282 /* Update signalling */ 2283 channelType[outOffsetTable[outCh]] = inChTypes[inOffsetTable[ch]]; 2284 channelIndices[outOffsetTable[outCh]] = inChIndices[inOffsetTable[ch]]; 2285 inOffsetTable[ch] = 255; 2286 outOffsetTable[outCh] = 255; 2287 nContentCh += 1; 2288 } 2289 } 2290 /* Set the remaining output channel pointer */ 2291 for (ch = 0; ch < PCM_DMX_MAX_CHANNELS; ch+=1) { 2292 if (outOffsetTable[ch] < 255) { 2293 pOut[nContentCh+nEmptyCh] = &pPcmBuf[outOffsetTable[ch]*offset+(frameSize-1)*outStride]; 2294 /* Expand output signalling */ 2295 channelType[outOffsetTable[ch]] = ACT_NONE; 2296 channelIndices[outOffsetTable[ch]] = nEmptyCh; 2297 outOffsetTable[ch] = 255; 2298 nEmptyCh += 1; 2299 } 2300 } 2301 } 2302 else { 2303 /* Set the remaining output channel pointer */ 2304 for (ch = nContentCh; ch < numOutChannels; ch+=1) { 2305 pOut[ch] = &pPcmBuf[ch*offset+(frameSize-1)*outStride]; 2306 /* Expand output signalling */ 2307 channelType[ch] = ACT_NONE; 2308 channelIndices[ch] = nEmptyCh; 2309 nEmptyCh += 1; 2310 } 2311 } 2312 2313 /* First copy the channels that have signal */ 2314 for (sample = 0; sample < frameSize; sample+=1) { 2315 INT_PCM tIn[PCM_DMX_MAX_CHANNELS]; 2316 /* Read all channel samples */ 2317 for (ch = 0; ch < nContentCh; ch+=1) { 2318 tIn[ch] = *pIn[ch]; 2319 pIn[ch] -= inStride; 2320 } 2321 /* Write all channel samples */ 2322 for (ch = 0; ch < nContentCh; ch+=1) { 2323 *pOut[ch] = tIn[ch]; 2324 pOut[ch] -= outStride; 2325 } 2326 } 2327 2328 /* Clear all the other channels */ 2329 for (sample = 0; sample < frameSize; sample++) { 2330 for (ch = nContentCh; ch < numOutChannels; ch+=1) { 2331 *pOut[ch] = (INT_PCM)0; 2332 pOut[ch] -= outStride; 2333 } 2334 } 2335 } 2336 #endif /* if (PCM_DMX_MAX_OUT_CHANNELS > 2) */ 2337 2338 /* update the number of output channels */ 2339 *nChannels = numOutChannels; 2340 } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 2341 else 2342 #endif /* PCM_CHANNEL_EXTENSION_ENABLE */ 2343 if ( numInChannels == numOutChannels ) 2344 { 2345 /* Don't need to change the channel description here */ 2346 2347 switch (numInChannels) 2348 { 2349 case 2: 2350 { /* Set up channel pointer */ 2351 INT_PCM *pInPcm[PCM_DMX_MAX_CHANNELS]; 2352 INT_PCM *pOutL, *pOutR; 2353 FIXP_DMX flev; 2354 2355 UINT sample; 2356 int inStride, outStride, offset; 2357 2358 if (fInterleaved) { 2359 inStride = numInChannels; 2360 outStride = 2; /* fixed !!! (below stereo is donwmixed to mono if required */ 2361 offset = 1; /* Channel specific offset factor */ 2362 } else { 2363 inStride = 1; 2364 outStride = 1; 2365 offset = frameSize; /* Channel specific offset factor */ 2366 } 2367 2368 /* Set input channel pointer */ 2369 pInPcm[LEFT_FRONT_CHANNEL] = &pPcmBuf[inOffsetTable[LEFT_FRONT_CHANNEL]*offset]; 2370 pInPcm[RIGHT_FRONT_CHANNEL] = &pPcmBuf[inOffsetTable[RIGHT_FRONT_CHANNEL]*offset]; 2371 2372 /* Set output channel pointer (same as input) */ 2373 pOutL = pInPcm[LEFT_FRONT_CHANNEL]; 2374 pOutR = pInPcm[RIGHT_FRONT_CHANNEL]; 2375 2376 /* Set downmix levels: */ 2377 flev = FL2FXCONST_DMX(0.70710678f); 2378 /* 2/0 input: */ 2379 switch (dualChannelMode) 2380 { 2381 case CH1_MODE: /* L' = 0.707 * Ch1; R' = 0.707 * Ch1 */ 2382 for (sample = 0; sample < frameSize; sample++) { 2383 *pOutL = *pOutR = 2384 (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInPcm[LEFT_FRONT_CHANNEL], flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS); 2385 2386 pInPcm[LEFT_FRONT_CHANNEL] += inStride; 2387 pOutL += outStride; pOutR += outStride; 2388 } 2389 break; 2390 case CH2_MODE: /* L' = 0.707 * Ch2; R' = 0.707 * Ch2 */ 2391 for (sample = 0; sample < frameSize; sample++) { 2392 *pOutL = *pOutR = 2393 (INT_PCM)SATURATE_RIGHT_SHIFT(fMult((FIXP_PCM)*pInPcm[RIGHT_FRONT_CHANNEL], flev), DFRACT_BITS-SAMPLE_BITS, SAMPLE_BITS); 2394 2395 pInPcm[RIGHT_FRONT_CHANNEL] += inStride; 2396 pOutL += outStride; pOutR += outStride; 2397 } 2398 break; 2399 case MIXED_MODE: /* L' = 0.5*Ch1 + 0.5*Ch2; R' = 0.5*Ch1 + 0.5*Ch2 */ 2400 for (sample = 0; sample < frameSize; sample++) { 2401 *pOutL = *pOutR = (*pInPcm[LEFT_FRONT_CHANNEL] >> 1) + (*pInPcm[RIGHT_FRONT_CHANNEL] >> 1); 2402 2403 pInPcm[LEFT_FRONT_CHANNEL] += inStride; pInPcm[RIGHT_FRONT_CHANNEL] += inStride; 2404 pOutL += outStride; pOutR += outStride; 2405 } 2406 break; 2407 default: 2408 case STEREO_MODE: 2409 /* nothing to do */ 2410 break; 2411 } 2412 } 2413 break; 2414 2415 default: 2416 /* nothing to do */ 2417 break; 2418 } 2419 } 2420 2421 return (errorStatus); 2422 } 2423 2424 2425 /** Close an instance of the PCM downmix module. 2426 * @param [inout] Pointer to a buffer containing the handle of the instance. 2427 * @returns Returns an error code. 2428 **/ 2429 PCMDMX_ERROR pcmDmx_Close ( 2430 HANDLE_PCM_DOWNMIX *pSelf 2431 ) 2432 { 2433 if (pSelf == NULL) { 2434 return (PCMDMX_INVALID_HANDLE); 2435 } 2436 2437 FreePcmDmxInstance( pSelf ); 2438 *pSelf = NULL; 2439 2440 return (PCMDMX_OK); 2441 } 2442 2443 2444 /** Get library info for this module. 2445 * @param [out] Pointer to an allocated LIB_INFO structure. 2446 * @returns Returns an error code. 2447 */ 2448 PCMDMX_ERROR pcmDmx_GetLibInfo( LIB_INFO *info ) 2449 { 2450 int i; 2451 2452 if (info == NULL) { 2453 return PCMDMX_INVALID_ARGUMENT; 2454 } 2455 2456 /* Search for next free tab */ 2457 for (i = 0; i < FDK_MODULE_LAST; i++) { 2458 if (info[i].module_id == FDK_NONE) break; 2459 } 2460 if (i == FDK_MODULE_LAST) { 2461 return PCMDMX_UNKNOWN; 2462 } 2463 2464 /* Add the library info */ 2465 info[i].module_id = FDK_PCMDMX; 2466 info[i].version = LIB_VERSION(PCMDMX_LIB_VL0, PCMDMX_LIB_VL1, PCMDMX_LIB_VL2); 2467 LIB_VERSION_STRING(info+i); 2468 info[i].build_date = PCMDMX_LIB_BUILD_DATE; 2469 info[i].build_time = PCMDMX_LIB_BUILD_TIME; 2470 info[i].title = PCMDMX_LIB_TITLE; 2471 2472 /* Set flags */ 2473 info[i].flags = 0 2474 #ifdef PCM_DOWNMIX_ENABLE 2475 | CAPF_DMX_BLIND /* At least blind downmixing is possible */ 2476 #ifdef PCE_METADATA_ENABLE 2477 | CAPF_DMX_PCE /* Guided downmix with data from MPEG-2/4 Program Config Elements (PCE). */ 2478 #ifdef ARIB_MIXDOWN_ENABLE 2479 | CAPF_DMX_ARIB /* PCE guided downmix with slightly different equations and levels. */ 2480 #endif 2481 #endif /* PCE_METADATA_ENABLE */ 2482 #ifdef DSE_METADATA_ENABLE 2483 | CAPF_DMX_DVB /* Guided downmix with data from DVB ancillary data fields. */ 2484 #endif 2485 #endif /* PCM_DOWNMIX_ENABLE */ 2486 #ifdef PCM_CHANNEL_EXTENSION_ENABLE 2487 | CAPF_DMX_CH_EXP /* Simple upmixing by dublicating channels or adding zero channels. */ 2488 #endif 2489 ; 2490 2491 /* Add lib info for FDK tools (if not yet done). */ 2492 FDK_toolsGetLibInfo(info); 2493 2494 return PCMDMX_OK; 2495 } 2496 2497 2498 2499