diff --git a/include/audio.h b/include/audio.h index 01f79ed..c92747c 100644 --- a/include/audio.h +++ b/include/audio.h @@ -19,40 +19,43 @@ #include -enum audio_type { - AUDIO_MUSIC, - AUDIO_SOUND -}; - void audio_init(void); void audio_fini(void); -bool audio_exists(enum audio_type type, int no); -int audio_prepare(enum audio_type type, int channel, int no); -int audio_unprepare(enum audio_type type, int channel); -int audio_play(enum audio_type type, int channel); -int audio_stop(enum audio_type type, int channel); -bool audio_is_playing(enum audio_type type, int channel); -int audio_set_loop_count(enum audio_type type, int channel, int count); -int audio_get_loop_count(enum audio_type type, int channel); -int audio_set_loop_start_pos(enum audio_type type, int channel, int pos); -int audio_set_loop_end_pos(enum audio_type type, int channel, int pos); -int audio_fade(enum audio_type type, int channel, int time, int volume, bool stop); -int audio_stop_fade(enum audio_type type, int channel); -bool audio_is_fading(enum audio_type type, int channel); -int audio_pause(enum audio_type type, int channel); -int audio_restart(enum audio_type type, int channel); -bool audio_is_paused(enum audio_type type, int channel); -int audio_get_pos(enum audio_type type, int channel); -int audio_get_length(enum audio_type type, int channel); -int audio_get_sample_pos(enum audio_type type, int channel); -int audio_get_sample_length(enum audio_type type, int channel); -int audio_seek(enum audio_type type, int channel, int pos); -int audio_get_unused_channel(enum audio_type type); -int audio_reverse_LR(enum audio_type type, int channel); -int audio_get_volume(enum audio_type type, int channel); -int audio_get_time_length(enum audio_type type, int channel); -int audio_get_group_num(enum audio_type type, int channel); -int audio_prepare_from_file(enum audio_type type, int channel, char *filename); +bool wav_exists(int no); +bool bgm_exists(int no); +int wav_prepare(int ch, int no); +int bgm_prepare(int ch, int no); +int wav_unprepare(int ch); +int bgm_unprepare(int ch); +int wav_play(int ch); +int bgm_play(int ch); +int wav_stop(int ch); +int bgm_stop(int ch); +bool wav_is_playing(int ch); +bool bgm_is_playing(int ch); +//int audio_set_loop_count(enum audio_type type, int channel, int count); +//int audio_get_loop_count(enum audio_type type, int channel); +//int audio_set_loop_start_pos(enum audio_type type, int channel, int pos); +//int audio_set_loop_end_pos(enum audio_type type, int channel, int pos); +int wav_fade(int ch, int time, int volume, bool stop); +int bgm_fade(int ch, int time, int volume, bool stop); +//int audio_stop_fade(enum audio_type type, int channel); +//bool audio_is_fading(enum audio_type type, int channel); +//int audio_pause(enum audio_type type, int channel); +//int audio_restart(enum audio_type type, int channel); +//bool audio_is_paused(enum audio_type type, int channel); +//int audio_get_pos(enum audio_type type, int channel); +//int audio_get_length(enum audio_type type, int channel); +//int audio_get_sample_pos(enum audio_type type, int channel); +//int audio_get_sample_length(enum audio_type type, int channel); +//int audio_seek(enum audio_type type, int channel, int pos); +int wav_get_unused_channel(void); +int bgm_get_unused_channel(void); +//int audio_reverse_LR(enum audio_type type, int channel); +//int audio_get_volume(enum audio_type type, int channel); +int wav_get_time_length(int ch); +//int audio_get_group_num(enum audio_type type, int channel); +//int audio_prepare_from_file(enum audio_type type, int channel, char *filename); #endif /* SYSTEM4_AUDIO_H */ diff --git a/include/xsystem4.h b/include/xsystem4.h index 7e2fedb..08ed78c 100644 --- a/include/xsystem4.h +++ b/include/xsystem4.h @@ -29,6 +29,9 @@ struct config { char *home_dir; int view_width; int view_height; + + char *bgi_path; + char *wai_path; }; struct config config; diff --git a/src/ald.c b/src/ald.c index f835b25..b9ab719 100644 --- a/src/ald.c +++ b/src/ald.c @@ -341,7 +341,6 @@ struct archive *ald_open(char **files, int count, int flags, int *error) for (int i = 0; i < count; i++) { if (!files[i]) continue; - printf("OPENING FILE %s\n", files[i]); if (!(fp = fopen(files[i], "r"))) { *error = ARCHIVE_FILE_ERROR; goto exit_err; diff --git a/src/audio.c b/src/audio.c index 4e4285f..c7b2c7b 100644 --- a/src/audio.c +++ b/src/audio.c @@ -24,16 +24,90 @@ #define AUDIO_SLOT_ALLOC_STEP 256 -struct audio_slot { +struct wav_slot { Mix_Chunk *chunk; int channel; int no; }; -static struct { - struct audio_slot *slots; +struct bgm_slot { + Mix_Music *music; + int no; +}; + +struct { + struct wav_slot *slots; int nr_slots; -} audio[2]; +} wav; + +struct { + struct bgm_slot *slots; + int nr_slots; + int playing; +} bgm; + +#define BGI_MAX 100 + +struct bgi { + int no; + int loopno; + int looptop; + int len; +}; + +static int bgi_nfile; +static struct bgi bgi_data[BGI_MAX]; + +static char *bgi_gets(char *buf, int n, FILE *fp) { + char *s = buf; + int c; + while (--n > 0 && (c = fgetc(fp)) != EOF) { + c = c >> 4 | (c & 0xf) << 4; // decrypt + *s++ = c; + if (c == '\n') + break; + } + if (s == buf && c == EOF) + return NULL; + *s = '\0'; + return buf; +} + +static void bgi_read(const char *path) +{ + FILE *fp = fopen(path, "rb"); + if (!fp) { + WARNING("Failed to open bgi file: %s", path); + return; + } + + char buf[100]; + while (bgi_nfile < BGI_MAX && bgi_gets(buf, sizeof(buf), fp)) { + int terminator; + if (sscanf(buf, " %d, %d, %d, %d, %d", + &bgi_data[bgi_nfile].no, + &bgi_data[bgi_nfile].loopno, + &bgi_data[bgi_nfile].looptop, + &bgi_data[bgi_nfile].len, + &terminator) != 5 + || terminator != -1) { + continue; + } + bgi_nfile++; + } + + for (int i = 0; i < bgi_nfile; i++) { + NOTICE("BGI %d: %d, %d, %d, %d", i, bgi_data[i].no, bgi_data[i].loopno, bgi_data[i].looptop, bgi_data[i].len); + } +} + +possibly_unused static struct bgi *bgi_find(int no) { + for (int i = 0; i < bgi_nfile; i++) { + if (bgi_data[i].no == no) + return &bgi_data[i]; + } + return NULL; +} void audio_init(void) { @@ -42,11 +116,15 @@ void audio_init(void) WARNING("Audio initialization failed"); } - audio[AUDIO_MUSIC].slots = xcalloc(16, sizeof(struct audio_slot)); - audio[AUDIO_MUSIC].nr_slots = 16; + wav.slots = xcalloc(16, sizeof(struct wav_slot)); + wav.nr_slots = 16; - audio[AUDIO_SOUND].slots = xcalloc(16, sizeof(struct audio_slot)); - audio[AUDIO_SOUND].nr_slots = 16; + bgm.slots = xcalloc(16, sizeof(struct bgm_slot)); + bgm.nr_slots = 16; + bgm.playing = -1; + + if (config.bgi_path) + bgi_read(config.bgi_path); } void audio_fini(void) @@ -55,64 +133,92 @@ void audio_fini(void) Mix_Quit(); } -static void audio_realloc(enum audio_type type, int new_size) +static void wav_realloc(int new_size) { - audio[type].slots = xrealloc(audio[type].slots, new_size * sizeof(struct audio_slot)); - for (int i = audio[type].nr_slots; i < new_size; i++) { - audio[type].slots[i].chunk = NULL; - audio[type].slots[i].channel = -1; + wav.slots = xrealloc(wav.slots, new_size * sizeof(struct wav_slot)); + for (int i = wav.nr_slots; i < new_size; i++) { + wav.slots[i].chunk = NULL; + wav.slots[i].channel = -1; } - audio[type].nr_slots = new_size; + wav.nr_slots = new_size; } -static struct audio_slot *audio_alloc_channel(enum audio_type type, int ch) +static void bgm_realloc(int new_size) { - if (ch >= audio[type].nr_slots) - audio_realloc(type, ch + AUDIO_SLOT_ALLOC_STEP); - return &audio[type].slots[ch]; + bgm.slots = xrealloc(bgm.slots, new_size * sizeof(struct bgm_slot)); + for (int i = bgm.nr_slots; i < new_size; i++) { + bgm.slots[i].music = NULL; + } + bgm.nr_slots = new_size; } -int audio_get_unused_channel(enum audio_type type) +static struct wav_slot *wav_alloc_channel(int ch) { - for (int i = 0; i < audio[type].nr_slots; i++) { - if (!audio[type].slots[i].chunk) + if (ch >= wav.nr_slots) + wav_realloc(ch + AUDIO_SLOT_ALLOC_STEP); + return &wav.slots[ch]; +} + +static struct bgm_slot *bgm_alloc_channel(int ch) +{ + if (ch >= bgm.nr_slots) + bgm_realloc(ch + AUDIO_SLOT_ALLOC_STEP); + return &bgm.slots[ch]; +} + +int wav_get_unused_channel(void) +{ + for (int i = 0; i < wav.nr_slots; i++) { + if (!wav.slots[i].chunk) return i; } - int slot = audio[type].nr_slots; - audio_realloc(type, slot + AUDIO_SLOT_ALLOC_STEP); + int slot = wav.nr_slots; + wav_realloc(slot + AUDIO_SLOT_ALLOC_STEP); return slot; } -static struct audio_slot *get_slot(enum audio_type type, int ch) +int bgm_get_unused_channel(void) { - if (ch < 0 || ch >= audio[type].nr_slots) - return NULL; - return &audio[type].slots[ch]; -} - -static int audio_type_to_archive_type(enum audio_type type) -{ - switch (type) { - case AUDIO_MUSIC: return ALDFILE_BGM; - case AUDIO_SOUND: return ALDFILE_WAVE; + for (int i = 0; i < bgm.nr_slots; i++) { + if (!bgm.slots[i].music) + return i; } - ERROR("Unknown audio type: %d", type); + + int slot = bgm.nr_slots; + bgm_realloc(slot + AUDIO_SLOT_ALLOC_STEP); + return slot; } -bool audio_exists(enum audio_type type, int no) +static struct wav_slot *wav_get_slot(int ch) { - int archive = audio_type_to_archive_type(type); - return ald[archive] && archive_exists(ald[archive], no); + if (ch < 0 || ch >= wav.nr_slots) + return NULL; + return &wav.slots[ch]; } -static Mix_Chunk *load_chunk(enum audio_type type, int no) +static struct bgm_slot *bgm_get_slot(int ch) { - struct archive_data *dfile; - int archive = audio_type_to_archive_type(type); + if (ch < 0 || ch >= bgm.nr_slots) + return NULL; + return &bgm.slots[ch]; +} - if (!(dfile = archive_get(ald[archive], no))) { - WARNING("Failed to load %s %d", archive == ALDFILE_BGM ? "BGM" : "WAV", no); +bool wav_exists(int no) +{ + return ald[ALDFILE_WAVE] && archive_exists(ald[ALDFILE_WAVE], no); +} + +bool bgm_exists(int no) +{ + return ald[ALDFILE_BGM] && archive_exists(ald[ALDFILE_BGM], no); +} + +static Mix_Chunk *wav_load_chunk(int no) +{ + struct archive_data *dfile = archive_get(ald[ALDFILE_WAVE], no); + if (!dfile) { + WARNING("Failed to load WAV %d", no); return NULL; } @@ -120,14 +226,33 @@ static Mix_Chunk *load_chunk(enum audio_type type, int no) archive_free_data(dfile); if (!chunk) { - WARNING("%s %d: not a valid audio file", archive == ALDFILE_BGM ? "BGM" : "WAV", no); + WARNING("WAV %d: not a valid audio file", no); return NULL; } return chunk; } -static void unload_slot(struct audio_slot *slot) +static Mix_Music *bgm_load_music(int no) +{ + struct archive_data *dfile = archive_get(ald[ALDFILE_BGM], no); + if (!dfile) { + WARNING("Failed to load WAV %d", no); + return NULL; + } + + Mix_Music *music = Mix_LoadMUSType_RW(SDL_RWFromConstMem(dfile->data, dfile->size), MUS_WAV, SDL_TRUE); + archive_free_data(dfile); + + if (!music) { + WARNING("BGM %d: not a valid audio file", no); + return NULL; + } + + return music; +} + +static void wav_unload_slot(struct wav_slot *slot) { if (slot->chunk) { Mix_HaltChannel(slot->channel); @@ -137,32 +262,63 @@ static void unload_slot(struct audio_slot *slot) slot->channel = -1; } -int audio_prepare(enum audio_type type, int ch, int no) +static void bgm_unload_slot(struct bgm_slot *slot) +{ + if (slot->music) { + Mix_FreeMusic(slot->music); + slot->music = NULL; + } +} + +int wav_prepare(int ch, int no) { if (ch < 0) return 0; - struct audio_slot *slot = audio_alloc_channel(type, ch); - unload_slot(slot); + struct wav_slot *slot = wav_alloc_channel(ch); + wav_unload_slot(slot); - audio[type].slots[ch].chunk = load_chunk(type, no); - audio[type].slots[ch].no = no; - return !!audio[type].slots[ch].chunk; + wav.slots[ch].chunk = wav_load_chunk(no); + wav.slots[ch].no = no; + return !!wav.slots[ch].chunk; } -int audio_unprepare(enum audio_type type, int ch) +int bgm_prepare(int ch, int no) { - struct audio_slot *slot = get_slot(type, ch); + if (ch < 0) + return 0; + + struct bgm_slot *slot = bgm_alloc_channel(ch); + bgm_unload_slot(slot); + + bgm.slots[ch].music = bgm_load_music(no); + bgm.slots[ch].no = no; + return !!bgm.slots[ch].music; +} + +int wav_unprepare(int ch) +{ + struct wav_slot *slot = wav_get_slot(ch); if (!slot) return 0; - unload_slot(slot); + wav_unload_slot(slot); return 1; } -int audio_play(enum audio_type type, int ch) +int bgm_unprepare(int ch) { - struct audio_slot *slot = get_slot(type, ch); + struct bgm_slot *slot = bgm_get_slot(ch); + if (!slot) + return 0; + + bgm_unload_slot(slot); + return 1; +} + +int wav_play(int ch) +{ + struct wav_slot *slot = wav_get_slot(ch); if (!slot || !slot->chunk) return 0; @@ -170,14 +326,23 @@ int audio_play(enum audio_type type, int ch) Mix_Resume(slot->channel); return 1; } - - slot->channel = Mix_PlayChannel(-1, slot->chunk, type == AUDIO_MUSIC ? -1 : 0); + slot->channel = Mix_PlayChannel(-1, slot->chunk, 0); return slot->channel >= 0; } -int audio_stop(enum audio_type type, int ch) +int bgm_play(int ch) { - struct audio_slot *slot = get_slot(type, ch); + struct bgm_slot *slot = bgm_get_slot(ch); + if (!slot || !slot->music) + return 0; + + bgm.playing = slot - bgm.slots; + return !Mix_PlayMusic(slot->music, -1); +} + +int wav_stop(int ch) +{ + struct wav_slot *slot = wav_get_slot(ch); if (!slot) return 0; @@ -186,23 +351,46 @@ int audio_stop(enum audio_type type, int ch) return 1; } -bool audio_is_playing(enum audio_type type, int ch) +int bgm_stop(int ch) { - struct audio_slot *slot = get_slot(type, ch); - return slot && slot->channel >= 0 && Mix_Playing(slot->channel); -} - -int audio_fade(enum audio_type type, int ch, possibly_unused int time, possibly_unused int volume, bool stop) -{ - // TODO: fade - if (stop) - audio_stop(type, ch); + // FIXME: what if channel isn't playing? + if (bgm.playing == ch) { + Mix_FadeOutMusic(10); + bgm.playing = -1; + } return 1; } -int audio_get_time_length(enum audio_type type, int ch) +bool wav_is_playing(int ch) { - struct audio_slot *slot = get_slot(type, ch); + struct wav_slot *slot = wav_get_slot(ch); + return slot && slot->channel >= 0 && Mix_Playing(slot->channel); +} + +bool bgm_is_playing(int ch) +{ + return bgm.playing == ch && Mix_PlayingMusic(); +} + +int wav_fade(int ch, possibly_unused int time, possibly_unused int volume, bool stop) +{ + // TODO: fade + if (stop) + wav_stop(ch); + return 1; +} + +int bgm_fade(int ch, possibly_unused int time, possibly_unused int volume, bool stop) +{ + // TODO: fade + if (stop) + bgm_stop(ch); + return 1; +} + +int wav_get_time_length(int ch) +{ + struct wav_slot *slot = wav_get_slot(ch); if (!slot || !slot->chunk) return 0; diff --git a/src/hll/SACT2.c b/src/hll/SACT2.c index 049abf8..fa2d932 100644 --- a/src/hll/SACT2.c +++ b/src/hll/SACT2.c @@ -120,82 +120,82 @@ int sact_CG_IsExist(int cg_no) int sact_Music_IsExist(int n) { - return audio_exists(AUDIO_MUSIC, n - 1); + return bgm_exists(n - 1); } int sact_Music_Prepare(int ch, int n) { - return audio_prepare(AUDIO_MUSIC, ch, n - 1); + return bgm_prepare(ch, n - 1); } int sact_Music_Unprepare(int ch) { - return audio_unprepare(AUDIO_MUSIC, ch); + return bgm_unprepare(ch); } int sact_Music_Play(int ch) { - return audio_play(AUDIO_MUSIC, ch); + return bgm_play(ch); } int sact_Music_Stop(int ch) { - return audio_stop(AUDIO_MUSIC, ch); + return bgm_stop(ch); } int sact_Music_IsPlay(int ch) { - return audio_is_playing(AUDIO_MUSIC, ch); + return bgm_is_playing(ch); } int sact_Music_Fade(int ch, int time, int volume, int stop) { - return audio_fade(AUDIO_MUSIC, ch, time, volume, stop); + return bgm_fade(ch, time, volume, stop); } int sact_Sound_IsExist(int n) { - return audio_exists(AUDIO_SOUND, n - 1); + return wav_exists(n - 1); } int sact_Sound_GetUnuseChannel(void) { - return audio_get_unused_channel(AUDIO_SOUND); + return wav_get_unused_channel(); } int sact_Sound_Prepare(int ch, int n) { - return audio_prepare(AUDIO_SOUND, ch, n - 1); + return wav_prepare(ch, n - 1); } int sact_Sound_Unprepare(int ch) { - return audio_unprepare(AUDIO_SOUND, ch); + return wav_unprepare(ch); } int sact_Sound_Play(int ch) { - return audio_play(AUDIO_SOUND, ch); + return wav_play(ch); } int sact_Sound_Stop(int ch) { - return audio_stop(AUDIO_SOUND, ch); + return wav_stop(ch); } int sact_Sound_IsPlay(int ch) { - return audio_is_playing(AUDIO_SOUND, ch); + return wav_is_playing(ch); } int sact_Sound_Fade(int ch, int time, int volume, int stop) { - return audio_fade(AUDIO_SOUND, ch, time, volume, stop); + return wav_fade(ch, time, volume, stop); } int sact_Sound_GetTimeLength(int ch) { - return audio_get_time_length(AUDIO_SOUND, ch); + return wav_get_time_length(ch); } void sact_System_GetDate(int *year, int *month, int *mday, int *wday) diff --git a/src/system4.c b/src/system4.c index bc21135..e1d4436 100644 --- a/src/system4.c +++ b/src/system4.c @@ -140,31 +140,45 @@ static void init_gamedata_dir(const char *path) int dno; size_t len = strlen(d->d_name); snprintf(filepath, 511, "%s/%s", path, d->d_name); - if (strcasecmp(d->d_name+len-4, ".ald")) - continue; - dno = toupper(*(d->d_name+len-5)) - 'A'; - if (dno < 0 || dno >= ALD_FILEMAX) - continue; + if (!strcasecmp(d->d_name+len-4, ".ald")) { + dno = toupper(*(d->d_name+len-5)) - 'A'; + if (dno < 0 || dno >= ALD_FILEMAX) { + WARNING("Invalid ALD index: %s", d->d_name); + continue; + } - switch (*(d->d_name+len-6)) { - case 'b': - case 'B': - ald_filenames[ALDFILE_BGM][dno] = strdup(filepath); - ald_count[ALDFILE_BGM] = max(ald_count[ALDFILE_BGM], dno+1); - break; - case 'g': - case 'G': - ald_filenames[ALDFILE_CG][dno] = strdup(filepath); - ald_count[ALDFILE_CG] = max(ald_count[ALDFILE_CG], dno+1); - break; - case 'w': - case 'W': - ald_filenames[ALDFILE_WAVE][dno] = strdup(filepath); - ald_count[ALDFILE_WAVE] = max(ald_count[ALDFILE_WAVE], dno+1); - break; - default: - WARNING("Unhandled ALD file: %s", d->d_name); - break; + switch (*(d->d_name+len-6)) { + case 'b': + case 'B': + ald_filenames[ALDFILE_BGM][dno] = strdup(filepath); + ald_count[ALDFILE_BGM] = max(ald_count[ALDFILE_BGM], dno+1); + break; + case 'g': + case 'G': + ald_filenames[ALDFILE_CG][dno] = strdup(filepath); + ald_count[ALDFILE_CG] = max(ald_count[ALDFILE_CG], dno+1); + break; + case 'w': + case 'W': + ald_filenames[ALDFILE_WAVE][dno] = strdup(filepath); + ald_count[ALDFILE_WAVE] = max(ald_count[ALDFILE_WAVE], dno+1); + break; + default: + WARNING("Unhandled ALD file: %s", d->d_name); + break; + } + } else if (!strcasecmp(d->d_name+len-4, ".bgi")) { + if (config.bgi_path) { + WARNING("Multiple bgi files"); + continue; + } + config.bgi_path = strdup(filepath); + } else if (!strcasecmp(d->d_name+len-4, ".wai")) { + if (config.wai_path) { + WARNING("Multiple wai files"); + continue; + } + config.wai_path = strdup(filepath); } }