user10650826
user10650826

Reputation:

Checking booleans from multiple arrays simultaneously, without multiple if statements

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

Answers (2)

Roko C. Buljan
Roko C. Buljan

Reputation: 206505

  • Use forEach() instead of hardcoding loop[0], loop[1], etc…. That way you can have endless instruments in your track.
  • Clear your tick timeout when stopping (or pausing) your playback.
  • Preload your sounds (and populate them into each respective loop object.audio).
  • Instead of true and false you can use 0 and 1 i to simply and cleanly instruct boolean values.
  • Volume goes from 0.0 to 1.0
  • You can use Modulo oparator % 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

Zakaria Chabihi
Zakaria Chabihi

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

Related Questions