Reputation:
The code is running okay, but I'm sure there is a more efficient way to do this. At the moment it is working okay in Firefox, but falls to pieces in Chrome. The boolean values are checked at each step, which are 110ms apart, and the outcome whether the item in the array is true or false determines whether a sound is triggered or not (unique to that array). Something in the code is stacking when Chrome spikes, which is causing all kinds of glitches and leaks... I can't seem to figure out a way to bundle this all into one check on each loop, rather than running all these if
statements. Is it possible?
var loop = [{
"sound": "one",
"pattern": [true, false, false, false],
"volume": 100
},{
"sound": "two",
"pattern": [false, true, false, true],
"volume": 100
},{
"sound": "three",
"pattern": [true, true, true, true],
"volume": 100
}]
var s = 0;
function startLoop(){
if (playing === true){
setTimeout(function(){
if (typeof loop[0] !== "undefined") {
if (loop[0].pattern[s] === true){
soundset.play(loop[0].sound);
}
}
if (typeof loop[1] !== "undefined") {
if (loop[1].pattern[s] === true){
soundset.play(loop[1].sound);
}
}
if (typeof loop[2] !== "undefined") {
if (loop[2].pattern[s] === true){
soundset.play(loop[2].sound);
}
}
s++;
if (s < loop[0].pattern.length){
startLoop();
} else {
s = 0;
startLoop();
}
}, 110)
} else {return;}
};
The typeof loop[x] !== "undefined"
is in place in case loops above x
are not in place. The plan was to have about 10 of these running, but this way of checking each step is struggling at only three.
Upvotes: 1
Views: 140
Reputation: 206505
forEach()
instead of hardcoding loop[0], loop[1], etc…
. That way you can have endless instruments in your track. loop
object.audio
). true
and false
you can use 0
and 1
i to simply and cleanly instruct boolean values. 0.0
to 1.0
%
to loopback to 0
your s
ticker index.var bpm = 60; // Beats per minute
var div = 4; // "4/4 division" (the pattern length)
var s = 0;
var tickTimeout = null;
var loop = [{
name: "kick", // it's a sound/file name
pattern: [1, 0, 0, 0], // can be expressed using 0 and 1
volume: 1 // volume goes from 0.0 to 1.0, remember?
},{
name: "snare",
pattern: [0, 1, 0, 1],
volume: 1
},{
name: "hihat",
pattern: [1, 1, 1, 1],
volume: 1
}];
// Preload sounds
loop.map(function(obj){
obj.audio = new Audio("../audio/drumset-rock/"+ obj.name +".mp3");
obj.audio.volume = obj.volume;
});
// Play tick
function play(){
var names = ""; // Demo only
loop.forEach(function(obj) {
if (obj.pattern[s]) {
obj.audio.play(); // Play sound if in pattern
names += " "+ obj.name // Demo only
}
});
console.log(s +': '+ names); // Demo only
s = ++s % div; // Increment and loopback
tickTimeout = setTimeout(play, 1000 * 60 / bpm); // Next tick at bpm
}
function stop() {
clearTimeout(tickTimeout);
}
play(); // Start loop
// stop(); // Use to immediately stop drum machine
Upvotes: 0
Reputation: 56
Try this:
var loop = [
{
"sound": "one",
"pattern": [true, false, false, false],
"volume": 100
},{
"sound": "two",
"pattern": [false, true, false, true],
"volume": 100
},{
"sound": "three",
"pattern": [true, true, true, true],
"volume": 100
}
];
var s = 0;
function startLoop(){
if (playing !== true)
return;
setTimeout(function(){
for(const i in loop){
if(loop[i].pattern.hasOwnProperty(s)){
if(loop[i].pattern[s]){
soundset.play(loop[i].sound);
}
}else{
s = 0;
}
}
s++;
startLoop();
}, 110);
};
Upvotes: 0