play sound and play note block

This commit is contained in:
Eric Rosenbaum 2016-09-13 17:52:54 -04:00
parent 7709a4095e
commit d9a703b4ad
5 changed files with 54 additions and 143 deletions

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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>

View file

@ -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;
};

View file

@ -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;