javascripttonejs

Using tone.js to play a wav file at specific intervals


When I attempt to use tone.js's Player to repeatedly play a wav file at specific intervals (i.e., at the start, the first measure, and the fourth measure), the first few tones are at the correct intervals but subsequent tones are played at the beginning of every interval.

My html file has a button to start the playing:

<button id="playIt">Play</button>

Here is my javascript/jquery:

$(document).ready(function () {
    $("#playIt").click(function () {
        if (Tone.context.state != "running") {
            Tone.start();
        }

        playNotes();
    });
});

const player = new Tone.Player({
    url: "/tick.mp3",
    loop: true,
    autostart: false
}).toDestination();

Tone.Transport.bpm.value = 140;

// Schedule the player to start at specific times
Tone.Transport.schedule(time => {
    player.start(time);
}, "0:0:0"); // Play at the start

Tone.Transport.schedule(time => {
    player.start(time);
}, "0:1:0"); // Play at 1st measure

Tone.Transport.schedule(time => {
    player.start(time);
}, "0:4:0"); // Play at 4th measure

async function playNotes() {
    Tone.Transport.start();
}

If I turn off looping, it plays once, correctly. When it loops, it plays correctly once and then plays the tone on every measure.

Thanks for your help!


Solution

  • You need to not loop and let the scheduleRepeat do the playing

    Something like this

    $(document).ready(function() {
      $("#playIt").click(function() {
        if (Tone.context.state !== "running") {
          Tone.start(); 
        }
        Tone.Transport.start();
      });
    });
    
    const player = new Tone.Player({
      url: "/tick.mp3",
      loop: false, // We handle repetition later
      autostart: false
    }).toDestination();
    
    Tone.Transport.bpm.value = 140;
    const tickDuration = "8n"; // Adjust as needed
    const cycleLength = "4m"; // Repeats every 4 measures
    
    // Schedule and repeat tick sounds
    ["0:0:0", "0:1:0", "0:4:0"].forEach(time => {
      Tone.Transport.scheduleRepeat(t => {
        player.start(t);
        player.stop(t + Tone.Time(tickDuration));
      }, cycleLength, time);
    });