From ab379f2bb081f3fe2ea77ed163f755f59a49e6cf Mon Sep 17 00:00:00 2001 From: Takamichi Horikawa Date: Wed, 12 Apr 2017 01:04:15 +0900 Subject: added wave output --- common/fmplayer_common.h | 17 ++++++ common/fmplayer_drumrom_unix.c | 53 +++++++++++++++++ common/fmplayer_drumrom_win.c | 49 ++++++++++++++++ common/fmplayer_file.c | 113 +++++++++++++++++++++++++++++++++++- common/fmplayer_file.h | 4 +- common/fmplayer_file_gio.c | 4 +- common/fmplayer_file_unix.c | 127 +++++++++++++++++++++++++++++++++++++++++ common/fmplayer_file_win.c | 2 +- common/fmplayer_work_opna.c | 63 ++++++++++++++++++++ 9 files changed, 427 insertions(+), 5 deletions(-) create mode 100644 common/fmplayer_drumrom_unix.c create mode 100644 common/fmplayer_drumrom_win.c create mode 100644 common/fmplayer_file_unix.c create mode 100644 common/fmplayer_work_opna.c (limited to 'common') diff --git a/common/fmplayer_common.h b/common/fmplayer_common.h index 5394293..c4f58af 100644 --- a/common/fmplayer_common.h +++ b/common/fmplayer_common.h @@ -2,7 +2,24 @@ #define MYON_FMPLAYER_COMMON_H_INCLUDED #include +#include void *fmplayer_load_data(const char *name, size_t size); +struct fmdriver_work; +struct ppz8; +struct opna; +struct opna_timer; +void fmplayer_init_work_opna( + struct fmdriver_work *work, + struct ppz8 *ppz8, + struct opna *opna, + struct opna_timer *timer, + void *adpcm_ram +); + +struct opna_drum; +bool fmplayer_drum_rom_load(struct opna_drum *drum); +bool fmplayer_drum_loaded(void); + #endif // MYON_FMPLAYER_COMMON_H_INCLUDED diff --git a/common/fmplayer_drumrom_unix.c b/common/fmplayer_drumrom_unix.c new file mode 100644 index 0000000..791b264 --- /dev/null +++ b/common/fmplayer_drumrom_unix.c @@ -0,0 +1,53 @@ +#include "fmplayer_common.h" +#include +#include +#include +#include "libopna/opnadrum.h" + +static struct { + uint8_t drum_rom[OPNA_ROM_SIZE]; + bool loaded; +} g; + +#define DATADIR "/.local/share/fmplayer/" + +void loadfile(void) { + const char *path = "ym2608_adpcm_rom.bin"; + const char *home = getenv("HOME"); + char *dpath = 0; + if (home) { + const char *datadir = DATADIR; + dpath = malloc(strlen(home)+strlen(datadir)+strlen(path) + 1); + if (dpath) { + strcpy(dpath, home); + strcat(dpath, datadir); + strcat(dpath, path); + path = dpath; + } + } + FILE *rhythm = fopen(path, "r"); + free(dpath); + if (!rhythm) goto err; + if (fseek(rhythm, 0, SEEK_END) != 0) goto err_file; + long size = ftell(rhythm); + if (size != OPNA_ROM_SIZE) goto err_file; + if (fseek(rhythm, 0, SEEK_SET) != 0) goto err_file; + if (fread(g.drum_rom, 1, OPNA_ROM_SIZE, rhythm) != OPNA_ROM_SIZE) goto err_file; + fclose(rhythm); + g.loaded = true; + return; +err_file: + fclose(rhythm); +err: + return; +} + +bool fmplayer_drum_rom_load(struct opna_drum *drum) { + if (!g.loaded) { + loadfile(); + } + if (g.loaded) { + opna_drum_set_rom(drum, g.drum_rom); + } + return g.loaded; +} diff --git a/common/fmplayer_drumrom_win.c b/common/fmplayer_drumrom_win.c new file mode 100644 index 0000000..aab4546 --- /dev/null +++ b/common/fmplayer_drumrom_win.c @@ -0,0 +1,49 @@ +#include "fmplayer_common.h" +#include "libopna/opnadrum.h" +#define WIN32_LEAN_AND_MEAN +#include +#include +static struct { + char drum_rom[OPNA_ROM_SIZE]; + bool loaded; +} g; + +static void loadrom(void) { + const wchar_t *path = L"ym2608_adpcm_rom.bin"; + wchar_t exepath[MAX_PATH]; + if (GetModuleFileName(0, exepath, MAX_PATH)) { + PathRemoveFileSpec(exepath); + if ((lstrlen(exepath) + lstrlen(path) + 1) < MAX_PATH) { + lstrcat(exepath, L"\\"); + lstrcat(exepath, path); + path = exepath; + } + } + HANDLE file = CreateFile(path, GENERIC_READ, + 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (file == INVALID_HANDLE_VALUE) goto err; + DWORD filesize = GetFileSize(file, 0); + if (filesize != OPNA_ROM_SIZE) goto err; + DWORD readbytes; + if (!ReadFile(file, g.drum_rom, OPNA_ROM_SIZE, &readbytes, 0) + || readbytes != OPNA_ROM_SIZE) goto err; + CloseHandle(file); + g.loaded = true; + return; +err: + if (file != INVALID_HANDLE_VALUE) CloseHandle(file); + return; +} + + +bool fmplayer_drum_rom_load(struct opna_drum *drum) { + if (!g.loaded) loadrom(); + if (g.loaded) { + opna_drum_set_rom(drum, g.drum_rom); + } + return g.loaded; +} + +bool fmplayer_drum_loaded(void) { + return g.loaded; +} diff --git a/common/fmplayer_file.c b/common/fmplayer_file.c index 1080625..3c05cab 100644 --- a/common/fmplayer_file.c +++ b/common/fmplayer_file.c @@ -12,6 +12,92 @@ void fmplayer_file_free(const struct fmplayer_file *fmfileptr) { free(fmfile); } +static void opna_writereg_dummy(struct fmdriver_work *work, unsigned addr, unsigned data) { +} + +static unsigned opna_readreg_dummy(struct fmdriver_work *work, unsigned addr) { + return 0xff; +} + +struct dummy_opna { + uint32_t timerb_loop; + uint8_t loopcnt; +}; + +static uint8_t opna_status_dummy(struct fmdriver_work *work, bool a1) { + struct dummy_opna *opna = work->opna; + if (!opna->timerb_loop) { + if (work->loop_cnt >= opna->loopcnt) { + opna->timerb_loop = work->timerb_cnt; + } else if (work->timerb_cnt > 0xfffff) { + opna->timerb_loop = -1; + } + } + return opna->timerb_loop ? 0 : 2; +} + +static void dummy_work_init(struct fmdriver_work *work, struct dummy_opna *dopna) { + work->opna_writereg = opna_writereg_dummy; + work->opna_readreg = opna_readreg_dummy; + work->opna_status = opna_status_dummy; + work->opna = dopna; +} + +static struct driver_pmd *pmd_dup(const struct driver_pmd *pmd) { + struct driver_pmd *pmddup = malloc(sizeof(*pmddup)); + if (!pmddup) return 0; + memcpy(pmddup, pmd, sizeof(*pmd)); + size_t datalen = pmddup->datalen+1; + const uint8_t *data = pmddup->data-1; + uint8_t *datadup = malloc(datalen); + if (!datadup) { + free(pmddup); + return 0; + } + memcpy(datadup, data, datalen); + pmddup->data = datadup+1; + pmddup->datalen = datalen-1; + return pmddup; +} + +static void pmd_free(struct driver_pmd *pmd) { + if (pmd) { + free(pmd->data-1); + free(pmd); + } +} + +static struct driver_fmp *fmp_dup(const struct driver_fmp *fmp) { + struct driver_fmp *fmpdup = malloc(sizeof(*fmpdup)); + if (!fmpdup) return 0; + memcpy(fmpdup, fmp, sizeof(*fmp)); + fmpdup->data = malloc(fmp->datalen); + if (!fmpdup->data) { + free(fmpdup); + return 0; + } + memcpy((void*)fmpdup->data, fmp->data, fmp->datalen); + return fmpdup; +} + +static void fmp_free(struct driver_fmp *fmp) { + if (fmp) { + free((void*)fmp->data); + free(fmp); + } +} + +static void calc_loop(struct fmdriver_work *work, int loopcnt) { + if ((loopcnt < 1) || (0xff < loopcnt)) { + work->loop_timerb_cnt = -1; + return; + } + struct dummy_opna *opna = work->opna; + opna->loopcnt = loopcnt; + while (!opna->timerb_loop) work->driver_opna_interrupt(work); + work->loop_timerb_cnt = opna->timerb_loop; +} + struct fmplayer_file *fmplayer_file_alloc(const void *path, enum fmplayer_file_error *error) { struct fmplayer_file *fmfile = calloc(1, sizeof(*fmfile)); if (!fmfile) { @@ -116,9 +202,21 @@ static void loadfmpppz(struct fmdriver_work *work, struct fmplayer_file *fmfile) fmfile->fmp_ppz_err = !loadppzpvi(work, fmfile, pvifile); } -void fmplayer_file_load(struct fmdriver_work *work, struct fmplayer_file *fmfile) { +void fmplayer_file_load(struct fmdriver_work *work, struct fmplayer_file *fmfile, int loopcnt) { + struct dummy_opna dopna = {0}; + struct fmdriver_work dwork = {0}; switch (fmfile->type) { case FMPLAYER_FILE_TYPE_PMD: + { + struct driver_pmd *pmddup = pmd_dup(&fmfile->driver.pmd); + if (pmddup) { + dummy_work_init(&dwork, &dopna); + pmd_init(&dwork, pmddup); + calc_loop(&dwork, loopcnt); + pmd_free(pmddup); + work->loop_timerb_cnt = dwork.loop_timerb_cnt; + } + } pmd_init(work, &fmfile->driver.pmd); loadppc(work, fmfile); loadpmdppz(work, fmfile); @@ -126,6 +224,16 @@ void fmplayer_file_load(struct fmdriver_work *work, struct fmplayer_file *fmfile work->pcmerror[1] = fmfile->pmd_ppz_err; break; case FMPLAYER_FILE_TYPE_FMP: + { + struct driver_fmp *fmpdup = fmp_dup(&fmfile->driver.fmp); + if (fmpdup) { + dummy_work_init(&dwork, &dopna); + fmp_init(&dwork, fmpdup); + calc_loop(&dwork, loopcnt); + fmp_free(fmpdup); + work->loop_timerb_cnt = dwork.loop_timerb_cnt; + } + } fmp_init(work, &fmfile->driver.fmp); loadpvi(work, fmfile); loadfmpppz(work, fmfile); @@ -139,6 +247,7 @@ void fmplayer_file_load(struct fmdriver_work *work, struct fmplayer_file *fmfile #define MSG_FILE_ERR_FILEIO "File I/O error" #define MSG_FILE_ERR_BADFILE_SIZE "Invalid file size" #define MSG_FILE_ERR_BADFILE "Invalid file format" +#define MSG_FILE_ERR_NOTFOUND "File not found" #define XWIDE(x) L ## x #define WIDE(x) XWIDE(x) @@ -151,6 +260,7 @@ const char *fmplayer_file_strerror(enum fmplayer_file_error error) { MSG_FILE_ERR_FILEIO, MSG_FILE_ERR_BADFILE_SIZE, MSG_FILE_ERR_BADFILE, + MSG_FILE_ERR_NOTFOUND, }; return errtable[error]; } @@ -163,6 +273,7 @@ const wchar_t *fmplayer_file_strerror_w(enum fmplayer_file_error error) { WIDE(MSG_FILE_ERR_FILEIO), WIDE(MSG_FILE_ERR_BADFILE_SIZE), WIDE(MSG_FILE_ERR_BADFILE), + WIDE(MSG_FILE_ERR_NOTFOUND), }; return errtable[error]; } diff --git a/common/fmplayer_file.h b/common/fmplayer_file.h index fd7c53e..143c349 100644 --- a/common/fmplayer_file.h +++ b/common/fmplayer_file.h @@ -5,6 +5,7 @@ #include "fmdriver/fmdriver.h" #include "fmdriver/fmdriver_pmd.h" #include "fmdriver/fmdriver_fmp.h" +#include "libopna/opnadrum.h" enum fmplayer_file_type { FMPLAYER_FILE_TYPE_PMD, @@ -17,6 +18,7 @@ enum fmplayer_file_error { FMPLAYER_FILE_ERR_FILEIO, FMPLAYER_FILE_ERR_BADFILE_SIZE, FMPLAYER_FILE_ERR_BADFILE, + FMPLAYER_FILE_ERR_NOTFOUND, FMPLAYER_FILE_ERR_COUNT }; @@ -36,7 +38,7 @@ struct fmplayer_file { }; struct fmplayer_file *fmplayer_file_alloc(const void *path, enum fmplayer_file_error *error); void fmplayer_file_free(const struct fmplayer_file *fmfile); -void fmplayer_file_load(struct fmdriver_work *work, struct fmplayer_file *fmfile); +void fmplayer_file_load(struct fmdriver_work *work, struct fmplayer_file *fmfile, int loopcnt); const char *fmplayer_file_strerror(enum fmplayer_file_error error); const wchar_t *fmplayer_file_strerror_w(enum fmplayer_file_error error); diff --git a/common/fmplayer_file_gio.c b/common/fmplayer_file_gio.c index 5e9dd84..a2b52d2 100644 --- a/common/fmplayer_file_gio.c +++ b/common/fmplayer_file_gio.c @@ -27,7 +27,7 @@ static void *fileread(GFile *f, size_t maxsize, size_t *filesize, enum fmplayer_ } fstream = g_file_read(f, 0, 0); if (!fstream) { - if (error) *error = FMPLAYER_FILE_ERR_FILEIO; + if (error) *error = FMPLAYER_FILE_ERR_NOTFOUND; goto err; } buf = malloc(filelen); @@ -107,7 +107,7 @@ void *fmplayer_fileread(const void *pathptr, const char *pcmname, const char *ex g_object_unref(G_OBJECT(pcmfile)); g_object_unref(G_OBJECT(info)); } - if (error) *error = FMPLAYER_FILE_ERR_FILEIO; + if (error) *error = FMPLAYER_FILE_ERR_NOTFOUND; err: if (direnum) g_object_unref(G_OBJECT(direnum)); if (dir) g_object_unref(G_OBJECT(dir)); diff --git a/common/fmplayer_file_unix.c b/common/fmplayer_file_unix.c new file mode 100644 index 0000000..d2855c3 --- /dev/null +++ b/common/fmplayer_file_unix.c @@ -0,0 +1,127 @@ + +#define _POSIX_C_SOURCE 200809l +#include "common/fmplayer_file.h" +#include +#include +#include +#include +#include + +static void *fileread(const char *path, size_t maxsize, size_t *filesize, enum fmplayer_file_error *error) { + FILE *f = 0; + void *buf = 0; + + f = fopen(path, "rb"); + if (!f) { + if (error) *error = FMPLAYER_FILE_ERR_NOTFOUND; + goto err; + } + if (fseek(f, 0, SEEK_END)) { + *error = FMPLAYER_FILE_ERR_FILEIO; + goto err; + } + size_t fsize; + { + long ssize = ftell(f); + if (ssize < 0) { + *error = FMPLAYER_FILE_ERR_FILEIO; + goto err; + } + if (maxsize && ((size_t)ssize > maxsize)) { + *error = FMPLAYER_FILE_ERR_BADFILE_SIZE; + goto err; + } + fsize = ssize; + } + if (fseek(f, 0, SEEK_SET)) { + *error = FMPLAYER_FILE_ERR_FILEIO; + goto err; + } + buf = malloc(fsize); + if (!buf) { + if (error) *error = FMPLAYER_FILE_ERR_NOMEM; + goto err; + } + if (fread(buf, 1, fsize, f) != fsize) { + *error = FMPLAYER_FILE_ERR_FILEIO; + goto err; + } + fclose(f); + *filesize = fsize; + return buf; +err: + free(buf); + if (f) fclose(f); + return 0; +} + +void *fmplayer_fileread(const void *pathptr, const char *pcmname, const char *extension, + size_t maxsize, size_t *filesize, enum fmplayer_file_error *error) { + const char *path = pathptr; + if (!pcmname) return fileread(path, maxsize, filesize, error); + + char *namebuf = 0; + char *dirbuf = 0; + DIR *d = 0; + + if (extension) { + size_t namebuflen = strlen(pcmname) + strlen(extension) + 1; + namebuf = malloc(namebuflen); + if (!namebuf) { + if (error) *error = FMPLAYER_FILE_ERR_NOMEM; + goto err; + } + strcpy(namebuf, pcmname); + strcat(namebuf, extension); + pcmname = namebuf; + } + + const char *slash = strrchr(path, '/'); + const char *dirpath = 0; + if (slash) { + dirbuf = strdup(path); + if (!dirbuf) { + if (error) *error = FMPLAYER_FILE_ERR_NOMEM; + goto err; + } + *strrchr(dirbuf, '/') = 0; + dirpath = dirbuf; + } else { + dirpath = "."; + } + d = opendir(dirpath); + if (!d) { + *error = FMPLAYER_FILE_ERR_FILEIO; + goto err; + } + const struct dirent *de; + while ((de = readdir(d))) { + if (!strcasecmp(de->d_name, pcmname)) { + size_t pathlen = strlen(dirpath) + 1 + strlen(de->d_name) + 1; + char *pcmpath = malloc(pathlen); + if (!pcmpath) { + if (error) *error = FMPLAYER_FILE_ERR_NOMEM; + goto err; + } + strcpy(pcmpath, dirpath); + strcat(pcmpath, "/"); + strcat(pcmpath, de->d_name); + void *buf = fileread(pcmpath, maxsize, filesize, error); + free(pcmpath); + closedir(d); + free(dirbuf); + free(namebuf); + return buf; + } + } + if (error) *error = FMPLAYER_FILE_ERR_NOTFOUND; +err: + if (d) closedir(d); + free(dirbuf); + free(namebuf); + return 0; +} + +void *fmplayer_path_dup(const void *path) { + return strdup(path); +} diff --git a/common/fmplayer_file_win.c b/common/fmplayer_file_win.c index 3397bcc..2910953 100644 --- a/common/fmplayer_file_win.c +++ b/common/fmplayer_file_win.c @@ -12,7 +12,7 @@ static void *fileread(const wchar_t *path, void *buf = 0; file = CreateFile(path, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (file == INVALID_HANDLE_VALUE) { - if (error) *error = FMPLAYER_FILE_ERR_FILEIO; + if (error) *error = FMPLAYER_FILE_ERR_NOTFOUND; goto err; } LARGE_INTEGER li; diff --git a/common/fmplayer_work_opna.c b/common/fmplayer_work_opna.c new file mode 100644 index 0000000..b3b0c69 --- /dev/null +++ b/common/fmplayer_work_opna.c @@ -0,0 +1,63 @@ +#include "fmplayer_common.h" +#include "fmdriver/fmdriver.h" +#include "fmdriver/ppz8.h" +#include "libopna/opna.h" +#include "libopna/opnatimer.h" +#include + +enum { + SRATE = 55467, + PPZ8MIX = 0xa000, +}; + +static void opna_writereg_libopna(struct fmdriver_work *work, unsigned addr, unsigned data) { + struct opna_timer *timer = (struct opna_timer *)work->opna; + opna_timer_writereg(timer, addr, data); +} + +static unsigned opna_readreg_libopna(struct fmdriver_work *work, unsigned addr) { + struct opna_timer *timer = (struct opna_timer *)work->opna; + return opna_readreg(timer->opna, addr); +} + +static uint8_t opna_status_libopna(struct fmdriver_work *work, bool a1) { + struct opna_timer *timer = (struct opna_timer *)work->opna; + uint8_t status = opna_timer_status(timer); + if (!a1) { + status &= 0x83; + } + return status; +} + +static void opna_int_cb(void *userptr) { + struct fmdriver_work *work = (struct fmdriver_work *)userptr; + work->driver_opna_interrupt(work); +} + +static void opna_mix_cb(void *userptr, int16_t *buf, unsigned samples) { + struct ppz8 *ppz8 = (struct ppz8 *)userptr; + ppz8_mix(ppz8, buf, samples); +} + +void fmplayer_init_work_opna( + struct fmdriver_work *work, + struct ppz8 *ppz8, + struct opna *opna, + struct opna_timer *timer, + void *adpcm_ram +) { + opna_reset(opna); + fmplayer_drum_rom_load(&opna->drum); + opna_adpcm_set_ram_256k(&opna->adpcm, adpcm_ram); + opna_timer_reset(timer, opna); + ppz8_init(ppz8, SRATE, PPZ8MIX); + memset(work, 0, sizeof(*work)); + work->opna_writereg = opna_writereg_libopna; + work->opna_readreg = opna_readreg_libopna; + work->opna_status = opna_status_libopna; + work->opna = timer; + work->ppz8 = ppz8; + work->ppz8_functbl = &ppz8_functbl; + opna_timer_set_int_callback(timer, opna_int_cb, work); + opna_timer_set_mix_callback(timer, opna_mix_cb, ppz8); +} -- cgit v1.2.3