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): Matthias Hildenbrand 98 99 Description: Module to efficiently handle QMF data for multiple channels and 100 to share the data between e.g. SBR and MPS 101 102 *******************************************************************************/ 103 104 #include "FDK_qmf_domain.h" 105 106 #include "common_fix.h" 107 108 #define WORKBUFFER1_TAG 0 109 #define WORKBUFFER2_TAG 1 110 111 #define WORKBUFFER3_TAG 4 112 #define WORKBUFFER4_TAG 5 113 #define WORKBUFFER5_TAG 6 114 #define WORKBUFFER6_TAG 7 115 116 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore1, FIXP_DBL, QMF_WB_SECTION_SIZE, 117 SECT_DATA_L1, WORKBUFFER1_TAG) 118 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore2, FIXP_DBL, QMF_WB_SECTION_SIZE, 119 SECT_DATA_L2, WORKBUFFER2_TAG) 120 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore3, FIXP_DBL, QMF_WB_SECTION_SIZE, 121 SECT_DATA_L2, WORKBUFFER3_TAG) 122 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore4, FIXP_DBL, QMF_WB_SECTION_SIZE, 123 SECT_DATA_L2, WORKBUFFER4_TAG) 124 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore5, FIXP_DBL, QMF_WB_SECTION_SIZE, 125 SECT_DATA_L2, WORKBUFFER5_TAG) 126 C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore6, FIXP_DBL, QMF_WB_SECTION_SIZE, 127 SECT_DATA_L2, WORKBUFFER6_TAG) 128 129 /*! Analysis states buffer. <br> 130 Dimension: #((8) + (1)) */ 131 C_ALLOC_MEM2(AnaQmfStates, FIXP_QAS, 10 * QMF_DOMAIN_MAX_ANALYSIS_QMF_BANDS, 132 ((8) + (1))) 133 134 /*! Synthesis states buffer. <br> 135 Dimension: #((8) + (1)) */ 136 C_ALLOC_MEM2(SynQmfStates, FIXP_QSS, 9 * QMF_DOMAIN_MAX_SYNTHESIS_QMF_BANDS, 137 ((8) + (1))) 138 139 /*! Pointer to real qmf data for each time slot. <br> 140 Dimension: #((8) + (1)) */ 141 C_ALLOC_MEM2(QmfSlotsReal, FIXP_DBL *, 142 QMF_DOMAIN_MAX_TIMESLOTS + QMF_DOMAIN_MAX_OV_TIMESLOTS, 143 ((8) + (1))) 144 145 /*! Pointer to imaginary qmf data for each time slot. <br> 146 Dimension: #((8) + (1)) */ 147 C_ALLOC_MEM2(QmfSlotsImag, FIXP_DBL *, 148 QMF_DOMAIN_MAX_TIMESLOTS + QMF_DOMAIN_MAX_OV_TIMESLOTS, 149 ((8) + (1))) 150 151 /*! QMF overlap buffer. <br> 152 Dimension: #((8) + (1)) */ 153 C_AALLOC_MEM2(QmfOverlapBuffer, FIXP_DBL, 154 2 * QMF_DOMAIN_MAX_OV_TIMESLOTS * QMF_DOMAIN_MAX_QMF_PROC_BANDS, 155 ((8) + (1))) 156 157 /*! Analysis states buffer. <br> 158 Dimension: #((8) + (1)) */ 159 C_ALLOC_MEM2(AnaQmfStates16, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_16, 160 ((8) + (1))) 161 162 /*! Analysis states buffer. <br> 163 Dimension: #((8) + (1)) */ 164 C_ALLOC_MEM2(AnaQmfStates24, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_24, 165 ((8) + (1))) 166 167 /*! Analysis states buffer. <br> 168 Dimension: #((8) + (1)) */ 169 C_ALLOC_MEM2(AnaQmfStates32, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_32, 170 ((8) + (1))) 171 172 /*! Pointer to real qmf data for each time slot. <br> 173 Dimension: #((8) + (1)) */ 174 C_ALLOC_MEM2(QmfSlotsReal16, FIXP_DBL *, 175 QMF_DOMAIN_TIMESLOTS_16 + QMF_DOMAIN_OV_TIMESLOTS_16, ((8) + (1))) 176 177 /*! Pointer to real qmf data for each time slot. <br> 178 Dimension: #((8) + (1)) */ 179 C_ALLOC_MEM2(QmfSlotsReal32, FIXP_DBL *, 180 QMF_DOMAIN_TIMESLOTS_32 + QMF_DOMAIN_OV_TIMESLOTS_32, ((8) + (1))) 181 182 /*! Pointer to imaginary qmf data for each time slot. <br> 183 Dimension: #((8) + (1)) */ 184 C_ALLOC_MEM2(QmfSlotsImag16, FIXP_DBL *, 185 QMF_DOMAIN_TIMESLOTS_16 + QMF_DOMAIN_OV_TIMESLOTS_16, ((8) + (1))) 186 187 /*! Pointer to imaginary qmf data for each time slot. <br> 188 Dimension: #((8) + (1)) */ 189 C_ALLOC_MEM2(QmfSlotsImag32, FIXP_DBL *, 190 QMF_DOMAIN_TIMESLOTS_32 + QMF_DOMAIN_OV_TIMESLOTS_32, ((8) + (1))) 191 192 /*! QMF overlap buffer. <br> 193 Dimension: #((8) + (1)) */ 194 C_AALLOC_MEM2(QmfOverlapBuffer16, FIXP_DBL, 195 2 * QMF_DOMAIN_OV_TIMESLOTS_16 * QMF_DOMAIN_MAX_QMF_PROC_BANDS, 196 ((8) + (1))) 197 198 /*! QMF overlap buffer. <br> 199 Dimension: #((8) + (1)) */ 200 C_AALLOC_MEM2(QmfOverlapBuffer32, FIXP_DBL, 201 2 * QMF_DOMAIN_OV_TIMESLOTS_32 * QMF_DOMAIN_MAX_QMF_PROC_BANDS, 202 ((8) + (1))) 203 204 static int FDK_QmfDomain_FreePersistentMemory(HANDLE_FDK_QMF_DOMAIN qd) { 205 int err = 0; 206 int ch; 207 208 for (ch = 0; ch < ((8) + (1)); ch++) { 209 if (qd->QmfDomainIn[ch].pAnaQmfStates) { 210 if (qd->globalConf.nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_16) { 211 FreeAnaQmfStates16(&qd->QmfDomainIn[ch].pAnaQmfStates); 212 } else if (qd->globalConf.nBandsAnalysis == 213 QMF_DOMAIN_ANALYSIS_QMF_BANDS_24) { 214 FreeAnaQmfStates24(&qd->QmfDomainIn[ch].pAnaQmfStates); 215 } else if (qd->globalConf.nBandsAnalysis == 216 QMF_DOMAIN_ANALYSIS_QMF_BANDS_32) { 217 FreeAnaQmfStates32(&qd->QmfDomainIn[ch].pAnaQmfStates); 218 } else { 219 FreeAnaQmfStates(&qd->QmfDomainIn[ch].pAnaQmfStates); 220 } 221 } 222 223 if (qd->QmfDomainIn[ch].pOverlapBuffer) { 224 if (qd->globalConf.nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_16) { 225 FreeQmfOverlapBuffer16(&qd->QmfDomainIn[ch].pOverlapBuffer); 226 } else if (qd->globalConf.nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_32) { 227 FreeQmfOverlapBuffer32(&qd->QmfDomainIn[ch].pOverlapBuffer); 228 } else { 229 FreeQmfOverlapBuffer(&qd->QmfDomainIn[ch].pOverlapBuffer); 230 } 231 } 232 233 if (qd->QmfDomainIn[ch].hQmfSlotsReal) { 234 if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_16) { 235 FreeQmfSlotsReal16(&qd->QmfDomainIn[ch].hQmfSlotsReal); 236 } else if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_32) { 237 FreeQmfSlotsReal32(&qd->QmfDomainIn[ch].hQmfSlotsReal); 238 } else { 239 FreeQmfSlotsReal(&qd->QmfDomainIn[ch].hQmfSlotsReal); 240 } 241 } 242 243 if (qd->QmfDomainIn[ch].hQmfSlotsImag) { 244 if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_16) { 245 FreeQmfSlotsImag16(&qd->QmfDomainIn[ch].hQmfSlotsImag); 246 } 247 if (qd->globalConf.nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_32) { 248 FreeQmfSlotsImag32(&qd->QmfDomainIn[ch].hQmfSlotsImag); 249 } else { 250 FreeQmfSlotsImag(&qd->QmfDomainIn[ch].hQmfSlotsImag); 251 } 252 } 253 } 254 255 for (ch = 0; ch < ((8) + (1)); ch++) { 256 if (qd->QmfDomainOut[ch].pSynQmfStates) { 257 FreeSynQmfStates(&qd->QmfDomainOut[ch].pSynQmfStates); 258 } 259 } 260 261 return err; 262 } 263 264 static int FDK_QmfDomain_AllocatePersistentMemory(HANDLE_FDK_QMF_DOMAIN qd) { 265 int err = 0; 266 int ch; 267 HANDLE_FDK_QMF_DOMAIN_GC gc = &qd->globalConf; 268 269 if ((gc->nInputChannels > ((8) + (1))) || (gc->nOutputChannels > ((8) + (1)))) 270 return err = 1; 271 for (ch = 0; ch < gc->nInputChannels; ch++) { 272 int size; 273 274 size = gc->nBandsAnalysis * 10; 275 if (size > 0) { 276 if (gc->nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_16) { 277 if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) { 278 if (NULL == 279 (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates16(ch))) 280 goto bail; 281 } 282 } else if (gc->nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_24) { 283 if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) { 284 if (NULL == 285 (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates24(ch))) 286 goto bail; 287 } 288 } else if (gc->nBandsAnalysis == QMF_DOMAIN_ANALYSIS_QMF_BANDS_32) { 289 if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) { 290 if (NULL == 291 (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates32(ch))) 292 goto bail; 293 } 294 } else { 295 if (qd->QmfDomainIn[ch].pAnaQmfStates == NULL) { 296 if (NULL == (qd->QmfDomainIn[ch].pAnaQmfStates = GetAnaQmfStates(ch))) 297 goto bail; 298 } 299 } 300 } else { 301 qd->QmfDomainIn[ch].pAnaQmfStates = NULL; 302 } 303 304 size = gc->nQmfOvTimeSlots + gc->nQmfTimeSlots; 305 if (size > 0) { 306 if (gc->nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_16) { 307 if (qd->QmfDomainIn[ch].hQmfSlotsReal == NULL) { 308 if (NULL == 309 (qd->QmfDomainIn[ch].hQmfSlotsReal = GetQmfSlotsReal16(ch))) 310 goto bail; 311 } 312 if (qd->QmfDomainIn[ch].hQmfSlotsImag == NULL) { 313 if (NULL == 314 (qd->QmfDomainIn[ch].hQmfSlotsImag = GetQmfSlotsImag16(ch))) 315 goto bail; 316 } 317 } else if (gc->nQmfTimeSlots == QMF_DOMAIN_TIMESLOTS_32) { 318 if (qd->QmfDomainIn[ch].hQmfSlotsReal == NULL) { 319 if (NULL == 320 (qd->QmfDomainIn[ch].hQmfSlotsReal = GetQmfSlotsReal32(ch))) 321 goto bail; 322 } 323 if (qd->QmfDomainIn[ch].hQmfSlotsImag == NULL) { 324 if (NULL == 325 (qd->QmfDomainIn[ch].hQmfSlotsImag = GetQmfSlotsImag32(ch))) 326 goto bail; 327 } 328 } else { 329 if (qd->QmfDomainIn[ch].hQmfSlotsReal == NULL) { 330 if (NULL == (qd->QmfDomainIn[ch].hQmfSlotsReal = GetQmfSlotsReal(ch))) 331 goto bail; 332 } 333 if (qd->QmfDomainIn[ch].hQmfSlotsImag == NULL) { 334 if (NULL == (qd->QmfDomainIn[ch].hQmfSlotsImag = GetQmfSlotsImag(ch))) 335 goto bail; 336 } 337 } 338 } else { 339 qd->QmfDomainIn[ch].hQmfSlotsReal = NULL; 340 qd->QmfDomainIn[ch].hQmfSlotsImag = NULL; 341 } 342 343 size = gc->nQmfOvTimeSlots * gc->nQmfProcBands * CMPLX_MOD; 344 if (size > 0) { 345 if (gc->nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_16) { 346 if (qd->QmfDomainIn[ch].pOverlapBuffer == NULL) { 347 if (NULL == 348 (qd->QmfDomainIn[ch].pOverlapBuffer = GetQmfOverlapBuffer16(ch))) 349 goto bail; 350 } 351 } else if (gc->nQmfOvTimeSlots == QMF_DOMAIN_OV_TIMESLOTS_32) { 352 if (qd->QmfDomainIn[ch].pOverlapBuffer == NULL) { 353 if (NULL == 354 (qd->QmfDomainIn[ch].pOverlapBuffer = GetQmfOverlapBuffer32(ch))) 355 goto bail; 356 } 357 } else { 358 if (qd->QmfDomainIn[ch].pOverlapBuffer == NULL) { 359 if (NULL == 360 (qd->QmfDomainIn[ch].pOverlapBuffer = GetQmfOverlapBuffer(ch))) 361 goto bail; 362 } 363 } 364 } else { 365 qd->QmfDomainIn[ch].pOverlapBuffer = NULL; 366 } 367 } 368 369 for (ch = 0; ch < gc->nOutputChannels; ch++) { 370 int size = gc->nBandsSynthesis * 9; 371 if (size > 0) { 372 if (qd->QmfDomainOut[ch].pSynQmfStates == NULL) { 373 if (NULL == (qd->QmfDomainOut[ch].pSynQmfStates = GetSynQmfStates(ch))) 374 goto bail; 375 } 376 } else { 377 qd->QmfDomainOut[ch].pSynQmfStates = NULL; 378 } 379 } 380 381 return err; 382 383 bail: 384 FDK_QmfDomain_FreePersistentMemory(qd); 385 return -1; 386 } 387 388 QMF_DOMAIN_ERROR FDK_QmfDomain_ClearPersistentMemory( 389 HANDLE_FDK_QMF_DOMAIN hqd) { 390 QMF_DOMAIN_ERROR err = QMF_DOMAIN_OK; 391 int ch, size; 392 if (hqd) { 393 HANDLE_FDK_QMF_DOMAIN_GC gc = &hqd->globalConf; 394 395 size = gc->nQmfOvTimeSlots * gc->nQmfProcBands * CMPLX_MOD; 396 for (ch = 0; ch < gc->nInputChannels; ch++) { 397 if (hqd->QmfDomainIn[ch].pOverlapBuffer) { 398 FDKmemclear(hqd->QmfDomainIn[ch].pOverlapBuffer, 399 size * sizeof(FIXP_DBL)); 400 } 401 } 402 if (FDK_QmfDomain_InitFilterBank(hqd, 0)) { 403 err = QMF_DOMAIN_INIT_ERROR; 404 } 405 } else { 406 err = QMF_DOMAIN_INIT_ERROR; 407 } 408 return err; 409 } 410 411 /* 412 FDK_getWorkBuffer 413 414 Parameters: 415 416 pWorkBuffer i: array of pointers which point to different workbuffer 417 sections workBufferOffset i: offset in the workbuffer to the requested 418 memory memSize i: size of requested memory 419 420 Function: 421 422 The functions returns the address to the requested memory in the workbuffer. 423 424 The overall workbuffer is divided into several sections. There are 425 QMF_MAX_WB_SECTIONS sections of size QMF_WB_SECTION_SIZE. The function 426 selects the workbuffer section with the help of the workBufferOffset and than 427 it verifies whether the requested amount of memory fits into the selected 428 workbuffer section. 429 430 Returns: 431 432 address to workbuffer 433 */ 434 static FIXP_DBL *FDK_getWorkBuffer(FIXP_DBL **pWorkBuffer, 435 USHORT workBufferOffset, 436 USHORT workBufferSectSize, USHORT memSize) { 437 int idx1; 438 int idx2; 439 FIXP_DBL *pwb; 440 441 /* a section must be a multiple of the number of processing bands (currently 442 * always 64) */ 443 FDK_ASSERT((workBufferSectSize % 64) == 0); 444 445 /* calculate offset within the section */ 446 idx2 = workBufferOffset % workBufferSectSize; 447 /* calculate section number */ 448 idx1 = (workBufferOffset - idx2) / workBufferSectSize; 449 /* maximum sectionnumber is QMF_MAX_WB_SECTIONS */ 450 FDK_ASSERT(idx1 < QMF_MAX_WB_SECTIONS); 451 452 /* check, whether workbuffer is available */ 453 FDK_ASSERT(pWorkBuffer[idx1] != NULL); 454 455 /* check, whether buffer fits into selected section */ 456 FDK_ASSERT((idx2 + memSize) <= workBufferSectSize); 457 458 /* get requested address to workbuffer */ 459 pwb = &pWorkBuffer[idx1][idx2]; 460 461 return pwb; 462 } 463 464 static int FDK_QmfDomain_FeedWorkBuffer(HANDLE_FDK_QMF_DOMAIN qd, int ch, 465 FIXP_DBL **pWorkBuffer, 466 USHORT workBufferOffset, 467 USHORT workBufferSectSize, int size) { 468 int err = 0; 469 int mem_needed; 470 471 mem_needed = qd->QmfDomainIn[ch].workBuf_nBands * 472 qd->QmfDomainIn[ch].workBuf_nTimeSlots * CMPLX_MOD; 473 if (mem_needed > size) { 474 return (err = 1); 475 } 476 qd->QmfDomainIn[ch].pWorkBuffer = pWorkBuffer; 477 qd->QmfDomainIn[ch].workBufferOffset = workBufferOffset; 478 qd->QmfDomainIn[ch].workBufferSectSize = workBufferSectSize; 479 480 return err; 481 } 482 483 int FDK_QmfDomain_IsInitialized(const HANDLE_FDK_QMF_DOMAIN qd) { 484 FDK_ASSERT(qd != NULL); 485 return ((qd->QmfDomainIn[0].pAnaQmfStates == NULL) && 486 (qd->QmfDomainOut[0].pSynQmfStates == NULL)) 487 ? 0 488 : 1; 489 } 490 491 int FDK_QmfDomain_InitFilterBank(HANDLE_FDK_QMF_DOMAIN qd, UINT extra_flags) { 492 FDK_ASSERT(qd != NULL); 493 int err = 0; 494 int ch, ts; 495 HANDLE_FDK_QMF_DOMAIN_GC gc = &qd->globalConf; 496 int noCols = gc->nQmfTimeSlots; 497 int lsb = gc->nBandsAnalysis; 498 int usb = fMin((INT)gc->nBandsSynthesis, 64); 499 int nProcBands = gc->nQmfProcBands; 500 FDK_ASSERT(nProcBands % ALIGNMENT_DEFAULT == 0); 501 502 if (extra_flags & QMF_FLAG_MPSLDFB) { 503 gc->flags &= ~QMF_FLAG_CLDFB; 504 gc->flags |= QMF_FLAG_MPSLDFB; 505 } 506 for (ch = 0; ch < gc->nInputChannels; ch++) { 507 /* distribute memory to slots array */ 508 FIXP_DBL *ptrOv = 509 qd->QmfDomainIn[ch].pOverlapBuffer; /* persistent memory for overlap */ 510 if ((ptrOv == NULL) && (gc->nQmfOvTimeSlots != 0)) { 511 err = 1; 512 return err; 513 } 514 /* This assumes the workbuffer defined for ch0 is the big one being used to 515 * hold one full frame of QMF data. */ 516 FIXP_DBL **ptr = 517 qd->QmfDomainIn[fMin(ch, fMax((INT)gc->nQmfProcChannels - 1, 0))] 518 .pWorkBuffer; /* non-persistent workbuffer */ 519 USHORT workBufferOffset = 520 qd->QmfDomainIn[fMin(ch, fMax((INT)gc->nQmfProcChannels - 1, 0))] 521 .workBufferOffset; 522 USHORT workBufferSectSize = 523 qd->QmfDomainIn[fMin(ch, fMax((INT)gc->nQmfProcChannels - 1, 0))] 524 .workBufferSectSize; 525 526 if ((ptr == NULL) && (gc->nQmfTimeSlots != 0)) { 527 err = 1; 528 return err; 529 } 530 531 qd->QmfDomainIn[ch].pGlobalConf = gc; 532 for (ts = 0; ts < gc->nQmfOvTimeSlots; ts++) { 533 qd->QmfDomainIn[ch].hQmfSlotsReal[ts] = ptrOv; 534 ptrOv += nProcBands; 535 qd->QmfDomainIn[ch].hQmfSlotsImag[ts] = ptrOv; 536 ptrOv += nProcBands; 537 } 538 for (; ts < (gc->nQmfOvTimeSlots + gc->nQmfTimeSlots); ts++) { 539 qd->QmfDomainIn[ch].hQmfSlotsReal[ts] = FDK_getWorkBuffer( 540 ptr, workBufferOffset, workBufferSectSize, nProcBands); 541 workBufferOffset += nProcBands; 542 qd->QmfDomainIn[ch].hQmfSlotsImag[ts] = FDK_getWorkBuffer( 543 ptr, workBufferOffset, workBufferSectSize, nProcBands); 544 workBufferOffset += nProcBands; 545 } 546 err |= qmfInitAnalysisFilterBank( 547 &qd->QmfDomainIn[ch].fb, qd->QmfDomainIn[ch].pAnaQmfStates, noCols, 548 (qd->QmfDomainIn[ch].fb.lsb == 0) ? lsb : qd->QmfDomainIn[ch].fb.lsb, 549 (qd->QmfDomainIn[ch].fb.usb == 0) ? usb : qd->QmfDomainIn[ch].fb.usb, 550 gc->nBandsAnalysis, gc->flags | extra_flags); 551 } 552 553 for (ch = 0; ch < gc->nOutputChannels; ch++) { 554 FIXP_DBL outGain_m = qd->QmfDomainOut[ch].fb.outGain_m; 555 int outGain_e = qd->QmfDomainOut[ch].fb.outGain_e; 556 int outScale = qmfGetOutScalefactor(&qd->QmfDomainOut[ch].fb); 557 err |= qmfInitSynthesisFilterBank( 558 &qd->QmfDomainOut[ch].fb, qd->QmfDomainOut[ch].pSynQmfStates, noCols, 559 (qd->QmfDomainOut[ch].fb.lsb == 0) ? lsb : qd->QmfDomainOut[ch].fb.lsb, 560 (qd->QmfDomainOut[ch].fb.usb == 0) ? usb : qd->QmfDomainOut[ch].fb.usb, 561 gc->nBandsSynthesis, gc->flags | extra_flags); 562 if (outGain_m != (FIXP_DBL)0) { 563 qmfChangeOutGain(&qd->QmfDomainOut[ch].fb, outGain_m, outGain_e); 564 } 565 if (outScale) { 566 qmfChangeOutScalefactor(&qd->QmfDomainOut[ch].fb, outScale); 567 } 568 } 569 570 return err; 571 } 572 573 void FDK_QmfDomain_SaveOverlap(HANDLE_FDK_QMF_DOMAIN_IN qd_ch, int offset) { 574 FDK_ASSERT(qd_ch != NULL); 575 int ts; 576 HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf; 577 int ovSlots = gc->nQmfOvTimeSlots; 578 int nCols = gc->nQmfTimeSlots; 579 int nProcBands = gc->nQmfProcBands; 580 FIXP_DBL **qmfReal = qd_ch->hQmfSlotsReal; 581 FIXP_DBL **qmfImag = qd_ch->hQmfSlotsImag; 582 QMF_SCALE_FACTOR *pScaling = &qd_ch->scaling; 583 584 /* for high part it would be enough to save only used part of overlap area */ 585 if (qmfImag != NULL) { 586 for (ts = offset; ts < ovSlots; ts++) { 587 FDKmemcpy(qmfReal[ts], qmfReal[nCols + ts], 588 sizeof(FIXP_DBL) * nProcBands); 589 FDKmemcpy(qmfImag[ts], qmfImag[nCols + ts], 590 sizeof(FIXP_DBL) * nProcBands); 591 } 592 } else { 593 for (ts = 0; ts < ovSlots; ts++) { 594 FDKmemcpy(qmfReal[ts], qmfReal[nCols + ts], 595 sizeof(FIXP_DBL) * nProcBands); 596 } 597 } 598 pScaling->ov_lb_scale = pScaling->lb_scale; 599 } 600 601 /* Convert headroom bits to exponent */ 602 #define SCALE2EXP(s) (15 - (s)) 603 #define EXP2SCALE(e) (15 - (e)) 604 605 void FDK_QmfDomain_GetSlot(const HANDLE_FDK_QMF_DOMAIN_IN qd_ch, const int ts, 606 const int start_band, const int stop_band, 607 FIXP_DBL *pQmfOutReal, FIXP_DBL *pQmfOutImag, 608 const int exp_out) { 609 FDK_ASSERT(qd_ch != NULL); 610 FDK_ASSERT(pQmfOutReal != NULL); 611 HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf; 612 const FIXP_DBL *real = qd_ch->hQmfSlotsReal[ts]; 613 const FIXP_DBL *imag = qd_ch->hQmfSlotsImag[ts]; 614 const int ovSlots = gc->nQmfOvTimeSlots; 615 const int exp_lb = SCALE2EXP((ts < ovSlots) ? qd_ch->scaling.ov_lb_scale 616 : qd_ch->scaling.lb_scale); 617 const int exp_hb = SCALE2EXP(qd_ch->scaling.hb_scale); 618 const int lsb = qd_ch->fb.lsb; 619 const int usb = qd_ch->fb.usb; 620 int b = start_band; 621 int lb_sf, hb_sf; 622 623 int target_exp = 624 ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK + qd_ch->fb.filterScale; 625 626 FDK_ASSERT(ts < (gc->nQmfTimeSlots + gc->nQmfOvTimeSlots)); 627 FDK_ASSERT(start_band >= 0); 628 FDK_ASSERT(stop_band <= gc->nQmfProcBands); 629 630 if (qd_ch->fb.no_channels == 24) { 631 target_exp -= 1; 632 } 633 634 /* Limit scaling factors to maximum negative value to avoid faulty behaviour 635 due to right-shifts. Corresponding asserts were observed during robustness 636 testing. 637 */ 638 lb_sf = fMax(exp_lb - target_exp - exp_out, -31); 639 FDK_ASSERT(lb_sf < 32); 640 hb_sf = fMax(exp_hb - target_exp - exp_out, -31); 641 FDK_ASSERT(hb_sf < 32); 642 643 if (pQmfOutImag == NULL) { 644 for (; b < fMin(lsb, stop_band); b++) { 645 pQmfOutReal[b] = scaleValue(real[b], lb_sf); 646 } 647 for (; b < fMin(usb, stop_band); b++) { 648 pQmfOutReal[b] = scaleValue(real[b], hb_sf); 649 } 650 for (; b < stop_band; b++) { 651 pQmfOutReal[b] = (FIXP_DBL)0; 652 } 653 } else { 654 FDK_ASSERT(imag != NULL); 655 for (; b < fMin(lsb, stop_band); b++) { 656 pQmfOutReal[b] = scaleValue(real[b], lb_sf); 657 pQmfOutImag[b] = scaleValue(imag[b], lb_sf); 658 } 659 for (; b < fMin(usb, stop_band); b++) { 660 pQmfOutReal[b] = scaleValue(real[b], hb_sf); 661 pQmfOutImag[b] = scaleValue(imag[b], hb_sf); 662 } 663 for (; b < stop_band; b++) { 664 pQmfOutReal[b] = (FIXP_DBL)0; 665 pQmfOutImag[b] = (FIXP_DBL)0; 666 } 667 } 668 } 669 670 void FDK_QmfDomain_GetWorkBuffer(const HANDLE_FDK_QMF_DOMAIN_IN qd_ch, 671 const int ts, FIXP_DBL **ppQmfReal, 672 FIXP_DBL **ppQmfImag) { 673 FDK_ASSERT(qd_ch != NULL); 674 FDK_ASSERT(ppQmfReal != NULL); 675 FDK_ASSERT(ppQmfImag != NULL); 676 const int bands = qd_ch->workBuf_nBands; 677 FIXP_DBL **pWorkBuf = qd_ch->pWorkBuffer; 678 USHORT workBufferOffset = qd_ch->workBufferOffset; 679 USHORT workBufferSectSize = qd_ch->workBufferSectSize; 680 681 FDK_ASSERT(bands > 0); 682 FDK_ASSERT(ts < qd_ch->workBuf_nTimeSlots); 683 684 *ppQmfReal = FDK_getWorkBuffer( 685 pWorkBuf, workBufferOffset + (ts * CMPLX_MOD + 0) * bands, 686 workBufferSectSize, bands); 687 *ppQmfImag = FDK_getWorkBuffer( 688 pWorkBuf, workBufferOffset + (ts * CMPLX_MOD + 1) * bands, 689 workBufferSectSize, bands); 690 } 691 692 void FDK_QmfDomain_WorkBuffer2ProcChannel( 693 const HANDLE_FDK_QMF_DOMAIN_IN qd_ch) { 694 FDK_ASSERT(qd_ch != NULL); 695 HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf; 696 FIXP_DBL **pWorkBuf = qd_ch->pWorkBuffer; 697 USHORT workBufferOffset = qd_ch->workBufferOffset; 698 USHORT workBufferSectSize = qd_ch->workBufferSectSize; 699 700 if (FDK_getWorkBuffer(pWorkBuf, workBufferOffset, workBufferSectSize, 701 qd_ch->workBuf_nBands) == 702 qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots]) { 703 /* work buffer is part of processing channel => nothing to do */ 704 return; 705 } else { 706 /* copy parked new QMF data to processing channel */ 707 const int bands = qd_ch->workBuf_nBands; 708 const int slots = qd_ch->workBuf_nTimeSlots; 709 int ts; 710 for (ts = 0; ts < slots; ts++) { 711 FDKmemcpy(qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts], 712 FDK_getWorkBuffer(pWorkBuf, workBufferOffset, 713 workBufferSectSize, bands), 714 sizeof(FIXP_DBL) * bands); // parkBuf_to_anaMatrix 715 workBufferOffset += bands; 716 FDKmemcpy(qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts], 717 FDK_getWorkBuffer(pWorkBuf, workBufferOffset, 718 workBufferSectSize, bands), 719 sizeof(FIXP_DBL) * bands); 720 workBufferOffset += bands; 721 } 722 } 723 } 724 725 void FDK_QmfDomain_QmfData2HBE(HANDLE_FDK_QMF_DOMAIN_IN qd_ch, 726 FIXP_DBL **ppQmfReal, FIXP_DBL **ppQmfImag) { 727 FDK_ASSERT(qd_ch != NULL); 728 FDK_ASSERT(ppQmfReal != NULL); 729 FDK_ASSERT(ppQmfImag != NULL); 730 HANDLE_FDK_QMF_DOMAIN_GC gc = qd_ch->pGlobalConf; 731 FIXP_DBL **pWorkBuf = qd_ch->pWorkBuffer; 732 USHORT workBufferOffset = qd_ch->workBufferOffset; 733 USHORT workBufferSectSize = qd_ch->workBufferSectSize; 734 735 if (FDK_getWorkBuffer(pWorkBuf, workBufferOffset, workBufferSectSize, 736 qd_ch->workBuf_nBands) == 737 qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots]) { // left channel (anaMatrix) 738 int ts; 739 const int bands = gc->nBandsAnalysis; 740 const int slots = qd_ch->workBuf_nTimeSlots; 741 FDK_ASSERT(bands <= 64); 742 for (ts = 0; ts < slots; ts++) { 743 /* copy current data of processing channel */ 744 FIXP_DBL tmp[64]; // one slot 745 /* real */ 746 FDKmemcpy(tmp, qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts], 747 sizeof(FIXP_DBL) * bands); // anaMatrix_to_tmp 748 FDKmemcpy(qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts], ppQmfReal[ts], 749 sizeof(FIXP_DBL) * bands); // HBE_to_anaMatrix 750 FDKmemcpy(ppQmfReal[ts], tmp, sizeof(FIXP_DBL) * bands); // tmp_to_HBE 751 /* imag */ 752 FDKmemcpy(tmp, qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts], 753 sizeof(FIXP_DBL) * bands); 754 FDKmemcpy(qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts], ppQmfImag[ts], 755 sizeof(FIXP_DBL) * bands); 756 FDKmemcpy(ppQmfImag[ts], tmp, sizeof(FIXP_DBL) * bands); 757 } 758 } else { // right channel (parkBuf) 759 const int bands = qd_ch->workBuf_nBands; 760 const int slots = qd_ch->workBuf_nTimeSlots; 761 int ts; 762 FDK_ASSERT(qd_ch->workBuf_nBands == gc->nBandsAnalysis); 763 for (ts = 0; ts < slots; ts++) { 764 /* copy HBE QMF data buffer to processing channel */ 765 FDKmemcpy(qd_ch->hQmfSlotsReal[gc->nQmfOvTimeSlots + ts], ppQmfReal[ts], 766 sizeof(FIXP_DBL) * bands); // HBE_to_anaMatrix 767 FDKmemcpy(qd_ch->hQmfSlotsImag[gc->nQmfOvTimeSlots + ts], ppQmfImag[ts], 768 sizeof(FIXP_DBL) * bands); 769 /* copy parked new QMF data to HBE QMF data buffer */ 770 FDKmemcpy(ppQmfReal[ts], 771 FDK_getWorkBuffer(pWorkBuf, workBufferOffset, 772 workBufferSectSize, bands), 773 sizeof(FIXP_DBL) * bands); // parkBuf_to_HBE 774 workBufferOffset += bands; 775 FDKmemcpy(ppQmfImag[ts], 776 FDK_getWorkBuffer(pWorkBuf, workBufferOffset, 777 workBufferSectSize, bands), 778 sizeof(FIXP_DBL) * bands); 779 workBufferOffset += bands; 780 } 781 } 782 } 783 784 void FDK_QmfDomain_ClearRequested(HANDLE_FDK_QMF_DOMAIN_GC hgc) { 785 hgc->qmfDomainExplicitConfig = 0; 786 hgc->flags_requested = 0; 787 hgc->nInputChannels_requested = 0; 788 hgc->nOutputChannels_requested = 0; 789 hgc->parkChannel_requested = 0; 790 hgc->nBandsAnalysis_requested = 0; 791 hgc->nBandsSynthesis_requested = 0; 792 hgc->nQmfTimeSlots_requested = 0; 793 hgc->nQmfOvTimeSlots_requested = 0; 794 hgc->nQmfProcBands_requested = 0; 795 hgc->nQmfProcChannels_requested = 0; 796 } 797 798 static void FDK_QmfDomain_ClearConfigured(HANDLE_FDK_QMF_DOMAIN_GC hgc) { 799 hgc->flags = 0; 800 hgc->nInputChannels = 0; 801 hgc->nOutputChannels = 0; 802 hgc->parkChannel = 0; 803 hgc->nBandsAnalysis = 0; 804 hgc->nBandsSynthesis = 0; 805 hgc->nQmfTimeSlots = 0; 806 hgc->nQmfOvTimeSlots = 0; 807 hgc->nQmfProcBands = 0; 808 hgc->nQmfProcChannels = 0; 809 } 810 811 static void FDK_QmfDomain_ClearFilterBank(HANDLE_FDK_QMF_DOMAIN hqd) { 812 int ch; 813 814 for (ch = 0; ch < ((8) + (1)); ch++) { 815 FDKmemclear(&hqd->QmfDomainIn[ch].fb, sizeof(hqd->QmfDomainIn[ch].fb)); 816 } 817 818 for (ch = 0; ch < ((8) + (1)); ch++) { 819 FDKmemclear(&hqd->QmfDomainOut[ch].fb, sizeof(hqd->QmfDomainIn[ch].fb)); 820 } 821 } 822 823 QMF_DOMAIN_ERROR FDK_QmfDomain_Configure(HANDLE_FDK_QMF_DOMAIN hqd) { 824 FDK_ASSERT(hqd != NULL); 825 QMF_DOMAIN_ERROR err = QMF_DOMAIN_OK; 826 int i, size_main, size, size_temp = 0; 827 828 HANDLE_FDK_QMF_DOMAIN_GC hgc = &hqd->globalConf; 829 FIXP_DBL **pWorkBuffer = hgc->pWorkBuffer; 830 831 int hasChanged = 0; 832 833 if ((hgc->nQmfProcChannels_requested > 0) && 834 (hgc->nQmfProcBands_requested != 64)) { 835 return QMF_DOMAIN_INIT_ERROR; 836 } 837 if (hgc->nBandsAnalysis_requested > hgc->nQmfProcBands_requested) { 838 /* In general the output of the qmf analysis is written to QMF memory slots 839 which size is defined by nQmfProcBands. nBandsSynthesis may be larger 840 than nQmfProcBands. This is e.g. the case if the QMF based resampler is 841 used. 842 */ 843 return QMF_DOMAIN_INIT_ERROR; 844 } 845 846 /* 1. adjust change of processing channels by comparison of current and 847 * requested parameters */ 848 if ((hgc->nQmfProcChannels != hgc->nQmfProcChannels_requested) || 849 (hgc->nQmfProcBands != hgc->nQmfProcBands_requested) || 850 (hgc->nQmfTimeSlots != hgc->nQmfTimeSlots_requested)) { 851 for (i = 0; i < hgc->nQmfProcChannels_requested; i++) { 852 hqd->QmfDomainIn[i].workBuf_nBands = hgc->nQmfProcBands_requested; 853 hgc->nQmfProcBands = hgc->nQmfProcBands_requested; 854 855 hqd->QmfDomainIn[i].workBuf_nTimeSlots = hgc->nQmfTimeSlots_requested; 856 } 857 858 hgc->nQmfProcChannels = 859 hgc->nQmfProcChannels_requested; /* keep highest value encountered so 860 far as allocated */ 861 862 hasChanged = 1; 863 } 864 865 /* 2. reallocate persistent memory if necessary (analysis state-buffers, 866 * timeslot-pointer-array, overlap-buffers, synthesis state-buffers) */ 867 if ((hgc->nInputChannels != hgc->nInputChannels_requested) || 868 (hgc->nBandsAnalysis != hgc->nBandsAnalysis_requested) || 869 (hgc->nQmfTimeSlots != hgc->nQmfTimeSlots_requested) || 870 (hgc->nQmfOvTimeSlots != hgc->nQmfOvTimeSlots_requested) || 871 (hgc->nOutputChannels != hgc->nOutputChannels_requested) || 872 (hgc->nBandsSynthesis != hgc->nBandsSynthesis_requested) || 873 (hgc->parkChannel != hgc->parkChannel_requested)) { 874 hgc->nInputChannels = hgc->nInputChannels_requested; 875 hgc->nBandsAnalysis = hgc->nBandsAnalysis_requested; 876 hgc->nQmfTimeSlots = hgc->nQmfTimeSlots_requested; 877 hgc->nQmfOvTimeSlots = hgc->nQmfOvTimeSlots_requested; 878 hgc->nOutputChannels = hgc->nOutputChannels_requested; 879 hgc->nBandsSynthesis = hgc->nBandsSynthesis_requested; 880 hgc->parkChannel = hgc->parkChannel_requested; 881 882 if (FDK_QmfDomain_AllocatePersistentMemory(hqd)) { 883 err = QMF_DOMAIN_OUT_OF_MEMORY; 884 goto bail; 885 } 886 887 /* 3. set request-flag for downsampled SBR */ 888 if ((hgc->nBandsAnalysis == 32) && (hgc->nBandsSynthesis == 32) && 889 !(hgc->flags & (QMF_FLAG_CLDFB | QMF_FLAG_MPSLDFB))) { 890 hgc->flags_requested |= QMF_FLAG_DOWNSAMPLED; 891 } 892 893 hasChanged = 1; 894 } 895 896 /* 4. initialize tables and buffer for QMF-resampler */ 897 898 /* 5. set requested flags */ 899 if (hgc->flags != hgc->flags_requested) { 900 if ((hgc->flags_requested & QMF_FLAG_MPSLDFB) && 901 (hgc->flags_requested & QMF_FLAG_CLDFB)) { 902 hgc->flags_requested &= ~QMF_FLAG_CLDFB; 903 } 904 hgc->flags = hgc->flags_requested; 905 hasChanged = 1; 906 } 907 908 if (hasChanged) { 909 /* 6. recalculate and check size of required workbuffer-space */ 910 911 if (hgc->parkChannel && (hqd->globalConf.nQmfProcChannels == 1)) { 912 /* configure temp QMF buffer for parking right channel MPS212 output, 913 * (USAC stereoConfigIndex 3 only) */ 914 hqd->QmfDomainIn[1].workBuf_nBands = hqd->globalConf.nBandsAnalysis; 915 hqd->QmfDomainIn[1].workBuf_nTimeSlots = hqd->globalConf.nQmfTimeSlots; 916 size_temp = hqd->QmfDomainIn[1].workBuf_nBands * 917 hqd->QmfDomainIn[1].workBuf_nTimeSlots * CMPLX_MOD; 918 } 919 920 size_main = hqd->QmfDomainIn[0].workBuf_nBands * 921 hqd->QmfDomainIn[0].workBuf_nTimeSlots * CMPLX_MOD; 922 923 size = size_main * hgc->nQmfProcChannels + size_temp; 924 925 if (size > (QMF_MAX_WB_SECTIONS * QMF_WB_SECTION_SIZE)) { 926 err = QMF_DOMAIN_OUT_OF_MEMORY; 927 goto bail; 928 } 929 930 /* 7. allocate additional workbuffer if necessary */ 931 if ((size > 0 /* *QMF_WB_SECTION_SIZE */) && (pWorkBuffer[0] == NULL)) { 932 /* get work buffer of size QMF_WB_SECTION_SIZE */ 933 pWorkBuffer[0] = GetQmfWorkBufferCore6(); 934 } 935 936 if ((size > 1 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[1] == NULL)) { 937 /* get work buffer of size QMF_WB_SECTION_SIZE */ 938 pWorkBuffer[1] = GetQmfWorkBufferCore1(); 939 } 940 941 if ((size > 2 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[2] == NULL)) { 942 /* get work buffer of size QMF_WB_SECTION_SIZE */ 943 pWorkBuffer[2] = GetQmfWorkBufferCore3(); 944 } 945 946 if ((size > 3 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[3] == NULL)) { 947 /* get work buffer of size QMF_WB_SECTION_SIZE */ 948 pWorkBuffer[3] = GetQmfWorkBufferCore4(); 949 } 950 951 if ((size > 4 * QMF_WB_SECTION_SIZE) && (pWorkBuffer[4] == NULL)) { 952 /* get work buffer of size QMF_WB_SECTION_SIZE */ 953 pWorkBuffer[4] = GetQmfWorkBufferCore5(); 954 } 955 956 /* 8. distribute workbuffer over processing channels */ 957 for (i = 0; i < hgc->nQmfProcChannels; i++) { 958 FDK_QmfDomain_FeedWorkBuffer(hqd, i, pWorkBuffer, size_main * i, 959 QMF_WB_SECTION_SIZE, size_main); 960 } 961 if (hgc->parkChannel) { 962 for (; i < hgc->nInputChannels; i++) { 963 FDK_QmfDomain_FeedWorkBuffer(hqd, 1, pWorkBuffer, 964 size_main * hgc->nQmfProcChannels, 965 QMF_WB_SECTION_SIZE, size_temp); 966 } 967 } 968 969 /* 9. (re-)init filterbank */ 970 for (i = 0; i < hgc->nOutputChannels; i++) { 971 if ((hqd->QmfDomainOut[i].fb.lsb == 0) && 972 (hqd->QmfDomainOut[i].fb.usb == 0)) { 973 /* Although lsb and usb are set in the SBR module, they are initialized 974 * at this point due to the case of using MPS without SBR. */ 975 hqd->QmfDomainOut[i].fb.lsb = hgc->nBandsAnalysis_requested; 976 hqd->QmfDomainOut[i].fb.usb = 977 fMin((INT)hgc->nBandsSynthesis_requested, 64); 978 } 979 } 980 if (FDK_QmfDomain_InitFilterBank(hqd, 0)) { 981 err = QMF_DOMAIN_INIT_ERROR; 982 } 983 } 984 985 bail: 986 if (err) { 987 FDK_QmfDomain_FreeMem(hqd); 988 } 989 return err; 990 } 991 992 static void FDK_QmfDomain_FreeWorkBuffer(HANDLE_FDK_QMF_DOMAIN hqd) { 993 FIXP_DBL **pWorkBuffer = hqd->globalConf.pWorkBuffer; 994 995 if (pWorkBuffer[0]) FreeQmfWorkBufferCore6(&pWorkBuffer[0]); 996 if (pWorkBuffer[1]) FreeQmfWorkBufferCore1(&pWorkBuffer[1]); 997 if (pWorkBuffer[2]) FreeQmfWorkBufferCore3(&pWorkBuffer[2]); 998 if (pWorkBuffer[3]) FreeQmfWorkBufferCore4(&pWorkBuffer[3]); 999 if (pWorkBuffer[4]) FreeQmfWorkBufferCore5(&pWorkBuffer[4]); 1000 } 1001 1002 void FDK_QmfDomain_FreeMem(HANDLE_FDK_QMF_DOMAIN hqd) { 1003 FDK_QmfDomain_FreeWorkBuffer(hqd); 1004 1005 FDK_QmfDomain_FreePersistentMemory(hqd); 1006 1007 FDK_QmfDomain_ClearFilterBank(hqd); 1008 1009 FDK_QmfDomain_ClearConfigured(&hqd->globalConf); 1010 1011 FDK_QmfDomain_ClearRequested(&hqd->globalConf); 1012 } 1013 1014 void FDK_QmfDomain_Close(HANDLE_FDK_QMF_DOMAIN hqd) { 1015 FDK_QmfDomain_FreeWorkBuffer(hqd); 1016 1017 FDK_QmfDomain_FreePersistentMemory(hqd); 1018 } 1019