Sound & Music

Game Boy audio architecture, hUGE music driver, sound effect playback, channel muting, and direct hardware register control for plugin development. The sound system is implemented in C.

Game Boy Audio Architecture

The Game Boy has four dedicated sound channels, each with distinct synthesis capabilities. All channels share a 4-bit volume range (0–15) and a length counter. On the Game Boy Color, each channel can be individually panned left/right for stereo output.

ChannelTypeCapabilities
CH1PulseFrequency sweep, 4 duty cycles, volume envelope
CH2Pulse4 duty cycles, volume envelope (no sweep)
CH3WaveCustom 32-sample 4-bit waveform
CH4NoiseLFSR-based noise, adjustable frequency
Shared resource

Music and sound effects share these four channels. When a sound effect plays on a channel, it temporarily overrides the music on that channel. Plan your music arrangements and SFX channel usage to avoid unwanted cutoffs.

hUGE Music Driver

GB Studio uses the hUGE tracker driver for music playback. It supports the .uge file format and is installed as a VBlank routine, guaranteeing consistent tempo regardless of main loop performance.

Music Playback (C API)

// Start music playback
music_play(bank, music_ptr);

// Stop music
music_stop();

GBVM Music Commands

CommandDescription
VM_MUSIC_PLAYPlay a music track (bank, pointer)
VM_MUSIC_STOPStop current music
VM_MUSIC_MUTEMute specific channels (bitmask)
VM_MUSIC_ROUTINESet music event routine (callback on pattern events)

Channel Mute Masks

Mute individual channels to free them for sound effects or direct hardware control. The mask is a 4-bit value where each bit corresponds to a channel:

BitChannelHex Value
0CH1 (Pulse 1)0x01
1CH2 (Pulse 2)0x02
2CH3 (Wave)0x04
3CH4 (Noise)0x08
// Mute CH4 so noise SFX won't conflict with music
VM_MUSIC_MUTE 0x08

// Mute CH1 and CH2 for a dual-pulse SFX
VM_MUSIC_MUTE 0x03

// Unmute all channels
VM_MUSIC_MUTE 0x00

Sound Effects System

Sound effects are played via a VGM-style player that runs alongside the music driver. An SFX temporarily takes over one or more channels; when the effect finishes, the channel returns to the music driver automatically.

SFX Playback

// GBVM:
VM_SFX_PLAY bank, pointer, mask, priority

// mask:     which channels the SFX uses (same bitmask as mute)
// priority: higher value = won't be interrupted by lower priority SFX

Built-in Sound Types

GB Studio includes predefined sound effect types accessible from the event editor:

ISR-driven playback

SFX playback is handled by sfx_play_isr, a Z80 assembly ISR. This ensures sound effects play at consistent speed, independent of main loop timing.

Direct Channel Control

For plugins that need precise control over audio hardware, you can write directly to the Game Boy’s sound registers. This is necessary for custom tones, engine sound effects, and any audio behavior not covered by the built-in SFX system.

Pulse Channel Registers (CH1 / CH2)

RegisterAddressDescription
NR100xFF10CH1 sweep (period, direction, shift)
NR110xFF11CH1 duty cycle + length
NR120xFF12CH1 volume envelope
NR130xFF13CH1 frequency low byte
NR140xFF14CH1 frequency high + trigger
NR21–240xFF16–19CH2 (same layout, no sweep register)

Noise Channel Registers (CH4)

RegisterAddressDescription
NR410xFF20Length
NR420xFF21Volume envelope
NR430xFF22Polynomial counter (frequency)
NR440xFF23Trigger + length enable

Volume Envelope Format

Registers NR12, NR22, and NR42 share the same envelope format:

NRx2 format: VVVV DNNN
V = initial volume (0-15)
D = direction (0 = decrease, 1 = increase)
N = envelope period (0 = disabled, 1-7 = speed)
ValueEffect
0xF0Volume 15, no envelope (constant full volume)
0xF1Volume 15, fade out slowly
0xF7Volume 15, fade out quickly
0x11Volume 1, fade in slowly
0x00Silence (volume 0, no envelope)

Frequency Calculation

The pulse and wave channels use an 11-bit frequency register. To play a specific note frequency:

frequency_register = 2048 - (131072 / desired_hz)
NoteHzRegister Value
C4 (Middle C)2621548
A44401750
C55231797
A58801899

Common Patterns

Playing SFX Without Interrupting Music

Mute the target channel in the music driver before playing a sound effect on it:

// Mute CH4 in music, then use CH4 for noise SFX
VM_MUSIC_MUTE 0x08
VM_SFX_PLAY bank, sfx_ptr, 0x08, 5

Custom Tone from a Plugin

Play a 440 Hz tone (A4) on CH2 using direct register writes:

// Play a 440Hz tone on CH2
NR21_REG = 0x80;         // 50% duty cycle
NR22_REG = 0xF0;         // Volume 15, no envelope
UINT16 freq = 2048 - (131072 / 440);  // = 1750
NR23_REG = freq & 0xFF;               // Low byte
NR24_REG = 0x80 | ((freq >> 8) & 0x07);  // Trigger + high bits
Mute before direct writes

If music is playing, mute the target channel with VM_MUSIC_MUTE before writing to its registers. Otherwise the music driver will immediately overwrite your values on the next VBlank.

Stopping a Tone

Set the volume envelope to zero to silence a channel:

// Silence CH2
NR22_REG = 0x00;  // Volume 0, no envelope
NR24_REG = 0x80;  // Trigger to apply the new envelope