Game Boy Synthesizer: Building the Rungler in Assembly
Developing a software synthesizer for Game Boy (DMG/CGB) inspired by modular synthesis and sequencing. The project kicked off with emulating the Rungler Circuit—a Rob Hordijk design featuring two oscillators and a shift register for chaotic modulation. Implemented in Sharp SM83 assembly, tested solely on BGB and SameBoy emulators.
Background and Inspiration
The idea sparked after discovering Ess Mattisson's work: his single-track jam on the Dirtywave M8 and the Junior plugin for 4-bit synthesis akin to LSDJ. RetroPlug lets you plug a Game Boy emulator into your DAW as a VST with MIDI control. The goal? Pull chaotic sounds—beeps, bloops, and noise—from the Game Boy's APU (4 channels: 2x pulse, wave, noise).
Rungler Circuit: Two oscillators where one triggers a 3-bit linear feedback shift register (LFSR). Its output (0–7) modulates the oscillators' frequencies. Chaos theory in action—tiny parameter tweaks yield wildly different sounds.
Game Boy Technical Capabilities
Breaking down the APU and CPU for feasibility:
- Shift Register: 8-bit byte with bit ops (shift, OR). Straightforward to implement.
- Oscillators: Channels 1–2 (pulse with duty cycle). Freq down to 64 Hz, plus a counter for downsampling. Channel 1 has sweep.
- Modulation: Writing to audio registers (e.g., $FF17 for CH1 volume). No hardware multiply—bitwise ops instead. Volume: 4-bit (0–$F). Frequency: NR13/NR14, applied at frame end without retrigger.
- Reading Oscillators: GBC-only (undocumented registers), supported by BGB/SameBoy.
- UI: Sprites in VRAM, VBlank interrupt (~60 Hz, 4560 cycles) for updates. Tile-based graphics at 160x144.
Real-time pitfalls: Retriggering channels causes clicks; frequency modulation is smoother.
Assembly Development
Tools: RGBDS + VSCode plugin. Why asm over C? Real-time optimization—dissecting others' C code revealed heavy inline asm anyway.
Key challenges:
- VBlank Timing: Logic in interrupt, under 1500 cycles (profiler-checked). Overruns cause tearing (screen garbage).
- 16-bit Math: Manual A register juggling, tracking carry manually.
- Bitwise Ops: No mul/div—lookups or shifts/OR/XOR.
- Memory: VRAM writes only during VBlank (scanlines 0–153).
Getting started: Tutorials, Pandocs, AI help for "Hello World." UI: Cursor, params (freqs, modulation), reactive updates.
Implementation and Limitations
- LFSR Logic: Triggered by osc1, gated by osc2 for input. 3 bits → DAC (0–7) → scale + bias → registers.
- Sequencing: LFSR for triggers, periodic retriggers.
- Optimizations: Screen clear, cursor draw, LFSR viz. Profiler ensures safe zone.
Result: Not a full Blippoo Box (4-bit and timing limits), more like Double Knot. Sounds: Pulses to noise.
Key Takeaways:
- Game Boy APU works for LFSR modulation, but real-time is capped by retriggers and 4-bit resolution.
- VBlank is make-or-break for UI (<1500 cycles); asm is essential for headroom.
- GBC osc reading registers are undocumented, emulator-dependent.
- Bitwise ops sub for multiply: plenty for chaos effects.
- Scalable project: Wave CH3, Karplus-Strong next.
Future Directions
Next up: 4-bit synth (CH3 wave), Karplus-Strong/Risset Drum, audiovisual performances (à la Robert Henke), profiler debugging, pushing 16-bit math limits.
— Editorial Team
No comments yet.