diff options
| author | Takamichi Horikawa <takamichiho@gmail.com> | 2017-03-27 23:32:18 +0900 | 
|---|---|---|
| committer | Takamichi Horikawa <takamichiho@gmail.com> | 2017-03-27 23:32:18 +0900 | 
| commit | 0073f2b8befc6163f2970cb7a01e75fffc95994e (patch) | |
| tree | aab8d559720269e65b5ad05c07d98a865ff14e57 | |
| parent | e2ee18347d45e4620a8279afb8b0bc4a809441ef (diff) | |
refactor common file loading functions
| -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)) | 
