diff --git a/CMakeLists.txt b/CMakeLists.txt index bc87fbf..0151169 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,14 +112,14 @@ endif() if (EMSCRIPTEN) list(APPEND SRC_AUDIO) - list(APPEND SRC_AUDIO pcm.emscripten.c) + list(APPEND SRC_AUDIO pcm.emscripten.c bgm.dummy.c) list(APPEND SUMMARY_AUDIO "Emscripten") elseif (SDL2MIXER_FOUND) - list(APPEND SRC_AUDIO pcm.sdlmixer.c) + list(APPEND SRC_AUDIO pcm.sdlmixer.c bgm.sdlmixer.c) list(APPEND SUMMARY_AUDIO "SDL_mixer") set(ENABLE_SDLMIXER 1) else() - list(APPEND SRC_AUDIO pcm.dummy.c) + list(APPEND SRC_AUDIO pcm.dummy.c bgm.dummy.c) endif() # CDROM diff --git a/src/bgm.dummy.c b/src/bgm.dummy.c new file mode 100644 index 0000000..a25bd1f --- /dev/null +++ b/src/bgm.dummy.c @@ -0,0 +1,71 @@ +/* + * bgm.dummy.c BGM (*BA.ALD) dummy implementation + * + * Copyright (C) 2019 + * + * 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 +#include "portab.h" +#include "bgm.h" + +int musbgm_init() { + return NG; +} + +int musbgm_exit() { + return NG; +} + +int musbgm_play(int no, int time, int vol) { + printf("%s not implemented\n", __func__); + return NG; +} + +int musbgm_stop(int no, int time) { + printf("%s not implemented\n", __func__); + return NG; +} + +int musbgm_fade(int no, int time, int vol) { + printf("%s not implemented\n", __func__); + return NG; +} + +int musbgm_getpos(int no) { + printf("%s not implemented\n", __func__); + return 0; +} + +int musbgm_getlen(int no) { + printf("%s not implemented\n", __func__); + return 0; +} + +int musbgm_isplaying(int no) { + printf("%s not implemented\n", __func__); + return 0; +} + +int musbgm_stopall(int time) { + printf("%s not implemented\n", __func__); + return NG; +} + +int musbgm_wait(int no, int timeout) { + printf("%s not implemented\n", __func__); + return NG; +} diff --git a/src/bgm.h b/src/bgm.h new file mode 100644 index 0000000..0f2eb88 --- /dev/null +++ b/src/bgm.h @@ -0,0 +1,15 @@ +#ifndef __BGM_H__ +#define __BGM_H__ + +extern int musbgm_init(); +extern int musbgm_exit(); +extern int musbgm_play(int no, int time, int vol); +extern int musbgm_stop(int no, int time); +extern int musbgm_fade(int no, int time, int vol); +extern int musbgm_getpos(int no); +extern int musbgm_getlen(int no); +extern int musbgm_isplaying(int no); +extern int musbgm_stopall(int time); +extern int musbgm_wait(int no, int timeout); + +#endif /* __BGM_H__ */ diff --git a/src/bgm.sdlmixer.c b/src/bgm.sdlmixer.c new file mode 100644 index 0000000..eb6d824 --- /dev/null +++ b/src/bgm.sdlmixer.c @@ -0,0 +1,216 @@ +/* + * bgm.sdlmixer.c: BGM (*BA.ALD) playback + * + * Copyright (C) 1997-1998 Masaki Chikama (Wren) + * 1998- + * + * 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 +#include +#include +#include +#include +#include + +#include "portab.h" +#include "system.h" +#include "nact.h" +#include "bgm.h" +#include "music_private.h" +#include "ald_manager.h" + +#define BGI_MAX 100 + +typedef struct { + int no; // シナリオ上での曲番号 + int loopno; // ループ回数 (0の場合は無限) + int looptop; // ループ時先頭戻り位置 (サンプル数) + int len; // 曲長さ (サンプル数) +} bgi_t; + +static int bgi_nfile; +static bgi_t bgi_data[BGI_MAX]; + +static int current_no; +static Mix_Music *mix_music; +static void* wave_buf; +static Uint32 start_time; + +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() { + if (nact->files.bgi == NULL) + return; + + FILE *fp = fopen(nact->files.bgi, "r"); + if (!fp) { + WARNING("Could not open %s\n", nact->files.bgi); + 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++; + } + return; +} + +static bgi_t *bgi_find(int no) { + for (int i = 0; i < bgi_nfile; i++) { + if (bgi_data[i].no == no) + return &bgi_data[i]; + } + return NULL; +} + +static void free_music() { + current_no = 0; + if (mix_music) { + Mix_FreeMusic(mix_music); + mix_music = NULL; + } + if (wave_buf) { + free(wave_buf); + wave_buf = NULL; + } +} + +static Mix_Music *bgm_load(int no) { + dridata *dfile = ald_getdata(DRIFILE_BGM, no -1); + if (dfile == NULL) { + WARNING("DRIFILE_BGM fail to open %d\n", no -1); + return NULL; + } + + free_music(); + wave_buf = malloc(dfile->size); + memcpy(wave_buf, dfile->data, dfile->size); + SDL_RWops *rwops = SDL_RWFromConstMem(wave_buf, dfile->size); + ald_freedata(dfile); + + mix_music = Mix_LoadMUSType_RW(rwops, MUS_WAV, SDL_TRUE /* freesrc */); + if (mix_music == NULL) { + WARNING("not .wav file\n"); + free_music(); + return NULL; + } + + current_no = no; + return mix_music; +} + +int musbgm_init() { + bgi_read(); + if (!bgi_nfile) return NG; + return OK; +} + +int musbgm_exit() { + free_music(); + return OK; +} + +int musbgm_play(int no, int time, int vol) { + if (current_no) + musbgm_stop(current_no, 0); + + if (!bgm_load(no)) + return NG; + + // We don't use the loop information in the BGI file, but SDL_mixer + // 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) { + free_music(); + return NG; + } + start_time = SDL_GetTicks(); + + return OK; +} + +int musbgm_stop(int no, int time) { + if (no == current_no) + Mix_FadeOutMusic(time * 10); + return OK; +} + +int musbgm_fade(int no, int time, int vol) { + if (no != current_no) + return NG; + + // SDL_mixer doesn't provide arbitrary fading, so just set the volume immediately. + Mix_VolumeMusic(vol * MIX_MAX_VOLUME / 100); + return OK; +} + +int musbgm_getpos(int no) { + if (!musbgm_isplaying(no)) + return 0; + + // FIXME: This is not correct after loop + return (SDL_GetTicks() - start_time) / 10; +} + +int musbgm_getlen(int no) { + bgi_t *bgi = bgi_find(no); + if (!bgi) return 0; + + // FIXME: This assumes 44.1kHz + return bgi->len / 441; +} + +int musbgm_isplaying(int no) { + return no == current_no && Mix_PlayingMusic(); +} + +int musbgm_stopall(int time) { + return musbgm_stop(current_no, time); +} + +int musbgm_wait(int no, int timeout) { + while (timeout-- > 0 && musbgm_isplaying(no)) + SDL_Delay(10); + return OK; +} diff --git a/src/music.c b/src/music.c index 5a4fc7f..bc79a82 100644 --- a/src/music.c +++ b/src/music.c @@ -29,6 +29,7 @@ struct _musprvdat musprv; int mus_init(int audio_buffer_size) { + musbgm_init(); muscd_init(); musmidi_init(); prv.pcm_valid = muspcm_init(audio_buffer_size) == OK; @@ -36,6 +37,7 @@ int mus_init(int audio_buffer_size) { } int mus_exit() { + musbgm_exit(); if (prv.cd_valid) muscd_exit(); if (prv.midi_valid) musmidi_exit(); if (prv.pcm_valid) muspcm_exit(); @@ -437,38 +439,31 @@ int mus_wav_load_lrsw(int ch, int num) { } int mus_bgm_play(int no, int time, int vol) { - printf("%s not implemented\n", __func__); - return NG; + return musbgm_play(no, time, vol); } int mus_bgm_stop(int no, int time) { - printf("%s not implemented\n", __func__); - return NG; + return musbgm_stop(no, time); } int mus_bgm_stopall(int time) { - printf("%s not implemented\n", __func__); - return NG; + return musbgm_stopall(time); } int mus_bgm_fade(int no, int time, int vol) { - printf("%s not implemented\n", __func__); - return NG; + return musbgm_fade(no, time, vol); } int mus_bgm_getpos(int no) { - printf("%s not implemented\n", __func__); - return 0; + return musbgm_getpos(no); } int mus_bgm_getlength(int no) { - printf("%s not implemented\n", __func__); - return 0; + return musbgm_getlen(no); } int mus_bgm_wait(int no, int timeout) { - printf("%s not implemented\n", __func__); - return NG; + return musbgm_wait(no, timeout); } int mus_bgm_waitpos(int no, int index) { diff --git a/src/music_private.h b/src/music_private.h index 45718dc..e129179 100644 --- a/src/music_private.h +++ b/src/music_private.h @@ -23,6 +23,7 @@ #define __MUSIC_PRIVATE_H__ #include "portab.h" +#include "bgm.h" #include "cdrom.h" #include "midi.h" #include "music_cdrom.h"