Web64 IDE SID Tracker User Guide
Version: 2026-07-25
The SID Tracker is Web64 IDE's browser-local music editor for Commodore 64 SID compositions. The editable source of truth is a .w64sid file. Saving it generates one playable .sid and one assembly .inc; it does not generate a duplicate .bin.
The v2 tracker uses the modular web64-modular-v2 compiler and a compact adaptive player. The compiler mixes linked runtime commands, run-length encoded delays, and SID register events according to the features actually used by the song. The generated 6502 player decodes that stream and publishes its exact position through a stable status block.
For general project and emulator workflows, see the Web64 IDE User Manual.
Contents
- Tracker files
- Workspace
- Pattern editing
- Selection and clipboard
- Instruments
- Graphical ADSR editor
- Instrument tables
- Effects
- Song and order editor
- Subtunes
- Preview and audition
- Playback position
- Saving and generated files
- Generated include reference
- C project integration
- Driver limits and compatibility
- Troubleshooting
- Implementation modules
Tracker Files
The tracker recognizes these related project records:
| File | Purpose |
|---|---|
.w64sid | Editable composition, instruments, tables, patterns, orders, subtunes, metadata, and export settings |
.sid | Generated PSID v2 binary containing the Web64 player and rendered music data |
.inc | Generated assembly constants for loading and calling the .sid payload |
Use Export W64SID to download the editable source for transfer to another project. A downloaded .w64sid can be added through the IDE project-file import workflow.
Saving a tracker removes an obsolete same-stem .bin only when that file was generated from the same .w64sid. Manually authored binary files are preserved.
Version 1 .w64sid files are migrated in memory to schema version 2. The original musical data remains available, while the obsolete web64-fixed-v1 capability block is replaced by the v2 descriptor.
Workspace
The tracker is split into three responsive areas.
Song Rail
The left rail lists the project's .w64sid assets, validation diagnostics, driver version, and resource counts. Collapse it when the pattern needs more width.
Pattern Surface
The center contains:
- Compact icon buttons for play, stop, undo, and redo.
- FastSID or reSID realtime selection.
- Audio enable, mute, and a fixed-width toolbar volume control.
- Pattern selection and naming, New Pattern, Duplicate, and row add/remove.
- Entry octave, playback follow, and selected-pattern loop controls.
- Per-voice Mute and Solo buttons embedded in each sticky voice heading.
- The three-voice pattern grid.
The Name field beside the pattern selector renames the selected pattern. Press Enter or leave the field to commit the name; pattern renames participate in Undo and Redo. Blank names are rejected.
New Pattern creates an empty pattern without modifying an order list. Duplicate copies the pattern and appends the new pattern to the existing orders for backward compatibility.
Inspector
The right inspector uses tabs for Instrument, Tables, Song, and Info. It can be collapsed to a narrow strip that keeps the selected instrument visible.
Instrument topics are independently collapsible. Controls use compact typography and visual editors where a graph or gesture communicates the setting better than a numeric field. Raw numeric entry remains available.
Every editable field and compact control has a descriptive browser tooltip. Hover a field to see its range and command-specific meaning without opening the manual.
Pattern Editing
Each row has Note, Instrument, Effect, Parameter, and Volume fields for all three SID voices.
The one-digit Volume field is a per-note sustain-level override from $0 to $f. Leave it blank to inherit the instrument's Note volume. A volume value may also appear without a note to change the active voice's sustain level. This is separate from SID master volume: the pattern VOL effect and instrument/subtune Master values affect the shared $d418 volume nibble and therefore all three voices.
Notes use tracker notation such as C-4, C#4, and A-5. Special note values are:
| Value | Meaning |
|---|---|
Blank or ... | Hold the current voice state |
~~~ | Tie; keep the current note and gate |
=== | Release; clear the gate and let SID release run |
^^^ | Cut; clear the gate |
The editor wraps from the final row to row zero while entering notes or moving vertically.
Keyboard Note Entry
| Keys | Notes |
|---|---|
z s x d c v g b h n j m | C through B around octave 3 |
q 2 w 3 e r 5 t 6 y 7 u | C through B around octave 4 |
i 9 o 0 p | C through E around octave 5 |
. | Hold marker |
The Octave field shifts this keyboard layout. Entering a playable note immediately auditions the selected instrument at the entered pitch and advances to the next row.
Navigation and editing:
| Key | Action |
|---|---|
| Arrow keys | Move by row or field |
| Tab / Shift+Tab | Move to the next or previous voice |
| Enter | Move to the next row |
| Enter in Effect | Open the searchable command list |
| Home / End | First or last pattern row |
| Delete / Backspace | Clear the selected field or region |
| Ctrl/Cmd+A | Select the full pattern |
| Ctrl/Cmd+C | Copy selection |
| Ctrl/Cmd+X | Cut selection |
| Ctrl/Cmd+V | Paste at the cursor |
| Ctrl/Cmd+Z | Undo |
| Ctrl/Cmd+Y or Ctrl/Cmd+Shift+Z | Redo |
The Effect command popup lists every implemented command, its meaning, parameter format, and range. It opens upward inside the visible pattern area, scrolls long command lists internally, and keeps the active command visible during keyboard navigation. Search by command or description, then press Enter to apply it.
Selection and Clipboard
Drag across rows, voices, and individual fields to create a rectangular selection. Shift navigation extends the selection.
Selections are column-precise. Copying only Effect and Parameter does not overwrite Note or Instrument when pasted. Paste clips safely at the pattern and voice boundaries.
The Transpose - and Transpose + controls move playable notes down or up one semitone. They affect the highlighted block when a selection exists, or the note under the current cursor otherwise. Each transpose is one undoable transaction and clamps notes to the tracker's supported octave range.
The tracker writes a tab-and-line based text form to the browser clipboard and retains an internal clipboard if browser permission is unavailable. Empty note and effect placeholders round-trip as empty cells instead of commands. Cut and Clear use one undoable transaction.
Instruments
The v2 instrument model supports:
- Triangle, saw, pulse, and noise waveforms.
- Gate, test, oscillator sync, and ring modulation flags.
- Attack, decay, sustain, and release.
- Pulse width from
$000to$fff. - Arpeggio and vibrato, including vibrato delay.
- Default tone-portamento speed.
- Hard restart, first-frame control byte, and gate timer.
- A prominent default Note volume/ADSR sustain level from 0 to 15.
- Default SID master volume from 0 to 15.
- Complete SID filter cutoff, resonance, routing, modes, and voice 3 disable.
- Independent pointers into wave, pulse, filter, arpeggio, and vibrato tables.
The pulse-width editor shows the duty cycle with a transparent-to-slate-green fill and provides a slider plus raw hexadecimal entry. Vibrato and arpeggio have visual previews with raw-byte access. Click an editable arpeggio step to increment it, right-click to decrement it, or drag vertically for faster changes. Each arpeggio pole maps values 0 through 15 across the complete available lane height, excluding only the handle itself, so the handle follows the grabbed pointer without leaving an unused upper region. The editable poles expose cyan and purple gradient levels as they rise. Portamento has a continuous control and numeric entry on the same compact row as the arpeggio raw value.
Note volume and the ADSR graph's S point edit the same SID sustain nibble; SID hardware does not provide a separate per-voice volume register. The pattern Volume field can override that nibble per row. Master writes the SID's global volume nibble and is intentionally distinct; changing it can affect every active voice. Both volume controls are kept in the main Sound section rather than hidden under Advanced.
Every continuous slider, graph, and pole gesture uses component-local preview state while the pointer is moving. The tracker commits the final ADSR, pulse, filter, modulation, portamento, or volume value to project state once when the pointer is released. Keyboard changes still commit immediately. This keeps pointer feedback independent of project history, serialization, diagnostics, and the main IDE render tree.
The compact filter and advanced layouts keep related modes, routing, restart, volume, timing, and first-frame controls together while wrapping on narrow inspector widths. Hard restart emits a gate-off/test first-frame sequence before the normal control value. Gate Timer automatically releases the note after the configured tick count. A zero gate timer leaves the gate active until a pattern command or note event changes it.
Filter
Enable Route this voice through filter to make a triggered instrument claim the global SID filter. The instrument can set:
- 11-bit cutoff.
- 4-bit resonance.
- Low-pass, band-pass, and high-pass modes in any combination.
- Voice 1, 2, and 3 routing mask.
- Voice 3 output disable.
- Optional filter-table pointer.
The filter graph is draggable on both axes and keyboard accessible, with a light-blue response gradient below the curve. Horizontal movement changes cutoff and upward movement increases resonance. Arrow Left/Right adjust cutoff; Arrow Up/Down adjust resonance. The latest instrument or filter command that claims the filter supplies the active global settings.
Graphical ADSR Editor
The envelope editor displays attack, decay, sustain, and release as an interactive curve.
- Drag the four curve points to change values.
- Use arrow keys on a focused point for one-step changes.
- Enter values from 0 to 15 in the numeric fields.
- Read the corresponding SID attack/decay/release timing beside the graph.
The graph and numeric controls update the same quantized SID values. Each horizontal point uses the same segment for rendering and pointer conversion, so the point stays under the pointer throughout its valid range even when the SVG is responsively scaled. A yellow-orange gradient below the envelope makes its current shape easier to read. Similar modulation concepts use the same visual-first approach while retaining raw numeric entry.
Attack value 0 is drawn vertically at the left edge to represent the SID's effectively instant attack. Dragging the attack point to the right increases the attack value and displayed time.
Instrument Tables
Each instrument can point at a row in one or more global tables. Tables execute once per player tick and support duration, secondary value, jump target, and loop behavior.
| Table | Commands |
|---|---|
| Wave | WAV, GATE, ARP, DLY, JMP, END |
| Pulse | PUL, SET, SLD, DLY, JMP, END |
| Filter | FCO, SET, FRE, MOD, SLD, DLY, JMP, END |
| Arpeggio | ARP, DLY, JMP, END |
| Vibrato | VIB, DLY, JMP, END |
Table row fields:
| Field | Meaning |
|---|---|
| Command | Operation for this table |
| Value | Primary byte, word, or signed delta |
| Secondary | Routing, depth, or another command-specific value |
| Duration | Ticks to wait after executing the row, or the slide duration for SLD |
| Target | Row used by JMP or looping END |
| Loop | Makes END jump to Target instead of stopping the table |
The table tab shows a visual value plot above the raw row editor. Unknown commands remain in migrated source long enough for validation to report them; they are not silently converted.
Table Command Reference
| Command | Tables | Operation |
|---|---|---|
WAV | Wave | Set the voice waveform/control byte; gate state is still controlled by the note and GATE logic |
GATE | Wave | Set or clear the voice gate from Value bit 0 |
ARP | Wave, Arpeggio | Apply Value as a signed semitone offset to the current note |
PUL | Pulse | Set the 12-bit pulse width from Value |
SET | Pulse, Filter | Set pulse width or 11-bit filter cutoff directly |
FCO | Filter | Set the 11-bit filter cutoff directly |
FRE | Filter | Set resonance from Value's low nibble and voice routing from Secondary's low three bits |
MOD | Filter | Set low-pass, band-pass, high-pass, and voice-3-off mode bits from Value's high nibble |
VIB | Vibrato | Set speed from Value's high nibble and depth from its low nibble; nonzero Secondary overrides depth |
SLD | Pulse, Filter | Add signed Value on each tick for Duration ticks |
DLY | All tables | Wait Value ticks before processing the following row |
JMP | All tables | Continue at the zero-based Target row on a later tick |
END | All tables | Stop the table, or jump to Target when Loop is enabled |
An instrument table pointer and every pattern table-pointer effect use a zero-based row. Row 0 is valid; a blank instrument pointer disables that table. Wave, pulse, arpeggio, and vibrato tables are per voice. The filter table controls the SID's one shared filter and is owned by the latest instrument or filter effect that claims it.
Table rows execute once per player tick. A finite table stops when it reaches its last row or a non-looping END. Use a looping END for continuous PWM, vibrato, arpeggio, or filter movement. Use DLY and Duration to control timing without repeating identical rows.
Effects
All commands in the v2 effect contract are compiled for preview and export.
| Code | Parameter | Operation and usage |
|---|---|---|
SPD | $01-$1f | Set ticks per row immediately. Lower values advance rows faster. |
ARP | $00-$ff | Three-step arpeggio: root, high-nibble semitone offset, low-nibble semitone offset. Static forms use the compact adaptive runtime command. |
PU+ | $00-$ff | Raise frequency by the parameter amount on every tick. Zero uses the minimum step of one. |
PU- | $00-$ff | Lower frequency by the parameter amount on every tick. Zero uses the minimum step of one. |
TPO | $00-$ff | Slide the existing voice toward this row's note without retriggering its envelope. Zero uses the instrument Portamento value, then the minimum step. |
VIB | $00-$ff | Set vibrato speed in the high nibble and depth in the low nibble. For example, $24 is speed 2 and depth 4. |
PWM | $00-$ff | Start the pulse table at this zero-based row. PTB is the explicit equivalent. |
FCO | $00-$ff | Set filter cutoff to Parameter multiplied by 8, covering the SID's 11-bit range in coarse steps. |
FRE | $00-$ff | Set resonance from the high nibble and route voices from the low three bits. |
WAV | $00-$ff | Set the voice waveform/control byte; the current gate state supplies bit 0 during playback. |
VOL | $0-$f | Set the SID master-volume nibble. This is global and affects all three voices. |
INS | $00-$3f | Select an instrument by zero-based index, with or without a note on the same row. |
BRK | $00-$3f | Finish the current pattern and continue at this row in the next order position. |
JMP | $00-$ff | Jump to this zero-based order position. It can be combined with BRK on another voice to choose a start row. |
DLY | $0-$f | Delay this row's note trigger by the low-nibble tick count. |
CUT | $0-$f | Clear this voice's gate after the low-nibble tick count. |
AD | $00-$ff | Write attack in the high nibble and decay in the low nibble for this voice. |
SR | $00-$ff | Write sustain in the high nibble and release in the low nibble for this voice. |
WTB | $00-$ff | Start the wave table at this zero-based row. |
PTB | $00-$ff | Start the pulse table at this zero-based row. |
FTB | $00-$ff | Claim the shared filter and start the filter table at this zero-based row. |
ATB | $00-$ff | Start the arpeggio table at this zero-based row. |
VTB | $00-$ff | Start the vibrato table at this zero-based row. |
Unknown commands and out-of-range parameters produce diagnostics and block preview/export instead of generating incorrect data.
Filter effects on the same row as a filtered note take precedence over that instrument's default filter values. This lets FCO, FRE, or FTB establish the intended first filter frame instead of being overwritten by note initialization.
Song and Order Editor
The Song tab edits:
- The selected subtune and all of its playback settings.
- One independent pattern-order lane for each SID voice.
- Order-step append and removal.
- Global speed and tempo defaults.
Each order position chooses one pattern for each of the three voices. + Step appends a position to all voices, and - Step removes the final position. Start, Loop, and End in the selected subtune determine which range of that order is compiled.
Tempo is rendered relative to the 125 baseline used by the 50 Hz player. Higher values reduce rendered ticks per row; lower values increase them within the driver limits. Subtunes can inherit these global defaults or override them.
Subtunes
A subtune is an independently initialized and playable entry within one SID file. Subtunes are the normal way to package related audio that shares a player and sound resources:
- Title music and in-game music.
- Level, boss, or ambient themes.
- Game-over and completion jingles.
- One-shot sound effects such as pickups, alarms, or menu confirmations.
All subtunes share the composition's patterns, instruments, and five global tables. Each subtune owns an independent order list and playback settings, so the same patterns can be arranged differently without duplicating instrument/table data.
Creating and Managing Subtunes
Use the Song tab controls:
| Control | Result |
|---|---|
| + New | Create a new subtune with a new one-step order list that starts with pattern 0 |
| Duplicate | Copy the selected subtune settings and clone its complete order list |
| Delete | Remove the selected subtune and its private order list; at least one subtune always remains |
| Play | Compile and preview the selected subtune |
| Default | Make the selected subtune the PSID start song and default Web64 preview |
The compact Sub selector in the main tracker toolbar selects the subtune used by the icon Play button. Selecting a nonzero subtune passes its exact zero-based index to the generated driver's init routine. Play remains available and restarts the selected subtune; Stop ends preview.
Subtune Settings
| Setting | Meaning |
|---|---|
| Name | Human-readable name shown in selectors and generated include comments |
| Purpose | Music, Title music, Game music, Ambient, Jingle, Sound effect, or Custom classification |
| Description | Project notes describing where and how the subtune is used |
| Default | Initial song in PSID metadata and the default selection when opening the asset |
| Loop checkbox | On: return to Loop order after End. Off: emit STOP after End for one-shot playback |
| Start | First zero-based order position played after init |
| Loop order | Zero-based order position used when a looping subtune reaches End |
| End | Final zero-based order position included in this subtune |
| Speed | Optional ticks-per-row override; blank inherits Global speed |
| Tempo | Optional timing-scale override; blank inherits Global tempo |
| Master | Optional SID master-volume override from 0 to 15 |
| Transpose | Shift all playable notes from -24 to +24 semitones without modifying patterns |
For a sound effect, set Purpose to Sound effect, disable Loop, and keep Start/End around only the required order positions. When music is already playing, initializing such a subtune starts it as an overlay: the background stream continues advancing and the effect uses only its owned SID voices. A one-shot jingle remains a primary subtune unless its Purpose is Sound effect. For title/game music, leave Loop enabled and set Loop to the first order position that should repeat; an intro can remain before that point.
Subtune Master overrides instrument master values during that subtune. Per-note pattern Volume and instrument Note volume/ADSR sustain still control each voice's sustain level. Transpose is applied during compilation and leaves shared source patterns unchanged, which allows one pattern to serve several pitched effects.
Sound-Effect Voice Inheritance
A Sound effect can keep the current music on voices 1 and 2 and use a short pattern on voice 3. Assign the same background pattern/order sequence to the inherited voices and assign the effect pattern to its owned voice. The compiler compares each SFX channel with the music subtunes:
- A matching channel sequence is inherited and is not duplicated into the SFX stream.
- A different channel containing notes, commands, or volume changes is owned by the SFX.
- The SFX duration and encoded stream use only owned patterns. A 4-row voice-3 effect therefore remains four rows even if inherited voices point at a 64-row game pattern.
- Overlay streams preserve the shared SID master/filter registers. Pattern Volume and the instrument ADSR sustain value continue to control the owned voice.
Effects should own voices that the background arrangement leaves available. Starting another SFX while one is active replaces the current overlay. When an effect reaches STOP, its owned voice gates are cleared and the primary music remains selected and playing.
Runtime Numbering
The Web64 driver uses zero-based subtune indexes:
lda #song_sid_subtune_2 ; generated value 1
jsr song_sid_init_address
frame:
jsr song_sid_play_address
; wait for the next video frame
jmp frame
Call init once whenever switching primary subtunes, with the required index in A. Call play once per video frame while the status Playing byte is nonzero. A primary one-shot clears Playing when it reaches STOP; a looping subtune continues from its Loop position. Initializing a non-looping Sound effect while a primary subtune is playing starts the overlay without changing the primary status Subtune or Playing bytes.
Calling play again after a primary one-shot has stopped is safe: the driver checks Playing and returns without reading beyond the stream. An overlay STOP ends only the effect and does not require the game to initialize its music again.
The PSID header follows the SID file convention: song count and start song are one-based. The generated assembly constants and the driver's A register remain zero-based. Therefore song_sid_subtune_1 is 0, song_sid_subtune_2 is 1, and so on.
Saving compiles one event stream for every subtune. The adaptive player is shared once, so adding a subtune adds its music stream and order behavior rather than another complete driver. Sound-effect streams omit inherited music voices and shared global-register traffic. Stream encoding v3 also removes ordinary sequential row-status writes; the player advances those row counters itself and the stream emits a correction only at pattern, order, jump, or loop boundaries.
Keep one-shot sound effects limited to the rows and order positions they actually require. Eventless tails compress efficiently, but an intentionally short pattern also reduces render work and makes the generated per-subtune size constant easier to interpret.
Preview and Audition
Use the main Play icon for the selected subtune. Use Pattern Play beside the pattern selector to preview only the displayed pattern on all three voices without advancing into another pattern. With Loop pattern enabled it returns to row 0 after the final row; with Loop disabled it emits STOP and plays the pattern once.
Preview compiles the current draft, resets the Web64 runtime, writes the generated player and streams, initializes the selected subtune settings, and starts a 50 Hz IRQ wrapper.
Preview-only controls:
- FastSID for lower CPU cost and approximate playback.
- reSID realtime for the fidelity-reference realtime engine, including accurate portamento playback.
- Voice mute and solo.
- Pattern Play and Loop pattern for isolated pattern preview.
- Audio enable, mute, and volume.
Preview-only mute, solo, and pattern looping do not change the .w64sid or generated .sid.
Preview Instrument compiles a short C-E-G audition with the selected instrument and the current song tables. Notes entered in the pattern use a small CPU-executed 6502 audition routine that writes the selected pitch, waveform, ADSR, pulse width, flags, filter settings, and initial table values to the live SID I/O registers, then executes a timed gate-off routine. Monitor memory writes are not used for SID registers because they address underlying RAM rather than live I/O.
The tracker applies the chosen FastSID/reSID resources before song, instrument, and note preview.
Song Play and Pattern Play change the toolbar to an active preview state before runtime boot or compilation begins, so Stop is enabled on the next browser paint. Both remain available and restart their requested preview even while a note or instrument audition owns the preview runtime. Stop cancels an in-progress startup and updates the toolbar before waiting for emulator reset or destruction. Audio priming continues asynchronously after the player starts.
SID emulation and audio production run in the emulator Web Worker, while browser output runs in an AudioWorklet. On cross-origin-isolated deployments they exchange samples through a shared ring buffer. The non-isolated fallback uses a direct transferable MessageChannel from the emulator worker to the worklet, so tracker rendering and other main-thread work cannot delay audio block delivery. The worker preview path targets about 80 ms of queued audio instead of the older 240 ms target.
Playback Position
The v2 player publishes exact playback state in a 13-byte status block:
| Offset | Value |
|---|---|
| 0 | Playing |
| 1 | Subtune |
| 2 | Tick |
| 3 | Speed |
| 4-6 | Order position for voices 1-3 |
| 7-9 | Pattern index for voices 1-3 |
| 10-12 | Row index for voices 1-3 |
The emulator worker watches this block at its video cadence and pushes a message only when the bytes change. This removes repeated main-thread memory requests and their worker queue. The IDE does not estimate the row with a browser timer. The active row is highlighted for each voice.
Playback snapshots are published through a tracker-scoped external store rather than Web64Ide state. Follow playback changes pages only when the active row leaves the visible page, and it does not scroll the grid on every note. Only actual row/state changes render the tracker surface; playback no longer renders the complete IDE tree.
Saving and Generated Files
Save validates and writes the .w64sid, then regenerates:
<name>.sid<name>.inc
The PSID contains:
- One compact 6502 frame-event decoder shared by every subtune.
- Rendered register-event streams for all subtunes.
- Stable playback status block.
- Audition mailbox storage reserved by the v2 ABI.
Most pattern density affects rendered music data rather than decoder code. Stream encoding v3 selects direct-register writes, contiguous SID runs, voice masks, short delays, signed frequency deltas, signed pulse-width deltas, and repeated-delta runs only when the complete composition saves more bytes than the required decoder branch costs. Adaptively linked runtime features and their song-specific preset tables can also change driver size. Compile fails if the selected driver/music addresses would exceed C64 memory.
The generated include is replaced only when it is a generated sibling of the current .w64sid. Older tracker-generated includes are recognized by the Generated by Web64 IDE marker even when an older project format lacks generatedFrom metadata. A genuinely manual .inc at the same path is preserved.
Generated Include Reference
With the default prefix song_sid, the include exposes:
song_sid_load_addresssong_sid_init_addresssong_sid_play_addresssong_sid_driver_addresssong_sid_music_data_addresssong_sid_driver_sizesong_sid_music_data_sizesong_sid_status_addresssong_sid_status_sizesong_sid_status_versionsong_sid_status_playing,song_sid_status_subtune,song_sid_status_tick,song_sid_status_speedsong_sid_status_order_1throughsong_sid_status_order_3song_sid_status_pattern_1throughsong_sid_status_pattern_3song_sid_status_row_1throughsong_sid_status_row_3song_sid_audition_address,song_sid_audition_sizesong_sid_audition_command,song_sid_audition_note,song_sid_audition_instrument,song_sid_audition_voicesong_sid_size,song_sid_endsong_sid_subtune_count,song_sid_default_subtunesong_sid_subtune_1throughsong_sid_subtune_<count>as zero-based init valuessong_sid_subtune_1_stream_sizethroughsong_sid_subtune_<count>_stream_sizesong_sid_subtune_1_voice_maskthroughsong_sid_subtune_<count>_voice_masksong_sid_subtune_1_overlaythroughsong_sid_subtune_<count>_overlaysong_sid_driver_version,song_sid_stream_encoding_versionsong_sid_linked_compact_arpeggio,song_sid_linked_arpeggio_preset_countsong_sid_linked_short_delay,song_sid_linked_direct_sid,song_sid_linked_sid_run,song_sid_linked_voice_masksong_sid_linked_frequency_delta,song_sid_linked_frequency_delta_runsong_sid_linked_pulse_delta,song_sid_linked_pulse_delta_runsong_sid_linked_sfx_overlaysong_sid_driver_hash,song_sid_music_data_hash,song_sid_payload_hashsong_sid_file_sizesong_sid_data_offset,song_sid_c64_data_offset,song_sid_c64_data_sizesong_sid_payload_address,song_sid_payload_end
Assembly should import only the C64 payload from the PSID container:
.include "assets/music/title.inc"
* = song_sid_load_address
.incbin song_sid, "assets/music/title.sid", song_sid_c64_data_offset, song_sid_c64_data_size
Call song_sid_init_address with the zero-based subtune in A, then call song_sid_play_address once per video frame.
C Project Integration
For C builds, assets/generated.h exposes the generated .sid as one Web64SidAsset. The .w64sid source and .inc do not create duplicate C asset declarations.
Generated constants include the file size, C64 data offset and size, payload pointer, load/init/play addresses, song count, one-based PSID start song, and SID metadata flags. This lets C or mixed C/assembly code load the same payload described by the assembly include. Use the generated assembly subtune constants in a small assembly wrapper when C code needs to initialize a specific zero-based driver subtune in A.
Older projects that still contain only a generated .bin remain readable. Saving the composition with the current tracker creates the .sid/.inc pair and removes only the obsolete generated .bin.
Driver Limits and Compatibility
web64-modular-v2 supports:
- 3 SID voices.
- 64 patterns.
- 64 rows per pattern.
- 64 instruments.
- 255 rows per table.
- 8 subtunes.
- PSID v2 export.
- Single SID at
$d400.
RSID and multi-SID export remain intentionally unsupported and produce diagnostics. The runtime/player is browser-local and does not require native VICE tools, cc65, Electron, Tauri, or host filesystem paths.
Adaptive Linking and Stream Compression
The exported player is linked from the rendered song rather than emitted as one fixed feature-complete binary:
- A song without a compact instrument arpeggio contains no arpeggio interpreter, preset tables, or arpeggio state.
- Static three-step arpeggios link only the exact base/high/low frequency presets used by the composition. A note change selects one preset and the player cycles it at runtime instead of storing two frequency-register writes on every tick.
- Vibrato, pulse modulation, slides, and table-driven modulation retain deterministic rendered values. Repeated signed frequency or pulse-width deltas are collapsed into one delta-run command and expanded by the player once per frame.
- A one-register frame can use a two-byte direct write. Consecutive SID registers and sparse registers within one voice use compact run or mask records when their shared decoder is profitable.
- Consecutive frames without stream events use a delay run. Frequently occurring delays up to 32 frames use one-byte short-delay tokens.
- Tick and ordinary row progression are maintained by the player. Equal order, pattern, or nonsequential row values for all three voices use one grouped status command.
- Hard restart is prepared once on the final frame before the new note with the next instrument's First frame value; the note row does not store a redundant second gate-off write.
- Decoder branches and state for each v3 bytecode family are omitted unless aggregate savings across all subtunes exceed their player cost.
- Non-looping Sound effect subtunes link one secondary stream context. The primary pointer, delay, delta-run state, position, portamento, and sustain writes continue once per frame while the effect context decodes its owned voice.
- The hot stream pointer and frame counters use self-modifying operands. The player does not claim a fixed zero-page range, avoiding collisions with the host program's own zero-page allocation.
Existing .w64sid v2 projects remain source-compatible. Save the composition again to regenerate a .sid with stream encoding v3 and the adaptively linked player.
When copying a generated PSID payload at runtime, the generated <prefix>_c64_data_offset and <prefix>_c64_data_size constants provide the exact range. A fixed page count is also valid when its capacity has been checked against the current C64 payload size; for example, a 6 KB copy fully covers a 5.6 KB payload. Recheck that bound when the composition grows.
Troubleshooting
Nothing plays
Click Play or enter a note directly so the browser can grant audio permission. Check Audio, Mute, volume, and the selected FastSID/reSID engine. Validation errors are shown in the song rail and block compile.
Only the first subtune plays
Select the required subtune in the toolbar's Sub selector or the Song tab before pressing Play. At runtime, call init again with the zero-based subtune index in A; calling play without reinitializing continues the previously selected stream. PSID players show song numbers as one-based, while Web64 generated subtune constants are zero-based.
A sound-effect subtune never finishes
Disable the subtune Loop checkbox. Confirm End covers the final required order position. A non-looping subtune emits STOP and clears the generated status Playing byte after the last rendered frame.
Note volume changes every voice
Use the pattern Volume column or instrument Note volume for per-voice sustain level. Instrument Master, subtune Master, and the VOL effect write the shared SID master-volume register and can affect all voices.
Instrument tables do not affect Preview Instrument
Resave or reload the .w64sid if it came from an older build. Current Preview Instrument copies the active composition's tables and uses the selected instrument pointers.
Playhead is on the wrong row
Current versions read the generated status block. Confirm the current .w64sid draft was compiled and that the main project has not replaced the preview in emulator memory.
Main program does not start after tracker preview
The IDE Start command leaves tracker preview mode, stops status polling, power-resets the runtime, loads the current build, and starts it. Pause/Resume does not reset. If Start is blocked, inspect project compile diagnostics rather than tracker playback state.
Export is too large
Static instrument arpeggios and empty frame runs are compacted automatically. Long songs with continuously changing vibrato, pulse, filter, slide, or table modulation still require pre-rendered register events. Shorten unused order ranges, remove redundant table changes, or move the music-data address if the payload overlaps other C64 memory.
A manual include was not replaced
This is intentional. Web64 only overwrites .inc records marked as generated from the current .w64sid.
Implementation Modules
The tracker is no longer embedded in the main IDE component.
Core compiler modules:
web64-ide/sid-assets.mjs: schema, migration, transactions, validation, exports, preview payloads, and generated include.web64-ide/sid-tracker-contract.mjs: v2 commands, capabilities, ABIs, normalization, and ADSR math.web64-ide/sid-tracker-renderer.mjs: song/effect/table renderer and compact 6502 event player.
React workspace modules:
sid-tracker/SidTrackerWorkspace.jsxsid-tracker/PatternEditor.jsxsid-tracker/InstrumentEditor.jsxsid-tracker/AdsrCurveEditor.jsxsid-tracker/VisualParameterEditors.jsxsid-tracker/InstantRange.jsxsid-tracker/note-audition.mjssid-tracker/pointer-geometry.mjssid-tracker/playback-store.mjssid-tracker/TableEditors.jsxsid-tracker/SongEditor.jsx
Web64Ide.jsx retains only the project-file, runtime, audio, save/export, and preview bridge.