/src/aac/libDRCdec/src/drcGainDec_process.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 - 2018 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 | | /************************* MPEG-D DRC decoder library ************************** |
96 | | |
97 | | Author(s): |
98 | | |
99 | | Description: |
100 | | |
101 | | *******************************************************************************/ |
102 | | |
103 | | #include "drcDec_types.h" |
104 | | #include "drcDec_gainDecoder.h" |
105 | | #include "drcGainDec_process.h" |
106 | | |
107 | | #define E_TGAINSTEP 12 |
108 | | |
109 | | static DRC_ERROR _prepareLnbIndex(ACTIVE_DRC* pActiveDrc, |
110 | | const int channelOffset, |
111 | | const int drcChannelOffset, |
112 | | const int numChannelsProcessed, |
113 | 0 | const int lnbPointer) { |
114 | 0 | int g, c; |
115 | 0 | DRC_INSTRUCTIONS_UNI_DRC* pInst = pActiveDrc->pInst; |
116 | | |
117 | | /* channelOffset: start index of physical channels |
118 | | numChannelsProcessed: number of processed channels, physical channels and |
119 | | DRC channels channelOffset + drcChannelOffset: start index of DRC channels, |
120 | | i.e. the channel order referenced in pInst.sequenceIndex */ |
121 | | |
122 | | /* sanity checks */ |
123 | 0 | if ((channelOffset + numChannelsProcessed) > 8) return DE_NOT_OK; |
124 | | |
125 | 0 | if ((channelOffset + drcChannelOffset + numChannelsProcessed) > 8) |
126 | 0 | return DE_NOT_OK; |
127 | | |
128 | 0 | if ((channelOffset + drcChannelOffset) < 0) return DE_NOT_OK; |
129 | | |
130 | | /* prepare lnbIndexForChannel, a map of indices from each channel to its |
131 | | * corresponding linearNodeBuffer instance */ |
132 | 0 | for (c = channelOffset; c < channelOffset + numChannelsProcessed; c++) { |
133 | 0 | if (pInst->drcSetId > 0) { |
134 | 0 | int drcChannel = c + drcChannelOffset; |
135 | | /* fallback for configuration with more physical channels than DRC |
136 | | channels: reuse DRC gain of first channel. This is necessary for HE-AAC |
137 | | mono with stereo output */ |
138 | 0 | if (drcChannel >= pInst->drcChannelCount) drcChannel = 0; |
139 | 0 | g = pActiveDrc->channelGroupForChannel[drcChannel]; |
140 | 0 | if ((g >= 0) && !pActiveDrc->channelGroupIsParametricDrc[g]) { |
141 | 0 | pActiveDrc->lnbIndexForChannel[c][lnbPointer] = |
142 | 0 | pActiveDrc->activeDrcOffset + pActiveDrc->gainElementForGroup[g]; |
143 | 0 | } |
144 | 0 | } |
145 | 0 | } |
146 | |
|
147 | 0 | return DE_OK; |
148 | 0 | } |
149 | | |
150 | | static DRC_ERROR _interpolateDrcGain( |
151 | | const GAIN_INTERPOLATION_TYPE gainInterpolationType, |
152 | | const SHORT timePrev, /* time0 */ |
153 | | const SHORT tGainStep, /* time1 - time0 */ |
154 | | const SHORT start, const SHORT stop, const SHORT stepsize, |
155 | | const FIXP_DBL gainLeft, const FIXP_DBL gainRight, const FIXP_DBL slopeLeft, |
156 | 0 | const FIXP_DBL slopeRight, FIXP_DBL* buffer) { |
157 | 0 | int n, n_buf; |
158 | 0 | int start_modulo, start_offset; |
159 | |
|
160 | 0 | if (tGainStep < 0) { |
161 | 0 | return DE_NOT_OK; |
162 | 0 | } |
163 | 0 | if (tGainStep == 0) { |
164 | 0 | return DE_OK; |
165 | 0 | } |
166 | | |
167 | | /* get start index offset and buffer index for downsampled interpolation */ |
168 | | /* start_modulo = (start+timePrev)%stepsize; */ /* stepsize is a power of 2 */ |
169 | 0 | start_modulo = (start + timePrev) & (stepsize - 1); |
170 | 0 | start_offset = (start_modulo ? stepsize - start_modulo : 0); |
171 | | /* n_buf = (start + timePrev + start_offset)/stepsize; */ |
172 | 0 | n_buf = (start + timePrev + start_offset) >> (15 - fixnormz_S(stepsize)); |
173 | |
|
174 | 0 | { /* gainInterpolationType == GIT_LINEAR */ |
175 | 0 | LONG a; |
176 | | /* runs = ceil((stop - start - start_offset)/stepsize). This works for |
177 | | * stepsize = 2^N only. */ |
178 | 0 | INT runs = (INT)(stop - start - start_offset + stepsize - 1) >> |
179 | 0 | (30 - CountLeadingBits(stepsize)); |
180 | 0 | INT n_min = fMin( |
181 | 0 | fMin(CntLeadingZeros(gainRight), CntLeadingZeros(gainLeft)) - 1, 8); |
182 | 0 | a = (LONG)((gainRight << n_min) - (gainLeft << n_min)) / tGainStep; |
183 | 0 | LONG a_step = a * stepsize; |
184 | 0 | n = start + start_offset; |
185 | 0 | a = a * n + (LONG)(gainLeft << n_min); |
186 | 0 | buffer += n_buf; |
187 | | #if defined(FUNCTION_interpolateDrcGain_func1) |
188 | | interpolateDrcGain_func1(buffer, a, a_step, n_min, runs); |
189 | | #else |
190 | 0 | a -= a_step; |
191 | 0 | n_min = 8 - n_min; |
192 | 0 | for (int i = 0; i < runs; i++) { |
193 | 0 | a += a_step; |
194 | 0 | buffer[i] = fMultDiv2(buffer[i], (FIXP_DBL)a) << n_min; |
195 | 0 | } |
196 | 0 | #endif /* defined(FUNCTION_interpolateDrcGain_func1) */ |
197 | 0 | } |
198 | 0 | return DE_OK; |
199 | 0 | } |
200 | | |
201 | | static DRC_ERROR _processNodeSegments( |
202 | | const int frameSize, const GAIN_INTERPOLATION_TYPE gainInterpolationType, |
203 | | const int nNodes, const NODE_LIN* pNodeLin, const int offset, |
204 | | const SHORT stepsize, |
205 | | const NODE_LIN nodePrevious, /* the last node of the previous frame */ |
206 | 0 | const FIXP_DBL channelGain, FIXP_DBL* buffer) { |
207 | 0 | DRC_ERROR err = DE_OK; |
208 | 0 | SHORT timePrev, duration, start, stop, time; |
209 | 0 | int n; |
210 | 0 | FIXP_DBL gainLin = FL2FXCONST_DBL(1.0f / (float)(1 << 7)), gainLinPrev; |
211 | 0 | FIXP_DBL slopeLin = (FIXP_DBL)0, slopeLinPrev = (FIXP_DBL)0; |
212 | |
|
213 | 0 | timePrev = nodePrevious.time + offset; |
214 | 0 | gainLinPrev = nodePrevious.gainLin; |
215 | 0 | for (n = 0; n < nNodes; n++) { |
216 | 0 | time = pNodeLin[n].time + offset; |
217 | 0 | duration = time - timePrev; |
218 | 0 | gainLin = pNodeLin[n].gainLin; |
219 | 0 | if (channelGain != FL2FXCONST_DBL(1.0f / (float)(1 << 8))) |
220 | 0 | gainLin = |
221 | 0 | SATURATE_LEFT_SHIFT(fMultDiv2(gainLin, channelGain), 9, DFRACT_BITS); |
222 | |
|
223 | 0 | if ((timePrev >= (frameSize - 1)) || |
224 | 0 | (time < 0)) { /* This segment (between previous and current node) lies |
225 | | outside of this audio frame */ |
226 | 0 | timePrev = time; |
227 | 0 | gainLinPrev = gainLin; |
228 | 0 | slopeLinPrev = slopeLin; |
229 | 0 | continue; |
230 | 0 | } |
231 | | |
232 | | /* start and stop are the boundaries of the region of this segment that lie |
233 | | within this audio frame. Their values are relative to the beginning of |
234 | | this segment. stop is the first sample that isn't processed any more. */ |
235 | 0 | start = fMax(-timePrev, 1); |
236 | 0 | stop = fMin(time, (SHORT)(frameSize - 1)) - timePrev + 1; |
237 | |
|
238 | 0 | err = _interpolateDrcGain(gainInterpolationType, timePrev, duration, start, |
239 | 0 | stop, stepsize, gainLinPrev, gainLin, |
240 | 0 | slopeLinPrev, slopeLin, buffer); |
241 | 0 | if (err) return err; |
242 | | |
243 | 0 | timePrev = time; |
244 | 0 | gainLinPrev = gainLin; |
245 | 0 | } |
246 | 0 | return err; |
247 | 0 | } |
248 | | |
249 | | /* process DRC on time-domain signal */ |
250 | | DRC_ERROR |
251 | | processDrcTime(HANDLE_DRC_GAIN_DECODER hGainDec, const int activeDrcIndex, |
252 | | const int delaySamples, const int channelOffset, |
253 | | const int drcChannelOffset, const int numChannelsProcessed, |
254 | 0 | const int timeDataChannelOffset, FIXP_DBL* deinterleavedAudio) { |
255 | 0 | DRC_ERROR err = DE_OK; |
256 | 0 | int c, b, i; |
257 | 0 | ACTIVE_DRC* pActiveDrc = &(hGainDec->activeDrc[activeDrcIndex]); |
258 | 0 | DRC_GAIN_BUFFERS* pDrcGainBuffers = &(hGainDec->drcGainBuffers); |
259 | 0 | int lnbPointer = pDrcGainBuffers->lnbPointer, lnbIx; |
260 | 0 | LINEAR_NODE_BUFFER* pLinearNodeBuffer = pDrcGainBuffers->linearNodeBuffer; |
261 | 0 | LINEAR_NODE_BUFFER* pDummyLnb = &(pDrcGainBuffers->dummyLnb); |
262 | 0 | int offset = 0; |
263 | |
|
264 | 0 | if (hGainDec->delayMode == DM_REGULAR_DELAY) { |
265 | 0 | offset = hGainDec->frameSize; |
266 | 0 | } |
267 | |
|
268 | 0 | if ((delaySamples + offset) > |
269 | 0 | (NUM_LNB_FRAMES - 2) * |
270 | 0 | hGainDec->frameSize) /* if delaySamples is too big, NUM_LNB_FRAMES |
271 | | should be increased */ |
272 | 0 | return DE_NOT_OK; |
273 | | |
274 | 0 | err = _prepareLnbIndex(pActiveDrc, channelOffset, drcChannelOffset, |
275 | 0 | numChannelsProcessed, lnbPointer); |
276 | 0 | if (err) return err; |
277 | | |
278 | 0 | deinterleavedAudio += |
279 | 0 | channelOffset * timeDataChannelOffset; /* apply channelOffset */ |
280 | | |
281 | | /* signal processing loop */ |
282 | 0 | for (c = channelOffset; c < channelOffset + numChannelsProcessed; c++) { |
283 | 0 | if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex) |
284 | 0 | pDrcGainBuffers->channelGain[c][lnbPointer] = hGainDec->channelGain[c]; |
285 | |
|
286 | 0 | b = 0; |
287 | 0 | { |
288 | 0 | LINEAR_NODE_BUFFER *pLnb, *pLnbPrevious; |
289 | 0 | NODE_LIN nodePrevious; |
290 | 0 | int lnbPointerDiff; |
291 | 0 | FIXP_DBL channelGain; |
292 | | /* get pointer to oldest linearNodes */ |
293 | 0 | lnbIx = lnbPointer + 1 - NUM_LNB_FRAMES; |
294 | 0 | while (lnbIx < 0) lnbIx += NUM_LNB_FRAMES; |
295 | |
|
296 | 0 | if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex) |
297 | 0 | channelGain = pDrcGainBuffers->channelGain[c][lnbIx]; |
298 | 0 | else |
299 | 0 | channelGain = FL2FXCONST_DBL(1.0f / (float)(1 << 8)); |
300 | | |
301 | | /* Loop over all node buffers in linearNodeBuffer. |
302 | | All nodes which are not relevant for the current frame are sorted out |
303 | | inside _processNodeSegments. */ |
304 | 0 | for (i = 0; i < NUM_LNB_FRAMES - 1; i++) { |
305 | | /* Prepare previous node */ |
306 | 0 | if (pActiveDrc->lnbIndexForChannel[c][lnbIx] >= 0) |
307 | 0 | pLnbPrevious = &( |
308 | 0 | pLinearNodeBuffer[pActiveDrc->lnbIndexForChannel[c][lnbIx] + b]); |
309 | 0 | else |
310 | 0 | pLnbPrevious = pDummyLnb; |
311 | 0 | nodePrevious = |
312 | 0 | pLnbPrevious->linearNode[lnbIx][pLnbPrevious->nNodes[lnbIx] - 1]; |
313 | 0 | nodePrevious.time -= hGainDec->frameSize; |
314 | 0 | if (channelGain != FL2FXCONST_DBL(1.0f / (float)(1 << 8))) |
315 | 0 | nodePrevious.gainLin = SATURATE_LEFT_SHIFT( |
316 | 0 | fMultDiv2(nodePrevious.gainLin, |
317 | 0 | pDrcGainBuffers->channelGain[c][lnbIx]), |
318 | 0 | 9, DFRACT_BITS); |
319 | | |
320 | | /* Prepare current linearNodeBuffer instance */ |
321 | 0 | lnbIx++; |
322 | 0 | if (lnbIx >= NUM_LNB_FRAMES) lnbIx = 0; |
323 | | |
324 | | /* if lnbIndexForChannel changes over time, use the old indices for |
325 | | * smooth transitions */ |
326 | 0 | if (pActiveDrc->lnbIndexForChannel[c][lnbIx] >= 0) |
327 | 0 | pLnb = &( |
328 | 0 | pLinearNodeBuffer[pActiveDrc->lnbIndexForChannel[c][lnbIx] + b]); |
329 | 0 | else /* lnbIndexForChannel = -1 means "no DRC processing", due to |
330 | | drcInstructionsIndex < 0, drcSetId < 0 or channel group < 0 */ |
331 | 0 | pLnb = pDummyLnb; |
332 | |
|
333 | 0 | if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex) |
334 | 0 | channelGain = pDrcGainBuffers->channelGain[c][lnbIx]; |
335 | | |
336 | | /* number of frames of offset with respect to lnbPointer */ |
337 | 0 | lnbPointerDiff = i - (NUM_LNB_FRAMES - 2); |
338 | |
|
339 | 0 | err = _processNodeSegments( |
340 | 0 | hGainDec->frameSize, pLnb->gainInterpolationType, |
341 | 0 | pLnb->nNodes[lnbIx], pLnb->linearNode[lnbIx], |
342 | 0 | lnbPointerDiff * hGainDec->frameSize + delaySamples + offset, 1, |
343 | 0 | nodePrevious, channelGain, deinterleavedAudio); |
344 | 0 | if (err) return err; |
345 | 0 | } |
346 | 0 | deinterleavedAudio += timeDataChannelOffset; /* proceed to next channel */ |
347 | 0 | } |
348 | 0 | } |
349 | 0 | return DE_OK; |
350 | 0 | } |
351 | | |
352 | | /* process DRC on subband-domain signal */ |
353 | | DRC_ERROR |
354 | | processDrcSubband(HANDLE_DRC_GAIN_DECODER hGainDec, const int activeDrcIndex, |
355 | | const int delaySamples, const int channelOffset, |
356 | | const int drcChannelOffset, const int numChannelsProcessed, |
357 | | const int processSingleTimeslot, |
358 | | FIXP_DBL* deinterleavedAudioReal[], |
359 | 0 | FIXP_DBL* deinterleavedAudioImag[]) { |
360 | 0 | DRC_ERROR err = DE_OK; |
361 | 0 | int b, c, g, m, m_start, m_stop, s, i; |
362 | 0 | FIXP_DBL gainSb; |
363 | 0 | DRC_INSTRUCTIONS_UNI_DRC* pInst = hGainDec->activeDrc[activeDrcIndex].pInst; |
364 | 0 | DRC_GAIN_BUFFERS* pDrcGainBuffers = &(hGainDec->drcGainBuffers); |
365 | 0 | ACTIVE_DRC* pActiveDrc = &(hGainDec->activeDrc[activeDrcIndex]); |
366 | 0 | int activeDrcOffset = pActiveDrc->activeDrcOffset; |
367 | 0 | int lnbPointer = pDrcGainBuffers->lnbPointer, lnbIx; |
368 | 0 | LINEAR_NODE_BUFFER* pLinearNodeBuffer = pDrcGainBuffers->linearNodeBuffer; |
369 | 0 | FIXP_DBL(*subbandGains)[4 * 1024 / 256] = hGainDec->subbandGains; |
370 | 0 | FIXP_DBL* dummySubbandGains = hGainDec->dummySubbandGains; |
371 | 0 | SUBBAND_DOMAIN_MODE subbandDomainMode = hGainDec->subbandDomainSupported; |
372 | 0 | int signalIndex = 0; |
373 | 0 | int frameSizeSb = 0; |
374 | 0 | int nDecoderSubbands; |
375 | 0 | SHORT L = 0; /* L: downsampling factor */ |
376 | 0 | int offset = 0; |
377 | 0 | FIXP_DBL *audioReal = NULL, *audioImag = NULL; |
378 | |
|
379 | 0 | if (hGainDec->delayMode == DM_REGULAR_DELAY) { |
380 | 0 | offset = hGainDec->frameSize; |
381 | 0 | } |
382 | |
|
383 | 0 | if ((delaySamples + offset) > |
384 | 0 | (NUM_LNB_FRAMES - 2) * |
385 | 0 | hGainDec->frameSize) /* if delaySamples is too big, NUM_LNB_FRAMES |
386 | | should be increased */ |
387 | 0 | return DE_NOT_OK; |
388 | | |
389 | 0 | switch (subbandDomainMode) { |
390 | | #if ((1024 / 256) >= (4096 / SUBBAND_DOWNSAMPLING_FACTOR_QMF64)) |
391 | | case SDM_QMF64: |
392 | | nDecoderSubbands = SUBBAND_NUM_BANDS_QMF64; |
393 | | L = SUBBAND_DOWNSAMPLING_FACTOR_QMF64; |
394 | | /* analysisDelay = SUBBAND_ANALYSIS_DELAY_QMF64; */ |
395 | | break; |
396 | | case SDM_QMF71: |
397 | | nDecoderSubbands = SUBBAND_NUM_BANDS_QMF71; |
398 | | L = SUBBAND_DOWNSAMPLING_FACTOR_QMF71; |
399 | | /* analysisDelay = SUBBAND_ANALYSIS_DELAY_QMF71; */ |
400 | | break; |
401 | | #else |
402 | 0 | case SDM_QMF64: |
403 | 0 | case SDM_QMF71: |
404 | | /* QMF domain processing is not supported. */ |
405 | 0 | return DE_NOT_OK; |
406 | 0 | #endif |
407 | 0 | case SDM_STFT256: |
408 | 0 | nDecoderSubbands = SUBBAND_NUM_BANDS_STFT256; |
409 | 0 | L = SUBBAND_DOWNSAMPLING_FACTOR_STFT256; |
410 | | /* analysisDelay = SUBBAND_ANALYSIS_DELAY_STFT256; */ |
411 | 0 | break; |
412 | 0 | default: |
413 | 0 | return DE_NOT_OK; |
414 | 0 | } |
415 | | |
416 | | /* frameSizeSb = hGainDec->frameSize/L; */ /* L is a power of 2 */ |
417 | 0 | frameSizeSb = |
418 | 0 | hGainDec->frameSize >> (15 - fixnormz_S(L)); /* timeslots per frame */ |
419 | |
|
420 | 0 | if ((processSingleTimeslot < 0) || (processSingleTimeslot >= frameSizeSb)) { |
421 | 0 | m_start = 0; |
422 | 0 | m_stop = frameSizeSb; |
423 | 0 | } else { |
424 | 0 | m_start = processSingleTimeslot; |
425 | 0 | m_stop = m_start + 1; |
426 | 0 | } |
427 | |
|
428 | 0 | err = _prepareLnbIndex(pActiveDrc, channelOffset, drcChannelOffset, |
429 | 0 | numChannelsProcessed, lnbPointer); |
430 | 0 | if (err) return err; |
431 | | |
432 | 0 | if (!pActiveDrc->subbandGainsReady) /* only for the first time per frame that |
433 | | processDrcSubband is called */ |
434 | 0 | { |
435 | | /* write subbandGains */ |
436 | 0 | for (g = 0; g < pInst->nDrcChannelGroups; g++) { |
437 | 0 | b = 0; |
438 | 0 | { |
439 | 0 | LINEAR_NODE_BUFFER* pLnb = |
440 | 0 | &(pLinearNodeBuffer[activeDrcOffset + |
441 | 0 | pActiveDrc->gainElementForGroup[g] + b]); |
442 | 0 | NODE_LIN nodePrevious; |
443 | 0 | int lnbPointerDiff; |
444 | |
|
445 | 0 | for (m = 0; m < frameSizeSb; m++) { |
446 | 0 | subbandGains[activeDrcOffset + g][b * frameSizeSb + m] = |
447 | 0 | FL2FXCONST_DBL(1.0f / (float)(1 << 7)); |
448 | 0 | } |
449 | |
|
450 | 0 | lnbIx = lnbPointer - (NUM_LNB_FRAMES - 1); |
451 | 0 | while (lnbIx < 0) lnbIx += NUM_LNB_FRAMES; |
452 | | |
453 | | /* Loop over all node buffers in linearNodeBuffer. |
454 | | All nodes which are not relevant for the current frame are sorted out |
455 | | inside _processNodeSegments. */ |
456 | 0 | for (i = 0; i < NUM_LNB_FRAMES - 1; i++) { |
457 | | /* Prepare previous node */ |
458 | 0 | nodePrevious = pLnb->linearNode[lnbIx][pLnb->nNodes[lnbIx] - 1]; |
459 | 0 | nodePrevious.time -= hGainDec->frameSize; |
460 | |
|
461 | 0 | lnbIx++; |
462 | 0 | if (lnbIx >= NUM_LNB_FRAMES) lnbIx = 0; |
463 | | |
464 | | /* number of frames of offset with respect to lnbPointer */ |
465 | 0 | lnbPointerDiff = i - (NUM_LNB_FRAMES - 2); |
466 | |
|
467 | 0 | err = _processNodeSegments( |
468 | 0 | hGainDec->frameSize, pLnb->gainInterpolationType, |
469 | 0 | pLnb->nNodes[lnbIx], pLnb->linearNode[lnbIx], |
470 | 0 | lnbPointerDiff * hGainDec->frameSize + delaySamples + offset - |
471 | 0 | (L - 1) / 2, |
472 | 0 | L, nodePrevious, FL2FXCONST_DBL(1.0f / (float)(1 << 8)), |
473 | 0 | &(subbandGains[activeDrcOffset + g][b * frameSizeSb])); |
474 | 0 | if (err) return err; |
475 | 0 | } |
476 | 0 | } |
477 | 0 | } |
478 | 0 | pActiveDrc->subbandGainsReady = 1; |
479 | 0 | } |
480 | | |
481 | 0 | for (c = channelOffset; c < channelOffset + numChannelsProcessed; c++) { |
482 | 0 | FIXP_DBL* thisSubbandGainsBuffer; |
483 | 0 | if (pInst->drcSetId > 0) |
484 | 0 | g = pActiveDrc->channelGroupForChannel[c + drcChannelOffset]; |
485 | 0 | else |
486 | 0 | g = -1; |
487 | |
|
488 | 0 | audioReal = deinterleavedAudioReal[signalIndex]; |
489 | 0 | if (subbandDomainMode != SDM_STFT256) { |
490 | 0 | audioImag = deinterleavedAudioImag[signalIndex]; |
491 | 0 | } |
492 | |
|
493 | 0 | if ((g >= 0) && !pActiveDrc->channelGroupIsParametricDrc[g]) { |
494 | 0 | thisSubbandGainsBuffer = subbandGains[activeDrcOffset + g]; |
495 | 0 | } else { |
496 | 0 | thisSubbandGainsBuffer = dummySubbandGains; |
497 | 0 | } |
498 | |
|
499 | 0 | for (m = m_start; m < m_stop; m++) { |
500 | 0 | INT n_min = 8; |
501 | 0 | { /* single-band DRC */ |
502 | 0 | gainSb = thisSubbandGainsBuffer[m]; |
503 | 0 | if (activeDrcIndex == hGainDec->channelGainActiveDrcIndex) |
504 | 0 | gainSb = SATURATE_LEFT_SHIFT( |
505 | 0 | fMultDiv2(gainSb, hGainDec->channelGain[c]), 9, DFRACT_BITS); |
506 | | /* normalize gainSb for keeping signal precision */ |
507 | 0 | n_min = fMin(CntLeadingZeros(gainSb) - 1, n_min); |
508 | 0 | gainSb <<= n_min; |
509 | 0 | n_min = 8 - n_min; |
510 | 0 | if (subbandDomainMode == |
511 | 0 | SDM_STFT256) { /* For STFT filterbank, real and imaginary parts are |
512 | | interleaved. */ |
513 | 0 | for (s = 0; s < nDecoderSubbands; s++) { |
514 | 0 | *audioReal = fMultDiv2(*audioReal, gainSb) << n_min; |
515 | 0 | audioReal++; |
516 | 0 | *audioReal = fMultDiv2(*audioReal, gainSb) << n_min; |
517 | 0 | audioReal++; |
518 | 0 | } |
519 | 0 | } else { |
520 | 0 | for (s = 0; s < nDecoderSubbands; s++) { |
521 | 0 | *audioReal = fMultDiv2(*audioReal, gainSb) << n_min; |
522 | 0 | audioReal++; |
523 | 0 | *audioImag = fMultDiv2(*audioImag, gainSb) << n_min; |
524 | 0 | audioImag++; |
525 | 0 | } |
526 | 0 | } |
527 | 0 | } |
528 | 0 | } |
529 | 0 | signalIndex++; |
530 | 0 | } |
531 | 0 | return DE_OK; |
532 | 0 | } |