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