diff options
-rw-r--r-- | common/fmplayer_common.h | 8 | ||||
-rw-r--r-- | common/fmplayer_file.c | 168 | ||||
-rw-r--r-- | common/fmplayer_file.h | 52 | ||||
-rw-r--r-- | common/fmplayer_file_gio.c | 120 | ||||
-rw-r--r-- | common/fmplayer_file_win.c | 87 | ||||
-rw-r--r-- | gtk/Makefile.am | 3 | ||||
-rw-r--r-- | gtk/main.c | 285 | ||||
-rw-r--r-- | win32/amd64/Makefile | 4 | ||||
-rw-r--r-- | win32/fmplayer.mak | 4 | ||||
-rw-r--r-- | win32/main.c | 236 | ||||
-rw-r--r-- | win32/toneview.c | 4 | ||||
-rw-r--r-- | win32/x86/Makefile | 5 |
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) @@ -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)) |