Screenshot
Full music playback using SNESMOD, a tracker-based audio engine for the SNES.
Learning Objectives
After this lesson, you will understand:
- How SNESMOD works (module-based music)
- Loading soundbanks and modules
- Music playback controls (play, stop, pause, fade)
- Volume control
- The smconv tool workflow
Prerequisites
- Basic understanding of SNES audio concepts
- Understanding of BG text rendering
- Basic tracker music concepts (optional)
What This Example Does
- Displays a menu showing controls
- Plays an Impulse Tracker module on startup
- Full playback controls via joypad
- Volume adjustment with L/R triggers
- Fade out effect
Controls:
| Button | Action |
| A | Play music |
| B | Stop music |
| X | Pause/Resume toggle |
| L/R | Volume down/up |
| START | Fade out |
Code Type
Mixed C + Library + SNESMOD
| Component | Type |
| Hardware init | Library (consoleInit()) |
| Video mode | Library (setMode()) |
| Screen enable | Library (setScreenOn()) |
| VBlank sync | Library (WaitForVBlank()) |
| Audio | SNESMOD library |
| Font tiles | text module (textLoadFont) |
| Text rendering | text module (textPrintAt, textFlush) |
SNESMOD Overview
SNESMOD is a tracker-based music playback system:
Impulse Tracker file (.it)
|
v
[smconv tool]
|
v
soundbank.asm + soundbank.h
|
v
Linked into ROM
|
v
[SNESMOD driver]
|
v
SPC700 playback
Key Features
- 8 simultaneous channels
- Impulse Tracker module support
- Automatic BRR sample compression
- Volume control and fading
- Echo/reverb effects
- ~5.5KB driver footprint
SNESMOD API
Initialization
#include "soundbank.h"
static u16 bx
Definition main.c:159
void snesmodSetSoundbank(u8 bank)
Set the soundbank bank number.
void snesmodInit(void)
Initialize SNESMOD audio engine.
void snesmodPlay(u8 startPosition)
Start module playback.
void snesmodLoadModule(u16 moduleId)
Load a module from the soundbank.
SNESMOD - Tracker-based Audio Engine.
Main Loop (CRITICAL!)
while (1) {
}
void WaitForVBlank(void)
Wait for next VBlank period.
void snesmodProcess(void)
Process audio commands.
Warning: Failing to call snesmodProcess() every frame causes audio glitches, buffer underruns, and potential crashes.
Playback Control
void snesmodStop(void)
Stop module playback.
void snesmodPause(void)
Pause module playback.
void snesmodResume(void)
Resume module playback.
Volume Control
void snesmodSetModuleVolume(u8 volume)
Set module volume.
void snesmodFadeVolume(u8 targetVolume, u8 speed)
Fade module volume.
Creating Music
Using OpenMPT (Recommended)
- Download OpenMPT (free for Windows/Wine)
- Create new Impulse Tracker (.it) module
- Follow SNES constraints:
- Maximum 8 channels
- 32kHz sample rate
- Total samples under 58KB
- Export as
.it file
- Place in
music/ directory
Build Process
The Makefile automatically:
- Runs
smconv on your .it file
- Generates
soundbank.asm and soundbank.h
- Links the soundbank into the ROM
SOUNDBANK_SRC := music/mymusic.it
Generated Files
After building with smconv:
soundbank.h:
#define MOD_POLLEN8 0
#define SOUNDBANK_BANK 0x02
soundbank.asm:
.SECTION ".soundbank" SUPERFREE
soundbank:
.INCBIN "soundbank.bnk"
.ENDS
Build & Run
cd $OPENSNES_HOME
make -C examples/audio/snesmod_music
Then open music.sfc in your emulator (Mesen2 recommended).
Files
| File | Purpose |
main.c | UI and SNESMOD API calls |
Makefile | Build config with SNESMOD rules |
music/pollen8.it | Sample Impulse Tracker module |
soundbank.h | Generated: module IDs, bank number |
soundbank.asm | Generated: soundbank data |
soundbank.bnk | Generated: compiled soundbank |
Memory Layout
ROM
Bank 0-1: Code, tiles, tilemaps
Bank 2+: Soundbank data (smconv output)
SPC RAM
$0000-$00FF: Driver variables
$0200-$CFFF: Module data, samples
$D000-$FFFF: Echo buffer (if enabled)
Exercises
Exercise 1: Add Sound Effects
Use snesmodPlayEffect() to trigger sounds on button presses.
Exercise 2: Multiple Modules
Add a second .it file and switch between them with SELECT button.
Exercise 3: Echo Effects
Enable echo in your tracker module and hear the reverb.
Common Issues
No audio output
Music sounds wrong
- Verify module exports correctly from OpenMPT
- Check channel count (8 max)
- Verify sample rate (32kHz max)
Build fails with smconv error
- Check
.it file is valid Impulse Tracker format
- Verify smconv is built:
make -C $OPENSNES/bin smconv
Audio glitches
- Ensure
snesmodProcess() is called EVERY frame
- Check for infinite loops blocking the main loop
Technical Notes
Why Tracker-Based Music?
Tracker modules are efficient for the SNES:
- Compact pattern data (repeatable)
- Samples shared across patterns
- Volume, panning, effects per-channel
- No streaming required
smconv Options
smconv -s -o soundbank music/song.it
-s: Generate assembly and header
-o: Output basename
- Input: Impulse Tracker file(s)
What's Next?
Sound Effects: SNESMOD SFX - Sound effect playback with pitch control
Graphics: Simple Sprite - Display a sprite on screen
Credits
SNESMOD driver by Mukunda Johnson.
Sample music "pollen8" - Public domain.
License
Code: MIT SNESMOD: See snesmod.org license