scratch-audio/src/effects/PitchEffect.js

82 lines
2.7 KiB
JavaScript
Raw Normal View History

2017-04-17 11:22:16 -04:00
const Tone = require('tone');
2016-11-29 18:33:09 -05:00
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.
* @constructor
*/
2016-11-29 18:33:09 -05:00
function PitchEffect () {
2017-02-01 18:02:04 -05:00
this.value = 0; // effect value
this.ratio = 1; // the playback rate ratio
2016-11-29 18:33:09 -05:00
2016-11-30 11:29:00 -05:00
this.tone = new Tone();
2016-11-29 18:33:09 -05:00
}
2017-02-01 18:02:04 -05: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
*/
2016-11-29 18:33:09 -05:00
PitchEffect.prototype.set = function (val, players) {
this.value = val;
this.ratio = this.getRatio(this.value);
2016-11-29 18:33:09 -05:00
this.updatePlayers(players);
};
2017-02-01 18:02:04 -05: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
*/
2016-11-29 18:33:09 -05:00
PitchEffect.prototype.changeBy = function (val, players) {
this.set(this.value + val, players);
};
2017-02-01 18:02:04 -05: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
*/
PitchEffect.prototype.getRatio = function (val) {
return this.tone.intervalToFrequencyRatio(val / 10);
};
2017-02-01 18:02:04 -05:00
/**
* Update a sound player's playback rate using the current ratio for the effect
* @param {Object} player - a SoundPlayer object
*/
PitchEffect.prototype.updatePlayer = function (player) {
player.setPlaybackRate(this.ratio);
2016-11-29 18:33:09 -05:00
};
2017-02-01 18:02:04 -05: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
*/
2016-11-29 18:33:09 -05:00
PitchEffect.prototype.updatePlayers = function (players) {
if (!players) return;
2017-04-17 11:22:16 -04:00
for (const md5 in players) {
if (players.hasOwnProperty(md5)) {
this.updatePlayer(players[md5]);
}
2016-11-29 18:33:09 -05:00
}
};
module.exports = PitchEffect;