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 19 matching lines...) Expand all Loading... |
30 | 30 |
31 #if ENABLE(WEB_AUDIO) | 31 #if ENABLE(WEB_AUDIO) |
32 | 32 |
33 #include "platform/audio/DynamicsCompressorKernel.h" | 33 #include "platform/audio/DynamicsCompressorKernel.h" |
34 | 34 |
35 #include <algorithm> | 35 #include <algorithm> |
36 #include "platform/audio/AudioUtilities.h" | 36 #include "platform/audio/AudioUtilities.h" |
37 #include "platform/audio/DenormalDisabler.h" | 37 #include "platform/audio/DenormalDisabler.h" |
38 #include "wtf/MathExtras.h" | 38 #include "wtf/MathExtras.h" |
39 | 39 |
40 using namespace std; | |
41 | |
42 namespace blink { | 40 namespace blink { |
43 | 41 |
44 using namespace AudioUtilities; | 42 using namespace AudioUtilities; |
45 | 43 |
46 // Metering hits peaks instantly, but releases this fast (in seconds). | 44 // Metering hits peaks instantly, but releases this fast (in seconds). |
47 const float meteringReleaseTimeConstant = 0.325f; | 45 const float meteringReleaseTimeConstant = 0.325f; |
48 | 46 |
49 const float uninitializedValue = -1; | 47 const float uninitializedValue = -1; |
50 | 48 |
51 DynamicsCompressorKernel::DynamicsCompressorKernel(float sampleRate, unsigned nu
mberOfChannels) | 49 DynamicsCompressorKernel::DynamicsCompressorKernel(float sampleRate, unsigned nu
mberOfChannels) |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 // Makeup gain. | 231 // Makeup gain. |
234 float fullRangeGain = saturate(1, k); | 232 float fullRangeGain = saturate(1, k); |
235 float fullRangeMakeupGain = 1 / fullRangeGain; | 233 float fullRangeMakeupGain = 1 / fullRangeGain; |
236 | 234 |
237 // Empirical/perceptual tuning. | 235 // Empirical/perceptual tuning. |
238 fullRangeMakeupGain = powf(fullRangeMakeupGain, 0.6f); | 236 fullRangeMakeupGain = powf(fullRangeMakeupGain, 0.6f); |
239 | 237 |
240 float masterLinearGain = decibelsToLinear(dbPostGain) * fullRangeMakeupGain; | 238 float masterLinearGain = decibelsToLinear(dbPostGain) * fullRangeMakeupGain; |
241 | 239 |
242 // Attack parameters. | 240 // Attack parameters. |
243 attackTime = max(0.001f, attackTime); | 241 attackTime = std::max(0.001f, attackTime); |
244 float attackFrames = attackTime * sampleRate; | 242 float attackFrames = attackTime * sampleRate; |
245 | 243 |
246 // Release parameters. | 244 // Release parameters. |
247 float releaseFrames = sampleRate * releaseTime; | 245 float releaseFrames = sampleRate * releaseTime; |
248 | 246 |
249 // Detector release time. | 247 // Detector release time. |
250 float satReleaseTime = 0.0025f; | 248 float satReleaseTime = 0.0025f; |
251 float satReleaseFrames = satReleaseTime * sampleRate; | 249 float satReleaseFrames = satReleaseTime * sampleRate; |
252 | 250 |
253 // Create a smooth function which passes through four points. | 251 // Create a smooth function which passes through four points. |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 // Fix gremlins. | 314 // Fix gremlins. |
317 if (std::isnan(compressionDiffDb)) | 315 if (std::isnan(compressionDiffDb)) |
318 compressionDiffDb = -1; | 316 compressionDiffDb = -1; |
319 if (std::isinf(compressionDiffDb)) | 317 if (std::isinf(compressionDiffDb)) |
320 compressionDiffDb = -1; | 318 compressionDiffDb = -1; |
321 | 319 |
322 // Adaptive release - higher compression (lower compressionDiffDb)
releases faster. | 320 // Adaptive release - higher compression (lower compressionDiffDb)
releases faster. |
323 | 321 |
324 // Contain within range: -12 -> 0 then scale to go from 0 -> 3 | 322 // Contain within range: -12 -> 0 then scale to go from 0 -> 3 |
325 float x = compressionDiffDb; | 323 float x = compressionDiffDb; |
326 x = max(-12.0f, x); | 324 x = std::max(-12.0f, x); |
327 x = min(0.0f, x); | 325 x = std::min(0.0f, x); |
328 x = 0.25f * (x + 12); | 326 x = 0.25f * (x + 12); |
329 | 327 |
330 // Compute adaptive release curve using 4th order polynomial. | 328 // Compute adaptive release curve using 4th order polynomial. |
331 // Normal values for the polynomial coefficients would create a mono
tonically increasing function. | 329 // Normal values for the polynomial coefficients would create a mono
tonically increasing function. |
332 float x2 = x * x; | 330 float x2 = x * x; |
333 float x3 = x2 * x; | 331 float x3 = x2 * x; |
334 float x4 = x2 * x2; | 332 float x4 = x2 * x2; |
335 float releaseFrames = kA + kB * x + kC * x2 + kD * x3 + kE * x4; | 333 float releaseFrames = kA + kB * x + kC * x2 + kD * x3 + kE * x4; |
336 | 334 |
337 #define kSpacingDb 5 | 335 #define kSpacingDb 5 |
338 float dbPerFrame = kSpacingDb / releaseFrames; | 336 float dbPerFrame = kSpacingDb / releaseFrames; |
339 | 337 |
340 envelopeRate = decibelsToLinear(dbPerFrame); | 338 envelopeRate = decibelsToLinear(dbPerFrame); |
341 } else { | 339 } else { |
342 // Attack mode - compressionDiffDb should be positive dB | 340 // Attack mode - compressionDiffDb should be positive dB |
343 | 341 |
344 // Fix gremlins. | 342 // Fix gremlins. |
345 if (std::isnan(compressionDiffDb)) | 343 if (std::isnan(compressionDiffDb)) |
346 compressionDiffDb = 1; | 344 compressionDiffDb = 1; |
347 if (std::isinf(compressionDiffDb)) | 345 if (std::isinf(compressionDiffDb)) |
348 compressionDiffDb = 1; | 346 compressionDiffDb = 1; |
349 | 347 |
350 // As long as we're still in attack mode, use a rate based off | 348 // As long as we're still in attack mode, use a rate based off |
351 // the largest compressionDiffDb we've encountered so far. | 349 // the largest compressionDiffDb we've encountered so far. |
352 if (m_maxAttackCompressionDiffDb == -1 || m_maxAttackCompressionDiff
Db < compressionDiffDb) | 350 if (m_maxAttackCompressionDiffDb == -1 || m_maxAttackCompressionDiff
Db < compressionDiffDb) |
353 m_maxAttackCompressionDiffDb = compressionDiffDb; | 351 m_maxAttackCompressionDiffDb = compressionDiffDb; |
354 | 352 |
355 float effAttenDiffDb = max(0.5f, m_maxAttackCompressionDiffDb); | 353 float effAttenDiffDb = std::max(0.5f, m_maxAttackCompressionDiffDb); |
356 | 354 |
357 float x = 0.25f / effAttenDiffDb; | 355 float x = 0.25f / effAttenDiffDb; |
358 envelopeRate = 1 - powf(x, 1 / attackFrames); | 356 envelopeRate = 1 - powf(x, 1 / attackFrames); |
359 } | 357 } |
360 | 358 |
361 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~ | 359 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~ |
362 // Inner loop - calculate shaped power average - apply compression. | 360 // Inner loop - calculate shaped power average - apply compression. |
363 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~ | 361 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~ |
364 | 362 |
365 { | 363 { |
(...skipping 24 matching lines...) Expand all Loading... |
390 | 388 |
391 // Put through shaping curve. | 389 // Put through shaping curve. |
392 // This is linear up to the threshold, then enters a "knee" port
ion followed by the "ratio" portion. | 390 // This is linear up to the threshold, then enters a "knee" port
ion followed by the "ratio" portion. |
393 // The transition from the threshold to the knee is smooth (1st
derivative matched). | 391 // The transition from the threshold to the knee is smooth (1st
derivative matched). |
394 // The transition from the knee to the ratio portion is smooth (
1st derivative matched). | 392 // The transition from the knee to the ratio portion is smooth (
1st derivative matched). |
395 float shapedInput = saturate(absInput, k); | 393 float shapedInput = saturate(absInput, k); |
396 | 394 |
397 float attenuation = absInput <= 0.0001f ? 1 : shapedInput / absI
nput; | 395 float attenuation = absInput <= 0.0001f ? 1 : shapedInput / absI
nput; |
398 | 396 |
399 float attenuationDb = -linearToDecibels(attenuation); | 397 float attenuationDb = -linearToDecibels(attenuation); |
400 attenuationDb = max(2.0f, attenuationDb); | 398 attenuationDb = std::max(2.0f, attenuationDb); |
401 | 399 |
402 float dbPerFrame = attenuationDb / satReleaseFrames; | 400 float dbPerFrame = attenuationDb / satReleaseFrames; |
403 | 401 |
404 float satReleaseRate = decibelsToLinear(dbPerFrame) - 1; | 402 float satReleaseRate = decibelsToLinear(dbPerFrame) - 1; |
405 | 403 |
406 bool isRelease = (attenuation > detectorAverage); | 404 bool isRelease = (attenuation > detectorAverage); |
407 float rate = isRelease ? satReleaseRate : 1; | 405 float rate = isRelease ? satReleaseRate : 1; |
408 | 406 |
409 detectorAverage += (attenuation - detectorAverage) * rate; | 407 detectorAverage += (attenuation - detectorAverage) * rate; |
410 detectorAverage = min(1.0f, detectorAverage); | 408 detectorAverage = std::min(1.0f, detectorAverage); |
411 | 409 |
412 // Fix gremlins. | 410 // Fix gremlins. |
413 if (std::isnan(detectorAverage)) | 411 if (std::isnan(detectorAverage)) |
414 detectorAverage = 1; | 412 detectorAverage = 1; |
415 if (std::isinf(detectorAverage)) | 413 if (std::isinf(detectorAverage)) |
416 detectorAverage = 1; | 414 detectorAverage = 1; |
417 | 415 |
418 // Exponential approach to desired gain. | 416 // Exponential approach to desired gain. |
419 if (envelopeRate < 1) { | 417 if (envelopeRate < 1) { |
420 // Attack - reduce gain to desired. | 418 // Attack - reduce gain to desired. |
421 compressorGain += (scaledDesiredGain - compressorGain) * env
elopeRate; | 419 compressorGain += (scaledDesiredGain - compressorGain) * env
elopeRate; |
422 } else { | 420 } else { |
423 // Release - exponentially increase gain to 1.0 | 421 // Release - exponentially increase gain to 1.0 |
424 compressorGain *= envelopeRate; | 422 compressorGain *= envelopeRate; |
425 compressorGain = min(1.0f, compressorGain); | 423 compressorGain = std::min(1.0f, compressorGain); |
426 } | 424 } |
427 | 425 |
428 // Warp pre-compression gain to smooth out sharp exponential tra
nsition points. | 426 // Warp pre-compression gain to smooth out sharp exponential tra
nsition points. |
429 float postWarpCompressorGain = sinf(piOverTwoFloat * compressorG
ain); | 427 float postWarpCompressorGain = sinf(piOverTwoFloat * compressorG
ain); |
430 | 428 |
431 // Calculate total gain using master gain and effect blend. | 429 // Calculate total gain using master gain and effect blend. |
432 float totalGain = dryMix + wetMix * masterLinearGain * postWarpC
ompressorGain; | 430 float totalGain = dryMix + wetMix * masterLinearGain * postWarpC
ompressorGain; |
433 | 431 |
434 // Calculate metering. | 432 // Calculate metering. |
435 float dbRealGain = 20 * log10(postWarpCompressorGain); | 433 float dbRealGain = 20 * std::log10(postWarpCompressorGain); |
436 if (dbRealGain < m_meteringGain) | 434 if (dbRealGain < m_meteringGain) |
437 m_meteringGain = dbRealGain; | 435 m_meteringGain = dbRealGain; |
438 else | 436 else |
439 m_meteringGain += (dbRealGain - m_meteringGain) * m_metering
ReleaseK; | 437 m_meteringGain += (dbRealGain - m_meteringGain) * m_metering
ReleaseK; |
440 | 438 |
441 // Apply final gain. | 439 // Apply final gain. |
442 for (unsigned i = 0; i < numberOfChannels; ++i) { | 440 for (unsigned i = 0; i < numberOfChannels; ++i) { |
443 float* delayBuffer = m_preDelayBuffers[i]->data(); | 441 float* delayBuffer = m_preDelayBuffers[i]->data(); |
444 destinationChannels[i][frameIndex] = delayBuffer[preDelayRea
dIndex] * totalGain; | 442 destinationChannels[i][frameIndex] = delayBuffer[preDelayRea
dIndex] * totalGain; |
445 } | 443 } |
(...skipping 24 matching lines...) Expand all Loading... |
470 | 468 |
471 m_preDelayReadIndex = 0; | 469 m_preDelayReadIndex = 0; |
472 m_preDelayWriteIndex = DefaultPreDelayFrames; | 470 m_preDelayWriteIndex = DefaultPreDelayFrames; |
473 | 471 |
474 m_maxAttackCompressionDiffDb = -1; // uninitialized state | 472 m_maxAttackCompressionDiffDb = -1; // uninitialized state |
475 } | 473 } |
476 | 474 |
477 } // namespace blink | 475 } // namespace blink |
478 | 476 |
479 #endif // ENABLE(WEB_AUDIO) | 477 #endif // ENABLE(WEB_AUDIO) |
OLD | NEW |