summaryrefslogtreecommitdiffstats
path: root/gst/nsf/nsf.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/nsf/nsf.c')
-rw-r--r--gst/nsf/nsf.c713
1 files changed, 574 insertions, 139 deletions
diff --git a/gst/nsf/nsf.c b/gst/nsf/nsf.c
index 6fd34bba..a42022fe 100644
--- a/gst/nsf/nsf.c
+++ b/gst/nsf/nsf.c
@@ -23,6 +23,7 @@
** $Id$
*/
+
#include <stdio.h>
#include <string.h>
#include "types.h"
@@ -52,12 +53,16 @@ nsf_setcontext (nsf_t * nsf)
static uint8
read_mirrored_ram (uint32 address)
{
+ nes6502_chk_mem_access (&cur_nsf->cpu->acc_mem_page[0][address & 0x7FF],
+ NES6502_READ_ACCESS);
return cur_nsf->cpu->mem_page[0][address & 0x7FF];
}
static void
write_mirrored_ram (uint32 address, uint8 value)
{
+ nes6502_chk_mem_access (&cur_nsf->cpu->acc_mem_page[0][address & 0x7FF],
+ NES6502_WRITE_ACCESS);
cur_nsf->cpu->mem_page[0][address & 0x7FF] = value;
}
@@ -66,27 +71,32 @@ static void
nsf_bankswitch (uint32 address, uint8 value)
{
int cpu_page;
+ int roffset;
uint8 *offset;
cpu_page = address & 0x0F;
- offset = (cur_nsf->data - (cur_nsf->load_addr & 0x0FFF)) + (value << 12);
+ roffset = -(cur_nsf->load_addr & 0x0FFF) + ((int) value << 12);
+ offset = cur_nsf->data + roffset;
nes6502_getcontext (cur_nsf->cpu);
cur_nsf->cpu->mem_page[cpu_page] = offset;
+#ifdef NES6502_MEM_ACCESS_CTRL
+ cur_nsf->cpu->acc_mem_page[cpu_page] = offset + cur_nsf->length;
+#endif
nes6502_setcontext (cur_nsf->cpu);
}
static nes6502_memread default_readhandler[] = {
{0x0800, 0x1FFF, read_mirrored_ram},
{0x4000, 0x4017, apu_read},
- {(uint32) - 1, (uint32) - 1, NULL}
+ {-1, -1, NULL}
};
static nes6502_memwrite default_writehandler[] = {
{0x0800, 0x1FFF, write_mirrored_ram},
{0x4000, 0x4017, apu_write},
{0x5FF6, 0x5FFF, nsf_bankswitch},
- {(uint32) - 1, (uint32) - 1, NULL}
+ {-1, -1, NULL}
};
static uint8
@@ -251,6 +261,17 @@ nsf_inittune (nsf_t * nsf)
memset (nsf->cpu->mem_page[6], 0, 0x1000);
memset (nsf->cpu->mem_page[7], 0, 0x1000);
+#ifdef NES6502_MEM_ACCESS_CTRL
+ memset (nsf->cpu->acc_mem_page[0], 0, 0x800);
+ memset (nsf->cpu->acc_mem_page[6], 0, 0x1000);
+ memset (nsf->cpu->acc_mem_page[7], 0, 0x1000);
+ memset (nsf->data + nsf->length, 0, nsf->length);
+#endif
+ nsf->cur_frame = 0;
+/* nsf->last_access_frame = 0; */
+ nsf->cur_frame_end = !nsf->song_frames
+ ? 0 : nsf->song_frames[nsf->current_song];
+
if (nsf->bankswitched) {
/* the first hack of the NSF spec! */
if (EXT_SOUND_FDS == nsf->ext_sound_type) {
@@ -289,12 +310,37 @@ nsf_inittune (nsf_t * nsf)
void
nsf_frame (nsf_t * nsf)
{
- /* future expansion =) */
- /*nsf_setcontext(nsf); */
+ /* This is how Matthew Conte left it */
+ /* nsf_setcontext(nsf); *//* future expansion =) */
+
+ /* This was suggested by Arne Morten Kvarving, who says: */
+/* Also, I fixed a bug that prevented Nosefart to play multiple tunes at
+ one time (actually it was just a few missing setcontext calls in the
+ playback routine, it had a nice TODO commented beside it. You had to set
+ the cpu and apu contexts not just the nsf context).
+
+ it will affect any player that tries to use nosefart to play more than one
+ tune at a time.
+*/
+ nsf_setcontext (nsf);
+ apu_setcontext (nsf->apu);
+ nes6502_setcontext (nsf->cpu);
/* one frame of NES processing */
nsf_setup_routine (nsf->play_addr, 0, 0);
nes6502_execute ((int) NES_FRAME_CYCLES);
+
+ ++nsf->cur_frame;
+#if defined(NES6502_MEM_ACCESS_CTRL) && 0
+ if (nes6502_mem_access) {
+ uint32 sec =
+ (nsf->last_access_frame + nsf->playback_rate - 1) / nsf->playback_rate;
+ nsf->last_access_frame = nsf->cur_frame;
+ fprintf (stderr, "nsf : memory access [%x] at frame #%u [%u:%02u]\n",
+ nes6502_mem_access, nsf->last_access_frame, sec / 60, sec % 60);
+ }
+#endif
+
}
/* Deallocate memory */
@@ -302,26 +348,38 @@ void
nes_shutdown (nsf_t * nsf)
{
int i;
- void *mem;
ASSERT (nsf);
if (nsf->cpu) {
- if (nsf->cpu->mem_page[0])
- free (nsf->cpu->mem_page[0]);
+ if (nsf->cpu->mem_page[0]) {
+ free (nsf->cpu->mem_page[0]); /*tracks 1 and 2 of lifeforce hang here. */
+ }
for (i = 5; i <= 7; i++) {
- if (nsf->cpu->mem_page[i])
+ if (nsf->cpu->mem_page[i]) {
free (nsf->cpu->mem_page[i]);
+ }
+ }
+
+#ifdef NES6502_MEM_ACCESS_CTRL
+ if (nsf->cpu->acc_mem_page[0]) {
+ free (nsf->cpu->acc_mem_page[0]);
}
- mem = nsf->cpu;
- free (mem);
+ for (i = 5; i <= 7; i++) {
+ if (nsf->cpu->acc_mem_page[i]) {
+ free (nsf->cpu->acc_mem_page[i]);
+ }
+ }
+#endif
+ free (nsf->cpu);
}
}
-void
+int
nsf_init (void)
{
nes6502_init ();
+ return 0;
}
/* Initialize NES CPU, hardware, etc. */
@@ -347,19 +405,27 @@ nsf_cpuinit (nsf_t * nsf)
return -1;
}
+#ifdef NES6502_MEM_ACCESS_CTRL
+ nsf->cpu->acc_mem_page[0] = malloc (0x800);
+ if (NULL == nsf->cpu->acc_mem_page[0])
+ return -1;
+ /* allocate some space for the NSF "player" MMC5 EXRAM, and WRAM */
+ for (i = 5; i <= 7; i++) {
+ nsf->cpu->acc_mem_page[i] = malloc (0x1000);
+ if (NULL == nsf->cpu->acc_mem_page[i])
+ return -1;
+ }
+#endif
+
nsf->cpu->read_handler = nsf_readhandler;
nsf->cpu->write_handler = nsf_writehandler;
return 0;
}
-static void
-nsf_setup (nsf_t * nsf)
+static unsigned int
+nsf_playback_rate (nsf_t * nsf)
{
- int i;
-
- nsf->current_song = nsf->start_song;
-
if (nsf->pal_ntsc_bits & NSF_DEDICATED_PAL) {
if (nsf->pal_speed)
nsf->playback_rate = 1000000 / nsf->pal_speed;
@@ -371,9 +437,18 @@ nsf_setup (nsf_t * nsf)
else
nsf->playback_rate = 60; /* 60 Hz */
}
+ return 0;
+}
- nsf->bankswitched = FALSE;
+static void
+nsf_setup (nsf_t * nsf)
+{
+ int i;
+ nsf->current_song = nsf->start_song;
+ nsf_playback_rate (nsf);
+
+ nsf->bankswitched = FALSE;
for (i = 0; i < 8; i++) {
if (nsf->bankswitch_info[i]) {
nsf->bankswitched = TRUE;
@@ -388,68 +463,298 @@ nsf_setup (nsf_t * nsf)
#define SWAP_16(x) (((uint16) x >> 8) | (((uint16) x & 0xFF) << 8))
#endif /* !HOST_LITTLE_ENDIAN */
-/* Load a ROM image into memory */
-nsf_t *
-nsf_load (char *filename, void *source, int length)
+/* $$$ ben : find extension. Should be OK with DOS, but not with some
+ * OS like RiscOS ... */
+static char *
+find_ext (char *fn)
{
- FILE *fp = NULL;
- char *new_fn = NULL;
- nsf_t *temp_nsf;
+ char *a, *b, *c;
- if (NULL == filename && NULL == source)
- return NULL;
+ a = strrchr (fn, '.');
+ b = strrchr (fn, '/');
+ c = strrchr (fn, '\\');
+ if (a <= b || a <= c) {
+ a = 0;
+ }
+ return a;
+}
+
+/* $$$ ben : FILE loader */
+struct nsf_file_loader_t
+{
+ struct nsf_loader_t loader;
+ FILE *fp;
+ char *fname;
+ int name_allocated;
+};
+
+static int
+nfs_open_file (struct nsf_loader_t *loader)
+{
+ struct nsf_file_loader_t *floader = (struct nsf_file_loader_t *) loader;
+
+ floader->name_allocated = 0;
+ floader->fp = 0;
+ if (!floader->fname) {
+ return -1;
+ }
+ floader->fp = fopen (floader->fname, "rb");
+ if (!floader->fp) {
+ char *fname, *ext;
+
+ ext = find_ext (floader->fname);
+ if (ext) {
+ /* There was an extension, so we do not change it */
+ return -1;
+ }
+ fname = malloc (strlen (floader->fname) + 5);
+ if (!fname) {
+ return -1;
+ }
+ /* try with .nsf extension. */
+ strcpy (fname, floader->fname);
+ strcat (fname, ".nsf");
+ floader->fp = fopen (fname, "rb");
+ if (!floader->fp) {
+ free (fname);
+ return -1;
+ }
+ floader->fname = fname;
+ floader->name_allocated = 1;
+ }
+ return 0;
+}
+
+static void
+nfs_close_file (struct nsf_loader_t *loader)
+{
+ struct nsf_file_loader_t *floader = (struct nsf_file_loader_t *) loader;
+
+ if (floader->fp) {
+ fclose (floader->fp);
+ floader->fp = 0;
+ }
+ if (floader->fname && floader->name_allocated) {
+ free (floader->fname);
+ floader->fname = 0;
+ floader->name_allocated = 0;
+ }
+}
- if (NULL == source) {
- fp = fopen (filename, "rb");
+static int
+nfs_read_file (struct nsf_loader_t *loader, void *data, int n)
+{
+ struct nsf_file_loader_t *floader = (struct nsf_file_loader_t *) loader;
+ int r = fread (data, 1, n, floader->fp);
- /* Didn't find the file? Maybe the .NSF extension was omitted */
- if (NULL == fp) {
- new_fn = malloc (strlen (filename) + 5);
- if (NULL == new_fn)
- return NULL;
- strcpy (new_fn, filename);
+ if (r >= 0) {
+ r = n - r;
+ }
+ return r;
+}
- if (NULL == strrchr (new_fn, '.'))
- strcat (new_fn, ".nsf");
+static int
+nfs_length_file (struct nsf_loader_t *loader)
+{
+ struct nsf_file_loader_t *floader = (struct nsf_file_loader_t *) loader;
+ long save, pos;
+
+ save = ftell (floader->fp);
+ fseek (floader->fp, 0, SEEK_END);
+ pos = ftell (floader->fp);
+ fseek (floader->fp, save, SEEK_SET);
+ return pos;
+}
- fp = fopen (new_fn, "rb");
+static int
+nfs_skip_file (struct nsf_loader_t *loader, int n)
+{
+ struct nsf_file_loader_t *floader = (struct nsf_file_loader_t *) loader;
+ int r;
- if (NULL == fp) {
- void *t = new_fn;
+ r = fseek (floader->fp, n, SEEK_CUR);
+ return r;
+}
- log_printf ("could not find file '%s'\n", new_fn);
- free (t);
- return NULL;
- }
- }
+static const char *
+nfs_fname_file (struct nsf_loader_t *loader)
+{
+ struct nsf_file_loader_t *floader = (struct nsf_file_loader_t *) loader;
+
+ return floader->fname ? floader->fname : "<null>";
+}
+
+static struct nsf_file_loader_t nsf_file_loader = {
+ {
+ nfs_open_file,
+ nfs_close_file,
+ nfs_read_file,
+ nfs_length_file,
+ nfs_skip_file,
+ nfs_fname_file},
+ 0, 0, 0
+};
+
+struct nsf_mem_loader_t
+{
+ struct nsf_loader_t loader;
+ uint8 *data;
+ unsigned long cur;
+ unsigned long len;
+ char fname[32];
+};
+
+static int
+nfs_open_mem (struct nsf_loader_t *loader)
+{
+ struct nsf_mem_loader_t *mloader = (struct nsf_mem_loader_t *) loader;
+
+ if (!mloader->data) {
+ return -1;
}
+ mloader->cur = 0;
+ sprintf (mloader->fname, "<mem(%p,%u)>",
+ mloader->data, (unsigned int) mloader->len);
+ return 0;
+}
- temp_nsf = malloc (sizeof (nsf_t));
- if (NULL == temp_nsf)
- return NULL;
+static void
+nfs_close_mem (struct nsf_loader_t *loader)
+{
+ struct nsf_mem_loader_t *mloader = (struct nsf_mem_loader_t *) loader;
- /* Read in the header */
- if (NULL == source) {
- if (fread (temp_nsf, 1, NSF_HEADER_SIZE, fp) != NSF_HEADER_SIZE) {
- log_printf ("error reading file\n");
- free (temp_nsf);
- return NULL;
- }
- } else
- memcpy (temp_nsf, source, NSF_HEADER_SIZE);
+ mloader->data = 0;
+ mloader->cur = 0;
+ mloader->len = 0;
+}
- if (memcmp (temp_nsf->id, NSF_MAGIC, 5)) {
- if (NULL == source) {
- void *t = new_fn;
+static int
+nfs_read_mem (struct nsf_loader_t *loader, void *data, int n)
+{
+ struct nsf_mem_loader_t *mloader = (struct nsf_mem_loader_t *) loader;
+ int rem;
- log_printf ("%s is not an NSF format file\n", new_fn);
- fclose (fp);
- free (t);
- }
- nsf_free (&temp_nsf);
+ if (n <= 0) {
+ return n;
+ }
+ if (!mloader->data) {
+ return -1;
+ }
+ rem = mloader->len - mloader->cur;
+ if (rem > n) {
+ rem = n;
+ }
+ memcpy (data, mloader->data + mloader->cur, rem);
+ mloader->cur += rem;
+ return n - rem;
+}
+
+static int
+nfs_length_mem (struct nsf_loader_t *loader)
+{
+ struct nsf_mem_loader_t *mloader = (struct nsf_mem_loader_t *) loader;
+
+ return mloader->len;
+}
+
+static int
+nfs_skip_mem (struct nsf_loader_t *loader, int n)
+{
+ struct nsf_mem_loader_t *mloader = (struct nsf_mem_loader_t *) loader;
+ unsigned long goal = mloader->cur + n;
+
+ mloader->cur = (goal > mloader->len) ? mloader->len : goal;
+ return goal - mloader->cur;
+}
+
+/* FIXME: not used anywhere */
+#if 0
+static const char *
+nfs_fname_mem (struct nsf_loader_t *loader)
+{
+ struct nsf_mem_loader_t *mloader = (struct nsf_mem_loader_t *) loader;
+
+ return mloader->fname;
+}
+#endif
+
+static struct nsf_mem_loader_t nsf_mem_loader = {
+ {nfs_open_mem, nfs_close_mem, nfs_read_mem, nfs_length_mem, nfs_skip_mem},
+ 0, 0, 0
+};
+
+nsf_t *
+nsf_load_extended (struct nsf_loader_t *loader)
+{
+ nsf_t *temp_nsf = 0;
+ int length;
+ char id[6];
+
+ struct
+ {
+ uint8 magic[4]; /* always "NESM" */
+ uint8 type[4]; /* defines extension type */
+ uint8 size[4]; /* extension data size (this struct include) */
+ } nsf_file_ext;
+
+ /* no loader ! */
+ if (!loader) {
+ return NULL;
+ }
+
+ /* Open the "file" */
+ if (loader->open (loader) < 0) {
return NULL;
}
+ /* Get file size, and exit if there is not enough data for NSF header
+ * and more since it does not make sens to have header without data.
+ */
+ length = loader->length (loader);
+ /* For version 2, we do not need file length. just check error later. */
+#if 0
+ if (length <= NSF_HEADER_SIZE) {
+ log_printf ("nsf : [%s] not an NSF format file\n", loader->fname (loader));
+ goto error;
+ }
+#endif
+
+ /* Read magic */
+ if (loader->read (loader, id, 5)) {
+ log_printf ("nsf : [%s] error reading magic number\n",
+ loader->fname (loader));
+ goto error;
+ }
+
+ /* Check magic */
+ if (memcmp (id, NSF_MAGIC, 5)) {
+ log_printf ("nsf : [%s] is not an NSF format file\n",
+ loader->fname (loader));
+ goto error;
+ }
+
+ /* $$$ ben : Now the file should be an NSF, we can start allocating.
+ * first : the nsf struct
+ */
+ temp_nsf = malloc (sizeof (nsf_t));
+
+ if (NULL == temp_nsf) {
+ log_printf ("nsf : [%s] error allocating nsf header\n",
+ loader->fname (loader));
+ goto error;
+ }
+ /* $$$ ben : safety net */
+ memset (temp_nsf, 0, sizeof (nsf_t));
+ /* Copy magic ID */
+ memcpy (temp_nsf, id, 5);
+
+ /* Read header (without MAGIC) */
+ if (loader->read (loader, (int8 *) temp_nsf + 5, NSF_HEADER_SIZE - 5)) {
+ log_printf ("nsf : [%s] error reading nsf header\n",
+ loader->fname (loader));
+ goto error;
+ }
+
/* fixup endianness */
temp_nsf->load_addr = SWAP_16 (temp_nsf->load_addr);
temp_nsf->init_addr = SWAP_16 (temp_nsf->init_addr);
@@ -458,98 +763,236 @@ nsf_load (char *filename, void *source, int length)
temp_nsf->pal_speed = SWAP_16 (temp_nsf->pal_speed);
/* we're now at position 80h */
- if (NULL == source) {
- fseek (fp, 0, SEEK_END);
- temp_nsf->length = ftell (fp) - NSF_HEADER_SIZE;
- } else {
+
+
+ /* Here comes the specific codes for spec version 2 */
+
+ temp_nsf->length = 0;
+
+ if (temp_nsf->version > 1) {
+ /* Get specified data size in reserved field (3 bytes). */
+ temp_nsf->length = 0 + temp_nsf->reserved[0]
+ + (temp_nsf->reserved[1] << 8)
+ + (temp_nsf->reserved[2] << 16);
+
+ }
+ /* no specified size : try to guess with file length. */
+ if (!temp_nsf->length) {
temp_nsf->length = length - NSF_HEADER_SIZE;
}
+ if (temp_nsf->length <= 0) {
+ log_printf ("nsf : [%s] not an NSF format file (missing data)\n",
+ loader->fname (loader));
+ goto error;
+ }
+
/* Allocate NSF space, and load it up! */
- temp_nsf->data = malloc (temp_nsf->length);
+ {
+ int len = temp_nsf->length;
+
+#ifdef NES6502_MEM_ACCESS_CTRL
+ /* $$$ twice memory for access control shadow mem. */
+ len <<= 1;
+#endif
+ temp_nsf->data = malloc (len);
+ }
if (NULL == temp_nsf->data) {
- log_printf ("error allocating memory for NSF data\n");
- nsf_free (&temp_nsf);
- return NULL;
+ log_printf ("nsf : [%s] error allocating nsf data\n",
+ loader->fname (loader));
+ goto error;
}
- /* seek to end of header, read in data */
- if (NULL == source) {
- fseek (fp, NSF_HEADER_SIZE, SEEK_SET);
- if (fread (temp_nsf->data, temp_nsf->length, 1, fp) != 1)
- log_printf ("error reading end of header\n");
-
- fclose (fp);
+ /* Read data */
+ if (loader->read (loader, temp_nsf->data, temp_nsf->length)) {
+ log_printf ("nsf : [%s] error reading NSF data\n", loader->fname (loader));
+ goto error;
+ }
+ /* Here comes the second part of spec > 1 : get extension */
+ while (!loader->read (loader, &nsf_file_ext, sizeof (nsf_file_ext))
+ && !memcmp (nsf_file_ext.magic, id, 4)) {
+ /* Got a NESM extension here. Checks for known extension type :
+ * right now, the only extension is "TIME" which give songs length.
+ * in frames.
+ */
+ int size;
+
+ size = 0 + nsf_file_ext.size[0]
+ + (nsf_file_ext.size[1] << 8)
+ + (nsf_file_ext.size[2] << 16)
+ + (nsf_file_ext.size[3] << 24);
+
+ if (size < sizeof (nsf_file_ext)) {
+ log_printf ("nsf : [%s] corrupt extension size (%d)\n",
+ loader->fname (loader), size);
+ /* Not a fatal error here. Just skip extension loading. */
+ break;
+ }
+ size -= sizeof (nsf_file_ext);
+
+ if (!temp_nsf->song_frames && !memcmp (nsf_file_ext.type, "TIME", 4)
+ && !(size & 3)
+ && (size >= 2 * 4)
+ && (size <= 256 * 4)) {
+
+ uint8 tmp_time[256][4];
+ int tsongs = size >> 2;
+ int i;
+ int songs = temp_nsf->num_songs;
+
+ /* Add 1 for 0 which contains total time for all songs. */
+ ++songs;
+
+ if (loader->read (loader, tmp_time, size)) {
+ log_printf ("nsf : [%s] missing extension data\n",
+ loader->fname (loader));
+ /* Not a fatal error here. Just skip extension loading. */
+ break;
+ }
+ /* Alloc song_frames for songs (not tsongs). */
+ temp_nsf->song_frames = malloc (sizeof (*temp_nsf->song_frames) * songs);
+ if (!temp_nsf->song_frames) {
+ log_printf ("nsf : [%s] extension alloc failed\n",
+ loader->fname (loader));
+ /* Not a fatal error here. Just skip extension loading. */
+ break;
+ }
- if (new_fn) {
- void *t = new_fn;
+ if (tsongs > songs) {
+ tsongs = songs;
+ }
- free (t);
+ /* Copy time info. */
+ for (i = 0; i < tsongs; ++i) {
+ temp_nsf->song_frames[i] = 0 | tmp_time[i][0]
+ | (tmp_time[i][1] << 8)
+ | (tmp_time[i][2] << 16)
+ | (tmp_time[i][2] << 24);
+ }
+ /* Clear missing (safety net). */
+ for (; i < songs; ++i) {
+ temp_nsf->song_frames[i] = 0;
+ }
+ } else if (loader->skip (loader, size)) {
+ log_printf ("nsf : [%s] extension skip failed\n", loader->fname (loader));
+ /* Not a fatal error here. Just skip extension loading. */
+ break;
}
- } else
- memcpy (temp_nsf->data, (uint8 *) source + NSF_HEADER_SIZE,
- temp_nsf->length);
+ }
+
+
+ /* Close "file" */
+ loader->close (loader);
+ loader = 0;
/* Set up some variables */
nsf_setup (temp_nsf);
-
temp_nsf->apu = NULL; /* just make sure */
if (nsf_cpuinit (temp_nsf)) {
+ log_printf ("nsf : error cpu init\n");
+ goto error;
+ }
+ return temp_nsf;
+
+ /* $$$ ben : some people tell that goto are not clean. I am not agree with
+ * them. In most case, it allow to avoid code duplications, which are as
+ * most people know a source of error... Here we are sure of being clean
+ */
+error:
+ if (loader) {
+ loader->close (loader);
+ }
+ if (temp_nsf) {
nsf_free (&temp_nsf);
- return NULL;
}
+ return 0;
+}
- return temp_nsf;
+/* Load a ROM image into memory */
+nsf_t *
+nsf_load (const char *filename, void *source, int length)
+{
+ struct nsf_loader_t *loader = 0;
+
+ /* $$$ ben : new loader */
+ if (filename) {
+ nsf_file_loader.fname = (char *) filename;
+ loader = &nsf_file_loader.loader;
+ } else {
+ nsf_mem_loader.data = source;
+ nsf_mem_loader.len = length;
+ nsf_mem_loader.fname[0] = 0;
+ loader = &nsf_mem_loader.loader;
+ }
+ return nsf_load_extended (loader);
}
/* Free an NSF */
void
-nsf_free (nsf_t ** nsf)
+nsf_free (nsf_t ** pnsf)
{
- if (*nsf) {
- if ((*nsf)->apu)
- apu_destroy ((*nsf)->apu);
+ nsf_t *nsf;
+
+ if (!pnsf) {
+ return;
+ }
- nes_shutdown (*nsf);
+ nsf = *pnsf;
+ /* $$$ ben : Don't see why passing a pointer to pointer
+ * is not to clear it :) */
+ *pnsf = 0;
- if ((*nsf)->data) {
- void *mem = (*nsf)->data;
+ if (nsf) {
+ if (nsf->apu)
+ apu_destroy (nsf->apu);
- free (mem);
- }
+ nes_shutdown (nsf);
- free (*nsf);
+ if (nsf->data)
+ free (nsf->data);
+
+ if (nsf->song_frames)
+ free (nsf->song_frames);
+
+ free (nsf);
}
}
-void
+int
nsf_setchan (nsf_t * nsf, int chan, boolean enabled)
{
- if (nsf) {
- nsf_setcontext (nsf);
- apu_setchan (chan, enabled);
- }
+ if (!nsf)
+ return -1;
+
+ nsf_setcontext (nsf);
+ return apu_setchan (chan, enabled);
}
-void
+int
nsf_playtrack (nsf_t * nsf, int track, int sample_rate, int sample_bits,
boolean stereo)
{
- ASSERT (nsf);
+ if (!nsf) {
+ return -1;
+ }
/* make this NSF the current context */
nsf_setcontext (nsf);
/* create the APU */
- if (nsf->apu)
+ if (nsf->apu) {
apu_destroy (nsf->apu);
+ }
nsf->apu = apu_create (sample_rate, nsf->playback_rate, sample_bits, stereo);
if (NULL == nsf->apu) {
- nsf_free (&nsf);
- return;
+ /* $$$ ben : from my point of view this is not clean. Function should
+ * never destroy object it has not created...
+ */
+ /* nsf_free(&nsf); */
+ return -1;
}
apu_setext (nsf->apu, nsf_getext (nsf));
@@ -572,43 +1015,24 @@ nsf_playtrack (nsf_t * nsf, int track, int sample_rate, int sample_bits,
apu_reset ();
nsf_inittune (nsf);
+
+ return nsf->current_song;
}
-void
+int
nsf_setfilter (nsf_t * nsf, int filter_type)
{
- if (nsf) {
- nsf_setcontext (nsf);
- apu_setfilter (filter_type);
+ if (!nsf) {
+ return -1;
}
+ nsf_setcontext (nsf);
+ return apu_setfilter (filter_type);
}
/*
** $Log$
-** Revision 1.4 2006/10/17 11:04:14 tpm
-** Patch by: Josep Torra Valles <josep at fluendo com>
-** * gst/nsf/fds_snd.c:
-** * gst/nsf/mmc5_snd.c:
-** * gst/nsf/nsf.c:
-** * gst/nsf/vrc7_snd.c:
-** * gst/nsf/vrcvisnd.c:
-** Fix some things the Forte compiler warns about (#362626).
-**
-** Revision 1.3 2006/07/19 11:43:50 tpm
-** * gst/nsf/nsf.c: (nsf_load):
-** Really fix compilation. Apparently it's not enough to
-** just check the return value for errors, but we need to
-** check for short reads as well (now if only we handled
-** them too ...). Fixes #347935.
-**
-** Revision 1.2 2006/07/18 09:36:46 wtay
-** * gst/nsf/nsf.c: (nsf_load):
-** Fix compilation by not ignoring return values of fread.
-**
-** Revision 1.1 2006/07/13 15:07:28 wtay
-** Based on patches by: Johan Dahlin <johan at gnome dot org>
-** Ronald Bultje <rbultje at ronald dot bitfreak dot net>
-** * configure.ac:
+** Revision 1.5 2008/03/25 15:56:12 slomo
+** Patch by: Andreas Henriksson <andreas at fatal dot set>
** * gst/nsf/Makefile.am:
** * gst/nsf/dis6502.h:
** * gst/nsf/fds_snd.c:
@@ -616,7 +1040,6 @@ nsf_setfilter (nsf_t * nsf, int filter_type)
** * gst/nsf/fmopl.c:
** * gst/nsf/fmopl.h:
** * gst/nsf/gstnsf.c:
-** * gst/nsf/gstnsf.h:
** * gst/nsf/log.c:
** * gst/nsf/log.h:
** * gst/nsf/memguard.c:
@@ -635,7 +1058,19 @@ nsf_setfilter (nsf_t * nsf, int filter_type)
** * gst/nsf/vrc7_snd.h:
** * gst/nsf/vrcvisnd.c:
** * gst/nsf/vrcvisnd.h:
-** Added NSF decoder plugin. Fixes 151192.
+** Update our internal nosefart to nosefart-2.7-mls to fix segfaults
+** on some files. Fixes bug #498237.
+** Remove some // comments, fix some compiler warnings and use pow()
+** instead of a slow, selfmade implementation.
+**
+** Revision 1.3 2003/05/01 22:34:20 benjihan
+** New NSF plugin
+**
+** Revision 1.2 2003/04/09 14:50:32 ben
+** Clean NSF api.
+**
+** Revision 1.1 2003/04/08 20:53:00 ben
+** Adding more files...
**
** Revision 1.14 2000/07/05 14:54:45 matt
** fix for naughty Crystalis rip