audioengine loads sounds indexed by md5

audioplayers store list of their own active sound players indexed by md5 of the sound. sound players are created when the sound is played, deleted when it ends, and removed from the list of active sound players. the pitch effect uses this list of active sound players to set their playback ratios.
This commit is contained in:
Eric Rosenbaum 2017-01-30 11:09:45 -05:00
parent a150f018b5
commit e1d478244d
2 changed files with 65 additions and 49 deletions

View file

@ -8,12 +8,14 @@ var Tone = require('tone');
function PitchEffect () { function PitchEffect () {
this.value = 0; this.value = 0;
this.ratio = 1;
this.tone = new Tone(); this.tone = new Tone();
} }
PitchEffect.prototype.set = function (val, players) { PitchEffect.prototype.set = function (val, players) {
this.value = val; this.value = val;
this.ratio = this.getRatio(this.value);
this.updatePlayers(players); this.updatePlayers(players);
}; };
@ -21,19 +23,23 @@ PitchEffect.prototype.changeBy = function (val, players) {
this.set(this.value + val, players); this.set(this.value + val, players);
}; };
PitchEffect.prototype.getRatio = function () { PitchEffect.prototype.getRatio = function (val) {
return this.tone.intervalToFrequencyRatio(this.value / 10); return this.tone.intervalToFrequencyRatio(val / 10);
};
PitchEffect.prototype.updatePlayer = function (player) {
player.setPlaybackRate(this.ratio);
}; };
PitchEffect.prototype.updatePlayers = function (players) { PitchEffect.prototype.updatePlayers = function (players) {
if (!players) return; if (!players) return;
var ratio = this.getRatio(); for (var md5 in players) {
for (var i=0; i<players.length; i++) { this.updatePlayer(players[md5]);
players[i].setPlaybackRate(ratio);
} }
}; };
module.exports = PitchEffect; module.exports = PitchEffect;

View file

@ -48,8 +48,40 @@ function AudioEngine () {
// drum player for play drum blocks // drum player for play drum blocks
this.drumPlayer = new DrumPlayer(this.input); this.drumPlayer = new DrumPlayer(this.input);
this.numDrums = this.drumPlayer.drumSounds.length; this.numDrums = this.drumPlayer.drumSounds.length;
// a map of md5s to audio buffers, holding sounds for all sprites
this.audioBuffers = {};
} }
AudioEngine.prototype.loadSounds = function (sounds) {
// most sounds decode natively, but for adpcm sounds we use our own decoder
var storedContext = this;
for (var i=0; i<sounds.length; i++) {
var md5 = sounds[i].md5;
var buffer = new Tone.Buffer();
this.audioBuffers[md5] = buffer;
if (sounds[i].format == 'squeak') {
log.warn('unable to load sound in squeak format');
continue;
}
if (sounds[i].format == 'adpcm') {
log.warn('loading sound in adpcm format');
// create a closure to store the sound md5, to use when the
// decoder completes and resolves the promise
(function () {
var storedMd5 = sounds[i].md5;
var loader = new ADPCMSoundLoader();
loader.load(sounds[i].fileUrl).then(function (audioBuffer) {
storedContext.audioBuffers[storedMd5] = new Tone.Buffer(audioBuffer);
});
}());
} else {
this.audioBuffers[md5] = new Tone.Buffer(sounds[i].fileUrl);
}
}
};
AudioEngine.prototype.setTempo = function (value) { AudioEngine.prototype.setTempo = function (value) {
// var newTempo = this._clamp(value, this.minTempo, this.maxTempo); // var newTempo = this._clamp(value, this.minTempo, this.maxTempo);
this.currentTempo = value; this.currentTempo = value;
@ -94,52 +126,30 @@ function AudioPlayer (audioEngine) {
this.currentVolume = 100; this.currentVolume = 100;
this.currentInstrument = 0; this.currentInstrument = 0;
// sound players that are currently playing, indexed by the sound's md5
this.activeSoundPlayers = Object.create({});
} }
AudioPlayer.prototype.loadSounds = function (sounds) { AudioPlayer.prototype.playSound = function (md5) {
// if this sprite or clone is already playing this sound, stop it first
this.soundPlayers = []; // (this is not working, not sure why)
if (this.activeSoundPlayers[md5]) {
// create a set of empty sound player objects this.activeSoundPlayers[md5].stop();
// the sound buffers will be added asynchronously as they load
for (var i=0; i<sounds.length; i++){
this.soundPlayers[i] = new SoundPlayer(this.effectsNode);
} }
// load the sounds // create a new soundplayer to play the sound
// most sounds decode natively, but for adpcm sounds we use our own decoder var player = new SoundPlayer();
var storedContext = this; player.setBuffer(this.audioEngine.audioBuffers[md5]);
for (var index=0; index<sounds.length; index++) { player.connect(this.effectsNode);
if (sounds[index].format == 'squeak') { this.pitchEffect.updatePlayer(player);
log.warn('unable to load sound in squeak format'); player.start();
continue;
}
if (sounds[index].format == 'adpcm') {
log.warn('loading sound in adpcm format');
// create a closure to store the sound index, to use when the
// decoder completes and resolves the promise
(function () {
var storedIndex = index;
var loader = new ADPCMSoundLoader();
loader.load(sounds[storedIndex].fileUrl).then(function (audioBuffer) {
storedContext.soundPlayers[storedIndex].setBuffer(new Tone.Buffer(audioBuffer));
});
}());
} else {
this.soundPlayers[index].setBuffer(new Tone.Buffer(sounds[index].fileUrl));
}
}
}; // add it to the list of active sound players
this.activeSoundPlayers[md5] = player;
AudioPlayer.prototype.playSound = function (index) { // when the sound completes, remove it from the list of active sound players
if (!this.soundPlayers[index]) return; return player.finished().then(() => {
delete this.activeSoundPlayers[md5];
this.soundPlayers[index].start();
var storedContext = this;
return new Promise(function (resolve) {
storedContext.soundPlayers[index].onEnded(resolve);
}); });
}; };
@ -168,9 +178,9 @@ AudioPlayer.prototype.beatsToSec = function (beats) {
}; };
AudioPlayer.prototype.stopAllSounds = function () { AudioPlayer.prototype.stopAllSounds = function () {
// stop all sound players // stop all active sound players
for (var i=0; i<this.soundPlayers.length; i++) { for (var md5 in this.activeSoundPlayers) {
this.soundPlayers[i].stop(); this.activeSoundPlayers[md5].stop();
} }
// stop all instruments // stop all instruments