TimidityPlayer is a high-level JavaScript class that provides an interface to the libTiMidity WebAssembly module. It handles MIDI playback, real-time MIDI input, audio context management, patch downloading, and offline audio rendering.
Creates a new instance of the TimidityPlayer.
- Parameters:
options(Object): Configuration options.options.patchUrlBase(string): Base URL path for loading GUS patches andtimidity.cfg(e.g.,'gus-patch').options.buffserSize(number): Buffer size for audio processing. Default value is 4096. Note: A larger buffer size increases stability and reduces glitches, but it also introduces more latency, making real-time response (e.g., when playing notes from a MIDI controller) slower.options.bufferSizeRealtime(number) - Buffer size for realtime event (e.g noteOn). Default value is 1024options.sampleRate(number): Sample rate to render PCM. Default value is 44100.
The player exposes an internal event emitter that broadcasts state changes and MIDI events. Two registration styles are supported and are fully equivalent:
- Generic form:
player.on(eventName, listener)— the classic, explicit API. - Shorthand form:
player.onXxx(listener)— a convenient proxy that forwards toon('onXxx', listener).
Registers a callback function for a specific event.
- Parameters:
eventName(string): The name of the event, including theonprefix (e.g.,'onError','onMidiLoaded').listener(Function): Callback to execute when the event fires.
Dynamically generated for every supported event. Calling player.onError(cb) is exactly equivalent to player.on('onError', cb).
The shorthand is implemented via a Proxy on the instance. Any property access that:
- starts with
"on", and - is not already defined on the player,
is treated as an event registration function. It returns a function that forwards its arguments to on(eventName, ...args).
- Parameters:
listener(Function): Callback to execute when the event fires....extraArgs(any): Optional additional arguments passed through toon()(reserved for future use, e.g.{ once: true }).
- Returns:
undefined
Note: The
Proxyonly intercepts properties that do not already exist on the instance. Existing methods such ason,once(if you add one),onRuntimeInitialized(if set as a real property), or any future method whose name starts withonwill not be shadowed.
Note: Because the shorthand is generated on-the-fly, it is not enumerable and does not appear in
Object.keys(player). Use the genericon()form if you need to iterate over registered handlers.
Manually emits an event, invoking all registered listeners with the supplied arguments.
- Parameters:
eventName(string): The event name (with theonprefix)....args(any): Arguments forwarded to each listener.
Events are listed in onXxx form. The equivalent generic name is 'onXxx' (e.g., player.onError(cb) ⇔ player.on('onError', cb)).
| Event | Arguments | Description |
|---|---|---|
onRuntimeInitialized |
(none) | Fired when the WASM runtime reports it is ready (before onInit). |
onInit |
(none) | Fired when the WebAudio context and WASM engine are initialized. |
onMidiLoading |
(midi) |
Fired when a MIDI file starts loading. |
onMidiLoaded |
(midi, duration) |
Fired when a MIDI file has been fully loaded and parsed. |
onMidiUpdated |
(midi) |
Fired after updateMidiData() succeeds. |
onInstrumentLoading |
(loadedCount, totalCount, filename) |
Fired while downloading required patch files. |
onInstrumentLoaded |
(totalCount) |
Fired when all required patches have been successfully downloaded. |
onPlay |
(none) | Fired when playback starts. |
onPause |
(none) | Fired when playback is paused. |
onResume |
(none) | Fired when playback resumes after a pause. |
onStop |
(none) | Fired when playback is stopped and the song is unloaded. |
onEnded |
(none) | Fired when the song reaches its end naturally. |
onPlaying |
(tick, timeInSeconds) |
Fired periodically during playback to report progress. |
onSeek |
(tick, timeInSeconds) |
Fired when the playback position is manually shifted. Emitted twice per seek() call (before and after the engine seek). |
onRenderStart |
(none) | Fired when offline rendering starts. |
onRenderProgress |
(progressPercent) |
Fired during offline rendering. |
onRenderComplete |
(wavBlob) |
Fired when offline rendering finishes. |
onNoteOn |
({tick, channel, pitch, velocity}) |
Fired for Note On events. |
onNoteOff |
({tick, channel, pitch}) |
Fired for Note Off events (and Note On with velocity 0). |
onMidiEvent |
({tick, timeSecond, status, eventType, channel, a, b, text}) |
Fired for every MIDI event processed by the engine. |
onError |
(message) |
Fired when an internal error occurs. |
const player = new TimidityPlayer({ patchUrlBase: 'gus-patch' });
await player.init();
// Shorthand form
player.onInit(() => console.log('ready'));
player.onError(err => console.error(err));
player.onMidiLoaded((midi, duration) => console.log('duration', duration));
player.onNoteOn(({ pitch, velocity }) => console.log('note', pitch, velocity));
// Generic form — exactly equivalent
player.on('onInit', () => console.log('ready'));
player.on('onError', err => console.error(err));
// Listeners receive any number of arguments passed by emit()
player.onMidiEvent(ev => {
console.log(ev.tick, ev.channel, ev.eventType, ev.a, ev.b);
});
// Manual emit (rarely needed; listeners will fire synchronously)
player.emit('onError', new Error('custom'));Initializes the WebAudio context and the libTiMidity engine. Must be called before loading or playing any MIDI files.
- Parameters:
offline(boolean): Iftrue, creates anOfflineAudioContextfor rendering without audio playback.
- Returns:
Promise<boolean>-trueif initialization was successful.
Completely shuts down the player, stops playback, frees memory, and closes the WebAudio context.
Loads a MIDI file into the player and automatically analyzes and downloads the required patches.
- Parameters:
midi(File | Uint8Array): The MIDI file data.
- Returns:
Promise<boolean>-trueif loaded successfully.
Starts or resumes playback of the currently loaded MIDI song.
- Parameters:
offset(number): Time offset in seconds to start playing from.options(Object): Additional playback configuration. (Note: Currently intimidity-player.js, this object is empty and reserved for future use. No specific properties are implemented yet.)
Convenience method to sequentially call load() and play().
- Parameters:
midi(File | Uint8Array): The MIDI file data.offset(number): Time offset in seconds.options(Object): Additional playback configuration.
- Returns:
Promise<void>
Controls the playback state. stop() will also free the currently loaded song from memory.
Updates the currently playing MIDI data on-the-fly without stopping playback. The player will seamlessly transition to the new event list from its current time.
- Parameters:
midi(File | Uint8Array): The new MIDI file data to load.
- Returns:
Promise<boolean>-trueif the update was successful.
Controls the playback state. stop() will also free the currently loaded song from memory.
Seeks to a specific time position within the currently loaded MIDI song.
- Parameters:
timeInSeconds(number): The absolute target time in seconds.
Seeks to a specific MIDI tick position. This method parses the MIDI tempo map internally to accurately calculate the corresponding absolute time in seconds.
- Parameters:
ticks(number): The absolute target tick position.
Sets the master volume of the loaded song.
- Parameters:
volume(number): The volume level (0 to 100).
Sets the global pitch transpose.
- Parameters:
semitones(number): The number of semitones to shift (-12 to +12).
Mutes or unmutes a specific MIDI channel.
- Parameters:
channel(number): MIDI channel (0-15).mute(boolean):trueto mute,falseto unmute.
Mutes or unmutes a specific MIDI track.
- Parameters:
track(number): MIDI track index (0-255).mute(boolean):trueto mute,falseto unmute.
Instantly kills all currently sounding notes across all channels.
Sends a MIDI Note On message. Dynamically downloads the instrument patch if it hasn't been loaded yet.
- Parameters:
channel(number): MIDI channel (0-15).program(number): Instrument program number (0-127).pitch(number): MIDI pitch/note (0-127).velocity(number): Note velocity (0-127). Default is100.params(Object): Optional parameters to control the instrument's initial state.params.bank(number): Instrument bank number. Default is0.params.pan(number): Panning (0-127). Default is64(center).params.bend(number): Pitch bend (0-16383). Default is8192(center).params.modulation(number): Modulation wheel (0-127). Default is0.params.chorus(number): Chorus depth (0-127). Default is0.params.sustain(number): Sustain pedal (0-127). Default is0.
Sends a MIDI Note Off message.
Broadcasts a general MIDI event to the active synthesizer.
- Parameters:
eventType(number): Internal TiMidity event constant (e.g.,this.ME_PITCHWHEEL).
Gets metadata and information about the currently loaded song.
- Returns:
Object | null- Parsed JSON object containing song info (title, copyright, text events, etc.).
Gets the parsed tempo map of the currently loaded MIDI song.
- Returns:
Object | null- An object containing the MIDIdivision(ticks per beat) and atimeMaparray ([{tick, timeSec, mpqn}]), ornullif no song is loaded.
Converts a MIDI tick into an absolute beat number (useful for syncing metronomes).
- Parameters:
tick(number): The absolute tick position.
- Returns:
number- The absolute beat count (e.g.,0.5,1.0,16.0).
Converts a MIDI tick into a measure/bar number (useful for vocal training or DAW measure sync).
- Parameters:
tick(number): The absolute tick position.
- Returns:
number- The absolute measure count (1-indexed).
Converts a MIDI tick into an absolute time value in seconds.
- Parameters:
tick(number): The absolute tick position.
- Returns:
number- The corresponding absolute time in seconds, calculated based on the tempo map and ticks-per-quarter-note (PPQN) division.
Checks if a specific MIDI tick aligns exactly with a metronome click.
- Parameters:
tick(number): The absolute tick position.
- Returns:
Object | null- Metronome state at this tick:{ isClick: boolean, isDownbeat?: boolean, beatNumber?: number, measure?: number }, ornullif invalid.
- Returns:
number- The number of currently active polyphony voices.
- Returns:
number- The controller value (0-127) at the exact tick position.
These methods read directly from the timidity.cfg file located at patchUrlBase.
- Returns:
Promise<number[]>- A sorted array of available bank IDs.
- Parameters:
bank(number): The target bank ID.
- Returns:
Promise<Array<{id: number, file: string}>>- A sorted array of instrument objects containing the programidand the patchfileor name.
- Parameters:
bank(number): The target drumset bank ID.
- Returns:
Promise<Array<{id: number, file: string}>>- A sorted array of drum instrument objects.
Renders the currently loaded MIDI song to a WAV file offline (without playing it over speakers). Yields progress via the onRenderProgress event.
- Parameters:
options(Object): Configuration options for rendering.options.sampleRate(number): The target sample rate (default44100).options.isMono(boolean): If true, forces audio to 1 channel and sets all CC pan events to center (defaultfalse).options.isSpatial(boolean): If true, applies 3D spatial audio processing using Web AudioPannerNodebased on CC 20 (Y/Height) and CC 21 (Z/Depth) events. ForcesisMonoto false (defaultfalse).options.isSpatialInterpolation(boolean): If true, smoothly interpolates the spatial coordinates between CC events (defaultfalse).options.monoToStereo(boolean): If true, applies stereo widening (Spectral Panning / EQ) to the final output.options.monoToStereoWeight(number): The intensity of the stereo widening effect (gain in dB) (default5).options.soloTrack(number): If set to a valid track number, mutes all other tracks during rendering (default-1).
- Returns:
Promise<Blob>- The generated WAV file as aBlob.
Exports audio stems by iteratively rendering selected tracks offline. For each track, it solos the track, renders the full song duration, and calls the callback with the resulting WAV file. The onRenderProgress event will still fire repeatedly for each stem rendering cycle.
- Parameters:
trackList(number[]): Array of track numbers to export. If null or an empty array is provided, it defaults to exporting all parsed tracks in the MIDI file.options(Object): Configuration options passed directly torenderOffline(e.g.,{ monoToStereo: true }).callback(Function): A function called after each stem completes. Signature:callback(wavBlob, trackIndex).
- Returns:
Promise<void>- Resolves when all requested stems have been successfully exported.
Formats seconds into a human-readable string (e.g., H:MM:SS or M:SS.mmm).
- Returns:
string
The following functions are compiled from C and exported directly to JavaScript via the WebAssembly module (this.Module). They are primarily used internally by TimidityPlayer.
Creates a MidSongOptions struct dynamically via malloc and populates it. This is particularly used for setting up offline rendering audio configurations.
- Parameters:
rate(number): Sample rate (e.g., 44100).format(number): Audio format flag (e.g.,0x8010forMID_AUDIO_S16LSB).channels(number): Number of channels (1for mono,2for stereo).buffer_size(number): Buffer size in samples.
- Returns:
number- A memory pointer to the allocatedMidSongOptionsstruct.