Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Audio Functions

Sound effects and music playback with 16 channels.

Loading Sounds

load_sound

Loads a sound from WASM memory.

Signature:

#![allow(unused)]
fn main() {
fn load_sound(data_ptr: *const u8, byte_len: u32) -> u32
}

Parameters:

NameTypeDescription
data_ptr*const u8Pointer to PCM audio data
byte_lenu32Size of data in bytes

Returns: Sound handle (non-zero on success)

Audio Format: 22.05 kHz, 16-bit signed, mono PCM

Constraints: Init-only.

Example:

#![allow(unused)]
fn main() {
static JUMP_DATA: &[u8] = include_bytes!("jump.raw");
static mut JUMP_SFX: u32 = 0;

fn init() {
    unsafe {
        JUMP_SFX = load_sound(JUMP_DATA.as_ptr(), JUMP_DATA.len() as u32);
    }
}
}

Note: Prefer rom_sound() for sounds bundled in the ROM data pack.


Sound Effects

play_sound

Plays a sound on the next available channel.

Signature:

#![allow(unused)]
fn main() {
fn play_sound(sound: u32, volume: f32, pan: f32)
}

Parameters:

NameTypeDescription
soundu32Sound handle
volumef32Volume (0.0-1.0)
panf32Stereo pan (-1.0 = left, 0.0 = center, 1.0 = right)

Example:

#![allow(unused)]
fn main() {
fn update() {
    if button_pressed(0, BUTTON_A) != 0 {
        play_sound(JUMP_SFX, 1.0, 0.0);
    }

    // Positional audio
    let dx = enemy.x - player.x;
    let pan = (dx / 20.0).clamp(-1.0, 1.0);
    let dist = ((enemy.x - player.x).powi(2) + (enemy.z - player.z).powi(2)).sqrt();
    let vol = (1.0 - dist / 50.0).max(0.0);
    play_sound(ENEMY_GROWL, vol, pan);
}
}

channel_play

Plays a sound on a specific channel with loop control.

Signature:

#![allow(unused)]
fn main() {
fn channel_play(channel: u32, sound: u32, volume: f32, pan: f32, looping: u32)
}

Parameters:

NameTypeDescription
channelu32Channel index (0-15)
soundu32Sound handle
volumef32Volume (0.0-1.0)
panf32Stereo pan (-1.0 to 1.0)
loopingu321 to loop, 0 for one-shot

Example:

#![allow(unused)]
fn main() {
fn update() {
    // Engine sound on dedicated channel (looping)
    if vehicle.engine_on && !ENGINE_PLAYING {
        channel_play(0, ENGINE_SFX, 0.8, 0.0, 1);
        ENGINE_PLAYING = true;
    }

    // Adjust engine pitch based on speed
    if ENGINE_PLAYING {
        let vol = 0.5 + vehicle.speed * 0.005;
        channel_set(0, vol.min(1.0), 0.0);
    }
}
}

channel_set

Updates volume and pan for a playing channel.

Signature:

#![allow(unused)]
fn main() {
fn channel_set(channel: u32, volume: f32, pan: f32)
}

Parameters:

NameTypeDescription
channelu32Channel index (0-15)
volumef32New volume (0.0-1.0)
panf32New stereo pan

Example:

#![allow(unused)]
fn main() {
fn update() {
    // Fade out channel 0
    if fading {
        fade_vol -= delta_time() * 0.5;
        if fade_vol <= 0.0 {
            channel_stop(0);
            fading = false;
        } else {
            channel_set(0, fade_vol, 0.0);
        }
    }
}
}

channel_stop

Stops playback on a channel.

Signature:

#![allow(unused)]
fn main() {
fn channel_stop(channel: u32)
}

Parameters:

NameTypeDescription
channelu32Channel index (0-15)

Example:

#![allow(unused)]
fn main() {
fn update() {
    if vehicle.engine_off {
        channel_stop(0);
        ENGINE_PLAYING = false;
    }
}
}

Music

Music uses a dedicated stereo channel, separate from the 16 SFX channels.

music_play

Plays background music (looping).

Signature:

#![allow(unused)]
fn main() {
fn music_play(sound: u32, volume: f32)
}

Parameters:

NameTypeDescription
soundu32Sound handle
volumef32Volume (0.0-1.0)

Example:

#![allow(unused)]
fn main() {
fn init() {
    unsafe {
        MENU_MUSIC = rom_sound(b"menu_bgm".as_ptr(), 8);
        GAME_MUSIC = rom_sound(b"game_bgm".as_ptr(), 8);
    }
}

fn start_game() {
    music_play(GAME_MUSIC, 0.7);
}
}

music_stop

Stops the currently playing music.

Signature:

#![allow(unused)]
fn main() {
fn music_stop()
}

Example:

#![allow(unused)]
fn main() {
fn game_over() {
    music_stop();
    play_sound(GAME_OVER_SFX, 1.0, 0.0);
}
}

music_set_volume

Changes the music volume.

Signature:

#![allow(unused)]
fn main() {
fn music_set_volume(volume: f32)
}

Parameters:

NameTypeDescription
volumef32New volume (0.0-1.0)

Example:

#![allow(unused)]
fn main() {
fn render() {
    // Duck music during dialogue
    if dialogue_active {
        music_set_volume(0.3);
    } else {
        music_set_volume(0.7);
    }
}
}

Audio Architecture

  • 16 SFX channels (0-15) for sound effects
  • 1 Music channel (separate) for background music
  • 22.05 kHz sample rate, 16-bit mono PCM
  • Rollback-safe: Audio state is part of rollback snapshots
  • Per-frame audio generation with ring buffer

Complete Example

#![allow(unused)]
fn main() {
static mut JUMP_SFX: u32 = 0;
static mut LAND_SFX: u32 = 0;
static mut COIN_SFX: u32 = 0;
static mut MUSIC: u32 = 0;
static mut AMBIENT: u32 = 0;

fn init() {
    unsafe {
        // Load sounds from ROM
        JUMP_SFX = rom_sound(b"jump".as_ptr(), 4);
        LAND_SFX = rom_sound(b"land".as_ptr(), 4);
        COIN_SFX = rom_sound(b"coin".as_ptr(), 4);
        MUSIC = rom_sound(b"level1".as_ptr(), 6);
        AMBIENT = rom_sound(b"wind".as_ptr(), 4);

        // Start music and ambient
        music_play(MUSIC, 0.6);
        channel_play(15, AMBIENT, 0.3, 0.0, 1); // Looping ambient
    }
}

fn update() {
    unsafe {
        // Jump sound
        if button_pressed(0, BUTTON_A) != 0 && player.on_ground {
            play_sound(JUMP_SFX, 0.8, 0.0);
        }

        // Land sound
        if player.just_landed {
            play_sound(LAND_SFX, 0.6, 0.0);
        }

        // Coin pickup with positional audio
        for coin in &coins {
            if coin.just_collected {
                let dx = coin.x - player.x;
                let pan = (dx / 10.0).clamp(-1.0, 1.0);
                play_sound(COIN_SFX, 1.0, pan);
            }
        }

        // Pause menu - duck audio
        if game_paused {
            music_set_volume(0.2);
            channel_set(15, 0.1, 0.0);
        } else {
            music_set_volume(0.6);
            channel_set(15, 0.3, 0.0);
        }
    }
}
}

See Also: rom_sound