Note events in the MOD player

#retrocomputing #javascript #demoscene #web-audio

Written by Anders Tornblad

This is part 9 of the JavaScript MOD Player series. If you haven't read the first part, here it is: Generating sound in modern Web Audio API

In the previous articles in this series, I have explored how to load and play back Amiga ProTracker MOD music in the browser, how to use timing events (watch and watchRows) to synchronize demo effects with music, and how to expose playback controls through the ModPlayer API.

Today, I'm introducing a new feature that was requested by Antoine Santo of CODEF fame: the ability for consumers of the playback module to listen to individual note events as they’re played by the player, for example to drive a sequencer visualization, or note-triggered demo effects.

What’s New

The watchNotes method lets you subscribe to each note as it begins, with metadata including:

With this you can react *in real time* to every note event in the song, without having to decode rows yourself or poll for state.

Here’s the updated ModPlayer class signature:

/// Subscribes to all individual notes starting
/// The callback for watchNotes must have the following signature:
/// callbackFunc( { channel: 1..4, sample: 1..32, volume: 1..64, note: -63..45 } )
watchNotes(callback) { }

When a note starts, the callback is invoked with a plain object describing the note event.

Why This Matters

Previously, you could use:

...but these only fire at the *row level* in the pattern data, and they don’t tell you *which notes* are being played on each channel, nor do they expose sample, volume, or relative pitch.

With watchNotes, you now get fine-grained musical events, allowing a whole new class of musical interactivity in the browser, to drive animated visualizers that respond to melody and rhythm.

---

Example Usage

Here's a minimal example:

player.watchNotes(({ channel, sample, volume, note }) => {
    console.log(`Channel ${channel}: note=${note}, sample=${sample}, vol=${volume}`);
    animateVisualizer(channel, volume);
});

This invokes animateVisualizer whenever a note starts, passing musical data to your animation logic.

🚀 Let me know...

If you build something with watchNotes, get in touch. I’d love to showcase your work!

You can try this solution at atornblad.github.io/js-mod-player. The latest version of the code is always available in the GitHub repository.

Articles in this series: