OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 m_lastPreDelayFrames = preDelayFrames; | 87 m_lastPreDelayFrames = preDelayFrames; |
88 for (unsigned i = 0; i < m_preDelayBuffers.size(); ++i) | 88 for (unsigned i = 0; i < m_preDelayBuffers.size(); ++i) |
89 m_preDelayBuffers[i]->zero(); | 89 m_preDelayBuffers[i]->zero(); |
90 | 90 |
91 m_preDelayReadIndex = 0; | 91 m_preDelayReadIndex = 0; |
92 m_preDelayWriteIndex = preDelayFrames; | 92 m_preDelayWriteIndex = preDelayFrames; |
93 } | 93 } |
94 } | 94 } |
95 | 95 |
96 // Exponential curve for the knee. | 96 // Exponential curve for the knee. |
97 // It is 1st derivative matched at m_linearThreshold and asymptotically approach
es the value m_linearThreshold + 1 / k. | 97 // It is 1st derivative matched at m_linearThreshold and asymptotically |
| 98 // approaches the value m_linearThreshold + 1 / k. |
98 float DynamicsCompressorKernel::kneeCurve(float x, float k) { | 99 float DynamicsCompressorKernel::kneeCurve(float x, float k) { |
99 // Linear up to threshold. | 100 // Linear up to threshold. |
100 if (x < m_linearThreshold) | 101 if (x < m_linearThreshold) |
101 return x; | 102 return x; |
102 | 103 |
103 return m_linearThreshold + (1 - expf(-k * (x - m_linearThreshold))) / k; | 104 return m_linearThreshold + (1 - expf(-k * (x - m_linearThreshold))) / k; |
104 } | 105 } |
105 | 106 |
106 // Full compression curve with constant ratio after knee. | 107 // Full compression curve with constant ratio after knee. |
107 float DynamicsCompressorKernel::saturate(float x, float k) { | 108 float DynamicsCompressorKernel::saturate(float x, float k) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 float DynamicsCompressorKernel::kAtSlope(float desiredSlope) { | 144 float DynamicsCompressorKernel::kAtSlope(float desiredSlope) { |
144 float xDb = m_dbThreshold + m_dbKnee; | 145 float xDb = m_dbThreshold + m_dbKnee; |
145 float x = decibelsToLinear(xDb); | 146 float x = decibelsToLinear(xDb); |
146 | 147 |
147 // Approximate k given initial values. | 148 // Approximate k given initial values. |
148 float minK = 0.1; | 149 float minK = 0.1; |
149 float maxK = 10000; | 150 float maxK = 10000; |
150 float k = 5; | 151 float k = 5; |
151 | 152 |
152 for (int i = 0; i < 15; ++i) { | 153 for (int i = 0; i < 15; ++i) { |
153 // A high value for k will more quickly asymptotically approach a slope of 0
. | 154 // A high value for k will more quickly asymptotically approach a slope of |
| 155 // 0. |
154 float slope = slopeAt(x, k); | 156 float slope = slopeAt(x, k); |
155 | 157 |
156 if (slope < desiredSlope) { | 158 if (slope < desiredSlope) { |
157 // k is too high. | 159 // k is too high. |
158 maxK = k; | 160 maxK = k; |
159 } else { | 161 } else { |
160 // k is too low. | 162 // k is too low. |
161 minK = k; | 163 minK = k; |
162 } | 164 } |
163 | 165 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 // Create a smooth function which passes through four points. | 246 // Create a smooth function which passes through four points. |
245 | 247 |
246 // Polynomial of the form | 248 // Polynomial of the form |
247 // y = a + b*x + c*x^2 + d*x^3 + e*x^4; | 249 // y = a + b*x + c*x^2 + d*x^3 + e*x^4; |
248 | 250 |
249 float y1 = releaseFrames * releaseZone1; | 251 float y1 = releaseFrames * releaseZone1; |
250 float y2 = releaseFrames * releaseZone2; | 252 float y2 = releaseFrames * releaseZone2; |
251 float y3 = releaseFrames * releaseZone3; | 253 float y3 = releaseFrames * releaseZone3; |
252 float y4 = releaseFrames * releaseZone4; | 254 float y4 = releaseFrames * releaseZone4; |
253 | 255 |
254 // All of these coefficients were derived for 4th order polynomial curve fitti
ng where the y values | 256 // All of these coefficients were derived for 4th order polynomial curve |
255 // match the evenly spaced x values as follows: (y1 : x == 0, y2 : x == 1, y3
: x == 2, y4 : x == 3) | 257 // fitting where the y values match the evenly spaced x values as follows: |
| 258 // (y1 : x == 0, y2 : x == 1, y3 : x == 2, y4 : x == 3) |
256 float a = 0.9999999999999998f * y1 + 1.8432219684323923e-16f * y2 - | 259 float a = 0.9999999999999998f * y1 + 1.8432219684323923e-16f * y2 - |
257 1.9373394351676423e-16f * y3 + 8.824516011816245e-18f * y4; | 260 1.9373394351676423e-16f * y3 + 8.824516011816245e-18f * y4; |
258 float b = -1.5788320352845888f * y1 + 2.3305837032074286f * y2 - | 261 float b = -1.5788320352845888f * y1 + 2.3305837032074286f * y2 - |
259 0.9141194204840429f * y3 + 0.1623677525612032f * y4; | 262 0.9141194204840429f * y3 + 0.1623677525612032f * y4; |
260 float c = 0.5334142869106424f * y1 - 1.272736789213631f * y2 + | 263 float c = 0.5334142869106424f * y1 - 1.272736789213631f * y2 + |
261 0.9258856042207512f * y3 - 0.18656310191776226f * y4; | 264 0.9258856042207512f * y3 - 0.18656310191776226f * y4; |
262 float d = 0.08783463138207234f * y1 - 0.1694162967925622f * y2 + | 265 float d = 0.08783463138207234f * y1 - 0.1694162967925622f * y2 + |
263 0.08588057951595272f * y3 - 0.00429891410546283f * y4; | 266 0.08588057951595272f * y3 - 0.00429891410546283f * y4; |
264 float e = -0.042416883008123074f * y1 + 0.1115693827987602f * y2 - | 267 float e = -0.042416883008123074f * y1 + 0.1115693827987602f * y2 - |
265 0.09764676325265872f * y3 + 0.028494263462021576f * y4; | 268 0.09764676325265872f * y3 + 0.028494263462021576f * y4; |
266 | 269 |
267 // x ranges from 0 -> 3 0 1 2 3 | 270 // x ranges from 0 -> 3 0 1 2 3 |
268 // -15 -10 -5 0db | 271 // -15 -10 -5 0db |
269 | 272 |
270 // y calculates adaptive release frames depending on the amount of compression
. | 273 // y calculates adaptive release frames depending on the amount of |
| 274 // compression. |
271 | 275 |
272 setPreDelayTime(preDelayTime); | 276 setPreDelayTime(preDelayTime); |
273 | 277 |
274 const int nDivisionFrames = 32; | 278 const int nDivisionFrames = 32; |
275 | 279 |
276 const int nDivisions = framesToProcess / nDivisionFrames; | 280 const int nDivisions = framesToProcess / nDivisionFrames; |
277 | 281 |
278 unsigned frameIndex = 0; | 282 unsigned frameIndex = 0; |
279 for (int i = 0; i < nDivisions; ++i) { | 283 for (int i = 0; i < nDivisions; ++i) { |
280 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~ | 284 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~ |
281 // Calculate desired gain | 285 // Calculate desired gain |
282 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~ | 286 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~ |
283 | 287 |
284 // Fix gremlins. | 288 // Fix gremlins. |
285 if (std::isnan(m_detectorAverage)) | 289 if (std::isnan(m_detectorAverage)) |
286 m_detectorAverage = 1; | 290 m_detectorAverage = 1; |
287 if (std::isinf(m_detectorAverage)) | 291 if (std::isinf(m_detectorAverage)) |
288 m_detectorAverage = 1; | 292 m_detectorAverage = 1; |
289 | 293 |
290 float desiredGain = m_detectorAverage; | 294 float desiredGain = m_detectorAverage; |
291 | 295 |
292 // Pre-warp so we get desiredGain after sin() warp below. | 296 // Pre-warp so we get desiredGain after sin() warp below. |
293 float scaledDesiredGain = asinf(desiredGain) / (piOverTwoFloat); | 297 float scaledDesiredGain = asinf(desiredGain) / (piOverTwoFloat); |
294 | 298 |
295 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~ | 299 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~ |
296 // Deal with envelopes | 300 // Deal with envelopes |
297 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~ | 301 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~ |
298 | 302 |
299 // envelopeRate is the rate we slew from current compressor level to the des
ired level. | 303 // envelopeRate is the rate we slew from current compressor level to the |
300 // The exact rate depends on if we're attacking or releasing and by how much
. | 304 // desired level. The exact rate depends on if we're attacking or |
| 305 // releasing and by how much. |
301 float envelopeRate; | 306 float envelopeRate; |
302 | 307 |
303 bool isReleasing = scaledDesiredGain > m_compressorGain; | 308 bool isReleasing = scaledDesiredGain > m_compressorGain; |
304 | 309 |
305 // compressionDiffDb is the difference between current compression level and
the desired level. | 310 // compressionDiffDb is the difference between current compression level and |
| 311 // the desired level. |
306 float compressionDiffDb = | 312 float compressionDiffDb = |
307 linearToDecibels(m_compressorGain / scaledDesiredGain); | 313 linearToDecibels(m_compressorGain / scaledDesiredGain); |
308 | 314 |
309 if (isReleasing) { | 315 if (isReleasing) { |
310 // Release mode - compressionDiffDb should be negative dB | 316 // Release mode - compressionDiffDb should be negative dB |
311 m_maxAttackCompressionDiffDb = -1; | 317 m_maxAttackCompressionDiffDb = -1; |
312 | 318 |
313 // Fix gremlins. | 319 // Fix gremlins. |
314 if (std::isnan(compressionDiffDb)) | 320 if (std::isnan(compressionDiffDb)) |
315 compressionDiffDb = -1; | 321 compressionDiffDb = -1; |
316 if (std::isinf(compressionDiffDb)) | 322 if (std::isinf(compressionDiffDb)) |
317 compressionDiffDb = -1; | 323 compressionDiffDb = -1; |
318 | 324 |
319 // Adaptive release - higher compression (lower compressionDiffDb) releas
es faster. | 325 // Adaptive release - higher compression (lower compressionDiffDb) |
| 326 // releases faster. |
320 | 327 |
321 // Contain within range: -12 -> 0 then scale to go from 0 -> 3 | 328 // Contain within range: -12 -> 0 then scale to go from 0 -> 3 |
322 float x = compressionDiffDb; | 329 float x = compressionDiffDb; |
323 x = clampTo(x, -12.0f, 0.0f); | 330 x = clampTo(x, -12.0f, 0.0f); |
324 x = 0.25f * (x + 12); | 331 x = 0.25f * (x + 12); |
325 | 332 |
326 // Compute adaptive release curve using 4th order polynomial. | 333 // Compute adaptive release curve using 4th order polynomial. |
327 // Normal values for the polynomial coefficients would create a monotonica
lly increasing function. | 334 // Normal values for the polynomial coefficients would create a |
| 335 // monotonically increasing function. |
328 float x2 = x * x; | 336 float x2 = x * x; |
329 float x3 = x2 * x; | 337 float x3 = x2 * x; |
330 float x4 = x2 * x2; | 338 float x4 = x2 * x2; |
331 float releaseFrames = a + b * x + c * x2 + d * x3 + e * x4; | 339 float releaseFrames = a + b * x + c * x2 + d * x3 + e * x4; |
332 | 340 |
333 #define kSpacingDb 5 | 341 #define kSpacingDb 5 |
334 float dbPerFrame = kSpacingDb / releaseFrames; | 342 float dbPerFrame = kSpacingDb / releaseFrames; |
335 | 343 |
336 envelopeRate = decibelsToLinear(dbPerFrame); | 344 envelopeRate = decibelsToLinear(dbPerFrame); |
337 } else { | 345 } else { |
(...skipping 24 matching lines...) Expand all Loading... |
362 { | 370 { |
363 int preDelayReadIndex = m_preDelayReadIndex; | 371 int preDelayReadIndex = m_preDelayReadIndex; |
364 int preDelayWriteIndex = m_preDelayWriteIndex; | 372 int preDelayWriteIndex = m_preDelayWriteIndex; |
365 float detectorAverage = m_detectorAverage; | 373 float detectorAverage = m_detectorAverage; |
366 float compressorGain = m_compressorGain; | 374 float compressorGain = m_compressorGain; |
367 | 375 |
368 int loopFrames = nDivisionFrames; | 376 int loopFrames = nDivisionFrames; |
369 while (loopFrames--) { | 377 while (loopFrames--) { |
370 float compressorInput = 0; | 378 float compressorInput = 0; |
371 | 379 |
372 // Predelay signal, computing compression amount from un-delayed version
. | 380 // Predelay signal, computing compression amount from un-delayed |
| 381 // version. |
373 for (unsigned i = 0; i < numberOfChannels; ++i) { | 382 for (unsigned i = 0; i < numberOfChannels; ++i) { |
374 float* delayBuffer = m_preDelayBuffers[i]->data(); | 383 float* delayBuffer = m_preDelayBuffers[i]->data(); |
375 float undelayedSource = sourceChannels[i][frameIndex]; | 384 float undelayedSource = sourceChannels[i][frameIndex]; |
376 delayBuffer[preDelayWriteIndex] = undelayedSource; | 385 delayBuffer[preDelayWriteIndex] = undelayedSource; |
377 | 386 |
378 float absUndelayedSource = | 387 float absUndelayedSource = |
379 undelayedSource > 0 ? undelayedSource : -undelayedSource; | 388 undelayedSource > 0 ? undelayedSource : -undelayedSource; |
380 if (compressorInput < absUndelayedSource) | 389 if (compressorInput < absUndelayedSource) |
381 compressorInput = absUndelayedSource; | 390 compressorInput = absUndelayedSource; |
382 } | 391 } |
383 | 392 |
384 // Calculate shaped power on undelayed input. | 393 // Calculate shaped power on undelayed input. |
385 | 394 |
386 float scaledInput = compressorInput; | 395 float scaledInput = compressorInput; |
387 float absInput = scaledInput > 0 ? scaledInput : -scaledInput; | 396 float absInput = scaledInput > 0 ? scaledInput : -scaledInput; |
388 | 397 |
389 // Put through shaping curve. | 398 // Put through shaping curve. |
390 // This is linear up to the threshold, then enters a "knee" portion foll
owed by the "ratio" portion. | 399 // This is linear up to the threshold, then enters a "knee" portion |
391 // The transition from the threshold to the knee is smooth (1st derivati
ve matched). | 400 // followed by the "ratio" portion. The transition from the threshold |
392 // The transition from the knee to the ratio portion is smooth (1st deri
vative matched). | 401 // to the knee is smooth (1st derivative matched). The transition from |
| 402 // the knee to the ratio portion is smooth (1st derivative matched). |
393 float shapedInput = saturate(absInput, k); | 403 float shapedInput = saturate(absInput, k); |
394 | 404 |
395 float attenuation = absInput <= 0.0001f ? 1 : shapedInput / absInput; | 405 float attenuation = absInput <= 0.0001f ? 1 : shapedInput / absInput; |
396 | 406 |
397 float attenuationDb = -linearToDecibels(attenuation); | 407 float attenuationDb = -linearToDecibels(attenuation); |
398 attenuationDb = std::max(2.0f, attenuationDb); | 408 attenuationDb = std::max(2.0f, attenuationDb); |
399 | 409 |
400 float dbPerFrame = attenuationDb / satReleaseFrames; | 410 float dbPerFrame = attenuationDb / satReleaseFrames; |
401 | 411 |
402 float satReleaseRate = decibelsToLinear(dbPerFrame) - 1; | 412 float satReleaseRate = decibelsToLinear(dbPerFrame) - 1; |
(...skipping 13 matching lines...) Expand all Loading... |
416 // Exponential approach to desired gain. | 426 // Exponential approach to desired gain. |
417 if (envelopeRate < 1) { | 427 if (envelopeRate < 1) { |
418 // Attack - reduce gain to desired. | 428 // Attack - reduce gain to desired. |
419 compressorGain += (scaledDesiredGain - compressorGain) * envelopeRate; | 429 compressorGain += (scaledDesiredGain - compressorGain) * envelopeRate; |
420 } else { | 430 } else { |
421 // Release - exponentially increase gain to 1.0 | 431 // Release - exponentially increase gain to 1.0 |
422 compressorGain *= envelopeRate; | 432 compressorGain *= envelopeRate; |
423 compressorGain = std::min(1.0f, compressorGain); | 433 compressorGain = std::min(1.0f, compressorGain); |
424 } | 434 } |
425 | 435 |
426 // Warp pre-compression gain to smooth out sharp exponential transition
points. | 436 // Warp pre-compression gain to smooth out sharp exponential transition |
| 437 // points. |
427 float postWarpCompressorGain = sinf(piOverTwoFloat * compressorGain); | 438 float postWarpCompressorGain = sinf(piOverTwoFloat * compressorGain); |
428 | 439 |
429 // Calculate total gain using master gain and effect blend. | 440 // Calculate total gain using master gain and effect blend. |
430 float totalGain = | 441 float totalGain = |
431 dryMix + wetMix * masterLinearGain * postWarpCompressorGain; | 442 dryMix + wetMix * masterLinearGain * postWarpCompressorGain; |
432 | 443 |
433 // Calculate metering. | 444 // Calculate metering. |
434 float dbRealGain = 20 * std::log10(postWarpCompressorGain); | 445 float dbRealGain = 20 * std::log10(postWarpCompressorGain); |
435 if (dbRealGain < m_meteringGain) | 446 if (dbRealGain < m_meteringGain) |
436 m_meteringGain = dbRealGain; | 447 m_meteringGain = dbRealGain; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 for (unsigned i = 0; i < m_preDelayBuffers.size(); ++i) | 480 for (unsigned i = 0; i < m_preDelayBuffers.size(); ++i) |
470 m_preDelayBuffers[i]->zero(); | 481 m_preDelayBuffers[i]->zero(); |
471 | 482 |
472 m_preDelayReadIndex = 0; | 483 m_preDelayReadIndex = 0; |
473 m_preDelayWriteIndex = DefaultPreDelayFrames; | 484 m_preDelayWriteIndex = DefaultPreDelayFrames; |
474 | 485 |
475 m_maxAttackCompressionDiffDb = -1; // uninitialized state | 486 m_maxAttackCompressionDiffDb = -1; // uninitialized state |
476 } | 487 } |
477 | 488 |
478 } // namespace blink | 489 } // namespace blink |
OLD | NEW |