| 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 |