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.c632
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
-**
-*/