aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/fmplayer_common.h17
-rw-r--r--common/fmplayer_drumrom_unix.c53
-rw-r--r--common/fmplayer_drumrom_win.c49
-rw-r--r--common/fmplayer_file.c113
-rw-r--r--common/fmplayer_file.h4
-rw-r--r--common/fmplayer_file_gio.c4
-rw-r--r--common/fmplayer_file_unix.c127
-rw-r--r--common/fmplayer_file_win.c2
-rw-r--r--common/fmplayer_work_opna.c63
9 files changed, 427 insertions, 5 deletions
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 <stddef.h>
+#include <stdbool.h>
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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 <windows.h>
+#include <shlwapi.h>
+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 <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <string.h>
+#include <strings.h>
+
+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 <string.h>
+
+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);
+}