/* * Copyright (C) 2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Exponential curve for the knee. // It is 1st derivative matched at m_linearThreshold and asymptotically // approaches the value m_linearThreshold + 1 / k. float DynamicsCompressorKernel::kneeCurve(float x, float k) { // Linear up to threshold. if (x < m_linearThreshold) return x;
// Full compression curve with constant ratio after knee. float DynamicsCompressorKernel::saturate(float x, float k) { float y;
if (x < m_kneeThreshold)
y = kneeCurve(x, k); else { // Constant ratio after knee. float xDb = WebAudioUtils::ConvertLinearToDecibels(x, -1000.0f); float yDb = m_ykneeThresholdDb + m_slope * (xDb - m_kneeThresholdDb);
y = WebAudioUtils::ConvertDecibelsToLinear(yDb);
}
return y;
}
// Approximate 1st derivative with input and output expressed in dB. // This slope is equal to the inverse of the compression "ratio". // In other words, a compression ratio of 20 would be a slope of 1/20. float DynamicsCompressorKernel::slopeAt(float x, float k) { if (x < m_linearThreshold) return 1;
unsigned frameIndex = 0; for (int i = 0; i < nDivisions; ++i) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Calculate desired gain // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Fix gremlins. if (std::isnan(m_detectorAverage)) m_detectorAverage = 1; if (std::isinf(m_detectorAverage)) m_detectorAverage = 1;
float desiredGain = m_detectorAverage;
// Pre-warp so we get desiredGain after sin() warp below. float scaledDesiredGain = fdlibm_asinf(desiredGain) / (0.5f * M_PI);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Deal with envelopes // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// envelopeRate is the rate we slew from current compressor level to the // desired level. The exact rate depends on if we're attacking or releasing // and by how much. float envelopeRate;
// compressionDiffDb is the difference between current compression level and // the desired level. float compressionDiffDb; if (scaledDesiredGain == 0.0) {
compressionDiffDb = PositiveInfinity<float>();
} else {
compressionDiffDb = WebAudioUtils::ConvertLinearToDecibels(
m_compressorGain / scaledDesiredGain, -1000.0f);
}
if (isReleasing) { // Release mode - compressionDiffDb should be negative dB
m_maxAttackCompressionDiffDb = -1;
// Fix gremlins. if (std::isnan(compressionDiffDb)) compressionDiffDb = -1; if (std::isinf(compressionDiffDb)) compressionDiffDb = -1;
// Contain within range: -12 -> 0 then scale to go from 0 -> 3 float x = compressionDiffDb;
x = std::max(-12.0f, x);
x = std::min(0.0f, x);
x = 0.25f * (x + 12);
// Compute adaptive release curve using 4th order polynomial. // Normal values for the polynomial coefficients would create a // monotonically increasing function. float x2 = x * x; float x3 = x2 * x; float x4 = x2 * x2; float releaseFrames = kA + kB * x + kC * x2 + kD * x3 + kE * x4;
envelopeRate = WebAudioUtils::ConvertDecibelsToLinear(dbPerFrame);
} else { // Attack mode - compressionDiffDb should be positive dB
// Fix gremlins. if (std::isnan(compressionDiffDb)) compressionDiffDb = 1; if (std::isinf(compressionDiffDb)) compressionDiffDb = 1;
// As long as we're still in attack mode, use a rate based off // the largest compressionDiffDb we've encountered so far. if (m_maxAttackCompressionDiffDb == -1 ||
m_maxAttackCompressionDiffDb < compressionDiffDb)
m_maxAttackCompressionDiffDb = compressionDiffDb;
// Put through shaping curve. // This is linear up to the threshold, then enters a "knee" portion // followed by the "ratio" portion. The transition from the threshold to // the knee is smooth (1st derivative matched). The transition from the // knee to the ratio portion is smooth (1st derivative matched). float shapedInput = saturate(absInput, k);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.