/src/aac/libDRCdec/src/drcGainDec_preprocess.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 | | /************************* 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_preprocess.h" |
106 | | #include "drcDec_tools.h" |
107 | | #include "FDK_matrixCalloc.h" |
108 | | #include "drcDec_rom.h" |
109 | | |
110 | | #define SLOPE_FACTOR_DB_TO_LINEAR \ |
111 | 0 | FL2FXCONST_DBL(0.1151f * (float)(1 << 3)) /* ln(10) / 20 */ |
112 | | |
113 | | typedef struct { |
114 | | int drcSetEffect; |
115 | | DUCKING_MODIFICATION* pDMod; |
116 | | GAIN_MODIFICATION* pGMod; |
117 | | int drcCharacteristicPresent; |
118 | | CHARACTERISTIC_FORMAT characteristicFormatSource[2]; |
119 | | const CUSTOM_DRC_CHAR* pCCharSource[2]; |
120 | | CHARACTERISTIC_FORMAT characteristicFormatTarget[2]; |
121 | | const CUSTOM_DRC_CHAR* pCCharTarget[2]; |
122 | | int slopeIsNegative; |
123 | | int limiterPeakTargetPresent; |
124 | | FIXP_SGL limiterPeakTarget; |
125 | | FIXP_DBL loudnessNormalizationGainDb; |
126 | | FIXP_SGL compress; |
127 | | FIXP_SGL boost; |
128 | | } NODE_MODIFICATION; |
129 | | |
130 | | static DRC_ERROR _getCicpCharacteristic( |
131 | | const int cicpCharacteristic, |
132 | | CHARACTERISTIC_FORMAT pCharacteristicFormat[2], |
133 | 0 | const CUSTOM_DRC_CHAR* pCCharSource[2]) { |
134 | 0 | if ((cicpCharacteristic < 1) || (cicpCharacteristic > 11)) { |
135 | 0 | return DE_NOT_OK; |
136 | 0 | } |
137 | | |
138 | 0 | if (cicpCharacteristic < 7) { /* sigmoid characteristic */ |
139 | 0 | pCharacteristicFormat[CS_LEFT] = CF_SIGMOID; |
140 | 0 | pCCharSource[CS_LEFT] = |
141 | 0 | (const CUSTOM_DRC_CHAR*)(&cicpDrcCharSigmoidLeft[cicpCharacteristic - |
142 | 0 | 1]); |
143 | 0 | pCharacteristicFormat[CS_RIGHT] = CF_SIGMOID; |
144 | 0 | pCCharSource[CS_RIGHT] = |
145 | 0 | (const CUSTOM_DRC_CHAR*)(&cicpDrcCharSigmoidRight[cicpCharacteristic - |
146 | 0 | 1]); |
147 | 0 | } else { /* nodes characteristic */ |
148 | 0 | pCharacteristicFormat[CS_LEFT] = CF_NODES; |
149 | 0 | pCCharSource[CS_LEFT] = |
150 | 0 | (const CUSTOM_DRC_CHAR*)(&cicpDrcCharNodesLeft[cicpCharacteristic - 7]); |
151 | 0 | pCharacteristicFormat[CS_RIGHT] = CF_NODES; |
152 | 0 | pCCharSource[CS_RIGHT] = |
153 | 0 | (const CUSTOM_DRC_CHAR*)(&cicpDrcCharNodesRight[cicpCharacteristic - |
154 | 0 | 7]); |
155 | 0 | } |
156 | 0 | return DE_OK; |
157 | 0 | } |
158 | | |
159 | 0 | static int _getSign(FIXP_SGL in) { |
160 | 0 | if (in > (FIXP_DBL)0) return 1; |
161 | 0 | if (in < (FIXP_DBL)0) return -1; |
162 | 0 | return 0; |
163 | 0 | } |
164 | | |
165 | | static DRC_ERROR _getSlopeSign(const CHARACTERISTIC_FORMAT drcCharFormat, |
166 | 0 | const CUSTOM_DRC_CHAR* pCChar, int* pSlopeSign) { |
167 | 0 | if (drcCharFormat == CF_SIGMOID) { |
168 | 0 | *pSlopeSign = (pCChar->sigmoid.flipSign ? 1 : -1); |
169 | 0 | } else { |
170 | 0 | int k, slopeSign = 0, tmp_slopeSign; |
171 | 0 | for (k = 0; k < pCChar->nodes.characteristicNodeCount; k++) { |
172 | 0 | if (pCChar->nodes.nodeLevel[k + 1] > pCChar->nodes.nodeLevel[k]) { |
173 | 0 | tmp_slopeSign = |
174 | 0 | _getSign(pCChar->nodes.nodeGain[k + 1] - pCChar->nodes.nodeGain[k]); |
175 | 0 | } else { |
176 | 0 | tmp_slopeSign = -_getSign(pCChar->nodes.nodeGain[k + 1] - |
177 | 0 | pCChar->nodes.nodeGain[k]); |
178 | 0 | } |
179 | 0 | if ((slopeSign || tmp_slopeSign) && (slopeSign == -tmp_slopeSign)) |
180 | 0 | return DE_NOT_OK; /* DRC characteristic is not invertible */ |
181 | 0 | else |
182 | 0 | slopeSign = tmp_slopeSign; |
183 | 0 | } |
184 | 0 | *pSlopeSign = slopeSign; |
185 | 0 | } |
186 | 0 | return DE_OK; |
187 | 0 | } |
188 | | |
189 | | static DRC_ERROR _isSlopeNegative(const CHARACTERISTIC_FORMAT drcCharFormat[2], |
190 | | const CUSTOM_DRC_CHAR* pCChar[2], |
191 | 0 | int* pSlopeIsNegative) { |
192 | 0 | DRC_ERROR err = DE_OK; |
193 | 0 | int slopeSign[2] = {0, 0}; |
194 | |
|
195 | 0 | err = _getSlopeSign(drcCharFormat[CS_LEFT], pCChar[CS_LEFT], |
196 | 0 | &slopeSign[CS_LEFT]); |
197 | 0 | if (err) return err; |
198 | | |
199 | 0 | err = _getSlopeSign(drcCharFormat[CS_RIGHT], pCChar[CS_RIGHT], |
200 | 0 | &slopeSign[CS_RIGHT]); |
201 | 0 | if (err) return err; |
202 | | |
203 | 0 | if ((slopeSign[CS_LEFT] || slopeSign[CS_RIGHT]) && |
204 | 0 | (slopeSign[CS_LEFT] == -slopeSign[CS_RIGHT])) |
205 | 0 | return DE_NOT_OK; /* DRC characteristic is not invertible */ |
206 | | |
207 | 0 | *pSlopeIsNegative = (slopeSign[CS_LEFT] < 0); |
208 | 0 | return DE_OK; |
209 | 0 | } |
210 | | |
211 | | static DRC_ERROR _prepareDrcCharacteristic(const DRC_CHARACTERISTIC* pDChar, |
212 | | DRC_COEFFICIENTS_UNI_DRC* pCoef, |
213 | | const int b, |
214 | 0 | NODE_MODIFICATION* pNodeMod) { |
215 | 0 | DRC_ERROR err = DE_OK; |
216 | 0 | pNodeMod->drcCharacteristicPresent = pDChar->present; |
217 | 0 | if (pNodeMod->drcCharacteristicPresent) { |
218 | 0 | if (pDChar->isCICP == 1) { |
219 | 0 | err = _getCicpCharacteristic(pDChar->cicpIndex, |
220 | 0 | pNodeMod->characteristicFormatSource, |
221 | 0 | pNodeMod->pCCharSource); |
222 | 0 | if (err) return err; |
223 | 0 | } else { |
224 | 0 | pNodeMod->characteristicFormatSource[CS_LEFT] = |
225 | 0 | (CHARACTERISTIC_FORMAT) |
226 | 0 | pCoef->characteristicLeftFormat[pDChar->custom.left]; |
227 | 0 | pNodeMod->pCCharSource[CS_LEFT] = |
228 | 0 | &(pCoef->customCharacteristicLeft[pDChar->custom.left]); |
229 | 0 | pNodeMod->characteristicFormatSource[CS_RIGHT] = |
230 | 0 | (CHARACTERISTIC_FORMAT) |
231 | 0 | pCoef->characteristicRightFormat[pDChar->custom.right]; |
232 | 0 | pNodeMod->pCCharSource[CS_RIGHT] = |
233 | 0 | &(pCoef->customCharacteristicRight[pDChar->custom.right]); |
234 | 0 | } |
235 | 0 | err = _isSlopeNegative(pNodeMod->characteristicFormatSource, |
236 | 0 | pNodeMod->pCCharSource, &pNodeMod->slopeIsNegative); |
237 | 0 | if (err) return err; |
238 | | |
239 | 0 | if (pNodeMod->pGMod != NULL) { |
240 | 0 | if (pNodeMod->pGMod[b].targetCharacteristicLeftPresent) { |
241 | 0 | pNodeMod->characteristicFormatTarget[CS_LEFT] = |
242 | 0 | (CHARACTERISTIC_FORMAT)pCoef->characteristicLeftFormat |
243 | 0 | [pNodeMod->pGMod[b].targetCharacteristicLeftIndex]; |
244 | 0 | pNodeMod->pCCharTarget[CS_LEFT] = |
245 | 0 | &(pCoef->customCharacteristicLeft |
246 | 0 | [pNodeMod->pGMod[b].targetCharacteristicLeftIndex]); |
247 | 0 | } |
248 | 0 | if (pNodeMod->pGMod[b].targetCharacteristicRightPresent) { |
249 | 0 | pNodeMod->characteristicFormatTarget[CS_RIGHT] = |
250 | 0 | (CHARACTERISTIC_FORMAT)pCoef->characteristicRightFormat |
251 | 0 | [pNodeMod->pGMod[b].targetCharacteristicRightIndex]; |
252 | 0 | pNodeMod->pCCharTarget[CS_RIGHT] = |
253 | 0 | &(pCoef->customCharacteristicRight |
254 | 0 | [pNodeMod->pGMod[b].targetCharacteristicRightIndex]); |
255 | 0 | } |
256 | 0 | } |
257 | 0 | } |
258 | 0 | return DE_OK; |
259 | 0 | } |
260 | | |
261 | | static DRC_ERROR _compressorIO_sigmoid_common( |
262 | | const FIXP_DBL tmp, /* e = 7 */ |
263 | | const FIXP_DBL gainDbLimit, /* e = 6 */ |
264 | | const FIXP_DBL exp, /* e = 5 */ |
265 | | const int inverse, FIXP_DBL* out) /* e = 7 */ |
266 | 0 | { |
267 | 0 | FIXP_DBL x, tmp1, tmp2, invExp, denom; |
268 | 0 | int e_x, e_tmp1, e_tmp2, e_invExp, e_denom, e_out; |
269 | |
|
270 | 0 | if (exp < FL2FXCONST_DBL(1.0f / (float)(1 << 5))) { |
271 | 0 | return DE_NOT_OK; |
272 | 0 | } |
273 | | |
274 | | /* x = tmp / gainDbLimit; */ |
275 | 0 | x = fDivNormSigned(tmp, gainDbLimit, &e_x); |
276 | 0 | e_x += 7 - 6; |
277 | 0 | if (x < (FIXP_DBL)0) { |
278 | 0 | return DE_NOT_OK; |
279 | 0 | } |
280 | | |
281 | | /* out = tmp / pow(1.0f +/- pow(x, exp), 1.0f/exp); */ |
282 | 0 | tmp1 = fPow(x, e_x, exp, 5, &e_tmp1); |
283 | 0 | if (inverse) tmp1 = -tmp1; |
284 | 0 | tmp2 = fAddNorm(FL2FXCONST_DBL(1.0f / (float)(1 << 1)), 1, tmp1, e_tmp1, |
285 | 0 | &e_tmp2); |
286 | 0 | invExp = fDivNorm(FL2FXCONST_DBL(1.0f / (float)(1 << 1)), exp, &e_invExp); |
287 | 0 | e_invExp += 1 - 5; |
288 | 0 | if (tmp2 < (FIXP_DBL)0) { |
289 | 0 | return DE_NOT_OK; |
290 | 0 | } |
291 | 0 | denom = fPow(tmp2, e_tmp2, invExp, e_invExp, &e_denom); |
292 | 0 | *out = fDivNormSigned(tmp, denom, &e_out); |
293 | 0 | e_out += 7 - e_denom; |
294 | 0 | *out = scaleValueSaturate(*out, e_out - 7); |
295 | 0 | return DE_OK; |
296 | 0 | } |
297 | | |
298 | | static DRC_ERROR _compressorIO_sigmoid(const CUSTOM_DRC_CHAR_SIGMOID* pCChar, |
299 | | const FIXP_DBL inLevelDb, /* e = 7 */ |
300 | | FIXP_DBL* outGainDb) /* e = 7 */ |
301 | 0 | { |
302 | 0 | FIXP_DBL tmp; |
303 | 0 | FIXP_SGL exp = pCChar->exp; |
304 | 0 | DRC_ERROR err = DE_OK; |
305 | |
|
306 | 0 | tmp = fMultDiv2((DRC_INPUT_LOUDNESS_TARGET >> 1) - (inLevelDb >> 1), |
307 | 0 | pCChar->ioRatio); |
308 | 0 | tmp = SATURATE_LEFT_SHIFT(tmp, 2 + 1 + 1, DFRACT_BITS); |
309 | 0 | if (exp < (FIXP_SGL)MAXVAL_SGL) { |
310 | | /* x = tmp / gainDbLimit; */ |
311 | | /* *outGainDb = tmp / pow(1.0f + pow(x, exp), 1.0f/exp); */ |
312 | 0 | err = _compressorIO_sigmoid_common(tmp, FX_SGL2FX_DBL(pCChar->gain), |
313 | 0 | FX_SGL2FX_DBL(exp), 0, outGainDb); |
314 | 0 | if (err) return err; |
315 | 0 | } else { |
316 | 0 | *outGainDb = |
317 | 0 | tmp; /* scaling of outGainDb (7) is equal to scaling of tmp (7) */ |
318 | 0 | } |
319 | 0 | if (pCChar->flipSign == 1) { |
320 | 0 | *outGainDb = -*outGainDb; |
321 | 0 | } |
322 | 0 | return err; |
323 | 0 | } |
324 | | |
325 | | static DRC_ERROR _compressorIO_sigmoid_inverse( |
326 | | const CUSTOM_DRC_CHAR_SIGMOID* pCChar, const FIXP_SGL gainDb, |
327 | 0 | FIXP_DBL* inLev) { |
328 | 0 | DRC_ERROR err = DE_OK; |
329 | 0 | FIXP_SGL ioRatio = pCChar->ioRatio; |
330 | 0 | FIXP_SGL exp = pCChar->exp; |
331 | 0 | FIXP_DBL tmp = FX_SGL2FX_DBL(gainDb), tmp_out; |
332 | 0 | int e_out; |
333 | |
|
334 | 0 | if (pCChar->flipSign == 1) { |
335 | 0 | tmp = -tmp; |
336 | 0 | } |
337 | 0 | if (exp < (FIXP_SGL)MAXVAL_SGL) { |
338 | | /* x = tmp / gainDbLimit; */ |
339 | | /* tmp = tmp / pow(1.0f - pow(x, exp), 1.0f / exp); */ |
340 | 0 | err = _compressorIO_sigmoid_common(tmp, FX_SGL2FX_DBL(pCChar->gain), |
341 | 0 | FX_SGL2FX_DBL(exp), 1, &tmp); |
342 | 0 | if (err) return err; |
343 | 0 | } |
344 | 0 | if (ioRatio == (FIXP_SGL)0) { |
345 | 0 | return DE_NOT_OK; |
346 | 0 | } |
347 | 0 | tmp_out = fDivNormSigned(tmp, FX_SGL2FX_DBL(ioRatio), &e_out); |
348 | 0 | e_out += 7 - 2; |
349 | 0 | tmp_out = fAddNorm(DRC_INPUT_LOUDNESS_TARGET, 7, -tmp_out, e_out, &e_out); |
350 | 0 | *inLev = scaleValueSaturate(tmp_out, e_out - 7); |
351 | |
|
352 | 0 | return err; |
353 | 0 | } |
354 | | |
355 | | static DRC_ERROR _compressorIO_nodes(const CUSTOM_DRC_CHAR_NODES* pCChar, |
356 | | const FIXP_DBL inLevelDb, /* e = 7 */ |
357 | | FIXP_DBL* outGainDb) /* e = 7 */ |
358 | 0 | { |
359 | 0 | int n; |
360 | 0 | FIXP_DBL w; |
361 | 0 | const FIXP_SGL* nodeLevel = pCChar->nodeLevel; |
362 | 0 | const FIXP_SGL* nodeGain = pCChar->nodeGain; |
363 | |
|
364 | 0 | if (inLevelDb < DRC_INPUT_LOUDNESS_TARGET) { |
365 | 0 | for (n = 0; n < pCChar->characteristicNodeCount; n++) { |
366 | 0 | if ((inLevelDb <= FX_SGL2FX_DBL(nodeLevel[n])) && |
367 | 0 | (inLevelDb > FX_SGL2FX_DBL(nodeLevel[n + 1]))) { |
368 | 0 | w = fDivNorm(inLevelDb - FX_SGL2FX_DBL(nodeLevel[n + 1]), |
369 | 0 | FX_SGL2FX_DBL(nodeLevel[n] - nodeLevel[n + 1])); |
370 | 0 | *outGainDb = fMult(w, nodeGain[n]) + |
371 | 0 | fMult((FIXP_DBL)MAXVAL_DBL - w, nodeGain[n + 1]); |
372 | | /* *outGainDb = (w * nodeGain[n] + (1.0-w) * nodeGain[n+1]); */ |
373 | 0 | return DE_OK; |
374 | 0 | } |
375 | 0 | } |
376 | 0 | } else { |
377 | 0 | for (n = 0; n < pCChar->characteristicNodeCount; n++) { |
378 | 0 | if ((inLevelDb >= FX_SGL2FX_DBL(nodeLevel[n])) && |
379 | 0 | (inLevelDb < FX_SGL2FX_DBL(nodeLevel[n + 1]))) { |
380 | 0 | w = fDivNorm(FX_SGL2FX_DBL(nodeLevel[n + 1]) - inLevelDb, |
381 | 0 | FX_SGL2FX_DBL(nodeLevel[n + 1] - nodeLevel[n])); |
382 | 0 | *outGainDb = fMult(w, nodeGain[n]) + |
383 | 0 | fMult((FIXP_DBL)MAXVAL_DBL - w, nodeGain[n + 1]); |
384 | | /* *outGainDb = (w * nodeGain[n] + (1.0-w) * nodeGain[n+1]); */ |
385 | 0 | return DE_OK; |
386 | 0 | } |
387 | 0 | } |
388 | 0 | } |
389 | 0 | *outGainDb = FX_SGL2FX_DBL(nodeGain[pCChar->characteristicNodeCount]); |
390 | 0 | return DE_OK; |
391 | 0 | } |
392 | | |
393 | | static DRC_ERROR _compressorIO_nodes_inverse( |
394 | | const CUSTOM_DRC_CHAR_NODES* pCChar, const FIXP_SGL gainDb, /* e = 7 */ |
395 | | FIXP_DBL* inLev) /* e = 7 */ |
396 | 0 | { |
397 | 0 | int n; |
398 | 0 | int k; |
399 | 0 | FIXP_DBL w; |
400 | 0 | int gainIsNegative = 0; |
401 | 0 | const FIXP_SGL* nodeLevel = pCChar->nodeLevel; |
402 | 0 | const FIXP_SGL* nodeGain = pCChar->nodeGain; |
403 | 0 | int nodeCount = pCChar->characteristicNodeCount; |
404 | 0 | for (k = 0; k < nodeCount; k++) { |
405 | 0 | if (pCChar->nodeGain[k + 1] < (FIXP_SGL)0) { |
406 | 0 | gainIsNegative = 1; |
407 | 0 | } |
408 | 0 | } |
409 | 0 | if (gainIsNegative == 1) { |
410 | 0 | if (gainDb <= nodeGain[nodeCount]) { |
411 | 0 | *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]); |
412 | 0 | } else { |
413 | 0 | if (gainDb >= (FIXP_SGL)0) { |
414 | 0 | *inLev = DRC_INPUT_LOUDNESS_TARGET; |
415 | 0 | } else { |
416 | 0 | for (n = 0; n < nodeCount; n++) { |
417 | 0 | if ((gainDb <= nodeGain[n]) && (gainDb > nodeGain[n + 1])) { |
418 | 0 | FIXP_SGL gainDelta = nodeGain[n] - nodeGain[n + 1]; |
419 | 0 | if (gainDelta == (FIXP_SGL)0) { |
420 | 0 | *inLev = FX_SGL2FX_DBL(nodeLevel[n]); |
421 | 0 | return DE_OK; |
422 | 0 | } |
423 | 0 | w = fDivNorm(gainDb - nodeGain[n + 1], gainDelta); |
424 | 0 | *inLev = fMult(w, nodeLevel[n]) + |
425 | 0 | fMult((FIXP_DBL)MAXVAL_DBL - w, nodeLevel[n + 1]); |
426 | | /* *inLev = (w * nodeLevel[n] + (1.0-w) * nodeLevel[n+1]); */ |
427 | 0 | return DE_OK; |
428 | 0 | } |
429 | 0 | } |
430 | 0 | *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]); |
431 | 0 | } |
432 | 0 | } |
433 | 0 | } else { |
434 | 0 | if (gainDb >= nodeGain[nodeCount]) { |
435 | 0 | *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]); |
436 | 0 | } else { |
437 | 0 | if (gainDb <= (FIXP_SGL)0) { |
438 | 0 | *inLev = DRC_INPUT_LOUDNESS_TARGET; |
439 | 0 | } else { |
440 | 0 | for (n = 0; n < nodeCount; n++) { |
441 | 0 | if ((gainDb >= nodeGain[n]) && (gainDb < nodeGain[n + 1])) { |
442 | 0 | FIXP_SGL gainDelta = nodeGain[n + 1] - nodeGain[n]; |
443 | 0 | if (gainDelta == (FIXP_SGL)0) { |
444 | 0 | *inLev = FX_SGL2FX_DBL(nodeLevel[n]); |
445 | 0 | return DE_OK; |
446 | 0 | } |
447 | 0 | w = fDivNorm(nodeGain[n + 1] - gainDb, gainDelta); |
448 | 0 | *inLev = fMult(w, nodeLevel[n]) + |
449 | 0 | fMult((FIXP_DBL)MAXVAL_DBL - w, nodeLevel[n + 1]); |
450 | | /* *inLev = (w * nodeLevel[n] + (1.0-w) * nodeLevel[n+1]); */ |
451 | 0 | return DE_OK; |
452 | 0 | } |
453 | 0 | } |
454 | 0 | *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]); |
455 | 0 | } |
456 | 0 | } |
457 | 0 | } |
458 | 0 | return DE_OK; |
459 | 0 | } |
460 | | |
461 | | static DRC_ERROR _mapGain(const CHARACTERISTIC_FORMAT pCCharFormatSource, |
462 | | const CUSTOM_DRC_CHAR* pCCharSource, |
463 | | const CHARACTERISTIC_FORMAT pCCharFormatTarget, |
464 | | const CUSTOM_DRC_CHAR* pCCharTarget, |
465 | | const FIXP_SGL gainInDb, /* e = 7 */ |
466 | | FIXP_DBL* gainOutDb) /* e = 7 */ |
467 | 0 | { |
468 | 0 | FIXP_DBL inLevel = (FIXP_DBL)0; |
469 | 0 | DRC_ERROR err = DE_OK; |
470 | |
|
471 | 0 | switch (pCCharFormatSource) { |
472 | 0 | case CF_SIGMOID: |
473 | 0 | err = _compressorIO_sigmoid_inverse( |
474 | 0 | (const CUSTOM_DRC_CHAR_SIGMOID*)pCCharSource, gainInDb, &inLevel); |
475 | 0 | if (err) return err; |
476 | 0 | break; |
477 | 0 | case CF_NODES: |
478 | 0 | err = _compressorIO_nodes_inverse( |
479 | 0 | (const CUSTOM_DRC_CHAR_NODES*)pCCharSource, gainInDb, &inLevel); |
480 | 0 | if (err) return err; |
481 | 0 | break; |
482 | 0 | default: |
483 | 0 | return DE_NOT_OK; |
484 | 0 | } |
485 | 0 | switch (pCCharFormatTarget) { |
486 | 0 | case CF_SIGMOID: |
487 | 0 | err = _compressorIO_sigmoid((const CUSTOM_DRC_CHAR_SIGMOID*)pCCharTarget, |
488 | 0 | inLevel, gainOutDb); |
489 | 0 | if (err) return err; |
490 | 0 | break; |
491 | 0 | case CF_NODES: |
492 | 0 | err = _compressorIO_nodes((const CUSTOM_DRC_CHAR_NODES*)pCCharTarget, |
493 | 0 | inLevel, gainOutDb); |
494 | 0 | if (err) return err; |
495 | 0 | break; |
496 | 0 | default: |
497 | 0 | break; |
498 | 0 | } |
499 | 0 | return DE_OK; |
500 | 0 | } |
501 | | |
502 | | static DRC_ERROR _toLinear( |
503 | | const NODE_MODIFICATION* nodeMod, const int drcBand, |
504 | | const FIXP_SGL gainDb, /* in: gain value in dB, e = 7 */ |
505 | | const FIXP_SGL slopeDb, /* in: slope value in dB/deltaTmin, e = 2 */ |
506 | | FIXP_DBL* gainLin, /* out: linear gain value, e = 7 */ |
507 | | FIXP_DBL* slopeLin) /* out: linear slope value, e = 7 */ |
508 | 0 | { |
509 | 0 | FIXP_DBL gainRatio_m = FL2FXCONST_DBL(1.0f / (float)(1 << 1)); |
510 | 0 | GAIN_MODIFICATION* pGMod = NULL; |
511 | 0 | DUCKING_MODIFICATION* pDMod = nodeMod->pDMod; |
512 | 0 | FIXP_DBL tmp_dbl, gainDb_modified, gainDb_offset, gainDb_out, gainLin_m, |
513 | 0 | slopeLin_m; |
514 | 0 | int gainLin_e, gainRatio_e = 1, gainDb_out_e; |
515 | 0 | if (nodeMod->pGMod != NULL) { |
516 | 0 | pGMod = &(nodeMod->pGMod[drcBand]); |
517 | 0 | } |
518 | 0 | if (((nodeMod->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) == 0) && |
519 | 0 | (nodeMod->drcSetEffect != EB_FADE) && |
520 | 0 | (nodeMod->drcSetEffect != EB_CLIPPING)) { |
521 | 0 | DRC_ERROR err = DE_OK; |
522 | 0 | FIXP_DBL gainDbMapped; |
523 | |
|
524 | 0 | if ((pGMod != NULL) && (nodeMod->drcCharacteristicPresent)) { |
525 | 0 | if (((gainDb > (FIXP_SGL)0) && nodeMod->slopeIsNegative) || |
526 | 0 | ((gainDb < (FIXP_SGL)0) && !nodeMod->slopeIsNegative)) { |
527 | | /* left side */ |
528 | 0 | if (pGMod->targetCharacteristicLeftPresent == 1) { |
529 | 0 | err = _mapGain(nodeMod->characteristicFormatSource[CS_LEFT], |
530 | 0 | nodeMod->pCCharSource[CS_LEFT], |
531 | 0 | nodeMod->characteristicFormatTarget[CS_LEFT], |
532 | 0 | nodeMod->pCCharTarget[CS_LEFT], gainDb, &gainDbMapped); |
533 | 0 | if (err) return err; |
534 | 0 | gainRatio_m = fDivNormSigned( |
535 | 0 | gainDbMapped, FX_SGL2FX_DBL(gainDb), |
536 | 0 | &gainRatio_e); /* target characteristic in payload */ |
537 | 0 | } |
538 | 0 | } |
539 | | |
540 | 0 | else { /* if (((gainDb < (FIXP_SGL)0) && nodeMod->slopeIsNegative) || |
541 | | ((gainDb > (FIXP_SGL)0) && !nodeMod->slopeIsNegative)) */ |
542 | | |
543 | | /* right side */ |
544 | 0 | if (pGMod->targetCharacteristicRightPresent == 1) { |
545 | 0 | err = |
546 | 0 | _mapGain(nodeMod->characteristicFormatSource[CS_RIGHT], |
547 | 0 | nodeMod->pCCharSource[CS_RIGHT], |
548 | 0 | nodeMod->characteristicFormatTarget[CS_RIGHT], |
549 | 0 | nodeMod->pCCharTarget[CS_RIGHT], gainDb, &gainDbMapped); |
550 | 0 | if (err) return err; |
551 | 0 | gainRatio_m = fDivNormSigned( |
552 | 0 | gainDbMapped, FX_SGL2FX_DBL(gainDb), |
553 | 0 | &gainRatio_e); /* target characteristic in payload */ |
554 | 0 | } |
555 | 0 | } |
556 | 0 | } |
557 | 0 | if (gainDb < (FIXP_SGL)0) { |
558 | 0 | gainRatio_m = fMultDiv2(gainRatio_m, nodeMod->compress); |
559 | 0 | } else { |
560 | 0 | gainRatio_m = fMultDiv2(gainRatio_m, nodeMod->boost); |
561 | 0 | } |
562 | 0 | gainRatio_e += 2; |
563 | 0 | } |
564 | 0 | if ((pGMod != NULL) && (pGMod->gainScalingPresent == 1)) { |
565 | 0 | if (gainDb < (FIXP_SGL)0) { |
566 | 0 | gainRatio_m = fMultDiv2(gainRatio_m, pGMod->attenuationScaling); |
567 | 0 | } else { |
568 | 0 | gainRatio_m = fMultDiv2(gainRatio_m, pGMod->amplificationScaling); |
569 | 0 | } |
570 | 0 | gainRatio_e += 3; |
571 | 0 | } |
572 | 0 | if ((pDMod != NULL) && |
573 | 0 | (nodeMod->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) && |
574 | 0 | (pDMod->duckingScalingPresent == 1)) { |
575 | 0 | gainRatio_m = fMultDiv2(gainRatio_m, pDMod->duckingScaling); |
576 | 0 | gainRatio_e += 3; |
577 | 0 | } |
578 | |
|
579 | 0 | gainDb_modified = |
580 | 0 | fMultDiv2(gainDb, gainRatio_m); /* resulting e: 7 + gainRatio_e + 1*/ |
581 | 0 | gainDb_offset = (FIXP_DBL)0; |
582 | |
|
583 | 0 | if ((pGMod != NULL) && (pGMod->gainOffsetPresent == 1)) { |
584 | | /* *gainLin *= (float)pow(2.0, (double)(pGMod->gainOffset/6.0f)); */ |
585 | 0 | gainDb_offset += FX_SGL2FX_DBL(pGMod->gainOffset) >> 4; /* resulting e: 8 */ |
586 | 0 | } |
587 | 0 | if ((nodeMod->limiterPeakTargetPresent == 1) && |
588 | 0 | (nodeMod->drcSetEffect == |
589 | 0 | EB_CLIPPING)) { /* The only drcSetEffect is "clipping prevention" */ |
590 | | /* loudnessNormalizationGainModificationDb is included in |
591 | | * loudnessNormalizationGainDb */ |
592 | | /* *gainLin *= (float)pow(2.0, max(0.0, -nodeModification->limiterPeakTarget |
593 | | * - nodeModification->loudnessNormalizationGainDb)/6.0); */ |
594 | 0 | gainDb_offset += fMax( |
595 | 0 | (FIXP_DBL)0, |
596 | 0 | (FX_SGL2FX_DBL(-nodeMod->limiterPeakTarget) >> 3) - |
597 | 0 | (nodeMod->loudnessNormalizationGainDb >> 1)); /* resulting e: 8 */ |
598 | 0 | } |
599 | 0 | if (gainDb_offset != (FIXP_DBL)0) { |
600 | 0 | gainDb_out = fAddNorm(gainDb_modified, 7 + gainRatio_e + 1, gainDb_offset, |
601 | 0 | 8, &gainDb_out_e); |
602 | 0 | } else { |
603 | 0 | gainDb_out = gainDb_modified; |
604 | 0 | gainDb_out_e = 7 + gainRatio_e + 1; |
605 | 0 | } |
606 | | |
607 | | /* *gainLin = (float)pow(2.0, (double)(gainDb_modified[1] / 6.0f)); */ |
608 | 0 | gainLin_m = approxDb2lin(gainDb_out, gainDb_out_e, &gainLin_e); |
609 | 0 | *gainLin = scaleValueSaturate(gainLin_m, gainLin_e - 7); |
610 | | |
611 | | /* *slopeLin = SLOPE_FACTOR_DB_TO_LINEAR * gainRatio * *gainLin * slopeDb; */ |
612 | 0 | if (slopeDb == (FIXP_SGL)0) { |
613 | 0 | *slopeLin = (FIXP_DBL)0; |
614 | 0 | } else { |
615 | 0 | tmp_dbl = |
616 | 0 | fMult(slopeDb, SLOPE_FACTOR_DB_TO_LINEAR); /* resulting e: 2 - 3 = -1 */ |
617 | 0 | tmp_dbl = fMult(tmp_dbl, gainRatio_m); /* resulting e: -1 + gainRatio_e */ |
618 | 0 | if (gainDb_offset != |
619 | 0 | (FIXP_DBL)0) { /* recalculate gainLin from gainDb that wasn't modified |
620 | | by gainOffset and limiterPeakTarget */ |
621 | 0 | gainLin_m = approxDb2lin(gainDb_modified, 7 + gainRatio_e, &gainLin_e); |
622 | 0 | } |
623 | 0 | slopeLin_m = fMult(tmp_dbl, gainLin_m); |
624 | 0 | *slopeLin = |
625 | 0 | scaleValueSaturate(slopeLin_m, -1 + gainRatio_e + gainLin_e - 7); |
626 | 0 | } |
627 | |
|
628 | 0 | if ((nodeMod->limiterPeakTargetPresent == 1) && |
629 | 0 | (nodeMod->drcSetEffect == EB_CLIPPING)) { |
630 | 0 | if (*gainLin >= FL2FXCONST_DBL(1.0f / (float)(1 << 7))) { |
631 | 0 | *gainLin = FL2FXCONST_DBL(1.0f / (float)(1 << 7)); |
632 | 0 | *slopeLin = (FIXP_DBL)0; |
633 | 0 | } |
634 | 0 | } |
635 | |
|
636 | 0 | return DE_OK; |
637 | 0 | } |
638 | | |
639 | | /* prepare buffers containing linear nodes for each gain sequence */ |
640 | | DRC_ERROR |
641 | | prepareDrcGain(HANDLE_DRC_GAIN_DECODER hGainDec, |
642 | | HANDLE_UNI_DRC_GAIN hUniDrcGain, const FIXP_SGL compress, |
643 | | const FIXP_SGL boost, const FIXP_DBL loudnessNormalizationGainDb, |
644 | 0 | const int activeDrcIndex) { |
645 | 0 | int b, g, gainElementIndex; |
646 | 0 | DRC_GAIN_BUFFERS* drcGainBuffers = &(hGainDec->drcGainBuffers); |
647 | 0 | NODE_MODIFICATION nodeMod; |
648 | 0 | FDKmemclear(&nodeMod, sizeof(NODE_MODIFICATION)); |
649 | 0 | ACTIVE_DRC* pActiveDrc = &(hGainDec->activeDrc[activeDrcIndex]); |
650 | 0 | DRC_INSTRUCTIONS_UNI_DRC* pInst = pActiveDrc->pInst; |
651 | 0 | if (pInst == NULL) return DE_NOT_OK; |
652 | | |
653 | 0 | nodeMod.drcSetEffect = pInst->drcSetEffect; |
654 | |
|
655 | 0 | nodeMod.compress = compress; |
656 | 0 | nodeMod.boost = boost; |
657 | 0 | nodeMod.loudnessNormalizationGainDb = loudnessNormalizationGainDb; |
658 | 0 | nodeMod.limiterPeakTargetPresent = pInst->limiterPeakTargetPresent; |
659 | 0 | nodeMod.limiterPeakTarget = pInst->limiterPeakTarget; |
660 | |
|
661 | 0 | gainElementIndex = 0; |
662 | 0 | for (g = 0; g < pInst->nDrcChannelGroups; g++) { |
663 | 0 | int gainSetIndex = 0; |
664 | 0 | int nDrcBands = 0; |
665 | 0 | DRC_COEFFICIENTS_UNI_DRC* pCoef = pActiveDrc->pCoef; |
666 | 0 | if (pCoef == NULL) return DE_NOT_OK; |
667 | | |
668 | 0 | if (!pActiveDrc->channelGroupIsParametricDrc[g]) { |
669 | 0 | gainSetIndex = pInst->gainSetIndexForChannelGroup[g]; |
670 | |
|
671 | 0 | if (nodeMod.drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) { |
672 | 0 | nodeMod.pDMod = &(pActiveDrc->duckingModificationForChannelGroup[g]); |
673 | 0 | nodeMod.pGMod = NULL; |
674 | 0 | } else { |
675 | 0 | nodeMod.pGMod = pInst->gainModificationForChannelGroup[g]; |
676 | 0 | nodeMod.pDMod = NULL; |
677 | 0 | } |
678 | |
|
679 | 0 | nDrcBands = pActiveDrc->bandCountForChannelGroup[g]; |
680 | 0 | for (b = 0; b < nDrcBands; b++) { |
681 | 0 | DRC_ERROR err = DE_OK; |
682 | 0 | GAIN_SET* pGainSet = &(pCoef->gainSet[gainSetIndex]); |
683 | 0 | int seq = pGainSet->gainSequenceIndex[b]; |
684 | 0 | DRC_CHARACTERISTIC* pDChar = &(pGainSet->drcCharacteristic[b]); |
685 | | |
686 | | /* linearNodeBuffer contains a copy of the gain sequences (consisting of |
687 | | nodes) that are relevant for decoding. It also contains gain |
688 | | sequences of previous frames. */ |
689 | 0 | LINEAR_NODE_BUFFER* pLnb = |
690 | 0 | &(drcGainBuffers->linearNodeBuffer[pActiveDrc->activeDrcOffset + |
691 | 0 | gainElementIndex]); |
692 | 0 | int i, lnbp; |
693 | 0 | lnbp = drcGainBuffers->lnbPointer; |
694 | 0 | pLnb->gainInterpolationType = |
695 | 0 | (GAIN_INTERPOLATION_TYPE)pGainSet->gainInterpolationType; |
696 | |
|
697 | 0 | err = _prepareDrcCharacteristic(pDChar, pCoef, b, &nodeMod); |
698 | 0 | if (err) return err; |
699 | | |
700 | | /* copy a node buffer and convert from dB to linear */ |
701 | 0 | pLnb->nNodes[lnbp] = fMin((int)hUniDrcGain->nNodes[seq], 16); |
702 | 0 | for (i = 0; i < pLnb->nNodes[lnbp]; i++) { |
703 | 0 | FIXP_DBL gainLin, slopeLin; |
704 | 0 | err = _toLinear(&nodeMod, b, hUniDrcGain->gainNode[seq][i].gainDb, |
705 | 0 | (FIXP_SGL)0, &gainLin, &slopeLin); |
706 | 0 | if (err) return err; |
707 | 0 | pLnb->linearNode[lnbp][i].gainLin = gainLin; |
708 | 0 | pLnb->linearNode[lnbp][i].time = hUniDrcGain->gainNode[seq][i].time; |
709 | 0 | } |
710 | 0 | gainElementIndex++; |
711 | 0 | } |
712 | 0 | } else { |
713 | | /* parametric DRC not supported */ |
714 | 0 | gainElementIndex++; |
715 | 0 | } |
716 | 0 | } |
717 | 0 | return DE_OK; |
718 | 0 | } |