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¶
mmPlayLoop
mmPlayOnce
- type MmMixMode = enum¶
mmMix8kHz
– 8121 HzmmMix10kHz
– 10512 HzmmMix13kHz
– 13379 HzmmMix16kHz
– 15768 HzmmMix18kHz
– 18157 HzmmMix21kHz
– 21024 HzmmMix27kHz
– 26758 HzmmMix31kHz
– 31536 Hz
- type MmSoundEffect = object¶
Field
Type
Description
id
uint32 sample ID (defined in soundbank header)
rate
uint16 handle*: MmSfxHandle sound handle
volume
uint8 volume, 0..255
panning
uint8 panning, 0..255
- type MmGbaSystem = object¶
Field
Type
mixingMode
MmMixMode modChannelCount
uint32 mixChannelCount
uint32 moduleChannels
pointer activeChannels
pointer mixingChannels
pointer mixingMemory
pointer waveMemory
pointer soundbank
MmSoundbankPtr
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.
- 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.
- 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.
- 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)¶
Jumps to the pattern at the given index in the song’s pattern order table, and starts playing that pattern from the beginning.
- Position:
New position in the song.
- proc getPosition(): uint¶
Get playback position (i.e. the index of the current pattern).
- proc active(): bool¶
Returns true if module is playing.
- proc jingle(id: Module)¶
Play module as jingle. Jingles are limited to 4 channels only.
- Id:
ID of module (defined in
output/soundbank.nim
which is generated for your project)
- proc activeSub(): bool¶
Returns true if a jingle is actively playing.
- proc setModuleVolume(volume: FixedN[10])¶
Set volume scaler for music.
- 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.
- 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.
- 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.