Added NSF decoder plugin. Fixes 151192.

Original commit message from CVS:
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.
This commit is contained in:
Wim Taymans 2006-07-13 15:07:28 +00:00
parent 9d2c04267d
commit aae22fa1c9
29 changed files with 9934 additions and 1 deletions

View file

@ -1,3 +1,37 @@
2006-07-13 Wim Taymans <wim@fluendo.com>
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.
2006-07-13 Tim-Philipp Müller <tim at centricular dot net>
* tests/check/Makefile.am:

2
common

@ -1 +1 @@
Subproject commit dd173e2720ac21e4a47c97705d7ff32271a0ee66
Subproject commit 53ecdc0c97a2992e5abeddd41d514bc142401e5d

View file

@ -82,6 +82,7 @@ GST_PLUGINS_ALL="\
gdp \
h264parse \
modplug \
nsf \
spectrum \
speed \
qtdemux \
@ -822,6 +823,7 @@ gst/gdp/Makefile
gst/h264parse/Makefile
gst/modplug/Makefile
gst/modplug/libmodplug/Makefile
gst/nsf/Makefile
gst/spectrum/Makefile
gst/speed/Makefile
gst/qtdemux/Makefile

36
gst/nsf/Makefile.am Normal file
View file

@ -0,0 +1,36 @@
plugin_LTLIBRARIES = libgstnsf.la
NOSEFART_SOURCES=fmopl.c \
log.c \
mmc5_snd.c \
nes_apu.c \
vrc7_snd.c \
fds_snd.c \
memguard.c \
nes6502.c \
nsf.c \
vrcvisnd.c
NOSEFART_INCLUDES=fmopl.h \
log.h \
mmc5_snd.h \
nes_apu.h \
osd.h \
vrc7_snd.h \
fds_snd.h \
memguard.h \
nes6502.h \
nsf.h \
types.h \
vrcvisnd.h
libgstnsf_la_SOURCES = gstnsf.c $(NOSEFART_SOURCES)
libgstnsf_la_CFLAGS = $(GST_CFLAGS) -DNSF_PLAYER
libgstnsf_la_LIBADD =
libgstnsf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = gstnsf.h $(NOSEFART_INCLUDES)
EXTRA_DIST =

79
gst/nsf/dis6502.h Normal file
View file

@ -0,0 +1,79 @@
/*
** 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.
**
**
** dis6502.h
**
** 6502 disassembler header
** $Id$
*/
#ifndef _DIS6502_H_
#define _DIS6502_H_
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern void nes6502_disasm(uint32 PC, uint8 P, uint8 A, uint8 X, uint8 Y, uint8 S);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* !_DIS6502_H_ */
/*
** $Log$
** 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.4 2000/06/09 15:12:25 matt
** initial revision
**
*/

124
gst/nsf/fds_snd.c Normal file
View file

@ -0,0 +1,124 @@
/*
** 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.
**
**
** fds_snd.c
**
** Famicom Disk System sound emulation
** $Id$
*/
#include "types.h"
#include "nes_apu.h"
#include "fds_snd.h"
static int32 fds_incsize = 0;
/* mix sound channels together */
static int32
fds_process (void)
{
int32 output;
output = 0;
return output;
}
/* write to registers */
static void
fds_write (uint32 address, uint8 value)
{
}
/* reset state of vrcvi sound channels */
static void
fds_reset (void)
{
fds_incsize = apu_getcyclerate ();
}
static void
fds_init (void)
{
}
/* TODO: bleh */
static void
fds_shutdown (void)
{
}
static apu_memwrite fds_memwrite[] = {
{0x4040, 0x4092, fds_write},
{-1, -1, NULL}
};
apuext_t fds_ext = {
fds_init,
fds_shutdown,
fds_reset,
fds_process,
NULL, /* no reads */
fds_memwrite
};
/*
** $Log$
** 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.3 2000/07/03 02:18:53 matt
** much better external module exporting
**
** Revision 1.2 2000/06/20 04:06:16 matt
** migrated external sound definition to apu module
**
** Revision 1.1 2000/06/20 00:06:47 matt
** initial revision
**
*/

77
gst/nsf/fds_snd.h Normal file
View file

@ -0,0 +1,77 @@
/*
** 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.
**
**
** fds_snd.h
**
** Famicom Disk System sound emulation
** $Id$
*/
#ifndef _FDS_SND_H_
#define _FDS_SND_H_
#include "nes_apu.h"
extern apuext_t fds_ext;
#endif /* _VRCVISND_H_ */
/*
** $Log$
** 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.2 2000/06/20 04:06:16 matt
** migrated external sound definition to apu module
**
** Revision 1.1 2000/06/20 00:06:47 matt
** initial revision
**
*/

1392
gst/nsf/fmopl.c Normal file

File diff suppressed because it is too large Load diff

164
gst/nsf/fmopl.h Normal file
View file

@ -0,0 +1,164 @@
#ifndef __FMOPL_H_
#define __FMOPL_H_
#define HAS_YM3812 1
typedef signed short int FMSAMPLE;
#define BUILD_YM3812 (HAS_YM3812)
#define BUILD_YM3526 (HAS_YM3526)
#define BUILD_Y8950 (HAS_Y8950)
/* compiler dependence */
#ifndef OSD_CPU_H
#define OSD_CPU_H
typedef unsigned char UINT8; /* unsigned 8bit */
typedef unsigned short UINT16; /* unsigned 16bit */
typedef unsigned int UINT32; /* unsigned 32bit */
typedef signed char INT8; /* signed 8bit */
typedef signed short INT16; /* signed 16bit */
typedef signed int INT32; /* signed 32bit */
#endif
#if BUILD_Y8950
#include "ymdeltat.h"
#endif
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
typedef void (*OPL_IRQHANDLER)(int param,int irq);
typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
/* !!!!! here is private section , do not access there member direct !!!!! */
#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
#define OPL_TYPE_IO 0x08 /* I/O port */
/* ---------- OPL one of slot ---------- */
typedef struct fm_opl_slot {
INT32 TL; /* total level :TL << 8 */
INT32 TLL; /* adjusted now TL */
UINT8 KSR; /* key scale rate :(shift down bit) */
INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */
INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */
INT32 SL; /* sustin level :SL_TALBE[SL] */
INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */
UINT8 ksl; /* keyscale level :(shift down bits) */
UINT8 ksr; /* key scale rate :kcode>>KSR */
UINT32 mul; /* multiple :ML_TABLE[ML] */
UINT32 Cnt; /* frequency count : */
UINT32 Incr; /* frequency step : */
/* envelope generator state */
UINT8 eg_typ; /* envelope type flag */
UINT8 evm; /* envelope phase */
INT32 evc; /* envelope counter */
INT32 eve; /* envelope counter end point */
INT32 evs; /* envelope counter step */
INT32 evsa; /* envelope step for AR :AR[ksr] */
INT32 evsd; /* envelope step for DR :DR[ksr] */
INT32 evsr; /* envelope step for RR :RR[ksr] */
/* LFO */
UINT8 ams; /* ams flag */
UINT8 vib; /* vibrate flag */
/* wave selector */
INT32 **wavetable;
}OPL_SLOT;
/* ---------- OPL one of channel ---------- */
typedef struct fm_opl_channel {
OPL_SLOT SLOT[2];
UINT8 CON; /* connection type */
UINT8 FB; /* feed back :(shift down bit) */
INT32 *connect1; /* slot1 output pointer */
INT32 *connect2; /* slot2 output pointer */
INT32 op1_out[2]; /* slot1 output for selfeedback */
/* phase generator state */
UINT32 block_fnum; /* block+fnum : */
UINT8 kcode; /* key code : KeyScaleCode */
UINT32 fc; /* Freq. Increment base */
UINT32 ksl_base; /* KeyScaleLevel Base step */
UINT8 keyon; /* key on/off flag */
} OPL_CH;
/* OPL state */
typedef struct fm_opl_f {
UINT8 type; /* chip type */
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
double freqbase; /* frequency base */
double TimerBase; /* Timer base time (==sampling time) */
UINT8 address; /* address register */
UINT8 status; /* status flag */
UINT8 statusmask; /* status mask */
UINT32 mode; /* Reg.08 : CSM , notesel,etc. */
/* Timer */
int T[2]; /* timer counter */
UINT8 st[2]; /* timer enable */
/* FM channel slots */
OPL_CH *P_CH; /* pointer of CH */
int max_ch; /* maximum channel */
/* Rythm sention */
UINT8 rythm; /* Rythm mode , key flag */
#if BUILD_Y8950
/* Delta-T ADPCM unit (Y8950) */
YM_DELTAT *deltat; /* DELTA-T ADPCM */
#endif
/* Keyboard / I/O interface unit (Y8950) */
UINT8 portDirection;
UINT8 portLatch;
OPL_PORTHANDLER_R porthandler_r;
OPL_PORTHANDLER_W porthandler_w;
int port_param;
OPL_PORTHANDLER_R keyboardhandler_r;
OPL_PORTHANDLER_W keyboardhandler_w;
int keyboard_param;
/* time tables */
INT32 AR_TABLE[75]; /* atttack rate tables */
INT32 DR_TABLE[75]; /* decay rate tables */
UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */
/* LFO */
INT32 *ams_table;
INT32 *vib_table;
INT32 amsCnt;
INT32 amsIncr;
INT32 vibCnt;
INT32 vibIncr;
/* wave selector enable flag */
UINT8 wavesel;
/* external event callback handler */
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
int TimerParam; /* TIMER parameter */
OPL_IRQHANDLER IRQHandler; /* IRQ handler */
int IRQParam; /* IRQ parameter */
OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
int UpdateParam; /* stream update parameter */
} FM_OPL;
/* ---------- Generic interface section ---------- */
#define OPL_TYPE_YM3526 (0)
#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
FM_OPL *OPLCreate(int type, int clock, int rate);
void OPLDestroy(FM_OPL *OPL);
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
/* Y8950 port handlers */
void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
void OPLResetChip(FM_OPL *OPL);
int OPLWrite(FM_OPL *OPL,int a,int v);
unsigned char OPLRead(FM_OPL *OPL,int a);
int OPLTimerOver(FM_OPL *OPL,int c);
/* YM3626/YM3812 local section */
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
#endif

635
gst/nsf/gstnsf.c Normal file
View file

@ -0,0 +1,635 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* (C) <2004> Johan Dahlin <johan@gnome.org>
* (C) <2006> Wim Taymans <wim@fluendo.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "gstnsf.h"
#define GST_CAT_DEFAULT nsfdec_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
static const GstElementDetails gst_nsfdec_details =
GST_ELEMENT_DETAILS ("Nsf decoder",
"Codec/Audio/Decoder",
"Using nosefart to decode NSF audio tunes",
"Johan Dahlin <johan@gnome.org>");
/* Nsfdec signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
#define DEFAULT_TUNE 0
#define DEFAULT_FILTER NSF_FILTER_NONE
enum
{
PROP_0,
PROP_TUNE,
PROP_FILTER,
};
static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-nsf")
);
static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, "
"endianness = (int) BYTE_ORDER, "
"signed = (boolean) TRUE, "
"width = (int) { 8, 16 }, "
"depth = (int) { 8, 16 }, "
"rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ]")
);
#define GST_TYPE_NSF_FILTER (gst_nsf_filter_get_type())
static GType
gst_nsf_filter_get_type (void)
{
static GType nsf_filter_type = 0;
static GEnumValue nsf_filter[] = {
{NSF_FILTER_NONE, "NSF_FILTER_NONE", "None"},
{NSF_FILTER_LOWPASS, "NSF_FILTER_LOWPASS", "Lowpass"},
{NSF_FILTER_WEIGHTED, "NSF_FILTER_WEIGHTED", "Weighted"},
{0, NULL, NULL},
};
if (!nsf_filter_type) {
nsf_filter_type = g_enum_register_static ("GstNsfFilter", nsf_filter);
}
return nsf_filter_type;
}
static void gst_nsfdec_base_init (gpointer g_class);
static void gst_nsfdec_class_init (GstNsfDec * klass);
static void gst_nsfdec_init (GstNsfDec * nsfdec);
static void gst_nsfdec_finalize (GObject * object);
static GstFlowReturn gst_nsfdec_chain (GstPad * pad, GstBuffer * buffer);
static gboolean gst_nsfdec_sink_event (GstPad * pad, GstEvent * event);
static gboolean gst_nsfdec_src_convert (GstPad * pad, GstFormat src_format,
gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
static gboolean gst_nsfdec_src_event (GstPad * pad, GstEvent * event);
static gboolean gst_nsfdec_src_query (GstPad * pad, GstQuery * query);
static void gst_nsfdec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_nsfdec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static GstElementClass *parent_class = NULL;
//static guint gst_nsfdec_signals[LAST_SIGNAL] = { 0 };
GType
gst_nsfdec_get_type (void)
{
static GType nsfdec_type = 0;
if (G_UNLIKELY (nsfdec_type == 0)) {
static const GTypeInfo nsfdec_info = {
sizeof (GstNsfDecClass),
gst_nsfdec_base_init,
NULL,
(GClassInitFunc) gst_nsfdec_class_init,
NULL,
NULL,
sizeof (GstNsfDec),
0,
(GInstanceInitFunc) gst_nsfdec_init,
NULL
};
nsfdec_type =
g_type_register_static (GST_TYPE_ELEMENT, "GstNsfDec", &nsfdec_info,
(GTypeFlags) 0);
}
return nsfdec_type;
}
static void
gst_nsfdec_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details (element_class, &gst_nsfdec_details);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_templ));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_templ));
}
static void
gst_nsfdec_class_init (GstNsfDec * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
parent_class = GST_ELEMENT_CLASS (g_type_class_peek_parent (klass));
gobject_class->finalize = gst_nsfdec_finalize;
gobject_class->set_property = gst_nsfdec_set_property;
gobject_class->get_property = gst_nsfdec_get_property;
g_object_class_install_property (gobject_class, PROP_TUNE,
g_param_spec_int ("tune", "tune", "tune", 1, 100, 1, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_FILTER,
g_param_spec_enum ("filter", "filter", "filter", GST_TYPE_NSF_FILTER,
NSF_FILTER_NONE, G_PARAM_WRITABLE));
GST_DEBUG_CATEGORY_INIT (nsfdec_debug, "nsfdec", 0,
"NES sound file (nsf) decoder");
nsf_init ();
}
static void
gst_nsfdec_init (GstNsfDec * nsfdec)
{
nsfdec->sinkpad =
gst_pad_new_from_template (gst_static_pad_template_get (&sink_templ),
"sink");
gst_pad_set_query_function (nsfdec->sinkpad, NULL);
gst_pad_set_event_function (nsfdec->sinkpad, gst_nsfdec_sink_event);
gst_pad_set_chain_function (nsfdec->sinkpad, gst_nsfdec_chain);
gst_element_add_pad (GST_ELEMENT (nsfdec), nsfdec->sinkpad);
nsfdec->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&src_templ),
"src");
gst_pad_set_event_function (nsfdec->srcpad, gst_nsfdec_src_event);
gst_pad_set_query_function (nsfdec->srcpad, gst_nsfdec_src_query);
gst_pad_use_fixed_caps (nsfdec->srcpad);
gst_element_add_pad (GST_ELEMENT (nsfdec), nsfdec->srcpad);
nsfdec->nsf = NULL;
nsfdec->state = NSF_STATE_NEED_TUNE;
nsfdec->tune_buffer = NULL;
nsfdec->blocksize = 0;
nsfdec->frequency = 44100;
nsfdec->bits = 8;
nsfdec->stereo = FALSE;
nsfdec->channels = 1;
nsfdec->tune_number = DEFAULT_TUNE;
nsfdec->filter = DEFAULT_FILTER;
}
static void
gst_nsfdec_finalize (GObject * object)
{
GstNsfDec *nsfdec = GST_NSFDEC (object);
if (nsfdec->tune_buffer)
gst_buffer_unref (nsfdec->tune_buffer);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
nsfdec_negotiate (GstNsfDec * nsfdec)
{
GstCaps *allowed;
gboolean sign = TRUE;
gint width = 16, depth = 16;
GstStructure *structure;
int rate = 44100;
int channels = 1;
GstCaps *caps;
allowed = gst_pad_get_allowed_caps (nsfdec->srcpad);
if (!allowed)
goto nothing_allowed;
GST_DEBUG_OBJECT (nsfdec, "allowed caps: %" GST_PTR_FORMAT, allowed);
structure = gst_caps_get_structure (allowed, 0);
gst_structure_get_int (structure, "width", &width);
gst_structure_get_int (structure, "depth", &depth);
if (width && depth && width != depth)
goto wrong_width;
width = width | depth;
if (width) {
nsfdec->bits = width;
}
gst_structure_get_boolean (structure, "signed", &sign);
gst_structure_get_int (structure, "rate", &rate);
nsfdec->frequency = rate;
gst_structure_get_int (structure, "channels", &channels);
nsfdec->channels = channels;
nsfdec->stereo = (channels == 2);
caps = gst_caps_new_simple ("audio/x-raw-int",
"endianness", G_TYPE_INT, G_BYTE_ORDER,
"signed", G_TYPE_BOOLEAN, TRUE,
"width", G_TYPE_INT, nsfdec->bits,
"depth", G_TYPE_INT, nsfdec->bits,
"rate", G_TYPE_INT, nsfdec->frequency,
"channels", G_TYPE_INT, nsfdec->channels, NULL);
gst_pad_set_caps (nsfdec->srcpad, caps);
gst_caps_unref (caps);
gst_caps_unref (allowed);
return TRUE;
nothing_allowed:
{
GST_DEBUG_OBJECT (nsfdec, "could not get allowed caps");
return FALSE;
}
wrong_width:
{
GST_DEBUG_OBJECT (nsfdec, "width %d and depth %d are different",
width, depth);
gst_caps_unref (allowed);
return FALSE;
}
}
static void
play_loop (GstPad * pad)
{
GstFlowReturn ret;
GstNsfDec *nsfdec;
GstBuffer *out;
gint64 value, offset, time;
GstFormat format;
nsfdec = GST_NSFDEC (gst_pad_get_parent (pad));
out = gst_buffer_new_and_alloc (nsfdec->blocksize);
gst_buffer_set_caps (out, GST_PAD_CAPS (pad));
nsf_frame (nsfdec->nsf);
apu_process (GST_BUFFER_DATA (out), nsfdec->blocksize / nsfdec->bps);
/* get offset in samples */
format = GST_FORMAT_DEFAULT;
gst_nsfdec_src_convert (nsfdec->srcpad,
GST_FORMAT_BYTES, nsfdec->total_bytes, &format, &offset);
GST_BUFFER_OFFSET (out) = offset;
/* get current timestamp */
format = GST_FORMAT_TIME;
gst_nsfdec_src_convert (nsfdec->srcpad,
GST_FORMAT_BYTES, nsfdec->total_bytes, &format, &time);
GST_BUFFER_TIMESTAMP (out) = time;
/* update position and get new timestamp to calculate duration */
nsfdec->total_bytes += nsfdec->blocksize;
/* get offset in samples */
format = GST_FORMAT_DEFAULT;
gst_nsfdec_src_convert (nsfdec->srcpad,
GST_FORMAT_BYTES, nsfdec->total_bytes, &format, &value);
GST_BUFFER_OFFSET_END (out) = value;
format = GST_FORMAT_TIME;
gst_nsfdec_src_convert (nsfdec->srcpad,
GST_FORMAT_BYTES, nsfdec->total_bytes, &format, &value);
GST_BUFFER_DURATION (out) = value - time;
if ((ret = gst_pad_push (nsfdec->srcpad, out)) != GST_FLOW_OK)
goto pause;
done:
gst_object_unref (nsfdec);
return;
/* ERRORS */
pause:
{
const gchar *reason = gst_flow_get_name (ret);
GST_DEBUG_OBJECT (nsfdec, "pausing task, reason %s", reason);
gst_pad_pause_task (pad);
if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
if (ret == GST_FLOW_UNEXPECTED) {
/* perform EOS logic, FIXME, segment seek? */
gst_pad_push_event (pad, gst_event_new_eos ());
} else {
/* for fatal errors we post an error message */
GST_ELEMENT_ERROR (nsfdec, STREAM, FAILED,
(NULL), ("streaming task paused, reason %s", reason));
gst_pad_push_event (pad, gst_event_new_eos ());
}
}
goto done;
}
}
static gboolean
start_play_tune (GstNsfDec * nsfdec)
{
gboolean res;
nsfdec->nsf = nsf_load (NULL, GST_BUFFER_DATA (nsfdec->tune_buffer),
GST_BUFFER_SIZE (nsfdec->tune_buffer));
if (!nsfdec->nsf)
goto could_not_load;
if (!nsfdec_negotiate (nsfdec))
goto could_not_negotiate;
nsf_playtrack (nsfdec->nsf,
nsfdec->tune_number, nsfdec->frequency, nsfdec->bits, nsfdec->stereo);
nsf_setfilter (nsfdec->nsf, nsfdec->filter);
nsfdec->bps = (nsfdec->bits >> 3) * nsfdec->channels;
/* calculate the number of bytes we need to output after each call to
* nsf_frame(). */
nsfdec->blocksize =
nsfdec->bps * nsfdec->frequency / nsfdec->nsf->playback_rate;
gst_pad_push_event (nsfdec->srcpad,
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0));
res = gst_pad_start_task (nsfdec->srcpad,
(GstTaskFunction) play_loop, nsfdec->srcpad);
return res;
/* ERRORS */
could_not_load:
{
GST_ELEMENT_ERROR (nsfdec, LIBRARY, INIT,
("Could not load tune"), ("Could not load tune"));
return FALSE;
}
could_not_negotiate:
{
GST_ELEMENT_ERROR (nsfdec, CORE, NEGOTIATION,
("Could not negotiate format"), ("Could not negotiate format"));
return FALSE;
}
}
static gboolean
gst_nsfdec_sink_event (GstPad * pad, GstEvent * event)
{
GstNsfDec *nsfdec;
gboolean res;
nsfdec = GST_NSFDEC (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS:
res = start_play_tune (nsfdec);
break;
case GST_EVENT_NEWSEGMENT:
res = FALSE;
break;
default:
res = FALSE;
break;
}
gst_event_unref (event);
gst_object_unref (nsfdec);
return res;
}
static GstFlowReturn
gst_nsfdec_chain (GstPad * pad, GstBuffer * buffer)
{
GstNsfDec *nsfdec;
nsfdec = GST_NSFDEC (gst_pad_get_parent (pad));
/* collect all data, we start doing something when we get an EOS
* event */
if (nsfdec->tune_buffer) {
nsfdec->tune_buffer = gst_buffer_join (nsfdec->tune_buffer, buffer);
} else {
nsfdec->tune_buffer = buffer;
}
gst_object_unref (nsfdec);
return GST_FLOW_OK;
}
static gboolean
gst_nsfdec_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
GstFormat * dest_format, gint64 * dest_value)
{
gboolean res = TRUE;
guint scale = 1;
GstNsfDec *nsfdec;
nsfdec = GST_NSFDEC (gst_pad_get_parent (pad));
if (src_format == *dest_format) {
*dest_value = src_value;
return TRUE;
}
switch (src_format) {
case GST_FORMAT_BYTES:
switch (*dest_format) {
case GST_FORMAT_DEFAULT:
if (nsfdec->bps == 0)
return FALSE;
*dest_value = src_value / nsfdec->bps;
break;
case GST_FORMAT_TIME:
{
gint byterate = nsfdec->bps * nsfdec->frequency;
if (byterate == 0)
return FALSE;
*dest_value =
gst_util_uint64_scale_int (src_value, GST_SECOND, byterate);
break;
}
default:
res = FALSE;
}
break;
case GST_FORMAT_DEFAULT:
switch (*dest_format) {
case GST_FORMAT_BYTES:
*dest_value = src_value * nsfdec->bps;
break;
case GST_FORMAT_TIME:
if (nsfdec->frequency == 0)
return FALSE;
*dest_value =
gst_util_uint64_scale_int (src_value, GST_SECOND,
nsfdec->frequency);
break;
default:
res = FALSE;
}
break;
case GST_FORMAT_TIME:
switch (*dest_format) {
case GST_FORMAT_BYTES:
scale = nsfdec->bps;
/* fallthrough */
case GST_FORMAT_DEFAULT:
*dest_value =
gst_util_uint64_scale_int (src_value, scale * nsfdec->frequency,
GST_SECOND);
break;
default:
res = FALSE;
}
break;
default:
res = FALSE;
}
return res;
}
static gboolean
gst_nsfdec_src_event (GstPad * pad, GstEvent * event)
{
gboolean res = FALSE;
GstNsfDec *nsfdec;
nsfdec = GST_NSFDEC (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
default:
break;
}
gst_event_unref (event);
gst_object_unref (nsfdec);
return res;
}
static gboolean
gst_nsfdec_src_query (GstPad * pad, GstQuery * query)
{
gboolean res = TRUE;
GstNsfDec *nsfdec;
nsfdec = GST_NSFDEC (gst_pad_get_parent (pad));
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_POSITION:
{
GstFormat format;
gint64 current;
gst_query_parse_position (query, &format, NULL);
/* we only know about our bytes, convert to requested format */
res &= gst_nsfdec_src_convert (pad,
GST_FORMAT_BYTES, nsfdec->total_bytes, &format, &current);
if (res) {
gst_query_set_position (query, format, current);
}
break;
}
default:
res = gst_pad_query_default (pad, query);
break;
}
gst_object_unref (nsfdec);
return res;
}
static void
gst_nsfdec_set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
GstNsfDec *nsfdec;
nsfdec = GST_NSFDEC (object);
switch (prop_id) {
case PROP_TUNE:
nsfdec->tune_number = g_value_get_int (value);
break;
case PROP_FILTER:
nsfdec->filter = g_value_get_enum (value);
if (nsfdec->nsf)
nsf_setfilter (nsfdec->nsf, nsfdec->filter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
return;
}
}
static void
gst_nsfdec_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstNsfDec *nsfdec;
nsfdec = GST_NSFDEC (object);
switch (prop_id) {
case PROP_TUNE:
g_value_set_int (value, nsfdec->tune_number);
break;
case PROP_FILTER:
g_value_set_enum (value, nsfdec->filter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "nsfdec", GST_RANK_PRIMARY,
GST_TYPE_NSFDEC);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
"nsfdec",
"Uses nosefart to decode .nsf files",
plugin_init, VERSION, "GPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);

86
gst/nsf/gstnsf.h Normal file
View file

@ -0,0 +1,86 @@
/* Copyright (C) 2003 Johan Dahlin <johan@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_NSFDEC_H__
#define __GST_NSFDEC_H__
#include <stdlib.h>
#include <gst/gst.h>
#include "types.h"
#include "nsf.h"
G_BEGIN_DECLS
#define GST_TYPE_NSFDEC \
(gst_nsfdec_get_type())
#define GST_NSFDEC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NSFDEC,GstNsfDec))
#define GST_NSFDEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NSFDEC,GstNsfDec))
#define GST_IS_NSFDEC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NSFDEC))
#define GST_IS_NSFDEC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NSFDEC))
typedef struct _GstNsfDec GstNsfDec;
typedef struct _GstNsfDecClass GstNsfDecClass;
enum
{
NSF_STATE_NEED_TUNE = 1,
NSF_STATE_LOAD_TUNE = 2,
NSF_STATE_PLAY_TUNE = 3
};
struct _GstNsfDec {
GstElement element;
/* pads */
GstPad *sinkpad,
*srcpad;
gint state;
GstBuffer *tune_buffer;
guint64 total_bytes;
/* properties */
gint tune_number;
gint filter;
nsf_t *nsf;
gulong blocksize;
int frequency;
int bits;
gboolean stereo;
int channels;
int bps;
};
struct _GstNsfDecClass {
GstElementClass parent_class;
};
GType gst_nsfdec_get_type (void);
G_END_DECLS
#endif /* __GST_NSFDEC_H__ */

148
gst/nsf/log.c Normal file
View file

@ -0,0 +1,148 @@
/*
** 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.
**
**
** log.c
**
** Error logging functions
** $Id$
*/
#include <stdio.h>
#include <stdarg.h>
#include "types.h"
#include "log.h"
#ifdef OSD_LOG
#include "osd.h"
#endif
#if defined(OSD_LOG) && !defined(NOFRENDO_DEBUG)
#error NOFRENDO_DEBUG must be defined as well as OSD_LOG
#endif
/* Note that all of these functions will be empty if
** debugging is not enabled.
*/
#ifdef NOFRENDO_DEBUG
static FILE *errorlog;
#endif
int
log_init (void)
{
#ifdef NOFRENDO_DEBUG
#ifdef OSD_LOG
/* Initialize an OSD logging system */
osd_loginit ();
#endif /* OSD_LOG */
errorlog = fopen ("errorlog.txt", "wt");
if (NULL == errorlog)
return (-1);
#endif /* NOFRENDO_DEBUG */
return 0;
}
void
log_shutdown (void)
{
#ifdef NOFRENDO_DEBUG
/* Snoop around for unallocated blocks */
mem_checkblocks ();
mem_checkleaks ();
#ifdef OSD_LOG
osd_logshutdown ();
#endif /* OSD_LOG */
fclose (errorlog);
#endif /* NOFRENDO_DEBUG */
}
void
log_print (const char *string)
{
#ifdef NOFRENDO_DEBUG
#ifdef OSD_LOG
osd_logprint (string);
#endif /* OSD_LOG */
/* Log it to disk, as well */
fputs (string, errorlog);
#endif /* NOFRENDO_DEBUG */
}
void
log_printf (const char *format, ...)
{
#ifdef NOFRENDO_DEBUG
#ifdef OSD_LOG
char buffer[1024 + 1];
#endif /* OSD_LOG */
va_list arg;
va_start (arg, format);
#ifdef OSD_LOG
vsprintf (buffer, format, arg);
osd_logprint (buffer);
#endif /* OSD_LOG */
vfprintf (errorlog, format, arg);
va_end (arg);
#endif /* NOFRENDO_DEBUG */
}
/*
** $Log$
** 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.5 2000/06/26 04:55:33 matt
** minor change
**
** Revision 1.4 2000/06/09 15:12:25 matt
** initial revision
**
*/

76
gst/nsf/log.h Normal file
View file

@ -0,0 +1,76 @@
/*
** 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.
**
**
** log.h
**
** Error logging header file
** $Id$
*/
#ifndef _LOG_H_
#define _LOG_H_
#include <stdio.h>
extern int log_init(void);
extern void log_shutdown(void);
extern void log_print(const char *string);
extern void log_printf(const char *format, ...);
#endif /* _LOG_H_ */
/*
** $Log$
** 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.4 2000/06/09 15:12:25 matt
** initial revision
**
*/

398
gst/nsf/memguard.c Normal file
View file

@ -0,0 +1,398 @@
/*
** 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.
**
**
** memguard.c
**
** memory allocation wrapper routines
**
** NOTE: based on code (c) 1998 the Retrocade group
** $Id$
*/
#include "types.h"
/* undefine macro definitions, so we get real calls */
#undef malloc
#undef free
#include <string.h>
#include <stdlib.h>
#include "memguard.h"
#include "log.h"
/* Maximum number of allocated blocks at any one time */
#define MAX_BLOCKS 16384
/* Memory block structure */
typedef struct memblock_s
{
void *block_addr;
int block_size;
char *file_name;
int line_num;
} memblock_t;
boolean mem_debug = TRUE; /* debugging flag */
#ifdef NOFRENDO_DEBUG
static int mem_blockcount = 0; /* allocated block count */
static memblock_t *mem_record = NULL;
#define GUARD_STRING "GgUuAaRrDdSsTtRrIiNnGgBbLlOoCcKk"
#define GUARD_LENGTH 64 /* before and after allocated block */
/*
** Check the memory guard to make sure out of bounds writes have not
** occurred.
*/
static boolean
mem_checkguardblock (void *data, int guard_size)
{
uint8 *orig, *chk, *blk;
int i, alloc_size;
/* get the original pointer */
orig = (((uint8 *) data) - guard_size);
/* get the size */
alloc_size = *((uint32 *) orig);
/* now skip past the size */
blk = orig + sizeof (uint32);
/* check leading guard string */
chk = GUARD_STRING;
for (i = sizeof (uint32); i < guard_size; i++) {
if (0 == *chk)
chk = GUARD_STRING;
if (*blk != *chk)
return FALSE;
chk++;
blk++;
}
/* check end of block */
chk = GUARD_STRING;
blk = ((uint8 *) data) + alloc_size;
for (i = 0; i < guard_size; i++) {
if (0 == *chk)
chk = GUARD_STRING;
if (*blk != *chk)
return FALSE;
chk++;
blk++;
}
/* we're okay! */
return TRUE;
}
/* free a guard block */
static void
mem_freeguardblock (void *data, int guard_size)
{
uint8 *orig = (((uint8 *) data) - guard_size);
free (orig);
}
/* fill in the memory guard, advance the pointer to the 'real' memory */
static void *
mem_guardblock (int alloc_size, int guard_size)
{
void *orig;
uint8 *blk, *chk;
int i;
/* allocate memory */
orig = calloc (alloc_size + (guard_size * 2), 1);
if (NULL == orig)
return NULL;
blk = ((uint8 *) orig);
/* store the size of the newly allocated block */
*((uint32 *) blk) = alloc_size;
/* skip past the size */
blk += sizeof (uint32);
/* put guard string at beginning of block */
chk = GUARD_STRING;
for (i = sizeof (uint32); i < guard_size; i++) {
if (0 == *chk)
chk = GUARD_STRING;
*blk++ = *chk++;
}
/* check end of block */
chk = GUARD_STRING;
blk = guard_size + (uint8 *) orig + alloc_size;
for (i = 0; i < guard_size; i++) {
if (0 == *chk)
chk = GUARD_STRING;
*blk++ = *chk++;
}
return (void *) (guard_size + (uint8 *) orig);
}
/* Allocate a bunch of memory to keep track of all memory blocks */
static void
mem_init (void)
{
if (mem_record) {
free (mem_record);
mem_record = NULL;
}
mem_record = calloc (MAX_BLOCKS * sizeof (memblock_t), 1);
ASSERT (mem_record);
}
/* add a block of memory to the master record */
static void
mem_addblock (void *data, int block_size, char *file, int line)
{
int i;
for (i = 0; i < MAX_BLOCKS; i++) {
if (NULL == mem_record[i].block_addr) {
mem_record[i].block_addr = data;
mem_record[i].block_size = block_size;
mem_record[i].file_name = file;
mem_record[i].line_num = line;
return;
}
}
ASSERT_MSG ("out of memory blocks.");
}
/* find an entry in the block record and delete it */
static void
mem_deleteblock (void *data, char *file, int line)
{
int i;
char fail[256];
for (i = 0; i < MAX_BLOCKS; i++) {
if (data == mem_record[i].block_addr) {
if (FALSE == mem_checkguardblock (mem_record[i].block_addr, GUARD_LENGTH)) {
sprintf (fail,
"mem_deleteblock 0x%08X at line %d of %s -- block corrupt",
(uint32) data, line, file);
ASSERT_MSG (fail);
}
memset (&mem_record[i], 0, sizeof (memblock_t));
return;
}
}
sprintf (fail, "mem_deleteblock 0x%08X at line %d of %s -- block not found",
(uint32) data, line, file);
ASSERT_MSG (fail);
}
#endif /* NOFRENDO_DEBUG */
/* allocates memory and clears it */
#ifdef NOFRENDO_DEBUG
void *
_my_malloc (int size, char *file, int line)
#else
void *
_my_malloc (int size)
#endif
{
void *temp;
char fail[256];
#ifdef NOFRENDO_DEBUG
if (NULL == mem_record && FALSE != mem_debug)
mem_init ();
if (FALSE != mem_debug)
temp = mem_guardblock (size, GUARD_LENGTH);
else
#endif /* NOFRENDO_DEBUG */
temp = calloc (sizeof (uint8), size);
if (NULL == temp) {
#ifdef NOFRENDO_DEBUG
sprintf (fail, "malloc: out of memory at line %d of %s. block size: %d\n",
line, file, size);
#else
sprintf (fail, "malloc: out of memory. block size: %d\n", size);
#endif
ASSERT_MSG (fail);
}
#ifdef NOFRENDO_DEBUG
if (FALSE != mem_debug)
mem_addblock (temp, size, file, line);
mem_blockcount++;
#endif
return temp;
}
/* free a pointer allocated with my_malloc */
#ifdef NOFRENDO_DEBUG
void
_my_free (void **data, char *file, int line)
#else
void
_my_free (void **data)
#endif
{
char fail[256];
if (NULL == data || NULL == *data
|| 0xFFFFFFFF == (uint32) * data || 0xFFFFFFFF == (uint32) data) {
#ifdef NOFRENDO_DEBUG
sprintf (fail, "free: attempted to free NULL pointer at line %d of %s\n",
line, file);
#else
sprintf (fail, "free: attempted to free NULL pointer.\n");
#endif
ASSERT_MSG (fail);
}
#ifdef NOFRENDO_DEBUG
/* if this is true, we are in REAL trouble */
if (0 == mem_blockcount) {
ASSERT_MSG ("free: attempted to free memory when no blocks available");
}
if (FALSE != mem_debug)
mem_deleteblock (*data, file, line);
mem_blockcount--; /* dec our block count */
if (FALSE != mem_debug)
mem_freeguardblock (*data, GUARD_LENGTH);
else
#endif /* NOFRENDO_DEBUG */
free (*data);
*data = NULL; /* NULL our source */
}
/* check for orphaned memory handles */
void
mem_checkleaks (void)
{
#ifdef NOFRENDO_DEBUG
int i;
if (FALSE == mem_debug)
return;
if (mem_blockcount) {
log_printf ("memory leak - %d unfreed block%s\n\n", mem_blockcount,
mem_blockcount == 1 ? "" : "s");
for (i = 0; i < MAX_BLOCKS; i++) {
if (mem_record[i].block_addr) {
log_printf ("addr: 0x%08X, size: %d, line %d of %s%s\n",
(uint32) mem_record[i].block_addr,
mem_record[i].block_size,
mem_record[i].line_num,
mem_record[i].file_name,
(FALSE == mem_checkguardblock (mem_record[i].block_addr,
GUARD_LENGTH))
? " -- block corrupt" : "");
}
}
} else
log_printf ("no memory leaks\n");
#endif
}
void
mem_checkblocks (void)
{
#ifdef NOFRENDO_DEBUG
int i;
if (FALSE == mem_debug)
return;
for (i = 0; i < MAX_BLOCKS; i++) {
if (mem_record[i].block_addr) {
if (FALSE == mem_checkguardblock (mem_record[i].block_addr, GUARD_LENGTH)) {
log_printf ("addr: 0x%08X, size: %d, line %d of %s -- block corrupt\n",
(uint32) mem_record[i].block_addr,
mem_record[i].block_size,
mem_record[i].line_num, mem_record[i].file_name);
}
}
}
#endif /* NOFRENDO_DEBUG */
}
/*
** $Log$
** 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.8 2000/06/26 04:54:48 matt
** simplified and made more robust
**
** Revision 1.7 2000/06/12 01:11:41 matt
** cleaned up some error output for win32
**
** Revision 1.6 2000/06/09 15:12:25 matt
** initial revision
**
*/

95
gst/nsf/memguard.h Normal file
View file

@ -0,0 +1,95 @@
/*
** 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.
**
**
** memguard.h
**
** memory allocation wrapper routines
** $Id$
*/
#ifndef _MEMGUARD_H_
#define _MEMGUARD_H_
#ifdef NOFRENDO_DEBUG
#define malloc(s) _my_malloc((s), __FILE__, __LINE__)
#define free(d) _my_free((void **) &(d), __FILE__, __LINE__)
extern void *_my_malloc(int size, char *file, int line);
extern void _my_free(void **data, char *file, int line);
#else /* Non-debugging versions of calls */
#define malloc(s) _my_malloc((s))
#define free(d) _my_free((void **) &(d))
extern void *_my_malloc(int size);
extern void _my_free(void **data);
#endif /* NOFRENDO_DEBUG */
extern void mem_checkblocks(void);
extern void mem_checkleaks(void);
extern boolean mem_debug;
#endif /* _MEMGUARD_H_ */
/*
** $Log$
** 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.5 2000/06/26 04:54:48 matt
** simplified and made more robust
**
** Revision 1.4 2000/06/09 15:12:25 matt
** initial revision
**
*/

383
gst/nsf/mmc5_snd.c Normal file
View file

@ -0,0 +1,383 @@
/*
** 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.
**
**
** mmc5_snd.c
**
** Nintendo MMC5 sound emulation
** $Id$
*/
#include <string.h>
#include "types.h"
#include "mmc5_snd.h"
#include "nes_apu.h"
/* TODO: encapsulate apu/mmc5 rectangle */
#define APU_OVERSAMPLE
#define APU_VOLUME_DECAY(x) ((x) -= ((x) >> 7))
typedef struct mmc5dac_s
{
int32 output;
boolean enabled;
} mmc5dac_t;
/* look up table madness */
static int32 decay_lut[16];
static int vbl_lut[32];
/* various sound constants for sound emulation */
/* vblank length table used for rectangles, triangle, noise */
static const uint8 vbl_length[32] = {
5, 127, 10, 1, 19, 2, 40, 3, 80, 4, 30, 5, 7, 6, 13, 7,
6, 8, 12, 9, 24, 10, 48, 11, 96, 12, 36, 13, 8, 14, 16, 15
};
/* ratios of pos/neg pulse for rectangle waves
** 2/16 = 12.5%, 4/16 = 25%, 8/16 = 50%, 12/16 = 75%
** (4-bit adder in rectangles, hence the 16)
*/
static const int duty_lut[4] = {
2, 4, 8, 12
};
static int32 mmc5_incsize;
static uint8 mul[2];
static mmc5rectangle_t mmc5rect[2];
static mmc5dac_t mmc5dac;
#define MMC5_RECTANGLE_OUTPUT chan->output_vol
static int32
mmc5_rectangle (mmc5rectangle_t * chan)
{
int32 output;
#ifdef APU_OVERSAMPLE
int num_times;
int32 total;
#endif /* APU_OVERSAMPLE */
/* reg0: 0-3=volume, 4=envelope, 5=hold, 6-7=duty cycle
** reg1: 0-2=sweep shifts, 3=sweep inc/dec, 4-6=sweep length, 7=sweep on
** reg2: 8 bits of freq
** reg3: 0-2=high freq, 7-4=vbl length counter
*/
APU_VOLUME_DECAY (chan->output_vol);
if (FALSE == chan->enabled || 0 == chan->vbl_length)
return MMC5_RECTANGLE_OUTPUT;
/* vbl length counter */
if (FALSE == chan->holdnote)
chan->vbl_length--;
/* envelope decay at a rate of (env_delay + 1) / 240 secs */
chan->env_phase -= 4; /* 240/60 */
while (chan->env_phase < 0) {
chan->env_phase += chan->env_delay;
if (chan->holdnote)
chan->env_vol = (chan->env_vol + 1) & 0x0F;
else if (chan->env_vol < 0x0F)
chan->env_vol++;
}
if (chan->freq < APU_TO_FIXED (4))
return MMC5_RECTANGLE_OUTPUT;
chan->phaseacc -= mmc5_incsize; /* # of cycles per sample */
if (chan->phaseacc >= 0)
return MMC5_RECTANGLE_OUTPUT;
#ifdef APU_OVERSAMPLE
num_times = total = 0;
if (chan->fixed_envelope)
output = chan->volume << 8; /* fixed volume */
else
output = (chan->env_vol ^ 0x0F) << 8;
#endif
while (chan->phaseacc < 0) {
chan->phaseacc += chan->freq;
chan->adder = (chan->adder + 1) & 0x0F;
#ifdef APU_OVERSAMPLE
if (chan->adder < chan->duty_flip)
total += output;
else
total -= output;
num_times++;
#endif
}
#ifdef APU_OVERSAMPLE
chan->output_vol = total / num_times;
#else
if (chan->fixed_envelope)
output = chan->volume << 8; /* fixed volume */
else
output = (chan->env_vol ^ 0x0F) << 8;
if (0 == chan->adder)
chan->output_vol = output;
else if (chan->adder == chan->duty_flip)
chan->output_vol = -output;
#endif
return MMC5_RECTANGLE_OUTPUT;
}
static uint8
mmc5_read (uint32 address)
{
uint32 retval;
retval = (uint32) (mul[0] * mul[1]);
switch (address) {
case 0x5205:
return (uint8) retval;
case 0x5206:
return (uint8) (retval >> 8);
default:
return 0xFF;
}
}
/* mix vrcvi sound channels together */
static int32
mmc5_process (void)
{
int32 accum;
accum = mmc5_rectangle (&mmc5rect[0]);
accum += mmc5_rectangle (&mmc5rect[1]);
if (mmc5dac.enabled)
accum += mmc5dac.output;
return accum;
}
/* write to registers */
static void
mmc5_write (uint32 address, uint8 value)
{
int chan;
switch (address) {
/* rectangles */
case MMC5_WRA0:
case MMC5_WRB0:
chan = (address & 4) ? 1 : 0;
mmc5rect[chan].regs[0] = value;
mmc5rect[chan].volume = value & 0x0F;
mmc5rect[chan].env_delay = decay_lut[value & 0x0F];
mmc5rect[chan].holdnote = (value & 0x20) ? TRUE : FALSE;
mmc5rect[chan].fixed_envelope = (value & 0x10) ? TRUE : FALSE;
mmc5rect[chan].duty_flip = duty_lut[value >> 6];
break;
case MMC5_WRA1:
case MMC5_WRB1:
break;
case MMC5_WRA2:
case MMC5_WRB2:
chan = (address & 4) ? 1 : 0;
mmc5rect[chan].regs[2] = value;
if (mmc5rect[chan].enabled)
mmc5rect[chan].freq =
APU_TO_FIXED ((((mmc5rect[chan].regs[3] & 7) << 8) + value) + 1);
break;
case MMC5_WRA3:
case MMC5_WRB3:
chan = (address & 4) ? 1 : 0;
mmc5rect[chan].regs[3] = value;
if (mmc5rect[chan].enabled) {
mmc5rect[chan].vbl_length = vbl_lut[value >> 3];
mmc5rect[chan].env_vol = 0;
mmc5rect[chan].freq =
APU_TO_FIXED ((((value & 7) << 8) + mmc5rect[chan].regs[2]) + 1);
mmc5rect[chan].adder = 0;
}
break;
case MMC5_SMASK:
if (value & 0x01)
mmc5rect[0].enabled = TRUE;
else {
mmc5rect[0].enabled = FALSE;
mmc5rect[0].vbl_length = 0;
}
if (value & 0x02)
mmc5rect[1].enabled = TRUE;
else {
mmc5rect[1].enabled = FALSE;
mmc5rect[1].vbl_length = 0;
}
break;
case 0x5010:
if (value & 0x01)
mmc5dac.enabled = TRUE;
else
mmc5dac.enabled = FALSE;
break;
case 0x5011:
mmc5dac.output = (value ^ 0x80) << 8;
break;
case 0x5205:
mul[0] = value;
break;
case 0x5206:
mul[1] = value;
break;
default:
break;
}
}
/* reset state of vrcvi sound channels */
static void
mmc5_reset (void)
{
int i;
/* get the phase period from the apu */
mmc5_incsize = apu_getcyclerate ();
for (i = 0x5000; i < 0x5008; i++)
mmc5_write (i, 0);
mmc5_write (0x5010, 0);
mmc5_write (0x5011, 0);
}
static void
mmc5_init (void)
{
int i;
int num_samples = apu_getcontext ()->num_samples;
/* lut used for enveloping and frequency sweeps */
for (i = 0; i < 16; i++)
decay_lut[i] = num_samples * (i + 1);
/* used for note length, based on vblanks and size of audio buffer */
for (i = 0; i < 32; i++)
vbl_lut[i] = vbl_length[i] * num_samples;
}
/* TODO: bleh */
static void
mmc5_shutdown (void)
{
}
static apu_memread mmc5_memread[] = {
{0x5205, 0x5206, mmc5_read},
{-1, -1, NULL}
};
static apu_memwrite mmc5_memwrite[] = {
{0x5000, 0x5015, mmc5_write},
{0x5205, 0x5206, mmc5_write},
{-1, -1, NULL}
};
apuext_t mmc5_ext = {
mmc5_init,
mmc5_shutdown,
mmc5_reset,
mmc5_process,
mmc5_memread,
mmc5_memwrite
};
/*
** $Log$
** 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.6 2000/07/04 04:51:41 matt
** cleanups
**
** Revision 1.5 2000/07/03 02:18:53 matt
** much better external module exporting
**
** Revision 1.4 2000/06/28 22:03:51 matt
** fixed stupid oversight
**
** Revision 1.3 2000/06/20 20:46:58 matt
** minor cleanups
**
** Revision 1.2 2000/06/20 04:06:16 matt
** migrated external sound definition to apu module
**
** Revision 1.1 2000/06/20 00:06:47 matt
** initial revision
**
*/

109
gst/nsf/mmc5_snd.h Normal file
View file

@ -0,0 +1,109 @@
/*
** 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.
**
**
** mmc5_snd.h
**
** Nintendo MMC5 sound emulation header
** $Id$
*/
#ifndef _MMC5_SND_H_
#define _MMC5_SND_H_
#define MMC5_WRA0 0x5000
#define MMC5_WRA1 0x5001
#define MMC5_WRA2 0x5002
#define MMC5_WRA3 0x5003
#define MMC5_WRB0 0x5004
#define MMC5_WRB1 0x5005
#define MMC5_WRB2 0x5006
#define MMC5_WRB3 0x5007
#define MMC5_SMASK 0x5015
typedef struct mmc5rectangle_s
{
uint8 regs[4];
boolean enabled;
int32 phaseacc;
int32 freq;
int32 output_vol;
boolean fixed_envelope;
boolean holdnote;
uint8 volume;
int32 env_phase;
int32 env_delay;
uint8 env_vol;
int vbl_length;
uint8 adder;
int duty_flip;
} mmc5rectangle_t;
#include "nes_apu.h"
extern apuext_t mmc5_ext;
#endif /* !_MMC5_SND_H_ */
/*
** $Log$
** 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.2 2000/06/20 04:06:16 matt
** migrated external sound definition to apu module
**
** Revision 1.1 2000/06/20 00:06:47 matt
** initial revision
**
*/

2438
gst/nsf/nes6502.c Normal file

File diff suppressed because it is too large Load diff

160
gst/nsf/nes6502.h Normal file
View file

@ -0,0 +1,160 @@
/*
** 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.
**
**
** nes6502.h
**
** NES custom 6502 CPU definitions / prototypes
** $Id$
*/
/* NOTE: 16-bit addresses avoided like the plague: use 32-bit values
** wherever humanly possible
*/
#ifndef _NES6502_H_
#define _NES6502_H_
/* Define this to enable decimal mode in ADC / SBC (not needed in NES) */
/*#define NES6502_DECIMAL*/
/* number of bank pointers the CPU emulation core handles */
#ifdef NSF_PLAYER
#define NES6502_4KBANKS
#endif
#ifdef NES6502_4KBANKS
#define NES6502_NUMBANKS 16
#define NES6502_BANKSHIFT 12
#else
#define NES6502_NUMBANKS 8
#define NES6502_BANKSHIFT 13
#endif
#define NES6502_BANKMASK ((0x10000 / NES6502_NUMBANKS) - 1)
/* P (flag) register bitmasks */
#define N_FLAG 0x80
#define V_FLAG 0x40
#define R_FLAG 0x20 /* Reserved, always 1 */
#define B_FLAG 0x10
#define D_FLAG 0x08
#define I_FLAG 0x04
#define Z_FLAG 0x02
#define C_FLAG 0x01
/* Vector addresses */
#define NMI_VECTOR 0xFFFA
#define RESET_VECTOR 0xFFFC
#define IRQ_VECTOR 0xFFFE
/* cycle counts for interrupts */
#define INT_CYCLES 7
#define RESET_CYCLES 6
#define NMI_MASK 0x01
#define IRQ_MASK 0x02
/* Stack is located on 6502 page 1 */
#define STACK_OFFSET 0x0100
typedef struct
{
uint32 min_range, max_range;
uint8 (*read_func)(uint32 address);
} nes6502_memread;
typedef struct
{
uint32 min_range, max_range;
void (*write_func)(uint32 address, uint8 value);
} nes6502_memwrite;
typedef struct
{
uint8 *mem_page[NES6502_NUMBANKS]; /* memory page pointers */
nes6502_memread *read_handler;
nes6502_memwrite *write_handler;
int dma_cycles;
uint32 pc_reg;
uint8 a_reg, p_reg, x_reg, y_reg, s_reg;
uint8 int_pending;
} nes6502_context;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Functions which govern the 6502's execution */
extern void nes6502_init(void);
extern void nes6502_reset(void);
extern int nes6502_execute(int total_cycles);
extern void nes6502_nmi(void);
extern void nes6502_irq(void);
extern uint8 nes6502_getbyte(uint32 address);
extern uint32 nes6502_getcycles(boolean reset_flag);
extern void nes6502_setdma(int cycles);
/* Context get/set */
extern void nes6502_setcontext(nes6502_context *cpu);
extern void nes6502_getcontext(nes6502_context *cpu);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _NES6502_H_ */
/*
** $Log$
** 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.4 2000/06/09 15:12:25 matt
** initial revision
**
*/

1246
gst/nsf/nes_apu.c Normal file

File diff suppressed because it is too large Load diff

354
gst/nsf/nes_apu.h Normal file
View file

@ -0,0 +1,354 @@
/*
** 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.
**
**
** nes_apu.h
**
** NES APU emulation header file
** $Id$
*/
#ifndef _NES_APU_H_
#define _NES_APU_H_
#ifdef __GNUC__
#define INLINE static inline
#elif defined(WIN32)
#define INLINE static __inline
#else
#define INLINE static
#endif
/* define this for realtime generated noise */
#define REALTIME_NOISE
#define APU_WRA0 0x4000
#define APU_WRA1 0x4001
#define APU_WRA2 0x4002
#define APU_WRA3 0x4003
#define APU_WRB0 0x4004
#define APU_WRB1 0x4005
#define APU_WRB2 0x4006
#define APU_WRB3 0x4007
#define APU_WRC0 0x4008
#define APU_WRC2 0x400A
#define APU_WRC3 0x400B
#define APU_WRD0 0x400C
#define APU_WRD2 0x400E
#define APU_WRD3 0x400F
#define APU_WRE0 0x4010
#define APU_WRE1 0x4011
#define APU_WRE2 0x4012
#define APU_WRE3 0x4013
#define APU_OAMDMA 0x4014
#define APU_SMASK 0x4015
#define APU_JOY0 0x4016
#define APU_JOY1 0x4017
/* length of generated noise */
#define APU_NOISE_32K 0x7FFF
#define APU_NOISE_93 93
#define APU_BASEFREQ (NES_MASTER_CLOCK / 12)
/* to/from 16.16 fixed point */
#define APU_TO_FIXED(x) ((x) << 16)
#define APU_FROM_FIXED(x) ((x) >> 16)
/* channel structures */
/* As much data as possible is precalculated,
** to keep the sample processing as lean as possible
*/
typedef struct rectangle_s
{
uint8 regs[4];
boolean enabled;
int32 phaseacc;
int32 freq;
int32 output_vol;
boolean fixed_envelope;
boolean holdnote;
uint8 volume;
int32 sweep_phase;
int32 sweep_delay;
boolean sweep_on;
uint8 sweep_shifts;
uint8 sweep_length;
boolean sweep_inc;
int32 freq_limit;
int32 env_phase;
int32 env_delay;
uint8 env_vol;
int vbl_length;
uint8 adder;
int duty_flip;
} rectangle_t;
/*
enum
{
COUNTMODE_LOAD,
COUNTMODE_COUNT
};
*/
typedef struct triangle_s
{
uint8 regs[3];
boolean enabled;
int32 freq;
int32 phaseacc;
int32 output_vol;
uint8 adder;
boolean holdnote;
boolean counter_started;
/* quasi-hack */
int write_latency;
/* boolean countmode; */
int vbl_length;
int linear_length;
} triangle_t;
typedef struct noise_s
{
uint8 regs[3];
boolean enabled;
int32 freq;
int32 phaseacc;
int32 output_vol;
int32 env_phase;
int32 env_delay;
uint8 env_vol;
boolean fixed_envelope;
boolean holdnote;
uint8 volume;
int vbl_length;
#ifdef REALTIME_NOISE
uint8 xor_tap;
#else
boolean short_sample;
int cur_pos;
#endif /* REALTIME_NOISE */
} noise_t;
typedef struct dmc_s
{
uint8 regs[4];
/* bodge for timestamp queue */
boolean enabled;
int32 freq;
int32 phaseacc;
int32 output_vol;
uint32 address;
uint32 cached_addr;
int dma_length;
int cached_dmalength;
uint8 cur_byte;
boolean looping;
boolean irq_gen;
boolean irq_occurred;
} dmc_t;
enum
{
APU_FILTER_NONE,
APU_FILTER_LOWPASS,
APU_FILTER_WEIGHTED
};
typedef struct
{
uint32 min_range, max_range;
uint8 (*read_func)(uint32 address);
} apu_memread;
typedef struct
{
uint32 min_range, max_range;
void (*write_func)(uint32 address, uint8 value);
} apu_memwrite;
/* external sound chip stuff */
typedef struct apuext_s
{
void (*init)(void);
void (*shutdown)(void);
void (*reset)(void);
int32 (*process)(void);
apu_memread *mem_read;
apu_memwrite *mem_write;
} apuext_t;
/* APU queue structure */
#define APUQUEUE_SIZE 4096
#define APUQUEUE_MASK (APUQUEUE_SIZE - 1)
/* apu ring buffer member */
typedef struct apudata_s
{
uint32 timestamp, address;
uint8 value;
} apudata_t;
typedef struct apu_s
{
rectangle_t rectangle[2];
triangle_t triangle;
noise_t noise;
dmc_t dmc;
uint8 enable_reg;
apudata_t queue[APUQUEUE_SIZE];
int q_head, q_tail;
uint32 elapsed_cycles;
void *buffer; /* pointer to output buffer */
int num_samples;
boolean mix_enable[6];
int filter_type;
int32 cycle_rate;
int sample_rate;
int sample_bits;
int refresh_rate;
void (*process)(void *buffer, int num_samples);
/* external sound chip */
apuext_t *ext;
} apu_t;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Function prototypes */
extern apu_t *apu_create(int sample_rate, int refresh_rate, int sample_bits, boolean stereo);
extern void apu_destroy(apu_t *apu);
extern void apu_setext(apu_t *apu, apuext_t *ext);
extern void apu_setfilter(int filter_type);
extern void apu_process(void *buffer, int num_samples);
extern void apu_reset(void);
extern void apu_setchan(int chan, boolean enabled);
extern int32 apu_getcyclerate(void);
extern apu_t *apu_getcontext(void);
extern uint8 apu_read(uint32 address);
extern void apu_write(uint32 address, uint8 value);
/* for visualization */
extern void apu_getpcmdata(void **data, int *num_samples, int *sample_bits);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _NES_APU_H_ */
/*
** $Log$
** 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.12 2000/07/04 04:54:48 matt
** minor changes that helped with MAME
**
** Revision 1.11 2000/07/03 02:18:53 matt
** much better external module exporting
**
** Revision 1.10 2000/06/26 05:00:37 matt
** cleanups
**
** Revision 1.9 2000/06/23 03:29:28 matt
** cleaned up external sound inteface
**
** Revision 1.8 2000/06/20 04:06:16 matt
** migrated external sound definition to apu module
**
** Revision 1.7 2000/06/20 00:07:35 matt
** added convenience members to apu_t struct
**
** Revision 1.6 2000/06/09 16:49:02 matt
** removed all floating point from sound generation
**
** Revision 1.5 2000/06/09 15:12:28 matt
** initial revision
**
*/

648
gst/nsf/nsf.c Normal file
View file

@ -0,0 +1,648 @@
/*
** 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)
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) {
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);
fread (temp_nsf->data, temp_nsf->length, 1, fp);
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.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
**
*/

173
gst/nsf/nsf.h Normal file
View file

@ -0,0 +1,173 @@
/*
** 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.h
**
** NSF loading/saving related defines / prototypes
** $Id$
*/
#ifndef _NSF_H_
#define _NSF_H_
#include "osd.h"
#include "nes6502.h"
#include "nes_apu.h"
#define NSF_MAGIC "NESM\x1A"
#define NSF_DEDICATED_PAL 0x01
#define NSF_DUAL_PAL_NTSC 0x02
#define EXT_SOUND_NONE 0x00
#define EXT_SOUND_VRCVI 0x01
#define EXT_SOUND_VRCVII 0x02
#define EXT_SOUND_FDS 0x04
#define EXT_SOUND_MMC5 0x08
#define EXT_SOUND_NAMCO106 0x10
#define EXT_SOUND_SUNSOFT_FME07 0x20
/* bits 6,7: future expansion */
#define NSF_HEADER_SIZE 0x80
/* 60 Hertz refresh (NTSC) */
#define NES_MASTER_CLOCK 21477272.7272
#define NTSC_REFRESH 60
#define NTSC_SUBCARRIER_DIV 12
#define NTSC_SCANLINES 262
#define NES_FRAME_CYCLES ((NES_MASTER_CLOCK / NTSC_SUBCARRIER_DIV) / NTSC_REFRESH)
#define NES_SCANLINE_CYCLES (NES_FRAME_CYCLES / NTSC_SCANLINES)
/* filter levels */
enum
{
NSF_FILTER_NONE,
NSF_FILTER_LOWPASS,
NSF_FILTER_WEIGHTED
};
typedef struct nsf_s
{
/* NESM header */
uint8 id[5] ; /* NESM\x1A */
uint8 version ; /* spec version */
uint8 num_songs ; /* total num songs */
uint8 start_song ; /* first song */
uint16 load_addr __PACKED__; /* loc to load code */
uint16 init_addr __PACKED__; /* init call address */
uint16 play_addr __PACKED__; /* play call address */
uint8 song_name[32] ; /* name of song */
uint8 artist_name[32] ; /* artist name */
uint8 copyright[32] ; /* copyright info */
uint16 ntsc_speed __PACKED__; /* playback speed (if NTSC) */
uint8 bankswitch_info[8] ; /* initial code banking */
uint16 pal_speed __PACKED__; /* playback speed (if PAL) */
uint8 pal_ntsc_bits ; /* NTSC/PAL determination bits */
uint8 ext_sound_type ; /* type of external sound gen. */
uint8 reserved[4] ; /* reserved */
/* things that the NSF player needs */
uint8 *data; /* actual NSF data */
uint32 length; /* length of data */
uint32 playback_rate; /* current playback rate */
uint8 current_song; /* current song */
boolean bankswitched; /* is bankswitched? */
/* CPU and APU contexts */
nes6502_context *cpu;
apu_t *apu;
/* our main processing routine, calls all external mixing routines */
void (*process)(void *buffer, int num_samples);
} nsf_t;
/* Function prototypes */
extern void nsf_init(void);
extern nsf_t *nsf_load(char *filename, void *source, int length);
extern void nsf_free(nsf_t **nsf_info);
extern void nsf_playtrack(nsf_t *nsf, int track, int sample_rate, int sample_bits,
boolean stereo);
extern void nsf_frame(nsf_t *nsf);
extern void nsf_setchan(nsf_t *nsf, int chan, boolean enabled);
extern void nsf_setfilter(nsf_t *nsf, int filter_type);
#endif /* _NSF_H_ */
/*
** $Log$
** 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.11 2000/07/04 04:59:24 matt
** removed DOS-specific stuff
**
** Revision 1.10 2000/07/03 02:19:36 matt
** dynamic address range handlers, cleaner and faster
**
** Revision 1.9 2000/06/23 03:27:58 matt
** cleaned up external sound inteface
**
** Revision 1.8 2000/06/20 04:04:37 matt
** moved external soundchip struct to apu module
**
** Revision 1.7 2000/06/20 00:05:45 matt
** changed to driver-based external sound generation
**
** Revision 1.6 2000/06/13 03:51:54 matt
** update API to take freq/sample data on nsf_playtrack
**
** Revision 1.5 2000/06/12 01:13:00 matt
** added CPU/APU as members of the nsf struct
**
** Revision 1.4 2000/06/09 15:12:26 matt
** initial revision
**
*/

123
gst/nsf/osd.h Normal file
View file

@ -0,0 +1,123 @@
/*
** 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.
**
**
** osd.h
**
** O/S dependent routine defintions (must be customized)
** $Id$
*/
#ifndef _OSD_H_
#define _OSD_H_
#ifdef __GNUC__
#define __PACKED__ __attribute__ ((packed))
#define PATH_SEP '/'
#ifdef __DJGPP__
#include <dpmi.h>
#include "dos_ints.h"
#endif
#elif defined(WIN32)
#define __PACKED__
#define PATH_SEP '\\'
#else /* crapintosh? */
#define __PACKED__
#define PATH_SEP ':'
#endif
extern void osd_loginit(void);
extern void osd_logshutdown(void);
extern void osd_logprint(const char *string);
extern int osd_startsound(void (*playfunc)(void *buffer, int size));
extern int osd_getsoundbps(void);
extern int osd_getsamplerate(void);
#ifndef NSF_PLAYER
#include "rgb.h"
#include "bitmap.h"
extern bitmap_t *osd_getvidbuf(void);
typedef void (*blitproc_t)(bitmap_t *bmp, int x_pos, int y_pos, int width, int height);
extern blitproc_t osd_blit;
extern void osd_copytoscreen(void);
extern void osd_showusage(char *filename);
extern void osd_fullname(char *fullname, const char *shortname);
extern char *osd_newextension(char *string, char *ext);
extern void osd_setpalette(rgb_t *pal);
extern void osd_restorepalette(void);
extern void osd_getinput(void);
extern int osd_gethostinput(void);
extern void osd_getmouse(int *x, int *y, int *button);
extern int osd_init(void);
extern void osd_shutdown(void);
#endif /* !NSF_PLAYER */
#endif /* _OSD_H_ */
/*
** $Log$
** 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.7 2000/07/04 04:45:33 matt
** moved INLINE define into types.h
**
** Revision 1.6 2000/06/29 16:06:18 neil
** Wrapped DOS-specific headers in an ifdef
**
** Revision 1.5 2000/06/09 15:12:25 matt
** initial revision
**
*/

125
gst/nsf/types.h Normal file
View file

@ -0,0 +1,125 @@
/*
** 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.
**
**
** types.h
**
** Data type definitions
** $Id$
*/
#ifndef _TYPES_H_
#define _TYPES_H_
/* Define this if running on little-endian (x86) systems */
#define HOST_LITTLE_ENDIAN
#ifdef __GNUC__
#define INLINE static inline
#elif defined(WIN32)
#define INLINE static __inline
#else /* crapintosh? */
#define INLINE static
#endif
/* These should be changed depending on the platform */
typedef char int8;
typedef short int16;
typedef int int32;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef uint8 boolean;
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NULL
#define NULL ((void *) 0)
#endif
#ifdef NOFRENDO_DEBUG
#include <stdlib.h>
#include "memguard.h"
#include "log.h"
#define ASSERT(expr) if (FALSE == (expr))\
{\
log_printf("ASSERT: line %d of %s\n", __LINE__, __FILE__);\
log_shutdown();\
exit(1);\
}
#define ASSERT_MSG(msg) {\
log_printf("ASSERT: %s\n", msg);\
log_shutdown();\
exit(1);\
}
#else /* Not debugging */
#include "memguard.h"
#define ASSERT(expr)
#define ASSERT_MSG(msg)
#endif
#endif /* _TYPES_H_ */
/*
** $Log$
** 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.7 2000/07/04 04:46:44 matt
** moved INLINE define from osd.h
**
** Revision 1.6 2000/06/09 15:12:25 matt
** initial revision
**
*/

376
gst/nsf/vrc7_snd.c Normal file
View file

@ -0,0 +1,376 @@
/*
** 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.
**
**
** vrc7_snd.c
**
** VRCVII sound hardware emulation
** Thanks to Charles MacDonald (cgfm2@hooked.net) for donating code.
** $Id$
*/
#include <stdio.h>
#include "types.h"
#include "vrc7_snd.h"
#include "fmopl.h"
static int buflen;
static int16 *buffer;
#define OPL_WRITE(opl, r, d) \
{ \
OPLWrite((opl)->ym3812, 0, (r)); \
OPLWrite((opl)->ym3812, 1, (d)); \
}
static vrc7_t vrc7;
/* Fixed instrument settings, from MAME's YM2413 emulation */
/* This might need some tweaking... */
unsigned char table[16][11] = {
/* 20 23 40 43 60 63 80 83 E0 E3 C0 */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
/* MAME */
{0x01, 0x22, 0x23, 0x07, 0xF0, 0xF0, 0x07, 0x18, 0x00, 0x00, 0x00}, /* Violin */
{0x23, 0x01, 0x68, 0x05, 0xF2, 0x74, 0x6C, 0x89, 0x00, 0x00, 0x00}, /* Acoustic Guitar(steel) */
{0x13, 0x11, 0x25, 0x00, 0xD2, 0xB2, 0xF4, 0xF4, 0x00, 0x00, 0x00}, /* Acoustic Grand */
{0x22, 0x21, 0x1B, 0x05, 0xC0, 0xA1, 0x18, 0x08, 0x00, 0x00, 0x00}, /* Flute */
{0x22, 0x21, 0x2C, 0x03, 0xD2, 0xA1, 0x18, 0x57, 0x00, 0x00, 0x00}, /* Clarinet */
{0x01, 0x22, 0xBA, 0x01, 0xF1, 0xF1, 0x1E, 0x04, 0x00, 0x00, 0x00}, /* Oboe */
{0x21, 0x21, 0x28, 0x06, 0xF1, 0xF1, 0x6B, 0x3E, 0x00, 0x00, 0x00}, /* Trumpet */
{0x27, 0x21, 0x60, 0x00, 0xF0, 0xF0, 0x0D, 0x0F, 0x00, 0x00, 0x00}, /* Church Organ */
{0x20, 0x21, 0x2B, 0x06, 0x85, 0xF1, 0x6D, 0x89, 0x00, 0x00, 0x00}, /* French Horn */
{0x01, 0x21, 0xBF, 0x02, 0x53, 0x62, 0x5F, 0xAE, 0x01, 0x00, 0x00}, /* Synth Voice */
{0x23, 0x21, 0x70, 0x07, 0xD4, 0xA3, 0x4E, 0x64, 0x01, 0x00, 0x00}, /* Harpsichord */
{0x2B, 0x21, 0xA4, 0x07, 0xF6, 0x93, 0x5C, 0x4D, 0x00, 0x00, 0x00}, /* Vibraphone */
{0x21, 0x23, 0xAD, 0x07, 0x77, 0xF1, 0x18, 0x37, 0x00, 0x00, 0x00}, /* Synth Bass 1 */
{0x21, 0x21, 0x2A, 0x03, 0xF3, 0xE2, 0x29, 0x46, 0x00, 0x00, 0x00}, /* Acoustic Bass */
{0x21, 0x23, 0x37, 0x03, 0xF3, 0xE2, 0x29, 0x46, 0x00, 0x00, 0x00}, /* Electric Guitar(clean) */
#if 0
/* Horton, try 1 */
{0x05, 0x03, 0x10, 0x06, 0x74, 0xA1, 0x13, 0xF4, 0x00, 0x00, 0x00},
{0x05, 0x01, 0x16, 0x00, 0xF9, 0xA2, 0x15, 0xF5, 0x00, 0x00, 0x00},
{0x01, 0x41, 0x11, 0x00, 0xA0, 0xA0, 0x83, 0x95, 0x00, 0x00, 0x00},
{0x01, 0x41, 0x17, 0x00, 0x60, 0xF0, 0x83, 0x95, 0x00, 0x00, 0x00},
{0x24, 0x41, 0x1F, 0x00, 0x50, 0xB0, 0x94, 0x94, 0x00, 0x00, 0x00},
{0x05, 0x01, 0x0B, 0x04, 0x65, 0xA0, 0x54, 0x95, 0x00, 0x00, 0x00},
{0x11, 0x41, 0x0E, 0x04, 0x70, 0xC7, 0x13, 0x10, 0x00, 0x00, 0x00},
{0x02, 0x44, 0x16, 0x06, 0xE0, 0xE0, 0x31, 0x35, 0x00, 0x00, 0x00},
{0x48, 0x22, 0x22, 0x07, 0x50, 0xA1, 0xA5, 0xF4, 0x00, 0x00, 0x00},
{0x05, 0xA1, 0x18, 0x00, 0xA2, 0xA2, 0xF5, 0xF5, 0x00, 0x00, 0x00},
{0x07, 0x81, 0x2B, 0x05, 0xA5, 0xA5, 0x03, 0x03, 0x00, 0x00, 0x00},
{0x01, 0x41, 0x08, 0x08, 0xA0, 0xA0, 0x83, 0x95, 0x00, 0x00, 0x00},
{0x21, 0x61, 0x12, 0x00, 0x93, 0x92, 0x74, 0x75, 0x00, 0x00, 0x00},
{0x21, 0x62, 0x21, 0x00, 0x84, 0x85, 0x34, 0x15, 0x00, 0x00, 0x00},
{0x21, 0x62, 0x0E, 0x00, 0xA1, 0xA0, 0x34, 0x15, 0x00, 0x00, 0x00},
#endif
#if 0
/* Horton try 2 */
{0x31, 0x22, 0x23, 0x07, 0xF0, 0xF0, 0xE8, 0xF7, 0x00, 0x00, 0x00},
{0x03, 0x31, 0x68, 0x05, 0xF2, 0x74, 0x79, 0x9C, 0x00, 0x00, 0x00},
{0x01, 0x51, 0x72, 0x04, 0xF1, 0xD3, 0x9D, 0x8B, 0x00, 0x00, 0x00},
{0x22, 0x61, 0x1B, 0x05, 0xC0, 0xA1, 0xF8, 0xE8, 0x00, 0x00, 0x00},
{0x22, 0x61, 0x2C, 0x03, 0xD2, 0xA1, 0xA7, 0xE8, 0x00, 0x00, 0x00},
{0x31, 0x22, 0xFA, 0x01, 0xF1, 0xF1, 0xF4, 0xEE, 0x00, 0x00, 0x00},
{0x21, 0x61, 0x28, 0x06, 0xF1, 0xF1, 0xCE, 0x9B, 0x00, 0x00, 0x00},
{0x27, 0x61, 0x60, 0x00, 0xF0, 0xF0, 0xFF, 0xFD, 0x00, 0x00, 0x00},
{0x60, 0x21, 0x2B, 0x06, 0x85, 0xF1, 0x79, 0x9D, 0x00, 0x00, 0x00},
{0x31, 0xA1, 0xFF, 0x0A, 0x53, 0x62, 0x5E, 0xAF, 0x00, 0x00, 0x00},
{0x03, 0xA1, 0x70, 0x0F, 0xD4, 0xA3, 0x94, 0xBE, 0x00, 0x00, 0x00},
{0x2B, 0x61, 0xE4, 0x07, 0xF6, 0x93, 0xBD, 0xAC, 0x00, 0x00, 0x00},
{0x21, 0x63, 0xED, 0x07, 0x77, 0xF1, 0xC7, 0xE8, 0x00, 0x00, 0x00},
{0x21, 0x61, 0x2A, 0x03, 0xF3, 0xE2, 0xB6, 0xD9, 0x00, 0x00, 0x00},
{0x21, 0x63, 0x37, 0x03, 0xF3, 0xE2, 0xB6, 0xD9, 0x00, 0x00, 0x00},
#endif
};
static void
vrc7_reset (void)
{
int n;
/* Point to current VRC7 context */
vrc7_t *opll = &vrc7;
/* Clear all YM3812 registers */
for (n = 0; n < 0x100; n++)
OPL_WRITE (opll, n, 0x00);
/* Turn off rhythm mode and key-on bits */
OPL_WRITE (opll, 0xBD, 0xC0);
/* Enable waveform select */
OPL_WRITE (opll, 0x01, 0x20);
}
static void
vrc7_init (void)
{
vrc7.ym3812 =
OPLCreate (OPL_TYPE_YM3812, 3579545, apu_getcontext ()->sample_rate);
ASSERT (vrc7.ym3812);
buflen = apu_getcontext ()->num_samples;
buffer = malloc (buflen * 2);
ASSERT (buffer);
vrc7_reset ();
}
static void
vrc7_shutdown (void)
{
void *t = buffer;
vrc7_reset ();
OPLDestroy (vrc7.ym3812);
free (t);
}
/* channel (0-9), instrument (0-F), volume (0-3F, YM3812 format) */
static void
load_instrument (uint8 ch, uint8 inst, uint8 vol)
{
/* Point to current VRC7 context */
vrc7_t *opll = &vrc7;
/* Point to fixed instrument or user table */
uint8 *param = (inst == 0) ? &opll->user[0] : &table[inst][0];
/* Maps channels to operator registers */
uint8 ch2op[] = { 0, 1, 2, 8, 9, 10, 16, 17, 18 };
/* Make operator offset from requested channel */
uint8 op = ch2op[ch];
/* Store volume level */
opll->channel[ch].volume = (vol & 0x3F);
/* Store instrument number */
opll->channel[ch].instrument = (inst & 0x0F);
/* Update instrument settings, except frequency registers */
OPL_WRITE (opll, 0x20 + op, param[0]);
OPL_WRITE (opll, 0x23 + op, param[1]);
OPL_WRITE (opll, 0x40 + op, param[2]);
OPL_WRITE (opll, 0x43 + op, (param[3] & 0xC0) | opll->channel[ch].volume);
OPL_WRITE (opll, 0x60 + op, param[4]);
OPL_WRITE (opll, 0x63 + op, param[5]);
OPL_WRITE (opll, 0x80 + op, param[6]);
OPL_WRITE (opll, 0x83 + op, param[7]);
OPL_WRITE (opll, 0xE0 + op, param[8]);
OPL_WRITE (opll, 0xE3 + op, param[9]);
OPL_WRITE (opll, 0xC0 + ch, param[10]);
}
static void
vrc7_write (uint32 address, uint8 data)
{
/* Point to current VRC7 context */
vrc7_t *opll = &vrc7;
if (address & 0x0020) { /* data port */
/* Store register data */
opll->reg[opll->latch] = data;
switch (opll->latch & 0x30) {
case 0x00: /* User instrument registers */
switch (opll->latch & 0x0F) {
case 0x00: /* Misc. ctrl. (modulator) */
case 0x01: /* Misc. ctrl. (carrier) */
case 0x02: /* Key scale level and total level (modulator) */
case 0x04: /* Attack / Decay (modulator) */
case 0x05: /* Attack / Decay (carrier) */
case 0x06: /* Sustain / Release (modulator) */
case 0x07: /* Sustain / Release (carrier) */
opll->user[(opll->latch & 0x07)] = data;
break;
case 0x03: /* Key scale level, carrier/modulator waveform, feedback */
/* Key scale level (carrier) */
/* Don't touch the total level (channel volume) */
opll->user[3] = (opll->user[3] & 0x3F) | (data & 0xC0);
/* Waveform select for the modulator */
opll->user[8] = (data >> 3) & 1;
/* Waveform select for the carrier */
opll->user[9] = (data >> 4) & 1;
/* Store feedback level in YM3812 format */
opll->user[10] = ((data & 0x07) << 1) & 0x0E;
break;
}
/* If the user instrument registers were accessed, then
go through each channel and update the ones that were
currently using the user instrument. We can skip the
last three channels in rhythm mode since they can
only use percussion sounds anyways. */
if (opll->latch <= 0x05) {
uint8 x;
for (x = 0; x < 6; x++)
if (opll->channel[x].instrument == 0x00)
load_instrument (x, 0x00, opll->channel[x].volume);
}
break;
case 0x10: /* Channel Frequency (LSB) */
case 0x20: /* Channel Frequency (MSB) + key-on and sustain control */
{
uint8 block;
uint16 frequency;
uint8 ch = (opll->latch & 0x0F);
/* Ensure proper channel range */
if (ch > 0x05)
break;
/* Get VRC7 channel frequency */
frequency =
((opll->reg[0x10 + ch] & 0xFF) | ((opll->reg[0x20 +
ch] & 0x01) << 8));
/* Scale 9 bit frequency to 10 bits */
frequency = (frequency << 1) & 0x1FFF;
/* Get VRC7 block */
block = (opll->reg[0x20 + ch] >> 1) & 7;
/* Add in block */
frequency |= (block << 10);
/* Add key-on flag */
if (opll->reg[0x20 + ch] & 0x10)
frequency |= 0x2000;
/* Save current frequency/block/key-on setting */
opll->channel[ch].frequency = (frequency & 0x3FFF);
/* Write changes to YM3812 */
OPL_WRITE (opll, 0xA0 + ch, (opll->channel[ch].frequency >> 0) & 0xFF);
OPL_WRITE (opll, 0xB0 + ch, (opll->channel[ch].frequency >> 8) & 0xFF);
}
break;
case 0x30: /* Channel Volume Level and Instrument Select */
/* Ensure proper channel range */
if (opll->latch > 0x35)
break;
{
uint8 ch = (opll->latch & 0x0F);
uint8 inst = (data >> 4) & 0x0F;
uint8 vol = (data & 0x0F) << 2;
load_instrument (ch, inst, vol);
}
break;
}
} else { /* Register latch */
opll->latch = (data & 0x3F);
}
}
static int32
vrc7_process (void)
{
static int sample = 0;
/* update a large chunk at once */
if (sample >= buflen) {
sample -= buflen;
YM3812UpdateOne (vrc7.ym3812, buffer, buflen);
}
return (int32) ((int16 *) buffer)[sample++];
}
static apu_memwrite vrc7_memwrite[] = {
{0x9010, 0x9010, vrc7_write},
{0x9030, 0x9030, vrc7_write},
{-1, -1, NULL}
};
apuext_t vrc7_ext = {
vrc7_init,
vrc7_shutdown,
vrc7_reset,
vrc7_process,
NULL, /* no reads */
vrc7_memwrite
};
/*
** $Log$
** 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.5 2000/07/04 04:51:02 matt
** made data types stricter
**
** Revision 1.4 2000/07/03 02:18:53 matt
** much better external module exporting
**
** Revision 1.3 2000/06/20 20:45:09 matt
** minor cleanups
**
** Revision 1.2 2000/06/20 04:06:16 matt
** migrated external sound definition to apu module
**
** Revision 1.1 2000/06/20 00:06:47 matt
** initial revision
**
*/

99
gst/nsf/vrc7_snd.h Normal file
View file

@ -0,0 +1,99 @@
/*
** 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.
**
**
** vrc7_snd.h
**
** VRCVII (Konami MMC) sound hardware emulation header
** Thanks to Charles MacDonald (cgfm2@hooked.net) for donating code.
**
** $Id$
*/
#ifndef _VRC7_SND_H_
#define _VRC7_SND_H_
#include "fmopl.h"
/* VRC7 context */
typedef struct vrc7_s
{
uint8 reg[0x40]; /* 64 registers */
uint8 latch; /* Register latch */
uint8 user[0x10]; /* User instrument settings */
struct
{
uint16 frequency; /* Channel frequency */
uint8 volume; /* Channel volume */
uint8 instrument; /* Channel instrument */
} channel[9];
FM_OPL *ym3812;
} vrc7_t;
#include "nes_apu.h"
extern apuext_t vrc7_ext;
#endif /* !_VRC7_SND_H_ */
/*
** $Log$
** 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.3 2000/07/04 04:51:02 matt
** made data types stricter
**
** Revision 1.2 2000/06/20 04:06:16 matt
** migrated external sound definition to apu module
**
** Revision 1.1 2000/06/20 00:06:47 matt
** initial revision
**
*/

241
gst/nsf/vrcvisnd.c Normal file
View file

@ -0,0 +1,241 @@
/*
** 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.
**
**
** vrcvisnd.c
**
** VRCVI sound hardware emulation
** $Id$
*/
#include "types.h"
#include "vrcvisnd.h"
#include "nes_apu.h"
static vrcvisnd_t vrcvi;
static int32 vrcvi_incsize;
/* VRCVI rectangle wave generation */
static int32
vrcvi_rectangle (vrcvirectangle_t * chan)
{
/* reg0: 0-3=volume, 4-6=duty cycle
** reg1: 8 bits of freq
** reg2: 0-3=high freq, 7=enable
*/
chan->phaseacc -= vrcvi_incsize; /* # of clocks per wave cycle */
while (chan->phaseacc < 0) {
chan->phaseacc += chan->freq;
chan->adder = (chan->adder + 1) & 0x0F;
}
/* return if not enabled */
if (FALSE == chan->enabled)
return 0;
if (chan->adder < chan->duty_flip)
return -(chan->volume);
else
return chan->volume;
}
/* VRCVI sawtooth wave generation */
static int32
vrcvi_sawtooth (vrcvisawtooth_t * chan)
{
/* reg0: 0-5=phase accumulator bits
** reg1: 8 bits of freq
** reg2: 0-3=high freq, 7=enable
*/
chan->phaseacc -= vrcvi_incsize; /* # of clocks per wav cycle */
while (chan->phaseacc < 0) {
chan->phaseacc += chan->freq;
chan->output_acc += chan->volume;
if (7 == ++chan->adder) {
chan->adder = 0;
chan->output_acc = 0;
}
}
/* return if not enabled */
if (FALSE == chan->enabled)
return 0;
else
return (chan->output_acc >> 3) << 9;
}
/* mix vrcvi sound channels together */
static int32
vrcvi_process (void)
{
int32 output;
output = vrcvi_rectangle (&vrcvi.rectangle[0]);
output += vrcvi_rectangle (&vrcvi.rectangle[1]);
output += vrcvi_sawtooth (&vrcvi.saw);
return output;
}
/* write to registers */
static void
vrcvi_write (uint32 address, uint8 value)
{
int chan;
switch (address & 0xB003) {
case 0x9000:
case 0xA000:
chan = (address >> 12) - 9;
vrcvi.rectangle[chan].reg[0] = value;
vrcvi.rectangle[chan].volume = (value & 0x0F) << 8;
vrcvi.rectangle[chan].duty_flip = (value >> 4) + 1;
break;
case 0x9001:
case 0xA001:
chan = (address >> 12) - 9;
vrcvi.rectangle[chan].reg[1] = value;
vrcvi.rectangle[chan].freq =
APU_TO_FIXED (((vrcvi.rectangle[chan].reg[2] & 0x0F) << 8) + value +
1);
break;
case 0x9002:
case 0xA002:
chan = (address >> 12) - 9;
vrcvi.rectangle[chan].reg[2] = value;
vrcvi.rectangle[chan].freq =
APU_TO_FIXED (((value & 0x0F) << 8) + vrcvi.rectangle[chan].reg[1] +
1);
vrcvi.rectangle[chan].enabled = (value & 0x80) ? TRUE : FALSE;
break;
case 0xB000:
vrcvi.saw.reg[0] = value;
vrcvi.saw.volume = value & 0x3F;
break;
case 0xB001:
vrcvi.saw.reg[1] = value;
vrcvi.saw.freq =
APU_TO_FIXED ((((vrcvi.saw.reg[2] & 0x0F) << 8) + value + 1) << 1);
break;
case 0xB002:
vrcvi.saw.reg[2] = value;
vrcvi.saw.freq =
APU_TO_FIXED ((((value & 0x0F) << 8) + vrcvi.saw.reg[1] + 1) << 1);
vrcvi.saw.enabled = (value & 0x80) ? TRUE : FALSE;
break;
default:
break;
}
}
/* reset state of vrcvi sound channels */
static void
vrcvi_reset (void)
{
int i;
/* preload regs */
for (i = 0; i < 3; i++) {
vrcvi_write (0x9000 + i, 0);
vrcvi_write (0xA000 + i, 0);
vrcvi_write (0xB000 + i, 0);
}
/* get the phase period from the apu */
vrcvi_incsize = apu_getcyclerate ();
}
static void
vrcvi_dummy (void)
{
}
static apu_memwrite vrcvi_memwrite[] = {
/* { 0x4040, 0x4092, ext_write }, *//* FDS sound regs */
{0x9000, 0x9002, vrcvi_write}, /* vrc6 */
{0xA000, 0xA002, vrcvi_write},
{0xB000, 0xB002, vrcvi_write},
{-1, -1, NULL}
};
apuext_t vrcvi_ext = {
vrcvi_dummy, /* no init */
vrcvi_dummy, /* no shutdown */
vrcvi_reset,
vrcvi_process,
NULL, /* no reads */
vrcvi_memwrite
};
/*
** $Log$
** 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.9 2000/07/04 04:51:41 matt
** cleanups
**
** Revision 1.8 2000/07/03 02:18:53 matt
** much better external module exporting
**
** Revision 1.7 2000/06/20 04:06:16 matt
** migrated external sound definition to apu module
**
** Revision 1.6 2000/06/20 00:08:58 matt
** changed to driver based API
**
** Revision 1.5 2000/06/09 16:49:02 matt
** removed all floating point from sound generation
**
** Revision 1.4 2000/06/09 15:12:28 matt
** initial revision
**
*/

112
gst/nsf/vrcvisnd.h Normal file
View file

@ -0,0 +1,112 @@
/*
** 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.
**
**
** vrcvisnd.h
**
** VRCVI (Konami MMC) sound hardware emulation header
** $Id$
*/
#ifndef _VRCVISND_H_
#define _VRCVISND_H_
typedef struct vrcvirectangle_s
{
uint8 reg[3];
int32 phaseacc;
uint8 adder;
int32 freq;
int32 volume;
uint8 duty_flip;
boolean enabled;
} vrcvirectangle_t;
typedef struct vrcvisawtooth_s
{
uint8 reg[3];
int32 phaseacc;
uint8 adder;
uint8 output_acc;
int32 freq;
uint8 volume;
boolean enabled;
} vrcvisawtooth_t;
typedef struct vrcvisnd_s
{
vrcvirectangle_t rectangle[2];
vrcvisawtooth_t saw;
} vrcvisnd_t;
#include "nes_apu.h"
extern apuext_t vrcvi_ext;
#endif /* _VRCVISND_H_ */
/*
** $Log$
** 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.7 2000/06/20 04:06:16 matt
** migrated external sound definition to apu module
**
** Revision 1.6 2000/06/20 00:08:58 matt
** changed to driver based API
**
** Revision 1.5 2000/06/09 16:49:02 matt
** removed all floating point from sound generation
**
** Revision 1.4 2000/06/09 15:12:28 matt
** initial revision
**
*/