Manatee · Dreamcast audio & sound driver, explained
The Manatee driver

The sequencer

Each of the eight MIDI ports has a song player that reads compact sequence data from sound RAM and turns it into timed events. The format is smaller than a standard MIDI file, the timing is sample-exact, and note-offs are generated by the driver itself.

Songs in sound RAM

A sequence bank (tagged SMSB) is a list of sequences (SMSD), each with a small header (time base and initial tempo) and a single stream of events for all 16 MIDI channels. The game plays one with sdMidiPlay(port, bank, song, priority); the driver checks the bank's tag, version and end marker, then starts the port's player at the first event.

What a sequence contains

Notes, compactly

A note event carries the channel, note number, velocity, a gate length (how long to hold it) and the delay to the next event. There is no separate note-off in the data: the driver queues the note-off itself.

Channel messages

Controllers, program changes, pressure and pitch bend, each followed by its delay. The delay is one or two bytes, flagged in the event itself.

Tempo

Tempo changes are given in milliseconds per beat.

Structure

A one-level loop (start marker, end marker, repeat count or "forever"), a call ("play n events from over there, then come back") for repeated phrases, and an end marker.

Long values

Prefix events that extend the next note's gate or the next delay for very long notes and rests, keeping the common case short.

Status for the game

The port's status record exposes the current position, the number of beats played and the loop counter, which is how a game can synchronise to music.

Timing

Each port has a delay counter. Every 4 ms the port's current speed (1.0 = normal) is subtracted from it; when it runs out, the player executes events until one carries a non-zero delay, and adds that delay (converted using the current tempo and the song's time base) to the counter. Because the leftover of each subtraction is kept, there is no rounding drift, and because the 4 ms tick itself is exact, songs stay locked to the audio clock indefinitely.

delay 4 ms ticks → note fires, reload next event, reload Each step subtracts the port speed. Doubling the speed halves every delay: tempo changes without re-timing the data.
Figure 1. A port's delay counter (illustrative). Speed fades from the game change the slope smoothly.

Generated note-offs

When a note plays, the driver puts its note-off into a shared queue of 48 pending note-offs, each counting down with the port's speed. When the queue is full and another note arrives, one pending note is cut short: the driver prefers a priority-0 entry, otherwise the last entry with the lowest priority, and sends its note-off immediately. If the event ring itself is full, events wait in a 60-entry overflow queue.

What the game controls per port

CommandEffect
play / stopstart a sequence; stop it and release its voices
pause / continuefreeze the counters and key off the port's voices; resume, re-sounding held notes
volume, pan, pitch, speedeach with a fade time: the driver moves the value step by step every 4 ms
effect send, direct levelhow much of the port goes to the DSP and to the dry mix
break looplet a looping section finish and continue past it (e.g. to play an ending)
reset parameters, stop allback to defaults; silence every port
send MIDI messageinject any MIDI event into the port, for interactive music

Priorities

Every port is started with a priority. It is stamped on every event the port emits and becomes the priority of each voice it allocates. That gives a game a simple mixing policy for 48 voices: give sound-effect ports a higher priority than music, and effects will steal voices from the music when the scene gets busy, never the other way round.

Edge cases in this build

The sequencer has a few failure modes under overload: a port can stall for many minutes if the ring fills at the wrong moment, and when both the note-off queue and the overflow queue are full the steal path unbalances the stack and jumps to a low address (a crash). Both need extreme event rates. See the quirks page.