maxmod
maxmod copied to clipboard
Occasional crash on GBA when using mmInit
The crash can be replicated by simply taking the basic_sound example and changing the call to mmInitDefault
to mmInit
. For the code below, I'm using the GBA example given here:
https://maxmod.devkitpro.org/ref/functions/mmInit.html
...
// Mixing buffer (globals should go in IWRAM)
// Mixing buffer SHOULD be in IWRAM, otherwise the CPU load
// will _drastially_ increase
u8 myMixingBuffer[ MM_MIXLEN_16KHZ ] __attribute((aligned(4)));
void maxmodInit( void )
{
irqSet( IRQ_VBLANK, mmVBlank );
u8* myData;
mm_gba_system mySystem;
// allocate data for channel buffers & wave buffer (malloc'd data goes to EWRAM)
// Use the SIZEOF definitions to calculate how many bytes to reserve
myData = (u8*)malloc( 8 * (MM_SIZEOF_MODCH
+MM_SIZEOF_ACTCH
+MM_SIZEOF_MIXCH)
+MM_MIXLEN_16KHZ );
// setup system info
// 16KHz software mixing rate, select from mm_mixmode
mySystem.mixing_mode = MM_MIX_16KHZ;
// number of module/mixing channels
// higher numbers offer better polyphony at the expense
// of more memory and/or CPU usage.
mySystem.mod_channel_count = 8;
mySystem.mix_channel_count = 8;
// Assign memory blocks to pointers
mySystem.module_channels = (mm_addr)(myData+0);
mySystem.active_channels = (mm_addr)(myData+(8*MM_SIZEOF_MODCH));
mySystem.mixing_channels = (mm_addr)(myData+(8*(MM_SIZEOF_MODCH
+MM_SIZEOF_ACTCH)));
mySystem.mixing_memory = (mm_addr)myMixingBuffer;
mySystem.wave_memory = (mm_addr)(myData+(8*(MM_SIZEOF_MODCH
+MM_SIZEOF_ACTCH
+MM_SIZEOF_MIXCH)));
// Pass soundbank address
mySystem.soundbank = (mm_addr)soundbank_bin;
// Initialize Maxmod
mmInit( &mySystem );
}
int main() {
irqInit();
// Maxmod requires the vblank interrupt to reset sound DMA.
// Link the VBlank interrupt to mmVBlank, and enable it.
irqSet( IRQ_VBLANK, mmVBlank );
irqEnable(IRQ_VBLANK);
consoleDemoInit();
// ansi escape sequence to clear screen and home cursor
// /x1b[line;columnH
iprintf("\x1b[2J");
// initialise maxmod with soundbank and 8 channels
//mmInitDefault( (mm_addr)soundbank_bin, 8 );
maxmodInit();
...
The reason for the crash is because for
mySystem.mixing_mode = MM_MIX_16KHZ;
the compiler generates code that sets the mixing mode as a byte. But, when mmMixerInit
is called the mixing_mode
is read as word
ldr r1, [r0,#MM_GBA_SYSTEM_MODE]
Because there's padding between mixing_mode
and mod_channel_count
any bytes that were already on the stack get read as part of the mixing mode.
Besides remembering to zero the mm_gba_system
struct before using it, this could probably just be fixed by just changing the ldr
to a ldrb
in mmMixerInit