mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2024-12-23 06:23:37 -05:00
play sound and play note block
This commit is contained in:
parent
7709a4095e
commit
d9a703b4ad
5 changed files with 54 additions and 143 deletions
|
@ -39,29 +39,15 @@ AudioLocal.prototype._loadSoundFiles = function(filenames) {
|
|||
var samplers = [];
|
||||
|
||||
for (var name of filenames) {
|
||||
|
||||
// create an array of samplers for each sound (a hack to get polyphony for each sound)
|
||||
var myVoices = [];
|
||||
for (var i=0; i<6; i++) {
|
||||
var p = new Tone.Sampler('sounds/' + name + '.mp3').toMaster();
|
||||
myVoices.push(p);
|
||||
}
|
||||
|
||||
var polySampler = {
|
||||
voices : myVoices,
|
||||
currentVoice : 0,
|
||||
nextVoice : function() {return this.voices[this.currentVoice++ % this.voices.length];},
|
||||
stopAllVoices : function() {for (var i=0;i<this.voices.length;i++) {this.voices[i].triggerRelease()}},
|
||||
};
|
||||
|
||||
samplers.push(polySampler);
|
||||
var sampler = new Tone.Sampler('sounds/' + name + '.mp3').toMaster();
|
||||
samplers.push(sampler);
|
||||
}
|
||||
|
||||
return samplers;
|
||||
};
|
||||
|
||||
AudioLocal.prototype.midiToFreq = function(midiNote) {
|
||||
var freq = tone.intervalToFrequencyRatio(midiNote - 60) * 261.63; // 60 is C4
|
||||
AudioLocal.prototype._midiToFreq = function(midiNote) {
|
||||
var freq = this.tone.intervalToFrequencyRatio(midiNote - 60) * 261.63; // 60 is C4
|
||||
return freq;
|
||||
};
|
||||
|
||||
|
@ -70,11 +56,16 @@ AudioLocal.prototype.clamp = function(input, min, max) {
|
|||
};
|
||||
|
||||
AudioLocal.prototype.playNoteForBeats = function(note, beats) {
|
||||
var midiNote = scaleNoteToMidiNote(note, currentScale, rootNote);
|
||||
var freq = midiToFreq(midiNote);
|
||||
synth.triggerAttackRelease(freq, beats, quantizeUnit);
|
||||
var freq = this._midiToFreq(note);
|
||||
this.synth.triggerAttackRelease(freq, beats);
|
||||
};
|
||||
|
||||
AudioLocal.prototype.stopAllSounds = function() {
|
||||
// stop sounds triggered with playSound
|
||||
for (var i=0; i<this.soundSamplers.length; i++) {
|
||||
this.soundSamplers[i].triggerRelease();
|
||||
}
|
||||
};
|
||||
|
||||
AudioLocal.prototype.connectWorker = function(worker) {
|
||||
var instance = this;
|
||||
|
@ -87,7 +78,14 @@ AudioLocal.prototype._onWorkerMessage = function(worker, message) {
|
|||
if (message.data.type == 'audio') {
|
||||
switch(message.data.method) {
|
||||
case 'playSound' :
|
||||
this.soundSamplers[message.data.value].nextVoice().triggerAttack();
|
||||
this.soundSamplers[message.data.value].triggerRelease();
|
||||
this.soundSamplers[message.data.value].triggerAttack();
|
||||
break;
|
||||
case 'stopAllSounds' :
|
||||
this.stopAllSounds();
|
||||
break;
|
||||
case 'playNoteForBeats' :
|
||||
this.playNoteForBeats(message.data.note, message.data.beats);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,4 +10,20 @@ AudioWorker.prototype.playSound = function (soundNum) {
|
|||
});
|
||||
};
|
||||
|
||||
AudioWorker.prototype.stopAllSounds = function () {
|
||||
self.postMessage({
|
||||
type: 'audio',
|
||||
method: 'stopAllSounds'
|
||||
});
|
||||
};
|
||||
|
||||
AudioWorker.prototype.playNoteForBeats = function (note, beats) {
|
||||
self.postMessage({
|
||||
type: 'audio',
|
||||
method: 'playNoteForBeats',
|
||||
note: note,
|
||||
beats: beats
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = AudioWorker;
|
|
@ -278,28 +278,8 @@
|
|||
</value>
|
||||
</block>
|
||||
|
||||
<block type="sound_playwithpitch">
|
||||
<value name="SOUND_NUM">
|
||||
<shadow type="sound_sounds_menu">
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="PITCH">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
|
||||
<block type="sound_stopallsounds"></block>
|
||||
|
||||
<block type="sound_playdrum">
|
||||
<value name="DRUMTYPE">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
|
||||
<block type="sound_playdrumforbeats">
|
||||
<value name="DRUMTYPE">
|
||||
<shadow type="math_number">
|
||||
|
@ -320,18 +300,10 @@
|
|||
</value>
|
||||
</block>
|
||||
|
||||
<block type="sound_playnote">
|
||||
<value name="NOTE">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
|
||||
<block type="sound_playnoteforbeats">
|
||||
<value name="NOTE">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
<field name="NUM">60</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="BEATS">
|
||||
|
@ -339,34 +311,7 @@
|
|||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
|
||||
<block type="sound_scalenotetomidinote">
|
||||
<value name="NOTE">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">1</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="ROOT">
|
||||
<shadow type="sound_roots_menu">
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SCALE">
|
||||
<shadow type="sound_scales_menu">
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
|
||||
<block type="sound_setkey">
|
||||
<value name="ROOT">
|
||||
<shadow type="sound_roots_menu">
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="SCALE">
|
||||
<shadow type="sound_scales_menu">
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
|
||||
|
||||
<block type="sound_seteffectto">
|
||||
<value name="EFFECT">
|
||||
<shadow type="sound_effects_menu"></shadow>
|
||||
|
|
|
@ -13,74 +13,34 @@ function Scratch3SoundBlocks(runtime) {
|
|||
Scratch3SoundBlocks.prototype.getPrimitives = function() {
|
||||
return {
|
||||
'sound_playsound': this.playSound,
|
||||
'sound_playwithpitch': this.playSoundWithPitch,
|
||||
// 'sound_playsoundandwait': this.playSoundAndWait,
|
||||
'sound_stopallsounds': this.stopAllSounds,
|
||||
'sound_playnote': this.playNote,
|
||||
'sound_playnoteforbeats': this.playNoteForBeats,
|
||||
'sound_scalenotetomidinote': this.scaleNoteToMidiNote,
|
||||
'sound_playdrum': this.playDrum,
|
||||
'sound_playdrumforbeats': this.playDrumForBeats,
|
||||
'sound_setkey' : this.setKey,
|
||||
'sound_seteffectto' : this.setEffect,
|
||||
'sound_changeeffectby' : this.changeEffect,
|
||||
'sound_cleareffects' : this.clearEffects,
|
||||
'sound_scales_menu' : this.scalesMenu,
|
||||
'sound_sounds_menu' : this.soundsMenu,
|
||||
'sound_roots_menu' : this.rootsMenu,
|
||||
'sound_beats_menu' : this.beatsMenu,
|
||||
'sound_effects_menu' : this.effectsMenu,
|
||||
};
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.playSound = function (args, util) {
|
||||
// self.postMessage({method: 'playsound', soundnum:args.SOUND_NUM});
|
||||
util.target.playSound(args.SOUND_NUM);
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.playSoundWithPitch = function (args, util) {
|
||||
self.postMessage({method: 'playsoundwithpitch', soundnum:args.SOUND_NUM, pitch:args.PITCH});
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.stopAllSounds = function (args, util) {
|
||||
self.postMessage({method: 'stopallsounds'});
|
||||
util.target.stopAllSounds();
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.playNoteForBeats = function (args, util) {
|
||||
self.postMessage({method: 'playnoteforbeats', note:args.NOTE, beats:args.BEATS});
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(function() {
|
||||
resolve();
|
||||
}, (1000 * args.BEATS) );
|
||||
});
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.playNote = function (args, util) {
|
||||
self.postMessage({method: 'playnote', note:args.NOTE});
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.scaleNoteToMidiNote = function (args, util) {
|
||||
|
||||
var root = parseInt(args.ROOT) + 60;
|
||||
|
||||
var scales = {
|
||||
'MAJOR' : [0,2,4,5,7,9,11],
|
||||
'MINOR' : [0,2,3,5,7,8,10],
|
||||
'PENTATONIC': [0, 2, 4, 7, 9],
|
||||
'CHROMATIC' : [0,1,2,3,4,5,6,7,8,9,10,11],
|
||||
};
|
||||
|
||||
var scale = scales[args.SCALE];
|
||||
|
||||
var scaleNote = args.NOTE;
|
||||
|
||||
var scaleIndex = (Math.round(scaleNote) - 1) % scale.length;
|
||||
if (scaleIndex < 0) {
|
||||
scaleIndex += scale.length;
|
||||
}
|
||||
var octave = Math.floor((scaleNote - 1) / scale.length);
|
||||
var midiNote = root + (octave * 12) + scale[scaleIndex];
|
||||
|
||||
return midiNote;
|
||||
util.target.playNoteForBeats(args.NOTE, args.BEATS);
|
||||
return new Promise(function(resolve) {
|
||||
setTimeout(function() {
|
||||
resolve();
|
||||
}, (1000 * args.BEATS) );
|
||||
});
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.playDrumForBeats = function (args, util) {
|
||||
|
@ -92,14 +52,6 @@ Scratch3SoundBlocks.prototype.playDrumForBeats = function (args, util) {
|
|||
});
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.playDrum = function (args, util) {
|
||||
self.postMessage({method: 'playdrum', drum:args.DRUMTYPE});
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.setKey = function (args, util) {
|
||||
self.postMessage({method: 'setkey', root:args.ROOT, scale:args.SCALE});
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.setEffect = function (args, util) {
|
||||
self.postMessage({method: 'seteffect', effect:args.EFFECT, value:args.VALUE});
|
||||
};
|
||||
|
@ -116,14 +68,6 @@ Scratch3SoundBlocks.prototype.soundsMenu = function (args, util) {
|
|||
return args.SOUND_MENU;
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.scalesMenu = function (args, util) {
|
||||
return args.SCALE;
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.rootsMenu = function (args, util) {
|
||||
return args.ROOT;
|
||||
};
|
||||
|
||||
Scratch3SoundBlocks.prototype.beatsMenu = function (args, util) {
|
||||
return args.BEATS;
|
||||
};
|
||||
|
|
|
@ -244,4 +244,12 @@ Clone.prototype.playSound = function (soundNum) {
|
|||
this.audioWorker.playSound(soundNum);
|
||||
}
|
||||
|
||||
Clone.prototype.stopAllSounds = function () {
|
||||
this.audioWorker.stopAllSounds();
|
||||
}
|
||||
|
||||
Clone.prototype.playNoteForBeats = function (note,beats) {
|
||||
this.audioWorker.playNoteForBeats(note, beats);
|
||||
}
|
||||
|
||||
module.exports = Clone;
|
||||
|
|
Loading…
Reference in a new issue