GBA
GBA Programming Guide

Back to Index

Here is a guide to step through the basics of installation/usage of Maxmod in a GBA project. This tutorial will assume that you are using the default GBA template (makefile) from devkitPro.

Linking

Firstly, libmm must be added to your library references. Add -lmm to the LIBS in your makefile.

#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS    := -lmm -lgba

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". Add a variable to the directory section of the makefile.

#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# AUDIO is a list of directories containing sound and music files
#---------------------------------------------------------------------------------
TARGET   :=  $(shell basename $(CURDIR))
BUILD    :=  build
SOURCES  :=  gfx source data  
INCLUDES :=  include build
AUDIO    :=  audio

Next, you need to build a list of the files in the audio directory. Also add the soundbank output file to your binary file list.

CFILES    :=  $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES  :=  $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES    :=  $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES  :=  $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.bin))) soundbank.bin

# build audio file list, include full path
export AUDIOFILES := $(foreach dir,$(notdir $(wildcard $(AUDIO)/*.*)),$(CURDIR)/$(AUDIO)/$(dir))

Finally, you need a rule to make the soundbank file with the Maxmod Utility. Scroll down to the bottom somewhere and add something like this. You also need a rule to convert the output binary so it can be linked in.

#-------------------------------------------------------------
# rule for converting the output into an object file
#-------------------------------------------------------------
%.bin.o:	%.bin
#-------------------------------------------------------------
	@$(bin2o)

#-------------------------------------------------------------
# rule for generating soundbank file from audio files
#-------------------------------------------------------------
soundbank.bin:	$(AUDIOFILES)
#-------------------------------------------------------------
	@mmutil $^ -osoundbank.bin -hsoundbank.h

Now the soundbank file should be generated and linked into the project automatically. Load the audio folder with a few modules (and maybe some WAV files) to test with!

Setup

Now it's time to initialize Maxmod. maxmod.h has the definitions for a GBA project, include it in your source files. Also, include the generated soundbank header too.

#include <maxmod.h>    // Maxmod definitions for GBA
#include "soundbank.h"  // Soundbank definitions

Maxmod may be initialized now. The GBA library is customizable, so you can configure how many channels or what mixing rate to use, but for this example, we will just use the easy method. mmInitDefault. It's two parameters are the soundbank address, and the number of channels to allocate. It sets up everything for us (including VBlank IRQ [with libgba]) and uses 16KHz mixing rate.

#include <maxmod.h>
#include "soundbank.h"
#include "soundbank_bin.h" // Soundbank binary reference

int main( void ) {
    // Initialize maxmod with default settings
    // pass soundbank address, and allocate 8 channels.
    mmInitDefault( soundbank_bin, 8 );

    ...
}

Playing Music

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

#define MOD_SONG1        0
#define MOD_SONG2        1
#define MOD_CREDITS      2
#define MOD_ANOTHER      3
#define MOD_SECRET       4
#define SFX_BLASTER      179
#define SFX_PHASER       180
#define MSL_NSONGS       5
#define MSL_NSAMPS       181
#define MSL_BANKSIZE     186

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 DS projects).

Use mmStart to play a song.

mmStart( MOD_SONG2, MM_PLAY_LOOP );
// Song is playing now (well... almost)

Not just yet! The actual song playback (and software mixing) occurs when you call mmFrame. This must be called every frame (60hz) (in your main loop).

while(1) {
    // ..process game logic..
    
    // Update Maxmod
    mmFrame();
    
    // Wait for new frame (SWI 5)
    VBlankIntrWait();
    
    // ..update graphical data..
}

Sound Effects

The simplest way to play a sound is with mmEffect.

// Play SFX_BLASTER at default pitch with full volume and center panning
mmEffect( SFX_BLASTER );

If you need more control; use mmEffectEx to specify rate, volume, and panning (and more).

// Play sound at half playback rate, 200/255 volume, and center panning
mm_sound_effect sound;
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 );

mmEffect and mmEffectEx both return an mm_sfxhand type. This can be used to modify the sound effect while it's playing.

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 );

To stop an effect that's playing:

// Stop sound effect
mmEffectCancel( mysound );

Sometimes the effect you just played isn't so important. You can mark it as a background effect with mmEffectRelease.

mmEffectRelease( mysound );
// Now the sound is allowed to be interrupted by other effects/music (if the need arises)

Closing

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