2016-09-15 15:59:29 -04:00
|
|
|
function AudioEngine () {
|
2016-09-07 16:55:38 -04:00
|
|
|
|
2016-09-28 13:20:51 -04:00
|
|
|
// soundfont setup
|
|
|
|
|
|
|
|
Soundfont.instrument(Tone.context, 'acoustic_grand_piano').then(function (piano) {
|
|
|
|
this.instrument = piano;
|
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
// tone setup
|
|
|
|
|
2016-09-07 16:55:38 -04:00
|
|
|
this.tone = new Tone();
|
|
|
|
|
|
|
|
// effects setup
|
|
|
|
|
|
|
|
this.delay = new Tone.FeedbackDelay(0.25, 0.5);
|
|
|
|
this.delay.wet.value = 0;
|
|
|
|
|
|
|
|
this.pitchShift = new Tone.PitchShift();
|
|
|
|
|
|
|
|
this.panner = new Tone.Panner();
|
|
|
|
|
|
|
|
this.reverb = new Tone.Freeverb();
|
|
|
|
this.reverb.wet.value = 0;
|
|
|
|
|
|
|
|
Tone.Master.chain(this.delay, this.pitchShift, this.panner, this.reverb);
|
|
|
|
|
|
|
|
// drum sounds
|
|
|
|
|
|
|
|
var drumFileNames = ['high_conga', 'small_cowbell', 'snare_drum', 'splash cymbal'];
|
|
|
|
this.drumSamplers = this._loadSoundFiles(drumFileNames);
|
|
|
|
|
|
|
|
// sound files
|
|
|
|
|
2016-09-28 16:42:25 -04:00
|
|
|
// 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 = [];
|
2016-09-07 16:55:38 -04:00
|
|
|
}
|
|
|
|
|
2016-09-15 15:59:29 -04:00
|
|
|
AudioEngine.prototype.playSound = function (soundNum) {
|
2016-09-15 16:51:24 -04:00
|
|
|
this.soundSamplers[soundNum].triggerAttack();
|
2016-09-15 15:59:29 -04:00
|
|
|
};
|
|
|
|
|
2016-09-28 16:42:25 -04:00
|
|
|
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
|
2016-10-03 20:07:42 -04:00
|
|
|
// this results in a delay the first time you play the sound
|
2016-10-01 17:27:28 -04:00
|
|
|
var sampler = new Tone.Sampler(url, function() {
|
|
|
|
sampler.triggerAttack();
|
|
|
|
this.soundSamplers[url] = sampler;
|
|
|
|
}.bind(this)).toMaster();
|
2016-09-28 16:42:25 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-09-27 17:09:53 -04:00
|
|
|
AudioEngine.prototype.getSoundDuration = function (soundNum) {
|
|
|
|
return this.soundSamplers[soundNum].player.buffer.duration;
|
|
|
|
};
|
|
|
|
|
2016-09-15 16:51:24 -04:00
|
|
|
AudioEngine.prototype.playNoteForBeats = function(note, beats) {
|
2016-10-03 20:07:42 -04:00
|
|
|
this.instrument.start(note, Tone.context.currentTime, beats); // duration not working
|
2016-09-28 16:42:25 -04:00
|
|
|
// this.instrument.play(note).stop(Tone.context.currentTime+beats);
|
2016-09-15 16:51:24 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
2016-10-01 17:27:28 -04:00
|
|
|
// stop sounds triggered with playSound (indexed by their urls)
|
|
|
|
for (var i in this.soundSamplers) {
|
2016-09-15 16:51:24 -04:00
|
|
|
this.soundSamplers[i].triggerRelease();
|
|
|
|
}
|
2016-09-28 16:42:25 -04:00
|
|
|
// stop soundfont notes
|
|
|
|
this.instrument.stop();
|
2016-09-07 16:55:38 -04:00
|
|
|
};
|
|
|
|
|
2016-09-27 17:09:53 -04:00
|
|
|
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
|
|
|
|
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.clearEffects = function() {
|
|
|
|
this.delay.wet.value = 0;
|
|
|
|
this.panner.pan.value = 0;
|
|
|
|
this.reverb.wet.value = 0;
|
|
|
|
this.pitchShift.pitch = 0;
|
|
|
|
}
|
|
|
|
|
2016-09-28 16:42:25 -04:00
|
|
|
AudioEngine.prototype.loadSoundFromUrl = function(url) {
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2016-09-15 15:59:29 -04:00
|
|
|
AudioEngine.prototype._loadSoundFiles = function(filenames) {
|
2016-09-07 16:55:38 -04:00
|
|
|
var samplers = [];
|
|
|
|
|
|
|
|
for (var name of filenames) {
|
2016-09-13 17:52:54 -04:00
|
|
|
var sampler = new Tone.Sampler('sounds/' + name + '.mp3').toMaster();
|
|
|
|
samplers.push(sampler);
|
2016-09-07 16:55:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return samplers;
|
|
|
|
};
|
|
|
|
|
2016-09-15 15:59:29 -04:00
|
|
|
AudioEngine.prototype._midiToFreq = function(midiNote) {
|
2016-09-13 17:52:54 -04:00
|
|
|
var freq = this.tone.intervalToFrequencyRatio(midiNote - 60) * 261.63; // 60 is C4
|
2016-09-07 16:55:38 -04:00
|
|
|
return freq;
|
|
|
|
};
|
|
|
|
|
2016-09-15 16:51:24 -04:00
|
|
|
AudioEngine.prototype._clamp = function(input, min, max) {
|
2016-09-07 16:55:38 -04:00
|
|
|
return Math.min(Math.max(input, min), max);
|
|
|
|
};
|
|
|
|
|