aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/fmplayer_common.h8
-rw-r--r--common/fmplayer_file.c168
-rw-r--r--common/fmplayer_file.h52
-rw-r--r--common/fmplayer_file_gio.c120
-rw-r--r--common/fmplayer_file_win.c87
-rw-r--r--gtk/Makefile.am3
-rw-r--r--gtk/main.c285
-rw-r--r--win32/amd64/Makefile4
-rw-r--r--win32/fmplayer.mak4
-rw-r--r--win32/main.c236
-rw-r--r--win32/toneview.c4
-rw-r--r--win32/x86/Makefile5
12 files changed, 561 insertions, 415 deletions
diff --git a/common/fmplayer_common.h b/common/fmplayer_common.h
new file mode 100644
index 0000000..5394293
--- /dev/null
+++ b/common/fmplayer_common.h
@@ -0,0 +1,8 @@
+#ifndef MYON_FMPLAYER_COMMON_H_INCLUDED
+#define MYON_FMPLAYER_COMMON_H_INCLUDED
+
+#include <stddef.h>
+
+void *fmplayer_load_data(const char *name, size_t size);
+
+#endif // MYON_FMPLAYER_COMMON_H_INCLUDED
diff --git a/common/fmplayer_file.c b/common/fmplayer_file.c
new file mode 100644
index 0000000..1080625
--- /dev/null
+++ b/common/fmplayer_file.c
@@ -0,0 +1,168 @@
+#include "common/fmplayer_file.h"
+#include <string.h>
+#include <stdlib.h>
+
+void fmplayer_file_free(const struct fmplayer_file *fmfileptr) {
+ struct fmplayer_file *fmfile = (struct fmplayer_file *)fmfileptr;
+ if (!fmfile) return;
+ free(fmfile->path);
+ free(fmfile->buf);
+ free(fmfile->ppzbuf[0]);
+ free(fmfile->ppzbuf[1]);
+ free(fmfile);
+}
+
+struct fmplayer_file *fmplayer_file_alloc(const void *path, enum fmplayer_file_error *error) {
+ struct fmplayer_file *fmfile = calloc(1, sizeof(*fmfile));
+ if (!fmfile) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ fmfile->path = fmplayer_path_dup(path);
+ if (!fmfile->path) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ size_t filesize;
+ fmfile->buf = fmplayer_fileread(path, 0, 0, 0xffff, &filesize, error);
+ if (!fmfile->buf) goto err;
+ if (pmd_load(&fmfile->driver.pmd, fmfile->buf, filesize)) {
+ fmfile->type = FMPLAYER_FILE_TYPE_PMD;
+ return fmfile;
+ }
+ memset(&fmfile->driver, 0, sizeof(fmfile->driver));
+ if (fmp_load(&fmfile->driver.fmp, fmfile->buf, filesize)) {
+ fmfile->type = FMPLAYER_FILE_TYPE_FMP;
+ return fmfile;
+ }
+ if (error) *error = FMPLAYER_FILE_ERR_BADFILE;
+err:
+ fmplayer_file_free(fmfile);
+ return 0;
+}
+
+static void loadppc(struct fmdriver_work *work, struct fmplayer_file *fmfile) {
+ if (!strlen(fmfile->driver.pmd.ppcfile)) return;
+ size_t filesize;
+ void *ppcbuf = fmplayer_fileread(fmfile->path, fmfile->driver.pmd.ppcfile, ".PPC", 0, &filesize, 0);
+ if (ppcbuf) {
+ fmfile->pmd_ppc_err = !pmd_ppc_load(work, ppcbuf, filesize);
+ free(ppcbuf);
+ } else {
+ fmfile->pmd_ppc_err = true;
+ }
+}
+
+static bool loadppzpvi(struct fmdriver_work *work, struct fmplayer_file *fmfile, const char *name) {
+ size_t filesize;
+ void *pvibuf = 0, *ppzbuf = 0;
+ pvibuf = fmplayer_fileread(fmfile->path, name, ".PVI", 0, &filesize, 0);
+ if (!pvibuf) goto err;
+ ppzbuf = calloc(ppz8_pvi_decodebuf_samples(filesize), 2);
+ if (!ppzbuf) goto err;
+ if (!ppz8_pvi_load(work->ppz8, 0, pvibuf, filesize, ppzbuf)) goto err;
+ free(pvibuf);
+ free(fmfile->ppzbuf[0]);
+ fmfile->ppzbuf[0] = ppzbuf;
+ return true;
+err:
+ free(ppzbuf);
+ free(pvibuf);
+ return false;
+}
+
+static bool loadppzpzi(struct fmdriver_work *work, struct fmplayer_file *fmfile, const char *name) {
+ size_t filesize;
+ void *pzibuf = 0, *ppzbuf = 0;
+ pzibuf = fmplayer_fileread(fmfile->path, name, ".PZI", 0, &filesize, 0);
+ if (!pzibuf) goto err;
+ ppzbuf = calloc(ppz8_pzi_decodebuf_samples(filesize), 2);
+ if (!ppzbuf) goto err;
+ if (!ppz8_pzi_load(work->ppz8, 0, pzibuf, filesize, ppzbuf)) goto err;
+ free(pzibuf);
+ free(fmfile->ppzbuf[0]);
+ fmfile->ppzbuf[0] = ppzbuf;
+ return true;
+err:
+ free(ppzbuf);
+ free(pzibuf);
+ return false;
+}
+
+static void loadpmdppz(struct fmdriver_work *work, struct fmplayer_file *fmfile) {
+ const char *ppzfile = fmfile->driver.pmd.ppzfile;
+ if (!strlen(ppzfile)) return;
+ if (!loadppzpvi(work, fmfile, ppzfile) && !loadppzpzi(work, fmfile, ppzfile)) {
+ fmfile->pmd_ppz_err = true;
+ }
+}
+
+static void loadpvi(struct fmdriver_work *work, struct fmplayer_file *fmfile) {
+ const char *pvifile = fmfile->driver.fmp.pvi_name;
+ if (!strlen(pvifile)) return;
+ size_t filesize;
+ void *pvibuf = fmplayer_fileread(fmfile->path, pvifile, ".PVI", 0, &filesize, 0);
+ if (pvibuf) {
+ fmfile->fmp_pvi_err = !fmp_adpcm_load(work, pvibuf, filesize);
+ free(pvibuf);
+ } else {
+ fmfile->fmp_pvi_err = true;
+ }
+}
+
+static void loadfmpppz(struct fmdriver_work *work, struct fmplayer_file *fmfile) {
+ const char *pvifile = fmfile->driver.fmp.ppz_name;
+ if (!strlen(pvifile)) return;
+ fmfile->fmp_ppz_err = !loadppzpvi(work, fmfile, pvifile);
+}
+
+void fmplayer_file_load(struct fmdriver_work *work, struct fmplayer_file *fmfile) {
+ switch (fmfile->type) {
+ case FMPLAYER_FILE_TYPE_PMD:
+ pmd_init(work, &fmfile->driver.pmd);
+ loadppc(work, fmfile);
+ loadpmdppz(work, fmfile);
+ work->pcmerror[0] = fmfile->pmd_ppc_err;
+ work->pcmerror[1] = fmfile->pmd_ppz_err;
+ break;
+ case FMPLAYER_FILE_TYPE_FMP:
+ fmp_init(work, &fmfile->driver.fmp);
+ loadpvi(work, fmfile);
+ loadfmpppz(work, fmfile);
+ work->pcmerror[0] = fmfile->fmp_pvi_err;
+ work->pcmerror[1] = fmfile->fmp_ppz_err;
+ break;
+ }
+}
+#define MSG_FILE_ERR_UNKNOWN "Unknown error"
+#define MSG_FILE_ERR_NOMEM "Memory allocation error"
+#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 XWIDE(x) L ## x
+#define WIDE(x) XWIDE(x)
+
+const char *fmplayer_file_strerror(enum fmplayer_file_error error) {
+ if (error >= FMPLAYER_FILE_ERR_COUNT) return MSG_FILE_ERR_UNKNOWN;
+ static const char *errtable[] = {
+ "",
+ MSG_FILE_ERR_NOMEM,
+ MSG_FILE_ERR_FILEIO,
+ MSG_FILE_ERR_BADFILE_SIZE,
+ MSG_FILE_ERR_BADFILE,
+ };
+ return errtable[error];
+}
+
+const wchar_t *fmplayer_file_strerror_w(enum fmplayer_file_error error) {
+ if (error >= FMPLAYER_FILE_ERR_COUNT) return WIDE(MSG_FILE_ERR_UNKNOWN);
+ static const wchar_t *errtable[] = {
+ L"",
+ WIDE(MSG_FILE_ERR_NOMEM),
+ WIDE(MSG_FILE_ERR_FILEIO),
+ WIDE(MSG_FILE_ERR_BADFILE_SIZE),
+ WIDE(MSG_FILE_ERR_BADFILE),
+ };
+ return errtable[error];
+}
diff --git a/common/fmplayer_file.h b/common/fmplayer_file.h
new file mode 100644
index 0000000..fd7c53e
--- /dev/null
+++ b/common/fmplayer_file.h
@@ -0,0 +1,52 @@
+#ifndef MYON_FMPLAYER_FILE_H_INCLUDED
+#define MYON_FMPLAYER_FILE_H_INCLUDED
+
+#include <stddef.h>
+#include "fmdriver/fmdriver.h"
+#include "fmdriver/fmdriver_pmd.h"
+#include "fmdriver/fmdriver_fmp.h"
+
+enum fmplayer_file_type {
+ FMPLAYER_FILE_TYPE_PMD,
+ FMPLAYER_FILE_TYPE_FMP
+};
+
+enum fmplayer_file_error {
+ FMPLAYER_FILE_ERR_OK,
+ FMPLAYER_FILE_ERR_NOMEM,
+ FMPLAYER_FILE_ERR_FILEIO,
+ FMPLAYER_FILE_ERR_BADFILE_SIZE,
+ FMPLAYER_FILE_ERR_BADFILE,
+ FMPLAYER_FILE_ERR_COUNT
+};
+
+struct fmplayer_file {
+ void *path;
+ enum fmplayer_file_type type;
+ union {
+ struct driver_pmd pmd;
+ struct driver_fmp fmp;
+ } driver;
+ bool pmd_ppc_err;
+ bool pmd_ppz_err;
+ bool fmp_pvi_err;
+ bool fmp_ppz_err;
+ void *buf;
+ void *ppzbuf[2];
+};
+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);
+
+const char *fmplayer_file_strerror(enum fmplayer_file_error error);
+const wchar_t *fmplayer_file_strerror_w(enum fmplayer_file_error error);
+
+// path: wchar_t* on windows, else char*
+// examples:
+// fmplayer_fileread("/home/foo/bar.mz", 0, 0, &filesize);
+// fmplayer_fileread("/home/foo/bar.mz", "BAZ", ".PVI", &filesize);
+void *fmplayer_fileread(const void *path, const char *pcmname, const char *extension, size_t maxsize, size_t *filesize, enum fmplayer_file_error *error);
+
+void *fmplayer_path_dup(const void *path);
+
+#endif // MYON_FMPLAYER_FILE_H_INCLUDED
diff --git a/common/fmplayer_file_gio.c b/common/fmplayer_file_gio.c
new file mode 100644
index 0000000..053e4ae
--- /dev/null
+++ b/common/fmplayer_file_gio.c
@@ -0,0 +1,120 @@
+#include "common/fmplayer_file.h"
+#include <gio/gio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void *fileread(GFile *f, size_t maxsize, size_t *filesize, enum fmplayer_file_error *error) {
+ GFileInfo *finfo = 0;
+ GFileInputStream *fstream = 0;
+ void *buf = 0;
+ finfo = g_file_query_info(f, G_FILE_ATTRIBUTE_STANDARD_SIZE, 0, 0, 0);
+ if (!finfo) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ gsize filelen;
+ {
+ goffset sfilelen = g_file_info_get_size(finfo);
+ if (sfilelen < 0) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ filelen = sfilelen;
+ }
+ if (maxsize && (filelen > maxsize)) {
+ if (error) *error = FMPLAYER_FILE_ERR_BADFILE_SIZE;
+ goto err;
+ }
+ fstream = g_file_read(f, 0, 0);
+ if (!fstream) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ buf = malloc(filelen);
+ if (!buf) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ gsize fileread;
+ g_input_stream_read_all(G_INPUT_STREAM(fstream), buf, filelen, &fileread, 0, 0);
+ if (fileread != filelen) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ *filesize = filelen;
+ g_object_unref(G_OBJECT(fstream));
+ g_object_unref(G_OBJECT(finfo));
+ return buf;
+err:
+ free(buf);
+ if (fstream) g_object_unref(G_OBJECT(fstream));
+ if (finfo) g_object_unref(G_OBJECT(finfo));
+ 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) {
+ GFile *file = 0, *dir = 0;
+ GFileEnumerator *direnum = 0;
+ char *pcmnamebuf = 0;
+ const char *uri = pathptr;
+ file = g_file_new_for_uri(uri);
+ if (!pcmname) {
+ void *buf = fileread(file, maxsize, filesize, error);
+ g_object_unref(G_OBJECT(file));
+ return buf;
+ }
+ if (extension) {
+ size_t namebuflen = strlen(pcmname) + strlen(extension) + 1;
+ pcmnamebuf = malloc(namebuflen);
+ if (!pcmnamebuf) goto err;
+ strcpy(pcmnamebuf, pcmname);
+ strcat(pcmnamebuf, extension);
+ pcmname = pcmnamebuf;
+ }
+
+ dir = g_file_get_parent(file);
+ if (!dir) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ direnum = g_file_enumerate_children(dir,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ 0, 0);
+ if (!direnum) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ for (;;) {
+ GFileInfo *info;
+ GFile *pcmfile;
+ if (!g_file_enumerator_iterate(direnum, &info, &pcmfile, 0, 0)) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ if (!info || !pcmfile) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ if (!strcasecmp(g_file_info_get_name(info), pcmname)) {
+ void *buf = fileread(pcmfile, maxsize, filesize, error);
+ g_object_unref(G_OBJECT(direnum));
+ g_object_unref(G_OBJECT(dir));
+ g_object_unref(G_OBJECT(file));
+ free(pcmnamebuf);
+ return buf;
+ }
+ }
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+err:
+ if (direnum) g_object_unref(G_OBJECT(direnum));
+ if (dir) g_object_unref(G_OBJECT(dir));
+ g_object_unref(G_OBJECT(file));
+ free(pcmnamebuf);
+ 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
new file mode 100644
index 0000000..3397bcc
--- /dev/null
+++ b/common/fmplayer_file_win.c
@@ -0,0 +1,87 @@
+#include "common/fmplayer_file.h"
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <shlwapi.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+static void *fileread(const wchar_t *path,
+ size_t maxsize, size_t *filesize,
+ enum fmplayer_file_error *error) {
+ HANDLE file = INVALID_HANDLE_VALUE;
+ 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;
+ goto err;
+ }
+ LARGE_INTEGER li;
+ if (!GetFileSizeEx(file, &li)) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ if (li.HighPart || (maxsize && (li.LowPart > maxsize))) {
+ if (error) *error = FMPLAYER_FILE_ERR_BADFILE_SIZE;
+ goto err;
+ }
+ buf = malloc(li.LowPart);
+ if (!buf) {
+ if (error) *error = FMPLAYER_FILE_ERR_NOMEM;
+ goto err;
+ }
+ DWORD readlen;
+ if (!ReadFile(file, buf, li.LowPart, &readlen, 0) || (readlen != li.LowPart)) {
+ if (error) *error = FMPLAYER_FILE_ERR_FILEIO;
+ goto err;
+ }
+ *filesize = li.QuadPart;
+ CloseHandle(file);
+ return buf;
+err:
+ free(buf);
+ if (file != INVALID_HANDLE_VALUE) CloseHandle(file);
+ 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 wchar_t *path = (const wchar_t *)pathptr;
+ wchar_t *wpcmpath = 0, *wpcmname = 0, *wpcmextname = 0;
+ if (!pcmname) return fileread(path, maxsize, filesize, error);
+ int wpcmnamelen = MultiByteToWideChar(932, 0, pcmname, -1, 0, 0);
+ if (!wpcmnamelen) goto err;
+ if (extension) {
+ int wextensionlen = MultiByteToWideChar(932, 0, extension, -1, 0, 0);
+ if (!wextensionlen) goto err;
+ wpcmnamelen += wextensionlen;
+ wpcmnamelen -= 1;
+ wpcmextname = malloc(wextensionlen * sizeof(wchar_t));
+ if (!wpcmextname) goto err;
+ if (!MultiByteToWideChar(932, 0, extension, -1, wpcmextname, wextensionlen)) goto err;
+ }
+ wpcmname = malloc(wpcmnamelen * sizeof(wchar_t));
+ if (!wpcmname) goto err;
+ if (!MultiByteToWideChar(932, 0, pcmname, -1, wpcmname, wpcmnamelen)) goto err;
+ if (wpcmextname) wcscat(wpcmname, wpcmextname);
+ wpcmpath = malloc((wcslen(path) + 1 + wcslen(wpcmname) + 1) * sizeof(wchar_t));
+ if (!wpcmpath) goto err;
+ wcscpy(wpcmpath, path);
+ PathRemoveFileSpec(wpcmpath);
+ wcscat(wpcmpath, L"\\");
+ wcscat(wpcmpath, wpcmname);
+ void *buf = fileread(wpcmpath, maxsize, filesize, error);
+ free(wpcmextname);
+ free(wpcmname);
+ free(wpcmpath);
+ return buf;
+err:
+ free(wpcmextname);
+ free(wpcmname);
+ free(wpcmpath);
+ return 0;
+}
+
+void *fmplayer_path_dup(const void *pathptr) {
+ const wchar_t *path = (const wchar_t *)pathptr;
+ return wcsdup(path);
+}
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 970bf73..174f5e9 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -18,7 +18,10 @@ FMDSP_SRC=../fmdsp/fmdsp.c \
fmplayer_SOURCES=main.c \
toneview.c \
+ oscilloview.c \
../tonedata/tonedata.c \
+ ../common/fmplayer_file.c \
+ ../common/fmplayer_file_gio.c \
$(LIBOPNA_SRC) \
$(FMDRIVER_SRC) \
$(FMDSP_SRC)
diff --git a/gtk/main.c b/gtk/main.c
index cd8c9ab..dd1dd18 100644
--- a/gtk/main.c
+++ b/gtk/main.c
@@ -7,6 +7,7 @@
#include <cairo.h>
#include <stdatomic.h>
+#include "common/fmplayer_file.h"
#include "fmdriver/fmdriver_fmp.h"
#include "fmdriver/fmdriver_pmd.h"
#include "fmdriver/ppz8.h"
@@ -14,6 +15,8 @@
#include "libopna/opnatimer.h"
#include "fmdsp/fmdsp.h"
#include "toneview.h"
+#include "oscillo/oscillo.h"
+#include "oscilloview.h"
#define DATADIR "/.local/share/fmplayer/"
//#define FMDSP_2X
@@ -24,11 +27,6 @@ enum {
AUDIOBUFLEN = 0,
};
-union drivers {
- struct driver_pmd pmd;
- struct driver_fmp fmp;
-};
-
static struct {
GtkWidget *mainwin;
bool pa_initialized;
@@ -42,15 +40,15 @@ static struct {
char drum_rom[OPNA_ROM_SIZE];
bool drum_rom_loaded;
char adpcm_ram[OPNA_ADPCM_RAM_SIZE];
- union drivers *driver;
+ struct fmplayer_file *fmfile;
void *data;
- void *ppzbuf;
uint8_t vram[PC98_W*PC98_H];
struct fmdsp_font font98;
uint8_t font98data[FONT_ROM_FILESIZE];
void *vram32;
int vram32_stride;
const char *current_uri;
+ struct oscillodata oscillodata_audiothread[LIBOPNA_OSCILLO_TRACK_COUNT];
} g;
static void quit(void) {
@@ -58,9 +56,7 @@ static void quit(void) {
Pa_CloseStream(g.pastream);
}
if (g.pa_initialized) Pa_Terminate();
- free(g.driver);
- free(g.data);
- free(g.ppzbuf);
+ fmplayer_file_free(g.fmfile);
gtk_main_quit();
}
@@ -76,6 +72,10 @@ static void on_tone_view(GtkMenuItem *menuitem, gpointer ptr) {
show_toneview();
}
+static void on_oscillo_view(GtkMenuItem *menuitem, gpointer ptr) {
+ show_oscilloview();
+}
+
static void msgbox_err(const char *msg) {
GtkWidget *d = gtk_message_dialog_new(GTK_WINDOW(g.mainwin), GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
@@ -92,13 +92,18 @@ static int pastream_cb(const void *inptr, void *outptr, unsigned long frames,
struct opna_timer *timer = (struct opna_timer *)userdata;
int16_t *buf = (int16_t *)outptr;
memset(outptr, 0, sizeof(int16_t)*frames*2);
- opna_timer_mix(timer, buf, frames);
+ opna_timer_mix_oscillo(timer, buf, frames, g.oscillodata_audiothread);
if (!atomic_flag_test_and_set_explicit(
&toneview_g.flag, memory_order_acquire)) {
tonedata_from_opna(&toneview_g.tonedata, &g.opna);
atomic_flag_clear_explicit(&toneview_g.flag, memory_order_release);
- }
+ }
+ if (!atomic_flag_test_and_set_explicit(
+ &oscilloview_g.flag, memory_order_acquire)) {
+ memcpy(oscilloview_g.oscillodata, g.oscillodata_audiothread, sizeof(oscilloview_g.oscillodata));
+ atomic_flag_clear_explicit(&oscilloview_g.flag, memory_order_release);
+ }
return paContinue;
}
@@ -131,153 +136,6 @@ static uint8_t opna_status_libopna(struct fmdriver_work *work, bool a1) {
return status;
}
-static GFileInputStream *pcmfilesearch(GFile *dir, const char *name) {
- char *name_l = malloc(strlen(name));
- if (name_l) {
- strcpy(name_l, name);
- // TODO: not SJIS aware
- for (char *c = name_l; *c; c++) {
- if (('A' <= *c) && (*c <= 'Z')) {
- *c += ('a' - 'A');
- }
- }
- }
- GFile *file = g_file_get_child(dir, name);
- GFileInputStream *stream = g_file_read(file, 0, 0);
- g_object_unref(G_OBJECT(file));
- if (stream) {
- free(name_l);
- return stream;
- }
- if (name_l) {
- file = g_file_get_child(dir, name_l);
- free(name_l);
- stream = g_file_read(file, 0, 0);
- g_object_unref(G_OBJECT(file));
- if (stream) return stream;
- }
- return 0;
-}
-
-static GFileInputStream *extsearch(GFile *dir, const char *base, const char *ext) {
- char *name = malloc(strlen(base) + strlen(ext) + 1);
- if (!name) return 0;
- strcpy(name, base);
- strcat(name, ext);
- GFileInputStream *ret = pcmfilesearch(dir, name);
- free(name);
- return ret;
-}
-
-static bool loadpvi(struct fmdriver_work *work,
- struct driver_fmp *fmp,
- GFile *dir) {
- // no need to load, always success
- if(strlen(fmp->pvi_name) == 0) return true;
- GFileInputStream *pvistream = extsearch(dir, fmp->pvi_name, ".PVI");
- if (!pvistream) goto err;
- void *data = malloc(OPNA_ADPCM_RAM_SIZE);
- if (!data) goto err_stream;
- gsize read;
- if (!g_input_stream_read_all(
- G_INPUT_STREAM(pvistream), data, OPNA_ADPCM_RAM_SIZE, &read, 0, 0
- )) goto err_data;
- if (!fmp_adpcm_load(work, data, OPNA_ADPCM_RAM_SIZE)) goto err_data;
- free(data);
- g_object_unref(pvistream);
- return true;
-err_data:
- free(data);
-err_stream:
- g_object_unref(G_OBJECT(pvistream));
-err:
- return false;
-}
-
-static bool loadppzpvi(struct fmdriver_work *work,
- struct driver_fmp *fmp,
- GFile *dir) {
- // no need to load, always success
- if(strlen(fmp->ppz_name) == 0) return true;
- GFileInputStream *pvistream = extsearch(dir, fmp->ppz_name, ".PVI");
- if (!pvistream) goto err;
- GFileInfo *pviinfo = g_file_input_stream_query_info(
- pvistream, G_FILE_ATTRIBUTE_STANDARD_SIZE,
- 0, 0);
- if (!pviinfo) goto err_stream;
- gsize fsize;
- {
- goffset sfsize = g_file_info_get_size(pviinfo);
- if (sfsize < 0) goto err_info;
- fsize = sfsize;
- }
- void *data = malloc(fsize);
- if (!data) goto err_info;
- gsize readsize;
- g_input_stream_read_all(G_INPUT_STREAM(pvistream),
- data, fsize, &readsize, 0, 0);
- if (readsize != fsize) goto err_memory;
- int16_t *decbuf = calloc(ppz8_pvi_decodebuf_samples(fsize), sizeof(int16_t));
- if (!decbuf) goto err_memory;
- if (!ppz8_pvi_load(work->ppz8, 0, data, fsize, decbuf)) goto err_decbuf;
- free(g.ppzbuf);
- g.ppzbuf = decbuf;
- free(data);
- g_object_unref(G_OBJECT(pviinfo));
- g_object_unref(G_OBJECT(pvistream));
- return true;
-err_decbuf:
- free(decbuf);
-err_memory:
- free(data);
-err_info:
- g_object_unref(pviinfo);
-err_stream:
- g_object_unref(pvistream);
-err:
- return false;
-}
-
-static bool loadppc(struct fmdriver_work *work,
- struct driver_pmd *pmd,
- GFile *dir) {
- // no need to load, always success
- if(strlen(pmd->ppcfile) == 0) return true;
- fprintf(stderr, "PPC: %s\n", pmd->ppcfile);
- GFileInputStream *stream = extsearch(dir, pmd->ppcfile, ".PPC");
- if (!stream) goto err;
- GFileInfo *info = g_file_input_stream_query_info(
- stream, G_FILE_ATTRIBUTE_STANDARD_SIZE,
- 0, 0);
- if (!info) goto err_stream;
- gsize fsize;
- {
- goffset sfsize = g_file_info_get_size(info);
- if (sfsize < 0) goto err_info;
- fsize = sfsize;
- }
- void *data = malloc(fsize);
- if (!data) goto err_info;
- gsize read;
- if (!g_input_stream_read_all(
- G_INPUT_STREAM(stream), data, fsize, &read, 0, 0
- )) goto err_data;
- if (read != fsize) goto err_data;
- if (!pmd_ppc_load(work, data, fsize)) goto err_data;
- free(data);
- g_object_unref(G_OBJECT(info));
- g_object_unref(G_OBJECT(stream));
- return true;
-err_data:
- free(data);
-err_info:
- g_object_unref(G_OBJECT(info));
-err_stream:
- g_object_unref(G_OBJECT(stream));
-err:
- return false;
-}
-
static void load_drumrom(void) {
const char *path = "ym2608_adpcm_rom.bin";
const char *home = getenv("HOME");
@@ -343,82 +201,41 @@ err:
}
static bool openfile(const char *uri) {
- enum {
- DRIVER_PMD,
- DRIVER_FMP
- } driver_type;
+ struct fmplayer_file *fmfile = 0;
if (!g.pa_initialized) {
msgbox_err("Could not initialize Portaudio");
goto err;
}
- GFile *fmfile = g_file_new_for_uri(uri);
- GFileInfo *fminfo = g_file_query_info(
- fmfile, G_FILE_ATTRIBUTE_STANDARD_SIZE,
- 0, 0, 0
- );
- if (!fminfo) {
- msgbox_err("Cannot get size information for file");
- goto err_file;
- }
- gsize filelen;
- {
- goffset sfilelen = g_file_info_get_size(fminfo);
- if (sfilelen < 0) {
- goto err_info;
- }
- filelen = sfilelen;
- }
- GFileInputStream *fmstream = g_file_read(fmfile, 0, 0);
- if (!fmstream) {
- msgbox_err("cannot open file for read");
- goto err_info;
- }
- void *fmbuf = malloc(filelen);
- if (!fmbuf) {
- msgbox_err("cannot allocate memory for file");
- goto err_stream;
- }
- gsize fileread;
- g_input_stream_read_all(
- G_INPUT_STREAM(fmstream), fmbuf, filelen, &fileread, 0, 0);
- if (fileread != filelen) {
- msgbox_err("cannot read file");
- goto err_buf;
- }
- union drivers *driver = calloc(1, sizeof(*driver));
- if (!driver) {
- msgbox_err("cannot allocate memory for fmp");
- goto err_buf;
- }
- if (fmp_load(&driver->fmp, fmbuf, filelen)) {
- driver_type = DRIVER_FMP;
- } else {
- memset(driver, 0, sizeof(*driver));
- if (pmd_load(&driver->pmd, fmbuf, filelen)) {
- driver_type = DRIVER_PMD;
- } else {
- msgbox_err("invalid file");
- goto err_driver;
+ enum fmplayer_file_error error;
+ fmfile = fmplayer_file_alloc(uri, &error);
+ if (!fmfile) {
+ const char *errstr = fmplayer_file_strerror(error);
+ const char *errmain = "cannot load file: ";
+ char *errbuf = malloc(strlen(errstr) + strlen(errmain) + 1);
+ if (errbuf) {
+ strcpy(errbuf, errmain);
+ strcat(errbuf, errstr);
}
+ msgbox_err(errbuf ? errbuf : "cannot load file");
+ free(errbuf);
+ goto err;
}
if (!g.pastream) {
PaError pe = Pa_OpenDefaultStream(&g.pastream, 0, 2, paInt16, SRATE, AUDIOBUFLEN,
pastream_cb, &g.opna_timer);
if (pe != paNoError) {
msgbox_err("cannot open portaudio stream");
- goto err_driver;
+ goto err;
}
} else if (!g.pa_paused) {
PaError pe = Pa_StopStream(g.pastream);
if (pe != paNoError) {
msgbox_err("Portaudio Error");
- goto err_driver;
+ goto err;
}
}
- free(g.driver);
- g.driver = driver;
- free(g.data);
- g.data = fmbuf;
+ fmplayer_file_free(g.fmfile);
+ g.fmfile = fmfile;
unsigned mask = opna_get_mask(&g.opna);
opna_reset(&g.opna);
opna_set_mask(&g.opna, mask);
@@ -447,26 +264,8 @@ static bool openfile(const char *uri) {
}
opna_timer_set_int_callback(&g.opna_timer, opna_int_cb, &g.work);
opna_timer_set_mix_callback(&g.opna_timer, opna_mix_cb, &g.ppz8);
- if (driver_type == DRIVER_FMP) {
- fmp_init(&g.work, &g.driver->fmp);
- GFile *dir = g_file_get_parent(fmfile);
- if (dir) {
- loadpvi(&g.work, &g.driver->fmp, dir);
- loadppzpvi(&g.work, &g.driver->fmp, dir);
- g_object_unref(G_OBJECT(dir));
- }
- } else {
- pmd_init(&g.work, &g.driver->pmd);
- GFile *dir = g_file_get_parent(fmfile);
- if (dir) {
- loadppc(&g.work, &g.driver->pmd, dir);
- g_object_unref(G_OBJECT(dir));
- }
- }
+ fmplayer_file_load(&g.work, g.fmfile);
fmdsp_vram_init(&g.fmdsp, &g.work, g.vram);
- g_object_unref(G_OBJECT(fmstream));
- g_object_unref(G_OBJECT(fminfo));
- g_object_unref(G_OBJECT(fmfile));
Pa_StartStream(g.pastream);
g.pa_paused = false;
{
@@ -475,17 +274,8 @@ static bool openfile(const char *uri) {
g.current_uri = turi;
}
return true;
-err_driver:
- free(driver);
-err_buf:
- free(fmbuf);
-err_stream:
- g_object_unref(G_OBJECT(fmstream));
-err_info:
- g_object_unref(G_OBJECT(fminfo));
-err_file:
- g_object_unref(G_OBJECT(fmfile));
err:
+ fmplayer_file_free(fmfile);
return false;
}
@@ -517,6 +307,9 @@ static GtkWidget *create_menubar() {
GtkWidget *toneview = gtk_menu_item_new_with_label("Tone view");
g_signal_connect(toneview, "activate", G_CALLBACK(on_tone_view), 0);
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), toneview);
+ GtkWidget *oscilloview = gtk_menu_item_new_with_label("Oscillo view");
+ g_signal_connect(oscilloview, "activate", G_CALLBACK(on_oscillo_view), 0);
+ gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), oscilloview);
return menubar;
}
diff --git a/win32/amd64/Makefile b/win32/amd64/Makefile
index d3b0130..177ef90 100644
--- a/win32/amd64/Makefile
+++ b/win32/amd64/Makefile
@@ -2,6 +2,8 @@ vpath %.c ../
vpath %.c ../../fmdriver
vpath %.c ../../libopna
vpath %.c ../../fmdsp
+vpath %.c ../../tonedata
+vpath %.c ../../common
vpath %.rc ..
include ../fmplayer.mak
@@ -12,7 +14,7 @@ PREFIX=$(ARCH)-w64-mingw32-
CC=$(PREFIX)gcc
WINDRES=$(PREFIX)windres
STRIP=$(PREFIX)strip
-CFLAGS=-std=c99 -Os -Wall -Wextra -pedantic -I../.. \
+CFLAGS=-std=c99 -O2 -Wall -Wextra -Werror -pedantic -Wno-unused-parameter -Wno-missing-field-initializers -I../.. \
$(addprefix -D,$(DEFINES))
LIBS=-s -mwindows -municode \
$(addprefix -l,$(LIBBASE))
diff --git a/win32/fmplayer.mak b/win32/fmplayer.mak
index c71ef6a..1f68f4d 100644
--- a/win32/fmplayer.mak
+++ b/win32/fmplayer.mak
@@ -23,12 +23,14 @@ FMDSP_OBJS=fmdsp \
TONEDATA_OBJS=tonedata
OBJBASE=main \
toneview \
+ oscilloview \
soundout \
dsoundout \
waveout \
- wasapiout \
winfont \
guid \
+ fmplayer_file \
+ fmplayer_file_win \
$(FMDRIVER_OBJS) \
$(LIBOPNA_OBJS) \
$(TONEDATA_OBJS) \
diff --git a/win32/main.c b/win32/main.c
index e312253..ab038ae 100644
--- a/win32/main.c
+++ b/win32/main.c
@@ -4,9 +4,12 @@
#include <shlwapi.h>
#include <windowsx.h>
#include <commctrl.h>
+#include <stdlib.h>
+#include <stdatomic.h>
#include "fmdriver/fmdriver_fmp.h"
#include "fmdriver/fmdriver_pmd.h"
+#include "common/fmplayer_file.h"
#include "libopna/opna.h"
#include "libopna/opnatimer.h"
#include "fmdsp/fmdsp.h"
@@ -14,12 +17,15 @@
#include "winfont.h"
#include "version.h"
#include "toneview.h"
+#include "oscillo/oscillo.h"
+#include "oscilloview.h"
enum {
ID_OPENFILE = 0x10,
ID_PAUSE,
ID_2X,
ID_TONEVIEW,
+ ID_OSCILLOVIEW,
};
#define FMPLAYER_CLASSNAME L"myon_fmplayer_ym2608_win32"
@@ -35,11 +41,6 @@ enum {
#define ENABLE_WM_DROPFILES
// #define ENABLE_IDROPTARGET
-union drivers {
- struct driver_pmd pmd;
- struct driver_fmp fmp;
-};
-
static struct {
HINSTANCE hinst;
HANDLE heap;
@@ -48,8 +49,7 @@ static struct {
struct opna_timer opna_timer;
struct ppz8 ppz8;
struct fmdriver_work work;
- union drivers *driver;
- uint8_t *data;
+ struct fmplayer_file *fmfile;
struct fmdsp fmdsp;
uint8_t vram[PC98_W*PC98_H];
struct fmdsp_font font;
@@ -57,7 +57,6 @@ static struct {
bool font_loaded;
void *drum_rom;
uint8_t opna_adpcm_ram[OPNA_ADPCM_RAM_SIZE];
- void *ppz8_buf;
bool paused;
HWND mainwnd;
WNDPROC btn_defproc;
@@ -65,6 +64,8 @@ static struct {
HWND button_2x;
const wchar_t *lastopenpath;
bool fmdsp_2x;
+ struct oscillodata oscillodata_audiothread[LIBOPNA_OSCILLO_TRACK_COUNT];
+ UINT mmtimer;
} g;
HWND g_currentdlg;
@@ -85,7 +86,7 @@ static void opna_writereg_libopna(struct fmdriver_work *work, unsigned addr, uns
}
static unsigned opna_readreg_libopna(struct fmdriver_work *work, unsigned addr) {
- struct opna_timer *timer = (struct opna_timer *)work->opna;
+// struct opna_timer *timer = (struct opna_timer *)work->opna;
return opna_readreg(&g.opna, addr);
}
@@ -101,41 +102,17 @@ static uint8_t opna_status_libopna(struct fmdriver_work *work, bool a1) {
static void sound_cb(void *p, int16_t *buf, unsigned frames) {
struct opna_timer *timer = (struct opna_timer *)p;
ZeroMemory(buf, sizeof(int16_t)*frames*2);
- opna_timer_mix(timer, buf, frames);
+ opna_timer_mix_oscillo(timer, buf, frames, g.oscillodata_audiothread);
if (!atomic_flag_test_and_set_explicit(
&toneview_g.flag, memory_order_acquire)) {
tonedata_from_opna(&toneview_g.tonedata, &g.opna);
atomic_flag_clear_explicit(&toneview_g.flag, memory_order_release);
- }
-}
-
-static void on_timer(HWND hwnd, UINT id) {
- if (id == TIMER_FMDSP) {
- InvalidateRect(hwnd, 0, FALSE);
}
-}
-
-static HANDLE pvisearch(const wchar_t *filename, const char *pviname_a) {
- enum {
- WPVINAMELEN = 8*2+1+3+1,
- };
- wchar_t pviname[WPVINAMELEN];
- wchar_t pvipath[MAX_PATH];
- if (MultiByteToWideChar(932, MB_ERR_INVALID_CHARS,
- pviname_a, -1, pviname, WPVINAMELEN) == 0) {
- return INVALID_HANDLE_VALUE;
- }
- lstrcat(pviname, L".PVI");
- if (lstrlen(filename) >= MAX_PATH) return INVALID_HANDLE_VALUE;
- lstrcpy(pvipath, filename);
- PathRemoveFileSpec(pvipath);
- if (lstrlen(pvipath) + lstrlen(pviname) + 1 >= MAX_PATH) {
- return INVALID_HANDLE_VALUE;
+ if (!atomic_flag_test_and_set_explicit(
+ &oscilloview_g.flag, memory_order_acquire)) {
+ memcpy(oscilloview_g.oscillodata, g.oscillodata_audiothread, sizeof(oscilloview_g.oscillodata));
+ atomic_flag_clear_explicit(&oscilloview_g.flag, memory_order_release);
}
- lstrcat(pvipath, L"\\");
- lstrcat(pvipath, pviname);
- return CreateFile(pvipath, GENERIC_READ,
- 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
}
static bool loadfontrom(void) {
@@ -207,115 +184,26 @@ err:
return;
}
-static bool loadpvi(struct fmdriver_work *work,
- struct driver_fmp *fmp,
- const wchar_t *filename) {
- if (!fmp->pvi_name[0]) return true;
- HANDLE pvifile = pvisearch(filename, fmp->pvi_name);
- if (pvifile == INVALID_HANDLE_VALUE) goto err;
- DWORD filesize = GetFileSize(pvifile, 0);
- if (filesize == INVALID_FILE_SIZE) goto err_file;
- void *data = HeapAlloc(g.heap, 0, filesize);
- if (!data) goto err_file;
- DWORD readbytes;
- if (!ReadFile(pvifile, data, filesize, &readbytes, 0)
- || readbytes != filesize) goto err_data;
- if (!fmp_adpcm_load(work, data, filesize)) goto err_data;
- HeapFree(g.heap, 0, data);
- CloseHandle(pvifile);
- return true;
-err_data:
- HeapFree(g.heap, 0, data);
-err_file:
- CloseHandle(pvifile);
-err:
- return false;
-}
-
-static bool loadppzpvi(struct fmdriver_work *work,
- struct driver_fmp *fmp,
- const wchar_t *filename) {
- if (!fmp->ppz_name[0]) return true;
- HANDLE pvifile = pvisearch(filename, fmp->ppz_name);
- if (pvifile == INVALID_HANDLE_VALUE) goto err;
- DWORD filesize = GetFileSize(pvifile, 0);
- if (filesize == INVALID_FILE_SIZE) goto err_file;
- void *data = HeapAlloc(g.heap, 0, filesize);
- if (!data) goto err_file;
- void *buf = HeapAlloc(g.heap, 0, ppz8_pvi_decodebuf_samples(filesize) * sizeof(int16_t));
- if (!buf) goto err_data;
- DWORD readbytes;
- if (!ReadFile(pvifile, data, filesize, &readbytes, 0)
- || readbytes != filesize) goto err_buf;
- if (!ppz8_pvi_load(work->ppz8, 0, data, filesize, buf)) goto err_buf;
- if (g.ppz8_buf) HeapFree(g.heap, 0, g.ppz8_buf);
- g.ppz8_buf = buf;
- HeapFree(g.heap, 0, data);
- CloseHandle(pvifile);
- return true;
-err_buf:
- HeapFree(g.heap, 0, buf);
-err_data:
- HeapFree(g.heap, 0, data);
-err_file:
- CloseHandle(pvifile);
-err:
- return false;
-}
-
static void openfile(HWND hwnd, const wchar_t *path) {
- enum {
- DRIVER_PMD,
- DRIVER_FMP
- } driver_type;
- HANDLE file = CreateFile(path, GENERIC_READ,
- 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
- if (file == INVALID_HANDLE_VALUE) {
- MessageBox(hwnd, L"Cannot open file", L"Error", MB_ICONSTOP);
- return;
- }
- LARGE_INTEGER li;
- if (!GetFileSizeEx(file, &li)) {
- MessageBox(hwnd, L"Cannot open file", L"Error", MB_ICONSTOP);
- goto err_file;
- }
- if (li.QuadPart > 0xffff) {
- MessageBox(hwnd, L"Invalid File (Filesize too large)", L"Error", MB_ICONSTOP);
- goto err_file;
- }
- void *data = HeapAlloc(g.heap, 0, li.QuadPart);
- if (!data) {
- MessageBox(hwnd, L"Cannot allocate memory for file", L"Error", MB_ICONSTOP);
- goto err_file;
- }
- DWORD readbytes;
- if (!ReadFile(file, data, li.QuadPart, &readbytes, 0) || readbytes != li.QuadPart) {
- MessageBox(hwnd, L"Cannot read file", L"Error", MB_ICONSTOP);
- goto err_data;
- }
- union drivers *driver = HeapAlloc(g.heap, HEAP_ZERO_MEMORY, sizeof(*driver));
- if (!driver) {
- MessageBox(hwnd, L"Cannot allocate memory for fmp", L"Error", MB_ICONSTOP);
- goto err_data;
- }
- if (fmp_load(&driver->fmp, data, li.QuadPart)) {
- driver_type = DRIVER_FMP;
- } else {
- ZeroMemory(driver, sizeof(*driver));
- if (pmd_load(&driver->pmd, data, li.QuadPart)) {
- driver_type = DRIVER_PMD;
- } else {
- MessageBox(hwnd, L"Invalid File (not FMP or PMD)", L"Error", MB_ICONSTOP);
- goto err_driver;
+ enum fmplayer_file_error error;
+ struct fmplayer_file *fmfile = fmplayer_file_alloc(path, &error);
+ if (!fmfile) {
+ const wchar_t *msg = L"Cannot open file: ";
+ const wchar_t *errmsg = fmplayer_file_strerror_w(error);
+ wchar_t *msgbuf = malloc((wcslen(msg) + wcslen(errmsg) + 1) * sizeof(wchar_t));
+ if (msgbuf) {
+ wcscpy(msgbuf, msg);
+ wcscat(msgbuf, errmsg);
}
+ MessageBox(hwnd, msgbuf ? msgbuf : L"Cannot open file", L"Error", MB_ICONSTOP);
+ free(msgbuf);
+ goto err;
}
if (g.sound) {
g.sound->pause(g.sound, 1);
}
- if (g.driver) HeapFree(g.heap, 0, g.driver);
- g.driver = driver;
- if (g.data) HeapFree(g.heap, 0, g.data);
- g.data = data;
+ fmplayer_file_free(g.fmfile);
+ g.fmfile = fmfile;
unsigned mask = opna_get_mask(&g.opna);
opna_reset(&g.opna);
opna_set_mask(&g.opna, mask);
@@ -333,23 +221,16 @@ static void openfile(HWND hwnd, const wchar_t *path) {
WideCharToMultiByte(932, WC_NO_BEST_FIT_CHARS, path, -1, g.work.filename, sizeof(g.work.filename), 0, 0);
opna_timer_set_int_callback(&g.opna_timer, opna_int_cb, &g.work);
opna_timer_set_mix_callback(&g.opna_timer, opna_mix_cb, &g.ppz8);
- if (driver_type == DRIVER_PMD) {
- pmd_init(&g.work, &g.driver->pmd);
- } else {
- fmp_init(&g.work, &g.driver->fmp);
- loadpvi(&g.work, &g.driver->fmp, path);
- loadppzpvi(&g.work, &g.driver->fmp, path);
- }
+ fmplayer_file_load(&g.work, g.fmfile);
if (!g.sound) {
g.sound = sound_init(hwnd, SRATE, SECTLEN,
sound_cb, &g.opna_timer);
SetWindowText(g.driverinfo, g.sound->apiname);
}
fmdsp_vram_init(&g.fmdsp, &g.work, g.vram);
- if (!g.sound) goto err_driver;
+ if (!g.sound) goto err;
g.sound->pause(g.sound, 0);
g.paused = false;
- CloseHandle(file);
wchar_t *pathcpy = HeapAlloc(g.heap, 0, (lstrlen(path)+1)*sizeof(wchar_t));
if (pathcpy) {
lstrcpy(pathcpy, path);
@@ -357,12 +238,8 @@ static void openfile(HWND hwnd, const wchar_t *path) {
if (g.lastopenpath) HeapFree(g.heap, 0, (void *)g.lastopenpath);
g.lastopenpath = pathcpy;
return;
-err_driver:
- HeapFree(g.heap, 0, driver);
-err_data:
- HeapFree(g.heap, 0, data);
-err_file:
- CloseHandle(file);
+err:
+ fmplayer_file_free(fmfile);
}
static void openfiledialog(HWND hwnd) {
@@ -560,6 +437,12 @@ static LRESULT CALLBACK btn_wndproc(
return CallWindowProc(g.btn_defproc, hwnd, msg, wParam, lParam);
}
+static void CALLBACK mmtimer_cb(UINT timerid, UINT msg,
+ DWORD_PTR userptr,
+ DWORD_PTR dw1, DWORD_PTR dw2) {
+ PostMessage(g.mainwnd, WM_USER, 0, 0);
+}
+
static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
(void)cs;
HWND button = CreateWindowEx(
@@ -601,17 +484,27 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
HWND button_toneview = CreateWindowEx(
0,
L"BUTTON",
- L"Tone &viewer",
+ L"&Tone viewer",
WS_TABSTOP | WS_VISIBLE | WS_CHILD,
250, 10,
100, 25,
hwnd, (HMENU)ID_TONEVIEW, g.hinst, 0
);
+ HWND button_oscilloview = CreateWindowEx(
+ 0,
+ L"BUTTON",
+ L"Oscillo&view",
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD,
+ 355, 10,
+ 100, 25,
+ hwnd, (HMENU)ID_OSCILLOVIEW, g.hinst, 0
+ );
g.btn_defproc = (WNDPROC)GetWindowLongPtr(button, GWLP_WNDPROC);
SetWindowLongPtr(button, GWLP_WNDPROC, (intptr_t)btn_wndproc);
SetWindowLongPtr(pbutton, GWLP_WNDPROC, (intptr_t)btn_wndproc);
SetWindowLongPtr(g.button_2x, GWLP_WNDPROC, (intptr_t)btn_wndproc);
SetWindowLongPtr(button_toneview, GWLP_WNDPROC, (intptr_t)btn_wndproc);
+ SetWindowLongPtr(button_oscilloview, GWLP_WNDPROC, (intptr_t)btn_wndproc);
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
@@ -621,11 +514,13 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
SetWindowFont(g.driverinfo, font, TRUE);
SetWindowFont(g.button_2x, font, TRUE);
SetWindowFont(button_toneview, font, TRUE);
+ SetWindowFont(button_oscilloview, font, TRUE);
loadrom();
loadfont();
fmdsp_init(&g.fmdsp, g.font_loaded ? &g.font : 0);
fmdsp_vram_init(&g.fmdsp, &g.work, g.vram);
- SetTimer(hwnd, TIMER_FMDSP, 16, 0);
+ //SetTimer(hwnd, TIMER_FMDSP, 16, 0);
+ g.mmtimer = timeSetEvent(16, 16, mmtimer_cb, 0, TIME_PERIODIC);
#ifdef ENABLE_WM_DROPFILES
DragAcceptFiles(hwnd, TRUE);
#endif
@@ -651,16 +546,18 @@ static void on_command(HWND hwnd, int id, HWND hwnd_c, UINT code) {
case ID_TONEVIEW:
show_toneview(g.hinst, hwnd);
break;
+ case ID_OSCILLOVIEW:
+ show_oscilloview(g.hinst, hwnd);
+ break;
}
}
static void on_destroy(HWND hwnd) {
(void)hwnd;
+ timeKillEvent(g.mmtimer);
if (g.sound) g.sound->free(g.sound);
- if (g.driver) HeapFree(g.heap, 0, g.driver);
- if (g.data) HeapFree(g.heap, 0, g.data);
+ fmplayer_file_free(g.fmfile);
if (g.drum_rom) HeapFree(g.heap, 0, g.drum_rom);
- if (g.ppz8_buf) HeapFree(g.heap, 0, g.ppz8_buf);
PostQuitMessage(0);
}
@@ -739,6 +636,15 @@ static void on_activate(HWND hwnd, bool activate, HWND targetwnd, WINBOOL state)
else g_currentdlg = 0;
}
+static bool on_erasebkgnd(HWND hwnd, HDC dc) {
+ RECT cr;
+ GetClientRect(hwnd, &cr);
+ // separate fmdsp drawing area to another window and remove this hack
+ cr.bottom -= 400 * (g.fmdsp_2x + 1);
+ FillRect(dc, &cr, (HBRUSH)(COLOR_BTNFACE+1));
+ return true;
+}
+
static LRESULT CALLBACK wndproc(
HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
) {
@@ -747,7 +653,7 @@ static LRESULT CALLBACK wndproc(
HANDLE_MSG(hwnd, WM_CREATE, on_create);
HANDLE_MSG(hwnd, WM_COMMAND, on_command);
HANDLE_MSG(hwnd, WM_PAINT, on_paint);
- HANDLE_MSG(hwnd, WM_TIMER, on_timer);
+ HANDLE_MSG(hwnd, WM_ERASEBKGND, on_erasebkgnd);
case WM_COPYDATA:
return on_copydata(hwnd, (HWND)wParam, (COPYDATASTRUCT *)lParam);
#ifdef ENABLE_WM_DROPFILES
@@ -758,6 +664,9 @@ static LRESULT CALLBACK wndproc(
HANDLE_MSG(hwnd, WM_SYSKEYDOWN, on_syskey);
HANDLE_MSG(hwnd, WM_SYSKEYUP, on_syskey);
HANDLE_MSG(hwnd, WM_ACTIVATE, on_activate);
+ case WM_USER:
+ InvalidateRect(hwnd, 0, FALSE);
+ return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
@@ -829,7 +738,7 @@ int CALLBACK wWinMain(HINSTANCE hinst, HINSTANCE hpinst,
if (argfile) {
openfile(g.mainwnd, argfile);
}
-
+ timeBeginPeriod(1);
MSG msg = {0};
while (GetMessage(&msg, 0, 0, 0)) {
if (!g_currentdlg || !IsDialogMessage(g_currentdlg, &msg)) {
@@ -837,6 +746,7 @@ int CALLBACK wWinMain(HINSTANCE hinst, HINSTANCE hpinst,
DispatchMessage(&msg);
}
}
+ timeEndPeriod(1);
return msg.wParam;
}
diff --git a/win32/toneview.c b/win32/toneview.c
index 63d1b73..adda8b6 100644
--- a/win32/toneview.c
+++ b/win32/toneview.c
@@ -181,7 +181,7 @@ static bool on_create(HWND hwnd, const CREATESTRUCT *cs) {
text,
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
COPY_X, 40 + (TONELABEL_H+5)*i, 100, TONELABEL_H,
- hwnd, (HMENU)(ID_COPY0+i), g.hinst, 0);
+ hwnd, (HMENU)((intptr_t)(ID_COPY0+i)), g.hinst, 0);
SetWindowFont(copybutton, g.font, TRUE);
}
ShowWindow(hwnd, SW_SHOW);
@@ -252,7 +252,7 @@ void show_toneview(HINSTANCE hinst, HWND parent) {
g.toneviewer = CreateWindowEx(0,
MAKEINTATOM(g.toneviewer_class),
L"FMPlayer Tone Viewer",
- WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_CLIPCHILDREN,
+ WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
parent, 0, g.hinst, 0);
} else {
diff --git a/win32/x86/Makefile b/win32/x86/Makefile
index 1a4c6d8..b26f3e1 100644
--- a/win32/x86/Makefile
+++ b/win32/x86/Makefile
@@ -3,6 +3,7 @@ vpath %.c ../../fmdriver
vpath %.c ../../libopna
vpath %.c ../../fmdsp
vpath %.c ../../tonedata
+vpath %.c ../../common
vpath %.rc ..
include ../fmplayer.mak
@@ -13,9 +14,9 @@ PREFIX=$(ARCH)-w64-mingw32-
CC=$(PREFIX)gcc
WINDRES=$(PREFIX)windres
STRIP=$(PREFIX)strip
-CFLAGS=-std=c99 -Os -Wall -Wextra -pedantic -I../.. \
+CFLAGS=-std=c99 -O2 -Wall -Wextra -Werror -pedantic -I../.. \
$(addprefix -D,$(DEFINES)) \
- -march=i586
+ -march=i586 -Wno-unused-parameter -Wno-missing-field-initializers
LIBS=-s -mwindows -municode \
$(addprefix -l,$(LIBBASE))