diff --git a/Makefile b/Makefile index ed3d23924..8c414ccfc 100644 --- a/Makefile +++ b/Makefile @@ -116,7 +116,7 @@ PNG_ASSETS_DIR = gfx/ MAPFILE = opl.map EE_LDFLAGS += -Wl,-Map,$(MAPFILE) -EE_LIBS = -L$(PS2SDK)/ports/lib -L$(GSKIT)/lib -L./lib -lgskit -ldmakit -lgskit_toolkit -lpoweroff -lfileXio -lpatches -ljpeg_ps2_addons -ljpeg -lpng -lz -ldebug -lm -lmc -lfreetype -lvux -lcdvd -lnetman -lps2ips -laudsrv -lpadx -lelf-loader +EE_LIBS = -L$(PS2SDK)/ports/lib -L$(GSKIT)/lib -L./lib -lgskit -ldmakit -lgskit_toolkit -lpoweroff -lfileXio -lpatches -ljpeg_ps2_addons -ljpeg -lpng -lz -ldebug -lm -lmc -lfreetype -lvux -lcdvd -lnetman -lps2ips -laudsrv -lvorbisfile -lvorbis -logg -lpadx -lelf-loader EE_INCS += -I$(PS2SDK)/ports/include -I$(PS2SDK)/ports/include/freetype2 -I$(GSKIT)/include -I$(GSKIT)/ee/dma/include -I$(GSKIT)/ee/gs/include -I$(GSKIT)/ee/toolkit/include -Imodules/iopcore/common -Imodules/network/common -Imodules/hdd/common -Iinclude BIN2C = $(PS2SDK)/bin/bin2c diff --git a/include/config.h b/include/config.h index ccb9ee1f0..4cd7f1f80 100644 --- a/include/config.h +++ b/include/config.h @@ -102,8 +102,11 @@ enum CONFIG_INDEX { #define CONFIG_OPL_PARENTAL_LOCK_PWD "parental_lock_password" #define CONFIG_OPL_SFX "enable_sfx" #define CONFIG_OPL_BOOT_SND "enable_boot_snd" +#define CONFIG_OPL_BGM "enable_bgm" #define CONFIG_OPL_SFX_VOLUME "sfx_volume" #define CONFIG_OPL_BOOT_SND_VOLUME "boot_snd_volume" +#define CONFIG_OPL_BGM_VOLUME "bgm_volume" +#define CONFIG_OPL_DEFAULT_BGM_PATH "default_bgm_path" // Network config keys #define CONFIG_NET_ETH_LINKM "eth_linkmode" diff --git a/include/dialogs.h b/include/dialogs.h index f599acb52..ba0efb2dd 100644 --- a/include/dialogs.h +++ b/include/dialogs.h @@ -56,8 +56,11 @@ enum UI_ITEMS { CFG_SFX, CFG_BOOT_SND, + CFG_BGM, CFG_SFX_VOLUME, CFG_BOOT_SND_VOLUME, + CFG_BGM_VOLUME, + CFG_DEFAULT_BGM_PATH, NETCFG_SHOW_ADVANCED_OPTS, NETCFG_PS2_IP_ADDR_TYPE, diff --git a/include/opl.h b/include/opl.h index bb84a1de8..a4f5b0e32 100644 --- a/include/opl.h +++ b/include/opl.h @@ -136,8 +136,11 @@ extern int gHDDGameListCache; extern int gEnableSFX; extern int gEnableBootSND; +extern int gEnableBGM; extern int gSFXVolume; extern int gBootSndVolume; +extern int gBGMVolume; +extern char gDefaultBGMPath[128]; extern int gCheatSource; extern int gGSMSource; diff --git a/include/sound.h b/include/sound.h index 6e3cbaac1..0ccc292b2 100644 --- a/include/sound.h +++ b/include/sound.h @@ -12,10 +12,16 @@ enum SFX { SFX_COUNT }; +void audioInit(void); +void audioEnd(void); +void audioSetVolume(void); + int sfxInit(int bootSnd); -void sfxEnd(void); -void sfxVolume(void); int sfxGetSoundDuration(int id); void sfxPlay(int id); +void bgmStart(void); +void bgmStop(void); +int isBgmPlaying(void); + #endif diff --git a/lng_tmpl/_base.yml b/lng_tmpl/_base.yml index 7748412c9..f2b29e0ff 100644 --- a/lng_tmpl/_base.yml +++ b/lng_tmpl/_base.yml @@ -662,3 +662,11 @@ gui_strings: string: OSD Language - label: ENABLE_LNG string: Change language +- label: BGM + string: Background Music +- label: BGM_VOLUME + string: Background Music Volume +- label: DEF_BGM_PATH + string: Default Theme Music +- label: DEF_BGM_PATH_HINT + string: Set path to stream music for internal theme. diff --git a/src/dialogs.c b/src/dialogs.c index bba944e1d..d14fb2d5e 100644 --- a/src/dialogs.c +++ b/src/dialogs.c @@ -968,6 +968,11 @@ struct UIItem diaAudioConfig[] = { {UI_LABEL, 0, 1, 1, -1, -40, 0, {.label = {NULL, _STR_BOOT_SND}}}, {UI_SPACER}, {UI_BOOL, CFG_BOOT_SND, 1, 1, -1, 0, 0, {.intvalue = {0, 0}}}, + {UI_BREAK}, + + {UI_LABEL, 0, 1, 1, -1, -40, 0, {.label = {NULL, _STR_BGM}}}, + {UI_SPACER}, + {UI_BOOL, CFG_BGM, 1, 1, -1, 0, 0, {.intvalue = {0, 0}}}, {UI_SPLITTER}, {UI_LABEL, 0, 1, 1, -1, -40, 0, {.label = {NULL, _STR_SFX_VOLUME}}}, @@ -980,6 +985,16 @@ struct UIItem diaAudioConfig[] = { {UI_INT, CFG_BOOT_SND_VOLUME, 1, 1, -1, 0, 0, {.intvalue = {0, 0, 0, 100}}}, {UI_BREAK}, + {UI_LABEL, 0, 1, 1, -1, -40, 0, {.label = {NULL, _STR_BGM_VOLUME}}}, + {UI_SPACER}, + {UI_INT, CFG_BGM_VOLUME, 1, 1, -1, 0, 0, {.intvalue = {0, 0, 0, 100}}}, + {UI_SPLITTER}, + + {UI_LABEL, 0, 1, 1, -1, -40, 0, {.label = {NULL, _STR_DEF_BGM_PATH}}}, + {UI_SPACER}, + {UI_STRING, CFG_DEFAULT_BGM_PATH, 1, 1, _STR_DEF_BGM_PATH_HINT, 0, 0, {.stringvalue = {"", "", NULL}}}, + {UI_BREAK}, + // buttons {UI_OK, 0, 1, 1, -1, 0, 0, {.label = {NULL, _STR_OK}}}, {UI_BREAK}, diff --git a/src/gui.c b/src/gui.c index 2a6b1dd41..41accc9d0 100644 --- a/src/gui.c +++ b/src/gui.c @@ -622,9 +622,11 @@ void guiShowUIConfig(void) , NULL}; // clang-format on int previousVMode; + int previousTheme; reselect_video_mode: previousVMode = gVMode; + previousTheme = thmGetGuiValue(); diaSetEnum(diaUIConfig, UICFG_THEME, (const char **)thmGetGuiList()); diaSetEnum(diaUIConfig, UICFG_LANG, (const char **)lngGetGuiList()); diaSetEnum(diaUIConfig, UICFG_VMODE, vmodeNames); @@ -664,8 +666,14 @@ void guiShowUIConfig(void) if (ret == UICFG_RESETCOL) setDefaultColors(); + if (previousTheme != themeID && isBgmPlaying()) + bgmStop(); + applyConfig(themeID, langID); sfxInit(0); + + if (gEnableBGM && !isBgmPlaying()) + bgmStart(); } if (previousVMode != gVMode) { @@ -828,9 +836,15 @@ static void guiSetAudioSettingsState(void) { diaGetInt(diaAudioConfig, CFG_SFX, &gEnableSFX); diaGetInt(diaAudioConfig, CFG_BOOT_SND, &gEnableBootSND); + diaGetInt(diaAudioConfig, CFG_BGM, &gEnableBGM); diaGetInt(diaAudioConfig, CFG_SFX_VOLUME, &gSFXVolume); diaGetInt(diaAudioConfig, CFG_BOOT_SND_VOLUME, &gBootSndVolume); - sfxVolume(); + diaGetInt(diaAudioConfig, CFG_BGM_VOLUME, &gBGMVolume); + diaGetString(diaAudioConfig, CFG_DEFAULT_BGM_PATH, gDefaultBGMPath, sizeof(gDefaultBGMPath)); + audioSetVolume(); + + if (gEnableBGM && !isBgmPlaying()) + bgmStart(); } static int guiAudioUpdater(int modified) @@ -846,8 +860,11 @@ void guiShowAudioConfig(void) { diaSetInt(diaAudioConfig, CFG_SFX, gEnableSFX); diaSetInt(diaAudioConfig, CFG_BOOT_SND, gEnableBootSND); + diaSetInt(diaAudioConfig, CFG_BGM, gEnableBGM); diaSetInt(diaAudioConfig, CFG_SFX_VOLUME, gSFXVolume); diaSetInt(diaAudioConfig, CFG_BOOT_SND_VOLUME, gBootSndVolume); + diaSetInt(diaAudioConfig, CFG_BGM_VOLUME, gBGMVolume); + diaSetString(diaAudioConfig, CFG_DEFAULT_BGM_PATH, gDefaultBGMPath); diaExecuteDialog(diaAudioConfig, -1, 1, guiAudioUpdater); } @@ -1494,6 +1511,9 @@ void guiMainLoop(void) if (gOPLPart[0] != '\0') showPartPopup = 1; + if (gEnableBGM) + bgmStart(); + while (!gTerminate) { guiStartFrame(); diff --git a/src/opl.c b/src/opl.c index d0a651132..43616d2e4 100644 --- a/src/opl.c +++ b/src/opl.c @@ -162,8 +162,11 @@ int gSelectButton; int gHDDGameListCache; int gEnableSFX; int gEnableBootSND; +int gEnableBGM; int gSFXVolume; int gBootSndVolume; +int gBGMVolume; +char gDefaultBGMPath[128]; int gCheatSource; int gGSMSource; int gPadEmuSource; @@ -881,8 +884,11 @@ static void _loadConfig() configGetInt(configOPL, CONFIG_OPL_ENABLE_MX4SIO, &gEnableMX4SIO); configGetInt(configOPL, CONFIG_OPL_SFX, &gEnableSFX); configGetInt(configOPL, CONFIG_OPL_BOOT_SND, &gEnableBootSND); + configGetInt(configOPL, CONFIG_OPL_BGM, &gEnableBGM); configGetInt(configOPL, CONFIG_OPL_SFX_VOLUME, &gSFXVolume); configGetInt(configOPL, CONFIG_OPL_BOOT_SND_VOLUME, &gBootSndVolume); + configGetInt(configOPL, CONFIG_OPL_BGM_VOLUME, &gBGMVolume); + configGetStrCopy(configOPL, CONFIG_OPL_DEFAULT_BGM_PATH, gDefaultBGMPath, sizeof(gDefaultBGMPath)); } } @@ -1037,8 +1043,11 @@ static void _saveConfig() configSetInt(configOPL, CONFIG_OPL_ENABLE_MX4SIO, gEnableMX4SIO); configSetInt(configOPL, CONFIG_OPL_SFX, gEnableSFX); configSetInt(configOPL, CONFIG_OPL_BOOT_SND, gEnableBootSND); + configSetInt(configOPL, CONFIG_OPL_BGM, gEnableBGM); configSetInt(configOPL, CONFIG_OPL_SFX_VOLUME, gSFXVolume); configSetInt(configOPL, CONFIG_OPL_BOOT_SND_VOLUME, gBootSndVolume); + configSetInt(configOPL, CONFIG_OPL_BGM_VOLUME, gBGMVolume); + configSetStr(configOPL, CONFIG_OPL_DEFAULT_BGM_PATH, gDefaultBGMPath); configSetInt(configOPL, CONFIG_OPL_SWAP_SEL_BUTTON, gSelectButton == KEY_CIRCLE ? 0 : 1); } @@ -1407,7 +1416,7 @@ static int loadLwnbdSvr(void) int ret, padStatus; // deint audio lib while nbd server is running - sfxEnd(); + audioEnd(); // block all io ops, wait for the ones still running to finish ioBlockOps(1); @@ -1466,8 +1475,10 @@ static void unloadLwnbdSvr(void) // init all supports again initAllSupport(1); - // deferred reinit of audio lib to avoid crashing if devices aren't ready - ioPutRequest(IO_CUSTOM_SIMPLEACTION, &deferredAudioInit); + audioInit(); + sfxInit(0); + if (gEnableBGM) + bgmStart(); } void handleLwnbdSrv() @@ -1528,7 +1539,7 @@ void deinit(int exception, int modeSelected) deinitAllSupport(exception, modeSelected); - sfxEnd(); + audioEnd(); ioEnd(); guiEnd(); menuEnd(); @@ -1622,8 +1633,11 @@ static void setDefaults(void) gWideScreen = 0; gEnableSFX = 0; gEnableBootSND = 0; + gEnableBGM = 0; gSFXVolume = 80; gBootSndVolume = 80; + gBGMVolume = 70; + gDefaultBGMPath[0] = '\0'; gBDMStartMode = START_MODE_DISABLED; gHDDStartMode = START_MODE_DISABLED; @@ -1700,6 +1714,7 @@ static void deferredAudioInit(void) { int ret; + audioInit(); ret = sfxInit(1); if (ret < 0) LOG("sfxInit: failed to initialize - %d.\n", ret); diff --git a/src/sound.c b/src/sound.c index 43cfb3a90..b01f6a8df 100644 --- a/src/sound.c +++ b/src/sound.c @@ -1,13 +1,20 @@ -/*-- Theme Sound Effects ---------------------------------------------------------------------------------------------- ----- SP193 wrote the code, I just made small changes. ---------------------------------------------------------------*/ +/* + Copyright 2022, Thanks to SP193 + Licenced under Academic Free License version 3.0 + Review OpenPS2Loader README & LICENSE files for further details. + */ #include +#include + #include "include/sound.h" #include "include/opl.h" #include "include/ioman.h" #include "include/themes.h" -// default sfx +/*-- Theme Sound Effects ---------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------------*/ + extern unsigned char boot_adp[]; extern unsigned int size_boot_adp; @@ -45,7 +52,7 @@ static struct sfxEffect sfx_files[SFX_COUNT] = { }; static struct audsrv_adpcm_t sfx[SFX_COUNT]; -static int sfx_initialized = 0; +static int audio_initialized = 0; // Returns 0 if the specified file was read. The sfxEffect structure will not be updated unless the file is successfully read. static int sfxRead(const char *full_path, struct sfxEffect *sfx) @@ -138,22 +145,6 @@ static int sfxLoad(struct sfxEffect *sfxData, audsrv_adpcm_t *sfx) return ret; } -void sfxVolume(void) -{ - int i; - - if (!sfx_initialized) { - LOG("SFX: %s: ERROR: not initialized!\n", __FUNCTION__); - return; - } - - for (i = 1; i < SFX_COUNT; i++) { - audsrv_adpcm_set_volume(i, gSFXVolume); - } - - audsrv_adpcm_set_volume(0, gBootSndVolume); -} - // Returns number of audio files successfully loaded, < 0 if an unrecoverable error occurred. int sfxInit(int bootSnd) { @@ -163,19 +154,14 @@ int sfxInit(int bootSnd) int thmSfxEnabled = 0; int i = 1; - if (!sfx_initialized) { - if (audsrv_init() != 0) { - LOG("SFX: Failed to initialize audsrv\n"); - LOG("SFX: Audsrv returned error string: %s\n", audsrv_get_error_string()); - return -1; - } - sfx_initialized = 1; + if (!audio_initialized) { + LOG("SFX: %s: ERROR: not initialized!\n", __FUNCTION__); + return -1; } audsrv_adpcm_init(); - sfxInitDefaults(); - sfxVolume(); + audioSetVolume(); // Check default theme is not current theme int themeID = thmGetGuiValue(); @@ -216,20 +202,9 @@ int sfxInit(int bootSnd) return loaded; } -void sfxEnd() -{ - if (!sfx_initialized) { - LOG("SFX: %s: ERROR: not initialized!\n", __FUNCTION__); - return; - } - - audsrv_quit(); - sfx_initialized = 0; -} - int sfxGetSoundDuration(int id) { - if (!sfx_initialized) { + if (!audio_initialized) { LOG("SFX: %s: ERROR: not initialized!\n", __FUNCTION__); return 0; } @@ -239,7 +214,7 @@ int sfxGetSoundDuration(int id) void sfxPlay(int id) { - if (!sfx_initialized) { + if (!audio_initialized) { LOG("SFX: %s: ERROR: not initialized!\n", __FUNCTION__); return; } @@ -248,3 +223,319 @@ void sfxPlay(int id) audsrv_ch_play_adpcm(id, &sfx[id]); } } + +/*-- Theme Background Music ------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------------------------*/ + +#define BGM_RING_BUFFER_COUNT 16 +#define BGM_RING_BUFFER_SIZE 4096 +#define BGM_THREAD_BASE_PRIO 0x40 +#define BGM_THREAD_STACK_SIZE 0x1000 + +extern void *_gp; + +static int bgmThreadID, bgmIoThreadID; +static int outSema, inSema; +static unsigned char terminateFlag, bgmIsPlaying; +static unsigned char rdPtr, wrPtr; +static char bgmBuffer[BGM_RING_BUFFER_COUNT][BGM_RING_BUFFER_SIZE]; +static volatile unsigned char bgmThreadRunning, bgmIoThreadRunning; + +static u8 bgmThreadStack[BGM_THREAD_STACK_SIZE] __attribute__((aligned(16))); +static u8 bgmIoThreadStack[BGM_THREAD_STACK_SIZE] __attribute__((aligned(16))); + +static OggVorbis_File *vorbisFile; + +static void bgmThread(void *arg) +{ + bgmThreadRunning = 1; + + while (!terminateFlag) { + SleepThread(); + + while (PollSema(outSema) == outSema) { + audsrv_wait_audio(BGM_RING_BUFFER_SIZE); + audsrv_play_audio(bgmBuffer[rdPtr], BGM_RING_BUFFER_SIZE); + rdPtr = (rdPtr + 1) % BGM_RING_BUFFER_COUNT; + + SignalSema(inSema); + } + } + + audsrv_stop_audio(); + + rdPtr = 0; + wrPtr = 0; + + bgmThreadRunning = 0; + bgmIsPlaying = 0; +} + +static void bgmIoThread(void *arg) +{ + int partsToRead, decodeTotal, bitStream, i; + + bgmIoThreadRunning = 1; + do { + WaitSema(inSema); + partsToRead = 1; + + while ((wrPtr + partsToRead < BGM_RING_BUFFER_COUNT) && (PollSema(inSema) == inSema)) + partsToRead++; + + decodeTotal = BGM_RING_BUFFER_SIZE; + int bufferPtr = 0; + do { + int ret = ov_read(vorbisFile, bgmBuffer[wrPtr] + bufferPtr, decodeTotal, 0, 2, 1, &bitStream); + if (ret > 0) { + bufferPtr += ret; + decodeTotal -= ret; + } else if (ret < 0) { + LOG("BGM: I/O error while reading.\n"); + terminateFlag = 1; + break; + } else if (ret == 0) + ov_pcm_seek(vorbisFile, 0); + } while (decodeTotal > 0); + + wrPtr = (wrPtr + partsToRead) % BGM_RING_BUFFER_COUNT; + for (i = 0; i < partsToRead; i++) + SignalSema(outSema); + WakeupThread(bgmThreadID); + } while (!terminateFlag && gEnableBGM); + + bgmIoThreadRunning = 0; + terminateFlag = 1; + WakeupThread(bgmThreadID); +} + +static int bgmLoad(void) +{ + FILE *bgmFile; + char bgmPath[256]; + + vorbisFile = malloc(sizeof(OggVorbis_File)); + memset(vorbisFile, 0, sizeof(OggVorbis_File)); + + int themeID = thmGetGuiValue(); + if (themeID != 0) { + char *thmPath = thmGetFilePath(themeID); + snprintf(bgmPath, sizeof(bgmPath), "%ssound/bgm.ogg", thmPath); + } else + snprintf(bgmPath, sizeof(bgmPath), gDefaultBGMPath); + + bgmFile = fopen(bgmPath, "rb"); + if (bgmFile == NULL) { + LOG("BGM: Failed to open Ogg file %s\n", bgmPath); + return -ENOENT; + } + + if (ov_open_callbacks(bgmFile, vorbisFile, NULL, 0, OV_CALLBACKS_DEFAULT) < 0) { + LOG("BGM: Input does not appear to be an Ogg bitstream.\n"); + return -ENOENT; + } + + return 0; +} + +static int bgmInit(void) +{ + ee_thread_t thread; + ee_sema_t sema; + int result; + + terminateFlag = 0; + rdPtr = 0; + wrPtr = 0; + bgmThreadRunning = 0; + bgmIoThreadRunning = 0; + + sema.max_count = BGM_RING_BUFFER_COUNT; + sema.init_count = BGM_RING_BUFFER_COUNT; + sema.attr = 0; + sema.option = (u32) "bgm-in-sema"; + inSema = CreateSema(&sema); + + if (inSema >= 0) { + sema.max_count = BGM_RING_BUFFER_COUNT; + sema.init_count = 0; + sema.attr = 0; + sema.option = (u32) "bgm-out-sema"; + outSema = CreateSema(&sema); + + if (outSema < 0) { + DeleteSema(inSema); + return outSema; + } + } else + return inSema; + + thread.func = &bgmThread; + thread.stack = bgmThreadStack; + thread.stack_size = sizeof(bgmThreadStack); + thread.gp_reg = &_gp; + thread.initial_priority = BGM_THREAD_BASE_PRIO; + thread.attr = 0; + thread.option = 0; + + // BGM thread will start in DORMANT state. + bgmThreadID = CreateThread(&thread); + + if (bgmThreadID >= 0) { + thread.func = &bgmIoThread; + thread.stack = bgmIoThreadStack; + thread.stack_size = sizeof(bgmIoThreadStack); + thread.gp_reg = &_gp; + thread.initial_priority = BGM_THREAD_BASE_PRIO + 1; + thread.attr = 0; + thread.option = 0; + + // BGM I/O thread will start in DORMANT state. + bgmIoThreadID = CreateThread(&thread); + if (bgmIoThreadID >= 0) { + result = 0; + } else { + DeleteSema(inSema); + DeleteSema(outSema); + DeleteThread(bgmThreadID); + result = bgmIoThreadID; + } + } else { + result = bgmThreadID; + DeleteSema(inSema); + DeleteSema(outSema); + } + + return result; +} + +static void bgmDeinit(void) +{ + DeleteSema(inSema); + DeleteSema(outSema); + DeleteThread(bgmThreadID); + DeleteThread(bgmIoThreadID); + + // Vorbisfile takes care of fclose. + ov_clear(vorbisFile); + free(vorbisFile); + vorbisFile = NULL; +} + +static void bgmShutdownDelayCallback(s32 alarm_id, u16 time, void *common) +{ + iWakeupThread((int)common); +} + +void bgmStart(void) +{ + struct audsrv_fmt_t audsrvFmt; + + if (!audio_initialized) { + LOG("BGM: %s: ERROR: not initialized!\n", __FUNCTION__); + return; + } + + int ret = bgmInit(); + if (ret >= 0) { + if (bgmLoad() != 0) { + bgmDeinit(); + return; + } + + vorbis_info *vi = ov_info(vorbisFile, -1); + ov_pcm_seek(vorbisFile, 0); + + audsrvFmt.channels = vi->channels; + audsrvFmt.freq = vi->rate; + audsrvFmt.bits = 16; + + audsrv_set_format(&audsrvFmt); + + bgmIsPlaying = 1; + + StartThread(bgmIoThreadID, NULL); + StartThread(bgmThreadID, NULL); + } +} + +void bgmStop(void) +{ + int threadId; + + if (!audio_initialized) { + LOG("BGM: %s: ERROR: not initialized!\n", __FUNCTION__); + return; + } + + LOG("BGM: terminating threads...\n"); + + terminateFlag = 1; + WakeupThread(bgmThreadID); + + threadId = GetThreadId(); + while (bgmIoThreadRunning) { + SetAlarm(200 * 16, &bgmShutdownDelayCallback, (void *)threadId); + SleepThread(); + } + while (bgmThreadRunning) { + SetAlarm(200 * 16, &bgmShutdownDelayCallback, (void *)threadId); + SleepThread(); + } + + bgmDeinit(); + + LOG("BGM: stopped.\n"); +} + +int isBgmPlaying(void) +{ + int ret = (int)bgmIsPlaying; + + return ret; +} + +/*-- General Audio ------------------------------------------------------------------------------------------------------ +-----------------------------------------------------------------------------------------------------------------------------*/ + +void audioInit(void) +{ + if (!audio_initialized) { + if (audsrv_init() != 0) { + LOG("AUDIO: Failed to initialize audsrv\n"); + LOG("AUDIO: Audsrv returned error string: %s\n", audsrv_get_error_string()); + return; + } + audio_initialized = 1; + } +} + +void audioEnd(void) +{ + if (!audio_initialized) { + LOG("AUDIO: %s: ERROR: not initialized!\n", __FUNCTION__); + return; + } + + if (gEnableBGM && isBgmPlaying()) + bgmStop(); + + audsrv_quit(); + audio_initialized = 0; +} + +void audioSetVolume(void) +{ + int i; + + if (!audio_initialized) { + LOG("AUDIO: %s: ERROR: not initialized!\n", __FUNCTION__); + return; + } + + for (i = 1; i < SFX_COUNT; i++) + audsrv_adpcm_set_volume(i, gSFXVolume); + + audsrv_adpcm_set_volume(0, gBootSndVolume); + audsrv_set_volume(gBGMVolume); +}