How to offset note scheduling for interactive recording of notes via user controls
<p>In the code below I have a note scheduler that increments a variable named <code>current16thNote</code> up to 16 and then looping back around to 1. The ultimate goal of the application is to  allow the user to click a drum pad and push the <code>current16thNote</code> value to an array. On each iteration of <code>current16thNote</code>  a loop is run on the track arrays looking for the current <code>current16thNote</code> value, if it finds it the sound will play.</p>

<pre><code>    //_________________________________________________________General variable declarations
    var isPlaying = false,
        tempo = 120.0, // tempo (in beats per minute)
        current16thNote = 1,
        futureTickTime = 0.0,
        timerID = 0,
        noteLength = 0.05; // length of "beep" (in seconds)

    //_________________________________________________________END General variable declarations

    //_________________________________________________________Load sounds
    var kick = audioFileLoader("sounds/kick.mp3"),
        snare = audioFileLoader("sounds/snare.mp3"),
        hihat = audioFileLoader("sounds/hihat.mp3"),
        shaker = audioFileLoader("sounds/shaker.mp3");


    //_________________________________________________________END Load sounds




    //_________________________________________________________Track arrays
    var track1 = [],
        track2 = [5, 13],
        track3 = [],
        track4 = [1, 3, 5, 7, 9, 11, 13, 15];

    //_________________________________________________________END Track arrays





    //_________________________________________________________Future tick
    function futureTick() {
        var secondsPerBeat = 60.0 / tempo;
        futureTickTime += 0.25 * secondsPerBeat;

        current16thNote += 1;
        if (current16thNote &gt; 16) {
            current16thNote = 1
        }


    }

    //_________________________________________________________END Future tick



    function checkIfRecordedAndPlay(trackArr, sound, beatDivisionNumber, time) {

        for (var i = 0; i &lt; trackArr.length; i += 1) {
            if (beatDivisionNumber === trackArr[i]) {
                sound.play(time);
            }
        }

    }




    //__________________________________________________________Schedule note
    function scheduleNote(beatDivisionNumber, time) {


        var osc = audioContext.createOscillator(); //____Metronome

        if (beatDivisionNumber === 1) {
            osc.frequency.value = 800;
        } else {
            osc.frequency.value = 400;
        }
        osc.connect(audioContext.destination);

        osc.start(time);
        osc.stop(time + noteLength);//___________________END Metronome




        checkIfRecordedAndPlay(track1, kick, beatDivisionNumber, time);
        checkIfRecordedAndPlay(track2, snare, beatDivisionNumber, time);
        checkIfRecordedAndPlay(track3, hihat, beatDivisionNumber, time);
        checkIfRecordedAndPlay(track4, shaker, beatDivisionNumber, time);


    }



    //_________________________________________________________END schedule note


    //_________________________________________________________Scheduler

    function scheduler() {
        while (futureTickTime &lt; audioContext.currentTime + 0.1) {
            scheduleNote(current16thNote, futureTickTime);
            futureTick();

        }
        timerID = window.requestAnimationFrame(scheduler);
    }


    //_________________________________________________________END Scheduler
</code></pre>

<p><strong>The Problem</strong>
In addition to the previous code I have some user interface controls as shown in the following image.</p>

<p><a href="https://i.stack.imgur.com/AYmV9.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/AYmV9.png" alt="enter image description here"></a></p>

<p>When a user <code>mousedowns</code> on a “drum pad” I want to do two things. The first is to hear the sound immediately , and the second is to push the <code>current16thNote</code> value to the respective array.</p>

<p>If I use the following code to do this a few problems emerge.</p>

<pre><code>$("#kick").on("mousedown", function() {

    kick.play(audioContext.currentTime)
    track1.push(current16thNote)

})
</code></pre>

<p>The first problem is that the sound plays twice. This is because when the sound is pushed to the array it is immediately recognized by the next iteration of the note scheduler and immediately plays. I fixed this by creating a delay with setInterval to offset the push to the array.</p>

<pre><code>$("#kick").on("mousedown", function() {

    kick.play(audioContext.currentTime)

      window.setTimeout(function() {

             track1.push(note)

    }, 500)


})
</code></pre>

<p>The second problem is musical.</p>

<p>When a user clicks a drum pad the value that the user anticipates the drum will be recorded at is one 16th value <em>earlier</em>. In other words if you listen to the metronome and click on the kick drum pad with the intent of landing right on the 1/1 down beat this won't happen. Instead, when the metronome loops back around it will have been “recorded” at one 16th increment <em>later</em>.</p>

<p>This can be remedied by writing code that intentionally offsets the value that is pushed to the array by -1 .</p>

<p>I wrote a helper function named <code>pushNote</code> to do this.</p>

<pre><code>$("#kick").on("mousedown", function() {

    var note = current16thNote;
    kick.play(audioContext.currentTime)

    window.setTimeout(function() {

        pushNote(track1, note)

    }, 500)



})

//________________________________________________Helper
    function pushNote(trackArr, note) {

        if (note - 1 === 0) {

            trackArr.push(16)

        } else {

            trackArr.push(note - 1)

        }

    }

//________________________________________________END Helper
</code></pre>

<p>My question is really a basic one. Is there a way to solve this problem without creating these odd “offsets” ? </p>

<p>I suspect there is a way to set/write/place the <code>current16thNote</code> increment without having to create offsets to other parts of the program. But I'm hazy on what it could be. </p>

<p>In the world of professional audio recording there isn't a tick per 16th division value , you usually have 480 ticks per <em>quarter note</em>. I want to begin exploring writing my apps using this larger value but I want to resolve this "offset" issue before I go down that rabbit hole.</p>