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) {
|
2017-06-19 17:41:08 -04:00
|
|
|
return this.intervalToFrequencyRatio(val / 10);
|
2017-04-17 12:55:09 -04:00
|
|
|
}
|
2017-01-30 11:09:45 -05: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) {
|
2017-06-21 10:46:42 -04:00
|
|
|
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]);
|
|
|
|
}
|
2017-02-02 15:10:10 -05:00
|
|
|
}
|
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;
|