3

While looking through the Tone.JS documentation, I found that MIDI files were supported.

MIDI To use MIDI files, you’ll first need to convert them into a JSON format which Tone.js can understand using Midi. Although there are many resources online to convert MIDI to JSON, I have not found a single code example or any documentation demonstrating the usage of MIDI files and/or JSON files.

Throughout many journeys through the documentation, I only found examples for playing .mp3 files and using effects. Google search was unfruitful as well. Is there anyone that can give me a code snippet demonstrating this?

py660
  • 138
  • 11

3 Answers3

1

Check out the source code of http://tonejs.github.io/Midi/. The JS is in the <script> tag at the bottom of the <body>

It looks like you need to loop through the object manually and schedule each note with tonejs. Here is the relevant part of the code. currentMidi is the Midi object constructed using the result of reading the midi file from the upload box. currentMidi is then looped through and has its tracks and notes processed and scheduled.

let currentMidi = null;

function parseFile(file) {
    //read the file
    const reader = new FileReader();
    reader.onload = function (e) {
        const midi = new Midi(e.target.result);
        document.querySelector(
            "#ResultsText"
        ).value = JSON.stringify(midi, undefined, 2);
        document
            .querySelector("tone-play-toggle")
            .removeAttribute("disabled");
        currentMidi = midi;
    };
    reader.readAsArrayBuffer(file);
}

const synths = [];
document
    .querySelector("tone-play-toggle")
    .addEventListener("play", (e) => {
        const playing = e.detail;
        if (playing && currentMidi) {
            const now = Tone.now() + 0.5;
            currentMidi.tracks.forEach((track) => {
                //create a synth for each track
                const synth = new Tone.PolySynth(Tone.Synth, {
                    envelope: {
                        attack: 0.02,
                        decay: 0.1,
                        sustain: 0.3,
                        release: 1,
                    },
                }).toDestination();
                synths.push(synth);
                //schedule all of the events
                track.notes.forEach((note) => {
                    synth.triggerAttackRelease(
                        note.name,
                        note.duration,
                        note.time + now,
                        note.velocity
                    );
                });
            });
        } else {
            //dispose the synth and make a new one
            while (synths.length) {
                const synth = synths.shift();
                synth.disconnect();
            }
        }
    });

To get the Midi class you will need https://github.com/Tonejs/Midi. I think their claim that it is tonejs friendly is a bit exaggerated, as you still need to write the code to play the individual notes, with all the setup required for that also. I would expect more of a single function to play the returned Midi object.

Luke B
  • 2,075
  • 2
  • 18
  • 26
0

Look to source code of MIDI-player https://surikov.github.io/webaudiofont/examples/midiplayer.html

user1024
  • 1,121
  • 1
  • 9
  • 17
0

If you are handling multiple side effects in addition to triggering the note, you can use transport to schedule them ensuring they occur simultaneously:

aSingleParsedMidiTrack.notes.forEach((note) => {
    const startTime = Tone.Time(note.time).toSeconds();
    const duration = Tone.Time(note.duration).toSeconds();

    Tone.Transport.schedule((time) => {

      sharedState.synth.triggerAttackRelease(
        note.name,
        duration,
        startTime,
        note.velocity
      );

      // side effects
      piano.dispatchEvent(
        new CustomEvent("highlight", { detail: { notes: [note.name] } })
      );
      canvas.dispatchEvent(
        new CustomEvent("paint", { detail: { notes: [note.name] } })
      );
    }, startTime);
}

Tone.Transport.start(0); // start at the beginning

This ensures side effects are processed at the head of a notes sound.

random-forest-cat
  • 33,652
  • 11
  • 120
  • 99