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