- /* 
- ** 
- ** File: fm.c -- software implementation of Yamaha FM sound generator 
- ** 
- ** Copyright (C) 2001, 2002, 2003 Jarek Burczynski (bujar at mame dot net) 
- ** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmulator development 
- ** 
- ** Version 1.4A (final beta) 
- ** 
- */ 
-   
- /* 
- ** History: 
- ** 
- ** 14-02-2006 Alone Coder: 
- **  - fixed YM2203 stop volume (511 instead of MAX_ATT_INDEX) - verified on real chip 
- **  - fixed YM2203 SSG-EG=#0a key off (inversion disabled) - verified on real chip 
- **  - uncommented sine generator in SSG-EG reinit - verified on real chip 
- ** 
- ** 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      */ 
- /************************************************************************/ 
-   
- //fnum= fq*2.3575 
- /* globals */ 
- #include "../std.h" 
- #include "../sysdefs.h" 
- #include "emul_2203.h" 
-   
- #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_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) 
- #define TYPE_YM2612 (TYPE_DAC |TYPE_LFOPAN |TYPE_6CH) 
-   
- #define FREQ_SH                 16U  /* 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               ((1U<<FREQ_SH)-1U) 
-   
- #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) 
-   
- #define ENV_QUIET               (TL_TAB_LEN>>3) 
-   
- #define RATE_STEPS (8) 
-   
- #define INTERNAL_TIMER_A(ST,CSM_CH) 
- #define INTERNAL_TIMER_B(ST,step) 
-   
- #define logerror(a,b,c,d,e) 
-   
- #define SC(db) (UINT32) ( db * (4.0/ENV_STEP) ) 
- static const UINT32 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 
-   
- static const UINT8 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 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 
-   
- #define O(a) (a*1) 
- static const UINT8 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 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 
- }; 
-   
- /* 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 
-   
- /* OPN key frequency number -> key code follow table */ 
- /* fnum higher 4bit -> keycode lower 2bit */ 
- static const UINT8 opn_fktable[16] = {0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3}; 
-   
- static INT16/*signed int*/ tl_tab[TL_TAB_LEN]; 
-   
- /* sin waveform table in 'decibel' scale */ 
- static UINT16/*unsigned int*/ sin_tab[SIN_LEN]; 
-   
- /* current chip state */ 
- static void     *_cur_chip = nullptr;   /* pointer of current chip struct */ 
- static FM_ST    *_State;                        /* basic status */ 
- static FM_CH    *_cch[3];               /* pointer of FM channels */ 
-   
-   
- static INT32    _m2,_c1,_c2;            /* Phase Modulation input for operators 2,3,4 */ 
- static INT32    _mem;                   /* one sample delay memory */ 
-   
- static INT32    _out_fm[3];             /* outputs of working channels */ 
-   
- /* limitter */ 
-   
- #define Limit(val, max,min) { \ 
-         if ( val > max )      val = max; \ 
-         else if ( val < min ) val = min; \ 
- } 
-   
- /* status set and IRQ handling */ 
- static 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->param,1); 
-         } 
- } 
-   
- /* status reset and IRQ handling */ 
- static 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->param,0); 
-         } 
- } 
-   
- /* IRQ mask set */ 
- static void FM_IRQMASK_SET(FM_ST *ST,int flag) 
- { 
-         ST->irqmask = UINT8(flag); 
-         /* IRQ handling check */ 
-         FM_STATUS_SET(ST,0); 
-         FM_STATUS_RESET(ST,0); 
- } 
-   
-   
- /* OPN Mode Register Write */ 
- static void set_timers( FM_ST *ST, void *n, int v ) 
- { 
-     (void)n; 
-   
-         /* 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 = UINT32(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->TimerBase); 
-                 } 
-         } 
-         else 
-         {       /* stop timer b */ 
-                 if( ST->TBC != 0 ) 
-                 { 
-                         ST->TBC = 0; 
- //                      if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,0,ST->TimerBase); 
-                 } 
-         } 
-         /* 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->TimerBase); 
-                 } 
-         } 
-         else 
-         {       /* stop timer a */ 
-                 if( ST->TAC != 0 ) 
-                 { 
-                         ST->TAC = 0; 
- //                      if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,0,ST->TimerBase); 
-                 } 
-         } 
- } 
-   
- /* Timer A Overflow */ 
- static 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->param,0,ST->TAC,ST->TimerBase); 
- } 
- /* Timer B Overflow */ 
- static 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->param,1,ST->TBC,ST->TimerBase); 
- } 
-   
-   
- #if FM_BUSY_FLAG_SUPPORT 
- static UINT8 FM_STATUS_FLAG(FM_ST *ST) 
- { 
-         if( ST->BusyExpire > 0) 
-         { 
-                 if( (ST->BusyExpire - FM_GET_TIME_NOW()) > 0) 
-                         return ST->status | 0x80;       /* with busy */ 
-                 /* expire */ 
-                 ST->BusyExpire = 0; 
-         } 
-         return ST->status; 
- } 
- static void FM_BUSY_SET(FM_ST *ST,int busyclock ) 
- { 
-         ST->BusyExpire = FM_GET_TIME_NOW() + (ST->TimerBase * busyclock); 
- } 
- #define FM_BUSY_CLEAR(ST) ((ST)->BusyExpire = 0) 
- #else 
- #define FM_STATUS_FLAG(ST) ((ST)->status) 
- #define FM_BUSY_SET(ST,bclock) {} 
- #define FM_BUSY_CLEAR(ST) {} 
- #endif 
-   
-   
- static void FM_KEYON(FM_CH *CH , int s ) 
- { 
-         FM_SLOT *SLOT = &CH->SLOT[s]; 
-         if( !SLOT->key ) 
-         { 
-                 SLOT->key = 1; 
-                 SLOT->phase = 0;                /* restart Phase Generator */ //restored by Alone Coder 
-                 SLOT->state = EG_ATT;   /* phase -> Attack */ 
-                 if ( SLOT->volume >= MAX_ATT_INDEX )SLOT->volume = 511; /* Alone Coder */ 
-         } 
- } 
-   
- static 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_CH *CH, int ch ) 
- { 
-         INT32 *carrier = &_out_fm[ch]; 
-   
-         INT32 **om1 = &CH->connect1; 
-         INT32 **oc1 = &CH->connect2; 
-         INT32 **om2 = &CH->connect3; 
-         INT32 **memc = &CH->mem_connect; 
-   
-         switch( CH->ALGO ){ 
-         case 0: 
-                 /* M1---C1---MEM---M2---C2---OUT */ 
-                 *om1 = &_c1; 
-                 *oc1 = &_mem; 
-                 *om2 = &_c2; 
-                 *memc= &_m2; 
-                 break; 
-         case 1: 
-                 /* M1------+-MEM---M2---C2---OUT */ 
-                 /*      C1-+                     */ 
-                 *om1 = &_mem; 
-                 *oc1 = &_mem; 
-                 *om2 = &_c2; 
-                 *memc= &_m2; 
-                 break; 
-         case 2: 
-                 /* M1-----------------+-C2---OUT */ 
-                 /*      C1---MEM---M2-+          */ 
-                 *om1 = &_c2; 
-                 *oc1 = &_mem; 
-                 *om2 = &_c2; 
-                 *memc= &_m2; 
-                 break; 
-         case 3: 
-                 /* M1---C1---MEM------+-C2---OUT */ 
-                 /*                 M2-+          */ 
-                 *om1 = &_c1; 
-                 *oc1 = &_mem; 
-                 *om2 = &_c2; 
-                 *memc= &_c2; 
-                 break; 
-         case 4: 
-                 /* M1---C1-+-OUT */ 
-                 /* M2---C2-+     */ 
-                 /* MEM: not used */ 
-                 *om1 = &_c1; 
-                 *oc1 = carrier; 
-                 *om2 = &_c2; 
-                 *memc= &_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= &_m2; 
-                 break; 
-         case 6: 
-                 /* M1---C1-+     */ 
-                 /*      M2-+-OUT */ 
-                 /*      C2-+     */ 
-                 /* MEM: not used */ 
-                 *om1 = &_c1; 
-                 *oc1 = carrier; 
-                 *om2 = carrier; 
-                 *memc= &_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= &_mem;   /* store it anywhere where it will not be used */ 
-                 break; 
-         } 
-   
-         CH->connect4 = carrier; 
- } 
-   
- /* set detune & multiple #3x */ 
- static 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=-1U; 
- } 
-   
- /* set total level #4x*/ 
- static void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v) 
- { 
-     (void)CH; 
-   
-     SLOT->tl = UINT32((v&0x7f)<<(ENV_BITS-7)); /* 7bit TL */ 
- } 
-   
- /* set attack rate & key scale #5x */ 
- static void set_ar_ksr(FM_CH *CH,FM_SLOT *SLOT,int v) 
- { 
-         UINT8 old_KSR = SLOT->KSR; 
-   
-         SLOT->ar = UINT32((v&0x1f) ? 32 + ((v&0x1f)<<1) : 0); 
-   
-         SLOT->KSR = UINT8(3-(v>>6)); 
-         if (SLOT->KSR != old_KSR) 
-         { 
-                 CH->SLOT[SLOT1].Incr=-1U; 
-         } 
-         else 
-         { 
-                 /* 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  #6x*/ 
- static void set_dr(FM_SLOT *SLOT,int v) 
- { 
-         SLOT->d1r = UINT32((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  #7x*/ 
- static void set_sr(FM_SLOT *SLOT,int v) 
- { 
-         SLOT->d2r = UINT32((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  #8x*/ 
- static void set_sl_rr(FM_SLOT *SLOT,int v) 
- { 
-         SLOT->sl = sl_table[ v>>4 ]; 
-   
-         SLOT->rr  = UINT32(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 signed int op_calc(UINT32 phase, unsigned int env, signed int pm) 
- { 
-         UINT32 p; 
-   
-         p = (env<<3) + sin_tab[ ( ((signed int)(int(phase & ~FREQ_MASK) + int(pm<<15))) >> FREQ_SH ) & SIN_MASK ]; 
-   
-         if (p >= TL_TAB_LEN) 
-                 return 0; 
-         return tl_tab[p]; 
- } 
-   
- static signed int op_calc1(UINT32 phase, unsigned int env, signed int pm) 
- { 
-         UINT32 p; 
-   
-         p = (env<<3) + sin_tab[ ( ((signed int)(int(phase & ~FREQ_MASK) + pm      )) >> FREQ_SH ) & SIN_MASK ]; 
-   
-         if (p >= TL_TAB_LEN) 
-                 return 0; 
-         return tl_tab[p]; 
- } 
-   
-   
- static void chan_calc(FM_OPN *OPN, FM_CH *CH) 
- { 
-     (void)OPN; 
-     (void)CH; 
-   
-     unsigned int eg_out; 
-   
- //      UINT32 AM = 0;//LFO_AM >> CH->ams; 
-   
-         _m2 = _c1 = _c2 = _mem = 0; 
-   
-         *CH->mem_connect = CH->mem_value;       /* restore delayed sample (MEM) value to _m2 or _c2 */ 
-   
-         eg_out = CH->SLOT[SLOT1].vol_out; 
-         { 
-                 INT32 out = CH->op1_out[0] + CH->op1_out[1]; 
-                 CH->op1_out[0] = CH->op1_out[1]; 
-   
-                 if( !CH->connect1 ){ 
-                         /* algorithm 5  */ 
-                         _mem = _c1 = _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 = CH->SLOT[SLOT3].vol_out; 
-         if( eg_out < ENV_QUIET )                /* SLOT 3 */ 
-                 *CH->connect3 += op_calc(CH->SLOT[SLOT3].phase, eg_out, _m2); 
-   
-         eg_out = CH->SLOT[SLOT2].vol_out; 
-         if( eg_out < ENV_QUIET )                /* SLOT 2 */ 
-                 *CH->connect2 += op_calc(CH->SLOT[SLOT2].phase, eg_out, _c1); 
-   
-         eg_out = CH->SLOT[SLOT4].vol_out; 
-         if( eg_out < ENV_QUIET )                /* SLOT 4 */ 
-                 *CH->connect4 += op_calc(CH->SLOT[SLOT4].phase, eg_out, _c2); 
-   
-   
-         /* store current MEM */ 
-         CH->mem_value = _mem; 
-   
-         /* update phase counters AFTER output calculations */ 
-         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 void refresh_fc_eg_slot(FM_SLOT *SLOT , int fc , int kc ) 
- { 
-         int ksr; 
-   
-         /* (frequency) phase increment counter */ 
-         SLOT->Incr = (UINT32(fc+SLOT->DT[kc])*SLOT->mul) >> 1; 
-   
-         ksr = kc >> SLOT->KSR; 
-         if( SLOT->ksr != ksr ) 
-         { 
-                 SLOT->ksr = UINT8(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_sel_d1r= eg_rate_select[SLOT->d1r + SLOT->ksr]; 
-   
-                 SLOT->eg_sh_d2r = eg_rate_shift [SLOT->d2r + SLOT->ksr]; 
-                 SLOT->eg_sel_d2r= eg_rate_select[SLOT->d2r + SLOT->ksr]; 
-   
-                 SLOT->eg_sh_rr  = eg_rate_shift [SLOT->rr  + SLOT->ksr]; 
-                 SLOT->eg_sel_rr = eg_rate_select[SLOT->rr  + SLOT->ksr]; 
-         } 
- } 
-   
- /* update phase increment counters */ 
- static void refresh_fc_eg_chan(FM_CH *CH ) 
- { 
-         if( CH->SLOT[SLOT1].Incr==-1U){ 
-                 int fc = int(CH->fc); 
-                 int kc = CH->kcode; 
-                 refresh_fc_eg_slot(&CH->SLOT[SLOT1] , fc , kc ); 
-                 refresh_fc_eg_slot(&CH->SLOT[SLOT2] , fc , kc ); 
-                 refresh_fc_eg_slot(&CH->SLOT[SLOT3] , fc , kc ); 
-                 refresh_fc_eg_slot(&CH->SLOT[SLOT4] , fc , kc ); 
-         } 
- } 
-   
- /* initialize time tables */ 
- static void init_timetables( FM_ST *ST , const UINT8 *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) rate; 
-                         ST->dt_tab[d+4][i] = -(INT32) rate; 
- #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((double)2, (double)((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 ] = INT16(n); 
-                 tl_tab[ x*2 + 1 ] = INT16(-n); 
-   
-                 for (i=1; i<13; i++) 
-                 { 
-                         tl_tab[ x*2+0 + i*2*TL_RES_LEN ] =  INT16(n>>i); 
-                         tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = INT16(-(n>>i)); 
-                 } 
-         } 
-         /*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) * PI / SIN_LEN ); /* checked against the real chip */ 
-   
-                 /* we never reach zero here due to ((i*2)+1) */ 
-                 if (m>0.0) 
-                         o = 8*(double)log(1.0/m)/log((double)2);        /* convert to 'decibels' */ 
-                 else 
-                         o = 8*(double)log(-1.0/m)/log((double)2);       /* 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 ] = UINT16(n*2 + (m>=0.0? 0: 1 )); 
- //              printf("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 );*/ 
-   
-         return 1; 
- } 
-   
- static void FMCloseTable( void ) 
- { 
- #ifdef SAVE_SAMPLE 
- //      fclose(sample[0]); 
- #endif 
-         return; 
- } 
-   
- /* CSM Key Controll */ 
- static void CSMKeyControll(FM_CH *CH) 
- { 
-         /* this is wrong, atm */ 
-   
-         /* all key on */ 
-         FM_KEYON(CH,SLOT1); 
-         FM_KEYON(CH,SLOT2); 
-         FM_KEYON(CH,SLOT3); 
-         FM_KEYON(CH,SLOT4); 
- } 
-   
-   
- __inline void advance_eg_channel(FM_OPN *OPN, FM_SLOT *SLOT) 
- { 
-         unsigned int out; 
-         unsigned int swap_flag = 0; 
-         unsigned int i; 
-   
-   
-         i = 4; /* four operators per channel */ 
-         do 
-         { 
-                 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 ( (UINT32)SLOT->volume >= 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 ( (UINT32)SLOT->volume >= 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 >= 512 /* с√ыю MAX_ATT_INDEX */ ) //Alone Coder 
-                                         { 
-                                                 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, 
-                                 only if AR is not maximum ??? ALWAYS! */ 
-                                                         SLOT->phase = 0; //Alone Coder 
-   
-                                                         /* phase -> Attack */ 
-                                                    SLOT->volume = 511; //Alone Coder 
-                                                         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) ) ) 
-                                 { 
-                                         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 = SLOT->tl + ((UINT32)SLOT->volume); 
-   
-                 if ((SLOT->ssg&0x08) && (SLOT->ssgn&2) && (SLOT->state != EG_OFF/*Alone Coder*/))       /* negate output (changes come from alternate bit, init comes from attack bit) */ 
-                         out ^= 511/*Alone Coder*/; //((1<<ENV_BITS)-1); /* 1023 */ 
-   
-                 /* we need to store the result here because we are going to change ssgn 
-             in next instruction */ 
-                 SLOT->vol_out = out; 
-   
-                 SLOT->ssgn ^= swap_flag; 
-   
-                 SLOT++; 
-                 i--; 
-         }while (i); 
-   
- } 
-   
- #ifdef _STATE_H 
-   
- enum { SS_INT8, SS_UINT8, SS_INT16, SS_UINT16, SS_INT32, SS_UINT32, SS_INT, SS_DOUBLE, SS_FLOAT}; 
-   
- static void ss_register_entry(const char *module, int instance, const char *name, int type, void *data, unsigned int size) 
- { 
-         int i; 
-         FILE* logfile=fopen("logfile.log", "a+"); 
-         if(!logfile) 
-                 return; 
-   
-         fprintf(logfile,"%20s:%3d [%10s]: ",module,instance,name); 
-   
-         if (type==SS_INT8) { fprintf(logfile,"INT8   "); for (i=0;i<(int)size;i++) fprintf(logfile,"[%2x]#%+02x ",i,((signed char*)data)[i]); } 
-         if (type==SS_INT16) { fprintf(logfile,"INT16  "); for (i=0;i<(int)size;i++) fprintf(logfile,"[%2x]#%+04x ",i,((signed short*)data)[i]); } 
-         if (type==SS_INT32) { fprintf(logfile,"INT32  "); for (i=0;i<(int)size;i++) fprintf(logfile,"[%2x]#%+08x ",i,((signed int*)data)[i]); } 
-         if (type==SS_UINT8&&size==256) { 
-                 fprintf(logfile,"UINT8  "); 
-                 for (i=0;i<(int)size;i++) { 
-                         if (i%16==0) fprintf(logfile,"\n"); 
-                         fprintf(logfile,"[%02x]#%02x ",i,((unsigned char*)data)[i]); 
-                 } 
-         } 
-         else if (type==SS_UINT8) { fprintf(logfile,"UINT8  "); for (i=0;i<(int)size;i++) fprintf(logfile,"[%2x]#%02x ",i,((unsigned char*)data)[i]); } 
-         if (type==SS_UINT16) { fprintf(logfile,"UINT16 "); for (i=0;i<(int)size;i++) fprintf(logfile,"[%2x]#%04x ",i,((unsigned short*)data)[i]); } 
-         if (type==SS_UINT32) { fprintf(logfile,"UINT32 "); for (i=0;i<(int)size;i++) fprintf(logfile,"[%2x]#%08x ",i,((unsigned int*)data)[i]); } 
-   
-         if (type==SS_INT) { fprintf(logfile,"INT    "); fprintf(logfile,"    %d ",((int*)data)[0]); } 
-         if (type==SS_DOUBLE) { fprintf(logfile,"DOUBLE "); for (i=0;i<(int)size;i++) fprintf(logfile,"[%d]%f ",i,((double*)data)[i]); } 
-         if (type==SS_FLOAT) { fprintf(logfile,"FLOAT  "); for (i=0;i<(int)size;i++) fprintf(logfile,"[%d]%f ",i, (double)((float*)data)[i]); } 
-   
-         fprintf(logfile,"\n"); 
-   
-         fclose(logfile); 
-         return; 
- } 
-   
- static void state_save_register_UINT8 (const char *module, int instance, const char *name, UINT8 *val, unsigned size) 
- { ss_register_entry(module, instance, name, SS_UINT8, val, size); } 
-   
- static void state_save_register_INT8  (const char *module, int instance, const char *name, INT8 *val, unsigned size) 
- { ss_register_entry(module, instance, name, SS_INT8, val, size); } 
-   
- static void state_save_register_UINT16(const char *module, int instance, const char *name, UINT16 *val, unsigned size) 
- { ss_register_entry(module, instance, name, SS_UINT16, val, size); } 
-   
- static void state_save_register_INT16 (const char *module, int instance, const char *name, INT16 *val, unsigned size) 
- { ss_register_entry(module, instance, name, SS_INT16, val, size); } 
-   
- static void state_save_register_UINT32(const char *module, int instance, const char *name, UINT32 *val, unsigned size) 
- { ss_register_entry(module, instance, name, SS_UINT32, val, size); } 
-   
- static void state_save_register_INT32 (const char *module, int instance, const char *name, INT32 *val, unsigned size) 
- { ss_register_entry(module, instance, name, SS_INT32, val, size); } 
-   
- static void state_save_register_int   (const char *module, int instance, const char *name, int *val) 
- { ss_register_entry(module, instance, name, SS_INT, val, 1); } 
-   
- static void state_save_register_double(const char *module, int instance, const char *name, double *val, unsigned size) 
- { ss_register_entry(module, instance, name, SS_DOUBLE, val, size); } 
-   
- static void state_save_register_float(const char *module, int instance, const char *name, float *val, unsigned size) 
- { ss_register_entry(module, instance, name, SS_FLOAT, val, size); } 
-   
-   
- /* FM channel save , internal state only */ 
- static void FMsave_state_channel(const char *name,int num,FM_CH *CH,int num_ch) 
- { 
-         int slot , ch; 
-         char state_name[20]; 
-         const char slot_array[4] = { 1 , 3 , 2 , 4 }; 
-   
-         for(ch=0;ch<num_ch;ch++,CH++) 
-         { 
-                 /* channel */ 
-                 sprintf(state_name,"%s.CH%d",name,ch); 
-                 state_save_register_INT32(state_name, num, "feedback" , CH->op1_out , 2); 
-                 state_save_register_UINT32(state_name, num, "phasestep"   , &CH->fc , 1); 
-                 state_save_register_UINT32(state_name, num, "block_fnum"   , &CH->block_fnum , 1); 
-                 /* slots */ 
-                 for(slot=0;slot<4;slot++) 
-                 { 
-                         FM_SLOT *SLOT = &CH->SLOT[slot]; 
-   
-                         sprintf(state_name,"%s.CH%d.SLOT%d",name,ch,slot_array[slot]); 
-                         state_save_register_UINT32(state_name, num, "phasecount" , &SLOT->phase, 1); 
-                         state_save_register_UINT8 (state_name, num, "state"      , &SLOT->state, 1); 
-                         state_save_register_INT32 (state_name, num, "volume"     , &SLOT->volume, 1); 
-                 } 
-         } 
- } 
-   
- static void FMsave_state_st(const char *state_name,int num,FM_ST *ST) 
- { 
- #if FM_BUSY_FLAG_SUPPORT 
-         state_save_register_double(state_name, num, "BusyExpire", &ST->BusyExpire , 1); 
- #endif 
-         state_save_register_UINT8 (state_name, num, "address"   , &ST->address , 1); 
-         state_save_register_UINT8 (state_name, num, "IRQ"       , &ST->irq     , 1); 
-         state_save_register_UINT8 (state_name, num, "IRQ MASK"  , &ST->irqmask , 1); 
-         state_save_register_UINT8 (state_name, num, "status"    , &ST->status  , 1); 
-         state_save_register_UINT32(state_name, num, "mode"      , &ST->mode    , 1); 
-         state_save_register_UINT8 (state_name, num, "prescaler" , &ST->prescaler_sel , 1); 
-         state_save_register_UINT8 (state_name, num, "freq latch", &ST->fn_h , 1); 
-         state_save_register_int   (state_name, num, "TIMER A"   , &ST->TA   ); 
-         state_save_register_int   (state_name, num, "TIMER Acnt", &ST->TAC  ); 
-         state_save_register_UINT8 (state_name, num, "TIMER B"   , &ST->TB   , 1); 
-         state_save_register_int   (state_name, num, "TIMER Bcnt", &ST->TBC  ); 
-   
-         state_save_register_int  (state_name, num, "clock"     , &ST->clock ); 
-         state_save_register_int  (state_name, num, "rate"      , &ST->rate ); 
- } 
-   
- #endif // _STATE_H 
-   
- /* prescaler set (and make time tables) */ 
- static void OPNSetPres(FM_OPN *OPN , int pres , int TimerPres, 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  = (UINT32)((1<<EG_SH)  *  OPN->ST.freqbase); 
-         OPN->eg_timer_overflow = (UINT32)(( 3 ) * (1<<EG_SH)); 
-   
-         /* Timer base time */ 
-         OPN->ST.TimerBase = 1.0/((double)OPN->ST.clock / (double)TimerPres); 
-   
-         /* SSG part  prescaler set */ 
- //      if( SSGpres ) (*OPN->ST.SSG->set_clock)( OPN->ST.param, OPN->ST.clock * 2 / SSGpres ); 
-         OPN->ST.SSGclock = 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*/ 
-         /* calculate fnumber -> increment counter table */ 
-         for(i = 0; i < 2048; i++) 
-         { 
-                 /* freq table for octave 7 */ 
-                 /* OPN phase increment counter = 20bit */ 
-                 OPN->fn_table[i] = (UINT32)( (double)i * 64 * OPN->ST.freqbase * (1<<(FREQ_SH-10)) ); 
-                 /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ 
-         } 
-   
- } 
-   
- /* write a OPN mode register 0x20-0x2f */ 
- static void OPNWriteMode(FM_OPN *OPN, int r, int v) 
- { 
-         UINT8 c; 
-         FM_CH *CH; 
-   
-         switch(r){ 
-         case 0x21:      /* Test */ 
-                 break; 
-         case 0x22:      /* LFO FREQ (YM2608/YM2610/YM2610B/YM2612) */ 
-                 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 = UINT8(v); 
-                 break; 
-         case 0x27:      /* mode, timer control */ 
-                 set_timers( &(OPN->ST),OPN->ST.param,v ); 
-                 break; 
-         case 0x28:      /* key on / off */ 
-                 c = v & 0x03; 
-                 if( c == 3 ) break; 
-                 CH = OPN->P_CH; 
-                 CH = &CH[c]; 
-                 if(v&0x10) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1); 
-                 if(v&0x20) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2); 
-                 if(v&0x40) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3); 
-                 if(v&0x80) FM_KEYON(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 c = OPN_CHAN(r); 
-   
-         if (c == 3) return; /* 0xX3,0xX7,0xXB,0xXF */ 
-   
-         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(CH,SLOT,v); 
-                 break; 
-   
-         case 0x60:      /*     DR */ 
-                 set_dr(SLOT,v); 
-                 break; 
-   
-         case 0x70:      /*     SR */ 
-                 set_sr(SLOT,v); 
-                 break; 
-   
-         case 0x80:      /* SL, RR */ 
-                 set_sl_rr(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 switches 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 fn = (((UINT32)( (OPN->ST.fn_h)&7))<<8) + UINT32(v); 
-                                 UINT8 blk = OPN->ST.fn_h>>3; 
-                                 /* keyscale code */ 
-                                 CH->kcode = UINT8((blk<<2) | opn_fktable[fn >> 7]); 
-                                 /* phase increment counter */ 
-                                 CH->fc = OPN->fn_table[fn]>>(7-blk); 
-   
-                                 /* store fnum in clear form for LFO PM calculations */ 
-                                 CH->block_fnum = UINT32(blk<<11U) | fn; 
-   
-                                 CH->SLOT[SLOT1].Incr=-1U; 
-                         } 
-                         break; 
-                 case 1:         /* 0xa4-0xa6 : FNUM2,BLK */ 
-                         OPN->ST.fn_h = v&0x3f; 
-                         break; 
-                 case 2:         /* 0xa8-0xaa : 3CH FNUM1 */ 
-                         if(r < 0x100) 
-                         { 
-                                 UINT32 fn = (((UINT32)(OPN->SL3.fn_h&7))<<8) + UINT32(v); 
-                                 UINT8 blk = OPN->SL3.fn_h>>3; 
-                                 /* keyscale code */ 
-                                 OPN->SL3.kcode[c]= UINT8((blk<<2) | opn_fktable[fn >> 7]); 
-                                 /* phase increment counter */ 
-                                 OPN->SL3.fc[c] = OPN->fn_table[fn]>>(7-blk); 
-                                 OPN->SL3.block_fnum[c] = fn; 
-                                 (OPN->P_CH)[2].SLOT[SLOT1].Incr=-1U; 
-                         } 
-                         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   = UINT8(feedback ? feedback+6 : 0); 
-                                 setup_connection( CH, c ); 
-                         } 
-                         break; 
-                 } 
-                 break; 
-         } 
- } 
-   
-   
- /* 
-   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) 
-   
- */ 
- 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 ); 
- } 
-   
- /*****************************************************************************/ 
- /*      YM2203 local section                                                 */ 
- /*****************************************************************************/ 
-   
- /* Generate samples for one of the YM2203s */ 
- void YM2203UpdateOne(void *chip, FMSAMPLE *buffer, int length) 
- { 
-         YM2203 *F2203 = (YM2203 *)chip; 
-         FM_OPN *OPN =   &F2203->OPN; 
-         int i; 
-         FMSAMPLE *buf = buffer; 
-   
-         _cur_chip = (void *)F2203; 
-         _State    = &F2203->OPN.ST; 
-         _cch[0]   = &F2203->CH[0]; 
-         _cch[1]   = &F2203->CH[1]; 
-         _cch[2]   = &F2203->CH[2]; 
-   
-         /* refresh PG and EG */ 
-         refresh_fc_eg_chan( _cch[0] ); 
-         refresh_fc_eg_chan( _cch[1] ); 
-         if( ((_State->mode & 0xc0) == 0x40) ) 
-         { 
-                 // 3SLOT MODE 
-                 if( _cch[2]->SLOT[SLOT1].Incr==-1U) 
-                 { 
-                         refresh_fc_eg_slot(&_cch[2]->SLOT[SLOT1] , int(OPN->SL3.fc[1]) , OPN->SL3.kcode[1] ); 
-                         refresh_fc_eg_slot(&_cch[2]->SLOT[SLOT2] , int(OPN->SL3.fc[2]) , OPN->SL3.kcode[2] ); 
-                         refresh_fc_eg_slot(&_cch[2]->SLOT[SLOT3] , int(OPN->SL3.fc[0]) , OPN->SL3.kcode[0] ); 
-                         refresh_fc_eg_slot(&_cch[2]->SLOT[SLOT4] , int(_cch[2]->fc) , _cch[2]->kcode ); 
-                 } 
-         }else 
-         refresh_fc_eg_chan( _cch[2] ); 
-   
-   
-         /* buffering */ 
-         for (i=0; i < length ; i++) 
-         { 
-                 /* clear outputs */ 
-                 _out_fm[0] = 0; 
-                 _out_fm[1] = 0; 
-                 _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] ); 
-                 chan_calc(OPN, _cch[1] ); 
-                 chan_calc(OPN, _cch[2] ); 
-   
-                 /* buffering */ 
-                 { 
-                         int lt; 
-                         lt = _out_fm[0] + _out_fm[1] + _out_fm[2]; 
-                         lt >>= FINAL_SH; 
-                         Limit( lt , MAXOUT, MINOUT ); 
- //                      #ifdef SAVE_SAMPLE 
- //                              SAVE_ALL_CHANNELS 
- //                      #endif 
-   
-                         /* buffering */ 
-                         buf[i] = FMSAMPLE(lt); 
-                 } 
-   
-                 /* timer A control */ 
-                 INTERNAL_TIMER_A( _State , _cch[2] ) 
-         } 
-         INTERNAL_TIMER_B(_State,length) 
- } 
-   
- /* ---------- reset one of chip ---------- */ 
- void YM2203ResetChip(void *chip) 
- { 
-         int i; 
-         YM2203 *F2203 = (YM2203 *)chip; 
-         FM_OPN *OPN = &F2203->OPN; 
-   
-         /* Reset Prescaler */ 
-         OPNPrescaler_w(OPN, 0 , 1 ); 
-         /* reset SSG section */ 
- //      (*OPN->ST.SSG->reset)(OPN->ST.param); 
-         /* 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 _STATE_H 
- void YM2203Postload(void *chip) 
- { 
-         if (chip) 
-         { 
-                 YM2203 *F2203 = (YM2203 *)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.param,0,r); 
- //                      (*F2203->OPN.ST.SSG->write)(F2203->OPN.ST.param,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);*/ 
-         } 
-         _cur_chip = nullptr; 
- } 
-   
- void YM2203_save_state(void *chip, int index) 
- { 
-         if (chip) 
-         { 
-                 YM2203 *F2203 = (YM2203 *)chip; 
-                 const char statename[] = "YM2203"; 
-   
-                 state_save_register_UINT8 (statename, index, "regs"   , F2203->REGS   , 256); 
-                 FMsave_state_st(statename,index,&F2203->OPN.ST); 
-                 FMsave_state_channel(statename,index,F2203->CH,3); 
-                 /* 3slots */ 
-                 state_save_register_UINT32 (statename, index, "slot3fc" , F2203->OPN.SL3.fc , 3); 
-                 state_save_register_UINT8  (statename, index, "slot3fh" , &F2203->OPN.SL3.fn_h , 1); 
-                 state_save_register_UINT8  (statename, index, "slot3kc" , F2203->OPN.SL3.kcode , 3); 
-         } 
- } 
- #endif /* _STATE_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 * YM2203Init(void *param, int index, int clock, int rate 
- //                              ,FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler, 
- //               const struct ssg_callbacks *ssg 
-                ) 
- { 
-     (void)index; 
-   
-         YM2203 *F2203; 
-   
-         _cur_chip = nullptr;    /* hiro-shi!! */ 
-   
-         /* allocate ym2203 state space */ 
-         if( (F2203 = (YM2203 *)malloc(sizeof(YM2203)))==nullptr) 
-                 return nullptr; 
-         /* clear */ 
-         memset(F2203,0,sizeof(YM2203)); 
-   
-         if( !init_tables() ) 
-         { 
-                 free( F2203 ); 
-                 return nullptr; 
-         } 
-   
-         F2203->OPN.ST.param = param; 
-         F2203->OPN.type = TYPE_YM2203; 
-         F2203->OPN.P_CH = F2203->CH; 
-         F2203->OPN.ST.clock = clock; 
-         F2203->OPN.ST.rate = rate; 
-   
- //      F2203->OPN.ST.Timer_Handler = TimerHandler; 
- //      F2203->OPN.ST.IRQ_Handler   = IRQHandler; 
- //      F2203->OPN.ST.SSG           = ssg; 
-         YM2203ResetChip(F2203); 
-   
- #ifdef _STATE_H 
-         YM2203_save_state(F2203, index); 
- #endif 
-         return F2203; 
- } 
-   
- /* shut down emulator */ 
- void YM2203Shutdown(void *chip) 
- { 
-         YM2203 *FM2203 = (YM2203 *)chip; 
-   
-         FMCloseTable(); 
-         free(FM2203); 
-         chip=nullptr; 
- } 
-   
- /* YM2203 I/O interface */ 
- int YM2203Write(void *chip,int a,UINT8 v) 
- { 
-         YM2203 *F2203 = (YM2203 *)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.param,0,v); 
-   
-         } 
-         else 
-         {       // data port 
-                 int addr = OPN->ST.address; 
-                 // prescaler select : 2d,2e,2f 
-                 if( addr >= 0x2d && addr <= 0x2f ) 
-                         OPNPrescaler_w(OPN , addr , 1); 
-                 else { 
- //#ifdef _STATE_H 
-                         F2203->REGS[addr] = v; 
- //#endif 
-                         switch( addr & 0xf0 ) 
-                         { 
-                         case 0x00:      /* 0x00-0x0f : SSG section */ 
-                                 /* Write data to SSG emulator */ 
- //                              (*OPN->ST.SSG->write)(OPN->ST.param,a,v); 
-                                 break; 
-                         case 0x20:      /* 0x20-0x2f : Mode section */ 
- //                              YM2203UpdateReq(OPN->ST.param); 
-                                 /* write register */ 
-                                 OPNWriteMode(OPN,addr,v); 
-                                 break; 
-                         default:        /* 0x30-0xff : OPN section */ 
- //                              YM2203UpdateReq(OPN->ST.param); 
-                                 /* write register */ 
-                                 OPNWriteReg(OPN,addr,v); 
-                         } 
-                         FM_BUSY_SET(&OPN->ST,1); 
-                 } 
-         } 
-         return OPN->ST.irq; 
- } 
-   
- UINT8 YM2203Read(void *chip,int a) 
- { 
-         YM2203 *F2203 = (YM2203 *)chip; 
- //      int addr = F2203->OPN.ST.address; 
-         UINT8 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.param); 
-         } 
-         return ret; 
- } 
-   
- int YM2203TimerOver(void *chip,int c) 
- { 
-         YM2203 *F2203 = (YM2203 *)chip; 
-   
-         if( c ) 
-         {       /* Timer B */ 
-                 TimerBOver( &(F2203->OPN.ST) ); 
-         } 
-         else 
-         {       /* Timer A */ 
- //              YM2203UpdateReq(F2203->OPN.ST.param); 
-                 /* timer update */ 
-                 TimerAOver( &(F2203->OPN.ST) ); 
-                 /* CSM mode key,TL control */ 
-                 if( F2203->OPN.ST.mode & 0x80 ) 
-                 {       /* CSM mode auto key on */ 
-                         CSMKeyControll( &(F2203->CH[2]) ); 
-                 } 
-         } 
-         return F2203->OPN.ST.irq; 
- } 
-