Created
January 19, 2020 13:44
-
-
Save khrykin/7e543c3af4b90e788b1a942b88bd7c4b to your computer and use it in GitHub Desktop.
Logarithmic fader (envelope) in javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Fades values in and out logarithmically. | |
* @param {number} sampleRate - Number of samples per duration unit | |
* @param {number} duration - Duration of an envelope | |
* @param {number} unity - Unity approximation | |
*/ | |
function Fader(sampleRate, duration, unity = 0.999) { | |
this._sampleDuration = duration / sampleRate; | |
let T = -duration / Math.log(1 - unity); | |
this._exp = Math.exp(this._sampleDuration / T); | |
this._numSamples = duration / this._sampleDuration; | |
this._isActive = false; | |
} | |
Fader.fadeIn = 0; | |
Fader.fadeOut = 1; | |
/** | |
* Starts an envelope with initial and target values. | |
* Note that initial value isn't included in the envelope. | |
*/ | |
Fader.prototype.start = function(initialValue, targetValue) { | |
this._currentUnitySample = 0.0; | |
this._currentSampleIndex = 0; | |
this._fadeType = targetValue <= initialValue ? Fader.fadeOut : Fader.fadeIn; | |
this._isActive = true; | |
switch (this._fadeType) { | |
case Fader.fadeIn: | |
this._minValue = initialValue; | |
this._maxValue = targetValue; | |
this._getCurrentExponentSample = function() { | |
return this._currentUnitySample / this._exp + 1 - 1 / this._exp; | |
}; | |
break; | |
case Fader.fadeOut: | |
this._minValue = targetValue; | |
this._maxValue = initialValue; | |
this._getCurrentExponentSample = function() { | |
return this._currentUnitySample / this._exp; | |
}; | |
break; | |
} | |
this._currentUnitySample = | |
(initialValue - this._minValue) / (this._maxValue - this._minValue); | |
}; | |
/** | |
* Returns the next unity sample (in the range of [0.0, 1.0] for this envelope. | |
*/ | |
Fader.prototype.getNextUnitySample = function() { | |
let unitySample; | |
if (this._currentSampleIndex < this._numSamples - 1) { | |
unitySample = this._getCurrentExponentSample(); | |
this._currentSampleIndex++; | |
} else { | |
switch (this._fadeType) { | |
case Fader.fadeIn: | |
unitySample = 1; | |
break; | |
case Fader.fadeOut: | |
unitySample = 0; | |
break; | |
} | |
this._isActive = false; | |
} | |
this._currentUnitySample = unitySample; | |
return unitySample; | |
}; | |
/** | |
* Returns the next sample for this envelope. | |
*/ | |
Fader.prototype.getNextSample = function() { | |
let unitySample = this.getNextUnitySample(); | |
return (this._maxValue - this._minValue) * unitySample + this._minValue; | |
}; | |
/** | |
* Returns the total number of samples for this envelope. | |
*/ | |
Fader.prototype.getNumSamples = function() { | |
return this._numSamples; | |
}; | |
/** | |
* Returns the duration of a single sample | |
*/ | |
Fader.prototype.getSampleDuration = function() { | |
return this._sampleDuration; | |
}; | |
/** | |
* Returns a boolean, indicating whether the target value is reached | |
*/ | |
Fader.prototype.isActive = function() { | |
return this._isActive; | |
}; | |
/* Usage */ | |
let sampleRate = 10; | |
let duration = 0.5; | |
let fader = new Fader(sampleRate, duration); | |
/* Fade in */ | |
fader.start(0.1, 0.5); | |
console.log("Fade in samples:"); | |
for (let i = 0; i < fader.getNumSamples(); i++) { | |
console.log(fader.getNextSample()); | |
} | |
/* Fade out */ | |
fader.start(0.5, 0.3); | |
console.log("Fade out samples:"); | |
for (let i = 0; i < fader.getNumSamples(); i++) { | |
console.log(fader.getNextSample()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment