Maxmod
DS Programming Guide

Here is a guide to step through the basics of installation/usage in a DS project. This tutorial will assume that you are using one of the templates of BlocksDS.

Linking

Firstly, libmm9 must be added to your library references. Add -lmm9 to the LIBS in your makefile like this:

LIBS := -lmm9 -lnds9

Next, you need to tell the makefile to make a soundbank file for you. What is a soundbank file? It's a file that contains all the samples and modules for your project!

Add a new directory to your project; I'll call it "audio". Then, set the variable AUDIODIR to point to that folder:

AUDIODIRS := audio

The Makefile will look for all .mod, .s3m, .xm, .it and .wav files in that folder and generate a soundbank from it.

If you're using NitroFS in your project, the soundbank will be stored in the NitroFS filesystem. If not, it will be added to the ARM9 binary as data, and it will be available in memory from the start.

Keeping it in memory means that you won't be able to use that memory for anything else! If you're making a very small game, that's okay. If not, by keeping the soundbank in the filesystem, Maxmod will only load the parts that are required for the songs and audio efects that you're playing right in that moment, leaving more RAM available for you to use however you want.

Setup

Now it's time to initialize Maxmod. maxmod9.h has the definitions for the ARM9 side, include it in your source files. Also, include the generated soundbank header too.

#include <maxmod9.h> // Maxmod definitions for ARM9
#include "soundbank.h" // Soundbank definitions
Global include of Maxmod for DS (ARM9 side).

There are multiple ways of setting up Maxmod to fit your needs. The easiest way is to use the mmInitDefault() or mmInitDefaultMem() functions. mmInitDefault() is used when your soundbank is in the filesystem, mmInitDefaultMem() is used when your soundbank is loaded into memory (as described above).

void main(void)
{
// Use this if you have the soundbank loaded into memory
mmInitDefaultMem((mm_addr)soundbank_bin);
// OR, use this if you have it in the filesystem
//mmInitDefault("nitro:/soundbank.bin");
}
void * mm_addr
Memory address (pointer)
Definition: mm_types.h:44
void mmInitDefaultMem(mm_addr soundbank)
Initialize Maxmod with default settings.

Playing Music

Let's have a look at the soundbank header generated by the Maxmod Utiltiy.

#define SFX_BLASTER 0
#define SFX_PHASER 1
#define SFX_BONK 2
#define MOD_TITLE 0
#define MOD_INGAME 1
#define MOD_CREDITS 2
#define MOD_ONEMORESONG 3
#define MSL_NSONGS 4
#define MSL_NSAMPS 156
#define MSL_BANKSIZE 160

Definitions prefixed by MOD_ are module IDs. Definitions prefixed by SFX_ are sample IDs. MSL_NSONGS is the total number of modules in the soundbank, MSL_NSAMPS is the total number of samples, and MSL_BANKSIZE is the total number of modules plus samples (useful for alternate setup process).

Before playing a song, the song must be loaded into memory. Use mmLoad() to load songs into memory (or acknowledge their existence in memory).

mmLoad(MOD_TITLE);
void mmLoad(mm_word module_ID)
Loads a module into memory for playback.

Now that MOD_TITLE is loaded. You may begin playing it with mmStart().

mmStart(MOD_TITLE, MM_PLAY_LOOP);
void mmStart(mm_word id module_ID, mm_pmode mode)
Begins playback of a module.
@ MM_PLAY_LOOP
Loop module forever (until stopped).
Definition: mm_types.h:141

There are two modes for playback: MM_PLAY_ONCE and MM_PLAY_LOOP. If MM_PLAY_ONCE is used, then the module will stop playing after it finishes the last pattern. If MM_PLAY_LOOP is used, then the module will start playing again from its restart position if it reaches the end.

When you are finished with a module, unload it from memory with mmUnload().

mmUnload(MOD_TITLE);
void mmUnload(mm_word module_ID)
Unloads and frees memory space occupied by a module.

Sound Effects

To load a sound effect into memory, use mmLoadEffect().

mmLoadEffect(SFX_BLASTER);
void mmLoadEffect(mm_word sample_ID)
Loads a sound effect into memory for playback.

Now it can be played with mmEffect().

// Play a sound at its default frequency
mmEffect(SFX_BLASTER);
mm_sfxhand mmEffect(mm_word sample_ID)
Plays a sound effect with default settings.

mmEffectEx() is a more flexible version of mmEffect(). It will let you specify all of the attributes for the sound.

// Play sound at half playback rate, 200/255 volume, and center panning
sound.id = SFX_BLASTER; // Sample ID (make sure it is loaded)
sound.rate = 0x400/2; // Playback rate, 1024 = original sound
sound.handle = 0; // 0 = allocate new handle
sound.volume = 200; // 200/255 volume level
sound.panning = 128; // Centered panning
mmEffectEx(&sound);
mm_sfxhand mmEffectEx(mm_sound_effect *sound)
Plays a sound effect with custom settings.
Information for playing a sound effect.
Definition: mm_types.h:206
mm_byte panning
Panning level. Ranges from 0 (far-left) to 255 (far-right).
Definition: mm_types.h:228
mm_byte volume
Volume level. Ranges from 0 (silent) to 255 (normal).
Definition: mm_types.h:225
mm_word id
ID of sample to be played. Values are defined in the soundbank header.
Definition: mm_types.h:210
mm_hword rate
Playback rate. 6.10 fixed point number. (1024 = original sound)
Definition: mm_types.h:218
mm_sfxhand handle
Handle of previous sound effect. If a valid handle is given, it will be recycled.
Definition: mm_types.h:222

Both mmEffect() and mmEffectEx() return a sound effect handle that can be used later to modify the sound.

mysound = mmEffect(SFX_BLASTER);
// Change pitch to +1 octave
mmEffectRate(mysound, 1024 * 2);
// Change volume to half level (128 / 255)
mmEffectVolume(mysound, 128);
// Change panning to far-right
mmEffectPanning(mysound, 255);
void mmEffectRate(mm_sfxhand handle, mm_word rate)
Changes the playback rate for a sound effect.
void mmEffectVolume(mm_sfxhand handle, mm_word volume)
Changes the volume of a sound effect.
void mmEffectPanning(mm_sfxhand handle, mm_byte panning)
Changes the panning of a sound effect.

If the effect isn't so important, you can mark it for interruption. This means it can be overridden by music and other effects (if there are no other channels available).

// Allow effect to be interrupted
mmEffectRelease(mysound);
void mmEffectRelease(mm_sfxhand handle)
Marks a sound effect as unimportant.

You can stop a sound effect like this:

// Stop sound effect
mmEffectCancel(mysound);
mm_word mmEffectCancel(mm_sfxhand handle)
Stops a sound effect. The handle will be invalidated.

When you are done using a sound effect, you can unload it from memory with mmUnloadEffect().

// Unload sound from memory
mmUnloadEffect(SFX_BLASTER);
void mmUnloadEffect(mm_word sample_ID)
Unloads a sound effect and frees the memory if the reference count becomes zero.

Closing

For a better understanding, please have a look at the source code for the DS examples.