Coverage Report

Created: 2025-07-18 06:08

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