Als ich mich vor ein paar Monaten etwas mit der Sound-Hardware und dessen Programmierung von einem Game Boy Advance beschäftigt habe, habe ich verschiedene Bibliotheken bzw. fertige Sound-Player gefunden. Im devkitPro Ordner befinden sich insgesamt 4 Beispiele, die man kompilieren kann. Im Februrar bzw. März hatte ich mir BoyScout angeschaut. Ein Tracker mit 4 Kanälen. Diese Software habe ich dann benutzt, um die Musik (wird man wohl so bezeichnen können!) für meine MSP430 Demo “A Dead Pixel” zu erstellen. Die Tracker Software habe ich dann speziell für den MSP430 geschrieben und mich auf BoyScout dabei gestützt. Aber das ist eine andere Geschichte. Mit MaxMod können mod-Files abgespielt werden. In dem vorhandenen MaxMod Beispiel habe ich ein paar Modifikationen vorgenommen. Normalerweise wird die Musik in der Hauptschleife nach einem Frame aktualisiert. Die Funktion zum aktualisieren muss also immer manuell aufgerufen werden. Dies kann natürlich zu Problemen in der Wiedergabe führen, besonders wenn in der Schleife viele Berechnungen durchgeführt werden und somit der genaue Zeitpunkt des Funktionsaufrufs nicht mehr eingehalten werden kann. Hier bietet MaxMod aber eine Problemlösung. Ein Frame-Update kann per Interrupt durchgeführt werden. Somit wird die Funktion bzw. ISR immer nach einem Frame aufgerufen. Der abgeänderte Beispiel-Code:
Die Website von MaxMod scheint nicht mehr online zu sein. Auf archive.org finden sich allerdings noch ein paar Snapshots. Hier also der Link zu der alten MaxMod Seite: MaxMod.org und die komplette Dokumentation: Maxmod Programming Reference
Die Interrupt Service Routine, um die Musik zu aktualisieren:
void updateSongFrame(void)
{
mmFrame();
}
Die ISR wird über die Funktion void mmSetVBlankHandler( void* function );
bekannt gemacht:
mmSetVBlankHandler(updateSongFrame);
Der komplette Source-Code:
#include <gba.h>
#include <maxmod.h>
#include <stdio.h>
#include <stdlib.h>
#include "soundbank.h"
#include "soundbank_bin.h"
void updateSongFrame(void)
{
mmFrame();
}
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);
mmSetVBlankHandler(updateSongFrame);
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 );
// Start playing module
//mmStart( MOD_FLATOUTLIES, MM_PLAY_LOOP );
mmStart( MOD_LOSTINMYDREAMS, MM_PLAY_LOOP );
mm_sound_effect ambulance = {
{ SFX_AMBULANCE } , // id
(int)(1.0f * (1<<10)), // rate
0, // handle
255, // volume
0, // panning
};
mm_sound_effect boom = {
{ SFX_BOOM } , // id
(int)(1.0f * (1<<10)), // rate
0, // handle
255, // volume
255, // panning
};
// ansi escape sequence to clear screen and home cursor
// /x1b[line;columnH
iprintf("\x1b[2J");
// ansi escape sequence to set print co-ordinates
// /x1b[line;columnH
iprintf("\x1b[0;8HMaxMod Audio demo");
iprintf("\x1b[3;0HHold A for ambulance sound");
iprintf("\x1b[4;0HPress B for boom sound");
// sound effect handle (for cancelling it later)
mm_sfxhand amb = 0;
do {
int keys_pressed, keys_released;
//VBlankIntrWait();
//mmFrame();
scanKeys();
keys_pressed = keysDown();
keys_released = keysUp();
// Play looping ambulance sound effect out of left speaker if A button is pressed
if ( keys_pressed & KEY_A ) {
amb = mmEffectEx(&ambulance);
}
// stop ambulance sound when A button is released
if ( keys_released & KEY_A ) {
mmEffectCancel(amb);
}
// Play explosion sound effect out of right speaker if B button is pressed
if ( keys_pressed & KEY_B ) {
mmEffectEx(&boom);
}
} while( 1 );
}