From dde697d3b4eeb69f5e02e6f09f2f1dea69ff13f1 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 5 Jan 2025 11:34:11 +0900 Subject: [PATCH] Implement S3xMusic HLL Used in Ore no Shita de Agake. Since the musbgm_* interface does not allow multiple channels, this implementation uses musbgm_* for channel 0 and muspcm_* for channel 1. --- modules/CMakeLists.txt | 1 + modules/NightDemonDemo/NightDemonDemo.c | 2 +- modules/S3xMusic/S3xMusic.c | 238 ++++++++++++++++++++++++ modules/SACT/SACT.c | 2 +- modules/modules.c | 1 + modules/modules.h | 1 + modules/tDemo/tDemo.c | 2 +- src/bgm.emscripten.c | 4 +- src/bgm.h | 2 +- src/bgm.sdlmixer.c | 4 +- src/cdrom.bgm.c | 2 +- src/music_pcm.h | 1 + src/pcm.emscripten.c | 4 + src/pcm.sdlmixer.c | 23 ++- 14 files changed, 273 insertions(+), 14 deletions(-) create mode 100644 modules/S3xMusic/S3xMusic.c diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 3987ead..20d5230 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -23,6 +23,7 @@ add_library(modules STATIC NIGHTDLL/nt_sound.c NightDemonDemo/NightDemonDemo.c RandMT/RandMT.c + S3xMusic/S3xMusic.c SACT/SACT.c SACT/sactcg.c SACT/sactsound.c diff --git a/modules/NightDemonDemo/NightDemonDemo.c b/modules/NightDemonDemo/NightDemonDemo.c index b330483..1ca391d 100644 --- a/modules/NightDemonDemo/NightDemonDemo.c +++ b/modules/NightDemonDemo/NightDemonDemo.c @@ -51,7 +51,7 @@ static void ndd_run(int demonum) { int mus = ndemo_mus[demonum]; if (mus) - musbgm_play(mus, 0, 100); + musbgm_play(mus, 0, 100, 0); uint32_t start = sdl_getTicks(); while (!nact->is_quit) { diff --git a/modules/S3xMusic/S3xMusic.c b/modules/S3xMusic/S3xMusic.c new file mode 100644 index 0000000..cc25cf6 --- /dev/null +++ b/modules/S3xMusic/S3xMusic.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2025 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "config.h" +#include "modules.h" +#include "nact.h" +#include "bgm.h" +#include "music.h" +#include "music_pcm.h" + +#define SLOT 128 + +static int current_no = 0; + +static void Init(void) { + int isys3x = getCaliValue(); + TRACE("S3xMusic.Init %d:", isys3x); +} + +static void CreateChannel(void) { + int nr_channels = getCaliValue(); + if (nr_channels != 2) + SYSERROR("Unsupported number of channels: %d", nr_channels); + TRACE("S3xMusic.CreateChannel %d:", nr_channels); +} + +static void Prepare(void) { + int ch = getCaliValue(); + int no = getCaliValue(); + int *result = getCaliVariable(); + + if (ch == 0) { + current_no = no; + *result = 1; + } else { + *result = muspcm_load_bgm(SLOT, no) == OK; + } + TRACE("S3xMusic.Prepare %d, %d => %d:", ch, no, *result); +} + +static void Unprepare(void) { + int ch = getCaliValue(); + + if (ch == 0) { + if (current_no) { + musbgm_stop(current_no, 0); + current_no = 0; + } + } else { + muspcm_unload(SLOT); + } + TRACE("S3xMusic.Unprepare %d:", ch); +} + +static void Play(void) { + int p1 = getCaliValue(); + int p2 = getCaliValue(); + TRACE_UNIMPLEMENTED("S3xMusic.Play %d, %d:", p1, p2); +} + +static void FadePlay(void) { + int ch = getCaliValue(); + int fadein_time = getCaliValue(); + int volume = getCaliValue(); + int loop_count = getCaliValue(); // 0 = infinite + + if (ch == 0) { + musbgm_play(current_no, fadein_time, volume, loop_count); + } else { + muspcm_start(SLOT, loop_count == 0 ? -1 : loop_count); + } + TRACE("S3xMusic.FadePlay %d, %d, %d, %d:", ch, fadein_time, volume, loop_count); +} + +static void PlayPosSample(void) { + int p1 = getCaliValue(); + int p2 = getCaliValue(); + int p3 = getCaliValue(); + int p4 = getCaliValue(); + TRACE_UNIMPLEMENTED("S3xMusic.PlayPosSample %d, %d, %d, %d:", p1, p2, p3, p4); +} + +static void IsPlay(void) { + int ch = getCaliValue(); + int *result = getCaliVariable(); + + if (ch == 0) { + *result = current_no && musbgm_isplaying(current_no); + } else { + *result = muspcm_isplaying(SLOT); + } + TRACE("S3xMusic.IsPlay %d => %d:", ch, *result); +} + +static void Stop(void) { + int ch = getCaliValue(); + + if (ch == 0) { + if (current_no) + musbgm_stop(current_no, 0); + current_no = 0; + } else { + muspcm_stop(SLOT); + } + TRACE("S3xMusic.Stop %d:", ch); +} + +static void Restart(void) { + int p1 = getCaliValue(); + TRACE_UNIMPLEMENTED("S3xMusic.Restart %d:", p1); +} + +static void GetPlayPos(void) { + int ch = getCaliValue(); + int *hour = getCaliVariable(); + int *min = getCaliVariable(); + int *sec = getCaliVariable(); + int *msec = getCaliVariable(); + if (ch == 0) { + int time = musbgm_getpos(current_no); + *hour = time / 360000; + *min = (time / 6000) % 60; + *sec = (time / 100) % 60; + *msec = (time % 100) * 10; + } else { + // not implemented + *hour = 0; + *min = 0; + *sec = 0; + *msec = 0; + } + TRACE("S3xMusic.GetPlayPos %d => %d, %d, %d, %d:", ch, *hour, *min, *sec, *msec); +} + +static void GetPlayPosSample(void) { + int p1 = getCaliValue(); + int *var1 = getCaliVariable(); + int *var2 = getCaliVariable(); + TRACE_UNIMPLEMENTED("S3xMusic.GetPlayPosSample %d, %p, %p:", p1, var1, var2); +} + +static void SetRepeatStart(void) { + int p1 = getCaliValue(); + int p2 = getCaliValue(); + int p3 = getCaliValue(); + TRACE_UNIMPLEMENTED("S3xMusic.SetRepeatStart %d, %d, %d:", p1, p2, p3); +} + +static void SetRepeatEnd(void) { + int p1 = getCaliValue(); + int p2 = getCaliValue(); + int p3 = getCaliValue(); + TRACE_UNIMPLEMENTED("S3xMusic.SetRepeatEnd %d, %d, %d:", p1, p2, p3); +} + +static void FadeVolume(void) { + int ch = getCaliValue(); + int time = getCaliValue(); + int volume = getCaliValue(); + int stop_after_fade = getCaliValue(); + + if (ch == 0) { + if (stop_after_fade) { + musbgm_stop(current_no, time / 10); + } else { + musbgm_fade(current_no, time / 10, volume); + } + } else { + if (stop_after_fade) { + muspcm_fadeout(SLOT, time); + } else { + muspcm_setvol(SLOT, volume); + } + } + TRACE("S3xMusic.FadeVolume %d, %d, %d, %d:", ch, time, volume, stop_after_fade); +} + +static void IsFade(void) { + int ch = getCaliValue(); + int *result = getCaliVariable(); + *result = 0; + TRACE_UNIMPLEMENTED("S3xMusic.IsFade %d => %d:", ch, *result); +} + +static void StopFade(void) { + int ch = getCaliValue(); + TRACE_UNIMPLEMENTED("S3xMusic.StopFade %d:", ch); +} + +static void WaitEnd(void) { + int p1 = getCaliValue(); + int p2 = getCaliValue(); // IWinMsg + TRACE_UNIMPLEMENTED("S3xMusic.WaitEnd %d, %d:", p1, p2); +} + +static void sleep(void) { + int p1 = getCaliValue(); // IWinMsg + TRACE_UNIMPLEMENTED("S3xMusic.sleep %d:", p1); +} + +static const ModuleFunc functions[] = { + {"CreateChannel", CreateChannel}, + {"FadePlay", FadePlay}, + {"FadeVolume", FadeVolume}, + {"GetPlayPos", GetPlayPos}, + {"GetPlayPosSample", GetPlayPosSample}, + {"Init", Init}, + {"IsFade", IsFade}, + {"IsPlay", IsPlay}, + {"Play", Play}, + {"PlayPosSample", PlayPosSample}, + {"Prepare", Prepare}, + {"Restart", Restart}, + {"SetRepeatEnd", SetRepeatEnd}, + {"SetRepeatStart", SetRepeatStart}, + {"Stop", Stop}, + {"StopFade", StopFade}, + {"Unprepare", Unprepare}, + {"WaitEnd", WaitEnd}, + {"sleep", sleep}, +}; + +const Module module_S3xMusic = {"S3xMusic", functions, sizeof(functions) / sizeof(ModuleFunc)}; diff --git a/modules/SACT/SACT.c b/modules/SACT/SACT.c index 9229fe0..510ebe6 100644 --- a/modules/SACT/SACT.c +++ b/modules/SACT/SACT.c @@ -1838,7 +1838,7 @@ static void MusicPlay() { int wFadeTime = getCaliValue(); int wVolume = getCaliValue(); - musbgm_play(wNum, wFadeTime, wVolume); + musbgm_play(wNum, wFadeTime, wVolume, 0); TRACE("SACT.MusicPlay %d,%d,%d:", wNum, wFadeTime, wVolume); } diff --git a/modules/modules.c b/modules/modules.c index c302686..8c47dbb 100644 --- a/modules/modules.c +++ b/modules/modules.c @@ -35,6 +35,7 @@ static const Module *modules[] = { &module_NIGHTDLL, &module_NightDemonDemo, &module_RandMT, + &module_S3xMusic, &module_SACT, &module_ShArray, &module_ShCalc, diff --git a/modules/modules.h b/modules/modules.h index 1452b3b..e6d6245 100644 --- a/modules/modules.h +++ b/modules/modules.h @@ -42,6 +42,7 @@ extern const Module module_MsgSkip; extern const Module module_NIGHTDLL; extern const Module module_NightDemonDemo; extern const Module module_RandMT; +extern const Module module_S3xMusic; extern const Module module_SACT; extern const Module module_ShArray; extern const Module module_ShCalc; diff --git a/modules/tDemo/tDemo.c b/modules/tDemo/tDemo.c index 689093d..fb2b33a 100644 --- a/modules/tDemo/tDemo.c +++ b/modules/tDemo/tDemo.c @@ -71,7 +71,7 @@ static void Run() { while (sys_getInputInfo()); // wait for key up - musbgm_play(TDEMO_MUSIC_NO, 0, 100); + musbgm_play(TDEMO_MUSIC_NO, 0, 100, 0); uint32_t start = sdl_getTicks(); while (!nact->is_quit) { diff --git a/src/bgm.emscripten.c b/src/bgm.emscripten.c index b998530..d0d3647 100644 --- a/src/bgm.emscripten.c +++ b/src/bgm.emscripten.c @@ -44,9 +44,9 @@ int musbgm_reset(void) { return OK; } -EM_JS(int, musbgm_play, (int no, int time, int vol), { +EM_JS(int, musbgm_play, (int no, int time, int vol, int loop_count), { xsystem35.cdPlayer.fade(time * 10, vol / 100); - xsystem35.cdPlayer.play(no, 1); + xsystem35.cdPlayer.play(no, loop_count == 0); return xsystem35.Status.OK; }); diff --git a/src/bgm.h b/src/bgm.h index ca8df3a..3c85df9 100644 --- a/src/bgm.h +++ b/src/bgm.h @@ -24,7 +24,7 @@ int musbgm_init(DRIFILETYPE type, int base_no); int musbgm_exit(void); int musbgm_reset(void); -int musbgm_play(int no, int time, int vol); +int musbgm_play(int no, int time, int vol, int loop_count); int musbgm_stop(int no, int time); int musbgm_fade(int no, int time, int vol); int musbgm_getpos(int no); diff --git a/src/bgm.sdlmixer.c b/src/bgm.sdlmixer.c index cc264a2..a62b7b7 100644 --- a/src/bgm.sdlmixer.c +++ b/src/bgm.sdlmixer.c @@ -96,7 +96,7 @@ int musbgm_reset(void) { return OK; } -int musbgm_play(int no, int time, int vol) { +int musbgm_play(int no, int time, int vol, int loop_count) { if (current_no) musbgm_stop(current_no, 0); @@ -107,7 +107,7 @@ int musbgm_play(int no, int time, int vol) { // understands loop info in the WAVE's "smpl" chunk. Mix_VolumeMusic(vol * MIX_MAX_VOLUME / 100); - if (Mix_FadeInMusic(mix_music, -1, time * 10) != 0) { + if (Mix_FadeInMusic(mix_music, loop_count == 0 ? -1 : loop_count, time * 10) != 0) { free_music(); return NG; } diff --git a/src/cdrom.bgm.c b/src/cdrom.bgm.c index e2b5457..5afc324 100644 --- a/src/cdrom.bgm.c +++ b/src/cdrom.bgm.c @@ -42,7 +42,7 @@ static int cdrom_bgm_reset(void) { } static int cdrom_bgm_start(int trk, int loop) { - if (musbgm_play(trk, 0, 100) != OK) + if (musbgm_play(trk, 0, 100, loop) != OK) return NG; current_track = trk; return OK; diff --git a/src/music_pcm.h b/src/music_pcm.h index 2f9547d..92b55b9 100644 --- a/src/music_pcm.h +++ b/src/music_pcm.h @@ -28,6 +28,7 @@ extern int muspcm_init(int audio_buffer_size); extern int muspcm_exit(void); extern int muspcm_reset(void); extern int muspcm_load_no(int slot, int no); +extern int muspcm_load_bgm(int slot, int no); extern int muspcm_load_mixlr(int slot, int noL, int noR); extern int muspcm_load_data(int slot, uint8_t *buf, uint32_t len); extern int muspcm_unload(int slot); diff --git a/src/pcm.emscripten.c b/src/pcm.emscripten.c index ec10778..4da1787 100644 --- a/src/pcm.emscripten.c +++ b/src/pcm.emscripten.c @@ -40,6 +40,10 @@ EM_ASYNC_JS(int, muspcm_load_no, (int slot, int no), { return await xsystem35.audio.pcm_load(slot, no); }); +EM_ASYNC_JS(int, muspcm_load_bgm, (int slot, int no), { + return await xsystem35.audio.pcm_load_bgm(slot, no); +}); + EM_ASYNC_JS(int, muspcm_load_data, (int slot, uint8_t *buf, uint32_t len), { return await xsystem35.audio.pcm_load_data(slot, buf, len); }); diff --git a/src/pcm.sdlmixer.c b/src/pcm.sdlmixer.c index a9e2ad6..c76b982 100644 --- a/src/pcm.sdlmixer.c +++ b/src/pcm.sdlmixer.c @@ -62,8 +62,8 @@ static mmap_t *wai_map; * 指定の番号の .WAV|.OGG をロードする。 * @param no: DRIファイル番号 */ -static Mix_Chunk *load_asset(int no) { - dridata *dfile = ald_getdata(DRIFILE_WAVE, no -1); +static Mix_Chunk *load_asset(DRIFILETYPE type, int no) { + dridata *dfile = ald_getdata(type, no -1); if (dfile == NULL) { WARNING("DRIFILE_WAVE fail to open %d", no -1); return NULL; @@ -99,8 +99,8 @@ static int load_chunk(int slot, Mix_Chunk *chunk) { * @return : 合成後の Mix_Chunk */ static Mix_Chunk *pcm_mixlr(int noL, int noR) { - Mix_Chunk *chunkL = load_asset(noL); - Mix_Chunk *chunkR = load_asset(noR); + Mix_Chunk *chunkL = load_asset(DRIFILE_WAVE, noL); + Mix_Chunk *chunkR = load_asset(DRIFILE_WAVE, noR); if (chunkL == NULL || chunkR == NULL) { if (chunkL) Mix_FreeChunk(chunkL); @@ -163,7 +163,7 @@ int muspcm_load_no(int slot, int no) { if ((unsigned)slot >= PCM_SLOTS) return NG; - Mix_Chunk *chunk = load_asset(no); + Mix_Chunk *chunk = load_asset(DRIFILE_WAVE, no); if (chunk == NULL) { return NG; } @@ -179,6 +179,19 @@ int muspcm_load_no(int slot, int no) { return load_chunk(slot, chunk); } +int muspcm_load_bgm(int slot, int no) { + if ((unsigned)slot >= PCM_SLOTS) + return NG; + + Mix_Chunk *chunk = load_asset(DRIFILE_BGM, no); + if (chunk == NULL) { + return NG; + } + prv.vol_pcm_sub[slot] = 0; + + return load_chunk(slot, chunk); +} + int muspcm_load_mixlr(int slot, int noL, int noR) { if ((unsigned)slot >= PCM_SLOTS) return NG;