This is a learn-by-building guide for the Crusty Studio SID Music Workshop. We will make an original, roughly 30-second cue, Neon Patrol, from an empty tune to a working crustyBASIC player include. The Workshop also includes a separate, roughly three-minute Neon Patrol — Warehouse Mix that turns the same ideas into a complete rave cue.
The Workshop is inspired by the practical tradition of C64 music programming: a patch is a small program, a player updates the SID every refresh, and three voices can imply a much larger arrangement through timing, motion, and careful rests. The goal is to understand those decisions and apply them to your own music.
Compose three reusable note streams, assign programmable instruments, add per-row effects and shared filter movement, audition both SID models, then export a generated .cbi player include.
.c64music.json asset in the Explorer.music/ folder; in browser preview, Save downloads the JSON file.The Workshop preview is a musical workbench, not a cycle-exact electrical simulation. Use it to compose and compare ideas, then test the generated player in your target emulator or hardware.
The Craft tab includes Load 3-minute demo. Use it when you want to hear a finished reference before composing, or when you want a rich project to take apart and study.
Neon Patrol — Warehouse Mix is about 3:04 at 120 BPM and contains 20 named patterns across 46 song-order entries. It hits immediately with a four-on-the-floor groove, jumping bass runs, a nonstop acid lead, and chord/percussion stabs layered across all three voices. The groove drops away twice for short, high-register lead breaks before the final overdrive. Its late-80s/early-90s arcade-rave character is an original nod to the energy of acts such as 808 State and Monty on the Run, not a quotation of any one track. The arrangement demonstrates every Workshop technique: fast arpeggios, delayed vibrato, pitch slides, filter events, pulse-width motion, programmed waveforms, voice time-sharing, hard sync, ring modulation, and chip-model colour.
The full demo is intentionally a listening reference rather than the first exercise in this guide. Choose New tune for the plain baseline, then come back to the demo and compare how each technique changes the same kind of three-voice material. Loading it does not overwrite a file until you choose Save tune.
The SID has three independent voices, each with an oscillator, pulse width, waveform, control register, and ADSR envelope. One shared filter can colour selected voices. A classic player writes those values repeatedly, so a note can evolve after it starts.
Think in four layers:
The Workshop keeps these layers separate so you can change an instrument once and hear that change everywhere it is used.
Use Import → MIDI in the Workshop header to convert a Standard MIDI file into an editable SID project. The converter quantises PPQN timing to sixteenth-note tracker rows, maps low notes to the bass voice, the upper line to the lead voice, and a second melodic track to the counter voice. MIDI drum hits are time-shared onto that third voice. Up to 64 patterns (2,048 rows) are preserved; longer files are clearly marked as clipped. The result is an intentionally editable sketch: use the tracker to clean up overlaps, choose SID patches, and add arpeggios, filter movement, or voice-time-sharing after import.
Use Import → GoatTracker SNG to convert a GoatTracker v2 .sng file. The importer reads the first subtune's three channel order lists, patterns, instruments, and modulation tables, then creates an editable .c64music.json-style project. Notes, ADSR, core waveform controls, pulse width, basic vibrato, and simple modulation are carried across; advanced per-row/table commands that do not have a direct Workshop equivalent are listed in the import status. Multiple subtunes are currently limited to the first subtune. Save the converted tune under a new name, then export its .cbi player include for the game.
The browser preview is a lightweight musical model, not a replacement for the silicon. For every note, Crusty Studio renders a short PCM buffer with a triangle, saw, pulse, or noise oscillator, then applies the instrument's pulse-width motion, ADSR envelope, arpeggio, vibrato, pitch slide, ring modulation, sync reset, and programmed waveform changes. A Web Audio filter approximates the selected 6581/8580 colour and the shared cutoff/resonance controls.
Long songs are rendered into complete preview buffers before playback begins. The Workshop shows rendering progress and a memory estimate for long previews; if the estimate is unsafe, play an individual pattern or shorten the arrangement. This affects only the browser preview, not the exported game player.
The real SID is register-driven: three voices have independent oscillator and envelope controls, while the filter is shared. The player include therefore writes SID.FREQ, SID.ADSR, SID.CTRL, SID.PULSE_WIDTH, and filter registers as a crustyBASIC routine. The browser model helps you compose and audition; an emulator or physical SID is the authority for cycle timing, analogue filter behaviour, oscillator leakage, and chip-to-chip variation.
The song preview renders one bounded mixed buffer and plays it through a single loopable source. That keeps the audio graph small and the loop boundary sample-stable; the UI follows the same Web Audio clock for row highlighting. Patch audition remains a short per-note render, so it can be used safely while experimenting with an instrument.
Make the musical roles explicit before entering notes:
| Voice | Role | Suggested range | Why it works |
|---|---|---|---|
| 1 | Bass and low percussion | C-2–A-2 | Anchors the harmony and leaves space above. |
| 2 | Lead and answer phrase | C-4–A-4 | Carries the tune where the ear can follow it. |
| 3 | Chords, echo, and drums | C-3–G-4 | Changes jobs over time instead of playing continuously. |
Use 125 BPM, Speed 6, PAL, and MOS 6581 as the starting point. Each 32-row pattern is one phrase. The compact starter arrangement uses eight song-order entries across four related patterns, giving the learning cue room to develop; the full demo expands that idea to 46 entries. Rests are intentional: they create contrast and leave room for sound effects.
neon-patrol.c64music.json.Neon Patrol and fill in Author.125 and Speed to 6.The default starter arrangement is safe to replace. Its purpose is to show the shape of a three-voice pattern while you learn the controls.
Before using SID tricks, make a version that would still work as a conventional three-part song. From a blank tune, press + Instrument three times so you have four patches. Turn every pulse motion, arpeggio, vibrato, wave-program step, sync, ring modulation, and row effect off for now.
Set the patches like this:
| Patch | Waveform | Envelope (A/D/S/R) | Gate | Other settings |
|---|---|---|---|---|
Neon Bass (1) |
Pulse | 0 / 4 / 9 / 2 |
5 ticks | Pulse width $800, no motion, filter off |
Neon Lead (2) |
Saw | 2 / 6 / 10 / 4 |
6 ticks | Arpeggio 0, vibrato depth 0, empty Wave program |
Neon Chord (3) |
Triangle | 1 / 5 / 8 / 3 |
5 ticks | Static, no filter routing |
Plain Drum (4) |
Noise | 0 / 2 / 0 / 1 |
2 ticks | Static noise, no sync or ring modulation |
Audition each patch. This is your control recording: save it as Neon Patrol — Plain or simply remember the sound before adding colour. Every later change should be something you can hear against this baseline.
Every tracker cell contains a note, an instrument number, and an optional three-character effect. For the baseline, leave the effect field empty and leave unlisted cells as rests (···). Enter these accented rows:
Row Voice 1 Voice 2 Voice 3
00 C-2 · 1 C-4 · 2 C-3 · 3
04 G-2 · 1 E-4 · 2 G-4 · 3
08 A#2 · 1 G-4 · 2 ··· · 4
0C G-2 · 1 E-4 · 2 C-4 · 3
10 C-2 · 1 C-4 · 2 ··· · 4
14 G-2 · 1 D-4 · 2 G-4 · 3
18 A#2 · 1 G-4 · 2 ··· · 4
1C G-2 · 1 E-4 · 2 C-4 · 3
Type notes directly: g2 becomes G-2, while g#2 becomes G#2. Keep the rhythm simple. Voice 1 is the bass, voice 2 is the melody, and voice 3 alternates chord and drum jobs. Press Play song, then use the voice checkboxes to hear the bass, lead, and harmony separately. The Volume slider in the transport changes only the browser preview level; it does not change the exported SID player’s chip volume.
Now make the baseline long enough to feel like a real cue before changing its sound:
Main riff.Neon lift, and move the final lead answer up an octave on rows 18 and 1C.Night drive, and enter a lower, sparser bass for its first half. Let the lead carry more of the rhythm.Night drive, rename the copy Finale sparks, and raise the lead one octave for the last four accented rows.Main riff → Neon lift → Main riff → Night drive → Finale sparks → Neon lift → Night drive → Finale sparks. Select a pattern and use ↑ Up or ↓ Down to move it; the selected pattern stays visible while you reorder the timeline.This is the “plain” version of Neon Patrol. Save it now so you can return to it after experimenting.
Make one listening pass with all three voices enabled, then repeat with each voice muted. The purpose is to hear the musical structure without relying on timbral tricks. Check that:
If the plain version does not work, stop here and rewrite the notes. Effects should reveal a good song, not conceal a weak one.
Duplicate your saved plain project or keep it open as the reference. After each change, press Play song, then compare the result with the plain version:
Neon lift, set Instrument 2's Arpeggio to 0, 4, 7. Replay voice 2 alone, then the full mix. The single oscillator now implies a major chord.A47 on voice 2 row 08 of Night drive. Compare that one entrance with the same row in Main riff.12¢, speed 6 Hz, delay 3. Compare a held lead note before and after; the attack should stay clear while the tail moves.U18 on the final bass entrance of Neon lift, then D12 on the answer in Night drive. These should sound like pickups and replies, not permanent bends.180 at 1.5 Hz. Toggle it back to 0 and listen for the change in width and brightness.0 = noise, tick 1 = pulse, and tick 4 = triangle. Replace one chord stab with this patch and compare the transient/body/tail shape with Plain Drum.F5A on the first voice-3 entrance of the finale. Compare the closed, plain entrance with the opening filter colour.Keep a note of which changes are improvements. The goal is not to use every effect everywhere; it is to make the same notes tell a more expressive story than the plain recording.
Once the comparisons are complete, turn the experiment into a deliberate final arrangement:
Main riff by itself. It should establish the key and rhythm with no sudden effect that sounds like an accident.Neon lift next. Check that the higher answer, brighter filter event, and faster movement feel like a lift rather than a new unrelated song.Main riff reprise. If it feels too static after the lift, add one small variation—an octave change, a passing note, or a different voice-3 hand-off—not a full rewrite.Night drive with voice 3 muted, then enabled. Its bass and lead should work alone; voice 3 should add colour, not be required to explain the harmony.Finale sparks and listen to the last four accented rows. Use a rising Uxx, falling Dxx, or filter opening only if it makes the arrival clearer. Remove anything that makes the ending feel unfinished.Main riff → Neon lift → Main riff → Night drive → Finale sparks → Neon lift → Night drive → Finale sparks. Rename any copy that still says copy..cbi. Keep Loop enabled while editing; turn it off for a one-shot cue so the generated player stops at the end.Effects are three hexadecimal characters. The first letter selects the operation; x and y are hexadecimal parameters.
| Code | Meaning | Example |
|---|---|---|
Axy |
Arpeggio: root, +x, +y semitones |
A47 = major-colour triad. |
Vxy |
Vibrato depth and speed override | V26 = gentle delayed movement. |
Uxx |
Slide pitch upward over ticks | U18 = rising bend. |
Dxx |
Slide pitch downward over ticks | D12 = falling bend. |
Fxx |
Set filter cutoff from the row | F5A = a darker-to-brighter transition. |
Use effects as punctuation. A bend on every row stops sounding like a bend; a single filter event at the start of a phrase makes the next entrance feel intentional.
Open the SID chip tab after the notes are working.
Audition both models before committing to a narrow filter setting. If the musical idea only works on one exact cutoff, simplify the patch or leave more headroom.
Choose PAL · 985248 Hz or NTSC · 1022727 Hz to match the machine you will target. The Workshop stores musical notes and derives the correct frequency words for the selected clock.
Start with low-pass mode, cutoff 1180, resonance 7, and master volume 13–15. A voice only reaches the filter when its instrument has Route through filter enabled. The live register view shows the selected voice's frequency, pulse, control, ADSR, and the shared filter registers at $D415–$D418.
Use filter movement as colour: open it for a chorus, close it for an intro, and avoid maximum resonance unless the result is deliberately unstable.
Press Play song and make one kind of change at a time:
The Craft tab's cards are reminders of the same approach: time-share voices, use fast arpeggios, program the note after gate-on, compose in three lines, and treat chip variation as part of the design.
Choose Save tune. In a desktop project this writes a .c64music.json file under music/ and updates the .crusty manifest's assets.music list. The file preserves:
Use Open tune to load a saved JSON project. The Workshop normalises invalid or missing values to safe defaults so an older hand-edited file can still be opened.
Choose Export .cbi to download the generated include. The generated source flattens the ordered patterns into arrays and includes a player routine.
@INCLUDE "neon-patrol.cbi"
PROC MAIN
SIDM_INIT
WHILE 1 = 1
FRAME_WAIT
SIDM_TICK
ENDWHILE
ENDPROC
The generated .cbi file includes this same example, with the actual .cbi
file name filled in. If the include is beside main.cbs in src/, paste the
shown @INCLUDE line as-is; change the path only when you store the include in
a subfolder.
Call SIDM_INIT once. Call SIDM_TICK at the display refresh cadence named in the generated file: 50 Hz for PAL or 60 Hz for NTSC. The player updates SID.FREQ, SID.ADSR, SID.CTRL, SID.PULSE_WIDTH, gate state, filter state, and master volume. Your game loop owns scheduling, pausing, and deciding how music shares time with sound effects.
If Loop is off, the generated player clears its playing flag and calls SID.ALL_OFF at the end. If you need a title-screen loop and a gameplay loop, export separate tune files or add a second player state in your game code.
The Workshop's design follows documented SID practice rather than a particular commercial score. Rob Hubbard's 1986 interview describes programmable patches and software that flips between them; Martin Galway's released Wizball source shows compact stream interpreters, patch changes, arpeggio data, pitch movement, pulse-width movement, and filter programs. The Commodore reference manual explains the underlying SID registers and envelope controls.
Read the originals for technique and hardware context, not for copying melodies or copyrighted game data:
docs/SID_MUSIC_WORKSHOP.md research and design notes in the repositoryNeon Patrol, the Workshop starter arrangement, and the generated data in this project are original examples.
music/ and appears in the project Explorer..cbi player is included and SIDM_TICK is scheduled at the documented refresh rate.