mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-01-14 11:39:59 -05:00
new setup for use with scratch-gui
This commit is contained in:
parent
0024b209bd
commit
7b179546ed
3 changed files with 180 additions and 9 deletions
163
src/audio/AudioEngine.js
Normal file
163
src/audio/AudioEngine.js
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
var Tone = require('tone');
|
||||||
|
var Soundfont = require('soundfont-player');
|
||||||
|
|
||||||
|
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 (url) {
|
||||||
|
return this.soundSamplers[url].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 (name in 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = AudioEngine;
|
||||||
|
|
|
@ -32,7 +32,7 @@ Scratch3SoundBlocks.prototype.getPrimitives = function() {
|
||||||
|
|
||||||
Scratch3SoundBlocks.prototype.playSound = function (args, util) {
|
Scratch3SoundBlocks.prototype.playSound = function (args, util) {
|
||||||
var url = this._getSoundUrl(args.SOUND_MENU, util);
|
var url = this._getSoundUrl(args.SOUND_MENU, util);
|
||||||
window.audioEngine.playSoundFromUrl(url);
|
util.target.audioEngine.playSoundFromUrl(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
Scratch3SoundBlocks.prototype._getSoundUrl = function (soundName, util) {
|
Scratch3SoundBlocks.prototype._getSoundUrl = function (soundName, util) {
|
||||||
|
@ -53,8 +53,10 @@ Scratch3SoundBlocks.prototype._getSoundUrl = function (soundName, util) {
|
||||||
|
|
||||||
|
|
||||||
Scratch3SoundBlocks.prototype.playSoundAndWait = function (args, util) {
|
Scratch3SoundBlocks.prototype.playSoundAndWait = function (args, util) {
|
||||||
// window.audioEngine.playSound(args.SOUND_NUM);
|
var url = this._getSoundUrl(args.SOUND_MENU, util);
|
||||||
// var duration = window.audioEngine.getSoundDuration(args.SOUND_NUM);
|
util.target.audioEngine.playSoundFromUrl(url);
|
||||||
|
|
||||||
|
var duration = util.target.audioEngine.getSoundDuration(url);
|
||||||
|
|
||||||
return new Promise(function(resolve) {
|
return new Promise(function(resolve) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
|
@ -64,11 +66,11 @@ Scratch3SoundBlocks.prototype.playSoundAndWait = function (args, util) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Scratch3SoundBlocks.prototype.stopAllSounds = function (args, util) {
|
Scratch3SoundBlocks.prototype.stopAllSounds = function (args, util) {
|
||||||
window.audioEngine.stopAllSounds();
|
util.target.audioEngine.stopAllSounds();
|
||||||
};
|
};
|
||||||
|
|
||||||
Scratch3SoundBlocks.prototype.playNoteForBeats = function (args, util) {
|
Scratch3SoundBlocks.prototype.playNoteForBeats = function (args, util) {
|
||||||
window.audioEngine.playNoteForBeats(args.NOTE, args.BEATS);
|
util.target.audioEngine.playNoteForBeats(args.NOTE, args.BEATS);
|
||||||
return new Promise(function(resolve) {
|
return new Promise(function(resolve) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
resolve();
|
resolve();
|
||||||
|
@ -77,7 +79,7 @@ Scratch3SoundBlocks.prototype.playNoteForBeats = function (args, util) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Scratch3SoundBlocks.prototype.playDrumForBeats = function (args, util) {
|
Scratch3SoundBlocks.prototype.playDrumForBeats = function (args, util) {
|
||||||
window.audioEngine.playDrumForBeats(args.DRUMTYPE, args.BEATS);
|
util.target.audioEngine.playDrumForBeats(args.DRUMTYPE, args.BEATS);
|
||||||
return new Promise(function(resolve) {
|
return new Promise(function(resolve) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
resolve();
|
resolve();
|
||||||
|
@ -86,15 +88,15 @@ Scratch3SoundBlocks.prototype.playDrumForBeats = function (args, util) {
|
||||||
};
|
};
|
||||||
|
|
||||||
Scratch3SoundBlocks.prototype.setEffect = function (args, util) {
|
Scratch3SoundBlocks.prototype.setEffect = function (args, util) {
|
||||||
window.audioEngine.setEffect(args.EFFECT, args.VALUE);
|
util.target.audioEngine.setEffect(args.EFFECT, args.VALUE);
|
||||||
};
|
};
|
||||||
|
|
||||||
Scratch3SoundBlocks.prototype.changeEffect = function (args, util) {
|
Scratch3SoundBlocks.prototype.changeEffect = function (args, util) {
|
||||||
window.audioEngine.changeEffect(args.EFFECT, args.VALUE);
|
util.target.audioEngine.changeEffect(args.EFFECT, args.VALUE);
|
||||||
};
|
};
|
||||||
|
|
||||||
Scratch3SoundBlocks.prototype.clearEffects = function (args, util) {
|
Scratch3SoundBlocks.prototype.clearEffects = function (args, util) {
|
||||||
window.audioEngine.clearEffects();
|
util.target.audioEngine.clearEffects();
|
||||||
};
|
};
|
||||||
|
|
||||||
Scratch3SoundBlocks.prototype.soundsMenu = function (args, util) {
|
Scratch3SoundBlocks.prototype.soundsMenu = function (args, util) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var MathUtil = require('../util/math-util');
|
var MathUtil = require('../util/math-util');
|
||||||
var Target = require('../engine/target');
|
var Target = require('../engine/target');
|
||||||
|
var AudioEngine = require('../audio/AudioEngine.js');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clone (instance) of a sprite.
|
* Clone (instance) of a sprite.
|
||||||
|
@ -43,6 +44,11 @@ function Clone(sprite, runtime) {
|
||||||
'brightness': 0,
|
'brightness': 0,
|
||||||
'ghost': 0
|
'ghost': 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Audio engine
|
||||||
|
*/
|
||||||
|
this.audioEngine = new AudioEngine();
|
||||||
}
|
}
|
||||||
util.inherits(Clone, Target);
|
util.inherits(Clone, Target);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue