summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/fm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/fm.cpp')
-rw-r--r--src/devices/sound/fm.cpp3917
1 files changed, 0 insertions, 3917 deletions
diff --git a/src/devices/sound/fm.cpp b/src/devices/sound/fm.cpp
deleted file mode 100644
index 23ea6633674..00000000000
--- a/src/devices/sound/fm.cpp
+++ /dev/null
@@ -1,3917 +0,0 @@
-// license:GPL-2.0+
-// copyright-holders:Jarek Burczynski,Tatsuyuki Satoh
-/*
-**
-** File: fm.c -- software implementation of Yamaha FM sound generator
-**
-** Copyright Jarek Burczynski (bujar at mame dot net)
-** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development
-**
-** Version 1.4.2 (final beta)
-**
-*/
-
-/*
-** History:
-**
-** 2006-2008 Eke-Eke (Genesis Plus GX), MAME backport by R. Belmont.
-** - implemented PG overflow, aka "detune bug" (Ariel, Comix Zone, Shaq Fu, Spiderman,...), credits to Nemesis
-** - fixed SSG-EG support, credits to Nemesis and additional fixes from Alone Coder
-** - modified EG rates and frequency, tested by Nemesis on real hardware
-** - implemented LFO phase update for CH3 special mode (Warlock birds, Alladin bug sound)
-** - fixed Attack Rate update (Batman & Robin intro)
-** - fixed attenuation level at the start of Substain (Gynoug explosions)
-** - fixed EG decay->substain transition to handle special cases, like SL=0 and Decay rate is very slow (Mega Turrican tracks 03,09...)
-**
-** 06-23-2007 Zsolt Vasvari:
-** - changed the timing not to require the use of floating point calculations
-**
-** 03-08-2003 Jarek Burczynski:
-** - fixed YM2608 initial values (after the reset)
-** - fixed flag and irqmask handling (YM2608)
-** - fixed BUFRDY flag handling (YM2608)
-**
-** 14-06-2003 Jarek Burczynski:
-** - implemented all of the YM2608 status register flags
-** - implemented support for external memory read/write via YM2608
-** - implemented support for deltat memory limit register in YM2608 emulation
-**
-** 22-05-2003 Jarek Burczynski:
-** - fixed LFO PM calculations (copy&paste bugfix)
-**
-** 08-05-2003 Jarek Burczynski:
-** - fixed SSG support
-**
-** 22-04-2003 Jarek Burczynski:
-** - implemented 100% correct LFO generator (verified on real YM2610 and YM2608)
-**
-** 15-04-2003 Jarek Burczynski:
-** - added support for YM2608's register 0x110 - status mask
-**
-** 01-12-2002 Jarek Burczynski:
-** - fixed register addressing in YM2608, YM2610, YM2610B chips. (verified on real YM2608)
-** The addressing patch used for early Neo-Geo games can be removed now.
-**
-** 26-11-2002 Jarek Burczynski, Nicola Salmoria:
-** - recreated YM2608 ADPCM ROM using data from real YM2608's output which leads to:
-** - added emulation of YM2608 drums.
-** - output of YM2608 is two times lower now - same as YM2610 (verified on real YM2608)
-**
-** 16-08-2002 Jarek Burczynski:
-** - binary exact Envelope Generator (verified on real YM2203);
-** identical to YM2151
-** - corrected 'off by one' error in feedback calculations (when feedback is off)
-** - corrected connection (algorithm) calculation (verified on real YM2203 and YM2610)
-**
-** 18-12-2001 Jarek Burczynski:
-** - added SSG-EG support (verified on real YM2203)
-**
-** 12-08-2001 Jarek Burczynski:
-** - corrected sin_tab and tl_tab data (verified on real chip)
-** - corrected feedback calculations (verified on real chip)
-** - corrected phase generator calculations (verified on real chip)
-** - corrected envelope generator calculations (verified on real chip)
-** - corrected FM volume level (YM2610 and YM2610B).
-** - changed YMxxxUpdateOne() functions (YM2203, YM2608, YM2610, YM2610B, YM2612) :
-** this was needed to calculate YM2610 FM channels output correctly.
-** (Each FM channel is calculated as in other chips, but the output of the channel
-** gets shifted right by one *before* sending to accumulator. That was impossible to do
-** with previous implementation).
-**
-** 23-07-2001 Jarek Burczynski, Nicola Salmoria:
-** - corrected YM2610 ADPCM type A algorithm and tables (verified on real chip)
-**
-** 11-06-2001 Jarek Burczynski:
-** - corrected end of sample bug in ADPCMA_calc_cha().
-** Real YM2610 checks for equality between current and end addresses (only 20 LSB bits).
-**
-** 08-12-98 hiro-shi:
-** rename ADPCMA -> ADPCMB, ADPCMB -> ADPCMA
-** move ROM limit check.(CALC_CH? -> 2610Write1/2)
-** test program (ADPCMB_TEST)
-** move ADPCM A/B end check.
-** ADPCMB repeat flag(no check)
-** change ADPCM volume rate (8->16) (32->48).
-**
-** 09-12-98 hiro-shi:
-** change ADPCM volume. (8->16, 48->64)
-** replace ym2610 ch0/3 (YM-2610B)
-** change ADPCM_SHIFT (10->8) missing bank change 0x4000-0xffff.
-** add ADPCM_SHIFT_MASK
-** change ADPCMA_DECODE_MIN/MAX.
-*/
-
-
-
-
-/************************************************************************/
-/* comment of hiro-shi(Hiromitsu Shioya) */
-/* YM2610(B) = OPN-B */
-/* YM2610 : PSG:3ch FM:4ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */
-/* YM2610B : PSG:3ch FM:6ch ADPCM(18.5KHz):6ch DeltaT ADPCM:1ch */
-/************************************************************************/
-
-#include "emu.h"
-
-#define YM2610B_WARNING
-#include "fm.h"
-
-
-/* include external DELTA-T unit (when needed) */
-#if (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B)
- #include "ymdeltat.h"
-#endif
-
-
-#if BUILD_YM2203
-#include "2203intf.h"
-#endif /* BUILD_YM2203 */
-
-#if BUILD_YM2608
-#include "2608intf.h"
-#endif /* BUILD_YM2608 */
-
-#if (BUILD_YM2610||BUILD_YM2610B)
-#include "2610intf.h"
-#endif /* (BUILD_YM2610||BUILD_YM2610B) */
-
-
-/* shared function building option */
-#define BUILD_OPN (BUILD_YM2203||BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B)
-#define BUILD_OPN_PRESCALER (BUILD_YM2203||BUILD_YM2608)
-
-
-/* globals */
-#define TYPE_SSG 0x01 /* SSG support */
-#define TYPE_LFOPAN 0x02 /* OPN type LFO and PAN */
-#define TYPE_6CH 0x04 /* FM 6CH / 3CH */
-#define TYPE_DAC 0x08 /* YM2612's DAC device */
-#define TYPE_ADPCM 0x10 /* two ADPCM units */
-#define TYPE_2610 0x20 /* bogus flag to differentiate 2608 from 2610 */
-
-
-#define TYPE_YM2203 (TYPE_SSG)
-#define TYPE_YM2608 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM)
-#define TYPE_YM2610 (TYPE_SSG |TYPE_LFOPAN |TYPE_6CH |TYPE_ADPCM |TYPE_2610)
-
-
-
-#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
-#define EG_SH 16 /* 16.16 fixed point (envelope generator 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<<FREQ_SH)-1)
-
-#define ENV_BITS 10
-#define ENV_LEN (1<<ENV_BITS)
-#define ENV_STEP (128.0/ENV_LEN)
-
-#define MAX_ATT_INDEX (ENV_LEN-1) /* 1023 */
-#define MIN_ATT_INDEX (0) /* 0 */
-
-#define EG_ATT 4
-#define EG_DEC 3
-#define EG_SUS 2
-#define EG_REL 1
-#define EG_OFF 0
-
-#define SIN_BITS 10
-#define SIN_LEN (1<<SIN_BITS)
-#define SIN_MASK (SIN_LEN-1)
-
-#define TL_RES_LEN (256) /* 8 bits addressing (real chip) */
-
-
-#if (FM_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
-
-
-/* TL_TAB_LEN is calculated as:
-* 13 - sinus amplitude bits (Y axis)
-* 2 - sinus sign bit (Y axis)
-* TL_RES_LEN - sinus resolution (X axis)
-*/
-#define TL_TAB_LEN (13*2*TL_RES_LEN)
-static signed int tl_tab[TL_TAB_LEN];
-
-#define ENV_QUIET (TL_TAB_LEN>>3)
-
-/* sin waveform table in 'decibel' scale */
-static unsigned int sin_tab[SIN_LEN];
-
-/* sustain level table (3dB per step) */
-/* bit0, bit1, bit2, bit3, bit4, bit5, bit6 */
-/* 1, 2, 4, 8, 16, 32, 64 (value)*/
-/* 0.75, 1.5, 3, 6, 12, 24, 48 (dB)*/
-
-/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
-#define SC(db) (uint32_t) ( db * (4.0/ENV_STEP) )
-static const uint32_t sl_table[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 uint8_t eg_inc[19*RATE_STEPS]={
-/*cycle:0 1 2 3 4 5 6 7*/
-
-/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..11 0 (increment by 0 or 1) */
-/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..11 1 */
-/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..11 2 */
-/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..11 3 */
-
-/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 12 0 (increment by 1) */
-/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 12 1 */
-/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 12 2 */
-/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 12 3 */
-
-/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 13 0 (increment by 2) */
-/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 13 1 */
-/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 13 2 */
-/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 13 3 */
-
-/*12 */ 4,4, 4,4, 4,4, 4,4, /* rate 14 0 (increment by 4) */
-/*13 */ 4,4, 4,8, 4,4, 4,8, /* rate 14 1 */
-/*14 */ 4,8, 4,8, 4,8, 4,8, /* rate 14 2 */
-/*15 */ 4,8, 8,8, 4,8, 8,8, /* rate 14 3 */
-
-/*16 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 8) */
-/*17 */ 16,16,16,16,16,16,16,16, /* rates 15 2, 15 3 for attack */
-/*18 */ 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(17) in this table - it's directly in the code */
-static const uint8_t eg_rate_select[32+64+32]={ /* Envelope Generator rates (32 + 64 rates + 32 RKS) */
-/* 32 infinite time rates */
-O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
-O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
-O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
-O(18),O(18),O(18),O(18),O(18),O(18),O(18),O(18),
-
-/* rates 00-11 */
-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 12 */
-O( 4),O( 5),O( 6),O( 7),
-
-/* rate 13 */
-O( 8),O( 9),O(10),O(11),
-
-/* rate 14 */
-O(12),O(13),O(14),O(15),
-
-/* rate 15 */
-O(16),O(16),O(16),O(16),
-
-/* 32 dummy rates (same as 15 3) */
-O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
-O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
-O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16),
-O(16),O(16),O(16),O(16),O(16),O(16),O(16),O(16)
-
-};
-
-#undef O
-
-/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15*/
-/*shift 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0 */
-/*mask 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0, 0 */
-
-#define O(a) (a*1)
-static const uint8_t eg_rate_shift[32+64+32]={ /* Envelope Generator counter shifts (32 + 64 rates + 32 RKS) */
-/* 32 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),
-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-11 */
-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 12 */
-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),
-
-/* 32 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),
-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
-
-static const uint8_t dt_tab[4 * 32]={
-/* this is YM2151 and YM2612 phase increment data (in 10.10 fixed point format)*/
-/* FD=0 */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-/* FD=1 */
- 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
- 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,
-/* FD=2 */
- 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
- 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16,
-/* FD=3 */
- 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
- 8 , 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22
-};
-
-
-/* OPN key frequency number -> key code follow table */
-/* fnum higher 4bit -> keycode lower 2bit */
-static const uint8_t opn_fktable[16] = {0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3};
-
-
-/* 8 LFO speed parameters */
-/* each value represents number of samples that one LFO level will last for */
-static const uint32_t lfo_samples_per_step[8] = {108, 77, 71, 67, 62, 44, 8, 5};
-
-
-
-/*There are 4 different LFO AM depths available, they are:
- 0 dB, 1.4 dB, 5.9 dB, 11.8 dB
- Here is how it is generated (in EG steps):
-
- 11.8 dB = 0, 2, 4, 6, 8, 10,12,14,16...126,126,124,122,120,118,....4,2,0
- 5.9 dB = 0, 1, 2, 3, 4, 5, 6, 7, 8....63, 63, 62, 61, 60, 59,.....2,1,0
- 1.4 dB = 0, 0, 0, 0, 1, 1, 1, 1, 2,...15, 15, 15, 15, 14, 14,.....0,0,0
-
- (1.4 dB is losing precision as you can see)
-
- It's implemented as generator from 0..126 with step 2 then a shift
- right N times, where N is:
- 8 for 0 dB
- 3 for 1.4 dB
- 1 for 5.9 dB
- 0 for 11.8 dB
-*/
-static const uint8_t lfo_ams_depth_shift[4] = {8, 3, 1, 0};
-
-
-
-/*There are 8 different LFO PM depths available, they are:
- 0, 3.4, 6.7, 10, 14, 20, 40, 80 (cents)
-
- Modulation level at each depth depends on F-NUMBER bits: 4,5,6,7,8,9,10
- (bits 8,9,10 = FNUM MSB from OCT/FNUM register)
-
- Here we store only first quarter (positive one) of full waveform.
- Full table (lfo_pm_table) containing all 128 waveforms is build
- at run (init) time.
-
- One value in table below represents 4 (four) basic LFO steps
- (1 PM step = 4 AM steps).
-
- For example:
- at LFO SPEED=0 (which is 108 samples per basic LFO step)
- one value from "lfo_pm_output" table lasts for 432 consecutive
- samples (4*108=432) and one full LFO waveform cycle lasts for 13824
- samples (32*432=13824; 32 because we store only a quarter of whole
- waveform in the table below)
-*/
-static const uint8_t lfo_pm_output[7*8][8]={ /* 7 bits meaningful (of F-NUMBER), 8 LFO output levels per one depth (out of 32), 8 LFO depths */
-/* FNUM BIT 4: 000 0001xxxx */
-/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 6 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 7 */ {0, 0, 0, 0, 1, 1, 1, 1},
-
-/* FNUM BIT 5: 000 0010xxxx */
-/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 5 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 6 */ {0, 0, 0, 0, 1, 1, 1, 1},
-/* DEPTH 7 */ {0, 0, 1, 1, 2, 2, 2, 3},
-
-/* FNUM BIT 6: 000 0100xxxx */
-/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 3 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 4 */ {0, 0, 0, 0, 0, 0, 0, 1},
-/* DEPTH 5 */ {0, 0, 0, 0, 1, 1, 1, 1},
-/* DEPTH 6 */ {0, 0, 1, 1, 2, 2, 2, 3},
-/* DEPTH 7 */ {0, 0, 2, 3, 4, 4, 5, 6},
-
-/* FNUM BIT 7: 000 1000xxxx */
-/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 1 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 2 */ {0, 0, 0, 0, 0, 0, 1, 1},
-/* DEPTH 3 */ {0, 0, 0, 0, 1, 1, 1, 1},
-/* DEPTH 4 */ {0, 0, 0, 1, 1, 1, 1, 2},
-/* DEPTH 5 */ {0, 0, 1, 1, 2, 2, 2, 3},
-/* DEPTH 6 */ {0, 0, 2, 3, 4, 4, 5, 6},
-/* DEPTH 7 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc},
-
-/* FNUM BIT 8: 001 0000xxxx */
-/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 1 */ {0, 0, 0, 0, 1, 1, 1, 1},
-/* DEPTH 2 */ {0, 0, 0, 1, 1, 1, 2, 2},
-/* DEPTH 3 */ {0, 0, 1, 1, 2, 2, 3, 3},
-/* DEPTH 4 */ {0, 0, 1, 2, 2, 2, 3, 4},
-/* DEPTH 5 */ {0, 0, 2, 3, 4, 4, 5, 6},
-/* DEPTH 6 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc},
-/* DEPTH 7 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18},
-
-/* FNUM BIT 9: 010 0000xxxx */
-/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 1 */ {0, 0, 0, 0, 2, 2, 2, 2},
-/* DEPTH 2 */ {0, 0, 0, 2, 2, 2, 4, 4},
-/* DEPTH 3 */ {0, 0, 2, 2, 4, 4, 6, 6},
-/* DEPTH 4 */ {0, 0, 2, 4, 4, 4, 6, 8},
-/* DEPTH 5 */ {0, 0, 4, 6, 8, 8, 0xa, 0xc},
-/* DEPTH 6 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18},
-/* DEPTH 7 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30},
-
-/* FNUM BIT10: 100 0000xxxx */
-/* DEPTH 0 */ {0, 0, 0, 0, 0, 0, 0, 0},
-/* DEPTH 1 */ {0, 0, 0, 0, 4, 4, 4, 4},
-/* DEPTH 2 */ {0, 0, 0, 4, 4, 4, 8, 8},
-/* DEPTH 3 */ {0, 0, 4, 4, 8, 8, 0xc, 0xc},
-/* DEPTH 4 */ {0, 0, 4, 8, 8, 8, 0xc,0x10},
-/* DEPTH 5 */ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18},
-/* DEPTH 6 */ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30},
-/* DEPTH 7 */ {0, 0,0x20,0x30,0x40,0x40,0x50,0x60},
-
-};
-
-/* all 128 LFO PM waveforms */
-static int32_t lfo_pm_table[128*8*32]; /* 128 combinations of 7 bits meaningful (of F-NUMBER), 8 LFO depths, 32 LFO output levels per one depth */
-
-
-
-
-
-/* register number to channel number , slot offset */
-#define OPN_CHAN(N) (N&3)
-#define OPN_SLOT(N) ((N>>2)&3)
-
-/* slot number */
-#define SLOT1 0
-#define SLOT2 2
-#define SLOT3 1
-#define SLOT4 3
-
-/* bit0 = Right enable , bit1 = Left enable */
-#define OUTD_RIGHT 1
-#define OUTD_LEFT 2
-#define OUTD_CENTER 3
-
-
-/* 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
-
-
-/* struct describing a single operator (SLOT) */
-struct FM_SLOT
-{
- int32_t *DT; /* detune :dt_tab[DT] */
- uint8_t KSR; /* key scale rate :3-KSR */
- uint32_t ar; /* attack rate */
- uint32_t d1r; /* decay rate */
- uint32_t d2r; /* sustain rate */
- uint32_t rr; /* release rate */
- uint8_t ksr; /* key scale rate :kcode>>(3-KSR) */
- uint32_t mul; /* multiple :ML_TABLE[ML] */
-
- /* Phase Generator */
- uint32_t phase; /* phase counter */
- int32_t Incr; /* phase step */
-
- /* Envelope Generator */
- uint8_t state; /* phase type */
- uint32_t tl; /* total level: TL << 3 */
- int32_t volume; /* envelope counter */
- uint32_t sl; /* sustain level:sl_table[SL] */
- uint32_t vol_out; /* current output from EG circuit (without AM from LFO) */
-
- uint8_t eg_sh_ar; /* (attack state) */
- uint8_t eg_sel_ar; /* (attack state) */
- uint8_t eg_sh_d1r; /* (decay state) */
- uint8_t eg_sel_d1r; /* (decay state) */
- uint8_t eg_sh_d2r; /* (sustain state) */
- uint8_t eg_sel_d2r; /* (sustain state) */
- uint8_t eg_sh_rr; /* (release state) */
- uint8_t eg_sel_rr; /* (release state) */
-
- uint8_t ssg; /* SSG-EG waveform */
- uint8_t ssgn; /* SSG-EG negated output */
-
- uint32_t key; /* 0=last key was KEY OFF, 1=KEY ON */
-
- /* LFO */
- uint32_t AMmask; /* AM enable flag */
-
-};
-
-struct FM_CH
-{
- FM_SLOT SLOT[4]; /* four SLOTs (operators) */
-
- uint8_t ALGO; /* algorithm */
- uint8_t FB; /* feedback shift */
- int32_t op1_out[2]; /* op1 output for feedback */
-
- int32_t *connect1; /* SLOT1 output pointer */
- int32_t *connect3; /* SLOT3 output pointer */
- int32_t *connect2; /* SLOT2 output pointer */
- int32_t *connect4; /* SLOT4 output pointer */
-
- int32_t *mem_connect;/* where to put the delayed sample (MEM) */
- int32_t mem_value; /* delayed sample (MEM) value */
-
- int32_t pms; /* channel PMS */
- uint8_t ams; /* channel AMS */
-
- uint32_t fc; /* fnum,blk:adjusted to sample rate */
- uint8_t kcode; /* key code: */
- uint32_t block_fnum; /* current blk/fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */
-};
-
-
-struct FM_ST
-{
- device_t *device;
- int clock; /* master clock (Hz) */
- int rate; /* sampling rate (Hz) */
- double freqbase; /* frequency base */
- int timer_prescaler; /* timer prescaler */
-#if FM_BUSY_FLAG_SUPPORT
- TIME_TYPE busy_expiry_time; /* expiry time of the busy status */
-#endif
- uint8_t address; /* address register */
- uint8_t irq; /* interrupt level */
- uint8_t irqmask; /* irq mask */
- uint8_t status; /* status flag */
- uint32_t mode; /* mode CSM / 3SLOT */
- uint8_t prescaler_sel; /* prescaler selector */
- uint8_t fn_h; /* freq latch */
- int32_t TA; /* timer a */
- int32_t TAC; /* timer a counter */
- uint8_t TB; /* timer b */
- int32_t TBC; /* timer b counter */
- /* local time tables */
- int32_t dt_tab[8][32]; /* DeTune table */
- /* Extention Timer and IRQ handler */
- FM_TIMERHANDLER timer_handler;
- FM_IRQHANDLER IRQ_Handler;
- const ssg_callbacks *SSG;
-};
-
-
-
-/***********************************************************/
-/* OPN unit */
-/***********************************************************/
-
-/* OPN 3slot struct */
-struct FM_3SLOT
-{
- uint32_t fc[3]; /* fnum3,blk3: calculated */
- uint8_t fn_h; /* freq3 latch */
- uint8_t kcode[3]; /* key code */
- uint32_t block_fnum[3]; /* current fnum value for this slot (can be different betweeen slots of one channel in 3slot mode) */
-};
-
-/* OPN/A/B common state */
-struct FM_OPN
-{
- uint8_t type; /* chip type */
- FM_ST ST; /* general state */
- FM_3SLOT SL3; /* 3 slot mode state */
- FM_CH *P_CH; /* pointer of CH */
- unsigned int pan[6*2]; /* fm channels output masks (0xffffffff = enable) */
-
- uint32_t eg_cnt; /* global envelope generator counter */
- uint32_t eg_timer; /* global envelope generator counter works at frequency = chipclock/64/3 */
- uint32_t eg_timer_add; /* step of eg_timer */
- uint32_t eg_timer_overflow;/* envelope generator timer overflows every 3 samples (on real chip) */
-
-
- /* there are 2048 FNUMs that can be generated using FNUM/BLK registers
- but LFO works with one more bit of a precision so we really need 4096 elements */
-
- uint32_t fn_table[4096]; /* fnumber->increment counter */
- uint32_t fn_max; /* maximal phase increment (used for phase overflow) */
-
- /* LFO */
- uint32_t LFO_AM; /* runtime LFO calculations helper */
- int32_t LFO_PM; /* runtime LFO calculations helper */
-
- uint32_t lfo_cnt;
- uint32_t lfo_inc;
-
- uint32_t lfo_freq[8]; /* LFO FREQ table */
-
- int32_t m2,c1,c2; /* Phase Modulation input for operators 2,3,4 */
- int32_t mem; /* one sample delay memory */
-
- int32_t out_fm[8]; /* outputs of working channels */
-
-#if (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B)
- int32_t out_adpcm[4]; /* channel output NONE,LEFT,RIGHT or CENTER for YM2608/YM2610 ADPCM */
- int32_t out_delta[4]; /* channel output NONE,LEFT,RIGHT or CENTER for YM2608/YM2610 DELTAT*/
-#endif
-};
-
-
-
-/* current chip state */
-
-/* log output level */
-#define LOG_ERR 3 /* ERROR */
-#define LOG_WAR 2 /* WARNING */
-#define LOG_INF 1 /* INFORMATION */
-#define LOG_LEVEL LOG_INF
-
-#ifndef __RAINE__
-#define LOG(d,n,x) do { if( (n)>=LOG_LEVEL ) d->logerror x; } while (0)
-#endif
-
-/* limitter */
-#define Limit(val, max,min) { \
- if ( val > max ) val = max; \
- else if ( val < min ) val = min; \
-}
-
-
-/* status set and IRQ handling */
-static inline void FM_STATUS_SET(FM_ST *ST,int flag)
-{
- /* set status flag */
- ST->status |= flag;
- if ( !(ST->irq) && (ST->status & ST->irqmask) )
- {
- ST->irq = 1;
- /* callback user interrupt handler (IRQ is OFF to ON) */
- if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->device,1);
- }
-}
-
-/* status reset and IRQ handling */
-static inline void FM_STATUS_RESET(FM_ST *ST,int flag)
-{
- /* reset status flag */
- ST->status &=~flag;
- if ( (ST->irq) && !(ST->status & ST->irqmask) )
- {
- ST->irq = 0;
- /* callback user interrupt handler (IRQ is ON to OFF) */
- if(ST->IRQ_Handler) (ST->IRQ_Handler)(ST->device,0);
- }
-}
-
-/* IRQ mask set */
-static inline void FM_IRQMASK_SET(FM_ST *ST,int flag)
-{
- ST->irqmask = flag;
- /* IRQ handling check */
- FM_STATUS_SET(ST,0);
- FM_STATUS_RESET(ST,0);
-}
-
-/* OPN Mode Register Write */
-static inline void set_timers( FM_ST *ST, device_t *n, int v )
-{
- /* b7 = CSM MODE */
- /* b6 = 3 slot mode */
- /* b5 = reset b */
- /* b4 = reset a */
- /* b3 = timer enable b */
- /* b2 = timer enable a */
- /* b1 = load b */
- /* b0 = load a */
- ST->mode = v;
-
- /* reset Timer b flag */
- if( v & 0x20 )
- FM_STATUS_RESET(ST,0x02);
- /* reset Timer a flag */
- if( v & 0x10 )
- FM_STATUS_RESET(ST,0x01);
- /* load b */
- if( v & 0x02 )
- {
- if( ST->TBC == 0 )
- {
- ST->TBC = ( 256-ST->TB)<<4;
- /* External timer handler */
- if (ST->timer_handler) (ST->timer_handler)(n,1,ST->TBC * ST->timer_prescaler,ST->clock);
- }
- }
- else
- { /* stop timer b */
- if( ST->TBC != 0 )
- {
- ST->TBC = 0;
- if (ST->timer_handler) (ST->timer_handler)(n,1,0,ST->clock);
- }
- }
- /* load a */
- if( v & 0x01 )
- {
- if( ST->TAC == 0 )
- {
- ST->TAC = (1024-ST->TA);
- /* External timer handler */
- if (ST->timer_handler) (ST->timer_handler)(n,0,ST->TAC * ST->timer_prescaler,ST->clock);
- }
- }
- else
- { /* stop timer a */
- if( ST->TAC != 0 )
- {
- ST->TAC = 0;
- if (ST->timer_handler) (ST->timer_handler)(n,0,0,ST->clock);
- }
- }
-}
-
-
-/* Timer A Overflow */
-static inline void TimerAOver(FM_ST *ST)
-{
- /* set status (if enabled) */
- if(ST->mode & 0x04) FM_STATUS_SET(ST,0x01);
- /* clear or reload the counter */
- ST->TAC = (1024-ST->TA);
- if (ST->timer_handler) (ST->timer_handler)(ST->device,0,ST->TAC * ST->timer_prescaler,ST->clock);
-}
-/* Timer B Overflow */
-static inline void TimerBOver(FM_ST *ST)
-{
- /* set status (if enabled) */
- if(ST->mode & 0x08) FM_STATUS_SET(ST,0x02);
- /* clear or reload the counter */
- ST->TBC = ( 256-ST->TB)<<4;
- if (ST->timer_handler) (ST->timer_handler)(ST->device,1,ST->TBC * ST->timer_prescaler,ST->clock);
-}
-
-
-#if FM_INTERNAL_TIMER
-/* ----- internal timer mode , update timer */
-
-/* ---------- calculate timer A ---------- */
- #define INTERNAL_TIMER_A(ST,CSM_CH) \
- { \
- if( ST->TAC && (ST->timer_handler==0) ) \
- if( (ST->TAC -= (int)(ST->freqbase*4096)) <= 0 ) \
- { \
- TimerAOver( ST ); \
- /* CSM mode total level latch and auto key on */ \
- if( ST->mode & 0x80 ) \
- CSMKeyControll( CSM_CH ); \
- } \
- }
-/* ---------- calculate timer B ---------- */
- #define INTERNAL_TIMER_B(ST,step) \
- { \
- if( ST->TBC && (ST->timer_handler==0) ) \
- if( (ST->TBC -= (int)(ST->freqbase*4096*step)) <= 0 ) \
- TimerBOver( ST ); \
- }
-#else /* FM_INTERNAL_TIMER */
-/* external timer mode */
-#define INTERNAL_TIMER_A(ST,CSM_CH)
-#define INTERNAL_TIMER_B(ST,step)
-#endif /* FM_INTERNAL_TIMER */
-
-
-
-#if FM_BUSY_FLAG_SUPPORT
-#define FM_BUSY_CLEAR(ST) ((ST)->busy_expiry_time = UNDEFINED_TIME)
-static inline uint8_t FM_STATUS_FLAG(FM_ST *ST)
-{
- if( COMPARE_TIMES(ST->busy_expiry_time, UNDEFINED_TIME) != 0 )
- {
- if (COMPARE_TIMES(ST->busy_expiry_time, FM_GET_TIME_NOW(&ST->device->machine())) > 0)
- return ST->status | 0x80; /* with busy */
- /* expire */
- FM_BUSY_CLEAR(ST);
- }
- return ST->status;
-}
-static inline void FM_BUSY_SET(FM_ST *ST,int busyclock )
-{
- TIME_TYPE expiry_period = MULTIPLY_TIME_BY_INT(attotime::from_hz(ST->clock), busyclock * ST->timer_prescaler);
- ST->busy_expiry_time = ADD_TIMES(FM_GET_TIME_NOW(&ST->device->machine()), expiry_period);
-}
-#else
-#define FM_STATUS_FLAG(ST) ((ST)->status)
-#define FM_BUSY_SET(ST,bclock) {}
-#define FM_BUSY_CLEAR(ST) {}
-#endif
-
-
-
-
-static inline void FM_KEYON(uint8_t type, FM_CH *CH , int s )
-{
- FM_SLOT *SLOT = &CH->SLOT[s];
- if( !SLOT->key )
- {
- SLOT->key = 1;
- SLOT->phase = 0; /* restart Phase Generator */
- SLOT->ssgn = (SLOT->ssg & 0x04) >> 1;
- SLOT->state = EG_ATT;
- }
-}
-
-static inline void FM_KEYOFF(FM_CH *CH , int s )
-{
- FM_SLOT *SLOT = &CH->SLOT[s];
- if( SLOT->key )
- {
- SLOT->key = 0;
- if (SLOT->state>EG_REL)
- SLOT->state = EG_REL;/* phase -> Release */
- }
-}
-
-/* set algorithm connection */
-static void setup_connection( FM_OPN *OPN, FM_CH *CH, int ch )
-{
- int32_t *carrier = &OPN->out_fm[ch];
-
- int32_t **om1 = &CH->connect1;
- int32_t **om2 = &CH->connect3;
- int32_t **oc1 = &CH->connect2;
-
- int32_t **memc = &CH->mem_connect;
-
- switch( CH->ALGO )
- {
- case 0:
- /* M1---C1---MEM---M2---C2---OUT */
- *om1 = &OPN->c1;
- *oc1 = &OPN->mem;
- *om2 = &OPN->c2;
- *memc= &OPN->m2;
- break;
- case 1:
- /* M1------+-MEM---M2---C2---OUT */
- /* C1-+ */
- *om1 = &OPN->mem;
- *oc1 = &OPN->mem;
- *om2 = &OPN->c2;
- *memc= &OPN->m2;
- break;
- case 2:
- /* M1-----------------+-C2---OUT */
- /* C1---MEM---M2-+ */
- *om1 = &OPN->c2;
- *oc1 = &OPN->mem;
- *om2 = &OPN->c2;
- *memc= &OPN->m2;
- break;
- case 3:
- /* M1---C1---MEM------+-C2---OUT */
- /* M2-+ */
- *om1 = &OPN->c1;
- *oc1 = &OPN->mem;
- *om2 = &OPN->c2;
- *memc= &OPN->c2;
- break;
- case 4:
- /* M1---C1-+-OUT */
- /* M2---C2-+ */
- /* MEM: not used */
- *om1 = &OPN->c1;
- *oc1 = carrier;
- *om2 = &OPN->c2;
- *memc= &OPN->mem; /* store it anywhere where it will not be used */
- break;
- case 5:
- /* +----C1----+ */
- /* M1-+-MEM---M2-+-OUT */
- /* +----C2----+ */
- *om1 = nullptr; /* special mark */
- *oc1 = carrier;
- *om2 = carrier;
- *memc= &OPN->m2;
- break;
- case 6:
- /* M1---C1-+ */
- /* M2-+-OUT */
- /* C2-+ */
- /* MEM: not used */
- *om1 = &OPN->c1;
- *oc1 = carrier;
- *om2 = carrier;
- *memc= &OPN->mem; /* store it anywhere where it will not be used */
- break;
- case 7:
- /* M1-+ */
- /* C1-+-OUT */
- /* M2-+ */
- /* C2-+ */
- /* MEM: not used*/
- *om1 = carrier;
- *oc1 = carrier;
- *om2 = carrier;
- *memc= &OPN->mem; /* store it anywhere where it will not be used */
- break;
- }
-
- CH->connect4 = carrier;
-}
-
-/* set detune & multiple */
-static inline void set_det_mul(FM_ST *ST,FM_CH *CH,FM_SLOT *SLOT,int v)
-{
- SLOT->mul = (v&0x0f)? (v&0x0f)*2 : 1;
- SLOT->DT = ST->dt_tab[(v>>4)&7];
- CH->SLOT[SLOT1].Incr=-1;
-}
-
-/* set total level */
-static inline void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v)
-{
- SLOT->tl = (v&0x7f)<<(ENV_BITS-7); /* 7bit TL */
-}
-
-/* set attack rate & key scale */
-static inline void set_ar_ksr(uint8_t type, FM_CH *CH,FM_SLOT *SLOT,int v)
-{
- uint8_t old_KSR = SLOT->KSR;
-
- SLOT->ar = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
-
- SLOT->KSR = 3-(v>>6);
- if (SLOT->KSR != old_KSR)
- {
- CH->SLOT[SLOT1].Incr=-1;
- }
-
- /* refresh Attack rate */
- if ((SLOT->ar + SLOT->ksr) < 32+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 = 17*RATE_STEPS;
- }
-}
-
-/* set decay rate */
-static inline void set_dr(uint8_t type, FM_SLOT *SLOT,int v)
-{
- SLOT->d1r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
-
- SLOT->eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr];
- SLOT->eg_sel_d1r= eg_rate_select[SLOT->d1r + SLOT->ksr];
-}
-
-/* set sustain rate */
-static inline void set_sr(uint8_t type, FM_SLOT *SLOT,int v)
-{
- SLOT->d2r = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0;
-
- SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr];
- SLOT->eg_sel_d2r= eg_rate_select[SLOT->d2r + SLOT->ksr];
-}
-
-/* set release rate */
-static inline void set_sl_rr(uint8_t type, FM_SLOT *SLOT,int v)
-{
- SLOT->sl = sl_table[ v>>4 ];
-
- SLOT->rr = 34 + ((v&0x0f)<<2);
-
- SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr];
- SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr];
-}
-
-
-
-static inline signed int op_calc(uint32_t phase, unsigned int env, signed int pm)
-{
- uint32_t p;
-
- p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ];
-
- if (p >= TL_TAB_LEN)
- return 0;
- return tl_tab[p];
-}
-
-static inline signed int op_calc1(uint32_t phase, unsigned int env, signed int pm)
-{
- uint32_t p;
-
- p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK ];
-
- if (p >= TL_TAB_LEN)
- return 0;
- return tl_tab[p];
-}
-
-/* advance LFO to next sample */
-static inline void advance_lfo(FM_OPN *OPN)
-{
- uint8_t pos;
-
- if (OPN->lfo_inc) /* LFO enabled ? */
- {
- OPN->lfo_cnt += OPN->lfo_inc;
-
- pos = (OPN->lfo_cnt >> LFO_SH) & 127;
-
-
- /* update AM when LFO output changes */
-
- /* actually I can't optimize is this way without rewriting chan_calc()
- to use chip->lfo_am instead of global lfo_am */
- {
- /* triangle */
- /* AM: 0 to 126 step +2, 126 to 0 step -2 */
- if (pos<64)
- OPN->LFO_AM = (pos&63) * 2;
- else
- OPN->LFO_AM = 126 - ((pos&63) * 2);
- }
-
- /* PM works with 4 times slower clock */
- pos >>= 2;
- /* update PM when LFO output changes */
- /*if (prev_pos != pos)*/ /* can't use global lfo_pm for this optimization, must be chip->lfo_pm instead*/
- {
- OPN->LFO_PM = pos;
- }
-
- }
- else
- {
- OPN->LFO_AM = 0;
- OPN->LFO_PM = 0;
- }
-}
-
-/* changed from static inline to static here to work around gcc 4.2.1 codegen bug */
-static void advance_eg_channel(FM_OPN *OPN, FM_SLOT *SLOT)
-{
- unsigned int out;
- unsigned int swap_flag;
- unsigned int i;
-
-
- i = 4; /* four operators per channel */
- do
- {
- /* reset SSG-EG swap flag */
- swap_flag = 0;
-
- switch(SLOT->state)
- {
- case EG_ATT: /* attack phase */
- if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_ar)-1) ) )
- {
- SLOT->volume += (~SLOT->volume *
- (eg_inc[SLOT->eg_sel_ar + ((OPN->eg_cnt>>SLOT->eg_sh_ar)&7)])
- ) >>4;
-
- if (SLOT->volume <= MIN_ATT_INDEX)
- {
- SLOT->volume = MIN_ATT_INDEX;
- SLOT->state = EG_DEC;
- }
- }
- break;
-
- case EG_DEC: /* decay phase */
- {
- if (SLOT->ssg&0x08) /* SSG EG type envelope selected */
- {
- if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_d1r)-1) ) )
- {
- SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d1r + ((OPN->eg_cnt>>SLOT->eg_sh_d1r)&7)];
-
- if ( SLOT->volume >= (int32_t)(SLOT->sl) )
- SLOT->state = EG_SUS;
- }
- }
- else
- {
- if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_d1r)-1) ) )
- {
- SLOT->volume += eg_inc[SLOT->eg_sel_d1r + ((OPN->eg_cnt>>SLOT->eg_sh_d1r)&7)];
-
- if ( SLOT->volume >= (int32_t)(SLOT->sl) )
- SLOT->state = EG_SUS;
- }
- }
- }
- break;
-
- case EG_SUS: /* sustain phase */
- if (SLOT->ssg&0x08) /* SSG EG type envelope selected */
- {
- if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_d2r)-1) ) )
- {
- SLOT->volume += 4 * eg_inc[SLOT->eg_sel_d2r + ((OPN->eg_cnt>>SLOT->eg_sh_d2r)&7)];
-
- if ( SLOT->volume >= ENV_QUIET )
- {
- SLOT->volume = MAX_ATT_INDEX;
-
- if (SLOT->ssg&0x01) /* bit 0 = hold */
- {
- if (SLOT->ssgn&1) /* have we swapped once ??? */
- {
- /* yes, so do nothing, just hold current level */
- }
- else
- swap_flag = (SLOT->ssg&0x02) | 1 ; /* bit 1 = alternate */
-
- }
- else
- {
- /* same as KEY-ON operation */
-
- /* restart of the Phase Generator should be here */
- SLOT->phase = 0;
-
- {
- /* phase -> Attack */
- SLOT->volume = 511;
- SLOT->state = EG_ATT;
- }
-
- swap_flag = (SLOT->ssg&0x02); /* bit 1 = alternate */
- }
- }
- }
- }
- else
- {
- if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_d2r)-1) ) )
- {
- SLOT->volume += eg_inc[SLOT->eg_sel_d2r + ((OPN->eg_cnt>>SLOT->eg_sh_d2r)&7)];
-
- if ( SLOT->volume >= MAX_ATT_INDEX )
- {
- SLOT->volume = MAX_ATT_INDEX;
- /* do not change SLOT->state (verified on real chip) */
- }
- }
-
- }
- break;
-
- case EG_REL: /* release phase */
- if ( !(OPN->eg_cnt & ((1<<SLOT->eg_sh_rr)-1) ) )
- {
- /* SSG-EG affects Release phase also (Nemesis) */
- SLOT->volume += eg_inc[SLOT->eg_sel_rr + ((OPN->eg_cnt>>SLOT->eg_sh_rr)&7)];
-
- if ( SLOT->volume >= MAX_ATT_INDEX )
- {
- SLOT->volume = MAX_ATT_INDEX;
- SLOT->state = EG_OFF;
- }
- }
- break;
-
- }
-
-
- out = ((uint32_t)SLOT->volume);
-
- /* negate output (changes come from alternate bit, init comes from attack bit) */
- if ((SLOT->ssg&0x08) && (SLOT->ssgn&2) && (SLOT->state > EG_REL))
- out ^= MAX_ATT_INDEX;
-
- /* we need to store the result here because we are going to change ssgn
- in next instruction */
- SLOT->vol_out = out + SLOT->tl;
-
- /* reverse SLOT inversion flag */
- SLOT->ssgn ^= swap_flag;
-
- SLOT++;
- i--;
- }while (i);
-
-}
-
-
-
-#define volume_calc(OP) ((OP)->vol_out + (AM & (OP)->AMmask))
-
-static inline void update_phase_lfo_slot(FM_OPN *OPN, FM_SLOT *SLOT, int32_t pms, uint32_t block_fnum)
-{
- uint32_t fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8;
- int32_t lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + pms + OPN->LFO_PM ];
-
- if (lfo_fn_table_index_offset) /* LFO phase modulation active */
- {
- uint8_t blk;
- uint32_t fn;
- int kc, fc;
-
- block_fnum = block_fnum*2 + lfo_fn_table_index_offset;
-
- blk = (block_fnum&0x7000) >> 12;
- fn = block_fnum & 0xfff;
-
- /* keyscale code */
- kc = (blk<<2) | opn_fktable[fn >> 8];
-
- /* phase increment counter */
- fc = (OPN->fn_table[fn]>>(7-blk)) + SLOT->DT[kc];
-
- /* detects frequency overflow (credits to Nemesis) */
- if (fc < 0) fc += OPN->fn_max;
-
- /* update phase */
- SLOT->phase += (fc * SLOT->mul) >> 1;
- }
- else /* LFO phase modulation = zero */
- {
- SLOT->phase += SLOT->Incr;
- }
-}
-
-static inline void update_phase_lfo_channel(FM_OPN *OPN, FM_CH *CH)
-{
- uint32_t block_fnum = CH->block_fnum;
-
- uint32_t fnum_lfo = ((block_fnum & 0x7f0) >> 4) * 32 * 8;
- int32_t lfo_fn_table_index_offset = lfo_pm_table[ fnum_lfo + CH->pms + OPN->LFO_PM ];
-
- if (lfo_fn_table_index_offset) /* LFO phase modulation active */
- {
- uint8_t blk;
- uint32_t fn;
- int kc, fc, finc;
-
- block_fnum = block_fnum*2 + lfo_fn_table_index_offset;
-
- blk = (block_fnum&0x7000) >> 12;
- fn = block_fnum & 0xfff;
-
- /* keyscale code */
- kc = (blk<<2) | opn_fktable[fn >> 8];
-
- /* phase increment counter */
- fc = (OPN->fn_table[fn]>>(7-blk));
-
- /* detects frequency overflow (credits to Nemesis) */
- finc = fc + CH->SLOT[SLOT1].DT[kc];
-
- if (finc < 0) finc += OPN->fn_max;
- CH->SLOT[SLOT1].phase += (finc*CH->SLOT[SLOT1].mul) >> 1;
-
- finc = fc + CH->SLOT[SLOT2].DT[kc];
- if (finc < 0) finc += OPN->fn_max;
- CH->SLOT[SLOT2].phase += (finc*CH->SLOT[SLOT2].mul) >> 1;
-
- finc = fc + CH->SLOT[SLOT3].DT[kc];
- if (finc < 0) finc += OPN->fn_max;
- CH->SLOT[SLOT3].phase += (finc*CH->SLOT[SLOT3].mul) >> 1;
-
- finc = fc + CH->SLOT[SLOT4].DT[kc];
- if (finc < 0) finc += OPN->fn_max;
- CH->SLOT[SLOT4].phase += (finc*CH->SLOT[SLOT4].mul) >> 1;
- }
- else /* LFO phase modulation = zero */
- {
- CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr;
- CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr;
- CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr;
- CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr;
- }
-}
-
-static inline void chan_calc(FM_OPN *OPN, FM_CH *CH, int chnum)
-{
- unsigned int eg_out;
-
- uint32_t AM = OPN->LFO_AM >> CH->ams;
-
-
- OPN->m2 = OPN->c1 = OPN->c2 = OPN->mem = 0;
-
- *CH->mem_connect = CH->mem_value; /* restore delayed sample (MEM) value to m2 or c2 */
-
- eg_out = volume_calc(&CH->SLOT[SLOT1]);
- {
- int32_t out = CH->op1_out[0] + CH->op1_out[1];
- CH->op1_out[0] = CH->op1_out[1];
-
- if( !CH->connect1 )
- {
- /* algorithm 5 */
- OPN->mem = OPN->c1 = OPN->c2 = CH->op1_out[0];
- }
- else
- {
- /* other algorithms */
- *CH->connect1 += CH->op1_out[0];
- }
-
- CH->op1_out[1] = 0;
- if( eg_out < ENV_QUIET ) /* SLOT 1 */
- {
- if (!CH->FB)
- out=0;
-
- CH->op1_out[1] = op_calc1(CH->SLOT[SLOT1].phase, eg_out, (out<<CH->FB) );
- }
- }
-
- eg_out = volume_calc(&CH->SLOT[SLOT3]);
- if( eg_out < ENV_QUIET ) /* SLOT 3 */
- *CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, OPN->m2);
-
- eg_out = volume_calc(&CH->SLOT[SLOT2]);
- if( eg_out < ENV_QUIET ) /* SLOT 2 */
- *CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, OPN->c1);
-
- eg_out = volume_calc(&CH->SLOT[SLOT4]);
- if( eg_out < ENV_QUIET ) /* SLOT 4 */
- *CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, OPN->c2);
-
-
- /* store current MEM */
- CH->mem_value = OPN->mem;
-
- /* update phase counters AFTER output calculations */
- if(CH->pms)
- {
- /* add support for 3 slot mode */
- if ((OPN->ST.mode & 0xC0) && (chnum == 2))
- {
- update_phase_lfo_slot(OPN, &CH->SLOT[SLOT1], CH->pms, OPN->SL3.block_fnum[1]);
- update_phase_lfo_slot(OPN, &CH->SLOT[SLOT2], CH->pms, OPN->SL3.block_fnum[2]);
- update_phase_lfo_slot(OPN, &CH->SLOT[SLOT3], CH->pms, OPN->SL3.block_fnum[0]);
- update_phase_lfo_slot(OPN, &CH->SLOT[SLOT4], CH->pms, CH->block_fnum);
- }
- else update_phase_lfo_channel(OPN, CH);
- }
- else /* no LFO phase modulation */
- {
- CH->SLOT[SLOT1].phase += CH->SLOT[SLOT1].Incr;
- CH->SLOT[SLOT2].phase += CH->SLOT[SLOT2].Incr;
- CH->SLOT[SLOT3].phase += CH->SLOT[SLOT3].Incr;
- CH->SLOT[SLOT4].phase += CH->SLOT[SLOT4].Incr;
- }
-}
-
-/* update phase increment and envelope generator */
-static inline void refresh_fc_eg_slot(FM_OPN *OPN, FM_SLOT *SLOT , int fc , int kc )
-{
- int ksr = kc >> SLOT->KSR;
-
- fc += SLOT->DT[kc];
-
- /* detects frequency overflow (credits to Nemesis) */
- if (fc < 0) fc += OPN->fn_max;
-
- /* (frequency) phase increment counter */
- SLOT->Incr = (fc * SLOT->mul) >> 1;
-
- if( SLOT->ksr != ksr )
- {
- SLOT->ksr = ksr;
-
- /* calculate envelope generator rates */
- if ((SLOT->ar + SLOT->ksr) < 32+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 = 17*RATE_STEPS;
- }
-
- SLOT->eg_sh_d1r = eg_rate_shift [SLOT->d1r + SLOT->ksr];
- SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr];
- SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr];
-
- SLOT->eg_sel_d1r= eg_rate_select[SLOT->d1r + SLOT->ksr];
- SLOT->eg_sel_d2r= eg_rate_select[SLOT->d2r + SLOT->ksr];
- SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr];
- }
-}
-
-/* update phase increment counters */
-/* Changed from static inline to static to work around gcc 4.2.1 codegen bug */
-static void refresh_fc_eg_chan(FM_OPN *OPN, FM_CH *CH )
-{
- if( CH->SLOT[SLOT1].Incr==-1)
- {
- int fc = CH->fc;
- int kc = CH->kcode;
- refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT1] , fc , kc );
- refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT2] , fc , kc );
- refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT3] , fc , kc );
- refresh_fc_eg_slot(OPN, &CH->SLOT[SLOT4] , fc , kc );
- }
-}
-
-/* initialize time tables */
-static void init_timetables( FM_ST *ST , const uint8_t *dttable )
-{
- int i,d;
- double rate;
-
-#if 0
- logerror("FM.C: samplerate=%8i chip clock=%8i freqbase=%f \n",
- ST->rate, ST->clock, ST->freqbase );
-#endif
-
- /* DeTune table */
- for (d = 0;d <= 3;d++)
- {
- for (i = 0;i <= 31;i++)
- {
- rate = ((double)dttable[d*32 + i]) * SIN_LEN * ST->freqbase * (1<<FREQ_SH) / ((double)(1<<20));
- ST->dt_tab[d][i] = (int32_t) rate;
- ST->dt_tab[d+4][i] = -ST->dt_tab[d][i];
-#if 0
- logerror("FM.C: DT [%2i %2i] = %8x \n", d, i, ST->dt_tab[d][i] );
-#endif
- }
- }
-
-}
-
-
-static void reset_channels( FM_ST *ST , FM_CH *CH , int num )
-{
- int c,s;
-
- ST->mode = 0; /* normal mode */
- ST->TA = 0;
- ST->TAC = 0;
- ST->TB = 0;
- ST->TBC = 0;
-
- for( c = 0 ; c < num ; c++ )
- {
- CH[c].fc = 0;
- for(s = 0 ; s < 4 ; s++ )
- {
- CH[c].SLOT[s].ssg = 0;
- CH[c].SLOT[s].ssgn = 0;
- CH[c].SLOT[s].state= EG_OFF;
- CH[c].SLOT[s].volume = MAX_ATT_INDEX;
- CH[c].SLOT[s].vol_out= MAX_ATT_INDEX;
- }
- }
-}
-
-/* initialize generic tables */
-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, (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 <<= 2; /* 13 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<13; 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);
- for (i=0; i<13; i++)
- logerror(", [%02i] %4x", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ]);
- logerror("\n");
- #endif
- }
- /*logerror("FM.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) * M_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("FM.C: sin [%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[i],tl_tab[sin_tab[i]]);*/
- }
-
- /*logerror("FM.C: ENV_QUIET= %08x\n",ENV_QUIET );*/
-
-
- /* build LFO PM modulation table */
- for(i = 0; i < 8; i++) /* 8 PM depths */
- {
- uint8_t fnum;
- for (fnum=0; fnum<128; fnum++) /* 7 bits meaningful of F-NUMBER */
- {
- uint8_t value;
- uint8_t step;
- uint32_t offset_depth = i;
- uint32_t offset_fnum_bit;
- uint32_t bit_tmp;
-
- for (step=0; step<8; step++)
- {
- value = 0;
- for (bit_tmp=0; bit_tmp<7; bit_tmp++) /* 7 bits */
- {
- if (fnum & (1<<bit_tmp)) /* only if bit "bit_tmp" is set */
- {
- offset_fnum_bit = bit_tmp * 8;
- value += lfo_pm_output[offset_fnum_bit + offset_depth][step];
- }
- }
- lfo_pm_table[(fnum*32*8) + (i*32) + step + 0] = value;
- lfo_pm_table[(fnum*32*8) + (i*32) +(step^7)+ 8] = value;
- lfo_pm_table[(fnum*32*8) + (i*32) + step +16] = -value;
- lfo_pm_table[(fnum*32*8) + (i*32) +(step^7)+24] = -value;
- }
-#if 0
- logerror("LFO depth=%1x FNUM=%04x (<<4=%4x): ", i, fnum, fnum<<4);
- for (step=0; step<16; step++) /* dump only positive part of waveforms */
- logerror("%02x ", lfo_pm_table[(fnum*32*8) + (i*32) + step] );
- logerror("\n");
-#endif
-
- }
- }
-
-
-
-#ifdef SAVE_SAMPLE
- sample[0]=fopen("sampsum.pcm","wb");
-#endif
-
- return 1;
-
-}
-
-
-
-static void FMCloseTable( void )
-{
-#ifdef SAVE_SAMPLE
- fclose(sample[0]);
-#endif
- return;
-}
-
-
-/* CSM Key Controll */
-static inline void CSMKeyControll(uint8_t type, FM_CH *CH)
-{
- /* all key on then off (only for operators which were OFF!) */
- if (!CH->SLOT[SLOT1].key)
- {
- FM_KEYON(type, CH,SLOT1);
- FM_KEYOFF(CH, SLOT1);
- }
- if (!CH->SLOT[SLOT2].key)
- {
- FM_KEYON(type, CH,SLOT2);
- FM_KEYOFF(CH, SLOT2);
- }
- if (!CH->SLOT[SLOT3].key)
- {
- FM_KEYON(type, CH,SLOT3);
- FM_KEYOFF(CH, SLOT3);
- }
- if (!CH->SLOT[SLOT4].key)
- {
- FM_KEYON(type, CH,SLOT4);
- FM_KEYOFF(CH, SLOT4);
- }
-}
-
-#ifdef MAME_EMU_SAVE_H
-/* FM channel save , internal state only */
-static void FMsave_state_channel(device_t *device,FM_CH *CH,int num_ch)
-{
- int slot , ch;
-
- for(ch=0;ch<num_ch;ch++,CH++)
- {
- /* channel */
- device->save_item(NAME(CH->op1_out), ch);
- device->save_item(NAME(CH->fc), ch);
- /* slots */
- for(slot=0;slot<4;slot++)
- {
- FM_SLOT *SLOT = &CH->SLOT[slot];
- device->save_item(NAME(SLOT->phase), ch * 4 + slot);
- device->save_item(NAME(SLOT->state), ch * 4 + slot);
- device->save_item(NAME(SLOT->volume), ch * 4 + slot);
- }
- }
-}
-
-static void FMsave_state_st(device_t *device,FM_ST *ST)
-{
-#if FM_BUSY_FLAG_SUPPORT
- device->save_item(NAME(ST->busy_expiry_time) );
-#endif
- device->save_item(NAME(ST->address) );
- device->save_item(NAME(ST->irq) );
- device->save_item(NAME(ST->irqmask) );
- device->save_item(NAME(ST->status) );
- device->save_item(NAME(ST->mode) );
- device->save_item(NAME(ST->prescaler_sel) );
- device->save_item(NAME(ST->fn_h) );
- device->save_item(NAME(ST->TA) );
- device->save_item(NAME(ST->TAC) );
- device->save_item(NAME(ST->TB) );
- device->save_item(NAME(ST->TBC) );
-}
-#endif /* MAME_EMU_SAVE_H */
-
-#if BUILD_OPN
-
-
-
-/* prescaler set (and make time tables) */
-static void OPNSetPres(FM_OPN *OPN, int pres, int timer_prescaler, int SSGpres)
-{
- int i;
-
- /* frequency base */
- OPN->ST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pres : 0;
-
-#if 0
- OPN->ST.rate = (double)OPN->ST.clock / pres;
- OPN->ST.freqbase = 1.0;
-#endif
-
- OPN->eg_timer_add = (1<<EG_SH) * OPN->ST.freqbase;
- OPN->eg_timer_overflow = ( 3 ) * (1<<EG_SH);
-
-
- /* Timer base time */
- OPN->ST.timer_prescaler = timer_prescaler;
-
- /* SSG part prescaler set */
- if( SSGpres ) (*OPN->ST.SSG->set_clock)( OPN->ST.device, OPN->ST.clock * 2 / SSGpres );
-
- /* make time tables */
- init_timetables( &OPN->ST, dt_tab );
-
- /* there are 2048 FNUMs that can be generated using FNUM/BLK registers
- but LFO works with one more bit of a precision so we really need 4096 elements */
- /* calculate fnumber -> increment counter table */
- for(i = 0; i < 4096; i++)
- {
- /* freq table for octave 7 */
- /* OPN phase increment counter = 20bit */
- OPN->fn_table[i] = (uint32_t)( (double)i * 32 * OPN->ST.freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
-#if 0
- logerror("FM.C: fn_table[%4i] = %08x (dec=%8i)\n",
- i, OPN->fn_table[i]>>6,OPN->fn_table[i]>>6 );
-#endif
- }
-
- /* maximal frequency is required for Phase overflow calculation, register size is 17 bits (Nemesis) */
- OPN->fn_max = (uint32_t)( (double)0x20000 * OPN->ST.freqbase * (1<<(FREQ_SH-10)) );
-
- /* LFO freq. table */
- for(i = 0; i < 8; i++)
- {
- /* Amplitude modulation: 64 output levels (triangle waveform); 1 level lasts for one of "lfo_samples_per_step" samples */
- /* Phase modulation: one entry from lfo_pm_output lasts for one of 4 * "lfo_samples_per_step" samples */
- OPN->lfo_freq[i] = (1.0 / lfo_samples_per_step[i]) * (1<<LFO_SH) * OPN->ST.freqbase;
-#if 0
- logerror("FM.C: lfo_freq[%i] = %08x (dec=%8i)\n",
- i, OPN->lfo_freq[i],OPN->lfo_freq[i] );
-#endif
- }
-}
-
-
-
-/* write a OPN mode register 0x20-0x2f */
-static void OPNWriteMode(FM_OPN *OPN, int r, int v)
-{
- uint8_t c;
- FM_CH *CH;
-
- switch(r)
- {
- case 0x21: /* Test */
- break;
- case 0x22: /* LFO FREQ (YM2608/YM2610/YM2610B/YM2612) */
- if( OPN->type & TYPE_LFOPAN )
- {
- if (v&0x08) /* LFO enabled ? */
- {
- OPN->lfo_inc = OPN->lfo_freq[v&7];
- }
- else
- {
- OPN->lfo_inc = 0;
- }
- }
- break;
- case 0x24: /* timer A High 8*/
- OPN->ST.TA = (OPN->ST.TA & 0x03)|(((int)v)<<2);
- break;
- case 0x25: /* timer A Low 2*/
- OPN->ST.TA = (OPN->ST.TA & 0x3fc)|(v&3);
- break;
- case 0x26: /* timer B */
- OPN->ST.TB = v;
- break;
- case 0x27: /* mode, timer control */
- set_timers( &(OPN->ST),OPN->ST.device,v );
- break;
- case 0x28: /* key on / off */
- c = v & 0x03;
- if( c == 3 ) break;
- if( (v&0x04) && (OPN->type & TYPE_6CH) ) c+=3;
- CH = OPN->P_CH;
- CH = &CH[c];
- if(v&0x10) FM_KEYON(OPN->type,CH,SLOT1); else FM_KEYOFF(CH,SLOT1);
- if(v&0x20) FM_KEYON(OPN->type,CH,SLOT2); else FM_KEYOFF(CH,SLOT2);
- if(v&0x40) FM_KEYON(OPN->type,CH,SLOT3); else FM_KEYOFF(CH,SLOT3);
- if(v&0x80) FM_KEYON(OPN->type,CH,SLOT4); else FM_KEYOFF(CH,SLOT4);
- break;
- }
-}
-
-/* write a OPN register (0x30-0xff) */
-static void OPNWriteReg(FM_OPN *OPN, int r, int v)
-{
- FM_CH *CH;
- FM_SLOT *SLOT;
-
- uint8_t c = OPN_CHAN(r);
-
- if (c == 3) return; /* 0xX3,0xX7,0xXB,0xXF */
-
- if (r >= 0x100) c+=3;
-
- CH = OPN->P_CH;
- CH = &CH[c];
-
- SLOT = &(CH->SLOT[OPN_SLOT(r)]);
-
- switch( r & 0xf0 )
- {
- case 0x30: /* DET , MUL */
- set_det_mul(&OPN->ST,CH,SLOT,v);
- break;
-
- case 0x40: /* TL */
- set_tl(CH,SLOT,v);
- break;
-
- case 0x50: /* KS, AR */
- set_ar_ksr(OPN->type,CH,SLOT,v);
- break;
-
- case 0x60: /* bit7 = AM ENABLE, DR */
- set_dr(OPN->type, SLOT,v);
-
- if(OPN->type & TYPE_LFOPAN) /* YM2608/2610/2610B/2612 */
- {
- SLOT->AMmask = (v&0x80) ? ~0 : 0;
- }
- break;
-
- case 0x70: /* SR */
- set_sr(OPN->type,SLOT,v);
- break;
-
- case 0x80: /* SL, RR */
- set_sl_rr(OPN->type,SLOT,v);
- break;
-
- case 0x90: /* SSG-EG */
- SLOT->ssg = v&0x0f;
- SLOT->ssgn = (v&0x04)>>1; /* bit 1 in ssgn = attack */
-
- /* SSG-EG envelope shapes :
-
- E AtAlH
- 1 0 0 0 \\\\
-
- 1 0 0 1 \___
-
- 1 0 1 0 \/\/
- ___
- 1 0 1 1 \
-
- 1 1 0 0 ////
- ___
- 1 1 0 1 /
-
- 1 1 1 0 /\/\
-
- 1 1 1 1 /___
-
-
- E = SSG-EG enable
-
-
- The shapes are generated using Attack, Decay and Sustain phases.
-
- Each single character in the diagrams above represents this whole
- sequence:
-
- - when KEY-ON = 1, normal Attack phase is generated (*without* any
- difference when compared to normal mode),
-
- - later, when envelope level reaches minimum level (max volume),
- the EG switches to Decay phase (which works with bigger steps
- when compared to normal mode - see below),
-
- - later when envelope level passes the SL level,
- the EG swithes to Sustain phase (which works with bigger steps
- when compared to normal mode - see below),
-
- - finally when envelope level reaches maximum level (min volume),
- the EG switches to Attack phase again (depends on actual waveform).
-
- Important is that when switch to Attack phase occurs, the phase counter
- of that operator will be zeroed-out (as in normal KEY-ON) but not always.
- (I havent found the rule for that - perhaps only when the output level is low)
-
- The difference (when compared to normal Envelope Generator mode) is
- that the resolution in Decay and Sustain phases is 4 times lower;
- this results in only 256 steps instead of normal 1024.
- In other words:
- when SSG-EG is disabled, the step inside of the EG is one,
- when SSG-EG is enabled, the step is four (in Decay and Sustain phases).
-
- Times between the level changes are the same in both modes.
-
-
- Important:
- Decay 1 Level (so called SL) is compared to actual SSG-EG output, so
- it is the same in both SSG and no-SSG modes, with this exception:
-
- when the SSG-EG is enabled and is generating raising levels
- (when the EG output is inverted) the SL will be found at wrong level !!!
- For example, when SL=02:
- 0 -6 = -6dB in non-inverted EG output
- 96-6 = -90dB in inverted EG output
- Which means that EG compares its level to SL as usual, and that the
- output is simply inverted afterall.
-
-
- The Yamaha's manuals say that AR should be set to 0x1f (max speed).
- That is not necessary, but then EG will be generating Attack phase.
-
- */
-
-
- break;
-
- case 0xa0:
- switch( OPN_SLOT(r) )
- {
- case 0: /* 0xa0-0xa2 : FNUM1 */
- {
- uint32_t fn = (((uint32_t)( (OPN->ST.fn_h)&7))<<8) + v;
- uint8_t blk = OPN->ST.fn_h>>3;
- /* keyscale code */
- CH->kcode = (blk<<2) | opn_fktable[fn >> 7];
- /* phase increment counter */
- CH->fc = OPN->fn_table[fn*2]>>(7-blk);
-
- /* store fnum in clear form for LFO PM calculations */
- CH->block_fnum = (blk<<11) | fn;
-
- CH->SLOT[SLOT1].Incr=-1;
- }
- break;
- case 1: /* 0xa4-0xa6 : FNUM2,BLK */
- OPN->ST.fn_h = v&0x3f;
- break;
- case 2: /* 0xa8-0xaa : 3CH FNUM1 */
- if(r < 0x100)
- {
- uint32_t fn = (((uint32_t)(OPN->SL3.fn_h&7))<<8) + v;
- uint8_t blk = OPN->SL3.fn_h>>3;
- /* keyscale code */
- OPN->SL3.kcode[c]= (blk<<2) | opn_fktable[fn >> 7];
- /* phase increment counter */
- OPN->SL3.fc[c] = OPN->fn_table[fn*2]>>(7-blk);
- OPN->SL3.block_fnum[c] = (blk<<11) | fn;
- (OPN->P_CH)[2].SLOT[SLOT1].Incr=-1;
- }
- break;
- case 3: /* 0xac-0xae : 3CH FNUM2,BLK */
- if(r < 0x100)
- OPN->SL3.fn_h = v&0x3f;
- break;
- }
- break;
-
- case 0xb0:
- switch( OPN_SLOT(r) )
- {
- case 0: /* 0xb0-0xb2 : FB,ALGO */
- {
- int feedback = (v>>3)&7;
- CH->ALGO = v&7;
- CH->FB = feedback ? feedback+6 : 0;
- setup_connection( OPN, CH, c );
- }
- break;
- case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2610B/YM2610/YM2608) */
- if( OPN->type & TYPE_LFOPAN)
- {
- /* b0-2 PMS */
- CH->pms = (v & 7) * 32; /* CH->pms = PM depth * 32 (index in lfo_pm_table) */
-
- /* b4-5 AMS */
- CH->ams = lfo_ams_depth_shift[(v>>4) & 0x03];
-
- /* PAN : b7 = L, b6 = R */
- OPN->pan[ c*2 ] = (v & 0x80) ? ~0 : 0;
- OPN->pan[ c*2+1 ] = (v & 0x40) ? ~0 : 0;
-
- }
- break;
- }
- break;
- }
-}
-
-#endif /* BUILD_OPN */
-
-#if BUILD_OPN_PRESCALER
-/*
- prescaler circuit (best guess to verified chip behaviour)
-
- +--------------+ +-sel2-+
- | +--|in20 |
- +---+ | +-sel1-+ | |
-M-CLK -+-|1/2|-+--|in10 | +---+ | out|--INT_CLOCK
- | +---+ | out|-|1/3|-|in21 |
- +----------|in11 | +---+ +------+
- +------+
-
-reg.2d : sel2 = in21 (select sel2)
-reg.2e : sel1 = in11 (select sel1)
-reg.2f : sel1 = in10 , sel2 = in20 (clear selector)
-reset : sel1 = in11 , sel2 = in21 (clear both)
-
-*/
-static void OPNPrescaler_w(FM_OPN *OPN , int addr, int pre_divider)
-{
- static const int opn_pres[4] = { 2*12 , 2*12 , 6*12 , 3*12 };
- static const int ssg_pres[4] = { 1 , 1 , 4 , 2 };
- int sel;
-
- switch(addr)
- {
- case 0: /* when reset */
- OPN->ST.prescaler_sel = 2;
- break;
- case 1: /* when postload */
- break;
- case 0x2d: /* divider sel : select 1/1 for 1/3line */
- OPN->ST.prescaler_sel |= 0x02;
- break;
- case 0x2e: /* divider sel , select 1/3line for output */
- OPN->ST.prescaler_sel |= 0x01;
- break;
- case 0x2f: /* divider sel , clear both selector to 1/2,1/2 */
- OPN->ST.prescaler_sel = 0;
- break;
- }
- sel = OPN->ST.prescaler_sel & 3;
- /* update prescaler */
- OPNSetPres( OPN, opn_pres[sel]*pre_divider,
- opn_pres[sel]*pre_divider,
- ssg_pres[sel]*pre_divider );
-}
-#endif /* BUILD_OPN_PRESCALER */
-
-#if BUILD_YM2203
-/*****************************************************************************/
-/* YM2203 local section */
-/*****************************************************************************/
-
-/* here's the virtual YM2203(OPN) */
-namespace {
-struct ym2203_state
-{
- uint8_t REGS[256]; /* registers */
- FM_OPN OPN; /* OPN state */
- FM_CH CH[3]; /* channel state */
-};
-} // anonymous namespace
-
-/* Generate samples for one of the YM2203s */
-void ym2203_update_one(void *chip, FMSAMPLE *buffer, int length)
-{
- ym2203_state *F2203 = (ym2203_state *)chip;
- FM_OPN *OPN = &F2203->OPN;
- int i;
- FMSAMPLE *buf = buffer;
- FM_CH *cch[3];
-
- cch[0] = &F2203->CH[0];
- cch[1] = &F2203->CH[1];
- cch[2] = &F2203->CH[2];
-
-
- /* refresh PG and EG */
- refresh_fc_eg_chan( OPN, cch[0] );
- refresh_fc_eg_chan( OPN, cch[1] );
- if( (F2203->OPN.ST.mode & 0xc0) )
- {
- /* 3SLOT MODE */
- if( cch[2]->SLOT[SLOT1].Incr==-1)
- {
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] );
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode );
- }
- }
- else
- refresh_fc_eg_chan( OPN, cch[2] );
-
-
- /* YM2203 doesn't have LFO so we must keep these globals at 0 level */
- OPN->LFO_AM = 0;
- OPN->LFO_PM = 0;
-
- /* buffering */
- for (i=0; i < length ; i++)
- {
- /* clear outputs */
- OPN->out_fm[0] = 0;
- OPN->out_fm[1] = 0;
- OPN->out_fm[2] = 0;
-
- /* advance envelope generator */
- OPN->eg_timer += OPN->eg_timer_add;
- while (OPN->eg_timer >= OPN->eg_timer_overflow)
- {
- OPN->eg_timer -= OPN->eg_timer_overflow;
- OPN->eg_cnt++;
-
- advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]);
- }
-
- /* calculate FM */
- chan_calc(OPN, cch[0], 0 );
- chan_calc(OPN, cch[1], 1 );
- chan_calc(OPN, cch[2], 2 );
-
- /* buffering */
- {
- int lt;
-
- lt = OPN->out_fm[0] + OPN->out_fm[1] + OPN->out_fm[2];
-
- lt >>= FINAL_SH;
-
- Limit( lt , MAXOUT, MINOUT );
-
- #ifdef SAVE_SAMPLE
- SAVE_ALL_CHANNELS
- #endif
-
- /* buffering */
- buf[i] = lt;
- }
-
- /* timer A control */
- INTERNAL_TIMER_A( &F2203->OPN.ST , cch[2] )
- }
- INTERNAL_TIMER_B(&F2203->OPN.ST,length)
-}
-
-/* ---------- reset one of chip ---------- */
-void ym2203_reset_chip(void *chip)
-{
- int i;
- ym2203_state *F2203 = (ym2203_state *)chip;
- FM_OPN *OPN = &F2203->OPN;
-
- /* Reset Prescaler */
- OPNPrescaler_w(OPN, 0 , 1 );
- /* reset SSG section */
- (*OPN->ST.SSG->reset)(OPN->ST.device);
- /* status clear */
- FM_IRQMASK_SET(&OPN->ST,0x03);
- FM_BUSY_CLEAR(&OPN->ST);
- OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */
-
- OPN->eg_timer = 0;
- OPN->eg_cnt = 0;
-
- FM_STATUS_RESET(&OPN->ST, 0xff);
-
- reset_channels( &OPN->ST , F2203->CH , 3 );
- /* reset OPerator paramater */
- for(i = 0xb2 ; i >= 0x30 ; i-- ) OPNWriteReg(OPN,i,0);
- for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
-}
-
-#ifdef MAME_EMU_SAVE_H
-void ym2203_postload(void *chip)
-{
- if (chip)
- {
- ym2203_state *F2203 = (ym2203_state *)chip;
- int r;
-
- /* prescaler */
- OPNPrescaler_w(&F2203->OPN,1,1);
-
- /* SSG registers */
- for(r=0;r<16;r++)
- {
- (*F2203->OPN.ST.SSG->write)(F2203->OPN.ST.device,0,r);
- (*F2203->OPN.ST.SSG->write)(F2203->OPN.ST.device,1,F2203->REGS[r]);
- }
-
- /* OPN registers */
- /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */
- for(r=0x30;r<0x9e;r++)
- if((r&3) != 3)
- OPNWriteReg(&F2203->OPN,r,F2203->REGS[r]);
- /* FB / CONNECT , L / R / AMS / PMS */
- for(r=0xb0;r<0xb6;r++)
- if((r&3) != 3)
- OPNWriteReg(&F2203->OPN,r,F2203->REGS[r]);
-
- /* channels */
- /*FM_channel_postload(F2203->CH,3);*/
- }
-}
-
-static void YM2203_save_state(ym2203_state *F2203, device_t *device)
-{
- device->save_item(NAME(F2203->REGS));
- FMsave_state_st(device,&F2203->OPN.ST);
- FMsave_state_channel(device,F2203->CH,3);
- /* 3slots */
- device->save_item (NAME(F2203->OPN.SL3.fc));
- device->save_item (NAME(F2203->OPN.SL3.fn_h));
- device->save_item (NAME(F2203->OPN.SL3.kcode));
-}
-#endif /* MAME_EMU_SAVE_H */
-
-/* ---------- Initialize YM2203 emulator(s) ----------
- 'num' is the number of virtual YM2203s to allocate
- 'clock' is the chip clock in Hz
- 'rate' is sampling rate
-*/
-void * ym2203_init(device_t *device, int clock, int rate, FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler, const ssg_callbacks *ssg)
-{
- ym2203_state *F2203;
-
- /* allocate ym2203 state space */
- F2203 = auto_alloc_clear(device->machine(), <ym2203_state>());
-
- if( !init_tables() )
- {
- auto_free( device->machine(), F2203 );
- return nullptr;
- }
-
- F2203->OPN.type = TYPE_YM2203;
- F2203->OPN.P_CH = F2203->CH;
- F2203->OPN.ST.device = device;
- F2203->OPN.ST.clock = clock;
- F2203->OPN.ST.rate = rate;
-
- F2203->OPN.ST.timer_handler = timer_handler;
- F2203->OPN.ST.IRQ_Handler = IRQHandler;
- F2203->OPN.ST.SSG = ssg;
-
-#ifdef MAME_EMU_SAVE_H
- YM2203_save_state(F2203, device);
-#endif
- return F2203;
-}
-
-void ym2203_clock_changed(void *chip, int clock, int rate)
-{
- ym2203_state *FM2203 = (ym2203_state *)chip;
-
- FM2203->OPN.ST.clock = clock;
- FM2203->OPN.ST.rate = rate;
-}
-
-/* shut down emulator */
-void ym2203_shutdown(void *chip)
-{
- ym2203_state *FM2203 = (ym2203_state *)chip;
-
- FMCloseTable();
- auto_free(FM2203->OPN.ST.device->machine(), FM2203);
-}
-
-/* YM2203 I/O interface */
-int ym2203_write(void *chip,int a,uint8_t v)
-{
- ym2203_state *F2203 = (ym2203_state *)chip;
- FM_OPN *OPN = &F2203->OPN;
-
- if( !(a&1) )
- { /* address port */
- OPN->ST.address = (v &= 0xff);
-
- /* Write register to SSG emulator */
- if( v < 16 ) (*OPN->ST.SSG->write)(OPN->ST.device,0,v);
-
- /* prescaler select : 2d,2e,2f */
- if( v >= 0x2d && v <= 0x2f )
- OPNPrescaler_w(OPN , v , 1);
- }
- else
- { /* data port */
- int addr = OPN->ST.address;
- F2203->REGS[addr] = v;
- switch( addr & 0xf0 )
- {
- case 0x00: /* 0x00-0x0f : SSG section */
- /* Write data to SSG emulator */
- (*OPN->ST.SSG->write)(OPN->ST.device,a,v);
- break;
- case 0x20: /* 0x20-0x2f : Mode section */
- ym2203_device::update_request(OPN->ST.device);
- /* write register */
- OPNWriteMode(OPN,addr,v);
- break;
- default: /* 0x30-0xff : OPN section */
- ym2203_device::update_request(OPN->ST.device);
- /* write register */
- OPNWriteReg(OPN,addr,v);
- }
- FM_BUSY_SET(&OPN->ST,1);
- }
- return OPN->ST.irq;
-}
-
-uint8_t ym2203_read(void *chip,int a)
-{
- ym2203_state *F2203 = (ym2203_state *)chip;
- int addr = F2203->OPN.ST.address;
- uint8_t ret = 0;
-
- if( !(a&1) )
- { /* status port */
- ret = FM_STATUS_FLAG(&F2203->OPN.ST);
- }
- else
- { /* data port (only SSG) */
- if( addr < 16 ) ret = (*F2203->OPN.ST.SSG->read)(F2203->OPN.ST.device);
- }
- return ret;
-}
-
-int ym2203_timer_over(void *chip,int c)
-{
- ym2203_state *F2203 = (ym2203_state *)chip;
-
- if( c )
- { /* Timer B */
- TimerBOver( &(F2203->OPN.ST) );
- }
- else
- { /* Timer A */
- ym2203_device::update_request(F2203->OPN.ST.device);
- /* timer update */
- TimerAOver( &(F2203->OPN.ST) );
- /* CSM mode key,TL control */
- if( F2203->OPN.ST.mode & 0x80 )
- { /* CSM mode auto key on */
- CSMKeyControll( F2203->OPN.type, &(F2203->CH[2]) );
- }
- }
- return F2203->OPN.ST.irq;
-}
-#endif /* BUILD_YM2203 */
-
-
-
-#if (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B)
-
-namespace {
-/**** YM2610 ADPCM defines ****/
-constexpr unsigned ADPCM_SHIFT = 16; /* frequency step rate */
-constexpr unsigned ADPCMA_ADDRESS_SHIFT = 8; /* adpcm A address shift */
-
-/* speedup purposes only */
-static int jedi_table[ 49*16 ];
-
-/* ADPCM type A channel struct */
-struct ADPCM_CH
-{
- uint8_t flag; /* port state */
- uint8_t flagMask; /* arrived flag mask */
- uint8_t now_data; /* current ROM data */
- uint32_t now_addr; /* current ROM address */
- uint32_t now_step;
- uint32_t step;
- uint32_t start; /* sample data start address*/
- uint32_t end; /* sample data end address */
- uint8_t IL; /* Instrument Level */
- int32_t adpcm_acc; /* accumulator */
- int32_t adpcm_step; /* step */
- int32_t adpcm_out; /* (speedup) hiro-shi!! */
- int8_t vol_mul; /* volume in "0.75dB" steps */
- uint8_t vol_shift; /* volume in "-6dB" steps */
- int32_t *pan; /* &out_adpcm[OPN_xxxx] */
-};
-
-/* here's the virtual YM2610 */
-struct ym2610_state
-{
- uint8_t REGS[512]; /* registers */
- FM_OPN OPN; /* OPN state */
- FM_CH CH[6]; /* channel state */
- uint8_t addr_A1; /* address line A1 */
-
- /* ADPCM-A unit */
- FM_READBYTE read_byte;
- uint8_t adpcmTL; /* adpcmA total level */
- ADPCM_CH adpcm[6]; /* adpcm channels */
- uint32_t adpcmreg[0x30]; /* registers */
- uint8_t adpcm_arrivedEndAddress;
- YM_DELTAT deltaT; /* Delta-T ADPCM unit */
-
- uint8_t flagmask; /* YM2608 only */
- uint8_t irqmask; /* YM2608 only */
-
- device_t *device;
-
- /* different from the usual ADPCM table */
- static constexpr int step_inc[8] = { -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16 };
-
- /* ADPCM A (Non control type) : calculate one channel output */
- inline void ADPCMA_calc_chan( ADPCM_CH *ch )
- {
- uint32_t step;
- uint8_t data;
-
-
- ch->now_step += ch->step;
- if ( ch->now_step >= (1<<ADPCM_SHIFT) )
- {
- step = ch->now_step >> ADPCM_SHIFT;
- ch->now_step &= (1<<ADPCM_SHIFT)-1;
- do{
- /* end check */
- /* 11-06-2001 JB: corrected comparison. Was > instead of == */
- /* YM2610 checks lower 20 bits only, the 4 MSB bits are sample bank */
- /* Here we use 1<<21 to compensate for nibble calculations */
-
- if ( (ch->now_addr & ((1<<21)-1)) == ((ch->end<<1) & ((1<<21)-1)) )
- {
- ch->flag = 0;
- adpcm_arrivedEndAddress |= ch->flagMask;
- return;
- }
-#if 0
- if ( ch->now_addr > (pcmsizeA<<1) )
- {
- LOG(LOG_WAR,("YM2610: Attempting to play past adpcm rom size!\n" ));
- return;
- }
-#endif
- if ( ch->now_addr&1 )
- data = ch->now_data & 0x0f;
- else
- {
- ch->now_data = read_byte(device, ch->now_addr>>1);
- data = (ch->now_data >> 4) & 0x0f;
- }
-
- ch->now_addr++;
-
- ch->adpcm_acc += jedi_table[ch->adpcm_step + data];
-
- /* the 12-bit accumulator wraps on the ym2610 and ym2608 (like the msm5205), it does not saturate (like the msm5218) */
- ch->adpcm_acc &= 0xfff;
-
- /* extend 12-bit signed int */
- if (ch->adpcm_acc & 0x800)
- ch->adpcm_acc |= ~0xfff;
-
- ch->adpcm_step += step_inc[data & 7];
- Limit( ch->adpcm_step, 48*16, 0*16 );
-
- }while(--step);
-
- /* calc pcm * volume data */
- ch->adpcm_out = ((ch->adpcm_acc * ch->vol_mul) >> ch->vol_shift) & ~3; /* multiply, shift and mask out 2 LSB bits */
- }
-
- /* output for work of output channels (out_adpcm[OPNxxxx])*/
- *(ch->pan) += ch->adpcm_out;
- }
-
- /* ADPCM type A Write */
- void FM_ADPCMAWrite(int r,int v)
- {
- uint8_t c = r&0x07;
-
- adpcmreg[r] = v&0xff; /* stock data */
- switch( r )
- {
- case 0x00: /* DM,--,C5,C4,C3,C2,C1,C0 */
- if( !(v&0x80) )
- {
- /* KEY ON */
- for( c = 0; c < 6; c++ )
- {
- if( (v>>c)&1 )
- {
- /**** start adpcm ****/
- adpcm[c].step = (uint32_t)((float)(1<<ADPCM_SHIFT)*((float)OPN.ST.freqbase)/3.0f);
- adpcm[c].now_addr = adpcm[c].start<<1;
- adpcm[c].now_step = 0;
- adpcm[c].adpcm_acc = 0;
- adpcm[c].adpcm_step= 0;
- adpcm[c].adpcm_out = 0;
- adpcm[c].flag = 1;
- }
- }
- }
- else
- {
- /* KEY OFF */
- for( c = 0; c < 6; c++ )
- if( (v>>c)&1 )
- adpcm[c].flag = 0;
- }
- break;
- case 0x01: /* B0-5 = TL */
- adpcmTL = (v & 0x3f) ^ 0x3f;
- for( c = 0; c < 6; c++ )
- {
- int volume = adpcmTL + adpcm[c].IL;
-
- if ( volume >= 63 ) /* This is correct, 63 = quiet */
- {
- adpcm[c].vol_mul = 0;
- adpcm[c].vol_shift = 0;
- }
- else
- {
- adpcm[c].vol_mul = 15 - (volume & 7); /* so called 0.75 dB */
- adpcm[c].vol_shift = 1 + (volume >> 3); /* Yamaha engineers used the approximation: each -6 dB is close to divide by two (shift right) */
- }
-
- /* calc pcm * volume data */
- adpcm[c].adpcm_out = ((adpcm[c].adpcm_acc * adpcm[c].vol_mul) >> adpcm[c].vol_shift) & ~3; /* multiply, shift and mask out low 2 bits */
- }
- break;
- default:
- c = r&0x07;
- if( c >= 0x06 ) return;
- switch( r&0x38 )
- {
- case 0x08: /* B7=L,B6=R, B4-0=IL */
- {
- int volume;
-
- adpcm[c].IL = (v & 0x1f) ^ 0x1f;
-
- volume = adpcmTL + adpcm[c].IL;
-
- if ( volume >= 63 ) /* This is correct, 63 = quiet */
- {
- adpcm[c].vol_mul = 0;
- adpcm[c].vol_shift = 0;
- }
- else
- {
- adpcm[c].vol_mul = 15 - (volume & 7); /* so called 0.75 dB */
- adpcm[c].vol_shift = 1 + (volume >> 3); /* Yamaha engineers used the approximation: each -6 dB is close to divide by two (shift right) */
- }
-
- adpcm[c].pan = &OPN.out_adpcm[(v>>6)&0x03];
-
- /* calc pcm * volume data */
- adpcm[c].adpcm_out = ((adpcm[c].adpcm_acc * adpcm[c].vol_mul) >> adpcm[c].vol_shift) & ~3; /* multiply, shift and mask out low 2 bits */
- }
- break;
- case 0x10:
- case 0x18:
- adpcm[c].start = ( (adpcmreg[0x18 + c]*0x0100 | adpcmreg[0x10 + c]) << ADPCMA_ADDRESS_SHIFT);
- break;
- case 0x20:
- case 0x28:
- adpcm[c].end = ( (adpcmreg[0x28 + c]*0x0100 | adpcmreg[0x20 + c]) << ADPCMA_ADDRESS_SHIFT);
- adpcm[c].end += (1<<ADPCMA_ADDRESS_SHIFT) - 1;
- break;
- }
- }
- }
-
-};
-
-constexpr int ym2610_state::step_inc[8];
-
-/* here is the virtual YM2608 */
-typedef ym2610_state ym2608_state;
-
-
-/* Algorithm and tables verified on real YM2608 and YM2610 */
-
-/* usual ADPCM table (16 * 1.1^N) */
-constexpr int steps[49] =
-{
- 16, 17, 19, 21, 23, 25, 28,
- 31, 34, 37, 41, 45, 50, 55,
- 60, 66, 73, 80, 88, 97, 107,
- 118, 130, 143, 157, 173, 190, 209,
- 230, 253, 279, 307, 337, 371, 408,
- 449, 494, 544, 598, 658, 724, 796,
- 876, 963, 1060, 1166, 1282, 1411, 1552
-};
-
-
-void Init_ADPCMATable()
-{
- int step, nib;
-
- for (step = 0; step < 49; step++)
- {
- /* loop over all nibbles and compute the difference */
- for (nib = 0; nib < 16; nib++)
- {
- int value = (2*(nib & 0x07) + 1) * steps[step] / 8;
- jedi_table[step*16 + nib] = (nib&0x08) ? -value : value;
- }
- }
-}
-
-#ifdef MAME_EMU_SAVE_H
-/* FM channel save , internal state only */
-void FMsave_state_adpcma(device_t *device,ADPCM_CH *adpcm)
-{
- int ch;
-
- for(ch=0;ch<6;ch++,adpcm++)
- {
- device->save_item(NAME(adpcm->flag), ch);
- device->save_item(NAME(adpcm->now_data), ch);
- device->save_item(NAME(adpcm->now_addr), ch);
- device->save_item(NAME(adpcm->now_step), ch);
- device->save_item(NAME(adpcm->adpcm_acc), ch);
- device->save_item(NAME(adpcm->adpcm_step), ch);
- device->save_item(NAME(adpcm->adpcm_out), ch);
- }
-}
-#endif /* MAME_EMU_SAVE_H */
-} // anonymous namespace
-
-#endif /* (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B) */
-
-
-#if BUILD_YM2608
-/*****************************************************************************/
-/* YM2608 local section */
-/*****************************************************************************/
-
-
-
-static const unsigned int YM2608_ADPCM_ROM_addr[2*6] = {
-0x0000, 0x01bf, /* bass drum */
-0x01c0, 0x043f, /* snare drum */
-0x0440, 0x1b7f, /* top cymbal */
-0x1b80, 0x1cff, /* high hat */
-0x1d00, 0x1f7f, /* tom tom */
-0x1f80, 0x1fff /* rim shot */
-};
-
-
-/* flag enable control 0x110 */
-static inline void YM2608IRQFlagWrite(FM_OPN *OPN, ym2608_state *F2608, int v)
-{
- if( v & 0x80 )
- { /* Reset IRQ flag */
- FM_STATUS_RESET(&OPN->ST, 0xf7); /* don't touch BUFRDY flag otherwise we'd have to call ymdeltat module to set the flag back */
- }
- else
- { /* Set status flag mask */
- F2608->flagmask = (~(v&0x1f));
- FM_IRQMASK_SET(&OPN->ST, (F2608->irqmask & F2608->flagmask) );
- }
-}
-
-/* compatible mode & IRQ enable control 0x29 */
-static inline void YM2608IRQMaskWrite(FM_OPN *OPN, ym2608_state *F2608, int v)
-{
- /* SCH,xx,xxx,EN_ZERO,EN_BRDY,EN_EOS,EN_TB,EN_TA */
-
- /* extend 3ch. enable/disable */
- if(v&0x80)
- OPN->type |= TYPE_6CH; /* OPNA mode - 6 FM channels */
- else
- OPN->type &= ~TYPE_6CH; /* OPN mode - 3 FM channels */
-
- /* IRQ MASK store and set */
- F2608->irqmask = v&0x1f;
- FM_IRQMASK_SET(&OPN->ST, (F2608->irqmask & F2608->flagmask) );
-}
-
-/* Generate samples for one of the YM2608s */
-void ym2608_update_one(void *chip, FMSAMPLE **buffer, int length)
-{
- ym2608_state *F2608 = (ym2608_state *)chip;
- FM_OPN *OPN = &F2608->OPN;
- YM_DELTAT *DELTAT = &F2608->deltaT;
- int i,j;
- FMSAMPLE *bufL,*bufR;
- FM_CH *cch[6];
- int32_t *out_fm = OPN->out_fm;
-
- /* set bufer */
- bufL = buffer[0];
- bufR = buffer[1];
-
- cch[0] = &F2608->CH[0];
- cch[1] = &F2608->CH[1];
- cch[2] = &F2608->CH[2];
- cch[3] = &F2608->CH[3];
- cch[4] = &F2608->CH[4];
- cch[5] = &F2608->CH[5];
-
- /* refresh PG and EG */
- refresh_fc_eg_chan( OPN, cch[0] );
- refresh_fc_eg_chan( OPN, cch[1] );
- if( (OPN->ST.mode & 0xc0) )
- {
- /* 3SLOT MODE */
- if( cch[2]->SLOT[SLOT1].Incr==-1)
- {
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] );
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode );
- }
- }
- else
- refresh_fc_eg_chan( OPN, cch[2] );
- refresh_fc_eg_chan( OPN, cch[3] );
- refresh_fc_eg_chan( OPN, cch[4] );
- refresh_fc_eg_chan( OPN, cch[5] );
-
-
- /* buffering */
- for(i=0; i < length ; i++)
- {
- advance_lfo(OPN);
-
- /* clear output acc. */
- OPN->out_adpcm[OUTD_LEFT] = OPN->out_adpcm[OUTD_RIGHT] = OPN->out_adpcm[OUTD_CENTER] = 0;
- OPN->out_delta[OUTD_LEFT] = OPN->out_delta[OUTD_RIGHT] = OPN->out_delta[OUTD_CENTER] = 0;
- /* clear outputs */
- out_fm[0] = 0;
- out_fm[1] = 0;
- out_fm[2] = 0;
- out_fm[3] = 0;
- out_fm[4] = 0;
- out_fm[5] = 0;
-
- /* calculate FM */
- chan_calc(OPN, cch[0], 0 );
- chan_calc(OPN, cch[1], 1 );
- chan_calc(OPN, cch[2], 2 );
- chan_calc(OPN, cch[3], 3 );
- chan_calc(OPN, cch[4], 4 );
- chan_calc(OPN, cch[5], 5 );
-
- /* deltaT ADPCM */
- if( DELTAT->portstate&0x80 )
- DELTAT->ADPCM_CALC();
-
- /* ADPCMA */
- for( j = 0; j < 6; j++ )
- {
- if( F2608->adpcm[j].flag )
- F2608->ADPCMA_calc_chan( &F2608->adpcm[j]);
- }
-
- /* advance envelope generator */
- OPN->eg_timer += OPN->eg_timer_add;
- while (OPN->eg_timer >= OPN->eg_timer_overflow)
- {
- OPN->eg_timer -= OPN->eg_timer_overflow;
- OPN->eg_cnt++;
-
- advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[3]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[4]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[5]->SLOT[SLOT1]);
- }
-
- /* buffering */
- {
- int lt,rt;
-
- lt = OPN->out_adpcm[OUTD_LEFT] + OPN->out_adpcm[OUTD_CENTER];
- rt = OPN->out_adpcm[OUTD_RIGHT] + OPN->out_adpcm[OUTD_CENTER];
- lt += (OPN->out_delta[OUTD_LEFT] + OPN->out_delta[OUTD_CENTER])>>9;
- rt += (OPN->out_delta[OUTD_RIGHT] + OPN->out_delta[OUTD_CENTER])>>9;
- lt += ((out_fm[0]>>1) & OPN->pan[0]); /* shift right verified on real YM2608 */
- rt += ((out_fm[0]>>1) & OPN->pan[1]);
- lt += ((out_fm[1]>>1) & OPN->pan[2]);
- rt += ((out_fm[1]>>1) & OPN->pan[3]);
- lt += ((out_fm[2]>>1) & OPN->pan[4]);
- rt += ((out_fm[2]>>1) & OPN->pan[5]);
- lt += ((out_fm[3]>>1) & OPN->pan[6]);
- rt += ((out_fm[3]>>1) & OPN->pan[7]);
- lt += ((out_fm[4]>>1) & OPN->pan[8]);
- rt += ((out_fm[4]>>1) & OPN->pan[9]);
- lt += ((out_fm[5]>>1) & OPN->pan[10]);
- rt += ((out_fm[5]>>1) & OPN->pan[11]);
-
- lt >>= FINAL_SH;
- rt >>= FINAL_SH;
-
- Limit( lt, MAXOUT, MINOUT );
- Limit( rt, MAXOUT, MINOUT );
- /* buffering */
- bufL[i] = lt;
- bufR[i] = rt;
-
- #ifdef SAVE_SAMPLE
- SAVE_ALL_CHANNELS
- #endif
-
- }
-
- /* timer A control */
- INTERNAL_TIMER_A( &OPN->ST , cch[2] )
- }
- INTERNAL_TIMER_B(&OPN->ST,length)
-
-
- /* check IRQ for DELTA-T EOS */
- FM_STATUS_SET(&OPN->ST, 0);
-
-}
-#ifdef MAME_EMU_SAVE_H
-void ym2608_postload(void *chip)
-{
- if (chip)
- {
- ym2608_state *F2608 = (ym2608_state *)chip;
- int r;
-
- /* prescaler */
- OPNPrescaler_w(&F2608->OPN,1,2);
- F2608->deltaT.freqbase = F2608->OPN.ST.freqbase;
- /* IRQ mask / mode */
- YM2608IRQMaskWrite(&F2608->OPN, F2608, F2608->REGS[0x29]);
- /* SSG registers */
- for(r=0;r<16;r++)
- {
- (*F2608->OPN.ST.SSG->write)(F2608->OPN.ST.device,0,r);
- (*F2608->OPN.ST.SSG->write)(F2608->OPN.ST.device,1,F2608->REGS[r]);
- }
-
- /* OPN registers */
- /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */
- for(r=0x30;r<0x9e;r++)
- if((r&3) != 3)
- {
- OPNWriteReg(&F2608->OPN,r,F2608->REGS[r]);
- OPNWriteReg(&F2608->OPN,r|0x100,F2608->REGS[r|0x100]);
- }
- /* FB / CONNECT , L / R / AMS / PMS */
- for(r=0xb0;r<0xb6;r++)
- if((r&3) != 3)
- {
- OPNWriteReg(&F2608->OPN,r,F2608->REGS[r]);
- OPNWriteReg(&F2608->OPN,r|0x100,F2608->REGS[r|0x100]);
- }
- /* FM channels */
- /*FM_channel_postload(F2608->CH,6);*/
- /* rhythm(ADPCMA) */
- F2608->FM_ADPCMAWrite(1,F2608->REGS[0x111]);
- for( r=0x08 ; r<0x0c ; r++)
- F2608->FM_ADPCMAWrite(r,F2608->REGS[r+0x110]);
- /* Delta-T ADPCM unit */
- F2608->deltaT.postload( &F2608->REGS[0x100] );
- }
-}
-
-static void YM2608_save_state(ym2608_state *F2608, device_t *device)
-{
- device->save_item(NAME(F2608->REGS));
- FMsave_state_st(device,&F2608->OPN.ST);
- FMsave_state_channel(device,F2608->CH,6);
- /* 3slots */
- device->save_item(NAME(F2608->OPN.SL3.fc));
- device->save_item(NAME(F2608->OPN.SL3.fn_h));
- device->save_item(NAME(F2608->OPN.SL3.kcode));
- /* address register1 */
- device->save_item(NAME(F2608->addr_A1));
- /* rhythm(ADPCMA) */
- FMsave_state_adpcma(device,F2608->adpcm);
- /* Delta-T ADPCM unit */
- F2608->deltaT.savestate(device);
-}
-#endif /* MAME_EMU_SAVE_H */
-
-static void YM2608_deltat_status_set(void *chip, uint8_t changebits)
-{
- ym2608_state *F2608 = (ym2608_state *)chip;
- FM_STATUS_SET(&(F2608->OPN.ST), changebits);
-}
-static void YM2608_deltat_status_reset(void *chip, uint8_t changebits)
-{
- ym2608_state *F2608 = (ym2608_state *)chip;
- FM_STATUS_RESET(&(F2608->OPN.ST), changebits);
-}
-/* YM2608(OPNA) */
-void * ym2608_init(device_t *device, int clock, int rate,
- FM_READBYTE InternalReadByte,
- FM_READBYTE ExternalReadByte, FM_WRITEBYTE ExternalWriteByte,
- FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler, const ssg_callbacks *ssg)
-{
- ym2608_state *F2608;
-
- /* allocate extend state space */
- F2608 = auto_alloc_clear(device->machine(), <ym2608_state>());
- /* allocate total level table (128kb space) */
- if( !init_tables() )
- {
- auto_free( device->machine(), F2608 );
- return nullptr;
- }
-
- F2608->device = device;
- F2608->OPN.type = TYPE_YM2608;
- F2608->OPN.P_CH = F2608->CH;
- F2608->OPN.ST.device = device;
- F2608->OPN.ST.clock = clock;
- F2608->OPN.ST.rate = rate;
-
- /* External handlers */
- F2608->OPN.ST.timer_handler = timer_handler;
- F2608->OPN.ST.IRQ_Handler = IRQHandler;
- F2608->OPN.ST.SSG = ssg;
-
- /* DELTA-T */
- F2608->deltaT.read_byte = ExternalReadByte;
- F2608->deltaT.write_byte = ExternalWriteByte;
-
- /*F2608->deltaT.write_time = 20.0 / clock;*/ /* a single byte write takes 20 cycles of main clock */
- /*F2608->deltaT.read_time = 18.0 / clock;*/ /* a single byte read takes 18 cycles of main clock */
-
- F2608->deltaT.status_set_handler = YM2608_deltat_status_set;
- F2608->deltaT.status_reset_handler = YM2608_deltat_status_reset;
- F2608->deltaT.status_change_which_chip = F2608;
- F2608->deltaT.status_change_EOS_bit = 0x04; /* status flag: set bit2 on End Of Sample */
- F2608->deltaT.status_change_BRDY_bit = 0x08; /* status flag: set bit3 on BRDY */
- F2608->deltaT.status_change_ZERO_bit = 0x10; /* status flag: set bit4 if silence continues for more than 290 milliseconds while recording the ADPCM */
-
- /* ADPCM Rhythm */
- F2608->read_byte = InternalReadByte;
-
- Init_ADPCMATable();
-
-#ifdef MAME_EMU_SAVE_H
- YM2608_save_state(F2608, device);
-#endif
- return F2608;
-}
-
-void ym2608_clock_changed(void *chip, int clock, int rate)
-{
- ym2608_state *F2608 = (ym2608_state *)chip;
-
- F2608->OPN.ST.clock = clock;
- F2608->OPN.ST.rate = rate;
-}
-
-/* shut down emulator */
-void ym2608_shutdown(void *chip)
-{
- ym2608_state *F2608 = (ym2608_state *)chip;
-
- FMCloseTable();
- auto_free(F2608->OPN.ST.device->machine(), F2608);
-}
-
-/* reset one of chips */
-void ym2608_reset_chip(void *chip)
-{
- int i;
- ym2608_state *F2608 = (ym2608_state *)chip;
- FM_OPN *OPN = &F2608->OPN;
- YM_DELTAT *DELTAT = &F2608->deltaT;
-
- /* Reset Prescaler */
- OPNPrescaler_w(OPN , 0 , 2);
- F2608->deltaT.freqbase = OPN->ST.freqbase;
- /* reset SSG section */
- (*OPN->ST.SSG->reset)(OPN->ST.device);
-
- /* status clear */
- FM_BUSY_CLEAR(&OPN->ST);
-
- /* register 0x29 - default value after reset is:
- enable only 3 FM channels and enable all the status flags */
- YM2608IRQMaskWrite(OPN, F2608, 0x1f ); /* default value for D4-D0 is 1 */
-
- /* register 0x10, A1=1 - default value is 1 for D4, D3, D2, 0 for the rest */
- YM2608IRQFlagWrite(OPN, F2608, 0x1c ); /* default: enable timer A and B, disable EOS, BRDY and ZERO */
-
- OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */
-
- OPN->eg_timer = 0;
- OPN->eg_cnt = 0;
-
- FM_STATUS_RESET(&OPN->ST, 0xff);
-
- reset_channels( &OPN->ST , F2608->CH , 6 );
- /* reset OPerator paramater */
- for(i = 0xb6 ; i >= 0xb4 ; i-- )
- {
- OPNWriteReg(OPN,i ,0xc0);
- OPNWriteReg(OPN,i|0x100,0xc0);
- }
- for(i = 0xb2 ; i >= 0x30 ; i-- )
- {
- OPNWriteReg(OPN,i ,0);
- OPNWriteReg(OPN,i|0x100,0);
- }
- for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
-
- /* ADPCM - percussion sounds */
- for( i = 0; i < 6; i++ )
- {
- if (i<=3) /* channels 0,1,2,3 */
- F2608->adpcm[i].step = (uint32_t)((float)(1<<ADPCM_SHIFT)*((float)F2608->OPN.ST.freqbase)/3.0f);
- else /* channels 4 and 5 work with slower clock */
- F2608->adpcm[i].step = (uint32_t)((float)(1<<ADPCM_SHIFT)*((float)F2608->OPN.ST.freqbase)/6.0f);
-
- F2608->adpcm[i].start = YM2608_ADPCM_ROM_addr[i*2];
- F2608->adpcm[i].end = YM2608_ADPCM_ROM_addr[i*2+1];
-
- F2608->adpcm[i].now_addr = 0;
- F2608->adpcm[i].now_step = 0;
- /* F2608->adpcm[i].delta = 21866; */
- F2608->adpcm[i].vol_mul = 0;
- F2608->adpcm[i].pan = &OPN->out_adpcm[OUTD_CENTER]; /* default center */
- F2608->adpcm[i].flagMask = 0;
- F2608->adpcm[i].flag = 0;
- F2608->adpcm[i].adpcm_acc = 0;
- F2608->adpcm[i].adpcm_step= 0;
- F2608->adpcm[i].adpcm_out = 0;
- }
- F2608->adpcmTL = 0x3f;
-
- F2608->adpcm_arrivedEndAddress = 0; /* not used */
-
- /* DELTA-T unit */
- DELTAT->freqbase = OPN->ST.freqbase;
- DELTAT->output_pointer = OPN->out_delta;
- DELTAT->portshift = 5; /* always 5bits shift */ /* ASG */
- DELTAT->output_range = 1<<23;
- DELTAT->ADPCM_Reset(OUTD_CENTER,YM_DELTAT::EMULATION_MODE_NORMAL,F2608->device);
-}
-
-/* YM2608 write */
-/* n = number */
-/* a = address */
-/* v = value */
-int ym2608_write(void *chip, int a,uint8_t v)
-{
- ym2608_state *F2608 = (ym2608_state *)chip;
- FM_OPN *OPN = &F2608->OPN;
- int addr;
-
- v &= 0xff; /*adjust to 8 bit bus */
-
-
- switch(a&3)
- {
- case 0: /* address port 0 */
- OPN->ST.address = v;
- F2608->addr_A1 = 0;
-
- /* Write register to SSG emulator */
- if( v < 16 ) (*OPN->ST.SSG->write)(OPN->ST.device,0,v);
- /* prescaler selecter : 2d,2e,2f */
- if( v >= 0x2d && v <= 0x2f )
- {
- OPNPrescaler_w(OPN , v , 2);
- F2608->deltaT.freqbase = OPN->ST.freqbase;
- }
- break;
-
- case 1: /* data port 0 */
- if (F2608->addr_A1 != 0)
- break; /* verified on real YM2608 */
-
- addr = OPN->ST.address;
- F2608->REGS[addr] = v;
- switch(addr & 0xf0)
- {
- case 0x00: /* SSG section */
- /* Write data to SSG emulator */
- (*OPN->ST.SSG->write)(OPN->ST.device,a,v);
- break;
- case 0x10: /* 0x10-0x1f : Rhythm section */
- ym2608_device::update_request(OPN->ST.device);
- F2608->FM_ADPCMAWrite(addr-0x10,v);
- break;
- case 0x20: /* Mode Register */
- switch(addr)
- {
- case 0x29: /* SCH,xx,xxx,EN_ZERO,EN_BRDY,EN_EOS,EN_TB,EN_TA */
- YM2608IRQMaskWrite(OPN, F2608, v);
- break;
- default:
- ym2608_device::update_request(OPN->ST.device);
- OPNWriteMode(OPN,addr,v);
- }
- break;
- default: /* OPN section */
- ym2608_device::update_request(OPN->ST.device);
- OPNWriteReg(OPN,addr,v);
- }
- break;
-
- case 2: /* address port 1 */
- OPN->ST.address = v;
- F2608->addr_A1 = 1;
- break;
-
- case 3: /* data port 1 */
- if (F2608->addr_A1 != 1)
- break; /* verified on real YM2608 */
-
- addr = OPN->ST.address;
- F2608->REGS[addr | 0x100] = v;
- ym2608_device::update_request(OPN->ST.device);
- switch( addr & 0xf0 )
- {
- case 0x00: /* DELTAT PORT */
- switch( addr )
- {
- case 0x0e: /* DAC data */
- F2608->device->logerror("YM2608: write to DAC data (unimplemented) value=%02x\n",v);
- break;
- default:
- /* 0x00-0x0d */
- F2608->deltaT.ADPCM_Write(addr,v);
- }
- break;
- case 0x10: /* IRQ Flag control */
- if( addr == 0x10 )
- {
- YM2608IRQFlagWrite(OPN, F2608, v);
- }
- break;
- default:
- OPNWriteReg(OPN,addr | 0x100,v);
- }
- }
- return OPN->ST.irq;
-}
-
-uint8_t ym2608_read(void *chip,int a)
-{
- ym2608_state *F2608 = (ym2608_state *)chip;
- int addr = F2608->OPN.ST.address;
- uint8_t ret = 0;
-
- switch( a&3 )
- {
- case 0: /* status 0 : YM2203 compatible */
- /* BUSY:x:x:x:x:x:FLAGB:FLAGA */
- ret = FM_STATUS_FLAG(&F2608->OPN.ST) & 0x83;
- break;
-
- case 1: /* status 0, ID */
- if( addr < 16 ) ret = (*F2608->OPN.ST.SSG->read)(F2608->OPN.ST.device);
- else if(addr == 0xff) ret = 0x01; /* ID code */
- break;
-
- case 2: /* status 1 : status 0 + ADPCM status */
- /* BUSY : x : PCMBUSY : ZERO : BRDY : EOS : FLAGB : FLAGA */
- ret = (FM_STATUS_FLAG(&F2608->OPN.ST) & (F2608->flagmask|0x80)) | ((F2608->deltaT.PCM_BSY & 1)<<5) ;
- break;
-
- case 3:
- if(addr == 0x08)
- {
- ret = F2608->deltaT.ADPCM_Read();
- }
- else
- {
- if(addr == 0x0f)
- {
- F2608->device->logerror("YM2608 A/D conversion is accessed but not implemented !\n");
- ret = 0x80; /* 2's complement PCM data - result from A/D conversion */
- }
- }
- break;
- }
- return ret;
-}
-
-int ym2608_timer_over(void *chip,int c)
-{
- ym2608_state *F2608 = (ym2608_state *)chip;
-
- switch(c)
- {
-#if 0
- case 2:
- { /* BUFRDY flag */
- F2608->deltaT.BRDY_callback();
- }
- break;
-#endif
- case 1:
- { /* Timer B */
- TimerBOver( &(F2608->OPN.ST) );
- }
- break;
- case 0:
- { /* Timer A */
- ym2608_device::update_request(F2608->OPN.ST.device);
- /* timer update */
- TimerAOver( &(F2608->OPN.ST) );
- /* CSM mode key,TL controll */
- if( F2608->OPN.ST.mode & 0x80 )
- { /* CSM mode total level latch and auto key on */
- CSMKeyControll( F2608->OPN.type, &(F2608->CH[2]) );
- }
- }
- break;
- default:
- break;
- }
-
- return F2608->OPN.ST.irq;
-}
-
-#endif /* BUILD_YM2608 */
-
-
-
-#if (BUILD_YM2610||BUILD_YM2610B)
-/* YM2610(OPNB) */
-
-/* Generate samples for one of the YM2610s */
-void ym2610_update_one(void *chip, FMSAMPLE **buffer, int length)
-{
- ym2610_state *F2610 = (ym2610_state *)chip;
- FM_OPN *OPN = &F2610->OPN;
- YM_DELTAT *DELTAT = &F2610->deltaT;
- int i,j;
- FMSAMPLE *bufL,*bufR;
- FM_CH *cch[4];
- int32_t *out_fm = OPN->out_fm;
-
- /* buffer setup */
- bufL = buffer[0];
- bufR = buffer[1];
-
- cch[0] = &F2610->CH[1];
- cch[1] = &F2610->CH[2];
- cch[2] = &F2610->CH[4];
- cch[3] = &F2610->CH[5];
-
-#ifdef YM2610B_WARNING
-#define FM_KEY_IS(SLOT) ((SLOT)->key)
-#define FM_MSG_YM2610B "YM2610-%p.CH%d is playing,Check whether the type of the chip is YM2610B\n"
- /* Check YM2610B warning message */
- if( FM_KEY_IS(&F2610->CH[0].SLOT[3]) )
- LOG(F2610->device,LOG_WAR,(FM_MSG_YM2610B,F2610->OPN.ST.device,0));
- if( FM_KEY_IS(&F2610->CH[3].SLOT[3]) )
- LOG(F2610->device,LOG_WAR,(FM_MSG_YM2610B,F2610->OPN.ST.device,3));
-#endif
-
- /* refresh PG and EG */
- refresh_fc_eg_chan( OPN, cch[0] );
- if( (OPN->ST.mode & 0xc0) )
- {
- /* 3SLOT MODE */
- if( cch[1]->SLOT[SLOT1].Incr==-1)
- {
- refresh_fc_eg_slot(OPN, &cch[1]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] );
- refresh_fc_eg_slot(OPN, &cch[1]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
- refresh_fc_eg_slot(OPN, &cch[1]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
- refresh_fc_eg_slot(OPN, &cch[1]->SLOT[SLOT4] , cch[1]->fc , cch[1]->kcode );
- }
- }
- else
- refresh_fc_eg_chan( OPN, cch[1] );
- refresh_fc_eg_chan( OPN, cch[2] );
- refresh_fc_eg_chan( OPN, cch[3] );
-
- /* buffering */
- for(i=0; i < length ; i++)
- {
- advance_lfo(OPN);
-
- /* clear output acc. */
- OPN->out_adpcm[OUTD_LEFT] = OPN->out_adpcm[OUTD_RIGHT] = OPN->out_adpcm[OUTD_CENTER] = 0;
- OPN->out_delta[OUTD_LEFT] = OPN->out_delta[OUTD_RIGHT] = OPN->out_delta[OUTD_CENTER] = 0;
- /* clear outputs */
- out_fm[1] = 0;
- out_fm[2] = 0;
- out_fm[4] = 0;
- out_fm[5] = 0;
-
- /* advance envelope generator */
- OPN->eg_timer += OPN->eg_timer_add;
- while (OPN->eg_timer >= OPN->eg_timer_overflow)
- {
- OPN->eg_timer -= OPN->eg_timer_overflow;
- OPN->eg_cnt++;
-
- advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[3]->SLOT[SLOT1]);
- }
-
- /* calculate FM */
- chan_calc(OPN, cch[0], 1 ); /*remapped to 1*/
- chan_calc(OPN, cch[1], 2 ); /*remapped to 2*/
- chan_calc(OPN, cch[2], 4 ); /*remapped to 4*/
- chan_calc(OPN, cch[3], 5 ); /*remapped to 5*/
-
- /* deltaT ADPCM */
- if( DELTAT->portstate&0x80 )
- DELTAT->ADPCM_CALC();
-
- /* ADPCMA */
- for( j = 0; j < 6; j++ )
- {
- if( F2610->adpcm[j].flag )
- F2610->ADPCMA_calc_chan(&F2610->adpcm[j]);
- }
-
- /* buffering */
- {
- int lt,rt;
-
- lt = OPN->out_adpcm[OUTD_LEFT] + OPN->out_adpcm[OUTD_CENTER];
- rt = OPN->out_adpcm[OUTD_RIGHT] + OPN->out_adpcm[OUTD_CENTER];
- lt += (OPN->out_delta[OUTD_LEFT] + OPN->out_delta[OUTD_CENTER])>>9;
- rt += (OPN->out_delta[OUTD_RIGHT] + OPN->out_delta[OUTD_CENTER])>>9;
-
-
- lt += ((out_fm[1]>>1) & OPN->pan[2]); /* the shift right was verified on real chip */
- rt += ((out_fm[1]>>1) & OPN->pan[3]);
- lt += ((out_fm[2]>>1) & OPN->pan[4]);
- rt += ((out_fm[2]>>1) & OPN->pan[5]);
-
- lt += ((out_fm[4]>>1) & OPN->pan[8]);
- rt += ((out_fm[4]>>1) & OPN->pan[9]);
- lt += ((out_fm[5]>>1) & OPN->pan[10]);
- rt += ((out_fm[5]>>1) & OPN->pan[11]);
-
-
- lt >>= FINAL_SH;
- rt >>= FINAL_SH;
-
- Limit( lt, MAXOUT, MINOUT );
- Limit( rt, MAXOUT, MINOUT );
-
- #ifdef SAVE_SAMPLE
- SAVE_ALL_CHANNELS
- #endif
-
- /* buffering */
- bufL[i] = lt;
- bufR[i] = rt;
- }
-
- /* timer A control */
- INTERNAL_TIMER_A( &OPN->ST , cch[1] )
- }
- INTERNAL_TIMER_B(&OPN->ST,length)
-
-}
-
-#if BUILD_YM2610B
-/* Generate samples for one of the YM2610Bs */
-void ym2610b_update_one(void *chip, FMSAMPLE **buffer, int length)
-{
- ym2610_state *F2610 = (ym2610_state *)chip;
- FM_OPN *OPN = &F2610->OPN;
- YM_DELTAT *DELTAT = &F2610->deltaT;
- int i,j;
- FMSAMPLE *bufL,*bufR;
- FM_CH *cch[6];
- int32_t *out_fm = OPN->out_fm;
-
- /* buffer setup */
- bufL = buffer[0];
- bufR = buffer[1];
-
- cch[0] = &F2610->CH[0];
- cch[1] = &F2610->CH[1];
- cch[2] = &F2610->CH[2];
- cch[3] = &F2610->CH[3];
- cch[4] = &F2610->CH[4];
- cch[5] = &F2610->CH[5];
-
- /* refresh PG and EG */
- refresh_fc_eg_chan( OPN, cch[0] );
- refresh_fc_eg_chan( OPN, cch[1] );
- if( (OPN->ST.mode & 0xc0) )
- {
- /* 3SLOT MODE */
- if( cch[2]->SLOT[SLOT1].Incr==-1)
- {
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] );
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] );
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] );
- refresh_fc_eg_slot(OPN, &cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode );
- }
- }
- else
- refresh_fc_eg_chan( OPN, cch[2] );
- refresh_fc_eg_chan( OPN, cch[3] );
- refresh_fc_eg_chan( OPN, cch[4] );
- refresh_fc_eg_chan( OPN, cch[5] );
-
- /* buffering */
- for(i=0; i < length ; i++)
- {
- advance_lfo(OPN);
-
- /* clear output acc. */
- OPN->out_adpcm[OUTD_LEFT] = OPN->out_adpcm[OUTD_RIGHT] = OPN->out_adpcm[OUTD_CENTER] = 0;
- OPN->out_delta[OUTD_LEFT] = OPN->out_delta[OUTD_RIGHT] = OPN->out_delta[OUTD_CENTER] = 0;
- /* clear outputs */
- out_fm[0] = 0;
- out_fm[1] = 0;
- out_fm[2] = 0;
- out_fm[3] = 0;
- out_fm[4] = 0;
- out_fm[5] = 0;
-
- /* advance envelope generator */
- OPN->eg_timer += OPN->eg_timer_add;
- while (OPN->eg_timer >= OPN->eg_timer_overflow)
- {
- OPN->eg_timer -= OPN->eg_timer_overflow;
- OPN->eg_cnt++;
-
- advance_eg_channel(OPN, &cch[0]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[1]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[2]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[3]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[4]->SLOT[SLOT1]);
- advance_eg_channel(OPN, &cch[5]->SLOT[SLOT1]);
- }
-
- /* calculate FM */
- chan_calc(OPN, cch[0], 0 );
- chan_calc(OPN, cch[1], 1 );
- chan_calc(OPN, cch[2], 2 );
- chan_calc(OPN, cch[3], 3 );
- chan_calc(OPN, cch[4], 4 );
- chan_calc(OPN, cch[5], 5 );
-
- /* deltaT ADPCM */
- if( DELTAT->portstate&0x80 )
- DELTAT->ADPCM_CALC();
-
- /* ADPCMA */
- for( j = 0; j < 6; j++ )
- {
- if( F2610->adpcm[j].flag )
- F2610->ADPCMA_calc_chan(&F2610->adpcm[j]);
- }
-
- /* buffering */
- {
- int lt,rt;
-
- lt = OPN->out_adpcm[OUTD_LEFT] + OPN->out_adpcm[OUTD_CENTER];
- rt = OPN->out_adpcm[OUTD_RIGHT] + OPN->out_adpcm[OUTD_CENTER];
- lt += (OPN->out_delta[OUTD_LEFT] + OPN->out_delta[OUTD_CENTER])>>9;
- rt += (OPN->out_delta[OUTD_RIGHT] + OPN->out_delta[OUTD_CENTER])>>9;
-
- lt += ((out_fm[0]>>1) & OPN->pan[0]); /* the shift right is verified on YM2610 */
- rt += ((out_fm[0]>>1) & OPN->pan[1]);
- lt += ((out_fm[1]>>1) & OPN->pan[2]);
- rt += ((out_fm[1]>>1) & OPN->pan[3]);
- lt += ((out_fm[2]>>1) & OPN->pan[4]);
- rt += ((out_fm[2]>>1) & OPN->pan[5]);
- lt += ((out_fm[3]>>1) & OPN->pan[6]);
- rt += ((out_fm[3]>>1) & OPN->pan[7]);
- lt += ((out_fm[4]>>1) & OPN->pan[8]);
- rt += ((out_fm[4]>>1) & OPN->pan[9]);
- lt += ((out_fm[5]>>1) & OPN->pan[10]);
- rt += ((out_fm[5]>>1) & OPN->pan[11]);
-
-
- lt >>= FINAL_SH;
- rt >>= FINAL_SH;
-
- Limit( lt, MAXOUT, MINOUT );
- Limit( rt, MAXOUT, MINOUT );
-
- #ifdef SAVE_SAMPLE
- SAVE_ALL_CHANNELS
- #endif
-
- /* buffering */
- bufL[i] = lt;
- bufR[i] = rt;
- }
-
- /* timer A control */
- INTERNAL_TIMER_A( &OPN->ST , cch[2] )
- }
- INTERNAL_TIMER_B(&OPN->ST,length)
-
-}
-#endif /* BUILD_YM2610B */
-
-
-#ifdef MAME_EMU_SAVE_H
-void ym2610_postload(void *chip)
-{
- if (chip)
- {
- ym2610_state *F2610 = (ym2610_state *)chip;
- int r;
-
- /* SSG registers */
- for(r=0;r<16;r++)
- {
- (*F2610->OPN.ST.SSG->write)(F2610->OPN.ST.device,0,r);
- (*F2610->OPN.ST.SSG->write)(F2610->OPN.ST.device,1,F2610->REGS[r]);
- }
-
- /* OPN registers */
- /* DT / MULTI , TL , KS / AR , AMON / DR , SR , SL / RR , SSG-EG */
- for(r=0x30;r<0x9e;r++)
- if((r&3) != 3)
- {
- OPNWriteReg(&F2610->OPN,r,F2610->REGS[r]);
- OPNWriteReg(&F2610->OPN,r|0x100,F2610->REGS[r|0x100]);
- }
- /* FB / CONNECT , L / R / AMS / PMS */
- for(r=0xb0;r<0xb6;r++)
- if((r&3) != 3)
- {
- OPNWriteReg(&F2610->OPN,r,F2610->REGS[r]);
- OPNWriteReg(&F2610->OPN,r|0x100,F2610->REGS[r|0x100]);
- }
- /* FM channels */
- /*FM_channel_postload(F2610->CH,6);*/
-
- /* rhythm(ADPCMA) */
- F2610->FM_ADPCMAWrite(1,F2610->REGS[0x101]);
- for( r=0 ; r<6 ; r++)
- {
- F2610->FM_ADPCMAWrite(r+0x08,F2610->REGS[r+0x108]);
- F2610->FM_ADPCMAWrite(r+0x10,F2610->REGS[r+0x110]);
- F2610->FM_ADPCMAWrite(r+0x18,F2610->REGS[r+0x118]);
- F2610->FM_ADPCMAWrite(r+0x20,F2610->REGS[r+0x120]);
- F2610->FM_ADPCMAWrite(r+0x28,F2610->REGS[r+0x128]);
- }
- /* Delta-T ADPCM unit */
- F2610->deltaT.postload( &F2610->REGS[0x010] );
- }
-}
-
-static void YM2610_save_state(ym2610_state *F2610, device_t *device)
-{
- device->save_item(NAME(F2610->REGS));
- FMsave_state_st(device,&F2610->OPN.ST);
- FMsave_state_channel(device,F2610->CH,6);
- /* 3slots */
- device->save_item(NAME(F2610->OPN.SL3.fc));
- device->save_item(NAME(F2610->OPN.SL3.fn_h));
- device->save_item(NAME(F2610->OPN.SL3.kcode));
- /* address register1 */
- device->save_item(NAME(F2610->addr_A1));
-
- device->save_item(NAME(F2610->adpcm_arrivedEndAddress));
- /* rhythm(ADPCMA) */
- FMsave_state_adpcma(device,F2610->adpcm);
- /* Delta-T ADPCM unit */
- F2610->deltaT.savestate(device);
-}
-#endif /* MAME_EMU_SAVE_H */
-
-static void YM2610_deltat_status_set(void *chip, uint8_t changebits)
-{
- ym2610_state *F2610 = (ym2610_state *)chip;
- F2610->adpcm_arrivedEndAddress |= changebits;
-}
-static void YM2610_deltat_status_reset(void *chip, uint8_t changebits)
-{
- ym2610_state *F2610 = (ym2610_state *)chip;
- F2610->adpcm_arrivedEndAddress &= (~changebits);
-}
-
-void *ym2610_init(device_t *device, int clock, int rate,
- FM_READBYTE adpcm_a_read_byte, FM_READBYTE adpcm_b_read_byte,
- FM_TIMERHANDLER timer_handler,FM_IRQHANDLER IRQHandler, const ssg_callbacks *ssg)
-{
- ym2610_state *F2610;
-
- /* allocate extend state space */
- F2610 = auto_alloc_clear(device->machine(), <ym2610_state>());
- /* allocate total level table (128kb space) */
- if( !init_tables() )
- {
- auto_free( device->machine(), F2610 );
- return nullptr;
- }
-
- F2610->device = device;
- /* FM */
- F2610->OPN.type = TYPE_YM2610;
- F2610->OPN.P_CH = F2610->CH;
- F2610->OPN.ST.device = device;
- F2610->OPN.ST.clock = clock;
- F2610->OPN.ST.rate = rate;
- /* Extend handler */
- F2610->OPN.ST.timer_handler = timer_handler;
- F2610->OPN.ST.IRQ_Handler = IRQHandler;
- F2610->OPN.ST.SSG = ssg;
- /* ADPCM */
- F2610->read_byte = adpcm_a_read_byte;
- /* DELTA-T */
- F2610->deltaT.read_byte = adpcm_b_read_byte;
- F2610->deltaT.write_byte = nullptr;
-
- F2610->deltaT.status_set_handler = YM2610_deltat_status_set;
- F2610->deltaT.status_reset_handler = YM2610_deltat_status_reset;
- F2610->deltaT.status_change_which_chip = F2610;
- F2610->deltaT.status_change_EOS_bit = 0x80; /* status flag: set bit7 on End Of Sample */
-
- Init_ADPCMATable();
-#ifdef MAME_EMU_SAVE_H
- YM2610_save_state(F2610, device);
-#endif
- return F2610;
-}
-
-void ym2610_clock_changed(void *chip, int clock, int rate)
-{
- ym2610_state *F2610 = (ym2610_state *)chip;
-
- F2610->OPN.ST.clock = clock;
- F2610->OPN.ST.rate = rate;
-}
-
-/* shut down emulator */
-void ym2610_shutdown(void *chip)
-{
- ym2610_state *F2610 = (ym2610_state *)chip;
-
- FMCloseTable();
- auto_free(F2610->OPN.ST.device->machine(), F2610);
-}
-
-/* reset one of chip */
-void ym2610_reset_chip(void *chip)
-{
- int i;
- ym2610_state *F2610 = (ym2610_state *)chip;
- FM_OPN *OPN = &F2610->OPN;
- YM_DELTAT *DELTAT = &F2610->deltaT;
-
- device_t* dev = F2610->OPN.ST.device;
- std::string name(dev->tag());
-
- /* Reset Prescaler */
- OPNSetPres( OPN, 6*24, 6*24, 4*2); /* OPN 1/6 , SSG 1/4 */
- /* reset SSG section */
- (*OPN->ST.SSG->reset)(OPN->ST.device);
- /* status clear */
- FM_IRQMASK_SET(&OPN->ST,0x03);
- FM_BUSY_CLEAR(&OPN->ST);
- OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */
-
- OPN->eg_timer = 0;
- OPN->eg_cnt = 0;
-
- FM_STATUS_RESET(&OPN->ST, 0xff);
-
- reset_channels( &OPN->ST , F2610->CH , 6 );
- /* reset OPerator paramater */
- for(i = 0xb6 ; i >= 0xb4 ; i-- )
- {
- OPNWriteReg(OPN,i ,0xc0);
- OPNWriteReg(OPN,i|0x100,0xc0);
- }
- for(i = 0xb2 ; i >= 0x30 ; i-- )
- {
- OPNWriteReg(OPN,i ,0);
- OPNWriteReg(OPN,i|0x100,0);
- }
- for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0);
- /**** ADPCM work initial ****/
- for( i = 0; i < 6 ; i++ )
- {
- F2610->adpcm[i].step = (uint32_t)((float)(1<<ADPCM_SHIFT)*((float)F2610->OPN.ST.freqbase)/3.0f);
- F2610->adpcm[i].now_addr = 0;
- F2610->adpcm[i].now_step = 0;
- F2610->adpcm[i].start = 0;
- F2610->adpcm[i].end = 0;
- /* F2610->adpcm[i].delta = 21866; */
- F2610->adpcm[i].vol_mul = 0;
- F2610->adpcm[i].pan = &OPN->out_adpcm[OUTD_CENTER]; /* default center */
- F2610->adpcm[i].flagMask = 1<<i;
- F2610->adpcm[i].flag = 0;
- F2610->adpcm[i].adpcm_acc = 0;
- F2610->adpcm[i].adpcm_step= 0;
- F2610->adpcm[i].adpcm_out = 0;
- }
- F2610->adpcmTL = 0x3f;
-
- F2610->adpcm_arrivedEndAddress = 0;
-
- /* DELTA-T unit */
- DELTAT->freqbase = OPN->ST.freqbase;
- DELTAT->output_pointer = OPN->out_delta;
- DELTAT->portshift = 8; /* allways 8bits shift */
- DELTAT->output_range = 1<<23;
- DELTAT->ADPCM_Reset(OUTD_CENTER,YM_DELTAT::EMULATION_MODE_YM2610,F2610->device);
-}
-
-/* YM2610 write */
-/* n = number */
-/* a = address */
-/* v = value */
-int ym2610_write(void *chip, int a, uint8_t v)
-{
- ym2610_state *F2610 = (ym2610_state *)chip;
- FM_OPN *OPN = &F2610->OPN;
- int addr;
- int ch;
-
- v &= 0xff; /* adjust to 8 bit bus */
-
- switch( a&3 )
- {
- case 0: /* address port 0 */
- OPN->ST.address = v;
- F2610->addr_A1 = 0;
-
- /* Write register to SSG emulator */
- if( v < 16 ) (*OPN->ST.SSG->write)(OPN->ST.device,0,v);
- break;
-
- case 1: /* data port 0 */
- if (F2610->addr_A1 != 0)
- break; /* verified on real YM2608 */
-
- addr = OPN->ST.address;
- F2610->REGS[addr] = v;
- switch(addr & 0xf0)
- {
- case 0x00: /* SSG section */
- /* Write data to SSG emulator */
- (*OPN->ST.SSG->write)(OPN->ST.device,a,v);
- break;
- case 0x10: /* DeltaT ADPCM */
- ym2610_device::update_request(OPN->ST.device);
-
- switch(addr)
- {
- case 0x10: /* control 1 */
- case 0x11: /* control 2 */
- case 0x12: /* start address L */
- case 0x13: /* start address H */
- case 0x14: /* stop address L */
- case 0x15: /* stop address H */
-
- case 0x19: /* delta-n L */
- case 0x1a: /* delta-n H */
- case 0x1b: /* volume */
- {
- F2610->deltaT.ADPCM_Write(addr-0x10,v);
- }
- break;
-
- case 0x1c: /* FLAG CONTROL : Extend Status Clear/Mask */
- {
- uint8_t statusmask = ~v;
- /* set arrived flag mask */
- for(ch=0;ch<6;ch++)
- F2610->adpcm[ch].flagMask = statusmask&(1<<ch);
-
- F2610->deltaT.status_change_EOS_bit = statusmask & 0x80; /* status flag: set bit7 on End Of Sample */
-
- /* clear arrived flag */
- F2610->adpcm_arrivedEndAddress &= statusmask;
- }
- break;
-
- default:
- F2610->device->logerror("YM2610: write to unknown deltat register %02x val=%02x\n",addr,v);
- break;
- }
-
- break;
- case 0x20: /* Mode Register */
- ym2610_device::update_request(OPN->ST.device);
- OPNWriteMode(OPN,addr,v);
- break;
- default: /* OPN section */
- ym2610_device::update_request(OPN->ST.device);
- /* write register */
- OPNWriteReg(OPN,addr,v);
- }
- break;
-
- case 2: /* address port 1 */
- OPN->ST.address = v;
- F2610->addr_A1 = 1;
- break;
-
- case 3: /* data port 1 */
- if (F2610->addr_A1 != 1)
- break; /* verified on real YM2608 */
-
- ym2610_device::update_request(OPN->ST.device);
- addr = OPN->ST.address;
- F2610->REGS[addr | 0x100] = v;
- if( addr < 0x30 )
- /* 100-12f : ADPCM A section */
- F2610->FM_ADPCMAWrite(addr,v);
- else
- OPNWriteReg(OPN,addr | 0x100,v);
- }
- return OPN->ST.irq;
-}
-
-uint8_t ym2610_read(void *chip,int a)
-{
- ym2610_state *F2610 = (ym2610_state *)chip;
- int addr = F2610->OPN.ST.address;
- uint8_t ret = 0;
-
- switch( a&3)
- {
- case 0: /* status 0 : YM2203 compatible */
- ret = FM_STATUS_FLAG(&F2610->OPN.ST) & 0x83;
- break;
- case 1: /* data 0 */
- if( addr < 16 ) ret = (*F2610->OPN.ST.SSG->read)(F2610->OPN.ST.device);
- if( addr == 0xff ) ret = 0x01;
- break;
- case 2: /* status 1 : ADPCM status */
- /* ADPCM STATUS (arrived End Address) */
- /* B,--,A5,A4,A3,A2,A1,A0 */
- /* B = ADPCM-B(DELTA-T) arrived end address */
- /* A0-A5 = ADPCM-A arrived end address */
- ret = F2610->adpcm_arrivedEndAddress;
- break;
- case 3:
- ret = 0;
- break;
- }
- return ret;
-}
-
-int ym2610_timer_over(void *chip,int c)
-{
- ym2610_state *F2610 = (ym2610_state *)chip;
-
- if( c )
- { /* Timer B */
- TimerBOver( &(F2610->OPN.ST) );
- }
- else
- { /* Timer A */
- ym2610_device::update_request(F2610->OPN.ST.device);
- /* timer update */
- TimerAOver( &(F2610->OPN.ST) );
- /* CSM mode key,TL controll */
- if( F2610->OPN.ST.mode & 0x80 )
- { /* CSM mode total level latch and auto key on */
- CSMKeyControll( F2610->OPN.type, &(F2610->CH[2]) );
- }
- }
- return F2610->OPN.ST.irq;
-}
-
-#endif /* (BUILD_YM2610||BUILD_YM2610B) */