mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-20 23:36:38 +00:00
1e5dc348d4
Original commit message from CVS: * 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.
664 lines
16 KiB
C
664 lines
16 KiB
C
/*
|
|
** 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$
|
|
*/
|
|
|
|
#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)
|
|
{
|
|
/* future expansion =) */
|
|
/*nsf_setcontext(nsf); */
|
|
|
|
/* one frame of NES processing */
|
|
nsf_setup_routine (nsf->play_addr, 0, 0);
|
|
nes6502_execute ((int) NES_FRAME_CYCLES);
|
|
}
|
|
|
|
/* Deallocate memory */
|
|
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]);
|
|
for (i = 5; i <= 7; i++) {
|
|
if (nsf->cpu->mem_page[i])
|
|
free (nsf->cpu->mem_page[i]);
|
|
}
|
|
mem = nsf->cpu;
|
|
free (mem);
|
|
}
|
|
}
|
|
|
|
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) {
|
|
void *t = new_fn;
|
|
|
|
log_printf ("could not find file '%s'\n", new_fn);
|
|
free (t);
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
temp_nsf = malloc (sizeof (nsf_t));
|
|
if (NULL == temp_nsf)
|
|
return NULL;
|
|
|
|
/* 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);
|
|
|
|
if (memcmp (temp_nsf->id, NSF_MAGIC, 5)) {
|
|
if (NULL == source) {
|
|
void *t = new_fn;
|
|
|
|
log_printf ("%s is not an NSF format file\n", new_fn);
|
|
fclose (fp);
|
|
free (t);
|
|
}
|
|
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);
|
|
if (fread (temp_nsf->data, temp_nsf->length, 1, fp) != 1)
|
|
log_printf ("error reading end of header\n");
|
|
|
|
fclose (fp);
|
|
|
|
|
|
if (new_fn) {
|
|
void *t = new_fn;
|
|
|
|
free (t);
|
|
}
|
|
} else
|
|
memcpy (temp_nsf->data, (uint8 *) source + NSF_HEADER_SIZE,
|
|
temp_nsf->length);
|
|
|
|
/* 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) {
|
|
void *mem = (*nsf)->data;
|
|
|
|
free (mem);
|
|
}
|
|
|
|
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$
|
|
** 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:
|
|
** * gst/nsf/Makefile.am:
|
|
** * gst/nsf/dis6502.h:
|
|
** * gst/nsf/fds_snd.c:
|
|
** * gst/nsf/fds_snd.h:
|
|
** * 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:
|
|
** * gst/nsf/memguard.h:
|
|
** * gst/nsf/mmc5_snd.c:
|
|
** * gst/nsf/mmc5_snd.h:
|
|
** * gst/nsf/nes6502.c:
|
|
** * gst/nsf/nes6502.h:
|
|
** * gst/nsf/nes_apu.c:
|
|
** * gst/nsf/nes_apu.h:
|
|
** * gst/nsf/nsf.c:
|
|
** * gst/nsf/nsf.h:
|
|
** * gst/nsf/osd.h:
|
|
** * gst/nsf/types.h:
|
|
** * gst/nsf/vrc7_snd.c:
|
|
** * gst/nsf/vrc7_snd.h:
|
|
** * gst/nsf/vrcvisnd.c:
|
|
** * gst/nsf/vrcvisnd.h:
|
|
** Added NSF decoder plugin. Fixes 151192.
|
|
**
|
|
** 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
|
|
**
|
|
*/
|