Skip to main content

The MIDI event stream

Feed a hardware synth over MIDI-out. Drive a stage-light show off the beat pulses. Log every note-on for post-session analysis. Anywhere you need something to happen the moment the audio plays it, subscribe to midiEventsPlayed. alphaTab surfaces every event the synthesizer sees β€” note-on, note-off, tempo changes, program changes, metronome ticks, and rests β€” filtered to only the types you asked for.

00:00 / 00:00
Filter: NoteOn, AlphaTabMetronome, TempoChange
Press play to see events…

Filter first, then subscribe​

For performance, alphaTab only fires events that match midiEventsPlayedFilter. Without a filter, the event does not fire even if you subscribe. Populate the filter with entries from alphaTab.midi.MidiEventType:

  • NoteOn / NoteOff β€” every note the synth plays.
  • AlphaTabMetronome β€” the metronome ticks generated by alphaTab (carry beat position, subdivision, and duration).
  • AlphaTabRest β€” synthetic events marking rests.
  • TempoChange β€” tempo automation, useful for converting ticks to wall-clock time.
  • TimeSignature, ProgramChange, ControlChange, PitchBend β€” for timing UIs and DAW-style integrations.

Latency and buffering​

Events fire once the audio buffer has actually played them, not when they enter the synth. Expect a delay proportional to player.bufferTimeInMilliseconds β€” around 50 to 100 ms in a typical browser setup. If your UI needs frame-accurate feedback, keep the buffer small; if it needs stability, keep the buffer large and compensate with a lookahead.

Show it in code​

import * as alphaTab from '@coderline/alphatab';

const container = getAlphaTabContainer();
const api = new alphaTab.AlphaTabApi(container, {
core: { file: '/scores/song.gp' },
player: {
playerMode: alphaTab.PlayerMode.EnabledSynthesizer,
soundFont: '/soundfont/sonivox.sf2',
},
});

api.midiEventsPlayedFilter = [
alphaTab.midi.MidiEventType.NoteOn,
alphaTab.midi.MidiEventType.NoteOff,
alphaTab.midi.MidiEventType.AlphaTabMetronome,
];

api.midiEventsPlayed.on((e) => {
for (const event of e.events) {
if (event.type === alphaTab.midi.MidiEventType.NoteOn) {
console.log(`note on: key=${event.noteKey} vel=${event.noteVelocity} ch=${event.channel}`);
} else if (event.type === alphaTab.midi.MidiEventType.NoteOff) {
console.log(`note off: key=${event.noteKey} ch=${event.channel}`);
} else if (event.isMetronome) {
console.log(`metronome: beat ${event.metronomeNumerator + 1}`);
}
}
});

getAlphaTabContainer() is a placeholder for the platform-specific step of obtaining the render target β€” a <div> on Web, an AlphaTab control on .NET, or an AlphaTabView on Android. midiEventsPlayed fires with the same event shape on every runtime.

Where to look next​