summaryrefslogtreecommitdiff
path: root/contrib/nosefart/nsf.c
diff options
context:
space:
mode:
authorDarren Salt <linux@youmustbejoking.demon.co.uk>2011-03-20 14:25:40 +0000
committerDarren Salt <linux@youmustbejoking.demon.co.uk>2011-03-20 14:25:40 +0000
commitced4b1666765715376058ea16669d18a4f3e68e6 (patch)
treedd8ca75cfc4f841b82f00ea7b24b849ee277577a /contrib/nosefart/nsf.c
parent77aa841ba7f4249dceaea6470cb025f976a6e57a (diff)
parent5f74ef4b65a270a8b985917373bc0e219fa06ecd (diff)
downloadxine-lib-ced4b1666765715376058ea16669d18a4f3e68e6.tar.gz
xine-lib-ced4b1666765715376058ea16669d18a4f3e68e6.tar.bz2
Merge from 1.1.
--HG-- rename : src/libxineadec/gsm610/Makefile.am => contrib/gsm610/Makefile.am rename : src/libxineadec/nosefart/diff_to_nosefart_cvs.patch => contrib/nosefart/diff_to_nosefart_cvs.patch rename : src/libxineadec/nosefart/nes6502.c => contrib/nosefart/nes6502.c rename : src/libxineadec/nosefart/nes6502.h => contrib/nosefart/nes6502.h rename : src/libxineadec/nosefart/nes_apu.c => contrib/nosefart/nes_apu.c rename : src/libxineadec/nosefart/nes_apu.h => contrib/nosefart/nes_apu.h rename : src/libxineadec/nosefart/nsf.c => contrib/nosefart/nsf.c rename : src/libxineadec/nosefart/nsf.h => contrib/nosefart/nsf.h rename : src/libxineadec/nosefart/types.h => contrib/nosefart/types.h rename : src/libxineadec/nosefart/version.h => contrib/nosefart/version.h rename : doc/faq/faq.sgml => doc/faq/faq.docbook rename : src/libsputext/demux_sputext.c => src/spu_dec/sputext_demuxer.c rename : src/libxinevdec/image.c => src/video_dec/image.c
Diffstat (limited to 'contrib/nosefart/nsf.c')
-rw-r--r--contrib/nosefart/nsf.c769
1 files changed, 596 insertions, 173 deletions
diff --git a/contrib/nosefart/nsf.c b/contrib/nosefart/nsf.c
index 6bbc96423..69f77546b 100644
--- a/contrib/nosefart/nsf.c
+++ b/contrib/nosefart/nsf.c
@@ -23,6 +23,7 @@
** $Id: nsf.c,v 1.4 2006/09/26 00:52:17 dgp85 Exp $
*/
+
#include <stdio.h>
#include <string.h>
#include "types.h"
@@ -50,25 +51,34 @@ static void nsf_setcontext(nsf_t *nsf)
static uint8 read_mirrored_ram(uint32 address)
{
- return cur_nsf->cpu->mem_page[0][address & 0x7FF];
+ 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)
{
- cur_nsf->cpu->mem_page[0][address & 0x7FF] = 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;
}
/* can be used for both banked and non-bankswitched NSFs */
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);
}
@@ -248,6 +258,18 @@ static void 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! */
@@ -289,36 +311,81 @@ static void nsf_inittune(nsf_t *nsf)
void nsf_frame(nsf_t *nsf)
{
- //nsf_setcontext(nsf); /* future expansion =) */
+ // 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 */
-static void nes_shutdown(nsf_t *nsf)
+void nes_shutdown(nsf_t *nsf)
{
int i;
ASSERT(nsf);
-
+
if (nsf->cpu)
{
if (nsf->cpu->mem_page[0])
- free(nsf->cpu->mem_page[0]);
- for (i = 5; i <= 7; i++)
- {
- if (nsf->cpu->mem_page[i])
- free(nsf->cpu->mem_page[i]);
+ {
+ 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])
+ {
+ 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]);
+ }
+ 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 nsf_init(void)
+int nsf_init(void)
{
nes6502_init();
+ return 0;
}
/* Initialize NES CPU, hardware, etc. */
@@ -344,18 +411,27 @@ static int 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)
@@ -370,9 +446,17 @@ static void 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])
@@ -389,212 +473,551 @@ static void 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;
+ a = strrchr(fn,'.');
+ b = strrchr(fn,'/');
+ c = strrchr(fn,'\\');
+ if (a <= b || a <= c) {
+ a = 0;
+ }
+ return a;
+}
- if (NULL == filename && NULL == source)
- return NULL;
-
- if (NULL == source)
- {
- fp = fopen(filename, "rb");
+/* $$$ ben : FILE loader */
+struct nsf_file_loader_t {
+ struct nsf_loader_t loader;
+ FILE *fp;
+ char * fname;
+ int name_allocated;
+};
- /* 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);
+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;
+}
- if (NULL == strrchr(new_fn, '.'))
- strcat(new_fn, ".nsf");
+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;
+ }
+}
- fp = fopen(new_fn, "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);
+ if (r >= 0) {
+ r = n-r;
+ }
+ return r;
+}
- if (NULL == fp)
- {
- log_printf("could not find file '%s'\n", new_fn);
- free(new_fn);
- return NULL;
- }
- }
- }
+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;
+}
- temp_nsf = malloc(sizeof(nsf_t));
- if (NULL == temp_nsf) {
- fclose(fp);
- free(new_fn);
- return NULL;
- }
+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;
+ r = fseek(floader->fp, n, SEEK_CUR);
+ return r;
+}
- /* Read in the header */
- if (NULL == source)
- fread(temp_nsf, 1, NSF_HEADER_SIZE, fp);
- else
- memcpy(temp_nsf, source, NSF_HEADER_SIZE);
+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>";
+}
- if (memcmp(temp_nsf->id, NSF_MAGIC, 5))
- {
- if (NULL == source)
- {
- log_printf("%s is not an NSF format file\n", new_fn);
- fclose(fp);
- free(new_fn);
- }
- nsf_free(&temp_nsf);
- return 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];
+};
- /* fixup endianness */
- temp_nsf->load_addr = SWAP_16(temp_nsf->load_addr);
- temp_nsf->init_addr = SWAP_16(temp_nsf->init_addr);
- temp_nsf->play_addr = SWAP_16(temp_nsf->play_addr);
- temp_nsf->ntsc_speed = SWAP_16(temp_nsf->ntsc_speed);
- temp_nsf->pal_speed = SWAP_16(temp_nsf->pal_speed);
+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;
+}
- /* we're now at position 80h */
- if (NULL == source)
- {
- fseek(fp, 0, SEEK_END);
- temp_nsf->length = ftell(fp) - NSF_HEADER_SIZE;
- }
- else
- {
- temp_nsf->length = length - NSF_HEADER_SIZE;
- }
+static void nfs_close_mem(struct nsf_loader_t *loader)
+{
+ struct nsf_mem_loader_t * mloader = (struct nsf_mem_loader_t *)loader;
+ mloader->data = 0;
+ mloader->cur = 0;
+ mloader->len = 0;
+}
- /* Allocate NSF space, and load it up! */
- temp_nsf->data = malloc(temp_nsf->length);
- if (NULL == temp_nsf->data)
- {
- log_printf("error allocating memory for NSF data\n");
- nsf_free(&temp_nsf);
- return NULL;
- }
+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;
+ 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;
+}
- /* seek to end of header, read in data */
- if (NULL == source)
- {
- fseek(fp, NSF_HEADER_SIZE, SEEK_SET);
- fread(temp_nsf->data, temp_nsf->length, 1, fp);
+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;
+}
- fclose(fp);
+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;
+}
- if (new_fn)
- free(new_fn);
- }
- else
- memcpy(temp_nsf->data, (uint8 *) source + NSF_HEADER_SIZE, length - NSF_HEADER_SIZE);
+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;
+}
+
+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);
+ goto error;
+ }
+#endif
+
+ /* Read magic */
+ if (loader->read(loader, id, 5)) {
+ log_printf("nsf : [%s] error reading magic number\n",
+ loader->fname);
+ goto error;
+ }
+
+ /* Check magic */
+ if (memcmp(id, NSF_MAGIC, 5)) {
+ log_printf("nsf : [%s] is not an NSF format file\n",
+ loader->fname);
+ 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);
+ 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);
+ goto error;
+ }
+
+ /* fixup endianness */
+ temp_nsf->load_addr = SWAP_16(temp_nsf->load_addr);
+ temp_nsf->init_addr = SWAP_16(temp_nsf->init_addr);
+ temp_nsf->play_addr = SWAP_16(temp_nsf->play_addr);
+ temp_nsf->ntsc_speed = SWAP_16(temp_nsf->ntsc_speed);
+ temp_nsf->pal_speed = SWAP_16(temp_nsf->pal_speed);
+
+ /* we're now at position 80h */
+
+
+ /* 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);
+ goto error;
+ }
+
+ /* Allocate NSF space, and load it up! */
+ {
+ 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("nsf : [%s] error allocating nsf data\n",
+ loader->fname);
+ goto error;
+ }
+
+ /* Read data */
+ if (loader->read(loader, temp_nsf->data, temp_nsf->length)) {
+ log_printf("nsf : [%s] error reading NSF data\n",
+ loader->fname);
+ 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, 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);
+ /* 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);
+ /* Not a fatal error here. Just skip extension loading. */
+ break;
+ }
+
+ if (tsongs > songs) {
+ tsongs = songs;
+ }
+
+ /* 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);
+ /* Not a fatal error here. Just skip extension loading. */
+ break;
+ }
+ }
+
+
+ /* 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))
- {
- nsf_free(&temp_nsf);
- return NULL;
+ if (nsf_cpuinit(temp_nsf)) {
+ log_printf("nsf : error cpu init\n");
+ goto error;
}
-
return temp_nsf;
-}
-
-/* Free an NSF */
-void nsf_free(nsf_t **nsf)
-{
- if (*nsf)
- {
- if ((*nsf)->apu)
- apu_destroy((*nsf)->apu);
-
- nes_shutdown(*nsf);
- if ((*nsf)->data)
- free((*nsf)->data);
-
- free(*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 0;
}
-void nsf_setchan(nsf_t *nsf, int chan, boolean enabled)
+/* Load a ROM image into memory */
+nsf_t *nsf_load(const char *filename, void *source, int length)
{
- if (nsf)
- {
- nsf_setcontext(nsf);
- apu_setchan(chan, enabled);
- }
+ 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);
}
-void nsf_playtrack(nsf_t *nsf, int track, int sample_rate, int sample_bits, boolean stereo)
+/* Free an NSF */
+void nsf_free(nsf_t **pnsf)
{
- ASSERT(nsf);
+ nsf_t *nsf;
- /* make this NSF the current context */
- nsf_setcontext(nsf);
+ if (!pnsf) {
+ return;
+ }
- /* create the APU */
- if (nsf->apu)
+ nsf = *pnsf;
+ /* $$$ ben : Don't see why passing a pointer to pointer
+ * is not to clear it :) */
+ *pnsf = 0;
+
+ if (nsf) {
+ 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;
- }
+ nes_shutdown(nsf);
+
+ if (nsf->data)
+ free(nsf->data);
- apu_setext(nsf->apu, nsf_getext(nsf));
+ if (nsf->song_frames)
+ free (nsf->song_frames);
- /* go ahead and init all the read/write handlers */
- build_address_handlers(nsf);
+ free(nsf);
+ }
+}
- /* convenience? */
- nsf->process = nsf->apu->process;
+int nsf_setchan(nsf_t *nsf, int chan, boolean enabled)
+{
+ if (!nsf)
+ return -1;
- nes6502_setcontext(nsf->cpu);
+ nsf_setcontext(nsf);
+ return apu_setchan(chan, enabled);
+}
- if (track > nsf->num_songs)
- track = nsf->num_songs;
- else if (track < 1)
- track = 1;
+int nsf_playtrack(nsf_t *nsf, int track, int sample_rate, int sample_bits,
+ boolean stereo)
+{
+ if (!nsf) {
+ return -1;
+ }
+
+ /* make this NSF the current context */
+ nsf_setcontext(nsf);
+
+ /* create the APU */
+ if (nsf->apu) {
+ apu_destroy(nsf->apu);
+ }
+
+ nsf->apu = apu_create(sample_rate, nsf->playback_rate, sample_bits, stereo);
+ if (NULL == nsf->apu)
+ {
+ /* $$$ ben : from my point of view this is not clean. Function should
+ * never destroy object it has not created...
+ */
+ /* nsf_free(&nsf); */
+ return -1;
+ }
- nsf->current_song = track;
+ apu_setext(nsf->apu, nsf_getext(nsf));
+
+ /* go ahead and init all the read/write handlers */
+ build_address_handlers(nsf);
+
+ /* convenience? */
+ nsf->process = nsf->apu->process;
+
+ nes6502_setcontext(nsf->cpu);
+
+ if (track > nsf->num_songs)
+ track = nsf->num_songs;
+ else if (track < 1)
+ track = 1;
+
+ nsf->current_song = track;
- apu_reset();
+ apu_reset();
+
+ nsf_inittune(nsf);
- nsf_inittune(nsf);
+ return nsf->current_song;
}
-void nsf_setfilter(nsf_t *nsf, int filter_type)
+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: nsf.c,v $
-** Revision 1.4 2006/09/26 00:52:17 dgp85
-** Free the filename string and close the file pointer when returning.
-**
-** Found by Coverity Scan.
-**
-** Revision 1.3 2003/08/25 21:51:43 f1rmb
-** Reduce GCC verbosity (various prototype declaration fixes). ffmpeg, wine and fft*post are untouched (fft: for now).
+** Revision 1.3 2003/05/01 22:34:20 benjihan
+** New NSF plugin
**
-** Revision 1.2 2003/01/09 18:36:40 jkeil
-** memcpy copies too much, corrupts malloc heap
+** Revision 1.2 2003/04/09 14:50:32 ben
+** Clean NSF api.
**
-** Revision 1.1 2003/01/08 07:04:35 tmmm
-** initial import of Nosefart sources
+** 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