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 /******************* Library for basic calculation routines ******************** 96 97 Author(s): Markus Lohwasser 98 99 Description: FDK Tools Hybrid Filterbank 100 101 *******************************************************************************/ 102 103 #include "FDK_hybrid.h" 104 105 #include "fft.h" 106 107 /*--------------- defines -----------------------------*/ 108 #define FFT_IDX_R(a) (2 * a) 109 #define FFT_IDX_I(a) (2 * a + 1) 110 111 #define HYB_COEF8_0 (0.00746082949812f) 112 #define HYB_COEF8_1 (0.02270420949825f) 113 #define HYB_COEF8_2 (0.04546865930473f) 114 #define HYB_COEF8_3 (0.07266113929591f) 115 #define HYB_COEF8_4 (0.09885108575264f) 116 #define HYB_COEF8_5 (0.11793710567217f) 117 #define HYB_COEF8_6 (0.12500000000000f) 118 #define HYB_COEF8_7 (HYB_COEF8_5) 119 #define HYB_COEF8_8 (HYB_COEF8_4) 120 #define HYB_COEF8_9 (HYB_COEF8_3) 121 #define HYB_COEF8_10 (HYB_COEF8_2) 122 #define HYB_COEF8_11 (HYB_COEF8_1) 123 #define HYB_COEF8_12 (HYB_COEF8_0) 124 125 /*--------------- structure definitions ---------------*/ 126 127 #if defined(ARCH_PREFER_MULT_32x16) 128 #define FIXP_HTB FIXP_SGL /* SGL data type. */ 129 #define FIXP_HTP FIXP_SPK /* Packed SGL data type. */ 130 #define HTC(a) (FX_DBL2FXCONST_SGL(a)) /* Cast to SGL */ 131 #define FL2FXCONST_HTB FL2FXCONST_SGL 132 #else 133 #define FIXP_HTB FIXP_DBL /* SGL data type. */ 134 #define FIXP_HTP FIXP_DPK /* Packed DBL data type. */ 135 #define HTC(a) ((FIXP_DBL)(LONG)(a)) /* Cast to DBL */ 136 #define FL2FXCONST_HTB FL2FXCONST_DBL 137 #endif 138 139 #define HTCP(real, imag) \ 140 { \ 141 { HTC(real), HTC(imag) } \ 142 } /* How to arrange the packed values. */ 143 144 struct FDK_HYBRID_SETUP { 145 UCHAR nrQmfBands; /*!< Number of QMF bands to be converted to hybrid. */ 146 UCHAR nHybBands[3]; /*!< Number of Hybrid bands generated by nrQmfBands. */ 147 SCHAR kHybrid[3]; /*!< Filter configuration of each QMF band. */ 148 UCHAR protoLen; /*!< Prototype filter length. */ 149 UCHAR filterDelay; /*!< Delay caused by hybrid filter. */ 150 const INT 151 *pReadIdxTable; /*!< Helper table to access input data ringbuffer. */ 152 }; 153 154 /*--------------- constants ---------------------------*/ 155 static const INT ringbuffIdxTab[2 * 13] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 156 9, 10, 11, 12, 0, 1, 2, 3, 4, 157 5, 6, 7, 8, 9, 10, 11, 12}; 158 159 static const FDK_HYBRID_SETUP setup_3_16 = {3, {8, 4, 4}, {8, 4, 4}, 160 13, (13 - 1) / 2, ringbuffIdxTab}; 161 static const FDK_HYBRID_SETUP setup_3_12 = {3, {8, 2, 2}, {8, 2, 2}, 162 13, (13 - 1) / 2, ringbuffIdxTab}; 163 static const FDK_HYBRID_SETUP setup_3_10 = {3, {6, 2, 2}, {-8, -2, 2}, 164 13, (13 - 1) / 2, ringbuffIdxTab}; 165 166 static const FIXP_HTP HybFilterCoef8[] = { 167 HTCP(0x10000000, 0x00000000), HTCP(0x0df26407, 0xfa391882), 168 HTCP(0xff532109, 0x00acdef7), HTCP(0x08f26d36, 0xf70d92ca), 169 HTCP(0xfee34b5f, 0x02af570f), HTCP(0x038f276e, 0xf7684793), 170 HTCP(0x00000000, 0x05d1eac2), HTCP(0x00000000, 0x05d1eac2), 171 HTCP(0x038f276e, 0x0897b86d), HTCP(0xfee34b5f, 0xfd50a8f1), 172 HTCP(0x08f26d36, 0x08f26d36), HTCP(0xff532109, 0xff532109), 173 HTCP(0x0df26407, 0x05c6e77e)}; 174 175 static const FIXP_HTB HybFilterCoef2[3] = {FL2FXCONST_HTB(0.01899487526049f), 176 FL2FXCONST_HTB(-0.07293139167538f), 177 FL2FXCONST_HTB(0.30596630545168f)}; 178 179 static const FIXP_HTB HybFilterCoef4[13] = {FL2FXCONST_HTB(-0.00305151927305f), 180 FL2FXCONST_HTB(-0.00794862316203f), 181 FL2FXCONST_HTB(0.0f), 182 FL2FXCONST_HTB(0.04318924038756f), 183 FL2FXCONST_HTB(0.12542448210445f), 184 FL2FXCONST_HTB(0.21227807049160f), 185 FL2FXCONST_HTB(0.25f), 186 FL2FXCONST_HTB(0.21227807049160f), 187 FL2FXCONST_HTB(0.12542448210445f), 188 FL2FXCONST_HTB(0.04318924038756f), 189 FL2FXCONST_HTB(0.0f), 190 FL2FXCONST_HTB(-0.00794862316203f), 191 FL2FXCONST_HTB(-0.00305151927305f)}; 192 193 /*--------------- function declarations ---------------*/ 194 static INT kChannelFiltering(const FIXP_DBL *const pQmfReal, 195 const FIXP_DBL *const pQmfImag, 196 const INT *const pReadIdx, 197 FIXP_DBL *const mHybridReal, 198 FIXP_DBL *const mHybridImag, 199 const SCHAR hybridConfig); 200 201 /*--------------- function definitions ----------------*/ 202 203 INT FDKhybridAnalysisOpen(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, 204 FIXP_DBL *const pLFmemory, const UINT LFmemorySize, 205 FIXP_DBL *const pHFmemory, const UINT HFmemorySize) { 206 INT err = 0; 207 208 /* Save pointer to extern memory. */ 209 hAnalysisHybFilter->pLFmemory = pLFmemory; 210 hAnalysisHybFilter->LFmemorySize = LFmemorySize; 211 212 hAnalysisHybFilter->pHFmemory = pHFmemory; 213 hAnalysisHybFilter->HFmemorySize = HFmemorySize; 214 215 return err; 216 } 217 218 INT FDKhybridAnalysisInit(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, 219 const FDK_HYBRID_MODE mode, const INT qmfBands, 220 const INT cplxBands, const INT initStatesFlag) { 221 int k; 222 INT err = 0; 223 FIXP_DBL *pMem = NULL; 224 HANDLE_FDK_HYBRID_SETUP setup = NULL; 225 226 switch (mode) { 227 case THREE_TO_TEN: 228 setup = &setup_3_10; 229 break; 230 case THREE_TO_TWELVE: 231 setup = &setup_3_12; 232 break; 233 case THREE_TO_SIXTEEN: 234 setup = &setup_3_16; 235 break; 236 default: 237 err = -1; 238 goto bail; 239 } 240 241 /* Initialize handle. */ 242 hAnalysisHybFilter->pSetup = setup; 243 if (initStatesFlag) { 244 hAnalysisHybFilter->bufferLFpos = setup->protoLen - 1; 245 hAnalysisHybFilter->bufferHFpos = 0; 246 } 247 hAnalysisHybFilter->nrBands = qmfBands; 248 hAnalysisHybFilter->cplxBands = cplxBands; 249 hAnalysisHybFilter->hfMode = 0; 250 251 /* Check available memory. */ 252 if (((2 * setup->nrQmfBands * setup->protoLen * sizeof(FIXP_DBL)) > 253 hAnalysisHybFilter->LFmemorySize)) { 254 err = -2; 255 goto bail; 256 } 257 if (hAnalysisHybFilter->HFmemorySize != 0) { 258 if (((setup->filterDelay * 259 ((qmfBands - setup->nrQmfBands) + (cplxBands - setup->nrQmfBands)) * 260 sizeof(FIXP_DBL)) > hAnalysisHybFilter->HFmemorySize)) { 261 err = -3; 262 goto bail; 263 } 264 } 265 266 /* Distribute LF memory. */ 267 pMem = hAnalysisHybFilter->pLFmemory; 268 for (k = 0; k < setup->nrQmfBands; k++) { 269 hAnalysisHybFilter->bufferLFReal[k] = pMem; 270 pMem += setup->protoLen; 271 hAnalysisHybFilter->bufferLFImag[k] = pMem; 272 pMem += setup->protoLen; 273 } 274 275 /* Distribute HF memory. */ 276 if (hAnalysisHybFilter->HFmemorySize != 0) { 277 pMem = hAnalysisHybFilter->pHFmemory; 278 for (k = 0; k < setup->filterDelay; k++) { 279 hAnalysisHybFilter->bufferHFReal[k] = pMem; 280 pMem += (qmfBands - setup->nrQmfBands); 281 hAnalysisHybFilter->bufferHFImag[k] = pMem; 282 pMem += (cplxBands - setup->nrQmfBands); 283 } 284 } 285 286 if (initStatesFlag) { 287 /* Clear LF buffer */ 288 for (k = 0; k < setup->nrQmfBands; k++) { 289 FDKmemclear(hAnalysisHybFilter->bufferLFReal[k], 290 setup->protoLen * sizeof(FIXP_DBL)); 291 FDKmemclear(hAnalysisHybFilter->bufferLFImag[k], 292 setup->protoLen * sizeof(FIXP_DBL)); 293 } 294 295 if (hAnalysisHybFilter->HFmemorySize != 0) { 296 if (qmfBands > setup->nrQmfBands) { 297 /* Clear HF buffer */ 298 for (k = 0; k < setup->filterDelay; k++) { 299 FDKmemclear(hAnalysisHybFilter->bufferHFReal[k], 300 (qmfBands - setup->nrQmfBands) * sizeof(FIXP_DBL)); 301 FDKmemclear(hAnalysisHybFilter->bufferHFImag[k], 302 (cplxBands - setup->nrQmfBands) * sizeof(FIXP_DBL)); 303 } 304 } 305 } 306 } 307 308 bail: 309 return err; 310 } 311 312 INT FDKhybridAnalysisScaleStates(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, 313 const INT scalingValue) { 314 INT err = 0; 315 316 if (hAnalysisHybFilter == NULL) { 317 err = 1; /* invalid handle */ 318 } else { 319 int k; 320 HANDLE_FDK_HYBRID_SETUP setup = hAnalysisHybFilter->pSetup; 321 322 /* Scale LF buffer */ 323 for (k = 0; k < setup->nrQmfBands; k++) { 324 scaleValues(hAnalysisHybFilter->bufferLFReal[k], setup->protoLen, 325 scalingValue); 326 scaleValues(hAnalysisHybFilter->bufferLFImag[k], setup->protoLen, 327 scalingValue); 328 } 329 if (hAnalysisHybFilter->nrBands > setup->nrQmfBands) { 330 /* Scale HF buffer */ 331 for (k = 0; k < setup->filterDelay; k++) { 332 scaleValues(hAnalysisHybFilter->bufferHFReal[k], 333 (hAnalysisHybFilter->nrBands - setup->nrQmfBands), 334 scalingValue); 335 scaleValues(hAnalysisHybFilter->bufferHFImag[k], 336 (hAnalysisHybFilter->cplxBands - setup->nrQmfBands), 337 scalingValue); 338 } 339 } 340 } 341 return err; 342 } 343 344 INT FDKhybridAnalysisApply(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, 345 const FIXP_DBL *const pQmfReal, 346 const FIXP_DBL *const pQmfImag, 347 FIXP_DBL *const pHybridReal, 348 FIXP_DBL *const pHybridImag) { 349 int k, hybOffset = 0; 350 INT err = 0; 351 const int nrQmfBandsLF = 352 hAnalysisHybFilter->pSetup 353 ->nrQmfBands; /* number of QMF bands to be converted to hybrid */ 354 355 const int writIndex = hAnalysisHybFilter->bufferLFpos; 356 int readIndex = hAnalysisHybFilter->bufferLFpos; 357 358 if (++readIndex >= hAnalysisHybFilter->pSetup->protoLen) readIndex = 0; 359 const INT *pBufferLFreadIdx = 360 &hAnalysisHybFilter->pSetup->pReadIdxTable[readIndex]; 361 362 /* 363 * LF buffer. 364 */ 365 for (k = 0; k < nrQmfBandsLF; k++) { 366 /* New input sample. */ 367 hAnalysisHybFilter->bufferLFReal[k][writIndex] = pQmfReal[k]; 368 hAnalysisHybFilter->bufferLFImag[k][writIndex] = pQmfImag[k]; 369 370 /* Perform hybrid filtering. */ 371 err |= 372 kChannelFiltering(hAnalysisHybFilter->bufferLFReal[k], 373 hAnalysisHybFilter->bufferLFImag[k], pBufferLFreadIdx, 374 pHybridReal + hybOffset, pHybridImag + hybOffset, 375 hAnalysisHybFilter->pSetup->kHybrid[k]); 376 377 hybOffset += hAnalysisHybFilter->pSetup->nHybBands[k]; 378 } 379 380 hAnalysisHybFilter->bufferLFpos = 381 readIndex; /* Index where to write next input sample. */ 382 383 if (hAnalysisHybFilter->nrBands > nrQmfBandsLF) { 384 /* 385 * HF buffer. 386 */ 387 if (hAnalysisHybFilter->hfMode != 0) { 388 /* HF delay compensation was applied outside. */ 389 FDKmemcpy( 390 pHybridReal + hybOffset, &pQmfReal[nrQmfBandsLF], 391 (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); 392 FDKmemcpy( 393 pHybridImag + hybOffset, &pQmfImag[nrQmfBandsLF], 394 (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); 395 } else { 396 FDK_ASSERT(hAnalysisHybFilter->HFmemorySize != 0); 397 /* HF delay compensation, filterlength/2. */ 398 FDKmemcpy( 399 pHybridReal + hybOffset, 400 hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos], 401 (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); 402 FDKmemcpy( 403 pHybridImag + hybOffset, 404 hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos], 405 (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); 406 407 FDKmemcpy( 408 hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos], 409 &pQmfReal[nrQmfBandsLF], 410 (hAnalysisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); 411 FDKmemcpy( 412 hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos], 413 &pQmfImag[nrQmfBandsLF], 414 (hAnalysisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); 415 416 if (++hAnalysisHybFilter->bufferHFpos >= 417 hAnalysisHybFilter->pSetup->filterDelay) 418 hAnalysisHybFilter->bufferHFpos = 0; 419 } 420 } /* process HF part*/ 421 422 return err; 423 } 424 425 INT FDKhybridAnalysisClose(HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter) { 426 INT err = 0; 427 428 if (hAnalysisHybFilter != NULL) { 429 hAnalysisHybFilter->pLFmemory = NULL; 430 hAnalysisHybFilter->pHFmemory = NULL; 431 hAnalysisHybFilter->LFmemorySize = 0; 432 hAnalysisHybFilter->HFmemorySize = 0; 433 } 434 435 return err; 436 } 437 438 INT FDKhybridSynthesisInit(HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter, 439 const FDK_HYBRID_MODE mode, const INT qmfBands, 440 const INT cplxBands) { 441 INT err = 0; 442 HANDLE_FDK_HYBRID_SETUP setup = NULL; 443 444 switch (mode) { 445 case THREE_TO_TEN: 446 setup = &setup_3_10; 447 break; 448 case THREE_TO_TWELVE: 449 setup = &setup_3_12; 450 break; 451 case THREE_TO_SIXTEEN: 452 setup = &setup_3_16; 453 break; 454 default: 455 err = -1; 456 goto bail; 457 } 458 459 hSynthesisHybFilter->pSetup = setup; 460 hSynthesisHybFilter->nrBands = qmfBands; 461 hSynthesisHybFilter->cplxBands = cplxBands; 462 463 bail: 464 return err; 465 } 466 467 void FDKhybridSynthesisApply(HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter, 468 const FIXP_DBL *const pHybridReal, 469 const FIXP_DBL *const pHybridImag, 470 FIXP_DBL *const pQmfReal, 471 FIXP_DBL *const pQmfImag) { 472 int k, n, hybOffset = 0; 473 const INT nrQmfBandsLF = hSynthesisHybFilter->pSetup->nrQmfBands; 474 475 /* 476 * LF buffer. 477 */ 478 for (k = 0; k < nrQmfBandsLF; k++) { 479 const int nHybBands = hSynthesisHybFilter->pSetup->nHybBands[k]; 480 481 FIXP_DBL accu1 = FL2FXCONST_DBL(0.f); 482 FIXP_DBL accu2 = FL2FXCONST_DBL(0.f); 483 484 /* Perform hybrid filtering. */ 485 for (n = 0; n < nHybBands; n++) { 486 accu1 += pHybridReal[hybOffset + n]; 487 accu2 += pHybridImag[hybOffset + n]; 488 } 489 pQmfReal[k] = accu1; 490 pQmfImag[k] = accu2; 491 492 hybOffset += nHybBands; 493 } 494 495 if (hSynthesisHybFilter->nrBands > nrQmfBandsLF) { 496 /* 497 * HF buffer. 498 */ 499 FDKmemcpy(&pQmfReal[nrQmfBandsLF], &pHybridReal[hybOffset], 500 (hSynthesisHybFilter->nrBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); 501 FDKmemcpy( 502 &pQmfImag[nrQmfBandsLF], &pHybridImag[hybOffset], 503 (hSynthesisHybFilter->cplxBands - nrQmfBandsLF) * sizeof(FIXP_DBL)); 504 } 505 506 return; 507 } 508 509 static void dualChannelFiltering(const FIXP_DBL *const pQmfReal, 510 const FIXP_DBL *const pQmfImag, 511 const INT *const pReadIdx, 512 FIXP_DBL *const mHybridReal, 513 FIXP_DBL *const mHybridImag, 514 const INT invert) { 515 FIXP_DBL r1, r6; 516 FIXP_DBL i1, i6; 517 518 const FIXP_HTB f0 = HybFilterCoef2[0]; /* corresponds to p1 and p11 */ 519 const FIXP_HTB f1 = HybFilterCoef2[1]; /* corresponds to p3 and p9 */ 520 const FIXP_HTB f2 = HybFilterCoef2[2]; /* corresponds to p5 and p7 */ 521 522 /* symmetric filter coefficients */ 523 r1 = fMultDiv2(f0, pQmfReal[pReadIdx[1]]) + 524 fMultDiv2(f0, pQmfReal[pReadIdx[11]]); 525 i1 = fMultDiv2(f0, pQmfImag[pReadIdx[1]]) + 526 fMultDiv2(f0, pQmfImag[pReadIdx[11]]); 527 r1 += fMultDiv2(f1, pQmfReal[pReadIdx[3]]) + 528 fMultDiv2(f1, pQmfReal[pReadIdx[9]]); 529 i1 += fMultDiv2(f1, pQmfImag[pReadIdx[3]]) + 530 fMultDiv2(f1, pQmfImag[pReadIdx[9]]); 531 r1 += fMultDiv2(f2, pQmfReal[pReadIdx[5]]) + 532 fMultDiv2(f2, pQmfReal[pReadIdx[7]]); 533 i1 += fMultDiv2(f2, pQmfImag[pReadIdx[5]]) + 534 fMultDiv2(f2, pQmfImag[pReadIdx[7]]); 535 536 r6 = pQmfReal[pReadIdx[6]] >> 2; 537 i6 = pQmfImag[pReadIdx[6]] >> 2; 538 539 FDK_ASSERT((invert == 0) || (invert == 1)); 540 mHybridReal[0 + invert] = (r6 + r1) << 1; 541 mHybridImag[0 + invert] = (i6 + i1) << 1; 542 543 mHybridReal[1 - invert] = (r6 - r1) << 1; 544 mHybridImag[1 - invert] = (i6 - i1) << 1; 545 } 546 547 static void fourChannelFiltering(const FIXP_DBL *const pQmfReal, 548 const FIXP_DBL *const pQmfImag, 549 const INT *const pReadIdx, 550 FIXP_DBL *const mHybridReal, 551 FIXP_DBL *const mHybridImag, 552 const INT invert) { 553 const FIXP_HTB *p = HybFilterCoef4; 554 555 FIXP_DBL fft[8]; 556 557 static const FIXP_DBL cr[13] = { 558 FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(-0.70710678118655f), 559 FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f), 560 FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(0.70710678118655f), 561 FL2FXCONST_DBL(1.f), FL2FXCONST_DBL(0.70710678118655f), 562 FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(-0.70710678118655f), 563 FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f), 564 FL2FXCONST_DBL(0.f)}; 565 static const FIXP_DBL ci[13] = { 566 FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f), 567 FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(0.70710678118655f), 568 FL2FXCONST_DBL(1.f), FL2FXCONST_DBL(0.70710678118655f), 569 FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(-0.70710678118655f), 570 FL2FXCONST_DBL(-1.f), FL2FXCONST_DBL(-0.70710678118655f), 571 FL2FXCONST_DBL(0.f), FL2FXCONST_DBL(0.70710678118655f), 572 FL2FXCONST_DBL(1.f)}; 573 574 /* FIR filter. */ 575 /* pre twiddeling with pre-twiddling coefficients c[n] */ 576 /* multiplication with filter coefficients p[n] */ 577 /* hint: (a + ib)*(c + id) = (a*c - b*d) + i(a*d + b*c) */ 578 /* write to fft coefficient n' */ 579 fft[FFT_IDX_R(0)] = 580 (fMult(p[10], (fMultSub(fMultDiv2(cr[2], pQmfReal[pReadIdx[2]]), ci[2], 581 pQmfImag[pReadIdx[2]]))) + 582 fMult(p[6], (fMultSub(fMultDiv2(cr[6], pQmfReal[pReadIdx[6]]), ci[6], 583 pQmfImag[pReadIdx[6]]))) + 584 fMult(p[2], (fMultSub(fMultDiv2(cr[10], pQmfReal[pReadIdx[10]]), ci[10], 585 pQmfImag[pReadIdx[10]])))); 586 fft[FFT_IDX_I(0)] = 587 (fMult(p[10], (fMultAdd(fMultDiv2(ci[2], pQmfReal[pReadIdx[2]]), cr[2], 588 pQmfImag[pReadIdx[2]]))) + 589 fMult(p[6], (fMultAdd(fMultDiv2(ci[6], pQmfReal[pReadIdx[6]]), cr[6], 590 pQmfImag[pReadIdx[6]]))) + 591 fMult(p[2], (fMultAdd(fMultDiv2(ci[10], pQmfReal[pReadIdx[10]]), cr[10], 592 pQmfImag[pReadIdx[10]])))); 593 594 /* twiddle dee dum */ 595 fft[FFT_IDX_R(1)] = 596 (fMult(p[9], (fMultSub(fMultDiv2(cr[3], pQmfReal[pReadIdx[3]]), ci[3], 597 pQmfImag[pReadIdx[3]]))) + 598 fMult(p[5], (fMultSub(fMultDiv2(cr[7], pQmfReal[pReadIdx[7]]), ci[7], 599 pQmfImag[pReadIdx[7]]))) + 600 fMult(p[1], (fMultSub(fMultDiv2(cr[11], pQmfReal[pReadIdx[11]]), ci[11], 601 pQmfImag[pReadIdx[11]])))); 602 fft[FFT_IDX_I(1)] = 603 (fMult(p[9], (fMultAdd(fMultDiv2(ci[3], pQmfReal[pReadIdx[3]]), cr[3], 604 pQmfImag[pReadIdx[3]]))) + 605 fMult(p[5], (fMultAdd(fMultDiv2(ci[7], pQmfReal[pReadIdx[7]]), cr[7], 606 pQmfImag[pReadIdx[7]]))) + 607 fMult(p[1], (fMultAdd(fMultDiv2(ci[11], pQmfReal[pReadIdx[11]]), cr[11], 608 pQmfImag[pReadIdx[11]])))); 609 610 /* twiddle dee dee */ 611 fft[FFT_IDX_R(2)] = 612 (fMult(p[12], (fMultSub(fMultDiv2(cr[0], pQmfReal[pReadIdx[0]]), ci[0], 613 pQmfImag[pReadIdx[0]]))) + 614 fMult(p[8], (fMultSub(fMultDiv2(cr[4], pQmfReal[pReadIdx[4]]), ci[4], 615 pQmfImag[pReadIdx[4]]))) + 616 fMult(p[4], (fMultSub(fMultDiv2(cr[8], pQmfReal[pReadIdx[8]]), ci[8], 617 pQmfImag[pReadIdx[8]]))) + 618 fMult(p[0], (fMultSub(fMultDiv2(cr[12], pQmfReal[pReadIdx[12]]), ci[12], 619 pQmfImag[pReadIdx[12]])))); 620 fft[FFT_IDX_I(2)] = 621 (fMult(p[12], (fMultAdd(fMultDiv2(ci[0], pQmfReal[pReadIdx[0]]), cr[0], 622 pQmfImag[pReadIdx[0]]))) + 623 fMult(p[8], (fMultAdd(fMultDiv2(ci[4], pQmfReal[pReadIdx[4]]), cr[4], 624 pQmfImag[pReadIdx[4]]))) + 625 fMult(p[4], (fMultAdd(fMultDiv2(ci[8], pQmfReal[pReadIdx[8]]), cr[8], 626 pQmfImag[pReadIdx[8]]))) + 627 fMult(p[0], (fMultAdd(fMultDiv2(ci[12], pQmfReal[pReadIdx[12]]), cr[12], 628 pQmfImag[pReadIdx[12]])))); 629 630 fft[FFT_IDX_R(3)] = 631 (fMult(p[11], (fMultSub(fMultDiv2(cr[1], pQmfReal[pReadIdx[1]]), ci[1], 632 pQmfImag[pReadIdx[1]]))) + 633 fMult(p[7], (fMultSub(fMultDiv2(cr[5], pQmfReal[pReadIdx[5]]), ci[5], 634 pQmfImag[pReadIdx[5]]))) + 635 fMult(p[3], (fMultSub(fMultDiv2(cr[9], pQmfReal[pReadIdx[9]]), ci[9], 636 pQmfImag[pReadIdx[9]])))); 637 fft[FFT_IDX_I(3)] = 638 (fMult(p[11], (fMultAdd(fMultDiv2(ci[1], pQmfReal[pReadIdx[1]]), cr[1], 639 pQmfImag[pReadIdx[1]]))) + 640 fMult(p[7], (fMultAdd(fMultDiv2(ci[5], pQmfReal[pReadIdx[5]]), cr[5], 641 pQmfImag[pReadIdx[5]]))) + 642 fMult(p[3], (fMultAdd(fMultDiv2(ci[9], pQmfReal[pReadIdx[9]]), cr[9], 643 pQmfImag[pReadIdx[9]])))); 644 645 /* fft modulation */ 646 /* here: fast manual fft modulation for a fft of length M=4 */ 647 /* fft_4{x[n]} = x[0]*exp(-i*2*pi/4*m*0) + x[1]*exp(-i*2*pi/4*m*1) + 648 x[2]*exp(-i*2*pi/4*m*2) + x[3]*exp(-i*2*pi/4*m*3) */ 649 650 /* 651 fft bin m=0: 652 X[0, n] = x[0] + x[1] + x[2] + x[3] 653 */ 654 mHybridReal[0] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] + 655 fft[FFT_IDX_R(3)]; 656 mHybridImag[0] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] + 657 fft[FFT_IDX_I(3)]; 658 659 /* 660 fft bin m=1: 661 X[1, n] = x[0] - i*x[1] - x[2] + i*x[3] 662 */ 663 mHybridReal[1] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] - 664 fft[FFT_IDX_I(3)]; 665 mHybridImag[1] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] + 666 fft[FFT_IDX_R(3)]; 667 668 /* 669 fft bin m=2: 670 X[2, n] = x[0] - x[1] + x[2] - x[3] 671 */ 672 mHybridReal[2] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] - 673 fft[FFT_IDX_R(3)]; 674 mHybridImag[2] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] - 675 fft[FFT_IDX_I(3)]; 676 677 /* 678 fft bin m=3: 679 X[3, n] = x[0] + j*x[1] - x[2] - j*x[3] 680 */ 681 mHybridReal[3] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] + 682 fft[FFT_IDX_I(3)]; 683 mHybridImag[3] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] - 684 fft[FFT_IDX_R(3)]; 685 } 686 687 static void eightChannelFiltering(const FIXP_DBL *const pQmfReal, 688 const FIXP_DBL *const pQmfImag, 689 const INT *const pReadIdx, 690 FIXP_DBL *const mHybridReal, 691 FIXP_DBL *const mHybridImag, 692 const INT invert) { 693 const FIXP_HTP *p = HybFilterCoef8; 694 INT k, sc; 695 696 FIXP_DBL mfft[16 + ALIGNMENT_DEFAULT]; 697 FIXP_DBL *pfft = (FIXP_DBL *)ALIGN_PTR(mfft); 698 699 FIXP_DBL accu1, accu2, accu3, accu4; 700 701 /* pre twiddeling */ 702 pfft[FFT_IDX_R(0)] = 703 pQmfReal[pReadIdx[6]] >> 704 (3 + 1); /* fMultDiv2(p[0].v.re, pQmfReal[pReadIdx[6]]); */ 705 pfft[FFT_IDX_I(0)] = 706 pQmfImag[pReadIdx[6]] >> 707 (3 + 1); /* fMultDiv2(p[0].v.re, pQmfImag[pReadIdx[6]]); */ 708 709 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[7]], pQmfImag[pReadIdx[7]], 710 p[1]); 711 pfft[FFT_IDX_R(1)] = accu1; 712 pfft[FFT_IDX_I(1)] = accu2; 713 714 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[0]], pQmfImag[pReadIdx[0]], 715 p[2]); 716 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[8]], pQmfImag[pReadIdx[8]], 717 p[3]); 718 pfft[FFT_IDX_R(2)] = accu1 + accu3; 719 pfft[FFT_IDX_I(2)] = accu2 + accu4; 720 721 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[1]], pQmfImag[pReadIdx[1]], 722 p[4]); 723 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[9]], pQmfImag[pReadIdx[9]], 724 p[5]); 725 pfft[FFT_IDX_R(3)] = accu1 + accu3; 726 pfft[FFT_IDX_I(3)] = accu2 + accu4; 727 728 pfft[FFT_IDX_R(4)] = fMultDiv2(pQmfImag[pReadIdx[10]], p[7].v.im) - 729 fMultDiv2(pQmfImag[pReadIdx[2]], p[6].v.im); 730 pfft[FFT_IDX_I(4)] = fMultDiv2(pQmfReal[pReadIdx[2]], p[6].v.im) - 731 fMultDiv2(pQmfReal[pReadIdx[10]], p[7].v.im); 732 733 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[3]], pQmfImag[pReadIdx[3]], 734 p[8]); 735 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[11]], pQmfImag[pReadIdx[11]], 736 p[9]); 737 pfft[FFT_IDX_R(5)] = accu1 + accu3; 738 pfft[FFT_IDX_I(5)] = accu2 + accu4; 739 740 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[4]], pQmfImag[pReadIdx[4]], 741 p[10]); 742 cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[12]], pQmfImag[pReadIdx[12]], 743 p[11]); 744 pfft[FFT_IDX_R(6)] = accu1 + accu3; 745 pfft[FFT_IDX_I(6)] = accu2 + accu4; 746 747 cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[5]], pQmfImag[pReadIdx[5]], 748 p[12]); 749 pfft[FFT_IDX_R(7)] = accu1; 750 pfft[FFT_IDX_I(7)] = accu2; 751 752 /* fft modulation */ 753 fft_8(pfft); 754 sc = 1 + 2; 755 756 if (invert) { 757 mHybridReal[0] = pfft[FFT_IDX_R(7)] << sc; 758 mHybridImag[0] = pfft[FFT_IDX_I(7)] << sc; 759 mHybridReal[1] = pfft[FFT_IDX_R(0)] << sc; 760 mHybridImag[1] = pfft[FFT_IDX_I(0)] << sc; 761 762 mHybridReal[2] = pfft[FFT_IDX_R(6)] << sc; 763 mHybridImag[2] = pfft[FFT_IDX_I(6)] << sc; 764 mHybridReal[3] = pfft[FFT_IDX_R(1)] << sc; 765 mHybridImag[3] = pfft[FFT_IDX_I(1)] << sc; 766 767 mHybridReal[4] = pfft[FFT_IDX_R(2)] << sc; 768 mHybridReal[4] += pfft[FFT_IDX_R(5)] << sc; 769 mHybridImag[4] = pfft[FFT_IDX_I(2)] << sc; 770 mHybridImag[4] += pfft[FFT_IDX_I(5)] << sc; 771 772 mHybridReal[5] = pfft[FFT_IDX_R(3)] << sc; 773 mHybridReal[5] += pfft[FFT_IDX_R(4)] << sc; 774 mHybridImag[5] = pfft[FFT_IDX_I(3)] << sc; 775 mHybridImag[5] += pfft[FFT_IDX_I(4)] << sc; 776 } else { 777 for (k = 0; k < 8; k++) { 778 mHybridReal[k] = pfft[FFT_IDX_R(k)] << sc; 779 mHybridImag[k] = pfft[FFT_IDX_I(k)] << sc; 780 } 781 } 782 } 783 784 static INT kChannelFiltering(const FIXP_DBL *const pQmfReal, 785 const FIXP_DBL *const pQmfImag, 786 const INT *const pReadIdx, 787 FIXP_DBL *const mHybridReal, 788 FIXP_DBL *const mHybridImag, 789 const SCHAR hybridConfig) { 790 INT err = 0; 791 792 switch (hybridConfig) { 793 case 2: 794 case -2: 795 dualChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, 796 mHybridImag, (hybridConfig < 0) ? 1 : 0); 797 break; 798 case 4: 799 case -4: 800 fourChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, 801 mHybridImag, (hybridConfig < 0) ? 1 : 0); 802 break; 803 case 8: 804 case -8: 805 eightChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, 806 mHybridImag, (hybridConfig < 0) ? 1 : 0); 807 break; 808 default: 809 err = -1; 810 } 811 812 return err; 813 } 814