From dddb296bae953e5fdf02a4fc7485be276f36a74e Mon Sep 17 00:00:00 2001 From: sparky4 Date: Fri, 31 Jul 2015 12:42:10 -0500 Subject: [PATCH] vgm sound driver added!! new file: 16/vgmsnd/3812intf.c new file: 16/vgmsnd/3812intf.h new file: 16/vgmsnd/FotF_Title.vgm new file: 16/vgmsnd/GingaNinkyouDen_Round3.vgm new file: 16/vgmsnd/Lemmings3D_SweetLand1.vgm new file: 16/vgmsnd/Lemmings_LetsGo.vgm renamed: VgmSndDrv.7z -> 16/vgmsnd/VgmSndDrv.7z new file: 16/vgmsnd/VgmSndDrv.exe new file: 16/vgmsnd/VgmSndDrv.sln new file: 16/vgmsnd/VgmSndDrv.vcxproj new file: 16/vgmsnd/VgmSndDrv.vcxproj.filters new file: 16/vgmsnd/fmopl.c new file: 16/vgmsnd/fmopl.h new file: 16/vgmsnd/main.c new file: 16/vgmsnd/mamedef.h new file: 16/vgmsnd/stdbool.h new file: 16/vgmsnd/stdtype.h new file: 16/vgmsnd/vgmSndDrv.c new file: 16/vgmsnd/vgmSndDrv.h --- 16/vgmsnd/3812intf.c | 97 + 16/vgmsnd/3812intf.h | 9 + 16/vgmsnd/FotF_Title.vgm | Bin 0 -> 43239 bytes 16/vgmsnd/GingaNinkyouDen_Round3.vgm | Bin 0 -> 12735 bytes 16/vgmsnd/Lemmings3D_SweetLand1.vgm | Bin 0 -> 53264 bytes 16/vgmsnd/Lemmings_LetsGo.vgm | Bin 0 -> 716 bytes VgmSndDrv.7z => 16/vgmsnd/VgmSndDrv.7z | Bin 16/vgmsnd/VgmSndDrv.exe | Bin 0 -> 26624 bytes 16/vgmsnd/VgmSndDrv.sln | 20 + 16/vgmsnd/VgmSndDrv.vcxproj | 99 + 16/vgmsnd/VgmSndDrv.vcxproj.filters | 57 + 16/vgmsnd/fmopl.c | 2755 ++++++++++++++++++++++++ 16/vgmsnd/fmopl.h | 118 + 16/vgmsnd/main.c | 277 +++ 16/vgmsnd/mamedef.h | 62 + 16/vgmsnd/stdbool.h | 15 + 16/vgmsnd/stdtype.h | 45 + 16/vgmsnd/vgmSndDrv.c | 756 +++++++ 16/vgmsnd/vgmSndDrv.h | 83 + 19 files changed, 4393 insertions(+) create mode 100644 16/vgmsnd/3812intf.c create mode 100644 16/vgmsnd/3812intf.h create mode 100644 16/vgmsnd/FotF_Title.vgm create mode 100644 16/vgmsnd/GingaNinkyouDen_Round3.vgm create mode 100644 16/vgmsnd/Lemmings3D_SweetLand1.vgm create mode 100644 16/vgmsnd/Lemmings_LetsGo.vgm rename VgmSndDrv.7z => 16/vgmsnd/VgmSndDrv.7z (100%) create mode 100644 16/vgmsnd/VgmSndDrv.exe create mode 100644 16/vgmsnd/VgmSndDrv.sln create mode 100644 16/vgmsnd/VgmSndDrv.vcxproj create mode 100644 16/vgmsnd/VgmSndDrv.vcxproj.filters create mode 100644 16/vgmsnd/fmopl.c create mode 100644 16/vgmsnd/fmopl.h create mode 100644 16/vgmsnd/main.c create mode 100644 16/vgmsnd/mamedef.h create mode 100644 16/vgmsnd/stdbool.h create mode 100644 16/vgmsnd/stdtype.h create mode 100644 16/vgmsnd/vgmSndDrv.c create mode 100644 16/vgmsnd/vgmSndDrv.h diff --git a/16/vgmsnd/3812intf.c b/16/vgmsnd/3812intf.c new file mode 100644 index 00000000..876bb573 --- /dev/null +++ b/16/vgmsnd/3812intf.c @@ -0,0 +1,97 @@ +/****************************************************************************** +* FILE +* Yamaha 3812 emulator interface - MAME VERSION +* +* CREATED BY +* Ernesto Corvi +* +* UPDATE LOG +* JB 28-04-2002 Fixed simultaneous usage of all three different chip types. +* Used real sample rate when resample filter is active. +* AAT 12-28-2001 Protected Y8950 from accessing unmapped port and keyboard handlers. +* CHS 1999-01-09 Fixes new ym3812 emulation interface. +* CHS 1998-10-23 Mame streaming sound chip update +* EC 1998 Created Interface +* +* NOTES +* +******************************************************************************/ +#include +#include "mamedef.h" +#include "3812intf.h" +#include "fmopl.h" + + +typedef struct _ym3812_state ym3812_state; +struct _ym3812_state +{ + void * chip; +}; + + +extern INT32 CHIP_SAMPLE_RATE; + +#define MAX_CHIPS 0x02 +static ym3812_state YM3812Data[MAX_CHIPS]; +static stream_sample_t* DUMMYBUF[0x02] = {NULL, NULL}; + +void ym3812_stream_update(UINT8 ChipID, stream_sample_t **outputs, int samples) +{ + ym3812_state *info = &YM3812Data[ChipID]; + ym3812_update_one(info->chip, outputs, samples); +} + +static void _stream_update(void * param/*, int interval*/) +{ + ym3812_state *info = (ym3812_state *)param; + ym3812_update_one(info->chip, DUMMYBUF, 0); +} + + +//static DEVICE_START( ym3812 ) +int device_start_ym3812(UINT8 ChipID, int clock) +{ + ym3812_state *info; + int rate; + + if (ChipID >= MAX_CHIPS) + return 0; + + info = &YM3812Data[ChipID]; + //rate = clock /72; + rate = CHIP_SAMPLE_RATE; + + info->chip = ym3812_init(clock, rate); + + /* YM3812 setup */ + ym3812_set_timer_handler (info->chip, NULL, info); + ym3812_set_irq_handler (info->chip, NULL, info); + ym3812_set_update_handler(info->chip, _stream_update, info); + + return rate; +} + +void device_stop_ym3812(UINT8 ChipID) +{ + ym3812_state *info = &YM3812Data[ChipID]; + ym3812_shutdown(info->chip); +} + +void device_reset_ym3812(UINT8 ChipID) +{ + ym3812_state *info = &YM3812Data[ChipID]; + ym3812_reset_chip(info->chip); +} + + +UINT8 ym3812_r(UINT8 ChipID, offs_t offset) +{ + ym3812_state *info = &YM3812Data[ChipID]; + return ym3812_read(info->chip, offset & 1); +} + +void ym3812_w(UINT8 ChipID, offs_t offset, UINT8 data) +{ + ym3812_state *info = &YM3812Data[ChipID]; + ym3812_write(info->chip, offset & 1, data); +} diff --git a/16/vgmsnd/3812intf.h b/16/vgmsnd/3812intf.h new file mode 100644 index 00000000..bb8c69f7 --- /dev/null +++ b/16/vgmsnd/3812intf.h @@ -0,0 +1,9 @@ +#pragma once + +void ym3812_stream_update(UINT8 ChipID, INT32 **outputs, int samples); +int device_start_ym3812(UINT8 ChipID, int clock); +void device_stop_ym3812(UINT8 ChipID); +void device_reset_ym3812(UINT8 ChipID); + +UINT8 ym3812_r(UINT8 ChipID, UINT32 offset); +void ym3812_w(UINT8 ChipID, UINT32 offset, UINT8 data); diff --git a/16/vgmsnd/FotF_Title.vgm b/16/vgmsnd/FotF_Title.vgm new file mode 100644 index 0000000000000000000000000000000000000000..652c8b4f5845dcc5bcb64c03793777658effc2d5 GIT binary patch literal 43239 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 YihhJW0SJEvNP9u2I{@STfKe3x50+tiH2?qr literal 0 HcmV?d00001 diff --git a/16/vgmsnd/GingaNinkyouDen_Round3.vgm b/16/vgmsnd/GingaNinkyouDen_Round3.vgm new file mode 100644 index 0000000000000000000000000000000000000000..5ac3233a0590cb2e989f2f2d07833c372e31aa60 GIT binary patch literal 12735 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 literal 0 HcmV?d00001 diff --git a/16/vgmsnd/Lemmings3D_SweetLand1.vgm b/16/vgmsnd/Lemmings3D_SweetLand1.vgm new file mode 100644 index 0000000000000000000000000000000000000000..fb4ee0ccfe7d55b2a0e2d715d0b46cc960977d1d GIT binary patch literal 53264 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 K@Y`RNeE$#CZt8jf literal 0 HcmV?d00001 diff --git a/16/vgmsnd/Lemmings_LetsGo.vgm b/16/vgmsnd/Lemmings_LetsGo.vgm new file mode 100644 index 0000000000000000000000000000000000000000..8cd74cac90ae2cb96b5b25af82d75dfdf3621731 GIT binary patch literal 716 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 cI*bd9i;PQ*WyT83c) + + + + Debug + Win32 + + + Release + Win32 + + + + {85B88412-1CEF-42C9-B991-C17D41E5A0AE} + Win32Proj + VgmSndDrv + + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + true + D:\VStudio-Programme\VC++\libvgm;$(IncludePath) + + + false + D:\VStudio-Programme\VC++\libvgm;$(IncludePath) + + + + + + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;AUDDRV_WINMM;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + kernel32.lib;user32.lib;winmm.lib + + + + + Level3 + + + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;AUDDRV_WINMM;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + kernel32.lib;user32.lib;winmm.lib + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/16/vgmsnd/VgmSndDrv.vcxproj.filters b/16/vgmsnd/VgmSndDrv.vcxproj.filters new file mode 100644 index 00000000..7d99f217 --- /dev/null +++ b/16/vgmsnd/VgmSndDrv.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + Quelldateien + + + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + \ No newline at end of file diff --git a/16/vgmsnd/fmopl.c b/16/vgmsnd/fmopl.c new file mode 100644 index 00000000..f8545fc0 --- /dev/null +++ b/16/vgmsnd/fmopl.c @@ -0,0 +1,2755 @@ +/* +** +** File: fmopl.c - software implementation of FM sound generator +** types OPL and OPL2 +** +** Copyright Jarek Burczynski (bujar at mame dot net) +** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development +** +** Version 0.72 +** + +Revision History: + +04-08-2003 Jarek Burczynski: + - removed BFRDY hack. BFRDY is busy flag, and it should be 0 only when the chip + handles memory read/write or during the adpcm synthesis when the chip + requests another byte of ADPCM data. + +24-07-2003 Jarek Burczynski: + - added a small hack for Y8950 status BFRDY flag (bit 3 should be set after + some (unknown) delay). Right now it's always set. + +14-06-2003 Jarek Burczynski: + - implemented all of the status register flags in Y8950 emulation + - renamed y8950_set_delta_t_memory() parameters from _rom_ to _mem_ since + they can be either RAM or ROM + +08-10-2002 Jarek Burczynski (thanks to Dox for the YM3526 chip) + - corrected ym3526_read() to always set bit 2 and bit 1 + to HIGH state - identical to ym3812_read (verified on real YM3526) + +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: ym3526_init(), ym3812_init() and y8950_init() + - 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 +*/ + +#include +#include "mamedef.h" +#ifdef _DEBUG +#include +#endif +#include +#include +//#include "sndintrf.h" +#include "fmopl.h" +#if BUILD_Y8950 +#include "ymdeltat.h" +#endif + + +#define NULL ((void *)0) + + +/* 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_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) */ + +#define FREQ_MASK ((1<=0) + { + if (value < 0x0200) + return (value & ~0); + if (value < 0x0400) + return (value & ~1); + if (value < 0x0800) + return (value & ~3); + if (value < 0x1000) + return (value & ~7); + if (value < 0x2000) + return (value & ~15); + if (value < 0x4000) + return (value & ~31); + return (value & ~63); + } + /*else value < 0*/ + if (value > -0x0200) + return (~abs(value) & ~0); + if (value > -0x0400) + return (~abs(value) & ~1); + if (value > -0x0800) + return (~abs(value) & ~3); + if (value > -0x1000) + return (~abs(value) & ~7); + if (value > -0x2000) + return (~abs(value) & ~15); + if (value > -0x4000) + return (~abs(value) & ~31); + return (~abs(value) & ~63); +} + + +static FILE *sample[1]; + #if 1 /*save to MONO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = acc_calc(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 0 +//static FILE * cymfile = NULL; + + + +#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) + + + +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 */ + UINT16 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) */ + UINT8 Muted; +} OPL_CH; + +/* OPL state */ +typedef struct fm_opl_f +{ + /* FM channel slots */ + OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ + UINT8 MuteSpc[6]; /* Mute Special: 5 Rhythm + 1 DELTA-T Channel */ + + 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 */ + UINT32 LFO_AM; + INT32 LFO_PM; + + 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 */ + + UINT32 T[2]; /* timer counters */ + UINT32 Trem[2]; + UINT8 st[2]; /* timer enable */ + +#if BUILD_Y8950 + /* Delta-T ADPCM unit (Y8950) */ + + YM_DELTAT *deltat; + + /* Keyboard and I/O ports interface */ + UINT8 portDirection; + UINT8 portLatch; + OPL_PORTHANDLER_R porthandler_r; + OPL_PORTHANDLER_W porthandler_w; + void * port_param; + OPL_PORTHANDLER_R keyboardhandler_r; + OPL_PORTHANDLER_W keyboardhandler_w; + void * keyboard_param; +#endif + + /* external event callback handlers */ + OPL_TIMERHANDLER timer_handler; /* TIMER handler */ + void *TimerParam; /* TIMER parameter */ + OPL_IRQHANDLER IRQHandler; /* IRQ handler */ + void *IRQParam; /* IRQ parameter */ + OPL_UPDATEHANDLER UpdateHandler;/* stream update handler */ + void *UpdateParam; /* stream update parameter */ + + UINT8 type; /* chip type */ + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 statusmask; /* status mask */ + UINT8 mode; /* Reg.08 : CSM,notesel,etc. */ + + UINT32 clock; /* master clock (Hz) */ + UINT32 rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + //attotime TimerBase; /* Timer base time (==sampling time)*/ + + signed int phase_modulation; /* phase modulation input (SLOT 2) */ + signed int output[1]; +#if BUILD_Y8950 + INT32 output_deltat[4]; /* for Y8950 DELTA-T, chip is mono, that 4 here is just for safety */ +#endif +} FM_OPL; + + + +/* mapping of register number (offset) to slot number used by the emulator */ +static const int slot_array[32]= +{ + 0, 2, 4, 1, 3, 5,-1,-1, + 6, 8,10, 7, 9,11,-1,-1, + 12,14,16,13,15,17,-1,-1, + -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) +static const UINT32 ksl_tab[8*16]= +{ + /* OCT 0 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + /* OCT 1 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV, + 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV, + /* OCT 2 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV, + 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV, + 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV, + /* OCT 3 */ + 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV, + 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV, + 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV, + 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV, + /* OCT 4 */ + 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV, + 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV, + 9.000/DV, 9.750/DV,10.125/DV,10.500/DV, + 10.875/DV,11.250/DV,11.625/DV,12.000/DV, + /* OCT 5 */ + 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV, + 9.000/DV,10.125/DV,10.875/DV,11.625/DV, + 12.000/DV,12.750/DV,13.125/DV,13.500/DV, + 13.875/DV,14.250/DV,14.625/DV,15.000/DV, + /* OCT 6 */ + 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV, + 12.000/DV,13.125/DV,13.875/DV,14.625/DV, + 15.000/DV,15.750/DV,16.125/DV,16.500/DV, + 16.875/DV,17.250/DV,17.625/DV,18.000/DV, + /* OCT 7 */ + 0.000/DV, 9.000/DV,12.000/DV,13.875/DV, + 15.000/DV,16.125/DV,16.875/DV,17.625/DV, + 18.000/DV,18.750/DV,19.125/DV,19.500/DV, + 19.875/DV,20.250/DV,20.625/DV,21.000/DV +}; +#undef DV + +/* 0 / 3.0 / 1.5 / 6.0 dB/OCT */ +static const UINT32 ksl_shift[4] = { 31, 1, 2, 0 }; + + +/* sustain level 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 */ + +/* 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) */ +}; + + +#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 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), + +/* 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 + + +/* multiple table */ +#define ML 2 +static const UINT8 mul_tab[16]= { +/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ + 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*ML +}; +#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 (losing 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*/ +}; + + +/* lock level of common table */ +static int num_lock = 0; + + +#define SLOT7_1 (&OPL->P_CH[7].SLOT[SLOT1]) +#define SLOT7_2 (&OPL->P_CH[7].SLOT[SLOT2]) +#define SLOT8_1 (&OPL->P_CH[8].SLOT[SLOT1]) +#define SLOT8_2 (&OPL->P_CH[8].SLOT[SLOT2]) + + + + +/*INLINE int limit( int val, int max, int min ) { + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +}*/ + + +/* status set and IRQ handling */ +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 */ + OPL->status |= 0x80; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); + } + } +} + +/* status reset and IRQ handling */ +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 &= 0x7f; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); + } + } +} + +/* IRQ mask set */ +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_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt >> LFO_SH ]; + + if (OPL->lfo_am_depth) + OPL->LFO_AM = tmp; + else + OPL->LFO_AM = tmp>>2; + + OPL->lfo_pm_cnt += OPL->lfo_pm_inc; + OPL->LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; +} + +INLINE void refresh_eg(FM_OPL* OPL) +{ + OPL_CH *CH; + OPL_SLOT *op; + int i; + int new_vol; + + 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<eg_sh_ar)-1) ) ) + { + new_vol = op->volume + ((~op->volume * + (eg_inc[op->eg_sel_ar + ((OPL->eg_cnt>>op->eg_sh_ar)&7)]) + ) >> 3); + if (new_vol <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + } + break; + /*case EG_DEC: // decay phase + if ( !(OPL->eg_cnt & ((1<eg_sh_dr)-1) ) ) + { + new_vol = op->volume + eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; + + if ( new_vol >= op->sl ) + op->state = EG_SUS; + } + break; + case EG_SUS: // sustain phase + if ( !op->eg_type) percussive mode + { + new_vol = op->volume + eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + if ( new_vol >= MAX_ATT_INDEX ) + op->volume = MAX_ATT_INDEX; + } + } + break; + case EG_REL: // release phase + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + new_vol = op->volume + eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + if ( new_vol >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + default: + break;*/ + } + } + + return; +} + +/* advance to next sample */ +INLINE void advance(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 < 2; i ++) + { + if (OPL->st[i]) + { + if (! OPL->Trem[i]) + OPLTimerOver(OPL, i); + OPL->Trem[i] --; + } + } + + 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<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<eg_sh_dr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; + + if ( op->volume >= op->sl ) + op->state = EG_SUS; + + } + 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<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<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; + } + + } + break; + + default: + break; + } + } + } + + 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; + unsigned int block_fnum = CH->block_fnum; + + unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; + + signed int lfo_fn_table_index_offset = lfo_pm_table[OPL->LFO_PM + 16*fnum_lfo ]; + + 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; + } + else /* LFO phase modulation = zero */ + { + op->Cnt += op->Incr; + } + } + else /* LFO phase modulation disabled for this operator */ + { + op->Cnt += op->Incr; + } + } + + /* 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) + { + /* + 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--; + } +} + + +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]; +} + +INLINE signed int op_calc1(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 )) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + + +#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (OPL->LFO_AM & (OP)->AMmask)) + +/* calculate output */ +INLINE void OPL_CALC_CH( FM_OPL *OPL, OPL_CH *CH ) +{ + OPL_SLOT *SLOT; + unsigned int env; + signed int out; + + if (CH->Muted) + return; + + OPL->phase_modulation = 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<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + OPL->output[0] += op_calc(SLOT->Cnt, env, OPL->phase_modulation, SLOT->wavetable); +} + +/* + 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 + + + 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( FM_OPL *OPL, OPL_CH *CH, unsigned int noise ) +{ + OPL_SLOT *SLOT; + signed int out; + unsigned int env; + + + /* 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 + */ + + OPL->phase_modulation = 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) + OPL->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<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET && ! OPL->MuteSpc[0] ) + OPL->output[0] += op_calc(SLOT->Cnt, env, OPL->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 && ! OPL->MuteSpc[4] ) + { + + /* 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; + } + 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; + } + + OPL->output[0] += op_calc(phase<wavetable) * 2; + } + + /* Snare Drum (verified on real YM3812) */ + env = volume_calc(SLOT7_2); + if( env < ENV_QUIET && ! OPL->MuteSpc[1] ) + { + /* 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; + + OPL->output[0] += op_calc(phase<wavetable) * 2; + } + + /* Tom Tom (verified on real YM3812) */ + env = volume_calc(SLOT8_1); + if( env < ENV_QUIET && ! OPL->MuteSpc[2] ) + OPL->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 && ! OPL->MuteSpc[3] ) + { + /* 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; + + OPL->output[0] += op_calc(phase<wavetable) * 2; + } +} + + +/* generic table initialize */ +static int init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + + for (x=0; x>= 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 + } + /*logerror("FMOPL.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ + + + for (i=0; i0.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]] );*/ + } + + for (i=0; i>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]] );*/ + } + /*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 */ + OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / 72.0) / OPL->rate : 0; +#if 0 + OPL->rate = (double)OPL->clock / 72.0; + OPL->freqbase = 1.0; +#endif + + /*logerror("freqbase=%f\n", OPL->freqbase);*/ + + /* Timer base time */ + //OPL->TimerBase = attotime_mul(ATTOTIME_IN_HZ(OPL->clock), 72); + + /* 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 + } + +#if 0 + for( i=0 ; i < 16 ; i++ ) + { + logerror("FMOPL.C: sl_tab[%i] = %08x\n", + i, sl_tab[i] ); + } + 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"); + } +#endif + + for(i = 0; i < 9; i ++) + OPL->P_CH[i].Muted = 0x00; + for(i = 0; i < 6; i ++) + OPL->MuteSpc[i] = 0x00; + + + /* 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 = (1.0 / 64.0 ) * (1<freqbase; + + /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ + OPL->lfo_pm_inc = (1.0 / 1024.0) * (1<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 = (1.0 / 1.0) * (1<freqbase; + + OPL->eg_timer_add = (1<freqbase; + OPL->eg_timer_overflow = ( 1 ) * (1<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; + } + 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; + } + } +} + +/* 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 ]; + } +} + +/* 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]; + + SLOT->ksl = ksl_shift[v >> 6]; + SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ + + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); +} + +/* 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; + + 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->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 ]; +} + +/* 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) +{ + OPL_CH *CH; + int slot; + int block_fnum; + + + /* adjust bus to 8 bits */ + r &= 0xff; + v &= 0xff; + + /*if (LOG_CYM_FILE && (cymfile) && (r!=0) ) + { + fputc( (unsigned char)r, cymfile ); + fputc( (unsigned char)v, cymfile ); + }*/ + + + 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 */ + } + break; + case 0x02: /* Timer 1 */ + OPL->T[0] = (256-v)*4; + break; + case 0x03: /* Timer 2 */ + OPL->T[1] = (256-v)*16; + break; + case 0x04: /* IRQ clear / mask and Timer enable */ + if(v&0x80) + { /* IRQ flag clear */ + OPL_STATUS_RESET(OPL,0x7f-0x08); /* don't reset BFRDY flag or we will have to call deltat module to set the flag */ + } + 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-0x08) ); + OPL_STATUSMASK_SET(OPL, (~v) & 0x78 ); + + /* timer 2 */ + if(OPL->st[1] != st2) + { + //attotime period = st2 ? attotime_mul(OPL->TimerBase, OPL->T[1]) : attotime_zero; + OPL->st[1] = st2; + //if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,1,period); + } + /* timer 1 */ + if(OPL->st[0] != st1) + { + //attotime period = st1 ? attotime_mul(OPL->TimerBase, OPL->T[0]) : attotime_zero; + OPL->st[0] = st1; + //if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,0,period); + } + } + 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); +#ifdef _DEBUG + else + logerror("Y8950: write unmapped KEYBOARD port\n"); +#endif + } + break; + case 0x07: /* DELTA-T control 1 : 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 control 2 : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ + OPL->mode = v; +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v&0x0f); /* mask 4 LSBs in register 08 for DELTA-T unit */ +#endif + break; + +#if BUILD_Y8950 + case 0x09: /* START ADD */ + case 0x0a: + case 0x0b: /* STOP ADD */ + case 0x0c: + case 0x0d: /* PRESCALE */ + case 0x0e: + case 0x0f: /* ADPCM data write */ + case 0x10: /* DELTA-N */ + case 0x11: /* DELTA-N */ + case 0x12: /* ADPCM volume */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + break; + + case 0x15: /* DAC data high 8 bits (F7,F6...F2) */ + case 0x16: /* DAC data low 2 bits (F1, F0 in bits 7,6) */ + case 0x17: /* DAC data shift (S2,S1,S0 in bits 2,1,0) */ +#ifdef _DEBUG + logerror("FMOPL.C: DAC data register written, but not implemented reg=%02x val=%02x\n",r,v); +#endif + 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; +#endif + default: +#ifdef _DEBUG + logerror("FMOPL.C: write to unknown register: %02x\n",r); +#endif + break; + } + break; + case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_mul(OPL,slot,v); + break; + case 0x40: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ksl_tl(OPL,slot,v); + break; + case 0x60: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ar_dr(OPL,slot,v); + break; + case 0x80: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_sl_rr(OPL,slot,v); + break; + 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) + { + /* 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); + } + /* 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); + /* 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); + } + 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; + } + 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); + } + } + /* update */ + if(CH->block_fnum != block_fnum) + { + UINT8 block = block_fnum >> 10; + + 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 */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + break; + case 0xc0: + /* FB,C */ + 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 ? &OPL->output[0] : &OPL->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; + } + break; + } +} + +/*static TIMER_CALLBACK( cymfile_callback ) +{ + if (cymfile) + { + fputc( (unsigned char)0, cymfile ); + } +}*/ + +/* lock/unlock for common table */ +static int OPL_LockTable(void) +{ + num_lock++; + if(num_lock>1) return 0; + + /* first time */ + + /* allocate total level table (128kb space) */ + if( !init_tables() ) + { + num_lock--; + return -1; + } + + /*if (LOG_CYM_FILE) + { + cymfile = fopen("3812_.cym","wb"); + if (cymfile) + timer_pulse ( device->machine, ATTOTIME_IN_HZ(110), NULL, 0, cymfile_callback); //110 Hz pulse timer + else + logerror("Could not create file 3812_.cym\n"); + }*/ + + return 0; +} + +static void OPL_UnLockTable(void) +{ + if(num_lock) num_lock--; + if(num_lock) return; + + /* last time */ + + OPLCloseTable(); + + /*if (cymfile) + fclose (cymfile); + cymfile = NULL;*/ +} + +static 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 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 */ + OPL->Trem[0] = OPL->Trem[1] = 0; + for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); + + /* reset operator parameters */ + for( c = 0 ; c < 9 ; c++ ) + { + OPL_CH *CH = &OPL->P_CH[c]; + 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; + } + } +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + { + YM_DELTAT *DELTAT = OPL->deltat; + + DELTAT->freqbase = OPL->freqbase; + DELTAT->output_pointer = &OPL->output_deltat[0]; + DELTAT->portshift = 5; + DELTAT->output_range = 1<<23; + YM_DELTAT_ADPCM_Reset(DELTAT,0,YM_DELTAT_EMULATION_MODE_NORMAL); + } +#endif +} + + +#if 0 +//static STATE_POSTLOAD( OPL_postload ) +static void OPL_postload(void* param) +{ + FM_OPL *OPL = (FM_OPL *)param; + int slot, ch; + + for( ch=0 ; ch < 9 ; ch++ ) + { + OPL_CH *CH = &OPL->P_CH[ch]; + + /* Look up key scale level */ + UINT32 block_fnum = CH->block_fnum; + CH->ksl_base = ksl_tab[block_fnum >> 6]; + CH->fc = OPL->fn_tab[block_fnum & 0x03ff] >> (7 - (block_fnum >> 10)); + + for( slot=0 ; slot < 2 ; slot++ ) + { + OPL_SLOT *SLOT = &CH->SLOT[slot]; + + /* Calculate key scale rate */ + SLOT->ksr = CH->kcode >> SLOT->KSR; + + /* Calculate attack, decay and release 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 ]; + + /* Calculate phase increment */ + SLOT->Incr = CH->fc * SLOT->mul; + + /* Total level */ + SLOT->TLL = SLOT->TL + (CH->ksl_base >> SLOT->ksl); + + /* Connect output */ + SLOT->connect1 = SLOT->CON ? &OPL->output[0] : &OPL->phase_modulation; + } + } +#if BUILD_Y8950 + if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) ) + { + // We really should call the postlod function for the YM_DELTAT, but it's hard without registers + // (see the way the YM2610 does it) + //YM_DELTAT_postload(OPL->deltat, REGS); + } +#endif +} + + +static void OPLsave_state_channel(OPL_CH *CH) +{ + int slot, ch; + + for( ch=0 ; ch < 9 ; ch++, CH++ ) + { + // channel + state_save_register_device_item(device, ch, CH->block_fnum); + state_save_register_device_item(device, ch, CH->kcode); + // slots + for( slot=0 ; slot < 2 ; slot++ ) + { + OPL_SLOT *SLOT = &CH->SLOT[slot]; + + state_save_register_device_item(device, ch * 2 + slot, SLOT->ar); + state_save_register_device_item(device, ch * 2 + slot, SLOT->dr); + state_save_register_device_item(device, ch * 2 + slot, SLOT->rr); + state_save_register_device_item(device, ch * 2 + slot, SLOT->KSR); + state_save_register_device_item(device, ch * 2 + slot, SLOT->ksl); + state_save_register_device_item(device, ch * 2 + slot, SLOT->mul); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->Cnt); + state_save_register_device_item(device, ch * 2 + slot, SLOT->FB); + state_save_register_device_item_array(device, ch * 2 + slot, SLOT->op1_out); + state_save_register_device_item(device, ch * 2 + slot, SLOT->CON); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->eg_type); + state_save_register_device_item(device, ch * 2 + slot, SLOT->state); + state_save_register_device_item(device, ch * 2 + slot, SLOT->TL); + state_save_register_device_item(device, ch * 2 + slot, SLOT->volume); + state_save_register_device_item(device, ch * 2 + slot, SLOT->sl); + state_save_register_device_item(device, ch * 2 + slot, SLOT->key); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->AMmask); + state_save_register_device_item(device, ch * 2 + slot, SLOT->vib); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->wavetable); + } + } +} +#endif + + +/* Register savestate for a virtual YM3812/YM3526/Y8950 */ + +/*static void OPL_save_state(FM_OPL *OPL) +{ + OPLsave_state_channel(device, OPL->P_CH); + + state_save_register_device_item(device, 0, OPL->eg_cnt); + state_save_register_device_item(device, 0, OPL->eg_timer); + + state_save_register_device_item(device, 0, OPL->rhythm); + + state_save_register_device_item(device, 0, OPL->lfo_am_depth); + state_save_register_device_item(device, 0, OPL->lfo_pm_depth_range); + state_save_register_device_item(device, 0, OPL->lfo_am_cnt); + state_save_register_device_item(device, 0, OPL->lfo_pm_cnt); + + state_save_register_device_item(device, 0, OPL->noise_rng); + state_save_register_device_item(device, 0, OPL->noise_p); + + if( OPL->type & OPL_TYPE_WAVESEL ) + { + state_save_register_device_item(device, 0, OPL->wavesel); + } + + state_save_register_device_item_array(device, 0, OPL->T); + state_save_register_device_item_array(device, 0, OPL->st); + +#if BUILD_Y8950 + if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) ) + { + YM_DELTAT_savestate(device, OPL->deltat); + } + + if ( OPL->type & OPL_TYPE_IO ) + { + state_save_register_device_item(device, 0, OPL->portDirection); + state_save_register_device_item(device, 0, OPL->portLatch); + } +#endif + + state_save_register_device_item(device, 0, OPL->address); + state_save_register_device_item(device, 0, OPL->status); + state_save_register_device_item(device, 0, OPL->statusmask); + state_save_register_device_item(device, 0, OPL->mode); + + state_save_register_postload(device->machine, OPL_postload, OPL); +}*/ + + +/* Create one of virtual YM3812/YM3526/Y8950 */ +/* 'clock' is chip clock in Hz */ +/* 'rate' is sampling rate */ +static FM_OPL *OPLCreate(UINT32 clock, UINT32 rate, int type) +{ + char *ptr; + FM_OPL *OPL; + int state_size; + + if (OPL_LockTable() == -1) return NULL; + + /* calculate OPL state size */ + state_size = sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); +#endif + + /* allocate memory block */ + ptr = (char *)malloc(state_size); + + 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 + + OPL->type = type; + OPL->clock = clock; + OPL->rate = rate; + + /* init global tables */ + OPL_initalize(OPL); + + return OPL; +} + +/* Destroy one of virtual YM3812 */ +static void OPLDestroy(FM_OPL *OPL) +{ + OPL_UnLockTable(); + free(OPL); +} + +/* Optional handlers */ + +static void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER timer_handler,void *param) +{ + OPL->timer_handler = timer_handler; + OPL->TimerParam = param; +} +static void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,void *param) +{ + OPL->IRQHandler = IRQHandler; + OPL->IRQParam = param; +} +static void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + OPL->UpdateHandler = UpdateHandler; + OPL->UpdateParam = param; +} + +static 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); + } + return OPL->status>>7; +} + +static unsigned char OPLRead(FM_OPL *OPL,int a) +{ + if( !(a&1) ) + { + /* status port */ + + #if BUILD_Y8950 + + if(OPL->type&OPL_TYPE_ADPCM) /* Y8950 */ + { + return (OPL->status & (OPL->statusmask|0x80)) | (OPL->deltat->PCM_BSY&1); + } + + #endif + + /* OPL and OPL2 */ + return OPL->status & (OPL->statusmask|0x80); + } + +#if BUILD_Y8950 + /* data port */ + switch(OPL->address) + { + case 0x05: /* KeyBoard IN */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_r) + return OPL->keyboardhandler_r(OPL->keyboard_param); +#ifdef _DEBUG + else + logerror("Y8950: read unmapped KEYBOARD port\n"); +#endif + } + return 0; + + case 0x0f: /* ADPCM-DATA */ + if(OPL->type&OPL_TYPE_ADPCM) + { + UINT8 val; + + val = YM_DELTAT_ADPCM_Read(OPL->deltat); + /*logerror("Y8950: read ADPCM value read=%02x\n",val);*/ + return val; + } + return 0; + + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + if(OPL->porthandler_r) + return OPL->porthandler_r(OPL->port_param); +#ifdef _DEBUG + else + logerror("Y8950:read unmapped I/O port\n"); +#endif + } + return 0; + case 0x1a: /* PCM-DATA */ + if(OPL->type&OPL_TYPE_ADPCM) + { +#ifdef _DEBUG + logerror("Y8950 A/D convertion is accessed but not implemented !\n"); +#endif + return 0x80; /* 2's complement PCM data - result from A/D convertion */ + } + 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); +} + + +static int OPLTimerOver(FM_OPL *OPL,int c) +{ + if( c ) + { /* Timer B */ + OPL_STATUS_SET(OPL,0x20); + } + 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 */ + int ch; + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam/*,0*/); + for(ch=0; ch<9; ch++) + CSMKeyControll( &OPL->P_CH[ch] ); + } + } + /* reload timer */ + OPL->Trem[c] = OPL->T[c]; + //if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,c,attotime_mul(OPL->TimerBase, OPL->T[c])); + return OPL->status>>7; +} + + +#define MAX_OPL_CHIPS 2 + + +#if (BUILD_YM3812) + +void * ym3812_init(UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *YM3812 = OPLCreate(clock,rate,OPL_TYPE_YM3812); + if (YM3812) + { + //OPL_save_state(YM3812); + ym3812_reset_chip(YM3812); + } + return YM3812; +} + +void ym3812_shutdown(void *chip) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + /* emulator shutdown */ + OPLDestroy(YM3812); +} +void ym3812_reset_chip(void *chip) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLResetChip(YM3812); +} + +int ym3812_write(void *chip, int a, int v) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + return OPLWrite(YM3812, a, v); +} + +unsigned char ym3812_read(void *chip, int a) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + /* YM3812 always returns bit2 and bit1 in HIGH state */ + return OPLRead(YM3812, a) | 0x06 ; +} +int ym3812_timer_over(void *chip, int c) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + return OPLTimerOver(YM3812, c); +} + +void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetTimerHandler(YM3812, timer_handler, param); +} +void ym3812_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetIRQHandler(YM3812, IRQHandler, param); +} +void ym3812_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetUpdateHandler(YM3812, UpdateHandler, param); +} + + +/* +** 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 ym3812_update_one(void *chip, OPLSAMPLE **buffer, int length) +{ + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *bufL = buffer[0]; + OPLSAMPLE *bufR = buffer[1]; + int i; + + if (! length) + { + refresh_eg(OPL); + return; + } + + for( i=0; i < length ; i++ ) + { + int lt; + + OPL->output[0] = 0; + + advance_lfo(OPL); + + /* FM part */ + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = OPL->output[0]; + + lt >>= FINAL_SH; + + /* limit check */ + //lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + bufL[i] = lt; + bufR[i] = lt; + + advance(OPL); + } + +} +#endif /* BUILD_YM3812 */ + + + +#if (BUILD_YM3526) + +void *ym3526_init(UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *YM3526 = OPLCreate(clock,rate,OPL_TYPE_YM3526); + if (YM3526) + { + //OPL_save_state(YM3526); + ym3526_reset_chip(YM3526); + } + return YM3526; +} + +void ym3526_shutdown(void *chip) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + /* emulator shutdown */ + OPLDestroy(YM3526); +} +void ym3526_reset_chip(void *chip) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLResetChip(YM3526); +} + +int ym3526_write(void *chip, int a, int v) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + return OPLWrite(YM3526, a, v); +} + +unsigned char ym3526_read(void *chip, int a) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + /* YM3526 always returns bit2 and bit1 in HIGH state */ + return OPLRead(YM3526, a) | 0x06 ; +} +int ym3526_timer_over(void *chip, int c) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + return OPLTimerOver(YM3526, c); +} + +void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetTimerHandler(YM3526, timer_handler, param); +} +void ym3526_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetIRQHandler(YM3526, IRQHandler, param); +} +void ym3526_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetUpdateHandler(YM3526, 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 ym3526_update_one(void *chip, OPLSAMPLE **buffer, int length) +{ + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *bufL = buffer[0]; + OPLSAMPLE *bufR = buffer[1]; + int i; + + for( i=0; i < length ; i++ ) + { + int lt; + + OPL->output[0] = 0; + + advance_lfo(OPL); + + /* FM part */ + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = OPL->output[0]; + + lt >>= FINAL_SH; + + /* limit check */ + //lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + bufL[i] = lt; + bufR[i] = lt; + + advance(OPL); + } + +} +#endif /* BUILD_YM3526 */ + + + + +#if BUILD_Y8950 + +static void Y8950_deltat_status_set(void *chip, UINT8 changebits) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPL_STATUS_SET(Y8950, changebits); +} +static void Y8950_deltat_status_reset(void *chip, UINT8 changebits) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPL_STATUS_RESET(Y8950, changebits); +} + +void *y8950_init(UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *Y8950 = OPLCreate(clock,rate,OPL_TYPE_Y8950); + if (Y8950) + { + Y8950->deltat->status_set_handler = Y8950_deltat_status_set; + Y8950->deltat->status_reset_handler = Y8950_deltat_status_reset; + Y8950->deltat->status_change_which_chip = Y8950; + Y8950->deltat->status_change_EOS_bit = 0x10; /* status flag: set bit4 on End Of Sample */ + Y8950->deltat->status_change_BRDY_bit = 0x08; /* status flag: set bit3 on BRDY (End Of: ADPCM analysis/synthesis, memory reading/writing) */ + + /*Y8950->deltat->write_time = 10.0 / clock;*/ /* a single byte write takes 10 cycles of main clock */ + /*Y8950->deltat->read_time = 8.0 / clock;*/ /* a single byte read takes 8 cycles of main clock */ + /* reset */ + //OPL_save_state(Y8950); + y8950_reset_chip(Y8950); + } + + return Y8950; +} + +void y8950_shutdown(void *chip) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + + free(Y8950->deltat->memory); Y8950->deltat->memory = NULL; + + /* emulator shutdown */ + OPLDestroy(Y8950); +} +void y8950_reset_chip(void *chip) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLResetChip(Y8950); +} + +int y8950_write(void *chip, int a, int v) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLWrite(Y8950, a, v); +} + +unsigned char y8950_read(void *chip, int a) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLRead(Y8950, a); +} +int y8950_timer_over(void *chip, int c) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLTimerOver(Y8950, c); +} + +void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetTimerHandler(Y8950, timer_handler, param); +} +void y8950_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetIRQHandler(Y8950, IRQHandler, param); +} +void y8950_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetUpdateHandler(Y8950, UpdateHandler, param); +} + +void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size ) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->deltat->memory = (UINT8 *)(deltat_mem_ptr); + OPL->deltat->memory_size = deltat_mem_size; +} + +void y8950_write_pcmrom(void *chip, offs_t ROMSize, offs_t DataStart, + offs_t DataLength, const UINT8* ROMData) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + + if (Y8950->deltat->memory_size != ROMSize) + { + Y8950->deltat->memory = (UINT8*)realloc(Y8950->deltat->memory, ROMSize); + Y8950->deltat->memory_size = ROMSize; + memset(Y8950->deltat->memory, 0xFF, ROMSize); + YM_DELTAT_calc_mem_mask(Y8950->deltat); + } + if (DataStart > ROMSize) + return; + if (DataStart + DataLength > ROMSize) + DataLength = ROMSize - DataStart; + + memcpy(Y8950->deltat->memory + DataStart, ROMData, DataLength); + + return; +} + +/* +** 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 y8950_update_one(void *chip, OPLSAMPLE **buffer, int length) +{ + int i; + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + YM_DELTAT *DELTAT = OPL->deltat; + OPLSAMPLE *bufL = buffer[0]; + OPLSAMPLE *bufR = buffer[1]; + + for( i=0; i < length ; i++ ) + { + int lt; + + OPL->output[0] = 0; + OPL->output_deltat[0] = 0; + + advance_lfo(OPL); + + /* deltaT ADPCM */ + if( DELTAT->portstate&0x80 && ! OPL->MuteSpc[5] ) + YM_DELTAT_ADPCM_CALC(DELTAT); + + /* FM part */ + OPL_CALC_CH(OPL, &OPL->P_CH[0]); + OPL_CALC_CH(OPL, &OPL->P_CH[1]); + OPL_CALC_CH(OPL, &OPL->P_CH[2]); + OPL_CALC_CH(OPL, &OPL->P_CH[3]); + OPL_CALC_CH(OPL, &OPL->P_CH[4]); + OPL_CALC_CH(OPL, &OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(OPL, &OPL->P_CH[6]); + OPL_CALC_CH(OPL, &OPL->P_CH[7]); + OPL_CALC_CH(OPL, &OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(OPL, &OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = OPL->output[0] + (OPL->output_deltat[0]>>11); + + lt >>= FINAL_SH; + + /* limit check */ + //lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + bufL[i] = lt; + bufR[i] = lt; + + advance(OPL); + } + +} + +void y8950_set_port_handler(void *chip,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,void * param) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->porthandler_w = PortHandler_w; + OPL->porthandler_r = PortHandler_r; + OPL->port_param = param; +} + +void y8950_set_keyboard_handler(void *chip,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,void * param) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->keyboardhandler_w = KeyboardHandler_w; + OPL->keyboardhandler_r = KeyboardHandler_r; + OPL->keyboard_param = param; +} + +#endif + +void opl_set_mute_mask(void *chip, UINT32 MuteMask) +{ + FM_OPL *opl = (FM_OPL *)chip; + UINT8 CurChn; + + for (CurChn = 0; CurChn < 9; CurChn ++) + opl->P_CH[CurChn].Muted = (MuteMask >> CurChn) & 0x01; + for (CurChn = 0; CurChn < 6; CurChn ++) + opl->MuteSpc[CurChn] = (MuteMask >> (9 + CurChn)) & 0x01; + + return; +} diff --git a/16/vgmsnd/fmopl.h b/16/vgmsnd/fmopl.h new file mode 100644 index 00000000..7a2db3a4 --- /dev/null +++ b/16/vgmsnd/fmopl.h @@ -0,0 +1,118 @@ +#pragma once + +//#include "attotime.h" + +/* --- select emulation chips --- */ +//#define BUILD_YM3812 (HAS_YM3812) +//#define BUILD_YM3526 (HAS_YM3526) +//#define BUILD_Y8950 (HAS_Y8950) +#define BUILD_YM3812 1 +#define BUILD_YM3526 0 +#define BUILD_Y8950 0 + +/* select output bits size of output : 8 or 16 */ +#define OPL_SAMPLE_BITS 16 + +/* compiler dependence */ +/*#ifndef __OSDCOMM_H__ +#define __OSDCOMM_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*/ /* __OSDCOMM_H__ */ + +typedef stream_sample_t OPLSAMPLE; +/* +#if (OPL_SAMPLE_BITS==16) +typedef INT16 OPLSAMPLE; +#endif +#if (OPL_SAMPLE_BITS==8) +typedef INT8 OPLSAMPLE; +#endif +*/ + +//typedef void (*OPL_TIMERHANDLER)(void *param,int timer,attotime period); +typedef void (*OPL_TIMERHANDLER)(void *param,int timer,int period); +typedef void (*OPL_IRQHANDLER)(void *param,int irq); +typedef void (*OPL_UPDATEHANDLER)(void *param/*,int min_interval_us*/); +typedef void (*OPL_PORTHANDLER_W)(void *param,unsigned char data); +typedef unsigned char (*OPL_PORTHANDLER_R)(void *param); + + +#if BUILD_YM3812 + +void *ym3812_init(UINT32 clock, UINT32 rate); +void ym3812_shutdown(void *chip); +void ym3812_reset_chip(void *chip); +int ym3812_write(void *chip, int a, int v); +unsigned char ym3812_read(void *chip, int a); +int ym3812_timer_over(void *chip, int c); +void ym3812_update_one(void *chip, OPLSAMPLE **buffer, int length); + +void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void ym3812_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void ym3812_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_YM3812 */ + + +#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 +*/ +void *ym3526_init(UINT32 clock, UINT32 rate); +/* shutdown the YM3526 emulators*/ +void ym3526_shutdown(void *chip); +void ym3526_reset_chip(void *chip); +int ym3526_write(void *chip, int a, int v); +unsigned char ym3526_read(void *chip, int a); +int ym3526_timer_over(void *chip, 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 ym3526_update_one(void *chip, OPLSAMPLE **buffer, int length); + +void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void ym3526_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void ym3526_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_YM3526 */ + + +#if BUILD_Y8950 + +/* Y8950 port handlers */ +void y8950_set_port_handler(void *chip, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, void *param); +void y8950_set_keyboard_handler(void *chip, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, void *param); +void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size ); +void y8950_write_pcmrom(void *chip, offs_t ROMSize, offs_t DataStart, + offs_t DataLength, const UINT8* ROMData); + +void * y8950_init(UINT32 clock, UINT32 rate); +void y8950_shutdown(void *chip); +void y8950_reset_chip(void *chip); +int y8950_write(void *chip, int a, int v); +unsigned char y8950_read (void *chip, int a); +int y8950_timer_over(void *chip, int c); +void y8950_update_one(void *chip, OPLSAMPLE **buffer, int length); + +void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void y8950_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void y8950_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_Y8950 */ + +void opl_set_mute_mask(void *chip, UINT32 MuteMask); + diff --git a/16/vgmsnd/main.c b/16/vgmsnd/main.c new file mode 100644 index 00000000..78bddc25 --- /dev/null +++ b/16/vgmsnd/main.c @@ -0,0 +1,277 @@ +#ifdef _WIN32 +#ifdef _DEBUG +#include +#endif +#endif + +#include +#include +#include +#include // for toupper() + + +#ifdef _WIN32 +int __cdecl _getch(void); // from conio.h +#else +#define _getch getchar +#endif + +#include +#include