diff options
| author | Jamieson Christian | 2003-07-11 07:14:21 +0000 | 
|---|---|---|
| committer | Jamieson Christian | 2003-07-11 07:14:21 +0000 | 
| commit | 8b8b964aadcf0f37cfb853c83857da7271af5ebc (patch) | |
| tree | 0084198c30998e89b2331a8b678cc42a21dbfa72 | |
| parent | 39b37df37a7fed6f5dd62d11fb10e4b8276f05c1 (diff) | |
| download | scummvm-rg350-8b8b964aadcf0f37cfb853c83857da7271af5ebc.tar.gz scummvm-rg350-8b8b964aadcf0f37cfb853c83857da7271af5ebc.tar.bz2 scummvm-rg350-8b8b964aadcf0f37cfb853c83857da7271af5ebc.zip  | |
Reverted to "old" YM3812 (FMOPL) emulator code.
Until specific information regarding the benefits
of migrating to the new emulator can be made
available, the "old" code will remain in effect
for the benefit of slower hardware platforms such
as some WinCE-based devices.
svn-id: r8903
| -rw-r--r-- | backends/midi/adlib.cpp | 19 | ||||
| -rw-r--r-- | sky/music/adlibchannel.cpp | 8 | ||||
| -rw-r--r-- | sky/music/adlibchannel.h | 4 | ||||
| -rw-r--r-- | sky/music/adlibmusic.cpp | 20 | ||||
| -rw-r--r-- | sky/music/adlibmusic.h | 2 | ||||
| -rw-r--r-- | sound/fmopl.cpp | 2926 | ||||
| -rw-r--r-- | sound/fmopl.h | 234 | 
7 files changed, 965 insertions, 2248 deletions
diff --git a/backends/midi/adlib.cpp b/backends/midi/adlib.cpp index 734f4632a6..434e6f1f69 100644 --- a/backends/midi/adlib.cpp +++ b/backends/midi/adlib.cpp @@ -577,6 +577,7 @@ private:  	bool _isOpen;  	bool _game_SmallHeader; +	FM_OPL *_opl;  	byte *_adlib_reg_cache;  	SoundMixer *_mixer; @@ -848,8 +849,12 @@ int MidiDriver_ADLIB::open() {  	_adlib_reg_cache = (byte *)calloc(256, 1);  	// We need to emulate one YM3812 chip -	if (0 != YM3812Init(1, 3579545, g_system->property(OSystem::PROP_GET_SAMPLE_RATE, 0))) -		error("Error initialising YM3812 sound chip emulation"); +//	if (0 != YM3812Init(1, 3579545, g_system->property(OSystem::PROP_GET_SAMPLE_RATE, 0))) +//		error("Error initialising YM3812 sound chip emulation"); +	int env_bits = g_system->property(OSystem::PROP_GET_FMOPL_ENV_BITS, NULL);    +	int eg_ent = g_system->property(OSystem::PROP_GET_FMOPL_EG_ENT, NULL);    +	OPLBuildTables((env_bits ? env_bits : FMOPL_ENV_BITS_HQ), (eg_ent ? eg_ent : FMOPL_EG_ENT_HQ)); +	_opl = OPLCreate(OPL_TYPE_YM3812, 3579545, g_system->property(OSystem::PROP_GET_SAMPLE_RATE, 0));  	adlib_write(1, 0x20);  	adlib_write(8, 0x40); @@ -876,7 +881,7 @@ void MidiDriver_ADLIB::close() {  	_mixer->setupPremix (0, 0);  	// Turn off the OPL emulation -	YM3812Shutdown(); +//	YM3812Shutdown();  	free(_adlib_reg_cache); @@ -986,8 +991,9 @@ void MidiDriver_ADLIB::adlib_write(byte port, byte value) {  		return;  	_adlib_reg_cache[port] = value; -	YM3812Write(0, 0, port); -	YM3812Write(0, 1, value); +//	YM3812Write(0, 0, port); +//	YM3812Write(0, 1, value); +	OPLWriteReg (_opl, port, value);  }  void MidiDriver_ADLIB::generate_samples(int16 *data, int len) { @@ -997,7 +1003,8 @@ void MidiDriver_ADLIB::generate_samples(int16 *data, int len) {  		step = len;  		if (step > _next_tick)  			step = _next_tick; -		YM3812UpdateOne(0, data, step); +//		YM3812UpdateOne(0, data, step); +		YM3812UpdateOne (_opl, data, step);  		_next_tick -= step;  		if (!_next_tick) { diff --git a/sky/music/adlibchannel.cpp b/sky/music/adlibchannel.cpp index 6a320969d5..7418b05568 100644 --- a/sky/music/adlibchannel.cpp +++ b/sky/music/adlibchannel.cpp @@ -22,8 +22,9 @@  #include "adlibchannel.h"  #include "sound/fmopl.h" -SkyAdlibChannel::SkyAdlibChannel(uint8 *pMusicData, uint16 startOfData) +SkyAdlibChannel::SkyAdlibChannel(FM_OPL *opl, uint8 *pMusicData, uint16 startOfData)  { +	_opl = opl;  	_musicData = pMusicData;  	_channelData.startOfData = startOfData;  	_channelData.eventDataPtr = startOfData; @@ -78,8 +79,9 @@ void SkyAdlibChannel::updateVolume(uint16 pVolume) {  void SkyAdlibChannel::setRegister(uint8 regNum, uint8 value) {  	if (_adlibRegMirror[regNum] != value) { -		YM3812Write(0, 0, regNum); -		YM3812Write(0, 1, value); +//		YM3812Write(0, 0, regNum); +//		YM3812Write(0, 1, value); +		OPLWriteReg (_opl, regNum, value);  		_adlibRegMirror[regNum] = value;  	}  } diff --git a/sky/music/adlibchannel.h b/sky/music/adlibchannel.h index 8ca72e8a58..3b27c2305b 100644 --- a/sky/music/adlibchannel.h +++ b/sky/music/adlibchannel.h @@ -26,6 +26,7 @@  #include "common/engine.h"  #include "sky/sky.h"  #include "sky/music/musicbase.h" +#include "sound/fmopl.h"  typedef struct {  	uint8 ad_Op1, ad_Op2; @@ -60,12 +61,13 @@ typedef struct {  class SkyAdlibChannel : public SkyChannelBase {  public: -	SkyAdlibChannel(uint8 *pMusicData, uint16 startOfData); +	SkyAdlibChannel (FM_OPL *opl, uint8 *pMusicData, uint16 startOfData);  	virtual void stopNote(void);  	virtual uint8 process(uint16 aktTime);  	virtual void updateVolume(uint16 pVolume);  	virtual bool isActive(void);  private: +	FM_OPL *_opl;  	uint8 *_musicData;  	uint16 _musicVolume;  	AdlibChannelType _channelData; diff --git a/sky/music/adlibmusic.cpp b/sky/music/adlibmusic.cpp index 6922295ef3..444e4cd3e0 100644 --- a/sky/music/adlibmusic.cpp +++ b/sky/music/adlibmusic.cpp @@ -33,15 +33,20 @@ SkyAdlibMusic::SkyAdlibMusic(SoundMixer *pMixer, SkyDisk *pSkyDisk, OSystem *sys  	_driverFileBase = 60202;      _mixer = pMixer;  	_sampleRate = g_system->property(OSystem::PROP_GET_SAMPLE_RATE, 0); -	if (0 != YM3812Init(1, 3579545, _sampleRate)) -		error("Error initialising YM3812 sound chip emulation"); +//	if (0 != YM3812Init(1, 3579545, _sampleRate)) +//		error("Error initialising YM3812 sound chip emulation"); +	int env_bits = g_system->property(OSystem::PROP_GET_FMOPL_ENV_BITS, NULL);    +	int eg_ent = g_system->property(OSystem::PROP_GET_FMOPL_EG_ENT, NULL);    +	OPLBuildTables((env_bits ? env_bits : FMOPL_ENV_BITS_HQ), (eg_ent ? eg_ent : FMOPL_EG_ENT_HQ)); +	_opl = OPLCreate(OPL_TYPE_YM3812, 3579545, g_system->property(OSystem::PROP_GET_SAMPLE_RATE, 0)); +    	_mixer->setupPremix(this, passMixerFunc);  }  SkyAdlibMusic::~SkyAdlibMusic(void) {  	_mixer->setupPremix(NULL, NULL); -	YM3812Shutdown(); +//	YM3812Shutdown();  }  void SkyAdlibMusic::setVolume(uint8 volume) { @@ -70,7 +75,7 @@ void SkyAdlibMusic::premixerCall(int16 *buf, uint len) {  		render = (len > _nextMusicPoll) ? (_nextMusicPoll) : (len);  		len -= render;  		_nextMusicPoll -= render; -		YM3812UpdateOne(0, buf, render); +		YM3812UpdateOne (_opl, buf, render);  		buf += render;  		if (_nextMusicPoll == 0) {  			pollMusic(); @@ -98,7 +103,7 @@ void SkyAdlibMusic::setupChannels(uint8 *channelData) {  	channelData++;  	for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++) {  		uint16 chDataStart = ((channelData[(cnt << 1) | 1] << 8) | channelData[cnt << 1]) + _musicDataLoc; -		_channels[cnt] = new SkyAdlibChannel(_musicData, chDataStart); +		_channels[cnt] = new SkyAdlibChannel(_opl, _musicData, chDataStart);  		_channels[cnt]->updateVolume(_musicVolume | 128);  	}  } @@ -107,8 +112,9 @@ void SkyAdlibMusic::startDriver(void) {  	uint16 cnt = 0;  	while (_initSequence[cnt] || _initSequence[cnt+1]) { -		YM3812Write(0, 0, _initSequence[cnt]); -		YM3812Write(0, 1, _initSequence[cnt+1]); +//		YM3812Write(0, 0, _initSequence[cnt]); +//		YM3812Write(0, 1, _initSequence[cnt+1]); +		OPLWriteReg (_opl, _initSequence[cnt], _initSequence[cnt+1]);  		cnt += 2;  	}  	_allowedCommands = 0xD; diff --git a/sky/music/adlibmusic.h b/sky/music/adlibmusic.h index dd7085b0cd..481977b385 100644 --- a/sky/music/adlibmusic.h +++ b/sky/music/adlibmusic.h @@ -28,6 +28,7 @@  #include "common/engine.h"  #include "adlibchannel.h"  #include "musicbase.h" +#include "sound/fmopl.h"  class SkyAdlibMusic : public SkyMusicBase {  public: @@ -35,6 +36,7 @@ public:  	~SkyAdlibMusic(void);  	virtual void setVolume(uint8 volume);  private: +	FM_OPL *_opl;  	SoundMixer *_mixer;  	uint8 *_initSequence;  	uint32 _sampleRate, _nextMusicPoll; diff --git a/sound/fmopl.cpp b/sound/fmopl.cpp index 549c4609b1..ef25721767 100644 --- a/sound/fmopl.cpp +++ b/sound/fmopl.cpp @@ -1,286 +1,101 @@ -/* -** -** File: fmopl.c - software implementation of FM sound generator -**                                            types OPL and OPL2 -** -** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmulator development -** Copyright (C) 2002 Jarek Burczynski -** -** Version 0.60 -** - -Revision History: - -04-28-2002 Jarek Burczynski: - - binary exact Envelope Generator (verified on real YM3812); -   compared to YM2151: the EG clock is equal to internal_clock, -   rates are 2 times slower and volume resolution is one bit less - - modified interface functions (they no longer return pointer - -   that's internal to the emulator now): -    - new wrapper functions for OPLCreate: YM3526Init(), YM3812Init() and Y8950Init() - - corrected 'off by one' error in feedback calculations (when feedback is off) - - enabled waveform usage (credit goes to Vlad Romascanu and zazzal22) - - speeded up noise generator calculations (Nicola Salmoria) - -03-24-2002 Jarek Burczynski (thanks to Dox for the YM3812 chip) - Complete rewrite (all verified on real YM3812): - - corrected sin_tab and tl_tab data - - corrected operator output calculations - - corrected waveform_select_enable register; -   simply: ignore all writes to waveform_select register when -   waveform_select_enable == 0 and do not change the waveform previously selected. - - corrected KSR handling - - corrected Envelope Generator: attack shape, Sustain mode and -   Percussive/Non-percussive modes handling - - Envelope Generator rates are two times slower now - - LFO amplitude (tremolo) and phase modulation (vibrato) - - rhythm sounds phase generation - - white noise generator (big thanks to Olivier Galibert for mentioning Berlekamp-Massey algorithm) - - corrected key on/off handling (the 'key' signal is ORed from three sources: FM, rhythm and CSM) - - funky details (like ignoring output of operator 1 in BD rhythm sound when connect == 1) - -12-28-2001 Acho A. Tang - - reflected Delta-T EOS status on Y8950 status port. - - fixed subscription range of attack/decay tables - - -	To do: -		add delay before key off in CSM mode (see CSMKeyControll) -		verify volume of the FM part on the Y8950 -*/ +/* ScummVM - Scumm Interpreter + * Copyright (C) 1999-2000 Tatsuyuki Satoh + * Copyright (C) 2001-2003 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. + * + * $Header$ + * + * LGPL licensed version of MAMEs fmopl (V0.37a modified) by + * Tatsuyuki Satoh. Included from LGPL'ed AdPlug. + */  #include "stdafx.h" -#include "scummsys.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h>  #include <math.h> +  #include "fmopl.h" +#include "common/engine.h"	// for warning/error/debug +  #ifndef PI  #define PI 3.14159265358979323846  #endif -#ifdef _MSC_VER -#  define INLINE __inline -#elif defined(__GNUC__) -#  define INLINE inline -#else -#  define INLINE -#endif +/* -------------------- preliminary define section --------------------- */ +/* attack/decay rate time rate */ +#define OPL_ARRATE     141280  /* RATE 4 =  2826.24ms @ 3.6MHz */ +#define OPL_DRRATE    1956000  /* RATE 4 = 39280.64ms @ 3.6MHz */ -/* output final shift */ -#if (OPL_SAMPLE_BITS==16) -	#define FINAL_SH	(0) -	#define MAXOUT		(+32767) -	#define MINOUT		(-32768) -#else -	#define FINAL_SH	(8) -	#define MAXOUT		(+127) -	#define MINOUT		(-128) -#endif +#define FREQ_BITS 24			/* frequency turn          */ + +/* counter bits = 20 , octerve 7 */ +#define FREQ_RATE   (1<<(FREQ_BITS-20)) +#define TL_BITS    (FREQ_BITS+2) +/* final output shift , limit minimum and maximum */ +#define OPL_OUTSB   (TL_BITS+3-16)		/* OPL output final shift 16bit */ +#define OPL_MAXOUT (0x7fff<<OPL_OUTSB) +#define OPL_MINOUT (-0x8000<<OPL_OUTSB) -#define FREQ_SH			16  /* 16.16 fixed point (frequency calculations) */ -#define EG_SH			16  /* 16.16 fixed point (EG timing)              */ -#define LFO_SH			24  /*  8.24 fixed point (LFO calculations)       */ -#define TIMER_SH		16  /* 16.16 fixed point (timers calculations)    */ +/* -------------------- quality selection --------------------- */ -#define FREQ_MASK		((1<<FREQ_SH)-1) +/* sinwave entries */ +/* used static memory = SIN_ENT * 4 (byte) */ +#define SIN_ENT 2048 +/* output level entries (envelope,sinwave) */ +/* envelope counter lower bits */ +int ENV_BITS;  /* envelope output entries */ -static const int	ENV_BITS	= 10; -static const int	ENV_LEN		= 1<<ENV_BITS; -static const float	ENV_STEP	= 128.f/ENV_LEN; +int EG_ENT; -#define MAX_ATT_INDEX	((1<<(ENV_BITS-1))-1) /*511*/ -#define MIN_ATT_INDEX	(0) +/* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */ +/* used static  memory = EG_ENT*4 (byte)                     */ +int EG_OFF;								 /* OFF */ +int EG_DED; +int EG_DST;								 /* DECAY START */ +int EG_AED; +#define EG_AST   0                       /* ATTACK START */ -/* sinwave entries */ -#define SIN_BITS		10 -#define SIN_LEN			(1<<SIN_BITS) -#define SIN_MASK		(SIN_LEN-1) +#define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step  */ -#define TL_RES_LEN		(256)	/* 8 bits addressing (real chip) */ +/* LFO table entries */ +#define VIB_ENT 512 +#define VIB_SHIFT (32-9) +#define AMS_ENT 512 +#define AMS_SHIFT (32-9) +#define VIB_RATE 256 +/* -------------------- local defines , macros --------------------- */  /* register number to channel number , slot offset */  #define SLOT1 0  #define SLOT2 1 -/* Envelope Generator phases */ - -#define EG_ATT			4 -#define EG_DEC			3 -#define EG_SUS			2 -#define EG_REL			1 -#define EG_OFF			0 - - -/* save output as raw 16-bit sample */ - -/*#define SAVE_SAMPLE*/ - -#ifdef SAVE_SAMPLE -static FILE *sample[1]; -	#if 1	/*save to MONO file */ -		#define SAVE_ALL_CHANNELS \ -		{	signed int pom = lt; \ -			fputc((unsigned short)pom&0xff,sample[0]); \ -			fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ -		} -	#else	/*save to STEREO file */ -		#define SAVE_ALL_CHANNELS \ -		{	signed int pom = lt; \ -			fputc((unsigned short)pom&0xff,sample[0]); \ -			fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ -			pom = rt; \ -			fputc((unsigned short)pom&0xff,sample[0]); \ -			fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ -		} -	#endif -#endif - -/* #define LOG_CYM_FILE */ -#ifdef LOG_CYM_FILE -	FILE * cymfile = NULL; -#endif - - - -#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			*/ - -/* ---------- 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) - - - -/* Saving is necessary for member of the 'R' mark for suspend/resume */ - -typedef struct{ -	UINT32	ar;			/* attack rate: AR<<2			*/ -	UINT32	dr;			/* decay rate:  DR<<2			*/ -	UINT32	rr;			/* release rate:RR<<2			*/ -	UINT8	KSR;		/* key scale rate				*/ -	UINT8	ksl;		/* keyscale level				*/ -	UINT8	ksr;		/* key scale rate: kcode>>KSR	*/ -	UINT8	mul;		/* multiple: mul_tab[ML]		*/ - -	/* Phase Generator */ -	UINT32	Cnt;		/* frequency counter			*/ -	UINT32	Incr;		/* frequency counter step		*/ -	UINT8   FB;			/* feedback shift value			*/ -	INT32   *connect1;	/* slot1 output pointer			*/ -	INT32   op1_out[2];	/* slot1 output for feedback	*/ -	UINT8   CON;		/* connection (algorithm) type	*/ - -	/* Envelope Generator */ -	UINT8	eg_type;	/* percussive/non-percussive mode */ -	UINT8	state;		/* phase type					*/ -	UINT32	TL;			/* total level: TL << 2			*/ -	INT32	TLL;		/* adjusted now TL				*/ -	INT32	volume;		/* envelope counter				*/ -	UINT32	sl;			/* sustain level: sl_tab[SL]	*/ - -	UINT8	eg_sh_ar;	/* (attack state)				*/ -	UINT8	eg_sel_ar;	/* (attack state)				*/ -	UINT8	eg_sh_dr;	/* (decay state)				*/ -	UINT8	eg_sel_dr;	/* (decay state)				*/ -	UINT8	eg_sh_rr;	/* (release state)				*/ -	UINT8	eg_sel_rr;	/* (release state)				*/ - -	UINT32	key;		/* 0 = KEY OFF, >0 = KEY ON		*/ - -	/* LFO */ -	UINT32	AMmask;		/* LFO Amplitude Modulation enable mask */ -	UINT8	vib;		/* LFO Phase Modulation enable flag (active high)*/ - -	/* waveform select */ -	unsigned int wavetable; -} OPL_SLOT; - -typedef struct{ -	OPL_SLOT SLOT[2]; -	/* phase generator state */ -	UINT32  block_fnum;	/* block+fnum					*/ -	UINT32  fc;			/* Freq. Increment base			*/ -	UINT32  ksl_base;	/* KeyScaleLevel Base step		*/ -	UINT8   kcode;		/* key code (for key scaling)	*/ -} OPL_CH; - -/* OPL state */ -typedef struct fm_opl_f { -	/* FM channel slots */ -	OPL_CH	P_CH[9];				/* OPL/OPL2 chips have 9 channels*/ - -	UINT32	eg_cnt;					/* global envelope generator counter	*/ -	UINT32	eg_timer;				/* global envelope generator counter works at frequency = chipclock/72 */ -	UINT32	eg_timer_add;			/* step of eg_timer						*/ -	UINT32	eg_timer_overflow;		/* envelope generator timer overlfows every 1 sample (on real chip) */ - -	UINT8	rhythm;					/* Rhythm mode					*/ - -	UINT32	fn_tab[1024];			/* fnumber->increment counter	*/ - -	/* LFO */ -	UINT8	lfo_am_depth; -	UINT8	lfo_pm_depth_range; -	UINT32	lfo_am_cnt; -	UINT32	lfo_am_inc; -	UINT32	lfo_pm_cnt; -	UINT32	lfo_pm_inc; - -	UINT32	noise_rng;				/* 23 bit noise shift register	*/ -	UINT32	noise_p;				/* current noise 'phase'		*/ -	UINT32	noise_f;				/* current noise period			*/ - -	UINT8	wavesel;				/* waveform select enable flag	*/ - -	int		T[2];					/* timer counters				*/ -	UINT8	st[2];					/* timer enable					*/ - -#if BUILD_Y8950 -	/* Delta-T ADPCM unit (Y8950) */ - -	YM_DELTAT *deltat; - -	/* Keyboard / I/O interface unit*/ -	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; -#endif - -	/* external event callback handlers */ -	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		*/ +/* envelope phase */ +#define ENV_MOD_RR  0x00 +#define ENV_MOD_DR  0x01 +#define ENV_MOD_AR  0x02 -	UINT8 type;						/* chip type					*/ -	UINT8 address;					/* address register				*/ -	UINT8 status;					/* status flag					*/ -	UINT8 statusmask;				/* status mask					*/ -	UINT8 mode;						/* Reg.08 : CSM,notesel,etc.	*/ - -	int clock;						/* master clock  (Hz)			*/ -	int rate;						/* sampling rate (Hz)			*/ -	double freqbase;				/* frequency base				*/ -	double TimerBase;				/* Timer base time (==sampling time)*/ -} FM_OPL; - - - -/* mapping of register number (offset) to slot number used by the emulator */ +/* -------------------- tables --------------------- */  static const int slot_array[32]=  {  	 0, 2, 4, 1, 3, 5,-1,-1, @@ -289,326 +104,142 @@ static const int slot_array[32]=  	-1,-1,-1,-1,-1,-1,-1,-1  }; -/* key scale level */ -/* table is 3dB/octave , DV converts this into 6dB/octave */ -/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ -#define DV (0.1875/2.0) -#define KSL(x) (UINT32)(x/DV) -static const UINT32 ksl_tab[8*16]= -{ +static uint KSL_TABLE[8 * 16]; + +static const double KSL_TABLE_SEED[8 * 16] = {  	/* OCT 0 */ -	 KSL(0.000), KSL(0.000), KSL(0.000), KSL(0.000), -	 KSL(0.000), KSL(0.000), KSL(0.000), KSL(0.000), -	 KSL(0.000), KSL(0.000), KSL(0.000), KSL(0.000), -	 KSL(0.000), KSL(0.000), KSL(0.000), KSL(0.000), +	0.000, 0.000, 0.000, 0.000, +	0.000, 0.000, 0.000, 0.000, +	0.000, 0.000, 0.000, 0.000, +	0.000, 0.000, 0.000, 0.000,  	/* OCT 1 */ -	 KSL(0.000), KSL(0.000), KSL(0.000), KSL(0.000), -	 KSL(0.000), KSL(0.000), KSL(0.000), KSL(0.000), -	 KSL(0.000), KSL(0.750), KSL(1.125), KSL(1.500), -	 KSL(1.875), KSL(2.250), KSL(2.625), KSL(3.000), +	0.000, 0.000, 0.000, 0.000, +	0.000, 0.000, 0.000, 0.000, +	0.000, 0.750, 1.125, 1.500, +	1.875, 2.250, 2.625, 3.000,  	/* OCT 2 */ -	 KSL(0.000), KSL(0.000), KSL(0.000), KSL(0.000), -	 KSL(0.000), KSL(1.125), KSL(1.875), KSL(2.625), -	 KSL(3.000), KSL(3.750), KSL(4.125), KSL(4.500), -	 KSL(4.875), KSL(5.250), KSL(5.625), KSL(6.000), +	0.000, 0.000, 0.000, 0.000, +	0.000, 1.125, 1.875, 2.625, +	3.000, 3.750, 4.125, 4.500, +	4.875, 5.250, 5.625, 6.000,  	/* OCT 3 */ -	 KSL(0.000), KSL(0.000), KSL(0.000), KSL(1.875), -	 KSL(3.000), KSL(4.125), KSL(4.875), KSL(5.625), -	 KSL(6.000), KSL(6.750), KSL(7.125), KSL(7.500), -	 KSL(7.875), KSL(8.250), KSL(8.625), KSL(9.000), +	0.000, 0.000, 0.000, 1.875, +	3.000, 4.125, 4.875, 5.625, +	6.000, 6.750, 7.125, 7.500, +	7.875, 8.250, 8.625, 9.000,  	/* OCT 4 */ -	 KSL(0.000), KSL(0.000), KSL(3.000), KSL(4.875), -	 KSL(6.000), KSL(7.125), KSL(7.875), KSL(8.625), -	 KSL(9.000), KSL(9.750),KSL(10.125),KSL(10.500), -	KSL(10.875),KSL(11.250),KSL(11.625),KSL(12.000), +	0.000, 0.000, 3.000, 4.875, +	6.000, 7.125, 7.875, 8.625, +	9.000, 9.750, 10.125, 10.500, +	10.875, 11.250, 11.625, 12.000,  	/* OCT 5 */ -	 KSL(0.000), KSL(3.000), KSL(6.000), KSL(7.875), -	 KSL(9.000),KSL(10.125),KSL(10.875),KSL(11.625), -	KSL(12.000),KSL(12.750),KSL(13.125),KSL(13.500), -	KSL(13.875),KSL(14.250),KSL(14.625),KSL(15.000), +	0.000, 3.000, 6.000, 7.875, +	9.000, 10.125, 10.875, 11.625, +	12.000, 12.750, 13.125, 13.500, +	13.875, 14.250, 14.625, 15.000,  	/* OCT 6 */ -	 KSL(0.000), KSL(6.000), KSL(9.000),KSL(10.875), -	KSL(12.000),KSL(13.125),KSL(13.875),KSL(14.625), -	KSL(15.000),KSL(15.750),KSL(16.125),KSL(16.500), -	KSL(16.875),KSL(17.250),KSL(17.625),KSL(18.000), +	0.000, 6.000, 9.000, 10.875, +	12.000, 13.125, 13.875, 14.625, +	15.000, 15.750, 16.125, 16.500, +	16.875, 17.250, 17.625, 18.000,  	/* OCT 7 */ -	 KSL(0.000), KSL(9.000),KSL(12.000),KSL(13.875), -	KSL(15.000),KSL(16.125),KSL(16.875),KSL(17.625), -	KSL(18.000),KSL(18.750),KSL(19.125),KSL(19.500), -	KSL(19.875),KSL(20.250),KSL(20.625),KSL(21.000) +	0.000, 9.000, 12.000, 13.875, +	15.000, 16.125, 16.875, 17.625, +	18.000, 18.750, 19.125, 19.500, +	19.875, 20.250, 20.625, 21.000  }; -#undef DV -#undef KSL -/* sustain level table (3dB per step) */ +/* sustain lebel table (3db per step) */  /* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ -#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) ) - -static const UINT32 sl_tab[16]={ - SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), - SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) -}; -#undef SC - - -#define RATE_STEPS (8) -static const unsigned char eg_inc[15*RATE_STEPS]={ - -/*cycle:0 1  2 3  4 5  6 7*/ - -/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ -/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ -/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ -/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ -/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ -/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ -/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ -/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ +static int SL_TABLE[16]; -/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ -/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ -/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ -/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ - -/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */ -/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */ -/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +static const uint SL_TABLE_SEED[16] = { +	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 31  }; +#define TL_MAX (EG_ENT * 2) /* limit(tl + ksr + envelope) + sinwave */ +/* TotalLevel : 48 24 12  6  3 1.5 0.75 (dB) */ +/* TL_TABLE[ 0      to TL_MAX          ] : plus  section */ +/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */ +static int *TL_TABLE; -#define O(a) (a*RATE_STEPS) - -/*note that there is no O(13) in this table - it's directly in the code */ -static const unsigned char eg_rate_select[16+64+16]={	/* Envelope Generator rates (16 + 64 rates + 16 RKS) */ -/* 16 dummy (infinite time) rates */ -O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), -O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), - -/* rates 00-12 */ -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), +/* pointers to TL_TABLE with sinwave output offset */ +static int **SIN_TABLE; -/* rate 13 */ -O( 4),O( 5),O( 6),O( 7), - -/* rate 14 */ -O( 8),O( 9),O(10),O(11), - -/* rate 15 */ -O(12),O(12),O(12),O(12), - -/* 16 dummy rates (same as 15 3) */ -O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), -O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), - -}; -#undef O - -//rate  0,    1,    2,    3,   4,   5,   6,  7,  8,  9,  10, 11, 12, 13, 14, 15 -//shift 12,   11,   10,   9,   8,   7,   6,  5,  4,  3,  2,  1,  0,  0,  0,  0 -//mask  4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7,  3,  1,  0,  0,  0,  0 - -#define O(a) (a*1) -static const unsigned char eg_rate_shift[16+64+16]={	/* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ -/* 16 infinite time rates */ -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), - -/* rates 00-12 */ -O(12),O(12),O(12),O(12), -O(11),O(11),O(11),O(11), -O(10),O(10),O(10),O(10), -O( 9),O( 9),O( 9),O( 9), -O( 8),O( 8),O( 8),O( 8), -O( 7),O( 7),O( 7),O( 7), -O( 6),O( 6),O( 6),O( 6), -O( 5),O( 5),O( 5),O( 5), -O( 4),O( 4),O( 4),O( 4), -O( 3),O( 3),O( 3),O( 3), -O( 2),O( 2),O( 2),O( 2), -O( 1),O( 1),O( 1),O( 1), -O( 0),O( 0),O( 0),O( 0), - -/* rate 13 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 14 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 15 */ -O( 0),O( 0),O( 0),O( 0), - -/* 16 dummy rates (same as 15 3) */ -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), - -}; -#undef O +/* LFO table */ +static int *AMS_TABLE; +static int *VIB_TABLE; +/* envelope output curve table */ +/* attack + decay + OFF */ +//static int ENV_CURVE[2*EG_ENT+1]; +static int ENV_CURVE[2 * 4096 + 1];   // to keep it static ...  /* multiple table */ -#define ML(x) (UINT8)(x*2) -static const UINT8 mul_tab[16]= { -/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ -   ML(0.50), ML(1.00), ML(2.00), ML(3.00), ML(4.00), ML(5.00), ML(6.00), ML(7.00), -   ML(8.00), ML(9.00),ML(10.00),ML(10.00),ML(12.00),ML(12.00),ML(15.00),ML(15.00) +#define ML(a) (int)(a * 2) +static const uint MUL_TABLE[16]= { +/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */ +	ML(0.50), ML(1.00), ML(2.00),  ML(3.00), ML(4.00), ML(5.00), ML(6.00), ML(7.00), +	ML(8.00), ML(9.00), ML(10.00), ML(10.00),ML(12.00),ML(12.00),ML(15.00),ML(15.00)  };  #undef ML -/*	TL_TAB_LEN is calculated as: -*	12 - sinus amplitude bits     (Y axis) -*	2  - sinus sign bit           (Y axis) -*	TL_RES_LEN - sinus resolution (X axis) -*/ -#define TL_TAB_LEN (12*2*TL_RES_LEN) -static signed int tl_tab[TL_TAB_LEN]; - -#define ENV_QUIET		(TL_TAB_LEN>>4) - -/* sin waveform table in 'decibel' scale */ -/* four waveforms on OPL2 type chips */ -static unsigned int sin_tab[SIN_LEN * 4]; - - -/* LFO Amplitude Modulation table (verified on real YM3812) -   27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples - -   Length: 210 elements. - -	Each of the elements has to be repeated -	exactly 64 times (on 64 consecutive samples). -	The whole table takes: 64 * 210 = 13440 samples. - -	When AM = 1 data is used directly -	When AM = 0 data is divided by 4 before being used (loosing precision is important) -*/ - -#define LFO_AM_TAB_ELEMENTS 210 - -static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { -0,0,0,0,0,0,0, -1,1,1,1, -2,2,2,2, -3,3,3,3, -4,4,4,4, -5,5,5,5, -6,6,6,6, -7,7,7,7, -8,8,8,8, -9,9,9,9, -10,10,10,10, -11,11,11,11, -12,12,12,12, -13,13,13,13, -14,14,14,14, -15,15,15,15, -16,16,16,16, -17,17,17,17, -18,18,18,18, -19,19,19,19, -20,20,20,20, -21,21,21,21, -22,22,22,22, -23,23,23,23, -24,24,24,24, -25,25,25,25, -26,26,26, -25,25,25,25, -24,24,24,24, -23,23,23,23, -22,22,22,22, -21,21,21,21, -20,20,20,20, -19,19,19,19, -18,18,18,18, -17,17,17,17, -16,16,16,16, -15,15,15,15, -14,14,14,14, -13,13,13,13, -12,12,12,12, -11,11,11,11, -10,10,10,10, -9,9,9,9, -8,8,8,8, -7,7,7,7, -6,6,6,6, -5,5,5,5, -4,4,4,4, -3,3,3,3, -2,2,2,2, -1,1,1,1 -}; - -/* LFO Phase Modulation table (verified on real YM3812) */ -static const INT8 lfo_pm_table[8*8*2] = { - -/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ -0, 0, 0, 0, 0, 0, 0, 0,	/*LFO PM depth = 0*/ -0, 0, 0, 0, 0, 0, 0, 0,	/*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */ -0, 0, 0, 0, 0, 0, 0, 0,	/*LFO PM depth = 0*/ -1, 0, 0, 0,-1, 0, 0, 0,	/*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */ -1, 0, 0, 0,-1, 0, 0, 0,	/*LFO PM depth = 0*/ -2, 1, 0,-1,-2,-1, 0, 1,	/*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */ -1, 0, 0, 0,-1, 0, 0, 0,	/*LFO PM depth = 0*/ -3, 1, 0,-1,-3,-1, 0, 1,	/*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */ -2, 1, 0,-1,-2,-1, 0, 1,	/*LFO PM depth = 0*/ -4, 2, 0,-2,-4,-2, 0, 2,	/*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */ -2, 1, 0,-1,-2,-1, 0, 1,	/*LFO PM depth = 0*/ -5, 2, 0,-2,-5,-2, 0, 2,	/*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */ -3, 1, 0,-1,-3,-1, 0, 1,	/*LFO PM depth = 0*/ -6, 3, 0,-3,-6,-3, 0, 3,	/*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */ -3, 1, 0,-1,-3,-1, 0, 1,	/*LFO PM depth = 0*/ -7, 3, 0,-3,-7,-3, 0, 3	/*LFO PM depth = 1*/ -}; +/* dummy attack / decay rate ( when rate == 0 ) */ +static int RATE_0[16]= +{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +/* -------------------- static state --------------------- */  /* lock level of common table */  static int num_lock = 0;  /* work table */  static void *cur_chip = NULL;	/* current chip point */ -OPL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2; +/* currenct chip state */ +/* static OPLSAMPLE  *bufL,*bufR; */ +static OPL_CH *S_CH; +static OPL_CH *E_CH; +OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2; + +static int outd[1]; +static int ams; +static int vib; +int *ams_table; +int *vib_table; +static int amsIncr; +static int vibIncr; +static int feedback2;		/* connect for SLOT 2 */ + +/* --------------------- rebuild tables ------------------- */ + +#define SC_KSL(mydb) ((uint) (mydb / (EG_STEP / 2))) +#define SC_SL(db) (int)(db * ((3 / EG_STEP) * (1 << ENV_BITS))) + EG_DST + +void OPLBuildTables(int ENV_BITS_PARAM, int EG_ENT_PARAM) { +	int i; -static signed int phase_modulation;		/* phase modulation input (SLOT 2) */ -static signed int output[1]; +	ENV_BITS = ENV_BITS_PARAM; +	EG_ENT = EG_ENT_PARAM; +	EG_OFF = ((2 * EG_ENT)<<ENV_BITS);  /* OFF          */ +	EG_DED = EG_OFF; +	EG_DST = (EG_ENT << ENV_BITS);     /* DECAY  START */ +	EG_AED = EG_DST; +	//EG_STEP = (96.0/EG_ENT); -#if BUILD_Y8950 -static INT32 output_deltat[4];		/* for Y8950 DELTA-T */ -#endif +	for (i = 0; i < (int)(sizeof(KSL_TABLE_SEED) / sizeof(double)); i++) +		KSL_TABLE[i] = SC_KSL(KSL_TABLE_SEED[i]); -static UINT32	LFO_AM; -static INT32	LFO_PM; +	for (i = 0; i < (int)(sizeof(SL_TABLE_SEED) / sizeof(uint)); i++) +		SL_TABLE[i] = SC_SL(SL_TABLE_SEED[i]); +} +#undef SC_KSL +#undef SC_SL +/* --------------------- subroutines  --------------------- */ -INLINE int limit( int val, int max, int min ) { +inline int Limit(int val, int max, int min) {  	if ( val > max )  		val = max;  	else if ( val < min ) @@ -617,32 +248,26 @@ INLINE int limit( int val, int max, int min ) {  	return val;  } -  /* status set and IRQ handling */ -INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) -{ +inline void OPL_STATUS_SET(FM_OPL *OPL, int flag) {  	/* set status flag */  	OPL->status |= flag; -	if(!(OPL->status & 0x80)) -	{ -		if(OPL->status & OPL->statusmask) -		{	/* IRQ on */ +	if(!(OPL->status & 0x80)) { +		if(OPL->status & OPL->statusmask) {	/* IRQ on */  			OPL->status |= 0x80;  			/* callback user interrupt handler (IRQ is OFF to ON) */ -			if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); +			if(OPL->IRQHandler) +				(OPL->IRQHandler)(OPL->IRQParam,1);  		}  	}  }  /* status reset and IRQ handling */ -INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) -{ +inline void OPL_STATUS_RESET(FM_OPL *OPL, int flag) {  	/* reset status flag */ -	OPL->status &=~flag; -	if((OPL->status & 0x80)) -	{ -		if (!(OPL->status & OPL->statusmask) ) -		{ +	OPL->status &= ~flag; +	if((OPL->status & 0x80)) { +		if (!(OPL->status & OPL->statusmask)) {  			OPL->status &= 0x7f;  			/* callback user interrupt handler (IRQ is ON to OFF) */  			if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); @@ -651,1182 +276,771 @@ INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag)  }  /* IRQ mask set */ -INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) -{ +inline void OPL_STATUSMASK_SET(FM_OPL *OPL, int flag) {  	OPL->statusmask = flag;  	/* IRQ handling check */  	OPL_STATUS_SET(OPL,0);  	OPL_STATUS_RESET(OPL,0);  } - -/* advance LFO to next sample */ -INLINE void advance_lfo(FM_OPL *OPL) -{ -	UINT8 tmp; - -	/* LFO */ -	OPL->lfo_am_cnt += OPL->lfo_am_inc; -	if (OPL->lfo_am_cnt >= (UINT32)(LFO_AM_TAB_ELEMENTS<<LFO_SH) )	/* lfo_am_table is 210 elements long */ -		OPL->lfo_am_cnt -= (UINT32)(LFO_AM_TAB_ELEMENTS<<LFO_SH); - -	tmp = lfo_am_table[ OPL->lfo_am_cnt >> LFO_SH ]; - -	if (OPL->lfo_am_depth) -		LFO_AM = tmp; -	else -		LFO_AM = tmp>>2; - -	OPL->lfo_pm_cnt += OPL->lfo_pm_inc; -	LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; +/* ----- key on  ----- */ +inline void OPL_KEYON(OPL_SLOT *SLOT) { +	/* sin wave restart */ +	SLOT->Cnt = 0; +	/* set attack */ +	SLOT->evm = ENV_MOD_AR; +	SLOT->evs = SLOT->evsa; +	SLOT->evc = EG_AST; +	SLOT->eve = EG_AED; +} +/* ----- key off ----- */ +inline void OPL_KEYOFF(OPL_SLOT *SLOT) { +	if( SLOT->evm > ENV_MOD_RR) { +		/* set envelope counter from envleope output */ +		SLOT->evm = ENV_MOD_RR; +		if( !(SLOT->evc & EG_DST) ) +			//SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST; +			SLOT->evc = EG_DST; +		SLOT->eve = EG_DED; +		SLOT->evs = SLOT->evsr; +	}  } -/* advance to next sample */ -INLINE void advancex(FM_OPL *OPL) -{ -	OPL_CH *CH; -	OPL_SLOT *op; -	int i; - -	OPL->eg_timer += OPL->eg_timer_add; - -	while (OPL->eg_timer >= OPL->eg_timer_overflow) -	{ -		OPL->eg_timer -= OPL->eg_timer_overflow; - -		OPL->eg_cnt++; - -		for (i=0; i<9*2; i++) -		{ -			CH  = &OPL->P_CH[i/2]; -			op  = &CH->SLOT[i&1]; - -			/* Envelope Generator */ -			switch(op->state) -			{ -			case EG_ATT:		/* attack phase */ -			{ - -				if ( !(OPL->eg_cnt & ((1<<op->eg_sh_ar)-1) ) ) -				{ -					op->volume += (~op->volume * -	                        		           (eg_inc[op->eg_sel_ar + ((OPL->eg_cnt>>op->eg_sh_ar)&7)]) -        			                          ) >>3; - -					if (op->volume <= MIN_ATT_INDEX) -					{ -						op->volume = MIN_ATT_INDEX; -						op->state = EG_DEC; -					} - -				} - -			} -			break; - -			case EG_DEC:	/* decay phase */ -				if ( !(OPL->eg_cnt & ((1<<op->eg_sh_dr)-1) ) ) -				{ -					op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; - -					if ( op->volume >= (INT32)op->sl ) -						op->state = EG_SUS; - -				} +/* ---------- calcrate Envelope Generator & Phase Generator ---------- */ +/* return : envelope output */ +inline uint OPL_CALC_SLOT(OPL_SLOT *SLOT) { +	/* calcrate envelope generator */ +	if((SLOT->evc += SLOT->evs) >= SLOT->eve) { +		switch( SLOT->evm ){ +		case ENV_MOD_AR: /* ATTACK -> DECAY1 */ +			/* next DR */ +			SLOT->evm = ENV_MOD_DR; +			SLOT->evc = EG_DST; +			SLOT->eve = SLOT->SL; +			SLOT->evs = SLOT->evsd;  			break; - -			case EG_SUS:	/* sustain phase */ - -				/* this is important behaviour: -				one can change percusive/non-percussive modes on the fly and -				the chip will remain in sustain phase - verified on real YM3812 */ - -				if(op->eg_type)		/* non-percussive mode */ -				{ -									/* do nothing */ -				} -				else				/* percussive mode */ -				{ -					/* during sustain phase chip adds Release Rate (in percussive mode) */ -					if ( !(OPL->eg_cnt & ((1<<op->eg_sh_rr)-1) ) ) -					{ -						op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; - -						if ( op->volume >= MAX_ATT_INDEX ) -							op->volume = MAX_ATT_INDEX; -					} -					/* else do nothing in sustain phase */ -				} -			break; - -			case EG_REL:	/* release phase */ -				if ( !(OPL->eg_cnt & ((1<<op->eg_sh_rr)-1) ) ) -				{ -					op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; - -					if ( op->volume >= MAX_ATT_INDEX ) -					{ -						op->volume = MAX_ATT_INDEX; -						op->state = EG_OFF; -					} - -				} +		case ENV_MOD_DR: /* DECAY -> SL or RR */ +			SLOT->evc = SLOT->SL; +			SLOT->eve = EG_DED; +			if(SLOT->eg_typ) { +				SLOT->evs = 0; +			} else { +				SLOT->evm = ENV_MOD_RR; +				SLOT->evs = SLOT->evsr; +			}  			break; - -			default: +		case ENV_MOD_RR: /* RR -> OFF */ +			SLOT->evc = EG_OFF; +			SLOT->eve = EG_OFF + 1; +			SLOT->evs = 0;  			break; -			}  		}  	} +	/* calcrate envelope */ +	return SLOT->TLL + ENV_CURVE[SLOT->evc>>ENV_BITS] + (SLOT->ams ? ams : 0); +} -	for (i=0; i<9*2; i++) -	{ -		CH  = &OPL->P_CH[i/2]; -		op  = &CH->SLOT[i&1]; - -		/* Phase Generator */ -		if(op->vib) -		{ -			UINT8 block; -			UINT32 block_fnum = CH->block_fnum; - -			unsigned int fnum_lfo   = (block_fnum&0x0380) >> 7; +/* set algorythm connection */ +static void set_algorythm(OPL_CH *CH) { +	int *carrier = &outd[0]; +	CH->connect1 = CH->CON ? carrier : &feedback2; +	CH->connect2 = carrier; +} -			signed int lfo_fn_table_index_offset = lfo_pm_table[LFO_PM + 16*fnum_lfo ]; +/* ---------- frequency counter for operater update ---------- */ +inline void CALC_FCSLOT(OPL_CH *CH, OPL_SLOT *SLOT) { +	int ksr; -			if (lfo_fn_table_index_offset)	/* LFO phase modulation active */ -			{ -				block_fnum += lfo_fn_table_index_offset; -				block = (block_fnum&0x1c00) >> 10; -				op->Cnt += (OPL->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul;//ok -			} -			else	/* LFO phase modulation  = zero */ -			{ -				op->Cnt += op->Incr; -			} -		} -		else	/* LFO phase modulation disabled for this operator */ -		{ -			op->Cnt += op->Incr; -		} -	} +	/* frequency step counter */ +	SLOT->Incr = CH->fc * SLOT->mul; +	ksr = CH->kcode >> SLOT->KSR; -	/*	The Noise Generator of the YM3812 is 23-bit shift register. -	*	Period is equal to 2^23-2 samples. -	*	Register works at sampling frequency of the chip, so output -	*	can change on every sample. -	* -	*	Output of the register and input to the bit 22 is: -	*	bit0 XOR bit14 XOR bit15 XOR bit22 -	* -	*	Simply use bit 22 as the noise output. -	*/ - -	OPL->noise_p += OPL->noise_f; -	i = OPL->noise_p >> FREQ_SH;		/* number of events (shifts of the shift register) */ -	OPL->noise_p &= FREQ_MASK; -	while (i) +	if( SLOT->ksr != ksr )  	{ -		/* -		UINT32 j; -		j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1; -		OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1); -		*/ - -		/* -			Instead of doing all the logic operations above, we -			use a trick here (and use bit 0 as the noise output). -			The difference is only that the noise bit changes one -			step ahead. This doesn't matter since we don't know -			what is real state of the noise_rng after the reset. -		*/ - -		if (OPL->noise_rng & 1) OPL->noise_rng ^= 0x800302; -		OPL->noise_rng >>= 1; - -		i--; +		SLOT->ksr = ksr; +		/* attack , decay rate recalcration */ +		SLOT->evsa = SLOT->AR[ksr]; +		SLOT->evsd = SLOT->DR[ksr]; +		SLOT->evsr = SLOT->RR[ksr];  	} +	SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);  } +/* set multi,am,vib,EG-TYP,KSR,mul */ +inline void set_mul(FM_OPL *OPL, int slot, int v) { +	OPL_CH   *CH   = &OPL->P_CH[slot / 2]; +	OPL_SLOT *SLOT = &CH->SLOT[slot & 1]; -INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ -	UINT32 p; - -	p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; - -	if (p >= TL_TAB_LEN) -		return 0; -	return tl_tab[p]; +	SLOT->mul    = MUL_TABLE[v & 0x0f]; +	SLOT->KSR    = (v & 0x10) ? 0 : 2; +	SLOT->eg_typ = (v & 0x20) >> 5; +	SLOT->vib    = (v & 0x40); +	SLOT->ams    = (v & 0x80); +	CALC_FCSLOT(CH, SLOT);  } -INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ -	UINT32 p; -	INT32  i; +/* set ksl & tl */ +inline void set_ksl_tl(FM_OPL *OPL, int slot, int v) { +	OPL_CH   *CH   = &OPL->P_CH[slot / 2]; +	OPL_SLOT *SLOT = &CH->SLOT[slot & 1]; +	int ksl = v >> 6; /* 0 / 1.5 / 3 / 6 db/OCT */ -	i = (phase & ~FREQ_MASK) + pm; +	SLOT->ksl = ksl ? 3-ksl : 31; +	SLOT->TL  = (int)((v & 0x3f) * (0.75 / EG_STEP)); /* 0.75db step */ -/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, phase>>FREQ_SH, pm);*/ +	if(!(OPL->mode & 0x80)) {	/* not CSM latch total level */ +		SLOT->TLL = SLOT->TL + (CH->ksl_base >> SLOT->ksl); +	} +} -	p = (env<<4) + sin_tab[ wave_tab + ((i>>FREQ_SH) & SIN_MASK)]; +/* set attack rate & decay rate  */ +inline void set_ar_dr(FM_OPL *OPL, int slot, int v) { +	OPL_CH   *CH   = &OPL->P_CH[slot / 2]; +	OPL_SLOT *SLOT = &CH->SLOT[slot & 1]; +	int ar = v >> 4; +	int dr = v & 0x0f; -/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/ +	SLOT->AR = ar ? &OPL->AR_TABLE[ar << 2] : RATE_0; +	SLOT->evsa = SLOT->AR[SLOT->ksr]; +	if(SLOT->evm == ENV_MOD_AR) +		SLOT->evs = SLOT->evsa; -	if (p >= TL_TAB_LEN) -		return 0; -	return tl_tab[p]; +	SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0; +	SLOT->evsd = SLOT->DR[SLOT->ksr]; +	if(SLOT->evm == ENV_MOD_DR) +		SLOT->evs = SLOT->evsd;  } - -#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask)) - -/* calculate output */ -INLINE void OPL_CALC_CH( OPL_CH *CH ) -{ +/* set sustain level & release rate */ +inline void set_sl_rr(FM_OPL *OPL, int slot, int v) { +	OPL_CH   *CH   = &OPL->P_CH[slot / 2]; +	OPL_SLOT *SLOT = &CH->SLOT[slot & 1]; +	int sl = v >> 4; +	int rr = v & 0x0f; + +	SLOT->SL = SL_TABLE[sl]; +	if(SLOT->evm == ENV_MOD_DR) +		SLOT->eve = SLOT->SL; +	SLOT->RR = &OPL->DR_TABLE[rr<<2]; +	SLOT->evsr = SLOT->RR[SLOT->ksr]; +	if(SLOT->evm == ENV_MOD_RR) +		SLOT->evs = SLOT->evsr; +} + +/* operator output calcrator */ +#define OP_OUT(slot,env,con)   slot->wavetable[((slot->Cnt + con) / (0x1000000 / SIN_ENT)) & (SIN_ENT-1)][env] +/* ---------- calcrate one of channel ---------- */ +inline void OPL_CALC_CH(OPL_CH *CH) { +	uint env_out;  	OPL_SLOT *SLOT; -	unsigned int env; -	signed int out; - -	phase_modulation = 0; +	feedback2 = 0;  	/* SLOT 1 */  	SLOT = &CH->SLOT[SLOT1]; -	env  = volume_calc(SLOT); -	out  = SLOT->op1_out[0] + SLOT->op1_out[1]; -	SLOT->op1_out[0] = SLOT->op1_out[1]; -	*SLOT->connect1 += SLOT->op1_out[0]; -	SLOT->op1_out[1] = 0; -	if( env < ENV_QUIET ) -	{ -		if (!SLOT->FB) -			out = 0; -		SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<<SLOT->FB), SLOT->wavetable ); +	env_out=OPL_CALC_SLOT(SLOT); +	if(env_out < (uint)(EG_ENT - 1)) { +		/* PG */ +		if(SLOT->vib)  +			SLOT->Cnt += (SLOT->Incr * vib / VIB_RATE); +		else +			SLOT->Cnt += SLOT->Incr; +		/* connectoion */ +		if(CH->FB) { +			int feedback1 = (CH->op1_out[0] + CH->op1_out[1]) >> CH->FB; +			CH->op1_out[1] = CH->op1_out[0]; +			*CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT, env_out, feedback1); +		} +		else 		{ +			*CH->connect1 += OP_OUT(SLOT, env_out, 0); +		} +	}else { +		CH->op1_out[1] = CH->op1_out[0]; +		CH->op1_out[0] = 0;  	} -  	/* SLOT 2 */ -	SLOT++; -	env = volume_calc(SLOT); -	if( env < ENV_QUIET ) -		output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable); +	SLOT = &CH->SLOT[SLOT2]; +	env_out=OPL_CALC_SLOT(SLOT); +	if(env_out < (uint)(EG_ENT - 1)) { +		/* PG */ +		if(SLOT->vib) +			SLOT->Cnt += (SLOT->Incr * vib / VIB_RATE); +		else +			SLOT->Cnt += SLOT->Incr; +		/* connectoion */ +		outd[0] += OP_OUT(SLOT, env_out, feedback2); +	}  } -/* -	operators used in the rhythm sounds generation process: - -	Envelope Generator: - -channel  operator  register number   Bass  High  Snare Tom  Top -/ slot   number    TL ARDR SLRR Wave Drum  Hat   Drum  Tom  Cymbal - 6 / 0   12        50  70   90   f0  + - 6 / 1   15        53  73   93   f3  + - 7 / 0   13        51  71   91   f1        + - 7 / 1   16        54  74   94   f4              + - 8 / 0   14        52  72   92   f2                    + - 8 / 1   17        55  75   95   f5                          + +/* ---------- calcrate rythm block ---------- */ +#define WHITE_NOISE_db 6.0 +inline void OPL_CALC_RH(OPL_CH *CH) { +	uint env_tam, env_sd, env_top, env_hh; +	int whitenoise = int((rand()&1) * (WHITE_NOISE_db / EG_STEP)); +	int tone8; -	Phase Generator: - -channel  operator  register number   Bass  High  Snare Tom  Top -/ slot   number    MULTIPLE          Drum  Hat   Drum  Tom  Cymbal - 6 / 0   12        30                + - 6 / 1   15        33                + - 7 / 0   13        31                      +     +           + - 7 / 1   16        34                -----  n o t  u s e d ----- - 8 / 0   14        32                                  + - 8 / 1   17        35                      +                 + - -channel  operator  register number   Bass  High  Snare Tom  Top -number   number    BLK/FNUM2 FNUM    Drum  Hat   Drum  Tom  Cymbal -   6     12,15     B6        A6      + - -   7     13,16     B7        A7            +     +           + - -   8     14,17     B8        A8            +           +     + - -*/ - -/* calculate rhythm */ - -INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) -{  	OPL_SLOT *SLOT; -	signed int out; -	unsigned int env; - +	int env_out; -	/* Bass Drum (verified on real YM3812): -	  - depends on the channel 6 'connect' register: -	      when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) -	      when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored -	  - output sample always is multiplied by 2 -	*/ - -	phase_modulation = 0; +	/* BD : same as FM serial mode and output level is large */ +	feedback2 = 0;  	/* SLOT 1 */  	SLOT = &CH[6].SLOT[SLOT1]; -	env = volume_calc(SLOT); - -	out = SLOT->op1_out[0] + SLOT->op1_out[1]; -	SLOT->op1_out[0] = SLOT->op1_out[1]; - -	if (!SLOT->CON) -		phase_modulation = SLOT->op1_out[0]; -	//else ignore output of operator 1 - -	SLOT->op1_out[1] = 0; -	if( env < ENV_QUIET ) -	{ -		if (!SLOT->FB) -			out = 0; -		SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<<SLOT->FB), SLOT->wavetable ); +	env_out = OPL_CALC_SLOT(SLOT); +	if(env_out < EG_ENT-1) { +		/* PG */ +		if(SLOT->vib) +			SLOT->Cnt += (SLOT->Incr * vib / VIB_RATE); +		else +			SLOT->Cnt += SLOT->Incr; +		/* connectoion */ +		if(CH[6].FB) { +			int feedback1 = (CH[6].op1_out[0] + CH[6].op1_out[1]) >> CH[6].FB; +			CH[6].op1_out[1] = CH[6].op1_out[0]; +			feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT, env_out, feedback1); +		} +		else { +			feedback2 = OP_OUT(SLOT, env_out, 0); +		} +	}else { +		feedback2 = 0; +		CH[6].op1_out[1] = CH[6].op1_out[0]; +		CH[6].op1_out[0] = 0;  	} -  	/* SLOT 2 */ -	SLOT++; -	env = volume_calc(SLOT); -	if( env < ENV_QUIET ) -		output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable) * 2; - - -	/* Phase generation is based on: */ -	// HH  (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) -	// SD  (16) channel 7->slot 1 -	// TOM (14) channel 8->slot 1 -	// TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) - -	/* Envelope generation based on: */ -	// HH  channel 7->slot1 -	// SD  channel 7->slot2 -	// TOM channel 8->slot1 -	// TOP channel 8->slot2 - - -	/* The following formulas can be well optimized. -	   I leave them in direct form for now (in case I've missed something). -	*/ - -	/* High Hat (verified on real YM3812) */ -	env = volume_calc(SLOT7_1); -	if( env < ENV_QUIET ) -	{ - -		/* high hat phase generation: -			phase = d0 or 234 (based on frequency only) -			phase = 34 or 2d0 (based on noise) -		*/ - -		/* base frequency derived from operator 1 in channel 7 */ -		unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; -		unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; -		unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; - -		unsigned char res1 = (bit2 ^ bit7) | bit3; - -		/* when res1 = 0 phase = 0x000 | 0xd0; */ -		/* when res1 = 1 phase = 0x200 | (0xd0>>2); */ -		UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; - -		/* enable gate based on frequency of operator 2 in channel 8 */ -		unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; -		unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; - -		unsigned char res2 = (bit3e ^ bit5e); - -		/* when res2 = 0 pass the phase from calculation above (res1); */ -		/* when res2 = 1 phase = 0x200 | (0xd0>>2); */ -		if (res2) -			phase = (0x200|(0xd0>>2)); - - -		/* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ -		/* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ -		if (phase&0x200) -		{ -			if (noise) -				phase = 0x200|0xd0; -		} +	SLOT = &CH[6].SLOT[SLOT2]; +	env_out = OPL_CALC_SLOT(SLOT); +	if(env_out < EG_ENT-1) { +		/* PG */ +		if(SLOT->vib) +			SLOT->Cnt += (SLOT->Incr * vib / VIB_RATE);  		else -		/* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ -		/* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ -		{ -			if (noise) -				phase = 0xd0>>2; -		} - -		output[0] += op_calc(phase<<FREQ_SH, env, 0, SLOT7_1->wavetable) * 2; +			SLOT->Cnt += SLOT->Incr; +		/* connectoion */ +		outd[0] += OP_OUT(SLOT, env_out, feedback2) * 2;  	} -	/* Snare Drum (verified on real YM3812) */ -	env = volume_calc(SLOT7_2); -	if( env < ENV_QUIET ) -	{ -		/* base frequency derived from operator 1 in channel 7 */ -		unsigned char bit8 = ((SLOT7_1->Cnt>>FREQ_SH)>>8)&1; - -		/* when bit8 = 0 phase = 0x100; */ -		/* when bit8 = 1 phase = 0x200; */ -		UINT32 phase = bit8 ? 0x200 : 0x100; - -		/* Noise bit XOR'es phase by 0x100 */ -		/* when noisebit = 0 pass the phase from calculation above */ -		/* when noisebit = 1 phase ^= 0x100; */ -		/* in other words: phase ^= (noisebit<<8); */ -		if (noise) -			phase ^= 0x100; - -		output[0] += op_calc(phase<<FREQ_SH, env, 0, SLOT7_1->wavetable) * 2; +	// SD  (17) = mul14[fnum7] + white noise +	// TAM (15) = mul15[fnum8] +	// TOP (18) = fnum6(mul18[fnum8]+whitenoise) +	// HH  (14) = fnum7(mul18[fnum8]+whitenoise) + white noise +	env_sd = OPL_CALC_SLOT(SLOT7_2) + whitenoise; +	env_tam =OPL_CALC_SLOT(SLOT8_1); +	env_top = OPL_CALC_SLOT(SLOT8_2); +	env_hh = OPL_CALC_SLOT(SLOT7_1) + whitenoise; + +	/* PG */ +	if(SLOT7_1->vib) +		SLOT7_1->Cnt += (2 * SLOT7_1->Incr * vib / VIB_RATE); +	else +		SLOT7_1->Cnt += 2 * SLOT7_1->Incr; +	if(SLOT7_2->vib) +		SLOT7_2->Cnt += ((CH[7].fc * 8) * vib / VIB_RATE); +	else +		SLOT7_2->Cnt += (CH[7].fc * 8); +	if(SLOT8_1->vib) +		SLOT8_1->Cnt += (SLOT8_1->Incr * vib / VIB_RATE); +	else +		SLOT8_1->Cnt += SLOT8_1->Incr; +	if(SLOT8_2->vib) +		SLOT8_2->Cnt += ((CH[8].fc * 48) * vib / VIB_RATE); +	else +		SLOT8_2->Cnt += (CH[8].fc * 48); + +	tone8 = OP_OUT(SLOT8_2,whitenoise,0 ); + +	/* SD */ +	if(env_sd < (uint)(EG_ENT - 1)) +		outd[0] += OP_OUT(SLOT7_1, env_sd, 0) * 8; +	/* TAM */ +	if(env_tam < (uint)(EG_ENT - 1)) +		outd[0] += OP_OUT(SLOT8_1, env_tam, 0) * 2; +	/* TOP-CY */ +	if(env_top < (uint)(EG_ENT - 1)) +		outd[0] += OP_OUT(SLOT7_2, env_top, tone8) * 2; +	/* HH */ +	if(env_hh  < (uint)(EG_ENT-1)) +		outd[0] += OP_OUT(SLOT7_2, env_hh, tone8) * 2; +} + +/* ----------- initialize time tabls ----------- */ +static void init_timetables(FM_OPL *OPL, int ARRATE, int DRRATE) { +	int i; +	double rate; + +	/* make attack rate & decay rate tables */ +	for (i = 0; i < 4; i++) +		OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0; +	for (i = 4; i <= 60; i++){ +		rate = OPL->freqbase;						/* frequency rate */ +		if(i < 60)  +			rate *= 1.0 + (i & 3) * 0.25;		/* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ +		rate *= 1 << ((i >> 2) - 1);						/* b2-5 : shift bit */ +		rate *= (double)(EG_ENT << ENV_BITS); +		OPL->AR_TABLE[i] = (int)(rate / ARRATE); +		OPL->DR_TABLE[i] = (int)(rate / DRRATE);  	} - -	/* Tom Tom (verified on real YM3812) */ -	env = volume_calc(SLOT8_1); -	if( env < ENV_QUIET ) -		output[0] += op_calc(SLOT8_1->Cnt, env, 0, SLOT8_1->wavetable) * 2; - -	/* Top Cymbal (verified on real YM3812) */ -	env = volume_calc(SLOT8_2); -	if( env < ENV_QUIET ) -	{ -		/* base frequency derived from operator 1 in channel 7 */ -		unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; -		unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; -		unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; - -		unsigned char res1 = (bit2 ^ bit7) | bit3; - -		/* when res1 = 0 phase = 0x000 | 0x100; */ -		/* when res1 = 1 phase = 0x200 | 0x100; */ -		UINT32 phase = res1 ? 0x300 : 0x100; - -		/* enable gate based on frequency of operator 2 in channel 8 */ -		unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; -		unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; - -		unsigned char res2 = (bit3e ^ bit5e); -		/* when res2 = 0 pass the phase from calculation above (res1); */ -		/* when res2 = 1 phase = 0x200 | 0x100; */ -		if (res2) -			phase = 0x300; - -		output[0] += op_calc(phase<<FREQ_SH, env, 0, SLOT8_2->wavetable) * 2; +	for (i = 60; i < 75; i++) { +		OPL->AR_TABLE[i] = EG_AED-1; +		OPL->DR_TABLE[i] = OPL->DR_TABLE[60];  	} -  } +/* ---------- generic table initialize ---------- */ +static int OPLOpenTable(void) { +	int s,t; +	double rate; +	int i,j; +	double pom; -/* generic table initialize */ -static int init_tables(void) -{ -	signed int i,x; -	signed int n; -	double o,m; - - -	for (x=0; x<TL_RES_LEN; x++) -	{ -		m = (1<<16) / pow(2.0, (x+1) * (ENV_STEP/4.0) / 8.0); -		m = floor(m); - -		/* we never reach (1<<16) here due to the (x+1) */ -		/* result fits within 16 bits at maximum */ - -		n = (int)m;		/* 16 bits here */ -		n >>= 4;		/* 12 bits here */ -		if (n&1)		/* round to nearest */ -			n = (n>>1)+1; -		else -			n = n>>1; -						/* 11 bits here (rounded) */ -		n <<= 1;		/* 12 bits here (as in real chip) */ -		tl_tab[ x*2 + 0 ] = n; -		tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; - -		for (i=1; i<12; i++) -		{ -			tl_tab[ x*2+0 + i*2*TL_RES_LEN ] =  tl_tab[ x*2+0 ]>>i; -			tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; -		} -	#if 0 -			logerror("tl %04i", x*2); -			for (i=0; i<12; i++) -				logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); -			logerror("\n"); -	#endif +	/* allocate dynamic tables */ +	if((TL_TABLE = (int *)malloc(TL_MAX * 2 * sizeof(int))) == NULL) +		return 0; +	if((SIN_TABLE = (int **)malloc(SIN_ENT * 4 * sizeof(int *))) == NULL) { +		free(TL_TABLE); +		return 0;  	} -	/*logerror("FMOPL.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ - - -	for (i=0; i<SIN_LEN; i++) -	{ -		/* non-standard sinus */ -		m = sin( ((i*2)+1) * PI / SIN_LEN ); /* checked against the real chip */ - -		/* we never reach zero here due to ((i*2)+1) */ - -		if (m>0.0) -			o = 8*log(1.0/m)/log(2.0);	/* convert to 'decibels' */ -		else -			o = 8*log(-1.0/m)/log(2.0);	/* convert to 'decibels' */ - -		o = o / (ENV_STEP/4); - -		n = (int)(2.0*o); -		if (n&1)						/* round to nearest */ -			n = (n>>1)+1; -		else -			n = n>>1; - -		sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); - -		/*logerror("FMOPL.C: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ +	if((AMS_TABLE = (int *)malloc(AMS_ENT * 2 * sizeof(int))) == NULL) { +		free(TL_TABLE); +		free(SIN_TABLE); +		return 0;  	} - -	for (i=0; i<SIN_LEN; i++) -	{ -		/* waveform 1:  __      __     */ -		/*             /  \____/  \____*/ -		/* output only first half of the sinus waveform (positive one) */ - -		if (i & (1<<(SIN_BITS-1)) ) -			sin_tab[1*SIN_LEN+i] = TL_TAB_LEN; -		else -			sin_tab[1*SIN_LEN+i] = sin_tab[i]; - -		/* waveform 2:  __  __  __  __ */ -		/*             /  \/  \/  \/  \*/ -		/* abs(sin) */ - -		sin_tab[2*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>1) ]; - -		/* waveform 3:  _   _   _   _  */ -		/*             / |_/ |_/ |_/ |_*/ -		/* abs(output only first quarter of the sinus waveform) */ - -		if (i & (1<<(SIN_BITS-2)) ) -			sin_tab[3*SIN_LEN+i] = TL_TAB_LEN; -		else -			sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)]; - -		/*logerror("FMOPL.C: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] ); -		logerror("FMOPL.C: sin2[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[2*SIN_LEN+i], tl_tab[sin_tab[2*SIN_LEN+i]] ); -		logerror("FMOPL.C: sin3[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[3*SIN_LEN+i], tl_tab[sin_tab[3*SIN_LEN+i]] );*/ +	if((VIB_TABLE = (int *)malloc(VIB_ENT * 2 * sizeof(int))) == NULL) { +		free(TL_TABLE); +		free(SIN_TABLE); +		free(AMS_TABLE); +		return 0;  	} -	/*logerror("FMOPL.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/ - - -#ifdef SAVE_SAMPLE -	sample[0]=fopen("sampsum.pcm","wb"); -#endif - -	return 1; -} - -static void OPLCloseTable( void ) -{ -#ifdef SAVE_SAMPLE -	fclose(sample[0]); -#endif -} - - - -static void OPL_initalize(FM_OPL *OPL) -{ -	int i; - -	/* frequency base */ -#if 1 -	OPL->freqbase  = (OPL->rate) ? ((double)OPL->clock / 72.0) / OPL->rate  : 0; -#else -	OPL->rate = (double)OPL->clock / 72.0; -	OPL->freqbase  = 1.0; -#endif - -	/* Timer base time */ -	OPL->TimerBase = 1.0 / ((double)OPL->clock / 72.0 ); - -	/* make fnumber -> increment counter table */ -	for( i=0 ; i < 1024 ; i++ ) -	{ -		/* opn phase increment counter = 20bit */ -		OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ -#if 0 -		logerror("FMOPL.C: fn_tab[%4i] = %08x (dec=%8i)\n", -				 i, OPL->fn_tab[i]>>6, OPL->fn_tab[i]>>6 ); -#endif +	/* make total level table */ +	for (t = 0; t < EG_ENT - 1 ; t++){ +		rate = ((1 << TL_BITS) - 1) / pow(10, EG_STEP * t / 20);	/* dB -> voltage */ +		TL_TABLE[         t] =  (int)rate; +		TL_TABLE[TL_MAX + t] = -TL_TABLE[t]; +	} +	/* fill volume off area */ +	for (t = EG_ENT - 1; t < TL_MAX; t++){ +		TL_TABLE[t] = TL_TABLE[TL_MAX + t] = 0;  	} -#if 0 -	for( i=0 ; i < 16 ; i++ ) -	{ -		logerror("FMOPL.C: sl_tab[%i] = %08x\n", -			i, sl_tab[i] ); +	/* make sinwave table (total level offet) */ +	/* degree 0 = degree 180                   = off */ +	SIN_TABLE[0] = SIN_TABLE[SIN_ENT /2 ]         = &TL_TABLE[EG_ENT - 1]; +	for (s = 1;s <= SIN_ENT / 4; s++){ +		pom = sin(2 * PI * s / SIN_ENT); /* sin     */ +		pom = 20 * log10(1 / pom);	   /* decibel */ +		j = int(pom / EG_STEP);         /* TL_TABLE steps */ + +        /* degree 0   -  90    , degree 180 -  90 : plus section */ +		SIN_TABLE[          s] = SIN_TABLE[SIN_ENT / 2 - s] = &TL_TABLE[j]; +        /* degree 180 - 270    , degree 360 - 270 : minus section */ +		SIN_TABLE[SIN_ENT / 2 + s] = SIN_TABLE[SIN_ENT - s] = &TL_TABLE[TL_MAX + j];  	} -	for( i=0 ; i < 8 ; i++ ) -	{ -		int j; -		logerror("FMOPL.C: ksl_tab[oct=%2i] =",i); -		for (j=0; j<16; j++) -		{ -			logerror("%08x ", ksl_tab[i*16+j] ); -		} -		logerror("\n"); +	for (s = 0;s < SIN_ENT; s++) { +		SIN_TABLE[SIN_ENT * 1 + s] = s < (SIN_ENT / 2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT]; +		SIN_TABLE[SIN_ENT * 2 + s] = SIN_TABLE[s % (SIN_ENT / 2)]; +		SIN_TABLE[SIN_ENT * 3 + s] = (s / (SIN_ENT / 4)) & 1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT * 2 + s];  	} -#endif - - -	/* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ -	/* One entry from LFO_AM_TABLE lasts for 64 samples */ -	OPL->lfo_am_inc = (UINT32)((1.0 / 64.0 ) * (1<<LFO_SH) * OPL->freqbase); - -	/* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ -	OPL->lfo_pm_inc = (UINT32)((1.0 / 1024.0) * (1<<LFO_SH) * OPL->freqbase); -	/*logerror ("OPL->lfo_am_inc = %8x ; OPL->lfo_pm_inc = %8x\n", OPL->lfo_am_inc, OPL->lfo_pm_inc);*/ - -	/* Noise generator: a step takes 1 sample */ -	OPL->noise_f = (UINT32)((1.0 / 1.0) * (1<<FREQ_SH) * OPL->freqbase); - -	OPL->eg_timer_add  = (UINT32)((1<<EG_SH)  * OPL->freqbase); -	OPL->eg_timer_overflow = ( 1 ) * (1<<EG_SH); -	/*logerror("OPLinit eg_timer_add=%8x eg_timer_overflow=%8x\n", OPL->eg_timer_add, OPL->eg_timer_overflow);*/ - -} - -INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set) -{ -	if( !SLOT->key ) -	{ -		/* restart Phase Generator */ -		SLOT->Cnt = 0; -		/* phase -> Attack */ -		SLOT->state = EG_ATT; +	/* envelope counter -> envelope output table */ +	for (i=0; i < EG_ENT; i++) { +		/* ATTACK curve */ +		pom = pow(((double)(EG_ENT - 1 - i) / EG_ENT), 8) * EG_ENT; +		/* if( pom >= EG_ENT ) pom = EG_ENT-1; */ +		ENV_CURVE[i] = (int)pom; +		/* DECAY ,RELEASE curve */ +		ENV_CURVE[(EG_DST >> ENV_BITS) + i]= i;  	} -	SLOT->key |= key_set; -} - -INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr) -{ -	if( SLOT->key ) -	{ -		SLOT->key &= key_clr; - -		if( !SLOT->key ) -		{ -			/* phase -> Release */ -			if (SLOT->state>EG_REL) -				SLOT->state = EG_REL; -		} +	/* off */ +	ENV_CURVE[EG_OFF >> ENV_BITS]= EG_ENT - 1; +	/* make LFO ams table */ +	for (i=0; i < AMS_ENT; i++) { +		pom = (1.0 + sin(2 * PI * i / AMS_ENT)) / 2; /* sin */ +		AMS_TABLE[i]         = (int)((1.0 / EG_STEP) * pom); /* 1dB   */ +		AMS_TABLE[AMS_ENT + i] = (int)((4.8 / EG_STEP) * pom); /* 4.8dB */  	} -} - -/* update phase increment counter of operator (also update the EG rates if necessary) */ -INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) -{ -	int ksr; - -	/* (frequency) phase increment counter */ -	SLOT->Incr = CH->fc * SLOT->mul; -	ksr = CH->kcode >> SLOT->KSR; - -	if( SLOT->ksr != ksr ) -	{ -		SLOT->ksr = ksr; - -		/* calculate envelope generator rates */ -		if ((SLOT->ar + SLOT->ksr) < 16+62) -		{ -			SLOT->eg_sh_ar  = eg_rate_shift [SLOT->ar + SLOT->ksr ]; -			SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; -		} -		else -		{ -			SLOT->eg_sh_ar  = 0; -			SLOT->eg_sel_ar = 13*RATE_STEPS; -		} -		SLOT->eg_sh_dr  = eg_rate_shift [SLOT->dr + SLOT->ksr ]; -		SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; -		SLOT->eg_sh_rr  = eg_rate_shift [SLOT->rr + SLOT->ksr ]; -		SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; +	/* make LFO vibrate table */ +	for (i=0; i < VIB_ENT; i++) { +		/* 100cent = 1seminote = 6% ?? */ +		pom = (double)VIB_RATE * 0.06 * sin(2 * PI * i / VIB_ENT); /* +-100sect step */ +		VIB_TABLE[i]         = (int)(VIB_RATE + (pom * 0.07)); /* +- 7cent */ +		VIB_TABLE[VIB_ENT + i] = (int)(VIB_RATE + (pom * 0.14)); /* +-14cent */  	} +	return 1;  } -/* set multi,am,vib,EG-TYP,KSR,mul */ -INLINE void set_mul(FM_OPL *OPL,int slot,int v) -{ -	OPL_CH   *CH   = &OPL->P_CH[slot/2]; -	OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - -	SLOT->mul     = mul_tab[v&0x0f]; -	SLOT->KSR     = (v&0x10) ? 0 : 2; -	SLOT->eg_type = (v&0x20); -	SLOT->vib     = (v&0x40); -	SLOT->AMmask  = (v&0x80) ? ~0 : 0; -	CALC_FCSLOT(CH,SLOT); -} - -/* set ksl & tl */ -INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) -{ -	OPL_CH   *CH   = &OPL->P_CH[slot/2]; -	OPL_SLOT *SLOT = &CH->SLOT[slot&1]; -	int ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */ - -	SLOT->ksl = ksl ? 3-ksl : 31; -	SLOT->TL  = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ - -	SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); +static void OPLCloseTable(void) { +	free(TL_TABLE); +	free(SIN_TABLE); +	free(AMS_TABLE); +	free(VIB_TABLE);  } -/* set attack rate & decay rate  */ -INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) -{ -	OPL_CH   *CH   = &OPL->P_CH[slot/2]; -	OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - -	SLOT->ar = (v>>4)  ? 16 + ((v>>4)  <<2) : 0; +/* CSM Key Controll */ +inline void CSMKeyControll(OPL_CH *CH) { +	OPL_SLOT *slot1 = &CH->SLOT[SLOT1]; +	OPL_SLOT *slot2 = &CH->SLOT[SLOT2]; +	/* all key off */ +	OPL_KEYOFF(slot1); +	OPL_KEYOFF(slot2); +	/* total level latch */ +	slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); +	slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); +	/* key on */ +	CH->op1_out[0] = CH->op1_out[1] = 0; +	OPL_KEYON(slot1); +	OPL_KEYON(slot2); +} + +/* ---------- opl initialize ---------- */ +static void OPL_initalize(FM_OPL *OPL) { +	int fn; -	if ((SLOT->ar + SLOT->ksr) < 16+62) -	{ -		SLOT->eg_sh_ar  = eg_rate_shift [SLOT->ar + SLOT->ksr ]; -		SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; -	} -	else -	{ -		SLOT->eg_sh_ar  = 0; -		SLOT->eg_sel_ar = 13*RATE_STEPS; +	/* frequency base */ +	OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0; +	/* Timer base time */ +	OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 ); +	/* make time tables */ +	init_timetables(OPL, OPL_ARRATE, OPL_DRRATE); +	/* make fnumber -> increment counter table */ +	for( fn=0; fn < 1024; fn++) { +		OPL->FN_TABLE[fn] = (uint)(OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2);  	} - -	SLOT->dr    = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; -	SLOT->eg_sh_dr  = eg_rate_shift [SLOT->dr + SLOT->ksr ]; -	SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; +	/* LFO freq.table */ +	OPL->amsIncr = (int)(OPL->rate ? (double)AMS_ENT * (1 << AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0); +	OPL->vibIncr = (int)(OPL->rate ? (double)VIB_ENT * (1 << VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0);  } -/* set sustain level & release rate */ -INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) -{ -	OPL_CH   *CH   = &OPL->P_CH[slot/2]; -	OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - -	SLOT->sl  = sl_tab[ v>>4 ]; - -	SLOT->rr  = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; -	SLOT->eg_sh_rr  = eg_rate_shift [SLOT->rr + SLOT->ksr ]; -	SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; -} - - -/* write a value v to register r on OPL chip */ -static void OPLWriteReg(FM_OPL *OPL, int r, int v) -{ +/* ---------- write a OPL registers ---------- */ +void OPLWriteReg(FM_OPL *OPL, int r, int v) {  	OPL_CH *CH;  	int slot; -	UINT32 block_fnum; - - -	/* adjust bus to 8 bits */ -	r &= 0xff; -	v &= 0xff; - -#ifdef LOG_CYM_FILE -	if ((cymfile) && (r!=0) ) -	{ -		fputc( (unsigned char)r, cymfile ); -		fputc( (unsigned char)v, cymfile ); -	} -#endif - - -	switch(r&0xe0) -	{ -	case 0x00:	/* 00-1f:control */ -		switch(r&0x1f) -		{ -		case 0x01:	/* waveform select enable */ -			if(OPL->type&OPL_TYPE_WAVESEL) -			{ -				OPL->wavesel = v&0x20; -				/* do not change the waveform previously selected */ +	uint block_fnum; + +	switch(r & 0xe0) { +	case 0x00: /* 00-1f:controll */ +		switch(r & 0x1f) { +		case 0x01: +			/* wave selector enable */ +			if(OPL->type&OPL_TYPE_WAVESEL) { +				OPL->wavesel = v & 0x20; +				if(!OPL->wavesel) { +					/* preset compatible mode */ +					int c; +					for(c=0; c<OPL->max_ch; c++) { +						OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0]; +						OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0]; +					} +				}  			} -			break; +			return;  		case 0x02:	/* Timer 1 */ -			OPL->T[0] = (256-v)*4; +			OPL->T[0] = (256-v) * 4;  			break;  		case 0x03:	/* Timer 2 */ -			OPL->T[1] = (256-v)*16; -			break; +			OPL->T[1] = (256-v) * 16; +			return;  		case 0x04:	/* IRQ clear / mask and Timer enable */ -			if(v&0x80) -			{	/* IRQ flag clear */ -				OPL_STATUS_RESET(OPL,0x7f); +			if(v & 0x80) {	/* IRQ flag clear */ +				OPL_STATUS_RESET(OPL, 0x7f);  			} -			else -			{	/* set IRQ mask ,timer enable*/ -				UINT8 st1 = v&1; -				UINT8 st2 = (v>>1)&1; +			else {	/* set IRQ mask ,timer enable*/ +				uint8 st1 = v & 1; +				uint8 st2 = (v >> 1) & 1;  				/* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ -				OPL_STATUS_RESET(OPL,v&0x78); -				OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01); +				OPL_STATUS_RESET(OPL, v & 0x78); +				OPL_STATUSMASK_SET(OPL,((~v) & 0x78) | 0x01);  				/* timer 2 */ -				if(OPL->st[1] != st2) -				{ -					double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0; +				if(OPL->st[1] != st2) { +					double interval = st2 ? (double)OPL->T[1] * OPL->TimerBase : 0.0;  					OPL->st[1] = st2; -					if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); +					if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam + 1, interval);  				}  				/* timer 1 */ -				if(OPL->st[0] != st1) -				{ -					double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0; +				if(OPL->st[0] != st1) { +					double interval = st1 ? (double)OPL->T[0] * OPL->TimerBase : 0.0;  					OPL->st[0] = st1; -					if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); +					if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam + 0, interval);  				}  			} -			break; -#if BUILD_Y8950 -		case 0x06:		/* Key Board OUT */ -			if(OPL->type&OPL_TYPE_KEYBOARD) -			{ -				if(OPL->keyboardhandler_w) -					OPL->keyboardhandler_w(OPL->keyboard_param,v); -				else -					logerror("OPL:write unmapped KEYBOARD port\n"); -			} -			break; -		case 0x07:	/* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ -			if(OPL->type&OPL_TYPE_ADPCM) -				YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); -			break; -#endif -		case 0x08:	/* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ -			OPL->mode = v; -#if !(BUILD_Y8950) -                        break; -#endif - -#if BUILD_Y8950 -			v&=0x1f;	/* for DELTA-T unit */ -		case 0x09:		/* START ADD */ -		case 0x0a: -		case 0x0b:		/* STOP ADD  */ -		case 0x0c: -		case 0x0d:		/* PRESCALE   */ -		case 0x0e: -		case 0x0f:		/* ADPCM data */ -		case 0x10: 		/* DELTA-N    */ -		case 0x11: 		/* DELTA-N    */ -		case 0x12: 		/* EG-CTRL    */ -			if(OPL->type&OPL_TYPE_ADPCM) -				YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); -			break; -#if 0 -		case 0x15:		/* DAC data    */ -		case 0x16: -		case 0x17:		/* SHIFT    */ -			break; -		case 0x18:		/* I/O CTRL (Direction) */ -			if(OPL->type&OPL_TYPE_IO) -				OPL->portDirection = v&0x0f; -			break; -		case 0x19:		/* I/O DATA */ -			if(OPL->type&OPL_TYPE_IO) -			{ -				OPL->portLatch = v; -				if(OPL->porthandler_w) -					OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); -			} -			break; -		case 0x1a:		/* PCM data */ -			break; -#endif -#endif +			return;  		}  		break; -	case 0x20:	/* am ON, vib ON, ksr, eg_type, mul */ +	case 0x20:	/* am,vib,ksr,eg type,mul */  		slot = slot_array[r&0x1f]; -		if(slot < 0) return; +		if(slot == -1) +			return;  		set_mul(OPL,slot,v); -		break; +		return;  	case 0x40:  		slot = slot_array[r&0x1f]; -		if(slot < 0) return; +		if(slot == -1) +			return;  		set_ksl_tl(OPL,slot,v); -		break; +		return;  	case 0x60:  		slot = slot_array[r&0x1f]; -		if(slot < 0) return; +		if(slot == -1) +			return;  		set_ar_dr(OPL,slot,v); -		break; +		return;  	case 0x80:  		slot = slot_array[r&0x1f]; -		if(slot < 0) return; +		if(slot == -1) +			return;  		set_sl_rr(OPL,slot,v); -		break; +		return;  	case 0xa0: -		if (r == 0xbd)			/* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ -		{ -			OPL->lfo_am_depth = v & 0x80; -			OPL->lfo_pm_depth_range = (v&0x40) ? 8 : 0; - -			OPL->rhythm  = v&0x3f; - -			if(OPL->rhythm&0x20) +		switch(r) { +		case 0xbd: +			/* amsep,vibdep,r,bd,sd,tom,tc,hh */  			{ +			uint8 rkey = OPL->rythm ^ v; +			OPL->ams_table = &AMS_TABLE[v & 0x80 ? AMS_ENT : 0]; +			OPL->vib_table = &VIB_TABLE[v & 0x40 ? VIB_ENT : 0]; +			OPL->rythm  = v & 0x3f; +			if(OPL->rythm & 0x20) {  				/* BD key on/off */ -				if(v&0x10) -				{ -					FM_KEYON (&OPL->P_CH[6].SLOT[SLOT1], 2); -					FM_KEYON (&OPL->P_CH[6].SLOT[SLOT2], 2); -				} -				else -				{ -					FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); -					FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); +				if(rkey & 0x10) { +					if(v & 0x10) { +						OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0; +						OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]); +						OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]); +					} +					else { +						OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]); +						OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]); +					}  				} -				/* HH key on/off */ -				if(v&0x01) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT1], 2); -				else       FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2);  				/* SD key on/off */ -				if(v&0x08) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT2], 2); -				else       FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); -				/* TOM key on/off */ -				if(v&0x04) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT1], 2); -				else       FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); +				if(rkey & 0x08) { +					if(v & 0x08) +						OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]); +					else +						OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]); +				}/* TAM key on/off */ +				if(rkey & 0x04) { +					if(v & 0x04) +						OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]); +					else +						OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]); +				}  				/* TOP-CY key on/off */ -				if(v&0x02) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT2], 2); -				else       FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); +				if(rkey & 0x02) { +					if(v & 0x02) +						OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]); +					else +						OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]); +				} +				/* HH key on/off */ +				if(rkey & 0x01) { +					if(v & 0x01) +						OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]); +					else +						OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]); +				}  			} -			else -			{ -				/* BD key off */ -				FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); -				FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); -				/* HH key off */ -				FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); -				/* SD key off */ -				FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); -				/* TOM key off */ -				FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); -				/* TOP-CY off */ -				FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2);  			}  			return;  		}  		/* keyon,block,fnum */ -		if( (r&0x0f) > 8) return; -		CH = &OPL->P_CH[r&0x0f]; -		if(!(r&0x10)) -		{	/* a0-a8 */ -			block_fnum  = (CH->block_fnum&0x1f00) | v; +		if((r & 0x0f) > 8) +			return; +		CH = &OPL->P_CH[r & 0x0f]; +		if(!(r&0x10)) {	/* a0-a8 */ +			block_fnum  = (CH->block_fnum & 0x1f00) | v;  		} -		else -		{	/* b0-b8 */ -			block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); - -			if(v&0x20) -			{ -				FM_KEYON (&CH->SLOT[SLOT1], 1); -				FM_KEYON (&CH->SLOT[SLOT2], 1); -			} -			else -			{ -				FM_KEYOFF(&CH->SLOT[SLOT1],~1); -				FM_KEYOFF(&CH->SLOT[SLOT2],~1); +		else {	/* b0-b8 */ +			int keyon = (v >> 5) & 1; +			block_fnum = ((v & 0x1f) << 8) | (CH->block_fnum & 0xff); +			if(CH->keyon != keyon) { +				if((CH->keyon=keyon)) { +					CH->op1_out[0] = CH->op1_out[1] = 0; +					OPL_KEYON(&CH->SLOT[SLOT1]); +					OPL_KEYON(&CH->SLOT[SLOT2]); +				} +				else { +					OPL_KEYOFF(&CH->SLOT[SLOT1]); +					OPL_KEYOFF(&CH->SLOT[SLOT2]); +				}  			}  		}  		/* update */ -		if(CH->block_fnum != block_fnum) -		{ -			UINT8 block  = block_fnum >> 10; - +		if(CH->block_fnum != block_fnum) { +			int blockRv = 7 - (block_fnum >> 10); +			int fnum = block_fnum & 0x3ff;  			CH->block_fnum = block_fnum; - -			CH->ksl_base = ksl_tab[block_fnum>>6]; -			CH->fc       = OPL->fn_tab[block_fnum&0x03ff] >> (7-block); - -			/* BLK 2,1,0 bits -> bits 3,2,1 of kcode */ -			CH->kcode    = (CH->block_fnum&0x1c00)>>9; - -			 /* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */ -			/* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum  */ -			/* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ -			if (OPL->mode&0x40) -				CH->kcode |= (CH->block_fnum&0x100)>>8;	/* notesel == 1 */ -			else -				CH->kcode |= (CH->block_fnum&0x200)>>9;	/* notesel == 0 */ - -			/* refresh Total Level in both SLOTs of this channel */ -			CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); -			CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); - -			/* refresh frequency counter in both SLOTs of this channel */ +			CH->ksl_base = KSL_TABLE[block_fnum >> 6]; +			CH->fc = OPL->FN_TABLE[fnum] >> blockRv; +			CH->kcode = CH->block_fnum >> 9; +			if((OPL->mode & 0x40) && CH->block_fnum & 0x100) +				CH->kcode |=1;  			CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);  			CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);  		} -		break; +		return;  	case 0xc0:  		/* FB,C */ -		if( (r&0x0f) > 8) return; +		if((r & 0x0f) > 8) +			return;  		CH = &OPL->P_CH[r&0x0f]; -		CH->SLOT[SLOT1].FB  = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; -		CH->SLOT[SLOT1].CON = v&1; -		CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &output[0] : &phase_modulation; -		break; -	case 0xe0: /* waveform select */ -		/* simply ignore write to the waveform select register if selecting not enabled in test register */ -		if(OPL->wavesel)  		{ -			slot = slot_array[r&0x1f]; -			if(slot < 0) return; -			CH = &OPL->P_CH[slot/2]; - -			CH->SLOT[slot&1].wavetable = (v&0x03)*SIN_LEN; +			int feedback = (v >> 1) & 7; +			CH->FB = feedback ? (8 + 1) - feedback : 0; +			CH->CON = v & 1; +			set_algorythm(CH);  		} -		break; -	} -} - -#ifdef LOG_CYM_FILE -static void cymfile_callback (int n) -{ -	if (cymfile) -	{ -		fputc( (unsigned char)0, cymfile ); +		return; +	case 0xe0: /* wave type */ +		slot = slot_array[r & 0x1f]; +		if(slot == -1) +			return; +		CH = &OPL->P_CH[slot / 2]; +		if(OPL->wavesel) { +			CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v & 0x03) * SIN_ENT]; +		} +		return;  	}  } -#endif  /* lock/unlock for common table */  static int OPL_LockTable(void)  {  	num_lock++; -	if(num_lock>1) return 0; - +	if(num_lock>1) +		return 0;  	/* first time */ -  	cur_chip = NULL;  	/* allocate total level table (128kb space) */ -	if( !init_tables() ) -	{ +	if(!OPLOpenTable()) {  		num_lock--;  		return -1;  	} - -#ifdef LOG_CYM_FILE -	cymfile = fopen("3812_.cym","wb"); -	if (cymfile) -		timer_pulse ( TIME_IN_HZ(110), 0, cymfile_callback); /*110 Hz pulse timer*/ -	else -		logerror("Could not create file 3812_.cym\n"); -#endif -  	return 0;  } -static void OPL_UnLockTable(void) -{ -	if(num_lock) num_lock--; -	if(num_lock) return; - +static void OPL_UnLockTable(void) { +	if(num_lock) +		num_lock--; +	if(num_lock) +		return;  	/* last time */ -  	cur_chip = NULL;  	OPLCloseTable(); +} -#ifdef LOG_CYM_FILE -	fclose (cymfile); -	cymfile = NULL; -#endif +/*******************************************************************************/ +/*		YM3812 local section                                                   */ +/*******************************************************************************/ +/* ---------- update one of chip ----------- */ +void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length) { +	int i; +	int data; +	int16 *buf = buffer; +	uint amsCnt = OPL->amsCnt; +	uint vibCnt = OPL->vibCnt; +	uint8 rythm = OPL->rythm & 0x20; +	OPL_CH *CH, *R_CH; + +	if((void *)OPL != cur_chip){ +		cur_chip = (void *)OPL; +		/* channel pointers */ +		S_CH = OPL->P_CH; +		E_CH = &S_CH[9]; +		/* rythm slot */ +		SLOT7_1 = &S_CH[7].SLOT[SLOT1]; +		SLOT7_2 = &S_CH[7].SLOT[SLOT2]; +		SLOT8_1 = &S_CH[8].SLOT[SLOT1]; +		SLOT8_2 = &S_CH[8].SLOT[SLOT2]; +		/* LFO state */ +		amsIncr = OPL->amsIncr; +		vibIncr = OPL->vibIncr; +		ams_table = OPL->ams_table; +		vib_table = OPL->vib_table; +	} +	R_CH = rythm ? &S_CH[6] : E_CH; +	for(i = 0; i < length; i++) { +		/*            channel A         channel B         channel C      */ +		/* LFO */ +		ams = ams_table[(amsCnt += amsIncr) >> AMS_SHIFT]; +		vib = vib_table[(vibCnt += vibIncr) >> VIB_SHIFT]; +		outd[0] = 0; +		/* FM part */ +		for(CH=S_CH; CH < R_CH; CH++) +			OPL_CALC_CH(CH); +		/* Rythn part */ +		if(rythm) +			OPL_CALC_RH(S_CH); +		/* limit check */ +		data = Limit(outd[0], OPL_MAXOUT, OPL_MINOUT); +		/* store to sound buffer */ +		buf[i] = data >> OPL_OUTSB; +	} + +	OPL->amsCnt = amsCnt; +	OPL->vibCnt = vibCnt;  } -static void OPLResetChip(FM_OPL *OPL) -{ +/* ---------- reset a chip ---------- */ +void OPLResetChip(FM_OPL *OPL) {  	int c,s;  	int i; -	OPL->eg_timer = 0; -	OPL->eg_cnt   = 0; - -	OPL->noise_rng = 1;	/* noise shift register */ -	OPL->mode   = 0;	/* normal mode */ -	OPL_STATUS_RESET(OPL,0x7f); - +	/* reset chip */ +	OPL->mode = 0;	/* normal mode */ +	OPL_STATUS_RESET(OPL, 0x7f);  	/* reset with register write */ -	OPLWriteReg(OPL,0x01,0); /* wavesel disable */ -	OPLWriteReg(OPL,0x02,0); /* Timer1 */ -	OPLWriteReg(OPL,0x03,0); /* Timer2 */ -	OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ -	for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); - -	/* reset operator parameters */ -	for( c = 0 ; c < 9 ; c++ ) -	{ +	OPLWriteReg(OPL, 0x01,0); /* wabesel disable */ +	OPLWriteReg(OPL, 0x02,0); /* Timer1 */ +	OPLWriteReg(OPL, 0x03,0); /* Timer2 */ +	OPLWriteReg(OPL, 0x04,0); /* IRQ mask clear */ +	for(i = 0xff; i >= 0x20; i--) +		OPLWriteReg(OPL,i,0); +	/* reset OPerator paramater */ +	for(c = 0; c < OPL->max_ch ;c++ ) {  		OPL_CH *CH = &OPL->P_CH[c]; -		for(s = 0 ; s < 2 ; s++ ) -		{ +		/* OPL->P_CH[c].PAN = OPN_CENTER; */ +		for(s = 0; s < 2; s++ ) {  			/* wave table */ -			CH->SLOT[s].wavetable = 0; -			CH->SLOT[s].state     = EG_OFF; -			CH->SLOT[s].volume    = MAX_ATT_INDEX; +			CH->SLOT[s].wavetable = &SIN_TABLE[0]; +			/* CH->SLOT[s].evm = ENV_MOD_RR; */ +			CH->SLOT[s].evc = EG_OFF; +			CH->SLOT[s].eve = EG_OFF + 1; +			CH->SLOT[s].evs = 0;  		}  	} -#if BUILD_Y8950 -	if(OPL->type&OPL_TYPE_ADPCM) -	{ -		YM_DELTAT *DELTAT = OPL->deltat; - -		DELTAT->freqbase = OPL->freqbase; -		DELTAT->output_pointer = &output_deltat[0]; -		DELTAT->portshift = 5; -		DELTAT->output_range = 1<<23; -		YM_DELTAT_ADPCM_Reset(DELTAT,0); -	} -#endif  } -/* Create one of virtual YM3812 */ -/* 'clock' is chip clock in Hz  */ -/* 'rate'  is sampling rate  */ -static FM_OPL *OPLCreate(int type, int clock, int rate) -{ +/* ----------  Create a virtual YM3812 ----------       */ +/* 'rate'  is sampling rate and 'bufsiz' is the size of the  */ +FM_OPL *OPLCreate(int type, int clock, int rate) {  	char *ptr;  	FM_OPL *OPL;  	int state_size; +	int max_ch = 9; /* normaly 9 channels */ -	if (OPL_LockTable() ==-1) return NULL; - -	/* calculate OPL state size */ +	if( OPL_LockTable() == -1) +		return NULL; +	/* allocate OPL state space */  	state_size  = sizeof(FM_OPL); - -#if BUILD_Y8950 -	if (type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); -#endif +	state_size += sizeof(OPL_CH) * max_ch;  	/* allocate memory block */ -	ptr = (char *)malloc(state_size); - -	if (ptr==NULL) +	ptr = (char *)calloc(state_size, 1); +	if(ptr == NULL)  		return NULL;  	/* clear */ -	memset(ptr,0,state_size); - -	OPL  = (FM_OPL *)ptr; - -	ptr += sizeof(FM_OPL); - -#if BUILD_Y8950 -	if (type&OPL_TYPE_ADPCM) -		OPL->deltat = (YM_DELTAT *)ptr; -	ptr += sizeof(YM_DELTAT); -#endif +	memset(ptr, 0, state_size); +	OPL       = (FM_OPL *)ptr; ptr += sizeof(FM_OPL); +	OPL->P_CH = (OPL_CH *)ptr; ptr += sizeof(OPL_CH) * max_ch; +	/* set channel state pointer */  	OPL->type  = type;  	OPL->clock = clock;  	OPL->rate  = rate; +	OPL->max_ch = max_ch; -	/* init global tables */ +	/* init grobal tables */  	OPL_initalize(OPL);  	/* reset chip */ @@ -1834,602 +1048,76 @@ static FM_OPL *OPLCreate(int type, int clock, int rate)  	return OPL;  } -/* Destroy one of virtual YM3812 */ -static void OPLDestroy(FM_OPL *OPL) -{ +/* ----------  Destroy one of vietual YM3812 ----------       */ +void OPLDestroy(FM_OPL *OPL) {  	OPL_UnLockTable();  	free(OPL);  } -/* Option handlers */ +/* ----------  Option handlers ----------       */ -static void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) -{ +void OPLSetTimerHandler(FM_OPL *OPL, OPL_TIMERHANDLER TimerHandler,int channelOffset) {  	OPL->TimerHandler   = TimerHandler;  	OPL->TimerParam = channelOffset;  } -static void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) -{ + +void OPLSetIRQHandler(FM_OPL *OPL, OPL_IRQHANDLER IRQHandler, int param) {  	OPL->IRQHandler     = IRQHandler;  	OPL->IRQParam = param;  } -static void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) -{ +void OPLSetUpdateHandler(FM_OPL *OPL, OPL_UPDATEHANDLER UpdateHandler,int param) {  	OPL->UpdateHandler = UpdateHandler;  	OPL->UpdateParam = param;  } -/* YM3812 I/O interface */ -static int OPLWrite(FM_OPL *OPL,int a,int v) -{ -	if( !(a&1) ) -	{	/* address port */ +/* ---------- YM3812 I/O interface ---------- */ +int OPLWrite(FM_OPL *OPL,int a,int v) { +	if(!(a & 1)) {	/* address port */  		OPL->address = v & 0xff;  	} -	else -	{	/* data port */ -		if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); -		OPLWriteReg(OPL,OPL->address,v); +	else {	/* data port */ +		if(OPL->UpdateHandler) +			OPL->UpdateHandler(OPL->UpdateParam,0); +		OPLWriteReg(OPL, OPL->address,v);  	} -	return OPL->status>>7; +	return OPL->status >> 7;  } -static unsigned char OPLRead(FM_OPL *OPL,int a) -{ -	if( !(a&1) ) -	{ -		/* status port */ -		return OPL->status & (OPL->statusmask|0x80); +unsigned char OPLRead(FM_OPL *OPL,int a) { +	if(!(a & 1)) {	/* status port */ +		return OPL->status & (OPL->statusmask | 0x80);  	} - -#if BUILD_Y8950  	/* data port */ -	switch(OPL->address) -	{ +	switch(OPL->address) {  	case 0x05: /* KeyBoard IN */ -		if(OPL->type&OPL_TYPE_KEYBOARD) -		{ -			if(OPL->keyboardhandler_r) -				return OPL->keyboardhandler_r(OPL->keyboard_param); -			else -				logerror("OPL:read unmapped KEYBOARD port\n"); -		} +		warning("OPL:read unmapped KEYBOARD port\n");  		return 0; -#if 0 -	case 0x0f: /* ADPCM-DATA  */ -		return 0; -#endif  	case 0x19: /* I/O DATA    */ -		if(OPL->type&OPL_TYPE_IO) -		{ -			if(OPL->porthandler_r) -				return OPL->porthandler_r(OPL->port_param); -			else -				logerror("OPL:read unmapped I/O port\n"); -		} +		warning("OPL:read unmapped I/O port\n");  		return 0;  	case 0x1a: /* PCM-DATA    */  		return 0;  	} -#endif - -	return 0xff; -} - -/* CSM Key Controll */ -INLINE void CSMKeyControll(OPL_CH *CH) -{ -	FM_KEYON (&CH->SLOT[SLOT1], 4); -	FM_KEYON (&CH->SLOT[SLOT2], 4); - -	/* The key off should happen exactly one sample later - not implemented correctly yet */ - -	FM_KEYOFF(&CH->SLOT[SLOT1], ~4); -	FM_KEYOFF(&CH->SLOT[SLOT2], ~4); +	return 0;  } - -static int OPLTimerOver(FM_OPL *OPL,int c) -{ -	if( c ) -	{	/* Timer B */ -		OPL_STATUS_SET(OPL,0x20); +int OPLTimerOver(FM_OPL *OPL, int c) { +	if(c) {	/* Timer B */ +		OPL_STATUS_SET(OPL, 0x20);  	} -	else -	{	/* Timer A */ -		OPL_STATUS_SET(OPL,0x40); +	else {	/* Timer A */ +		OPL_STATUS_SET(OPL, 0x40);  		/* CSM mode key,TL controll */ -		if( OPL->mode & 0x80 ) -		{	/* CSM mode total level latch and auto key on */ +		if(OPL->mode & 0x80) {	/* CSM mode total level latch and auto key on */  			int ch; -			if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); -			for(ch=0; ch<9; ch++) -				CSMKeyControll( &OPL->P_CH[ch] ); +			if(OPL->UpdateHandler) +				OPL->UpdateHandler(OPL->UpdateParam,0); +			for(ch = 0; ch < 9; ch++) +				CSMKeyControll(&OPL->P_CH[ch]);  		}  	}  	/* reload timer */ -	if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); -	return OPL->status>>7; -} - - -#define MAX_OPL_CHIPS 2 - - -#if (BUILD_YM3812) - -static FM_OPL *OPL_YM3812[MAX_OPL_CHIPS];	/* array of pointers to the YM3812's */ -static int YM3812NumChips = 0;				/* number of chips */ - -int YM3812Init(int num, int clock, int rate) -{ -	int i; - -	if (YM3812NumChips) -		return -1;	/* duplicate init. */ - -	YM3812NumChips = num; - -	for (i = 0;i < YM3812NumChips; i++) -	{ -		/* emulator create */ -		OPL_YM3812[i] = OPLCreate(OPL_TYPE_YM3812,clock,rate); -		if(OPL_YM3812[i] == NULL) -		{ -			/* it's really bad - we run out of memeory */ -			YM3812NumChips = 0; -			return -1; -		} -	} - -	return 0; -} - -void YM3812Shutdown(void) -{ -	int i; - -	for (i = 0;i < YM3812NumChips; i++) -	{ -		/* emulator shutdown */ -		OPLDestroy(OPL_YM3812[i]); -		OPL_YM3812[i] = NULL; -	} -	YM3812NumChips = 0; -} -void YM3812ResetChip(int which) -{ -	OPLResetChip(OPL_YM3812[which]); -} - -int YM3812Write(int which, int a, int v) -{ -	return OPLWrite(OPL_YM3812[which], a, v); -} - -unsigned char YM3812Read(int which, int a) -{ -	/* YM3812 always returns bit2 and bit1 in HIGH state */ -	return OPLRead(OPL_YM3812[which], a) | 0x06 ; -} -int YM3812TimerOver(int which, int c) -{ -	return OPLTimerOver(OPL_YM3812[which], c); -} - -void YM3812SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset) -{ -	OPLSetTimerHandler(OPL_YM3812[which], TimerHandler, channelOffset); -} -void YM3812SetIRQHandler(int which,OPL_IRQHANDLER IRQHandler,int param) -{ -	OPLSetIRQHandler(OPL_YM3812[which], IRQHandler, param); -} -void YM3812SetUpdateHandler(int which,OPL_UPDATEHANDLER UpdateHandler,int param) -{ -	OPLSetUpdateHandler(OPL_YM3812[which], UpdateHandler, param); +	if (OPL->TimerHandler) +		(OPL->TimerHandler)(OPL->TimerParam + c, (double)OPL->T[c] * OPL->TimerBase); +	return OPL->status >> 7;  } - - -/* -** Generate samples for one of the YM3812's -** -** 'which' is the virtual YM3812 number -** '*buffer' is the output buffer pointer -** 'length' is the number of samples that should be generated -*/ -void YM3812UpdateOne(int which, INT16 *buffer, int length) -{ -	FM_OPL		*OPL = OPL_YM3812[which]; -	UINT8		rhythm = OPL->rhythm&0x20; -	OPLSAMPLE	*buf = buffer; -	int i; - -	if( (void *)OPL != cur_chip ){ -		cur_chip = (void *)OPL; -		/* rhythm slots */ -		SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; -		SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; -		SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; -		SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; -	} -	for( i=0; i < length ; i++ ) -	{ -		int lt; - -		output[0] = 0; - -		advance_lfo(OPL); - -		/* FM part */ -		OPL_CALC_CH(&OPL->P_CH[0]); -		OPL_CALC_CH(&OPL->P_CH[1]); -		OPL_CALC_CH(&OPL->P_CH[2]); -		OPL_CALC_CH(&OPL->P_CH[3]); -		OPL_CALC_CH(&OPL->P_CH[4]); -		OPL_CALC_CH(&OPL->P_CH[5]); - -		if(!rhythm) -		{ -			OPL_CALC_CH(&OPL->P_CH[6]); -			OPL_CALC_CH(&OPL->P_CH[7]); -			OPL_CALC_CH(&OPL->P_CH[8]); -		} -		else		/* Rhythm part */ -		{ -			OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); -		} - -		lt = output[0]; - -		lt >>= FINAL_SH; - -		/* limit check */ -		lt = limit( lt , MAXOUT, MINOUT ); - -		#ifdef SAVE_SAMPLE -			SAVE_ALL_CHANNELS -		#endif - -		/* store to sound buffer */ -		buf[i] = lt; - -		advancex(OPL); -	} - -} -#endif /* BUILD_YM3812 */ - - - -#if (BUILD_YM3526) - -static FM_OPL *OPL_YM3526[MAX_OPL_CHIPS];	/* array of pointers to the YM3526's */ -static int YM3526NumChips = 0;				/* number of chips */ - -int YM3526Init(int num, int clock, int rate) -{ -	int i; - -	if (YM3526NumChips) -		return -1;	/* duplicate init. */ - -	YM3526NumChips = num; - -	for (i = 0;i < YM3526NumChips; i++) -	{ -		/* emulator create */ -		OPL_YM3526[i] = OPLCreate(OPL_TYPE_YM3526,clock,rate); -		if(OPL_YM3526[i] == NULL) -		{ -			/* it's really bad - we run out of memeory */ -			YM3526NumChips = 0; -			return -1; -		} -	} - -	return 0; -} - -void YM3526Shutdown(void) -{ -	int i; - -	for (i = 0;i < YM3526NumChips; i++) -	{ -		/* emulator shutdown */ -		OPLDestroy(OPL_YM3526[i]); -		OPL_YM3526[i] = NULL; -	} -	YM3526NumChips = 0; -} -void YM3526ResetChip(int which) -{ -	OPLResetChip(OPL_YM3526[which]); -} - -int YM3526Write(int which, int a, int v) -{ -	return OPLWrite(OPL_YM3526[which], a, v); -} - -unsigned char YM3526Read(int which, int a) -{ -	return OPLRead(OPL_YM3526[which], a); -} -int YM3526TimerOver(int which, int c) -{ -	return OPLTimerOver(OPL_YM3526[which], c); -} - -void YM3526SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset) -{ -	OPLSetTimerHandler(OPL_YM3526[which], TimerHandler, channelOffset); -} -void YM3526SetIRQHandler(int which,OPL_IRQHANDLER IRQHandler,int param) -{ -	OPLSetIRQHandler(OPL_YM3526[which], IRQHandler, param); -} -void YM3526SetUpdateHandler(int which,OPL_UPDATEHANDLER UpdateHandler,int param) -{ -	OPLSetUpdateHandler(OPL_YM3526[which], UpdateHandler, param); -} - - -/* -** Generate samples for one of the YM3526's -** -** 'which' is the virtual YM3526 number -** '*buffer' is the output buffer pointer -** 'length' is the number of samples that should be generated -*/ -void YM3526UpdateOne(int which, INT16 *buffer, int length) -{ -	FM_OPL		*OPL = OPL_YM3526[which]; -	UINT8		rhythm = OPL->rhythm&0x20; -	OPLSAMPLE	*buf = buffer; -	int i; - -	if( (void *)OPL != cur_chip ){ -		cur_chip = (void *)OPL; -		/* rhythm slots */ -		SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; -		SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; -		SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; -		SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; -	} -	for( i=0; i < length ; i++ ) -	{ -		int lt; - -		output[0] = 0; - -		advance_lfo(OPL); - -		/* FM part */ -		OPL_CALC_CH(&OPL->P_CH[0]); -		OPL_CALC_CH(&OPL->P_CH[1]); -		OPL_CALC_CH(&OPL->P_CH[2]); -		OPL_CALC_CH(&OPL->P_CH[3]); -		OPL_CALC_CH(&OPL->P_CH[4]); -		OPL_CALC_CH(&OPL->P_CH[5]); - -		if(!rhythm) -		{ -			OPL_CALC_CH(&OPL->P_CH[6]); -			OPL_CALC_CH(&OPL->P_CH[7]); -			OPL_CALC_CH(&OPL->P_CH[8]); -		} -		else		/* Rhythm part */ -		{ -			OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); -		} - -		lt = output[0]; - -		lt >>= FINAL_SH; - -		/* limit check */ -		lt = limit( lt , MAXOUT, MINOUT ); - -		#ifdef SAVE_SAMPLE -			SAVE_ALL_CHANNELS -		#endif - -		/* store to sound buffer */ -		buf[i] = lt; - -		advance(OPL); -	} - -} -#endif /* BUILD_YM3526 */ - - - - -#if BUILD_Y8950 - -static FM_OPL *OPL_Y8950[MAX_OPL_CHIPS];	/* array of pointers to the Y8950's */ -static int Y8950NumChips = 0;				/* number of chips */ - -int Y8950Init(int num, int clock, int rate) -{ -	int i; - -	if (Y8950NumChips) -		return -1;	/* duplicate init. */ - -	Y8950NumChips = num; - -	for (i = 0;i < Y8950NumChips; i++) -	{ -		/* emulator create */ -		OPL_Y8950[i] = OPLCreate(OPL_TYPE_Y8950,clock,rate); -		if(OPL_Y8950[i] == NULL) -		{ -			/* it's really bad - we run out of memeory */ -			Y8950NumChips = 0; -			return -1; -		} -	} - -	return 0; -} - -void Y8950Shutdown(void) -{ -	int i; - -	for (i = 0;i < Y8950NumChips; i++) -	{ -		/* emulator shutdown */ -		OPLDestroy(OPL_Y8950[i]); -		OPL_Y8950[i] = NULL; -	} -	Y8950NumChips = 0; -} -void Y8950ResetChip(int which) -{ -	OPLResetChip(OPL_Y8950[which]); -} - -int Y8950Write(int which, int a, int v) -{ -	return OPLWrite(OPL_Y8950[which], a, v); -} - -unsigned char Y8950Read(int which, int a) -{ -	return OPLRead(OPL_Y8950[which], a); -} -int Y8950TimerOver(int which, int c) -{ -	return OPLTimerOver(OPL_Y8950[which], c); -} - -void Y8950SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset) -{ -	OPLSetTimerHandler(OPL_Y8950[which], TimerHandler, channelOffset); -} -void Y8950SetIRQHandler(int which,OPL_IRQHANDLER IRQHandler,int param) -{ -	OPLSetIRQHandler(OPL_Y8950[which], IRQHandler, param); -} -void Y8950SetUpdateHandler(int which,OPL_UPDATEHANDLER UpdateHandler,int param) -{ -	OPLSetUpdateHandler(OPL_Y8950[which], UpdateHandler, param); -} - -void Y8950SetDeltaTMemory(int which, void * deltat_rom, int deltat_rom_size ) -{ -	FM_OPL		*OPL = OPL_Y8950[which]; -	OPL->deltat->memory = (UINT8 *)(deltat_rom); -	OPL->deltat->memory_size = deltat_rom_size; -} - -/* -** Generate samples for one of the Y8950's -** -** 'which' is the virtual Y8950 number -** '*buffer' is the output buffer pointer -** 'length' is the number of samples that should be generated -*/ -void Y8950UpdateOne(int which, INT16 *buffer, int length) -{ -	int i; -	FM_OPL		*OPL = OPL_Y8950[which]; -	UINT8		rhythm  = OPL->rhythm&0x20; -	YM_DELTAT	*DELTAT = OPL->deltat; -	OPLSAMPLE	*buf    = buffer; - -	/* setup DELTA-T unit */ -	YM_DELTAT_DECODE_PRESET(DELTAT); - -	if( (void *)OPL != cur_chip ){ -		cur_chip = (void *)OPL; -		/* rhythm slots */ -		SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; -		SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; -		SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; -		SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; - -	} -	for( i=0; i < length ; i++ ) -	{ -		int lt; - -		output[0] = 0; -		output_deltat[0] = 0; - -		advance_lfo(OPL); - -		/* deltaT ADPCM */ -		if( DELTAT->portstate ) -			YM_DELTAT_ADPCM_CALC(DELTAT); - -		/* FM part */ -		OPL_CALC_CH(&OPL->P_CH[0]); -		OPL_CALC_CH(&OPL->P_CH[1]); -		OPL_CALC_CH(&OPL->P_CH[2]); -		OPL_CALC_CH(&OPL->P_CH[3]); -		OPL_CALC_CH(&OPL->P_CH[4]); -		OPL_CALC_CH(&OPL->P_CH[5]); - -		if(!rhythm) -		{ -			OPL_CALC_CH(&OPL->P_CH[6]); -			OPL_CALC_CH(&OPL->P_CH[7]); -			OPL_CALC_CH(&OPL->P_CH[8]); -		} -		else		/* Rhythm part */ -		{ -			OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); -		} - -		lt = output[0] + (output_deltat[0]>>11); - -		lt >>= FINAL_SH; - -		/* limit check */ -		lt = limit( lt , MAXOUT, MINOUT ); - -		#ifdef SAVE_SAMPLE -			SAVE_ALL_CHANNELS -		#endif - -		/* store to sound buffer */ -		buf[i] = lt; - -		advance(OPL); -	} - -	/* deltaT START flag */ -	if( !DELTAT->portstate ) -		OPL->status &= 0xfe; - -	if( DELTAT->eos ) //AT: set bit 4 of OPL status register on EOS -	{ -		DELTAT->eos = 0; -		OPL->status |= 0x10; -	} -} - -void Y8950SetPortHandler(int which,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) -{ -	FM_OPL		*OPL = OPL_Y8950[which]; -	OPL->porthandler_w = PortHandler_w; -	OPL->porthandler_r = PortHandler_r; -	OPL->port_param = param; -} - -void Y8950SetKeyboardHandler(int which,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) -{ -	FM_OPL		*OPL = OPL_Y8950[which]; -	OPL->keyboardhandler_w = KeyboardHandler_w; -	OPL->keyboardhandler_r = KeyboardHandler_r; -	OPL->keyboard_param = param; -} - -#endif - diff --git a/sound/fmopl.h b/sound/fmopl.h index 0b4320e715..8fbeb175e3 100644 --- a/sound/fmopl.h +++ b/sound/fmopl.h @@ -18,125 +18,135 @@   *   * $Header$   * - * LGPL licensed version of MAMEs fmopl (V0.60a modified) by - * Tatsuyuki Satoh and Jarek Burczynski. Included from LGPL'ed AdPlug. + * LGPL licensed version of MAMEs fmopl (V0.37a modified) by + * Tatsuyuki Satoh. Included from LGPL'ed AdPlug.   */ +  #ifndef __FMOPL_H_  #define __FMOPL_H_ - -#define HAS_YM3812	1 - -/* --- select emulation chips --- */ -#ifdef _MSC_VER -// FIXME: how to fix it for VC6 ? -#define BUILD_YM3812 1 -#else -#define BUILD_YM3812 defined(HAS_YM3812) && HAS_YM3812 -#endif -#define BUILD_YM3526 defined(HAS_YM3526) && HAS_YM3526 -#define BUILD_Y8950  defined(HAS_Y8950) && HAS_Y8950 - -/* select output bits size of output : 8 or 16 */ -#define OPL_SAMPLE_BITS 16 - -/* 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 (OPL_SAMPLE_BITS==16) -typedef INT16 OPLSAMPLE; -#endif -#if (OPL_SAMPLE_BITS==8) -typedef INT8 OPLSAMPLE; -#endif - +#include "scummsys.h"  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); - - -#if BUILD_YM3812 - -int  YM3812Init(int num, int clock, int rate); -void YM3812Shutdown(void); -void YM3812ResetChip(int which); -int  YM3812Write(int which, int a, int v); -unsigned char YM3812Read(int which, int a); -int  YM3812TimerOver(int which, int c); -void YM3812UpdateOne(int which, INT16 *buffer, int length); - -void YM3812SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset); -void YM3812SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param); -void YM3812SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param); - -#endif - - -#if BUILD_YM3526 - -/* -** Initialize YM3526 emulator(s). -** -** 'num' is the number of virtual YM3526's to allocate -** 'clock' is the chip clock in Hz -** 'rate' is sampling rate -*/ -int  YM3526Init(int num, int clock, int rate); -/* shutdown the YM3526 emulators*/ -void YM3526Shutdown(void); -void YM3526ResetChip(int which); -int  YM3526Write(int which, int a, int v); -unsigned char YM3526Read(int which, int a); -int  YM3526TimerOver(int which, int c); -/* -** Generate samples for one of the YM3526's -** -** 'which' is the virtual YM3526 number -** '*buffer' is the output buffer pointer -** 'length' is the number of samples that should be generated -*/ -void YM3526UpdateOne(int which, INT16 *buffer, int length); - -void YM3526SetTimerHandler(int which, OPL_TIMERHANDLER TimerHandler, int channelOffset); -void YM3526SetIRQHandler(int which, OPL_IRQHANDLER IRQHandler, int param); -void YM3526SetUpdateHandler(int which, OPL_UPDATEHANDLER UpdateHandler, int param); - -#endif - - -#if BUILD_Y8950 - -#include "ymdeltat.h" - -/* Y8950 port handlers */ -void Y8950SetPortHandler(int which, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, int param); -void Y8950SetKeyboardHandler(int which, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, int param); -void Y8950SetDeltaTMemory(int which, void * deltat_rom, int deltat_rom_size ); - -int  Y8950Init (int num, int clock, int rate); -void Y8950Shutdown (void); -void Y8950ResetChip (int which); -int  Y8950Write (int which, int a, int v); -unsigned char Y8950Read (int which, int a); -int  Y8950TimerOver (int which, int c); -void Y8950UpdateOne (int which, INT16 *buffer, int length); - -void Y8950SetTimerHandler (int which, OPL_TIMERHANDLER TimerHandler, int channelOffset); -void Y8950SetIRQHandler (int which, OPL_IRQHANDLER IRQHandler, int param); -void Y8950SetUpdateHandler (int which, OPL_UPDATEHANDLER UpdateHandler, int param); - -#endif - +#define OPL_TYPE_WAVESEL   0x01  /* waveform select    */ + +/* Saving is necessary for member of the 'R' mark for suspend/resume */ +/* ---------- OPL one of slot  ---------- */ +typedef struct fm_opl_slot { +	int TL;		/* total level     :TL << 8				*/ +	int TLL;	/* adjusted now TL						*/ +	uint8 KSR;	/* key scale rate  :(shift down bit)	*/ +	int *AR;	/* attack rate     :&AR_TABLE[AR<<2]	*/ +	int *DR;	/* decay rate      :&DR_TABLE[DR<<2]	*/ +	int SL;		/* sustain level   :SL_TABLE[SL]		*/ +	int *RR;	/* release rate    :&DR_TABLE[RR<<2]	*/ +	uint8 ksl;	/* keyscale level  :(shift down bits)	*/ +	uint8 ksr;	/* key scale rate  :kcode>>KSR			*/ +	uint mul;	/* multiple        :ML_TABLE[ML]		*/ +	uint Cnt;	/* frequency count						*/ +	uint Incr;	/* frequency step						*/ +	 +	/* envelope generator state */ +	uint8 eg_typ;/* envelope type flag					*/ +	uint8 evm;	/* envelope phase						*/ +	int evc;	/* envelope counter						*/ +	int eve;	/* envelope counter end point			*/ +	int evs;	/* envelope counter step				*/ +	int evsa;	/* envelope step for AR :AR[ksr]		*/ +	int evsd;	/* envelope step for DR :DR[ksr]		*/ +	int evsr;	/* envelope step for RR :RR[ksr]		*/ + +	/* LFO */ +	uint8 ams;		/* ams flag                            */ +	uint8 vib;		/* vibrate flag                        */ +	/* wave selector */ +	int **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)*/ +	int *connect1;		/* slot1 output pointer				*/ +	int *connect2;		/* slot2 output pointer				*/ +	int op1_out[2];		/* slot1 output for selfeedback		*/ + +	/* phase generator state */ +	uint block_fnum;	/* block+fnum						*/ +	uint8 kcode;		/* key code        : KeyScaleCode	*/ +	uint fc;			/* Freq. Increment base				*/ +	uint 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                       */ +	uint 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 */ +	 +	/* time tables */ +	int AR_TABLE[75];	/* atttack rate tables				*/ +	int DR_TABLE[75];	/* decay rate tables				*/ +	uint FN_TABLE[1024];/* fnumber -> increment counter		*/ + +	/* LFO */ +	int *ams_table; +	int *vib_table; +	int amsCnt; +	int amsIncr; +	int vibCnt; +	int 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) + +void OPLBuildTables(int ENV_BITS_PARAM, int EG_ENT_PARAM); + +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); + +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); +void OPLWriteReg(FM_OPL *OPL, int r, int v); +void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);  #endif  | 
