maxmod#
Bindings for the Maxmod sound system by Mukunda Johnson. See the maxmod reference manual for more documentation.
Configuration#
The audio.nims
file is used to add music and sfx to your project. This runs before your game is compiled, and generates two enums which are available to your game code: Sample
for sound effects and Module
for songs.
In this file, the following operations are available:
- proc sample(name: string)#
Add a sound effect in
.wav
format, to be converted and added to the soundbank.
- proc module(name: string)#
Add a song in
.mod
,.xm
,.it
or.s3m
format, to be converted and added to the soundbank.
Since there are no other parameters to these procedures, you can write an audio.nims
to convert new files automatically, as shown in the tutorial section below.
Tutorial#
Configure your
audio.nims
to automatically scan a directory in your project:# Add all music and sounds from the audio directory. for f in listFiles("audio").sorted: if f.endsWith(".wav"): sample f else: module f
Note
The list of files should be sorted, otherwise the files aren’t guaranteed to appear in the same order on different machines, so you lose reproducibility of your builds. Ok, tbh there never was any reproducibility but it’s nice to pretend. x)
Add some music & sounds to the directory:
MyGame/ ├── audio.nims ├── audio │ ├── coin.wav │ ├── jump.wav │ ├── shoot.wav │ ├── spacecat.xm │ └── subway.xm ├── config.nims └── game.nim
Note
Sounds must be
.wav
files, 8-bit, mono. 16000 Hz sample rate is usually adequate. Music must be tracker modules in.mod
,.xm
,.it
or.s3m
formats.This will cause the following types to be generated:
type Sample = enum sfxCoin sfxJump sfxShoot Module = enum modSpacecat modSubway
Import maxmod, initialise it, and start using the
sfx
andmod
values in your code:import natu/[bios, irq, input, maxmod] # register maxmod VBlank handler irq.put(iiVBlank, maxmod.vblank) # init with 8 channels maxmod.init(soundbankBin, 8) # play music maxmod.start(modSpacecat, mmPlayLoop) while true: keyPoll() if keyHit(kiA): # play sound effect maxmod.effect(sfxShoot) # mix one frame of audio maxmod.frame() VBlankIntrWait()
Types#
- type Sample = enum#
Represents an audio sample in ROM, converted from a
.wav
file. Each converted sample will be given an enum value with the “sfx” prefix. For examplebark.wav
will becomesfxBark
.
- type Module = enum#
Represents a song in ROM, converted from a
.mod
,.xm
,.it
or.s3m
file. Each converted song will be given an enum value with the “mod” prefix. For examplefunky.xm
will becomemodFunky
.
- type MmSoundbankPtr = distinct cstring#
Pointer to soundbank data
- type MmSfxHandle = distinct uint16#
- proc `==`(a, b: MmSfxHandle): bool#
- type MmFnPtr = proc () {.nimcall.}#
- type MmCallback = proc (msg: uint; param: uint): uint {.nimcall.}#
- type MmPlaybackMode = enum#
- type MmMixMode = enum#
- type MmSoundEffect = object#
- type MmGbaSystem = object#
Variables#
- let soundbankBin: MmSoundbankPtr#
Pointer to your game’s soundbank data. You should pass this to
maxmod.init
.
Constants#
These are mostly useful for initialising Maxmod manually with a MmGbaSystem
object.
Procedures#
- proc init(soundbank: MmSoundbankPtr, channels: uint)#
Initialize Maxmod with default settings.
Parameters:
- soundbank
Memory address of soundbank (in ROM). A soundbank file can be created with the Maxmod Utility (or generated by Natu when you run
nim build
)- channels
Number of module/mixing channels to allocate. Must be greater or equal to the channel count in your modules.
For GBA, this function uses these default settings (and allocates memory): 16kHz mixing rate, channel buffers in EWRAM, wave buffer in EWRAM, and mixing buffer in IWRAM.
- proc init(setup: ptr MmGbaSystem)#
Initialize system. Call once at startup.
- proc vblank()#
This procedure must be linked directly to the VBlank IRQ, or be the very first thing that runs in your custom VBlank handler.
During this procedure, the sound DMA is reset. The timing is extremely critical, so make sure that it is not interrupted, otherwise garbage may be heard in the output.
- proc setVBlankHandler(function: MmFnPtr)#
Install user vblank handler.
Parameters:
- function
Pointer to your VBlank handler.
- proc setEventHandler(handler: MmCallback)#
Install handler to receive song events.
Use this function to receive song events. Song events occur in two situations: One is by special pattern data in a module (which is triggered by
SFx
/EFx
commands). The other occurs when a module finishes playback (inmmPlayOnce
mode).During the song event, Maxmod is in the middle of module processing. Avoid using any Maxmod related functions during your song event handler since they may cause problems in this situation.
- proc frame()#
This is the main work routine that processes music and updates the sound output.
This function must be called every frame. If a call is missed, garbage will be heard in the output and module processing will be delayed.
- proc start(id: Module, mode: MmPlaybackMode = mmPlayLoop)#
Start module playback.
Parameters:
- id
ID of module to play.
- mode
Playback mode (
mmPlayLoop
ormmPlayOnce
)
- proc pause()#
Pause module playback, resume with
maxmod.resume()
- proc resume()#
Resume module playback, pause with
maxmod.pause()
- proc stop()#
Stop module playback. start again with
maxmod.start()
.
- proc setPosition(position: uint)#
Set playback position.
Parameters:
- position
New position in the module sequence.
- proc getPosition(): uint#
Get playback position.
- proc active(): bool#
Returns true if module is playing.
- proc jingle(id: Module)#
Play module as jingle. Jingles are limited to 4 channels only.
Parameters:
- moduleID
ID of module (defined in soundbank header)
- proc activeSub(): bool#
Returns true if a jingle is actively playing.
- proc setModuleVolume(volume: FixedN[10])#
Set volume scaler for music.
Parameters:
- volume
Multipler for the overall volume of the song, ranging from
0.0 .. 1.0
(silent .. normal).
- proc setJingleVolume(volume: FixedN[10])#
Set volume scaler for jingles.
Parameters:
- volume
Multipler for the overall volume of the jingle, ranging from
0.0 .. 1.0
(silent .. normal).
- proc setModuleTempo(tempo: FixedN[10])#
Set tempo of playback.
Parameters:
- tempo
Multiplier for the overall tempo of the song, ranging from
0.5 .. 2.0
- proc setModulePitch(pitch: FixedN[10])#
Set pitch of playback.
- pitch
Multiplier for the overall pitch of the song, ranging from
0.5 .. 2.0
.
- proc playModule(address: pointer, mode: uint, layer: uint)#
Play direct MAS file
- proc effect(id: Sample): MmSfxHandle#
Play a sound effect at its default frequency with full volume and centered panning.
Parameters:
- id
Sound effect ID. (defined in
output/soundbank.nim
which is generated for your project)
- proc effectEx(sound: ptr MmSoundEffect): MmSfxHandle#
Play a sound effect with all parameters.
Parameters:
- sound
Sound effect attributes.
- proc setVolume(handle: MmSfxHandle, volume: FixedN[8])#
Set the volume of a sound effect.
Parameters:
- handle
Sound effect handle.
- volume
Effect volume ranging from
0.0 ..< 1.0
(underlying value from0 .. 255
)
- proc setPanning(handle: MmSfxHandle, panning: FixedN[8])#
Set the panning of a sound effect.
Parameters:
- handle
Sound effect handle.
- panning
0.0 ..< 1.0
=left .. right
- proc setRate(handle: MmSfxHandle, rate: FixedN[10])#
Set the playback rate of an effect.
Parameters:
- handle
Sound effect handle.
- rate
Absolute playback rate, ranging from
0.0 ..< 64.0
.
- proc scaleRate(handle: MmSfxHandle, factor: FixedN[10])#
Scale the playback rate of an effect.
Parameters:
- handle
Sound effect handle.
- factor
Amount by which to multiply the playback rate, ranging from
0.0 ..< 64.0
.
- proc cancel(handle: MmSfxHandle)#
Stop sound effect.
Parameters:
- handle
Sound effect handle.
- proc release(handle: MmSfxHandle)#
Release sound effect (invalidate handle and allow interruption)
Parameters:
- handle
Sound effect handle.
- proc active(): bool#
Returns true if module is playing.
- proc setEffectsVolume(volume: FixedN[8])#
Set master volume scale for effect playback.
Parameters:
- volume
0.0 ..< 1.0
representing 0% to 100% volume.
- proc cancelAllEffects()#
Stop all sound effects
Playback Events#
- const mmcbSongMessage = 0x0000002A'u32#
This happens when Maxmod reads a
SFx
(or mod/xmEFx
) effect from a module.param
will contain the number specified in the effect (e.g.3
forEF3
).
- const mmcbSongFinished = 0x0000002B'u32#
This happens when a module has finished playing, which can happen if you passed
mmPlayOnce
tomaxmod.start
, or when playing a jingle.param
will be0
if the main module has ended, or1
if the sub module (jingle) has ended.