Loading...
Searching...
No Matches
SNESMOD Music Example
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 <snes/snesmod.h>
#include "soundbank.h"
snesmodInit(); /* Initialize SPC driver */
snesmodSetSoundbank(SOUNDBANK_BANK); /* Set soundbank bank */
snesmodLoadModule(MOD_POLLEN8); /* Load module by ID */
snesmodPlay(0); /* Start from position 0 */
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) {
snesmodProcess(); /* MUST call every frame! */
// ... game logic ...
}
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

snesmodPlay(0); /* Play from start */
snesmodStop(); /* Stop playback */
snesmodPause(); /* Pause */
snesmodResume(); /* Resume from pause */
void snesmodStop(void)
Stop module playback.
void snesmodPause(void)
Pause module playback.
void snesmodResume(void)
Resume module playback.

Volume Control

snesmodSetModuleVolume(127); /* 0-127 */
snesmodFadeVolume(0, 4); /* Target volume, speed */
void snesmodSetModuleVolume(u8 volume)
Set module volume.
void snesmodFadeVolume(u8 targetVolume, u8 speed)
Fade module volume.

Creating Music

Using OpenMPT (Recommended)

  1. Download OpenMPT (free for Windows/Wine)
  2. Create new Impulse Tracker (.it) module
  3. Follow SNES constraints:
    • Maximum 8 channels
    • 32kHz sample rate
    • Total samples under 58KB
  4. Export as .it file
  5. Place in music/ directory

Build Process

The Makefile automatically:

  1. Runs smconv on your .it file
  2. Generates soundbank.asm and soundbank.h
  3. 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 /* ROM bank where soundbank lives */

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