Sequencer

The KN5000 includes a full-featured 16-track MIDI sequencer with real-time and step recording, playback, and editing capabilities. It also runs the auto-accompaniment style system and Feature Demo playback.

Architecture

The sequencer engine runs on the Main CPU and generates MIDI events that are sent to the Sub CPU via the inter-CPU latch for sound generation. The architecture has three main stages: a tick-driven dispatcher, a ring buffer pipeline, and MIDI event processing.

┌─────────────────────────────────────────────────────────────────────────┐
│                     MAIN CPU SEQUENCER ENGINE                           │
│                                                                         │
│  MainLoop (0xEF1245) ─── continuous loop ──────────────────────┐        │
│       │                                                        │        │
│       ├─ Seq_TickWrapper (0xEF1388) ─────────────────┐         │        │
│       │       │                                      │         │        │
│       │       └─ Seq_DispatcherEntry (0xF532E1)      │         │        │
│       │               │                              │         │        │
│       │               └─ Seq_DispatcherTick           │         │        │
│       │                       │                      │         │        │
│       │              ┌────────┴─────────┐            │         │        │
│       │              │ State Check      │            │         │        │
│       │              │ (8D36h)          │            │         │        │
│       │              │ skip if 0x10-0x16│            │         │        │
│       │              └────────┬─────────┘            │         │        │
│       │                       │                      │         │        │
│       │              Seq_DispatcherTick_Process       │         │        │
│       │                       │                      │         │        │
│       │              ┌────────┴─────────┐            │         │        │
│       │              │ RhythmROM_       │            │         │        │
│       │              │ CheckValid       │            │         │        │
│       │              │ (3277h check)    │            │         │        │
│       │              └────────┬─────────┘            │         │        │
│       │                       │                      │         │        │
│       │              Seq_RhythmProcessor (0xF5EC75)   │         │        │
│       │              RhythmROM_PatternDispatcher       │         │        │
│       │                       │                      │         │        │
│       │               ┌───────┴────────┐             │         │        │
│       │               │  Song Engine   │             │         │        │
│       │               │  writes MIDI   │─────────┐   │         │        │
│       │               │  to ring buf   │         │   │         │        │
│       │               └────────────────┘         │   │         │        │
│       │                                          v   │         │        │
│       │                              ┌──────────────────┐      │        │
│       │                              │  RING BUFFER     │      │        │
│       │                              │  Base: 0x01F37B  │      │        │
│       │                              │  WrPos: 0x01F377 │      │        │
│       │                              │  RdPos: 0x01F373 │      │        │
│       │                              └────────┬─────────┘      │        │
│       │                                       │                │        │
│       ├─ Seq_EventProcessingTick (0xEF14A3) ──┘                │        │
│       │       │                                                │        │
│       │       └─ Seq_ProcessEventLoop (0xEF14CA)               │        │
│       │               │                                        │        │
│       │       ┌───────┴──────────┐                             │        │
│       │       │ Seq_CheckSongEnd │                             │        │
│       │       │ WrPos == RdPos?  │                             │        │
│       │       └───────┬──────────┘                             │        │
│       │               │ (if data available)                    │        │
│       │               v                                        │        │
│       │       Seq_ProcessMidiEvent (0xEF13CD)                  │        │
│       │               │                                        │        │
│       │       ┌───────┴──────────────────────────┐             │        │
│       │       │ Parse MIDI status byte:           │             │        │
│       │       │  0x90 = Note On                   │             │        │
│       │       │  0x80 = Note Off                  │             │        │
│       │       │  0xB0 = Control Change            │             │        │
│       │       │  0xC0 = Program Change            │             │        │
│       │       │  0xE0 = Pitch Bend                │             │        │
│       │       └──────────────────────────────────┘             │        │
│       │                       │                                │        │
│       │                       v                                │        │
│       │               sendCOMM (0xEF32F4)                      │        │
│       │               Inter-CPU Latch → Sub CPU                │        │
│       │                                                        │        │
│       └────────────────────────────────────────────────────────┘        │
└─────────────────────────────────────────────────────────────────────────┘

Main Loop

The Main CPU firmware’s main application loop at MainLoop (0xEF1245) runs continuously after boot. Each iteration calls two sequencer functions:

Routine Address Purpose
Seq_TickWrapper 0xEF1388 Drives the sequencer tick dispatcher (song position advance, pattern loading)
Seq_EventProcessingTick 0xEF14A3 Reads MIDI events from the ring buffer and dispatches them to the Sub CPU

The main loop also handles other firmware tasks (UI updates, floppy I/O, MIDI processing) between sequencer calls, with control flow returning to MainLoop via JRL T.

Sequencer Dispatcher

The tick dispatcher processes sequencer timing and loads song/pattern data. It runs through a guarded pipeline:

Entry and Guards

Routine Address Purpose
Seq_DispatcherEntry 0xF532E1 Entry point from Seq_TickWrapper
Seq_DispatcherTick 0xF53318 State guard: skips processing if (8D36h) is 0x10-0x16
Seq_DispatcherTick_Process 0xF53328 Rhythm ROM guard: calls RhythmROM_CheckValid, skips if validation fails
Seq_RhythmProcessor 0xF5EC75 Main rhythm/sequencer processing after guards pass

State Machine Variable (8D36h)

The master sequencer state is stored in RAM at 0x8D36. The state controls which processing paths are active:

State Range Behavior
0x10-0x16 Skip allSeq_DispatcherTick returns immediately
0x00-0x0F, 0x17+ Process — dispatcher continues to tick processing

State transitions are written at a single location in the firmware: SeqState_TransitionMode (0xF9936D), which executes LD (8D36h), L.

Observed states during Feature Demo (from MAME log):

State Meaning When
0x00 Idle/startup Boot through initialization
0x01 Pre-demo Brief transition state
0xE0 DemoMode_Main_Operation Demo playback active (t=21s)
0xE4 DemoMode_Initialize Demo init complete (t=22.6s)

None of these values fall in the 0x10-0x16 skip range, confirming the sequencer dispatcher IS active during demo mode.

Ring Buffer Pipeline

The sequencer uses a ring buffer at RAM 0x01F37B to queue MIDI events for processing:

Variable Address Purpose
Read Position 0x01F373 Current read index
Write Position 0x01F377 Current write index
Buffer Data 0x01F37B Circular buffer start

Ring Buffer Routines

Multiple ring buffer instances exist for different sequencer channels. The core ring buffer implementation provides:

Routine Address Purpose
Seq_RingBuf_Init_256 0xEF2F69 Initialize 256-byte ring buffer
Seq_RingBuf_Init_512 0xEF2FF8 Initialize 512-byte ring buffer
Seq_RingBuf_Init_1024 0xEF3087 Initialize 1024-byte ring buffer
Seq_RingBuf_Init_2048 0xEF3116 Initialize 2048-byte ring buffer
Seq_RingBuf_ReadByte 0xEF2F83 Read one byte from ring buffer
Seq_RingBuf_ReadData 0xEF30BF Read data block from ring buffer
Seq_RingBuf_WriteByte 0xEF30F5 Write one byte to ring buffer
Seq_RingBuf_WriteByte_Small 0xEF2FD7 Write byte (small buffer variant)

SeqMain Buffer Wrappers (buffer at 0x01F37B)

Routine Address Purpose
SeqMain_WriteByte 0xEF276D Write one byte to main sequencer buffer
SeqMain_WriteBytes 0xEF2783 Write multiple bytes
SeqMain_GetTimingValue 0xEF27B7 Get timing/delta value
SeqMain_InitBuffer 0xEF27BD Initialize main buffer
SeqMain_SaveWritePos 0xEF27CB Save current write position
SeqMain_ReadData 0xEF27D8 Read data from main buffer

Additional Buffer Instances

Buffer Base Address Read Routine Write Routine
SeqAlt1 0x01F785 SeqAlt1_ReadByte (0xEF280E)
SeqAlt2 0x01FCA3 SeqAlt2_WriteByte (0xEF2A25)
SeqAlt3 0x0201C1 SeqAlt3_ReadByte (0xEF2C22)
SeqAlt4 0x0204DF SeqAlt4_ReadByte (0xEF2E2C)

Event Processing

Seq_EventProcessingTick (0xEF14A3) calls Seq_ProcessEventLoop (0xEF14CA), which:

  1. Calls Seq_CheckSongEnd (0xEF27A5) — compares write position (0x01F377) with read position (0x01F373)
  2. If positions are equal (buffer empty), returns 0 — no events to process
  3. If data available, reads MIDI bytes and calls Seq_ProcessMidiEvent (0xEF13CD)
  4. Seq_ProcessMidiEvent parses the MIDI status byte and dispatches via sendCOMM to the Sub CPU

Rhythm ROM

The 4MB Rhythm ROM (0x400000-0x7FFFFF) contains factory preset rhythm patterns, drum kits, and style data.

Validation

At boot, the firmware validates the rhythm ROM:

Routine Address Purpose
RhythmROM_ValidateHeader 0xF54651 Reads magic bytes at 0x400000, expects LE word 0x05040100
RhythmROM_CheckValid 0xF5452F Checks if (3277h) == 0xFFFFFFFF; if so, returns C=1 (invalid)

The validation result is stored at RAM 0x3277:

  • 0x00000000 = Valid (rhythm ROM present and header matches)
  • 0xFFFFFFFF = Invalid (no rhythm ROM or header mismatch)

When RhythmROM_CheckValid returns C=1, Seq_DispatcherTick_Process skips ALL rhythm/sequencer processing.

Pattern Loading

Routine Address Purpose
RhythmROM_PatternDispatcher 0xF634F3 Dispatches pattern loading by type
RhythmROM_LoadPattern 0xF6358D Loads a pattern from rhythm ROM into RAM
RhythmROM_CalcPatternAddr 0xF636E4 Calculates pattern address from index
RhythmROM_LoadDrumKit 0xF64550 Loads a drum kit configuration

Audio Mixer (0x150000)

The Main CPU configures an audio mixer/attenuator at address 0x150000 during initialization:

Routine Address Purpose
AudioMix_Init 0xEF17F4 Initialize audio mixer hardware
AudioMix_EnableChannels_Loop 0xEF1830 Enable mixer channels
AudioMix_WriteChannelGroup 0xEF183D Write channel group configuration
AudioMix_WriteChannelGroup_Loop 0xEF184B Per-channel write loop

Demo Mode Integration

The Feature Demo uses the sequencer engine to play pre-recorded demonstration songs. See Feature Demo for the SSF presentation system and Audio Subsystem for the detailed playback analysis.

Demo Mode Entry

Routine Address Purpose
DemoMode_Main_Operation 0xF8696F Normal demo playback (disables Timer7, posts events, calls Seq_StartMainControl)
DemoMode_Initialize 0xF869E3 First-time demo init (calls Seq_StartMainControlAlt, initializes buffers)

Demo Mode State

The demo mode handler SeqState_DemoModeHandler (0xF993AD) responds to event 0x01c00013. During demo playback:

  1. State transitions to 0xE0 (DemoMode_Main_Operation entry)
  2. State transitions to 0xE4 (DemoMode_Initialize completion)
  3. Startup flag at 0x0251D8 controls whether Seq_StartMainControlAlt configures audio hardware

Demo Song Data

Style/rhythm preset data at Demo_StyleRhythmData (0xF5CFCC) contains:

  • Rhythm/style parameter bytes (96 bytes)
  • ASCII variation names: “a-variation1” through “c-variation4” (12 variations)
  • Section names: “a-intro 1”, “a-fill in 1”, “a-ending 1”, etc. (24 sections)

Medley Playback System

The KN5000 supports several medley playback modes for playing multiple songs in sequence.

Medley Types

Type Function Description
Internal Medley FmmIntMedleyFunc Plays user-recorded sequences stored in SRAM
Disk Medley FmmDiskMedleySelectFunc Plays sequences from floppy disk
SMF Medley FmmSmfMedleyFunc Plays Standard MIDI Files
Performance Data FmmPdMedleyFunc Plays performance data files
Document Medley FmmDocMedleyFunc Plays document files

Internal Medley Memory Layout

Internal medley songs are stored in battery-backed SRAM:

Address Size Description
0xAB000 20KB 10 song slots (0x800 bytes each)
0xF180 2KB Current playback buffer

Each slot is 2048 bytes (0x800) and stores one user-recorded sequence.

Key Routines

Routine Address Purpose
SongBank_ScanActiveVoices 0xF2065A Check if slot has valid data
SongBank_SwitchAndUpdateTempo 0xF20BCE Load and play a song from slot
SongBank_LoadToWorkArea 0xF20BFA Copy slot to playback buffer (LDIR)
Medley_GetPlaybackStatus 0xF2076D Get current playback state

Medley State Variables

Address Name Description
0x84FE Play flag 0=stopped, 1=playing
0x889A Song count Number of songs in playlist
0x889C Current index Currently playing song
0x889E Repeat flag 0=no repeat, 1=repeat
0x8890 Order array 10-byte play order (0xFF=unused, 0xFE=marked)

Source Code

The medley system is implemented in maincpu/file_io/medley.asm with ~4700 lines of disassembled code including:

  • Song selection UI handlers
  • Playback state machine
  • Repeat/shuffle logic
  • Multi-format file loading

Event Storage Format

The sequencer stores events in a MIDI-like format with extensions. The SeqEvent_GetParamLength routine (0xF3E382) defines the event record sizes:

Event Types and Sizes

Status Byte Size (bytes) Type Description
0x90+ch 6 Note On Channel note-on with velocity
0xB0+ch 6 Control Change Controller number + value
0xC0+ch 6 Program Change Program number + bank info
0xA0 3 Aftertouch Channel pressure data
0xD0 3 Channel Pressure Mono aftertouch
0xD1 3 Extended Internal event type
0xD3 3 Extended Internal event type
0x80+ch 4 Note Off Channel note-off
0xD2 4 Extended Internal event type
0x85 2 Compact Short internal event
0x86 2 Compact Short internal event
0x81 1 Minimal Single-byte internal event
0x82 1 Minimal Single-byte internal event

The format is optimized for storage efficiency — common MIDI events (Note On, CC, Program Change) use the standard 6-byte format while internal events use shorter encodings. Status bytes 0x81-0x86 are non-standard extensions used for compact representation of sequencer-internal control events.

Ring Buffer Write Dispatch

Events enter the ring buffer via dispatch table at ROM 0xE00012:

Slot Handler Description
0 Seq_MultiWrite_Alt4 Multi-byte write variant 4
1 Seq_MultiWrite_Alt5 Multi-byte write variant 5
2 Seq_WriteMidi90 Standard MIDI Note On (0x90) handler
3 Seq_MultiWrite_Alt3 Multi-byte write variant 3
4 Seq_MultiWrite_Alt1 Multi-byte write variant 1
5-7 Seq_RingBuf_Nop No-op (unused slots)

Playback Processing

SeqPlay_ProcessTempoVoiceEvent dispatches incoming events by status:

Status Range Handler Purpose
0x90-0x9F Note processing Assign voices, set velocity
0x80-0x8F Note off Release voices
0xB0-0xBF Control change Apply CC values
0xC0-0xCF Program change Switch instrument
0xE0-0xEF Pitch bend Apply pitch bend

Track Organization

The sequencer supports 16 tracks with the following part assignments:

Track Group Parts Purpose
Right 1 Part 1 Melody voice 1
Right 2 Part 2 Melody voice 2
Left Part 3 Left hand voice
Part 4-15 Parts 4-15 Additional voices
Part 16 Part 16 Accompaniment/control

The SeqTrack_ScanActiveChannels routine scans all tracks to determine which have data, and SeqTrack_AssignFloppyChannels assigns loaded tracks to voice channels when loading from floppy disk.

Timing

Events use delta-time encoding relative to the previous event. The timing resolution is handled by SeqMain_GetTimingValue (0xEF27B7) and the tempo is computed by SeqTrack_ComputeTempoScaling.

Note Pool

SeqNotePool_Init (0xF3E3E0) initializes a note tracking pool for managing active notes during playback. The pool uses a linked-list structure starting at DRAM address 7602, with entries containing note number (0xFF = empty), velocity, and status bytes.

Known Information

Features

Based on KN5000 specifications:

Feature Description
Tracks 16 MIDI tracks
Resolution 96 PPQ (presumed)
Recording Real-time and step modes
Playback Variable tempo, loop
Editing Quantize, transpose, copy
Storage Save to floppy or HD

Style System

Structure

Each auto-accompaniment style contains 3 main variations (A, B, C), each with 6 sections:

Section Type Count Purpose
Intro 2 per variation Opening pattern (e.g., “a-intro 1”, “a-intro 2”)
Main (Variation) 4 per variation Main accompaniment loops (e.g., “a-variation1” through “a-variation4”)
Fill-In 2 per variation Transition fills (e.g., “a-fill in 1”, “a-fill in 2”)
Ending 2 per variation Closing pattern (e.g., “a-ending 1”, “a-ending 2”)

Variation names are stored as ASCII strings in ROM (e.g., at Demo_StyleRhythmData 0xF5CFCC).

Accompaniment Channels

Each pattern includes 5 accompaniment parts loaded from the Rhythm ROM:

Channel Pattern Buffer Offset Purpose
Drums +0x22 Percussion: kick, snare, hi-hat, cymbals
Bass +0x2A Bass line pattern
Accomp1 +0x32 Harmony part 1 (chords)
Accomp2 +0x3A Harmony part 2
Accomp3 (additional) Harmony part 3

Each channel’s metadata block is stored at a fixed offset within the pattern buffer (0x94800 or 0x95C00).

Pattern Loading Pipeline

RhythmROM_PatternDispatcher (0xF634F3) loads patterns using this address calculation:

ROM address = 0x400000 + base_offset + (selector << 8) + (type_index << 14)

Where:

  • selector is read from RAM at 0x348D-0x348F (pattern selectors A/B/type)
  • type_index selects the channel type (drums, bass, accomp, etc.)
  • Each pattern block is 1024 bytes (0x400)

The loaded pattern data goes into RAM buffers at 0x94800 and 0x95C00 for double-buffering during playback.

Chord Detection

The firmware supports multiple chord detection modes, with 5 chord maps identified in the style data. These likely correspond to:

Mode Description
Fingered Full chord recognition from held notes
Single Finger Root note + major/minor/7th from minimal input
Full Keyboard Split keyboard with left-hand chord area
AI Fingered Intelligent chord detection with voice leading
Pianist Chord detection across full keyboard range

Each chord map stores note-to-chord mappings that translate detected chord roots and types into bass and accompaniment note patterns for the 5 channels.

Key RAM Addresses

Address Purpose
0x8D36 Sequencer state machine (master state)
0x3277 Rhythm ROM validation (0 = valid, 0xFFFFFFFF = invalid)
0x348D-0x348F Pattern selectors (A/B/type)
0x3476 Variation index (0-0x1E)
0x35A0-0x35A1 Error flags and drum kit selection
0x94800 Pattern buffer A (1024 bytes per pattern)
0x95C00 Pattern buffer B (double-buffer)

Drum Kit Loading

RhythmROM_LoadDrumKit (0xF64550) loads drum kit definitions from the Rhythm ROM. Each kit maps MIDI note numbers to specific drum/percussion sounds. Up to 10 drum kit configurations can be loaded.

File Formats

Sequences and styles can be stored:

Format Extension Description
KN Sequence .SQT Native sequencer format
Standard MIDI .MID Import/export
Style .STY Auto-accompaniment

MAME Emulation Status

What Works

  • Sequencer dispatcher runs and rhythm ROM is validated successfully
  • State machine transitions correctly (0x00 → 0x01 → 0xE0 → 0xE4 during demo)
  • Rhythm ROM data is read from 0x400000 during demo (1800-3800 reads/second)
  • Sequencer processing code executes (PCs in F5CFxx-F641xx range during demo)

Known Issues

  • Ring buffer never written: The main sequencer ring buffer at 0x01F37B always has write position == read position (both 0x0000). The song engine never generates MIDI events into the buffer.
  • Startup flag stuck at 0: The flag at 0x0251D8 is always 0, which may cause Seq_StartMainControlAlt to skip audio hardware configuration.
  • Event loop rate drops 60x: After demo initialization, the event processing loop drops from ~11,500 iterations/sec to ~168-180/sec. The sequencer is busy processing but producing no output.
  • No Note On/Off events: The demo sends CC, Pitch Bend, Channel Pressure, and SysEx commands, but never Note On (0x90) or Note Off (0x80).

See Audio Subsystem - Feature Demo for detailed diagnostic log analysis.

Research Needed

  • Identify why the song engine never writes MIDI events to the ring buffer
  • Investigate the startup flag at 0x0251D8 — what sets it on real hardware?
  • Trace the path from rhythm ROM data reading to ring buffer writing
  • Document sequence data structure format
  • Analyze playback timing engine (Timer7 involvement)
  • Map recording routines
  • Decode full pattern data format within 1024-byte pattern blocks
  • Map chord detection algorithm (chord maps 1-5)
  • Identify quantization algorithms
  • Understand style format in Rhythm ROM — 3 variations × 6 sections, 5 channels per pattern, 1024-byte blocks
  • Document chord recognition — Partial: 5 chord maps identified, chord detection modes documented
  • Document medley playback system
  • Document main loop and dispatcher architecture
  • Document ring buffer pipeline and instances
  • Document rhythm ROM validation and loading
  • Document sequencer state machine

Code References

Sequencer Core

Symbol Address Purpose
Seq_TickWrapper 0xEF1388 Main loop sequencer tick driver
Seq_EventProcessingTick 0xEF14A3 MIDI event dispatch from ring buffer
Seq_ProcessEventLoop 0xEF14CA Event processing loop
Seq_ProcessMidiEvent 0xEF13CD Parse MIDI status byte and dispatch
Seq_DispatcherEntry 0xF532E1 Dispatcher entry point
Seq_DispatcherTick 0xF53318 State guard (skip if 0x10-0x16)
Seq_RhythmProcessor 0xF5EC75 Main rhythm/sequencer processing
SeqState_TransitionMode 0xF9936D State machine transition (writes 0x8D36)
sendCOMM 0xEF32F4 Send MIDI event to Sub CPU via latch

Ring Buffers

Symbol Address Purpose
SeqMain_WriteByte 0xEF276D Write to main sequencer buffer (0x01F37B)
SeqMain_ReadData 0xEF27D8 Read from main sequencer buffer
SeqMain_InitBuffer 0xEF27BD Initialize main buffer
Seq_CheckSongEnd 0xEF27A5 Check if buffer empty (WrPos == RdPos)
Seq_RingBuf_Init_256 0xEF2F69 Init 256-byte ring buffer
Seq_RingBuf_Init_1024 0xEF3087 Init 1024-byte ring buffer

Rhythm ROM

Symbol Address Purpose
RhythmROM_ValidateHeader 0xF54651 Validate magic bytes at 0x400000
RhythmROM_CheckValid 0xF5452F Check validation flag (0x3277)
RhythmROM_PatternDispatcher 0xF634F3 Dispatch pattern loading by type
RhythmROM_LoadPattern 0xF6358D Load pattern from ROM to RAM
RhythmROM_CalcPatternAddr 0xF636E4 Calculate pattern ROM address
RhythmROM_LoadDrumKit 0xF64550 Load drum kit configuration

Audio Mixer

Symbol Address Purpose
AudioMix_Init 0xEF17F4 Initialize audio mixer at 0x150000
AudioMix_EnableChannels_Loop 0xEF1830 Enable mixer channels
AudioMix_WriteChannelGroup 0xEF183D Write channel group config

Demo Mode

Symbol Address Purpose
DemoMode_Main_Operation 0xF8696F Demo playback handler
DemoMode_Initialize 0xF869E3 First-time demo initialization
SeqState_DemoModeHandler 0xF993AD Demo mode event handler