diff options
Diffstat (limited to 'src/libxineadec/nosefart/nsf.c')
-rw-r--r-- | src/libxineadec/nosefart/nsf.c | 632 |
1 files changed, 0 insertions, 632 deletions
diff --git a/src/libxineadec/nosefart/nsf.c b/src/libxineadec/nosefart/nsf.c deleted file mode 100644 index 6bbc96423..000000000 --- a/src/libxineadec/nosefart/nsf.c +++ /dev/null @@ -1,632 +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) -{ - 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; -} - -/* can be used for both banked and non-bankswitched NSFs */ -static void nsf_bankswitch(uint32 address, uint8 value) -{ - int cpu_page; - uint8 *offset; - - cpu_page = address & 0x0F; - offset = (cur_nsf->data - (cur_nsf->load_addr & 0x0FFF)) + (value << 12); - - nes6502_getcontext(cur_nsf->cpu); - cur_nsf->cpu->mem_page[cpu_page] = offset; - 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); - - 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) -{ - //nsf_setcontext(nsf); /* future expansion =) */ - - /* one frame of NES processing */ - nsf_setup_routine(nsf->play_addr, 0, 0); - nes6502_execute((int) NES_FRAME_CYCLES); -} - -/* Deallocate memory */ -static 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); - } -} - -void nsf_init(void) -{ - nes6502_init(); -} - -/* 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; - } - - nsf->cpu->read_handler = nsf_readhandler; - nsf->cpu->write_handler = nsf_writehandler; - - return 0; -} - -static void nsf_setup(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; - 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 */ - } - - 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 */ - -/* Load a ROM image into memory */ -nsf_t *nsf_load(char *filename, void *source, int length) -{ - FILE *fp = NULL; - char *new_fn = NULL; - nsf_t *temp_nsf; - - if (NULL == filename && NULL == source) - return NULL; - - if (NULL == source) - { - fp = fopen(filename, "rb"); - - /* 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 (NULL == strrchr(new_fn, '.')) - strcat(new_fn, ".nsf"); - - fp = fopen(new_fn, "rb"); - - if (NULL == fp) - { - log_printf("could not find file '%s'\n", new_fn); - free(new_fn); - return NULL; - } - } - } - - temp_nsf = malloc(sizeof(nsf_t)); - if (NULL == temp_nsf) { - fclose(fp); - free(new_fn); - return NULL; - } - - /* Read in the header */ - if (NULL == source) - fread(temp_nsf, 1, NSF_HEADER_SIZE, fp); - else - memcpy(temp_nsf, source, NSF_HEADER_SIZE); - - 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; - } - - /* 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 */ - if (NULL == source) - { - fseek(fp, 0, SEEK_END); - temp_nsf->length = ftell(fp) - NSF_HEADER_SIZE; - } - else - { - temp_nsf->length = length - NSF_HEADER_SIZE; - } - - /* 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; - } - - /* 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); - - fclose(fp); - - if (new_fn) - free(new_fn); - } - else - memcpy(temp_nsf->data, (uint8 *) source + NSF_HEADER_SIZE, length - NSF_HEADER_SIZE); - - /* 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; - } - - 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); - } -} - -void nsf_setchan(nsf_t *nsf, int chan, boolean enabled) -{ - if (nsf) - { - nsf_setcontext(nsf); - apu_setchan(chan, enabled); - } -} - -void nsf_playtrack(nsf_t *nsf, int track, int sample_rate, int sample_bits, boolean stereo) -{ - ASSERT(nsf); - - /* 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) - { - nsf_free(&nsf); - return; - } - - 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); -} - -void nsf_setfilter(nsf_t *nsf, int filter_type) -{ - if (nsf) - { - nsf_setcontext(nsf); - 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.2 2003/01/09 18:36:40 jkeil -** memcpy copies too much, corrupts malloc heap -** -** Revision 1.1 2003/01/08 07:04:35 tmmm -** initial import of Nosefart sources -** -** 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 -** -*/ |