spessasynth_lib documentation
    Preparing search index...

    Advanced Example

    See this demo live

    The previous example is very basic, as it only allows uploading a single MIDI file. We can add more features such as play/pause and time controls to our player without much effort.

    Let's add some control buttons:

    <p id="message">Please wait for the sound bank to load.</p>
    <input accept=".mid, .rmi, .xmf, .mxmf" id="midi_input" multiple type="file" />
    <br /><br />
    <input id="progress" max="1000" min="0" type="range" value="0" />
    <br />

    <button id="previous">Previous song</button>
    <button id="pause">Pause</button>
    <button id="next">Next song</button>

    <!-- note the type="module" -->
    <script src="advanced_demo.js" type="module"></script>

    Now we need to add functionality to those buttons:

    • Input can now accept more files
    • Previous song button
    • Pause button
    • Next song button
    • Song progress slider
    // Import the modules
    import { Sequencer, WorkletSynthesizer } from "../../src";
    import {
    EXAMPLE_SOUND_BANK_PATH,
    EXAMPLE_WORKLET_PATH
    } from "../examples_common";

    // Load the sound bank
    const response = await fetch(EXAMPLE_SOUND_BANK_PATH);

    // Load the sound bank into an array buffer
    const sfBuffer = await response.arrayBuffer();
    document.querySelector("#message")!.textContent = "Sound bank has been loaded!";

    // Create the context and add audio worklet
    const context = new AudioContext();
    await context.audioWorklet.addModule(EXAMPLE_WORKLET_PATH);
    const synth = new WorkletSynthesizer(context); // Create the synthesizer
    synth.connect(context.destination);
    await synth.soundBankManager.addSoundBank(sfBuffer, "main");
    const seq = new Sequencer(synth);

    // Add an event listener for the file input
    document
    .querySelector("#midi_input")!
    .addEventListener("change", async (event) => {
    // Check if any files are added
    const target = event.target as HTMLInputElement;
    const files = target.files;
    if (files === null || files.length === 0) {
    return;
    }
    // Resume the context if paused
    await context.resume();
    // Parse all the files
    const parsedSongs: { binary: ArrayBuffer; fileName: string }[] = [];
    for (const file of files) {
    const buffer = await file.arrayBuffer();
    parsedSongs.push({
    binary: buffer, // Binary: the binary data of the file
    fileName: file.name // FileName: the fallback name if the MIDI doesn't have one. Here we set it to the file name
    });
    }
    seq.loadNewSongList(parsedSongs); // Load the song list
    seq.play(); // Play the midi

    // Make the slider move with the song
    const slider = document.querySelector<HTMLInputElement>("#progress")!;
    setInterval(() => {
    // Slider ranges from 0 to 1000
    slider.value = String((seq.currentTime / seq.duration) * 1000);
    }, 100);

    // On song change, show the name
    seq.eventHandler.addEvent(
    "songChange",
    "example-time-change",
    (event) => {
    document.querySelector("#message")!.textContent =
    "Now playing: " + event.midiData.getName();
    }
    ); // Make sure to add a unique id!

    // Add time adjustment
    slider.addEventListener("change", () => {
    // Calculate the time
    seq.currentTime = (Number(slider.value) / 1000) * seq.duration; // Switch the time (the sequencer adjusts automatically)
    });

    // Add button controls
    document.querySelector("#previous")!.addEventListener("click", () => {
    seq.songIndex--; // Go back by one song
    });

    // On pause click
    document.querySelector("#pause")!.addEventListener("click", () => {
    if (seq.paused) {
    document.querySelector("#pause")!.textContent = "Pause";
    seq.play(); // Resume
    } else {
    document.querySelector("#pause")!.textContent = "Resume";
    seq.pause(); // Pause
    }
    });
    document.querySelector("#next")!.addEventListener("click", () => {
    seq.songIndex++; // Go to the next song
    });
    });

    // Make both objects accessible through the console
    Object.assign(globalThis, { synth, seq });