Web64 logo Web64 Documentation Web64 IDE SID Tracker User Guide

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

  1. Tracker files
  2. Workspace
  3. Pattern editing
  4. Selection and clipboard
  5. Instruments
  6. Graphical ADSR editor
  7. Instrument tables
  8. Effects
  9. Song and order editor
  10. Subtunes
  11. Preview and audition
  12. Playback position
  13. Saving and generated files
  14. Generated include reference
  15. C project integration
  16. Driver limits and compatibility
  17. Troubleshooting
  18. Implementation modules

Tracker Files

The tracker recognizes these related project records:

FilePurpose
.w64sidEditable composition, instruments, tables, patterns, orders, subtunes, metadata, and export settings
.sidGenerated PSID v2 binary containing the Web64 player and rendered music data
.incGenerated 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:

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:

ValueMeaning
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

KeysNotes
z s x d c v g b h n j mC through B around octave 3
q 2 w 3 e r 5 t 6 y 7 uC through B around octave 4
i 9 o 0 pC 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:

KeyAction
Arrow keysMove by row or field
Tab / Shift+TabMove to the next or previous voice
EnterMove to the next row
Enter in EffectOpen the searchable command list
Home / EndFirst or last pattern row
Delete / BackspaceClear the selected field or region
Ctrl/Cmd+ASelect the full pattern
Ctrl/Cmd+CCopy selection
Ctrl/Cmd+XCut selection
Ctrl/Cmd+VPaste at the cursor
Ctrl/Cmd+ZUndo
Ctrl/Cmd+Y or Ctrl/Cmd+Shift+ZRedo

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:

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:

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.

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.

TableCommands
WaveWAV, GATE, ARP, DLY, JMP, END
PulsePUL, SET, SLD, DLY, JMP, END
FilterFCO, SET, FRE, MOD, SLD, DLY, JMP, END
ArpeggioARP, DLY, JMP, END
VibratoVIB, DLY, JMP, END

Table row fields:

FieldMeaning
CommandOperation for this table
ValuePrimary byte, word, or signed delta
SecondaryRouting, depth, or another command-specific value
DurationTicks to wait after executing the row, or the slide duration for SLD
TargetRow used by JMP or looping END
LoopMakes 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

CommandTablesOperation
WAVWaveSet the voice waveform/control byte; gate state is still controlled by the note and GATE logic
GATEWaveSet or clear the voice gate from Value bit 0
ARPWave, ArpeggioApply Value as a signed semitone offset to the current note
PULPulseSet the 12-bit pulse width from Value
SETPulse, FilterSet pulse width or 11-bit filter cutoff directly
FCOFilterSet the 11-bit filter cutoff directly
FREFilterSet resonance from Value's low nibble and voice routing from Secondary's low three bits
MODFilterSet low-pass, band-pass, high-pass, and voice-3-off mode bits from Value's high nibble
VIBVibratoSet speed from Value's high nibble and depth from its low nibble; nonzero Secondary overrides depth
SLDPulse, FilterAdd signed Value on each tick for Duration ticks
DLYAll tablesWait Value ticks before processing the following row
JMPAll tablesContinue at the zero-based Target row on a later tick
ENDAll tablesStop 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.

CodeParameterOperation and usage
SPD$01-$1fSet ticks per row immediately. Lower values advance rows faster.
ARP$00-$ffThree-step arpeggio: root, high-nibble semitone offset, low-nibble semitone offset. Static forms use the compact adaptive runtime command.
PU+$00-$ffRaise frequency by the parameter amount on every tick. Zero uses the minimum step of one.
PU-$00-$ffLower frequency by the parameter amount on every tick. Zero uses the minimum step of one.
TPO$00-$ffSlide the existing voice toward this row's note without retriggering its envelope. Zero uses the instrument Portamento value, then the minimum step.
VIB$00-$ffSet vibrato speed in the high nibble and depth in the low nibble. For example, $24 is speed 2 and depth 4.
PWM$00-$ffStart the pulse table at this zero-based row. PTB is the explicit equivalent.
FCO$00-$ffSet filter cutoff to Parameter multiplied by 8, covering the SID's 11-bit range in coarse steps.
FRE$00-$ffSet resonance from the high nibble and route voices from the low three bits.
WAV$00-$ffSet the voice waveform/control byte; the current gate state supplies bit 0 during playback.
VOL$0-$fSet the SID master-volume nibble. This is global and affects all three voices.
INS$00-$3fSelect an instrument by zero-based index, with or without a note on the same row.
BRK$00-$3fFinish the current pattern and continue at this row in the next order position.
JMP$00-$ffJump to this zero-based order position. It can be combined with BRK on another voice to choose a start row.
DLY$0-$fDelay this row's note trigger by the low-nibble tick count.
CUT$0-$fClear this voice's gate after the low-nibble tick count.
AD$00-$ffWrite attack in the high nibble and decay in the low nibble for this voice.
SR$00-$ffWrite sustain in the high nibble and release in the low nibble for this voice.
WTB$00-$ffStart the wave table at this zero-based row.
PTB$00-$ffStart the pulse table at this zero-based row.
FTB$00-$ffClaim the shared filter and start the filter table at this zero-based row.
ATB$00-$ffStart the arpeggio table at this zero-based row.
VTB$00-$ffStart 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:

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:

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:

ControlResult
+ NewCreate a new subtune with a new one-step order list that starts with pattern 0
DuplicateCopy the selected subtune settings and clone its complete order list
DeleteRemove the selected subtune and its private order list; at least one subtune always remains
PlayCompile and preview the selected subtune
DefaultMake 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

SettingMeaning
NameHuman-readable name shown in selectors and generated include comments
PurposeMusic, Title music, Game music, Ambient, Jingle, Sound effect, or Custom classification
DescriptionProject notes describing where and how the subtune is used
DefaultInitial song in PSID metadata and the default selection when opening the asset
Loop checkboxOn: return to Loop order after End. Off: emit STOP after End for one-shot playback
StartFirst zero-based order position played after init
Loop orderZero-based order position used when a looping subtune reaches End
EndFinal zero-based order position included in this subtune
SpeedOptional ticks-per-row override; blank inherits Global speed
TempoOptional timing-scale override; blank inherits Global tempo
MasterOptional SID master-volume override from 0 to 15
TransposeShift 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:

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:

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:

OffsetValue
0Playing
1Subtune
2Tick
3Speed
4-6Order position for voices 1-3
7-9Pattern index for voices 1-3
10-12Row 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:

The PSID contains:

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:

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:

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:

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:

React workspace modules:

Web64Ide.jsx retains only the project-file, runtime, audio, save/export, and preview bridge.