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.
This commit is contained in:
kichikuou
2025-01-07 15:41:43 +09:00
parent c4d4f85ae4
commit dde697d3b4
14 changed files with 273 additions and 14 deletions
+1
View File
@@ -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
+1 -1
View File
@@ -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) {
+238
View File
@@ -0,0 +1,238 @@
/*
* Copyright (C) 2025 <KichikuouChrome@gmail.com>
*
* 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)};
+1 -1
View File
@@ -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);
}
+1
View File
@@ -35,6 +35,7 @@ static const Module *modules[] = {
&module_NIGHTDLL,
&module_NightDemonDemo,
&module_RandMT,
&module_S3xMusic,
&module_SACT,
&module_ShArray,
&module_ShCalc,
+1
View File
@@ -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;
+1 -1
View File
@@ -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) {
+2 -2
View File
@@ -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;
});
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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;
}
+1 -1
View File
@@ -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;
+1
View File
@@ -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);
+4
View File
@@ -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);
});
+18 -5
View File
@@ -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;