scratch-audio/src/effects/PitchEffect.js

89 lines
3 KiB
JavaScript
Raw Normal View History

2017-02-01 18:02:04 -05:00
/**
2017-02-02 14:53:17 -05:00
* A pitch change effect, which changes the playback rate of the sound in order
2017-02-01 18:02:04 -05:00
* to change its pitch: reducing the playback rate lowers the pitch, increasing the rate
* raises the pitch. The duration of the sound is also changed.
*
* Changing the value of the pitch effect by 10 causes a change in pitch by 1 semitone
* (i.e. a musical half-step, such as the difference between C and C#)
* Changing the pitch effect by 120 changes the pitch by one octave (12 semitones)
*
* The value of this effect is not clamped (i.e. it is typically between -120 and 120,
* but can be set much higher or much lower, with weird and fun results).
* We should consider what extreme values to use for clamping it.
*
* Note that this effect functions differently from the other audio effects. It is
* not part of a chain of audio nodes. Instead, it provides a way to set the playback
* on one SoundPlayer or a group of them.
*/
2017-04-17 12:55:09 -04:00
class PitchEffect {
constructor () {
this.value = 0; // effect value
this.ratio = 1; // the playback rate ratio
}
2016-11-29 18:33:09 -05:00
2017-04-17 12:55:09 -04:00
/**
* Set the effect value
* @param {number} val - the new value to set the effect to
* @param {object} players - a dictionary of SoundPlayer objects to apply the effect to, indexed by md5
*/
set (val, players) {
this.value = val;
this.ratio = this.getRatio(this.value);
this.updatePlayers(players);
}
2016-11-29 18:33:09 -05:00
2017-04-17 12:55:09 -04:00
/**
* Change the effect value
* @param {number} val - the value to change the effect by
* @param {object} players - a dictionary of SoundPlayer objects indexed by md5
*/
changeBy (val, players) {
this.set(this.value + val, players);
}
2016-11-29 18:33:09 -05:00
2017-04-17 12:55:09 -04:00
/**
* Compute the playback ratio for an effect value.
* The playback ratio is scaled so that a change of 10 in the effect value
* gives a change of 1 semitone in the ratio.
* @param {number} val - an effect value
* @returns {number} a playback ratio
*/
getRatio (val) {
return this.intervalToFrequencyRatio(val / 10);
2017-04-17 12:55:09 -04:00
}
2017-06-19 17:25:11 -04:00
/**
* Convert a musical interval to a frequency ratio.
* With thanks to Tone.js: https://github.com/Tonejs/Tone.js
* @param {number} interval - a musical interval, in semitones
* @returns {number} a frequency ratio
*/
intervalToFrequencyRatio (interval) {
return Math.pow(2, (interval/12));
2017-06-19 17:40:53 -04:00
}
2017-06-19 17:25:11 -04:00
2017-04-17 12:55:09 -04:00
/**
* Update a sound player's playback rate using the current ratio for the effect
* @param {object} player - a SoundPlayer object
*/
updatePlayer (player) {
player.setPlaybackRate(this.ratio);
}
2016-11-29 18:33:09 -05:00
2017-04-17 12:55:09 -04:00
/**
* Update a sound player's playback rate using the current ratio for the effect
* @param {object} players - a dictionary of SoundPlayer objects to update, indexed by md5
*/
updatePlayers (players) {
if (!players) return;
2016-11-29 18:33:09 -05:00
2017-04-17 12:55:09 -04:00
for (const md5 in players) {
if (players.hasOwnProperty(md5)) {
this.updatePlayer(players[md5]);
}
}
2016-11-29 18:33:09 -05:00
}
2017-04-17 12:55:09 -04:00
}
2016-11-29 18:33:09 -05:00
module.exports = PitchEffect;