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