From f725e4e83055f645fbf8496547284f39ce96691e Mon Sep 17 00:00:00 2001 From: kichikuou Date: Fri, 25 Mar 2022 09:55:59 +0900 Subject: [PATCH] Implement ChrLoader.LoadWavFile --- include/audio.h | 5 +++ include/mixer.h | 3 ++ src/audio.c | 15 +++++++++ src/audio_mixer.c | 74 ++++++++++++++++++++++++++------------------- src/hll/ChrLoader.c | 33 +++++++++++++++++++- 5 files changed, 98 insertions(+), 32 deletions(-) diff --git a/include/audio.h b/include/audio.h index 307f943..e84fd52 100644 --- a/include/audio.h +++ b/include/audio.h @@ -79,4 +79,9 @@ int bgm_get_time_length(int id); //int wav_prepare_from_file(int id, char *filename); //int bgm_prepare_from_file(int id, char *filename); +struct archive_data; + +// Takes ownership of dfile. +int wav_prepare_from_archive_data(int id, struct archive_data *dfile); + #endif /* SYSTEM4_AUDIO_H */ diff --git a/include/mixer.h b/include/mixer.h index 3889e77..c647587 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -48,10 +48,13 @@ int mixer_set_volume(int n, int volume); int mixer_get_mute(int n, int *mute); int mixer_set_mute(int n, int mute); +struct archive_data; struct channel; enum asset_type; struct channel *channel_open(enum asset_type type, int no); +// Takes ownership of dfile. +struct channel *channel_open_archive_data(struct archive_data *dfile); void channel_close(struct channel *ch); int channel_play(struct channel *ch); int channel_stop(struct channel *ch); diff --git a/src/audio.c b/src/audio.c index 9a45183..5b5fc9c 100644 --- a/src/audio.c +++ b/src/audio.c @@ -329,3 +329,18 @@ int bgm_get_time_length(int id) { return audio_get_time_length(&bgm, id); } //int bgm_get_group_num(int channel); //int wav_prepare_from_file(int channel, char *filename); //int bgm_prepare_from_file(int channel, char *filename); + +static int audio_prepare_from_archive_data(struct id_pool *pool, int id, struct archive_data *dfile) +{ + if (id < 0) + return 0; + struct channel *ch = channel_open_archive_data(dfile); + struct channel *old = id_pool_set(pool, id, ch); + if (old) + channel_close(old); + return !!ch; +} + +int wav_prepare_from_archive_data(int id, struct archive_data *dfile) { + return audio_prepare_from_archive_data(&wav, id, dfile); +} diff --git a/src/audio_mixer.c b/src/audio_mixer.c index 6757f0b..dbc4280 100644 --- a/src/audio_mixer.c +++ b/src/audio_mixer.c @@ -465,34 +465,18 @@ static SF_VIRTUAL_IO channel_vio = { struct channel *channel_open(enum asset_type type, int no) { - struct channel *ch = xcalloc(1, sizeof(struct channel)); - // get file from archive - ch->dfile = asset_get(type, no-1); - if (!ch->dfile) { + struct archive_data *dfile = asset_get(type, no-1); + if (!dfile) { WARNING("Failed to load %s %d", type == ASSET_SOUND ? "WAV" : "BGM", no); - goto error; + return NULL; } - // open file - ch->file = sf_open_virtual(&channel_vio, SFM_READ, &ch->info, ch); - if (sf_error(ch->file) != SF_ERR_NO_ERROR) { - WARNING("Failed to open %s %d: %s", type == ASSET_SOUND ? "WAV" : "BGM", no, sf_strerror(ch->file)); - goto error; + struct channel *ch = channel_open_archive_data(dfile); + if (!ch) { + WARNING("Failed to open %s %d", type == ASSET_SOUND ? "WAV" : "BGM", no); + return NULL; } - if (ch->info.channels > 2) { - WARNING("Audio file has more than 2 channels: %s %d", type == ASSET_SOUND ? "WAV" : "BGM", no); - goto error; - } - - // create stream - ch->stream.userdata = ch; - ch->stream.callback = refill_stream; - ch->stream.sample.frequency = ch->info.samplerate; - ch->stream.sample.audio_format = STS_MIXER_SAMPLE_FORMAT_FLOAT; - ch->stream.sample.length = CHUNK_SIZE * 2; - ch->stream.sample.data = ch->data; - ch->voice = -1; if (type == ASSET_SOUND) { struct wai *wai = wai_get(no); @@ -509,21 +493,49 @@ struct channel *channel_open(enum asset_type type, int no) ch->loop_end = clamp(0, ch->info.frames, bgi->loop_end); ch->loop_count = max(0, bgi->loop_count); ch->mixer_no = clamp(0, nr_mixers, bgi->channel); - } else { - ch->volume = 100; - ch->loop_start = 0; - ch->loop_end = ch->info.frames; - ch->loop_count = 0; - ch->mixer_no = 0; } } ch->no = no; return ch; +} + +struct channel *channel_open_archive_data(struct archive_data *dfile) +{ + struct channel *ch = xcalloc(1, sizeof(struct channel)); + ch->dfile = dfile; + + // open file + ch->file = sf_open_virtual(&channel_vio, SFM_READ, &ch->info, ch); + if (sf_error(ch->file) != SF_ERR_NO_ERROR) { + WARNING("sf_open_virtual failed: %s", sf_strerror(ch->file)); + goto error; + } + if (ch->info.channels > 2) { + WARNING("Audio file has more than 2 channels"); + goto error; + } + + // create stream + ch->stream.userdata = ch; + ch->stream.callback = refill_stream; + ch->stream.sample.frequency = ch->info.samplerate; + ch->stream.sample.audio_format = STS_MIXER_SAMPLE_FORMAT_FLOAT; + ch->stream.sample.length = CHUNK_SIZE * 2; + ch->stream.sample.data = ch->data; + ch->voice = -1; + + ch->volume = 100; + ch->loop_start = 0; + ch->loop_end = ch->info.frames; + ch->loop_count = 0; + ch->mixer_no = 0; + + ch->no = -1; + return ch; error: - if (ch->dfile) - archive_free_data(ch->dfile); + archive_free_data(dfile); free(ch); return NULL; } diff --git a/src/hll/ChrLoader.c b/src/hll/ChrLoader.c index 6f3e707..0258878 100644 --- a/src/hll/ChrLoader.c +++ b/src/hll/ChrLoader.c @@ -18,6 +18,8 @@ #include #include +#include "system4.h" +#include "system4/archive.h" #include "system4/cg.h" #include "system4/file.h" #include "system4/hashtable.h" @@ -25,6 +27,7 @@ #include "system4/string.h" #include "little_endian.h" +#include "audio.h" #include "sact.h" #include "xsystem4.h" @@ -146,7 +149,35 @@ static bool ChrLoader_LoadCG(int sprite, int x, int y, int id, int type) return true; } -HLL_WARN_UNIMPLEMENTED(false, bool, ChrLoader, LoadWavFile, int nSoundChannel, int nID); +static void chr_archive_free_data(struct archive_data *data) { /* no-op */ } + +static struct archive_ops chr_archive_ops = { + .free_data = chr_archive_free_data +}; + +static struct archive chr_archive = { .mmapped = false, .ops = &chr_archive_ops }; + +static bool ChrLoader_LoadWavFile(int sound_channel, int id) +{ + uint8_t *data = chr_get(id); + if (!data) + return false; + + size_t offset = LittleEndian_getDW(data, is_enemy(data) ? 36 : 44); + size_t size = LittleEndian_getDW(data, is_enemy(data) ? 40 : 48); + + struct archive_data *dfile = xcalloc(1, sizeof(struct archive_data)); + dfile->size = size; + dfile->data = data + offset; + dfile->no = id; + dfile->archive = &chr_archive; + + if (!wav_prepare_from_archive_data(sound_channel, dfile)) { + WARNING("ChrLoader.LoadWavFile %d failed", id); + return false; + } + return true; +} static bool ChrLoader_LoadSentence(int id, int type, struct string **msg) {