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