summaryrefslogtreecommitdiff
path: root/src/libxineadec/nosefart/nsf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libxineadec/nosefart/nsf.c')
-rw-r--r--src/libxineadec/nosefart/nsf.c1055
1 files changed, 0 insertions, 1055 deletions
diff --git a/src/libxineadec/nosefart/nsf.c b/src/libxineadec/nosefart/nsf.c
deleted file mode 100644
index 69f77546b..000000000
--- a/src/libxineadec/nosefart/nsf.c
+++ /dev/null
@@ -1,1055 +0,0 @@
-/*
-** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com)
-**
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of version 2 of the GNU Library General
-** Public License as published by the Free Software Foundation.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-** Library General Public License for more details. To obtain a
-** copy of the GNU Library General Public License, write to the Free
-** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-** Any permitted reproduction of these routines, in whole or in part,
-** must bear this legend.
-**
-**
-** nsf.c
-**
-** NSF loading/saving related functions
-** $Id: nsf.c,v 1.4 2006/09/26 00:52:17 dgp85 Exp $
-*/
-
-
-#include <stdio.h>
-#include <string.h>
-#include "types.h"
-#include "nsf.h"
-#include "log.h"
-#include "nes6502.h"
-#include "nes_apu.h"
-#include "vrcvisnd.h"
-#include "vrc7_snd.h"
-#include "mmc5_snd.h"
-#include "fds_snd.h"
-
-/* TODO: bleh! should encapsulate in NSF */
-#define MAX_ADDRESS_HANDLERS 32
-static nes6502_memread nsf_readhandler[MAX_ADDRESS_HANDLERS];
-static nes6502_memwrite nsf_writehandler[MAX_ADDRESS_HANDLERS];
-
-static nsf_t *cur_nsf = NULL;
-
-static void nsf_setcontext(nsf_t *nsf)
-{
- ASSERT(nsf);
- cur_nsf = 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;
-}
-
-/* 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;
- 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 },
- { -1, -1, NULL }
-};
-
-static nes6502_memwrite default_writehandler[] =
-{
- { 0x0800, 0x1FFF, write_mirrored_ram },
- { 0x4000, 0x4017, apu_write },
- { 0x5FF6, 0x5FFF, nsf_bankswitch },
- { -1, -1, NULL}
-};
-
-static uint8 invalid_read(uint32 address)
-{
-#ifdef NOFRENDO_DEBUG
- log_printf("filthy NSF read from $%04X\n", address);
-#endif /* NOFRENDO_DEBUG */
-
- return 0xFF;
-}
-
-static void invalid_write(uint32 address, uint8 value)
-{
-#ifdef NOFRENDO_DEBUG
- log_printf("filthy NSF tried to write $%02X to $%04X\n", value, address);
-#endif /* NOFRENDO_DEBUG */
-}
-
-/* set up the address handlers that the CPU uses */
-static void build_address_handlers(nsf_t *nsf)
-{
- int count, num_handlers;
-
- memset(nsf_readhandler, 0, sizeof(nsf_readhandler));
- memset(nsf_writehandler, 0, sizeof(nsf_writehandler));
-
- num_handlers = 0;
- for (count = 0; num_handlers < MAX_ADDRESS_HANDLERS; count++, num_handlers++)
- {
- if (NULL == default_readhandler[count].read_func)
- break;
-
- memcpy(&nsf_readhandler[num_handlers], &default_readhandler[count],
- sizeof(nes6502_memread));
- }
-
- if (nsf->apu->ext)
- {
- if (NULL != nsf->apu->ext->mem_read)
- {
- for (count = 0; num_handlers < MAX_ADDRESS_HANDLERS; count++, num_handlers++)
- {
- if (NULL == nsf->apu->ext->mem_read[count].read_func)
- break;
-
- memcpy(&nsf_readhandler[num_handlers], &nsf->apu->ext->mem_read[count],
- sizeof(nes6502_memread));
- }
- }
- }
-
- /* catch-all for bad reads */
- nsf_readhandler[num_handlers].min_range = 0x2000; /* min address */
- nsf_readhandler[num_handlers].max_range = 0x5BFF; /* max address */
- nsf_readhandler[num_handlers].read_func = invalid_read; /* handler */
- num_handlers++;
- nsf_readhandler[num_handlers].min_range = -1;
- nsf_readhandler[num_handlers].max_range = -1;
- nsf_readhandler[num_handlers].read_func = NULL;
- num_handlers++;
- ASSERT(num_handlers <= MAX_ADDRESS_HANDLERS);
-
- num_handlers = 0;
- for (count = 0; num_handlers < MAX_ADDRESS_HANDLERS; count++, num_handlers++)
- {
- if (NULL == default_writehandler[count].write_func)
- break;
-
- memcpy(&nsf_writehandler[num_handlers], &default_writehandler[count],
- sizeof(nes6502_memwrite));
- }
-
- if (nsf->apu->ext)
- {
- if (NULL != nsf->apu->ext->mem_write)
- {
- for (count = 0; num_handlers < MAX_ADDRESS_HANDLERS; count++, num_handlers++)
- {
- if (NULL == nsf->apu->ext->mem_write[count].write_func)
- break;
-
- memcpy(&nsf_writehandler[num_handlers], &nsf->apu->ext->mem_write[count],
- sizeof(nes6502_memwrite));
- }
- }
- }
-
- /* catch-all for bad writes */
- nsf_writehandler[num_handlers].min_range = 0x2000; /* min address */
- nsf_writehandler[num_handlers].max_range = 0x5BFF; /* max address */
- nsf_writehandler[num_handlers].write_func = invalid_write; /* handler */
- num_handlers++;
- /* protect region at $8000-$FFFF */
- nsf_writehandler[num_handlers].min_range = 0x8000; /* min address */
- nsf_writehandler[num_handlers].max_range = 0xFFFF; /* max address */
- nsf_writehandler[num_handlers].write_func = invalid_write; /* handler */
- num_handlers++;
- nsf_writehandler[num_handlers].min_range = -1;
- nsf_writehandler[num_handlers].max_range = -1;
- nsf_writehandler[num_handlers].write_func = NULL;
- num_handlers++;
- ASSERT(num_handlers <= MAX_ADDRESS_HANDLERS);
-}
-
-#define NSF_ROUTINE_LOC 0x5000
-
-/* sets up a simple loop that calls the desired routine and spins */
-static void nsf_setup_routine(uint32 address, uint8 a_reg, uint8 x_reg)
-{
- uint8 *mem;
-
- nes6502_getcontext(cur_nsf->cpu);
- mem = cur_nsf->cpu->mem_page[NSF_ROUTINE_LOC >> 12] + (NSF_ROUTINE_LOC & 0x0FFF);
-
- /* our lovely 4-byte 6502 NSF player */
- mem[0] = 0x20; /* JSR address */
- mem[1] = address & 0xFF;
- mem[2] = address >> 8;
- mem[3] = 0xF2; /* JAM (cpu kill op) */
-
- cur_nsf->cpu->pc_reg = NSF_ROUTINE_LOC;
- cur_nsf->cpu->a_reg = a_reg;
- cur_nsf->cpu->x_reg = x_reg;
- cur_nsf->cpu->y_reg = 0;
- cur_nsf->cpu->s_reg = 0xFF;
-
- nes6502_setcontext(cur_nsf->cpu);
-}
-
-/* retrieve any external soundchip driver */
-static apuext_t *nsf_getext(nsf_t *nsf)
-{
- switch (nsf->ext_sound_type)
- {
- case EXT_SOUND_VRCVI:
- return &vrcvi_ext;
-
- case EXT_SOUND_VRCVII:
- return &vrc7_ext;
-
- case EXT_SOUND_FDS:
- return &fds_ext;
-
- case EXT_SOUND_MMC5:
- return &mmc5_ext;
-
- case EXT_SOUND_NAMCO106:
- case EXT_SOUND_SUNSOFT_FME07:
- case EXT_SOUND_NONE:
- default:
- return NULL;
- }
-}
-
-static void nsf_inittune(nsf_t *nsf)
-{
- uint8 bank, x_reg;
- uint8 start_bank, num_banks;
-
- memset(nsf->cpu->mem_page[0], 0, 0x800);
- 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)
- {
- nsf_bankswitch(0x5FF6, nsf->bankswitch_info[6]);
- nsf_bankswitch(0x5FF7, nsf->bankswitch_info[7]);
- }
-
- for (bank = 0; bank < 8; bank++)
- nsf_bankswitch(0x5FF8 + bank, nsf->bankswitch_info[bank]);
- }
- else
- {
- /* not bankswitched, just page in our standard stuff */
- ASSERT(nsf->load_addr + nsf->length <= 0x10000);
-
- /* avoid ripper filth */
- for (bank = 0; bank < 8; bank++)
- nsf_bankswitch(0x5FF8 + bank, bank);
-
- start_bank = nsf->load_addr >> 12;
- num_banks = ((nsf->load_addr + nsf->length - 1) >> 12) - start_bank + 1;
-
- for (bank = 0; bank < num_banks; bank++)
- nsf_bankswitch(0x5FF0 + start_bank + bank, bank);
- }
-
- /* determine PAL/NTSC compatibility shite */
- if (nsf->pal_ntsc_bits & NSF_DEDICATED_PAL)
- x_reg = 1;
- else
- x_reg = 0;
-
- /* execute 1 frame or so; let init routine run free */
- nsf_setup_routine(nsf->init_addr, (uint8) (nsf->current_song - 1), x_reg);
- nes6502_execute((int) NES_FRAME_CYCLES);
-}
-
-void nsf_frame(nsf_t *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 */
-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]);/*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);
- }
-}
-
-int nsf_init(void)
-{
- nes6502_init();
- return 0;
-}
-
-/* Initialize NES CPU, hardware, etc. */
-static int nsf_cpuinit(nsf_t *nsf)
-{
- int i;
-
- nsf->cpu = malloc(sizeof(nes6502_context));
- if (NULL == nsf->cpu)
- return -1;
-
- memset(nsf->cpu, 0, sizeof(nes6502_context));
-
- nsf->cpu->mem_page[0] = malloc(0x800);
- if (NULL == nsf->cpu->mem_page[0])
- return -1;
-
- /* allocate some space for the NSF "player" MMC5 EXRAM, and WRAM */
- for (i = 5; i <= 7; i++)
- {
- nsf->cpu->mem_page[i] = malloc(0x1000);
- if (NULL == nsf->cpu->mem_page[i])
- 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 unsigned int nsf_playback_rate(nsf_t *nsf)
-{
- if (nsf->pal_ntsc_bits & NSF_DEDICATED_PAL)
- {
- if (nsf->pal_speed)
- nsf->playback_rate = 1000000 / nsf->pal_speed;
- else
- nsf->playback_rate = 50; /* 50 Hz */
- }
- else
- {
- if (nsf->ntsc_speed)
- nsf->playback_rate = 1000000 / nsf->ntsc_speed;
- else
- nsf->playback_rate = 60; /* 60 Hz */
- }
- return 0;
-}
-
-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;
- break;
- }
- }
-}
-
-#ifdef HOST_LITTLE_ENDIAN
-#define SWAP_16(x) (x)
-#else /* !HOST_LITTLE_ENDIAN */
-#define SWAP_16(x) (((uint16) x >> 8) | (((uint16) x & 0xFF) << 8))
-#endif /* !HOST_LITTLE_ENDIAN */
-
-/* $$$ ben : find extension. Should be OK with DOS, but not with some
- * OS like RiscOS ... */
-static char * find_ext(char *fn)
-{
- char * a, * b, * c;
- 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;
- }
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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)) {
- 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 0;
-}
-
-/* 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 **pnsf)
-{
- nsf_t *nsf;
-
- if (!pnsf) {
- return;
- }
-
- 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);
-
- nes_shutdown(nsf);
-
- if (nsf->data)
- free(nsf->data);
-
- if (nsf->song_frames)
- free (nsf->song_frames);
-
- free(nsf);
- }
-}
-
-int nsf_setchan(nsf_t *nsf, int chan, boolean enabled)
-{
- if (!nsf)
- return -1;
-
- nsf_setcontext(nsf);
- return apu_setchan(chan, enabled);
-}
-
-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;
- }
-
- 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();
-
- nsf_inittune(nsf);
-
- return nsf->current_song;
-}
-
-int nsf_setfilter(nsf_t *nsf, int filter_type)
-{
- if (!nsf) {
- return -1;
- }
- nsf_setcontext(nsf);
- return apu_setfilter(filter_type);
-}
-
-/*
-** $Log: nsf.c,v $
-** 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
-**
-** Revision 1.13 2000/07/04 04:59:38 matt
-** removed DOS-specific stuff, fixed bug in address handlers
-**
-** Revision 1.12 2000/07/03 02:19:36 matt
-** dynamic address range handlers, cleaner and faster
-**
-** Revision 1.11 2000/06/23 03:27:58 matt
-** cleaned up external sound inteface
-**
-** Revision 1.10 2000/06/20 20:42:47 matt
-** accuracy changes
-**
-** Revision 1.9 2000/06/20 00:05:58 matt
-** changed to driver-based external sound generation
-**
-** Revision 1.8 2000/06/13 03:51:54 matt
-** update API to take freq/sample data on nsf_playtrack
-**
-** Revision 1.7 2000/06/12 03:57:14 matt
-** more robust checking for winamp plugin
-**
-** Revision 1.6 2000/06/12 01:13:00 matt
-** added CPU/APU as members of the nsf struct
-**
-** Revision 1.5 2000/06/11 16:09:21 matt
-** nsf_free is more robust
-**
-** Revision 1.4 2000/06/09 15:12:26 matt
-** initial revision
-**
-*/