diff --git a/playground/AudioEngine.js b/playground/AudioEngine.js index 94eed307c..844910f63 100644 --- a/playground/AudioEngine.js +++ b/playground/AudioEngine.js @@ -23,10 +23,6 @@ function AudioEngine () { this.reverb.wet.value = 0; Tone.Master.chain(this.delay, this.pitchShift, this.panner, this.reverb); - - // synth setup for play note block - - this.synth = new Tone.PolySynth(6, Tone.Synth).toMaster(); // drum sounds @@ -35,20 +31,37 @@ function AudioEngine () { // sound files - var soundFileNames = ['meow','boing','cave','drip_drop','drum_machine','eggs','zoop']; - this.soundSamplers = this._loadSoundFiles(soundFileNames); + // var soundFileNames = ['meow','boing','cave','drip_drop','drum_machine','eggs','zoop']; + // this.soundSamplers = this._loadSoundFiles(soundFileNames); + + // sound urls - map each url to its tone.sampler + this.soundSamplers = []; } AudioEngine.prototype.playSound = function (soundNum) { this.soundSamplers[soundNum].triggerAttack(); }; +AudioEngine.prototype.playSoundFromUrl = function (url) { + if (url) { + // if we've loaded it already, play it + if (this.soundSamplers[url]) { + this.soundSamplers[url].triggerAttack(); + } else { + // else load, play, and store it + var sampler = new Tone.Sampler(url, function() {sampler.triggerAttack();}).toMaster(); + this.soundSamplers[url] = sampler; + } + } +}; + AudioEngine.prototype.getSoundDuration = function (soundNum) { return this.soundSamplers[soundNum].player.buffer.duration; }; AudioEngine.prototype.playNoteForBeats = function(note, beats) { - this.instrument.play(note, this.tone.now(), beats); + this.instrument.start(note, Tone.context.currentTime, beats); + // this.instrument.play(note).stop(Tone.context.currentTime+beats); }; AudioEngine.prototype.playDrumForBeats = function(drumNum, beats) { @@ -56,8 +69,6 @@ AudioEngine.prototype.playDrumForBeats = function(drumNum, beats) { }; AudioEngine.prototype.stopAllSounds = function() { - // stop synth notes - this.synth.releaseAll(); // stop drum notes for (var i=0; i - - - + + + - - + + diff --git a/src/blocks/scratch3_sound.js b/src/blocks/scratch3_sound.js index 5eb5b33fe..43f29dacd 100644 --- a/src/blocks/scratch3_sound.js +++ b/src/blocks/scratch3_sound.js @@ -1,4 +1,5 @@ var Cast = require('../util/cast'); +var MathUtil = require('../util/math-util'); var Promise = require('promise'); function Scratch3SoundBlocks(runtime) { @@ -15,7 +16,7 @@ function Scratch3SoundBlocks(runtime) { */ Scratch3SoundBlocks.prototype.getPrimitives = function() { return { - 'sound_playsound': this.playSound, + 'sound_play': this.playSound, 'sound_playuntildone': this.playSoundAndWait, 'sound_stopallsounds': this.stopAllSounds, 'sound_playnoteforbeats': this.playNoteForBeats, @@ -30,12 +31,31 @@ Scratch3SoundBlocks.prototype.getPrimitives = function() { }; Scratch3SoundBlocks.prototype.playSound = function (args, util) { - window.audioEngine.playSound(args.SOUND_NUM); + var url = this._getSoundUrl(args.SOUND_MENU, util); + window.audioEngine.playSoundFromUrl(url); }; +Scratch3SoundBlocks.prototype._getSoundUrl = function (soundName, util) { + if (util.target.sprite.sounds.length == 0) { + return ''; + } + var index; + if (typeof soundName === 'number') { + index = MathUtil.wrapClamp(soundName,0,util.target.sprite.sounds.length); + } else { + index = util.target.getSoundIndexByName(soundName); + if (index == -1) { + return ''; + } + } + return util.target.sprite.sounds[index].soundFile; +}; + + Scratch3SoundBlocks.prototype.playSoundAndWait = function (args, util) { - window.audioEngine.playSound(args.SOUND_NUM); - var duration = window.audioEngine.getSoundDuration(args.SOUND_NUM); + // window.audioEngine.playSound(args.SOUND_NUM); + // var duration = window.audioEngine.getSoundDuration(args.SOUND_NUM); + return new Promise(function(resolve) { setTimeout(function() { resolve(); diff --git a/src/import/sb2import.js b/src/import/sb2import.js index 0962074e3..42b43d131 100644 --- a/src/import/sb2import.js +++ b/src/import/sb2import.js @@ -62,6 +62,21 @@ function parseScratchObject (object, runtime, topLevel) { }); } } + // Sounds from JSON + if (object.hasOwnProperty('sounds')) { + for (var i = 0; i < object.sounds.length; i++) { + var sound = object.sounds[i]; + sprite.sounds.push({ + format: sound.format, + soundFile: 'https://cdn.assets.scratch.mit.edu/internalapi/asset/' + + sound.md5 + '/get/', + rate: sound.rate, + sampleCount: sound.sampleCount, + soundID: sound.soundID, + name: sound.soundName + }); + } + } // If included, parse any and all scripts/blocks on the object. if (object.hasOwnProperty('scripts')) { parseScripts(object.scripts, blocks); diff --git a/src/sprites/clone.js b/src/sprites/clone.js index 16c65a1de..5b3d2def2 100644 --- a/src/sprites/clone.js +++ b/src/sprites/clone.js @@ -255,6 +255,20 @@ Clone.prototype.getCostumeIndexByName = function (costumeName) { return -1; }; +/** + * Get a sound index of this clone, by name of the sound. + * @param {?string} soundName Name of a sound. + * @return {number} Index of the named sound, or -1 if not present. + */ +Clone.prototype.getSoundIndexByName = function (soundName) { + for (var i = 0; i < this.sprite.sounds.length; i++) { + if (this.sprite.sounds[i].name == soundName) { + return i; + } + } + return -1; +}; + /** * Update all drawable properties for this clone. * Use when a batch has changed, e.g., when the drawable is first created. diff --git a/src/sprites/sprite.js b/src/sprites/sprite.js index 687e30f72..cfa8de90d 100644 --- a/src/sprites/sprite.js +++ b/src/sprites/sprite.js @@ -33,6 +33,10 @@ function Sprite (blocks, runtime) { * @type {Array.} */ this.costumes = []; + /** + * List of sounds for this sprite. + */ + this.sounds = []; /** * List of clones for this sprite, including the original. * @type {Array.}