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 [email protected]
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 if (tmp2 < (FIXP_DBL)0) {
289 return DE_NOT_OK;
290 }
291 denom = fPow(tmp2, e_tmp2, invExp, e_invExp, &e_denom);
292 *out = fDivNormSigned(tmp, denom, &e_out);
293 e_out += 7 - e_denom;
294 *out = scaleValueSaturate(*out, e_out - 7);
295 return DE_OK;
296 }
297
_compressorIO_sigmoid(const CUSTOM_DRC_CHAR_SIGMOID * pCChar,const FIXP_DBL inLevelDb,FIXP_DBL * outGainDb)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 {
302 FIXP_DBL tmp;
303 FIXP_SGL exp = pCChar->exp;
304 DRC_ERROR err = DE_OK;
305
306 tmp = fMultDiv2((DRC_INPUT_LOUDNESS_TARGET >> 1) - (inLevelDb >> 1),
307 pCChar->ioRatio);
308 tmp = SATURATE_LEFT_SHIFT(tmp, 2 + 1 + 1, DFRACT_BITS);
309 if (exp < (FIXP_SGL)MAXVAL_SGL) {
310 /* x = tmp / gainDbLimit; */
311 /* *outGainDb = tmp / pow(1.0f + pow(x, exp), 1.0f/exp); */
312 err = _compressorIO_sigmoid_common(tmp, FX_SGL2FX_DBL(pCChar->gain),
313 FX_SGL2FX_DBL(exp), 0, outGainDb);
314 if (err) return err;
315 } else {
316 *outGainDb =
317 tmp; /* scaling of outGainDb (7) is equal to scaling of tmp (7) */
318 }
319 if (pCChar->flipSign == 1) {
320 *outGainDb = -*outGainDb;
321 }
322 return err;
323 }
324
_compressorIO_sigmoid_inverse(const CUSTOM_DRC_CHAR_SIGMOID * pCChar,const FIXP_SGL gainDb,FIXP_DBL * inLev)325 static DRC_ERROR _compressorIO_sigmoid_inverse(
326 const CUSTOM_DRC_CHAR_SIGMOID* pCChar, const FIXP_SGL gainDb,
327 FIXP_DBL* inLev) {
328 DRC_ERROR err = DE_OK;
329 FIXP_SGL ioRatio = pCChar->ioRatio;
330 FIXP_SGL exp = pCChar->exp;
331 FIXP_DBL tmp = FX_SGL2FX_DBL(gainDb), tmp_out;
332 int e_out;
333
334 if (pCChar->flipSign == 1) {
335 tmp = -tmp;
336 }
337 if (exp < (FIXP_SGL)MAXVAL_SGL) {
338 /* x = tmp / gainDbLimit; */
339 /* tmp = tmp / pow(1.0f - pow(x, exp), 1.0f / exp); */
340 err = _compressorIO_sigmoid_common(tmp, FX_SGL2FX_DBL(pCChar->gain),
341 FX_SGL2FX_DBL(exp), 1, &tmp);
342 if (err) return err;
343 }
344 if (ioRatio == (FIXP_SGL)0) {
345 return DE_NOT_OK;
346 }
347 tmp_out = fDivNormSigned(tmp, FX_SGL2FX_DBL(ioRatio), &e_out);
348 e_out += 7 - 2;
349 tmp_out = fAddNorm(DRC_INPUT_LOUDNESS_TARGET, 7, -tmp_out, e_out, &e_out);
350 *inLev = scaleValueSaturate(tmp_out, e_out - 7);
351
352 return err;
353 }
354
_compressorIO_nodes(const CUSTOM_DRC_CHAR_NODES * pCChar,const FIXP_DBL inLevelDb,FIXP_DBL * outGainDb)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 {
359 int n;
360 FIXP_DBL w;
361 const FIXP_SGL* nodeLevel = pCChar->nodeLevel;
362 const FIXP_SGL* nodeGain = pCChar->nodeGain;
363
364 if (inLevelDb < DRC_INPUT_LOUDNESS_TARGET) {
365 for (n = 0; n < pCChar->characteristicNodeCount; n++) {
366 if ((inLevelDb <= FX_SGL2FX_DBL(nodeLevel[n])) &&
367 (inLevelDb > FX_SGL2FX_DBL(nodeLevel[n + 1]))) {
368 w = fDivNorm(inLevelDb - FX_SGL2FX_DBL(nodeLevel[n + 1]),
369 FX_SGL2FX_DBL(nodeLevel[n] - nodeLevel[n + 1]));
370 *outGainDb = fMult(w, nodeGain[n]) +
371 fMult((FIXP_DBL)MAXVAL_DBL - w, nodeGain[n + 1]);
372 /* *outGainDb = (w * nodeGain[n] + (1.0-w) * nodeGain[n+1]); */
373 return DE_OK;
374 }
375 }
376 } else {
377 for (n = 0; n < pCChar->characteristicNodeCount; n++) {
378 if ((inLevelDb >= FX_SGL2FX_DBL(nodeLevel[n])) &&
379 (inLevelDb < FX_SGL2FX_DBL(nodeLevel[n + 1]))) {
380 w = fDivNorm(FX_SGL2FX_DBL(nodeLevel[n + 1]) - inLevelDb,
381 FX_SGL2FX_DBL(nodeLevel[n + 1] - nodeLevel[n]));
382 *outGainDb = fMult(w, nodeGain[n]) +
383 fMult((FIXP_DBL)MAXVAL_DBL - w, nodeGain[n + 1]);
384 /* *outGainDb = (w * nodeGain[n] + (1.0-w) * nodeGain[n+1]); */
385 return DE_OK;
386 }
387 }
388 }
389 *outGainDb = FX_SGL2FX_DBL(nodeGain[pCChar->characteristicNodeCount]);
390 return DE_OK;
391 }
392
_compressorIO_nodes_inverse(const CUSTOM_DRC_CHAR_NODES * pCChar,const FIXP_SGL gainDb,FIXP_DBL * inLev)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 {
397 int n;
398 int k;
399 FIXP_DBL w;
400 int gainIsNegative = 0;
401 const FIXP_SGL* nodeLevel = pCChar->nodeLevel;
402 const FIXP_SGL* nodeGain = pCChar->nodeGain;
403 int nodeCount = pCChar->characteristicNodeCount;
404 for (k = 0; k < nodeCount; k++) {
405 if (pCChar->nodeGain[k + 1] < (FIXP_SGL)0) {
406 gainIsNegative = 1;
407 }
408 }
409 if (gainIsNegative == 1) {
410 if (gainDb <= nodeGain[nodeCount]) {
411 *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
412 } else {
413 if (gainDb >= (FIXP_SGL)0) {
414 *inLev = DRC_INPUT_LOUDNESS_TARGET;
415 } else {
416 for (n = 0; n < nodeCount; n++) {
417 if ((gainDb <= nodeGain[n]) && (gainDb > nodeGain[n + 1])) {
418 FIXP_SGL gainDelta = nodeGain[n] - nodeGain[n + 1];
419 if (gainDelta == (FIXP_SGL)0) {
420 *inLev = FX_SGL2FX_DBL(nodeLevel[n]);
421 return DE_OK;
422 }
423 w = fDivNorm(gainDb - nodeGain[n + 1], gainDelta);
424 *inLev = fMult(w, nodeLevel[n]) +
425 fMult((FIXP_DBL)MAXVAL_DBL - w, nodeLevel[n + 1]);
426 /* *inLev = (w * nodeLevel[n] + (1.0-w) * nodeLevel[n+1]); */
427 return DE_OK;
428 }
429 }
430 *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
431 }
432 }
433 } else {
434 if (gainDb >= nodeGain[nodeCount]) {
435 *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
436 } else {
437 if (gainDb <= (FIXP_SGL)0) {
438 *inLev = DRC_INPUT_LOUDNESS_TARGET;
439 } else {
440 for (n = 0; n < nodeCount; n++) {
441 if ((gainDb >= nodeGain[n]) && (gainDb < nodeGain[n + 1])) {
442 FIXP_SGL gainDelta = nodeGain[n + 1] - nodeGain[n];
443 if (gainDelta == (FIXP_SGL)0) {
444 *inLev = FX_SGL2FX_DBL(nodeLevel[n]);
445 return DE_OK;
446 }
447 w = fDivNorm(nodeGain[n + 1] - gainDb, gainDelta);
448 *inLev = fMult(w, nodeLevel[n]) +
449 fMult((FIXP_DBL)MAXVAL_DBL - w, nodeLevel[n + 1]);
450 /* *inLev = (w * nodeLevel[n] + (1.0-w) * nodeLevel[n+1]); */
451 return DE_OK;
452 }
453 }
454 *inLev = FX_SGL2FX_DBL(nodeLevel[nodeCount]);
455 }
456 }
457 }
458 return DE_OK;
459 }
460
_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)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 {
468 FIXP_DBL inLevel = (FIXP_DBL)0;
469 DRC_ERROR err = DE_OK;
470
471 switch (pCCharFormatSource) {
472 case CF_SIGMOID:
473 err = _compressorIO_sigmoid_inverse(
474 (const CUSTOM_DRC_CHAR_SIGMOID*)pCCharSource, gainInDb, &inLevel);
475 if (err) return err;
476 break;
477 case CF_NODES:
478 err = _compressorIO_nodes_inverse(
479 (const CUSTOM_DRC_CHAR_NODES*)pCCharSource, gainInDb, &inLevel);
480 if (err) return err;
481 break;
482 default:
483 return DE_NOT_OK;
484 }
485 switch (pCCharFormatTarget) {
486 case CF_SIGMOID:
487 err = _compressorIO_sigmoid((const CUSTOM_DRC_CHAR_SIGMOID*)pCCharTarget,
488 inLevel, gainOutDb);
489 if (err) return err;
490 break;
491 case CF_NODES:
492 err = _compressorIO_nodes((const CUSTOM_DRC_CHAR_NODES*)pCCharTarget,
493 inLevel, gainOutDb);
494 if (err) return err;
495 break;
496 default:
497 break;
498 }
499 return DE_OK;
500 }
501
_toLinear(const NODE_MODIFICATION * nodeMod,const int drcBand,const FIXP_SGL gainDb,const FIXP_SGL slopeDb,FIXP_DBL * gainLin,FIXP_DBL * slopeLin)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 {
509 FIXP_DBL gainRatio_m = FL2FXCONST_DBL(1.0f / (float)(1 << 1));
510 GAIN_MODIFICATION* pGMod = NULL;
511 DUCKING_MODIFICATION* pDMod = nodeMod->pDMod;
512 FIXP_DBL tmp_dbl, gainDb_modified, gainDb_offset, gainDb_out, gainLin_m,
513 slopeLin_m;
514 int gainLin_e, gainRatio_e = 1, gainDb_out_e;
515 if (nodeMod->pGMod != NULL) {
516 pGMod = &(nodeMod->pGMod[drcBand]);
517 }
518 if (((nodeMod->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) == 0) &&
519 (nodeMod->drcSetEffect != EB_FADE) &&
520 (nodeMod->drcSetEffect != EB_CLIPPING)) {
521 DRC_ERROR err = DE_OK;
522 FIXP_DBL gainDbMapped;
523
524 if ((pGMod != NULL) && (nodeMod->drcCharacteristicPresent)) {
525 if (((gainDb > (FIXP_SGL)0) && nodeMod->slopeIsNegative) ||
526 ((gainDb < (FIXP_SGL)0) && !nodeMod->slopeIsNegative)) {
527 /* left side */
528 if (pGMod->targetCharacteristicLeftPresent == 1) {
529 err = _mapGain(nodeMod->characteristicFormatSource[CS_LEFT],
530 nodeMod->pCCharSource[CS_LEFT],
531 nodeMod->characteristicFormatTarget[CS_LEFT],
532 nodeMod->pCCharTarget[CS_LEFT], gainDb, &gainDbMapped);
533 if (err) return err;
534 gainRatio_m = fDivNormSigned(
535 gainDbMapped, FX_SGL2FX_DBL(gainDb),
536 &gainRatio_e); /* target characteristic in payload */
537 }
538 }
539
540 else { /* if (((gainDb < (FIXP_SGL)0) && nodeMod->slopeIsNegative) ||
541 ((gainDb > (FIXP_SGL)0) && !nodeMod->slopeIsNegative)) */
542
543 /* right side */
544 if (pGMod->targetCharacteristicRightPresent == 1) {
545 err =
546 _mapGain(nodeMod->characteristicFormatSource[CS_RIGHT],
547 nodeMod->pCCharSource[CS_RIGHT],
548 nodeMod->characteristicFormatTarget[CS_RIGHT],
549 nodeMod->pCCharTarget[CS_RIGHT], gainDb, &gainDbMapped);
550 if (err) return err;
551 gainRatio_m = fDivNormSigned(
552 gainDbMapped, FX_SGL2FX_DBL(gainDb),
553 &gainRatio_e); /* target characteristic in payload */
554 }
555 }
556 }
557 if (gainDb < (FIXP_SGL)0) {
558 gainRatio_m = fMultDiv2(gainRatio_m, nodeMod->compress);
559 } else {
560 gainRatio_m = fMultDiv2(gainRatio_m, nodeMod->boost);
561 }
562 gainRatio_e += 2;
563 }
564 if ((pGMod != NULL) && (pGMod->gainScalingPresent == 1)) {
565 if (gainDb < (FIXP_SGL)0) {
566 gainRatio_m = fMultDiv2(gainRatio_m, pGMod->attenuationScaling);
567 } else {
568 gainRatio_m = fMultDiv2(gainRatio_m, pGMod->amplificationScaling);
569 }
570 gainRatio_e += 3;
571 }
572 if ((pDMod != NULL) &&
573 (nodeMod->drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) &&
574 (pDMod->duckingScalingPresent == 1)) {
575 gainRatio_m = fMultDiv2(gainRatio_m, pDMod->duckingScaling);
576 gainRatio_e += 3;
577 }
578
579 gainDb_modified =
580 fMultDiv2(gainDb, gainRatio_m); /* resulting e: 7 + gainRatio_e + 1*/
581 gainDb_offset = (FIXP_DBL)0;
582
583 if ((pGMod != NULL) && (pGMod->gainOffsetPresent == 1)) {
584 /* *gainLin *= (float)pow(2.0, (double)(pGMod->gainOffset/6.0f)); */
585 gainDb_offset += FX_SGL2FX_DBL(pGMod->gainOffset) >> 4; /* resulting e: 8 */
586 }
587 if ((nodeMod->limiterPeakTargetPresent == 1) &&
588 (nodeMod->drcSetEffect ==
589 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 gainDb_offset += fMax(
595 (FIXP_DBL)0,
596 (FX_SGL2FX_DBL(-nodeMod->limiterPeakTarget) >> 3) -
597 (nodeMod->loudnessNormalizationGainDb >> 1)); /* resulting e: 8 */
598 }
599 if (gainDb_offset != (FIXP_DBL)0) {
600 gainDb_out = fAddNorm(gainDb_modified, 7 + gainRatio_e + 1, gainDb_offset,
601 8, &gainDb_out_e);
602 } else {
603 gainDb_out = gainDb_modified;
604 gainDb_out_e = 7 + gainRatio_e + 1;
605 }
606
607 /* *gainLin = (float)pow(2.0, (double)(gainDb_modified[1] / 6.0f)); */
608 gainLin_m = approxDb2lin(gainDb_out, gainDb_out_e, &gainLin_e);
609 *gainLin = scaleValueSaturate(gainLin_m, gainLin_e - 7);
610
611 /* *slopeLin = SLOPE_FACTOR_DB_TO_LINEAR * gainRatio * *gainLin * slopeDb; */
612 if (slopeDb == (FIXP_SGL)0) {
613 *slopeLin = (FIXP_DBL)0;
614 } else {
615 tmp_dbl =
616 fMult(slopeDb, SLOPE_FACTOR_DB_TO_LINEAR); /* resulting e: 2 - 3 = -1 */
617 tmp_dbl = fMult(tmp_dbl, gainRatio_m); /* resulting e: -1 + gainRatio_e */
618 if (gainDb_offset !=
619 (FIXP_DBL)0) { /* recalculate gainLin from gainDb that wasn't modified
620 by gainOffset and limiterPeakTarget */
621 gainLin_m = approxDb2lin(gainDb_modified, 7 + gainRatio_e, &gainLin_e);
622 }
623 slopeLin_m = fMult(tmp_dbl, gainLin_m);
624 *slopeLin =
625 scaleValueSaturate(slopeLin_m, -1 + gainRatio_e + gainLin_e - 7);
626 }
627
628 if ((nodeMod->limiterPeakTargetPresent == 1) &&
629 (nodeMod->drcSetEffect == EB_CLIPPING)) {
630 if (*gainLin >= FL2FXCONST_DBL(1.0f / (float)(1 << 7))) {
631 *gainLin = FL2FXCONST_DBL(1.0f / (float)(1 << 7));
632 *slopeLin = (FIXP_DBL)0;
633 }
634 }
635
636 return DE_OK;
637 }
638
639 /* prepare buffers containing linear nodes for each gain sequence */
640 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)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 const int activeDrcIndex) {
645 int b, g, gainElementIndex;
646 DRC_GAIN_BUFFERS* drcGainBuffers = &(hGainDec->drcGainBuffers);
647 NODE_MODIFICATION nodeMod;
648 FDKmemclear(&nodeMod, sizeof(NODE_MODIFICATION));
649 ACTIVE_DRC* pActiveDrc = &(hGainDec->activeDrc[activeDrcIndex]);
650 DRC_INSTRUCTIONS_UNI_DRC* pInst = pActiveDrc->pInst;
651 if (pInst == NULL) return DE_NOT_OK;
652
653 nodeMod.drcSetEffect = pInst->drcSetEffect;
654
655 nodeMod.compress = compress;
656 nodeMod.boost = boost;
657 nodeMod.loudnessNormalizationGainDb = loudnessNormalizationGainDb;
658 nodeMod.limiterPeakTargetPresent = pInst->limiterPeakTargetPresent;
659 nodeMod.limiterPeakTarget = pInst->limiterPeakTarget;
660
661 gainElementIndex = 0;
662 for (g = 0; g < pInst->nDrcChannelGroups; g++) {
663 int gainSetIndex = 0;
664 int nDrcBands = 0;
665 DRC_COEFFICIENTS_UNI_DRC* pCoef = pActiveDrc->pCoef;
666 if (pCoef == NULL) return DE_NOT_OK;
667
668 if (!pActiveDrc->channelGroupIsParametricDrc[g]) {
669 gainSetIndex = pInst->gainSetIndexForChannelGroup[g];
670
671 if (nodeMod.drcSetEffect & (EB_DUCK_OTHER | EB_DUCK_SELF)) {
672 nodeMod.pDMod = &(pActiveDrc->duckingModificationForChannelGroup[g]);
673 nodeMod.pGMod = NULL;
674 } else {
675 nodeMod.pGMod = pInst->gainModificationForChannelGroup[g];
676 nodeMod.pDMod = NULL;
677 }
678
679 nDrcBands = pActiveDrc->bandCountForChannelGroup[g];
680 for (b = 0; b < nDrcBands; b++) {
681 DRC_ERROR err = DE_OK;
682 GAIN_SET* pGainSet = &(pCoef->gainSet[gainSetIndex]);
683 int seq = pGainSet->gainSequenceIndex[b];
684 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 LINEAR_NODE_BUFFER* pLnb =
690 &(drcGainBuffers->linearNodeBuffer[pActiveDrc->activeDrcOffset +
691 gainElementIndex]);
692 int i, lnbp;
693 lnbp = drcGainBuffers->lnbPointer;
694 pLnb->gainInterpolationType =
695 (GAIN_INTERPOLATION_TYPE)pGainSet->gainInterpolationType;
696
697 err = _prepareDrcCharacteristic(pDChar, pCoef, b, &nodeMod);
698 if (err) return err;
699
700 /* copy a node buffer and convert from dB to linear */
701 pLnb->nNodes[lnbp] = fMin((int)hUniDrcGain->nNodes[seq], 16);
702 for (i = 0; i < pLnb->nNodes[lnbp]; i++) {
703 FIXP_DBL gainLin, slopeLin;
704 err = _toLinear(&nodeMod, b, hUniDrcGain->gainNode[seq][i].gainDb,
705 (FIXP_SGL)0, &gainLin, &slopeLin);
706 if (err) return err;
707 pLnb->linearNode[lnbp][i].gainLin = gainLin;
708 pLnb->linearNode[lnbp][i].time = hUniDrcGain->gainNode[seq][i].time;
709 }
710 gainElementIndex++;
711 }
712 } else {
713 /* parametric DRC not supported */
714 gainElementIndex++;
715 }
716 }
717 return DE_OK;
718 }
719