function AudioEngine () { // tone setup this.tone = new Tone(); // effects setup this.delay = new Tone.FeedbackDelay(0.25, 0.5); this.panner = new Tone.Panner(); this.reverb = new Tone.Freeverb(); this.clearEffects(); Tone.Master.chain(this.delay, this.panner, this.reverb); // drum sounds var drumFileNames = ['high_conga', 'small_cowbell', 'snare_drum', 'splash cymbal']; this.drumSamplers = this._loadSoundFiles(drumFileNames); // sound urls - map each url to its tone.sampler this.soundSamplers = []; // soundfont setup // instrument names used by Musyng Kite soundfont, in order to match scratch instruments this.instrumentNames = ['acoustic_grand_piano', 'electric_piano_1', 'drawbar_organ', 'acoustic_guitar_nylon', 'electric_guitar_clean', 'acoustic_bass', 'pizzicato_strings', 'cello', 'trombone', 'clarinet']; Soundfont.instrument(Tone.context, this.instrumentNames[0]).then(function (inst) { this.instrument = inst; this.instrument.connect(Tone.Master); }.bind(this)); } 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(); this.soundSamplers[url].player.start(); } else { // else load, play, and store it // this results in a delay the first time you play the sound var sampler = new Tone.Sampler(url, function() { sampler.triggerAttack(); this.soundSamplers[url] = sampler; }.bind(this)).toMaster(); } } }; AudioEngine.prototype.getSoundDuration = function (soundNum) { return this.soundSamplers[soundNum].player.buffer.duration; }; AudioEngine.prototype.playNoteForBeats = function(note, beats) { this.instrument.play(note, Tone.context.currentTime, {duration : Number(beats)}); }; AudioEngine.prototype.playDrumForBeats = function(drumNum, beats) { this.drumSamplers[drumNum].triggerAttack(); }; AudioEngine.prototype.stopAllSounds = function() { // stop drum notes for (var i=0; i<this.drumSamplers.length; i++) { this.drumSamplers[i].triggerRelease(); } // stop sounds triggered with playSound (indexed by their urls) for (var i in this.soundSamplers) { this.soundSamplers[i].triggerRelease(); } // stop soundfont notes this.instrument.stop(); }; AudioEngine.prototype.setEffect = function(effect, value) { switch (effect) { case 'ECHO': this.delay.wet.value = (value / 100) / 2; // max 50% wet (need dry signal too) break; case 'PAN': this.panner.pan.value = value / 100; break; case 'REVERB': this.reverb.wet.value = value / 100; break; case 'PITCH': // this.pitchShift.pitch = value / 20; // arbitrary scaling of 20 per semitone, for now... default 100 is a perfect fourth this._setPitchShift(value / 20); break; } } AudioEngine.prototype.changeEffect = function(effect, value) { switch (effect) { case 'ECHO': this.delay.wet.value += (value / 100) / 2; // max 50% wet (need dry signal too) this.delay.wet.value = this._clamp(this.delay.wet.value, 0, 0.5); break; case 'PAN': this.panner.pan.value += value / 100; this.panner.pan.value = this._clamp(this.panner.pan.value, -1, 1); break; case 'REVERB': this.reverb.wet.value += value / 100; this.reverb.wet.value = this._clamp(this.reverb.wet.value, 0, 1); break; case 'PITCH': // this.pitchShift.pitch += value / 20; break; } } AudioEngine.prototype._setPitchShift = function(value) { for (var i in this.soundSamplers) { this.soundSamplers[i].player.playbackRate = 1 + value; console.log(this.soundSamplers[i].player.playbackRate); } }; AudioEngine.prototype.clearEffects = function() { this.delay.wet.value = 0; this._setPitchShift(0); this.panner.pan.value = 0; this.reverb.wet.value = 0; }; AudioEngine.prototype.loadSoundFromUrl = function(url) { }; AudioEngine.prototype._loadSoundFiles = function(filenames) { var samplers = []; for (var name of filenames) { var sampler = new Tone.Sampler('sounds/' + name + '.mp3').toMaster(); samplers.push(sampler); } return samplers; }; AudioEngine.prototype._midiToFreq = function(midiNote) { var freq = this.tone.intervalToFrequencyRatio(midiNote - 60) * 261.63; // 60 is C4 return freq; }; AudioEngine.prototype._clamp = function(input, min, max) { return Math.min(Math.max(input, min), max); };