--- generator/ym2612/fm.c 2020/03/04 04:46:40 1.1.1.1 +++ generator/ym2612/fm.c 2020/03/04 04:46:59 1.1.1.2 @@ -5,17 +5,37 @@ /* ** -** File: fm.c -- software implementation of FM sound generator +** File: fm.c -- software implementation of Yamaha FM sound generator ** -** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmurator development +** Copyright (C) 1998 Tatsuyuki Satoh , MultiArcadeMachineEmulator development ** -** Version 0.35f +** Version 0.37e ** */ /* -**** change log. (hiro-shi) **** -** 08-12-98: +** History: +** +** 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 OPNB_ADPCM_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) @@ -23,7 +43,7 @@ ** ADPCMB repeat flag(no check) ** change ADPCM volume rate (8->16) (32->48). ** -** 09-12-98: +** 09-12-98 hiro-shi: ** change ADPCM volume. (8->16, 48->64) ** replace ym2610 ch0/3 (YM-2610B) ** init cur_chip (restart bug fix) @@ -32,42 +52,43 @@ ** change ADPCMA_DECODE_MIN/MAX. */ + + /* - no check: - YM2608 rhythm sound - OPN SSG type envelope - YM2612 DAC output mode - YM2151 CSM speech mode - no support: - status busy flag (already not busy) - LFO contoller (YM2612/YM2610/YM2608/YM2151) - YM2151 noise mode - YM2608 DELTA-T-ADPCM and RYTHM - YM2610 DELTA-T-ADPCM with PCM port - YM2610 PCM memory data access - - YM2608 status mask (register :0x110) - preliminary : - key scale level rate (?) - attack rate time rate , curve (?) - decay rate time rate , curve (?) - self feedback calcration - YM2610 ADPCM mixing level - Problem : + TO DO: +!!!!!!! CORRECT FIRST MISSING CREDIT SOUND IN GIGANDES (DELTA-T module, when DELTAN register = 0) !!!!!! + - add SSG envelope generator support (darkseal) + - use real sample rate and let mixer.c do the sample rate convertion + + no check: + YM2608 rhythm sound + OPN SSG type envelope (SEG) + YM2151 CSM speech mode + + no support: + YM2608 status mask (register :0x110) + YM2608 RYTHM sound + YM2608 PCM memory data access , DELTA-T-ADPCM with PCM port + YM2151 CSM speech mode with internal timer + + preliminary : + key scale level rate (?) + YM2151 noise mode (CH7.OP4) + LFO contoller (YM2612/YM2610/YM2608/YM2151) - note: + note: OPN OPM - fnum fMus * 2^20 / (fM/(12*n)) - TimerOverA (12*n)*(1024-NA)/fFM 64*(1024-Na)/fm - TimerOverB (12*n)*(256-NB)/fFM 1024*(256-Nb)/fm - output bits 10bit<<3bit 16bit * 2ch (YM3012=10bit<<3bit) - sampling rate fFM / (12*6) ? fFM / 64 - lfo freq ( fM*2^(LFRQ/16) ) / (4295*10^6) + fnum fM * 2^20 / (fM/(12*n)) + TimerOverA ( 12*n)*(1024-NA)/fM 64*(1024-Na)/fM + TimerOverB (192*n)*(256-NB)/fM 1024*(256-Nb)/fM + output bits 10bit<<3bit 16bit * 2ch (YM3012=10bit<<3bit) + sampling rate fFM / (12*prescaler) fM / 64 + lfo freq ( fM*2^(LFRQ/16) ) / (4295*10^6) */ /************************************************************************/ /* comment of hiro-shi(Hiromitsu Shioya) */ -/* YM2610(B) = (OPN-B */ +/* 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 */ /************************************************************************/ @@ -78,405 +99,100 @@ #include #include -/* tidied for Generator by James Ponder, 27th May 1999 */ - +/* Generator */ #include "support.h" #include "fm.h" +#include "genstate.h" +#define _STATE_H #ifndef PI -#define PI 3.14159265357989 +#define PI 3.14159265358979323846 #endif + /***** shared function building option ****/ -#define BUILD_OPN (BUILD_YM2203||BUILD_YM2608||BUILD_YM2610||BUILD_YM2612) +#define BUILD_OPN (BUILD_YM2203||BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B||BUILD_YM2612) #define BUILD_OPNB (BUILD_YM2610||BUILD_YM2610B) -#define BUILD_FM_ADPCMA (BUILD_YM2608||BUILD_YM2610) -#define BUILD_FM_ADPCMB (BUILD_YM2608||BUILD_YM2610) - -/**** YM2610 ADPCM defines ****/ -#define ADPCMA_VOLUME_RATE (1) -#define ADPCMB_VOLUME_RATE (2) /* DELTA-T volume rate */ +#define BUILD_OPN_PRESCALER (BUILD_YM2203||BUILD_YM2608) +#define BUILD_ADPCMA (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B) +#define BUILD_ADPCMB (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B) -#define ADPCM_SHIFT (16) -#define AUDIO_CONV(A) ((A)) -#define AUDIO_CONV16(A) ((A)) - -/* ------------------------------------------------------------------ */ -#ifdef __RAINE__ -#define INTERNAL_TIMER /* use internal timer */ -#endif -/* -------------------- speed up optimize switch -------------------- */ -/* ---------- Enable ---------- */ -#define TL_SAVE_MEM /* save some memories for total level */ -/* ---------- Disable ---------- */ -#if 0 -#define SEG_SUPPORT /* OPN SSG type envelope support */ -#define LFO_SUPPORT /* LFO support */ +#if BUILD_ADPCMB +/* include external DELTA-T ADPCM unit */ + #include "ymdeltat.h" /* DELTA-T ADPCM UNIT */ #endif -/* -------------------- preliminary define section --------------------- */ -/* attack/decay rate time rate */ -#define OPM_ARRATE 399128 -#define OPM_DRRATE 5514396 -/* It is not checked , because I haven't YM2203 rate */ -#define OPN_ARRATE OPM_ARRATE -#define OPN_DRRATE OPM_DRRATE - -#define FREQ_BITS 24 /* frequency turn */ - -/* counter bits = 21 , octerve 7 */ -#define FREQ_RATE (1<<(FREQ_BITS-21)) -#define TL_BITS (FREQ_BITS+2) - -/* final output shift , limit minimum and maximum */ -#define OPN_OUTSB (TL_BITS+2-16) /* OPN output final shift 16bit */ -#define OPN_MAXOUT (0x7fff<>2)&3) -#define OPM_CHAN(N) (N&7) -#define OPM_SLOT(N) ((N>>3)&3) -/* slot number */ -#define SLOT1 0 -#define SLOT2 2 -#define SLOT3 1 -#define SLOT4 3 - -/* envelope phase */ -#define ENV_MOD_OFF 0x00 -#define ENV_MOD_RR 0x01 -#define ENV_MOD_SR 0x02 -#define ENV_MOD_DR 0x03 -#define ENV_MOD_AR 0x04 -#define ENV_SSG_SR 0x05 -#define ENV_SSG_DR 0x06 -#define ENV_SSG_AR 0x07 - -/* bit0 = right enable , bit1 = left enable (FOR YM2612) */ -#define OPN_RIGHT 1 -#define OPN_LEFT 2 -#define OPN_CENTER 3 - -/* bit0 = left enable , bit1 = right enable */ -#define OPM_LEFT 1 -#define OPM_RIGHT 2 -#define OPM_CENTER 3 -/* */ - -/* YM2608 Rhythm Number */ -#define RY_BD 0 -#define RY_SD 1 -#define RY_TOP 2 -#define RY_HH 3 -#define RY_TOM 4 -#define RY_RIM 5 - -/* FM timer model */ -#define FM_TIMER_SINGLE (0) -#define FM_TIMER_INTERVAL (1) - -/* ---------- OPN / OPM one channel ---------- */ -typedef struct fm_slot { - int *DT; /* detune :DT_TABLE[DT] */ - int DT2; /* multiple,Detune2:(DT2<<4)|ML for OPM*/ - int TL; /* total level :TL << 8 */ - signed int TLL; /* adjusted now TL */ - unsigned char KSR; /* key scale rate :3-KSR */ - int *AR; /* attack rate :&AR_TABLE[AR<<1] */ - int *DR; /* decay rate :&DR_TALBE[DR<<1] */ - int *SR; /* sustin rate :&DR_TABLE[SR<<1] */ - int SL; /* sustin level :SL_TALBE[SL] */ - int *RR; /* release rate :&DR_TABLE[RR<<2+2] */ - unsigned char SEG; /* SSG EG type :SSGEG */ - unsigned char ksr; /* key scale rate :kcode>>(3-KSR) */ - unsigned int mul; /* multiple :ML_TABLE[ML] */ - unsigned int Cnt; /* frequency count : */ - int Incr; /* frequency step : */ - /* envelope generator state */ - unsigned char evm; /* envelope phase */ - signed int evc; /* envelope counter */ - signed int eve; /* envelope counter end point */ - signed int evs; /* envelope counter step */ - signed int evsa; /* envelope step for AR */ - signed int evsd; /* envelope step for DR */ - signed int evss; /* envelope step for SR */ - signed int evsr; /* envelope step for RR */ - /* LFO */ - unsigned char ams; - unsigned char pms; -}FM_SLOT; +#define ENV_BITS 10 +#define ENV_LEN (1< increment counter */ -} FM_OPN; - -/* here's the virtual YM2203(OPN) (Used by YM2608 / YM2612) */ -typedef struct ym2203_f { - FM_OPN OPN; /* OPN state */ -/* FMSAMPLE *Buf;*/ /* sound buffer */ - FM_CH CH[3]; /* channel state */ -} YM2203; - -/* here's the virtual YM2610 */ -typedef struct ym2610_f { - FM_OPN OPN; /* OPN state */ -/* FMSAMPLE *Buf[YM2610_NUMBUF];*/ /* sound buffer */ - FM_CH CH[6]; /* channel state */ - int address1; /* address register1 */ - /**** ADPCM control ****/ - char *pcmbuf[2]; - unsigned int pcm_size[2]; - int *TL_adpcmb; - ADPCM_CH adpcm[7]; /* normal ADPCM & deltaT ADPCM */ - unsigned int adpcmreg[2][0x30]; - int port0state, port0control, port0shift; - int port1state, port1control, port1shift; - unsigned char adpcm_arrivedEndAddress,adpcm_statusmask; -} YM2610; - -/* here's the virtual YM2608 */ -typedef YM2610 YM2608; - -/* here's the virtual YM2612 */ -typedef struct ym2612_f { - FM_OPN OPN; /* OPN state */ -/* FMSAMPLE *Buf[YM2612_NUMBUF];*/ /* sound buffer */ - FM_CH CH[6]; /* channel state */ - int address1; /* address register1 */ - /* dac output (YM2612) */ - int dacen; - int dacout; -} YM2612; - -/* here's the virtual YM2151(OPM) */ -typedef struct ym2151_f { -/* FMSAMPLE *Buf[YM2151_NUMBUF];*//* sound buffers */ - FM_ST ST; /* general state */ - FM_CH CH[8]; /* channel state */ - unsigned char NReg; /* noise enable,freq */ - unsigned char pmd; /* LFO pmd level */ - unsigned char amd; /* LFO amd level */ - unsigned char ctw; /* CT0,1 and waveform */ - unsigned int KC_TABLE[8*12*64+950];/* keycode,keyfunction -> count */ - void (*PortWrite)(int offset,int data);/* callback when write CT0/CT1 */ -} YM2151; +/* sinwave entries */ +#define SIN_BITS 10 +#define SIN_LEN (1< key code follow table */ -/* fnum higher 4bit -> keycode lower 2bit */ -static const char OPN_FKTABLE[16]={0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3}; +/* -------------------- tables --------------------- */ -static const int KC_TO_SEMITONE[16]={ - /*translate note code KC into more usable number of semitone*/ - 0*64, 1*64, 2*64, 3*64, - 3*64, 4*64, 5*64, 6*64, - 6*64, 7*64, 8*64, 9*64, - 9*64,10*64,11*64,12*64 -}; +/* 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)*/ -static const int DT2_TABLE[4]={ /* 4 DT2 values */ -/* - * DT2 defines offset in cents from base note - * - * The table below defines offset in deltas table... - * User's Manual page 22 - * Values below were calculated using formula: value = orig.val * 1.5625 - * - * DT2=0 DT2=1 DT2=2 DT2=3 - * 0 600 781 950 - */ - 0, 384, 500, 608 -}; - -/* sustain lebel table (3db per step) */ /* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ -#define SC(db) (db*((3/EG_STEP)*(1<>2)&3) +#define OPM_CHAN(N) (N&7) +#define OPM_SLOT(N) ((N>>3)&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 + +/* FM timer model */ +#define FM_TIMER_SINGLE (0) +#define FM_TIMER_INTERVAL (1) + +/* ---------- debug section ------------------- */ +/* save output as raw 16-bit sample */ +/* #define SAVE_SAMPLE */ + +#ifdef SAVE_SAMPLE +static FILE *sample[1]; + #if 0 /*save to MONO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = rt; \ + 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 -/* dummy attack / decay rate ( when rate == 0 ) */ -static int RATE_0[32]= -{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}; + +/* ---------- OPN / OPM one channel ---------- */ +typedef struct fm_slot { + INT32 *DT; /* detune :DT_TABLE[DT] */ + int DT2; /* multiple,Detune2:(DT2<<4)|ML for OPM */ + UINT32 TL; /* total level :TL << 3 */ + UINT8 KSR; /* key scale rate :3-KSR */ + UINT8 ARval; /* current AR */ + const UINT32 *AR; /* attack rate :&AR_TABLE[AR<<1] */ + const UINT32 *DR; /* decay rate :&DR_TABLE[DR<<1] */ + const UINT32 *SR; /* sustain rate :&DR_TABLE[SR<<1] */ + const UINT32 *RR; /* release rate :&DR_TABLE[RR<<2+2] */ + UINT8 SEG; /* SSG EG type :SSGEG */ + UINT8 ksr; /* key scale rate :kcode>>(3-KSR) */ + UINT32 mul; /* multiple :ML_TABLE[ML] */ + + /* Phase Generator */ + UINT32 Cnt; /* frequency count : */ + UINT32 Incr; /* frequency step : */ + + /* Envelope Generator */ + UINT8 state; /* phase type */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level :SL_TABLE[SL] */ + + UINT32 delta_ar; /* envelope step for Attack */ + UINT32 delta_dr; /* envelope step for Decay */ + UINT32 delta_sr; /* envelope step for Sustain */ + UINT32 delta_rr; /* envelope step for Release */ + UINT32 TLL; /* adjusted TotalLevel */ + + UINT32 key; /* 0=last key was KEY OFF, 1=KEY ON */ + + /* LFO */ + UINT32 amon; /* AMS enable flag */ + UINT32 ams; /* AMS depth level of this SLOT */ +}FM_SLOT; + +typedef struct fm_chan { + FM_SLOT SLOT[4]; + UINT8 ALGO; /* Algorithm */ + UINT8 FB; /* feedback shift */ + INT32 op1_out[2]; /* op1 output for feedback */ + /* Algorithm (connection) */ + INT32 *connect1; /* pointer of SLOT1 output */ + INT32 *connect2; /* pointer of SLOT2 output */ + INT32 *connect3; /* pointer of SLOT3 output */ + INT32 *connect4; /* pointer of SLOT4 output */ + /* LFO */ + INT32 pms; /* PMS depth channel level */ + UINT32 ams; /* AMS depth channel level */ + /* Phase Generator */ + UINT32 fc; /* fnum,blk:adjusted to sample rate */ + UINT8 kcode; /* key code: */ +} FM_CH; + +/* OPN/OPM common state */ +typedef struct fm_state { + UINT8 index; /* chip index (number of chip) */ + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + double TimerBase; /* Timer base time */ +#if FM_BUSY_FLAG_SUPPORT + double BusyExpire; /* ExpireTime of Busy clear */ +#endif + UINT8 address; /* address register */ + UINT8 irq; /* interrupt level */ + UINT8 irqmask; /* irq mask */ + UINT8 status; /* status flag */ + UINT32 mode; /* mode CSM / 3SLOT */ + UINT8 prescaler_sel;/* prescaler slelector */ + UINT8 fn_h; /* freq latch */ + int TA; /* timer a */ + int TAC; /* timer a counter */ + UINT8 TB; /* timer b */ + int TBC; /* timer b counter */ + /* local time tables */ + INT32 DT_TABLE[8][32]; /* DeTune table */ + UINT32 eg_tab [32+64+32]; /* Envelope Generator rates (32 + 64 rates + 32 RKS) */ + /* Extention Timer and IRQ handler */ + FM_TIMERHANDLER Timer_Handler; + FM_IRQHANDLER IRQ_Handler; + /* timer model single / interval */ + UINT8 timermodel; +}FM_ST; + /* -------------------- state --------------------- */ /* some globals */ -#define TYPE_SSG 0x01 /* SSG support */ -#define TYPE_OPN 0x02 /* OPN device */ +#define TYPE_SSG 0x01 /* SSG support */ +#define TYPE_OPN 0x02 /* OPN device */ //this one is not used ???? #define TYPE_LFOPAN 0x04 /* OPN type LFO and PAN */ -#define TYPE_6CH 0x08 /* FM 6CH / 3CH */ -#define TYPE_DAC 0x10 /* YM2612's DAC device */ -#define TYPE_ADPCM 0x20 /* ADPCM device */ +#define TYPE_6CH 0x08 /* FM 6CH / 3CH */ +#define TYPE_DAC 0x10 /* YM2612's DAC device */ +#define TYPE_ADPCM 0x20 /* 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_6CH |TYPE_LFOPAN |TYPE_DAC) +#define TYPE_YM2612 (TYPE_DAC |TYPE_LFOPAN |TYPE_6CH) -static int FMNumChips; /* total # of FM emulated */ +/* current chip state */ +static void *cur_chip = 0; /* pointer of current chip struct */ +static FM_ST *State; /* basic status */ +static FM_CH *cch[8]; /* pointer of FM channels */ -/* work table */ -static void *cur_chip = 0; /* current chip point */ -/* currenct chip state */ -static FM_ST *State; -static FMSAMPLE *bufL,*bufR; -static FM_CH *cch[8]; -static signed int outd[4]; - -/* operator connection work */ -static int feedback2; /* connect for operator 2 */ -static int feedback3; /* connect for operator 3 */ -static int feedback4; /* connect for operator 4 */ +/* runtime work */ +static INT32 out_fm[8]; /* outputs of working channels */ +#if BUILD_ADPCMA +static INT32 out_adpcm[4]; /* channel output NONE,LEFT,RIGHT or CENTER for YM2610 ADPCM */ +static INT32 out_delta[4]; /* channel output NONE,LEFT,RIGHT or CENTER for YM2610 DELTAT*/ +#endif +static INT32 pg_in2,pg_in3,pg_in4; /* PG input of SLOTs */ +/* -------------------- log output -------------------- */ /* 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__ -static void Log(int level,char *format,...) -{ - int i; - va_list argptr; +#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x +#endif - if( level < LOG_LEVEL ) return; - va_start(argptr,format); - /* */ - if (errorlog) vfprintf( errorlog, format , argptr); +/* ----- limitter ----- */ +#define Limit(val, max,min) { \ + if ( val > max ) val = max; \ + else if ( val < min ) val = min; \ +} + +/* ----- buffering one of data(STEREO chip) ----- */ +#if FM_STEREO_MIX +/* stereo mixing */ +#define FM_BUFFERING_STEREO \ +{ \ + /* get left & right output with clipping */ \ + out_ch[OUTD_LEFT] += out_ch[OUTD_CENTER]; \ + Limit( out_ch[OUTD_LEFT] , MAXOUT, MINOUT ); \ + out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER]; \ + Limit( out_ch[OUTD_RIGHT], MAXOUT, MINOUT ); \ + /* buffering */ \ + *bufL++ = out_ch[OUTD_LEFT] >>FINAL_SH; \ + *bufL++ = out_ch[OUTD_RIGHT]>>FINAL_SH; \ +} +#else +/* stereo separate */ +#define FM_BUFFERING_STEREO \ +{ \ + /* get left & right output with clipping */ \ + out_ch[OUTD_LEFT] += out_ch[OUTD_CENTER]; \ + Limit( out_ch[OUTD_LEFT] , MAXOUT, MINOUT ); \ + out_ch[OUTD_RIGHT] += out_ch[OUTD_CENTER]; \ + Limit( out_ch[OUTD_RIGHT], MAXOUT, MINOUT ); \ + /* buffering */ \ + bufL[i] = out_ch[OUTD_LEFT] >>FINAL_SH; \ + bufR[i] = out_ch[OUTD_RIGHT]>>FINAL_SH; \ } #endif -/* --------------- Customize External interface port (SSG,Timer,etc) ---------------*/ -#include "fmext.c" +#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 */ /* --------------------- subroutines --------------------- */ - -INLINE int Limit( int val, int max, int min ) { - if ( val > max ) - val = max; - else if ( val < min ) - val = min; - - return val; -} - /* status set and IRQ handling */ INLINE void 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->index,1); - } + /* 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->index,1); + } } /* status reset and IRQ handling */ 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->index,0); - } + /* 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->index,0); + } } /* IRQ mask set */ 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); + ST->irqmask = flag; + /* IRQ handling check */ + FM_STATUS_SET(ST,0); + FM_STATUS_RESET(ST,0); } -/* ----- key on ----- */ -INLINE void FM_KEYON(FM_CH *CH , int s ) +#if FM_BUSY_FLAG_SUPPORT +INLINE UINT8 FM_STATUS_FLAG(FM_ST *ST) { - FM_SLOT *SLOT = &CH->SLOT[s]; - if( SLOT->evm<= ENV_MOD_RR) - { - /* set envelope counter from envleope output */ - - /* sin wave restart */ - SLOT->Cnt = 0; - if( s == SLOT1 ) CH->op1_out = 0; - /* set attack */ -#ifdef SEG_SUPPORT - if( SLOT->SEG&8 ) SLOT->evm = ENV_SSG_AR; /* jp 09/06/99 */ - else -#endif - SLOT->evm = ENV_MOD_AR; - SLOT->evs = SLOT->evsa; -#if 0 - /* convert decay count to attack count */ - /* --- This caused the problem by credit sound of paper boy. --- */ - SLOT->evc = EG_AST + DRAR_TABLE[ENV_CURVE[SLOT->evc>>ENV_BITS]];/* + SLOT->evs;*/ -#else - /* reset attack counter */ - SLOT->evc = EG_AST; -#endif - SLOT->eve = EG_AED; - } + if( ST->BusyExpire ) + { + if( (ST->BusyExpire - FM_GET_TIME_NOW()) > 0) + return ST->status | 0x80; /* with busy */ + /* expire */ + ST->BusyExpire = 0; + } + return ST->status; } -/* ----- key off ----- */ -INLINE void FM_KEYOFF(FM_CH *CH , int s ) +INLINE void FM_BUSY_SET(FM_ST *ST,int busyclock ) { - FM_SLOT *SLOT = &CH->SLOT[s]; - if( SLOT->evm > ENV_MOD_RR) - { - /* set envelope counter from envleope output */ - SLOT->evm = ENV_MOD_RR; - if( !(SLOT->evc&EG_DST) ) - SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<eve = EG_DED; - SLOT->evs = SLOT->evsr; - } + ST->BusyExpire = FM_GET_TIME_NOW() + (ST->TimerBase * busyclock); } - -/* ---------- calcrate Envelope Generator & Phase Generator ---------- */ -/* return : envelope output */ -INLINE signed int FM_CALC_SLOT( FM_SLOT *SLOT ) -{ - /* calcrate phage generator */ - SLOT->Cnt += SLOT->Incr; - /* calcrate envelope generator */ - if( (SLOT->evc+=SLOT->evs) >= SLOT->eve ) - { - switch( SLOT->evm ){ - case ENV_MOD_AR: /* ATTACK -> DECAY1 */ - /* next DR */ - SLOT->evm = ENV_MOD_DR; - SLOT->evc = EG_DST; - SLOT->eve = SLOT->SL; - SLOT->evs = SLOT->evsd; - break; - case ENV_MOD_DR: /* DECAY -> SUSTAIN */ - SLOT->evm = ENV_MOD_SR; - SLOT->evc = SLOT->SL; - SLOT->eve = EG_DED; - SLOT->evs = SLOT->evss; - break; - case ENV_MOD_RR: /* RR -> OFF & STOP */ - SLOT->evm = ENV_MOD_OFF; - case ENV_MOD_SR: /* SR -> OFF & STOP */ - SLOT->evc = EG_OFF; - SLOT->eve = EG_OFF+1; - SLOT->evs = 0; - break; -#ifdef SEG_SUPPORT - case ENV_SSG_AR: /* SSG ATTACK */ - if( SLOT->SEG&4){ /* start direction */ - /* next SSG-SR (upside start ) */ - SLOT->evm = ENV_SSG_SR; - SLOT->evc = SLOT->SL + (EG_UST - EG_DST); - SLOT->eve = EG_UED; - SLOT->evs = SLOT->evss; - }else{ - /* next SSG-DR (downside start ) */ - SLOT->evm = ENV_SSG_DR; - SLOT->evc = EG_DST; - SLOT->eve = EG_DED; - SLOT->evs = SLOT->evsd; - } - break; - case ENV_SSG_DR: /* SEG down side */ - if( SLOT->SEG&2){ - /* reverce */ - SLOT->evm = ENV_SSG_SR; - SLOT->evc = SLOT->SL + (EG_UST - EG_DST); - SLOT->eve = EG_UED; - SLOT->evs = SLOT->evss; - }else{ - /* again */ - SLOT->evc = EG_DST; - } - /* hold */ - if( SLOT->SEG&1) SLOT->evs = 0; - break; - case ENV_SSG_SR: /* upside */ - if( SLOT->SEG&2){ - /* reverce */ - SLOT->evm = ENV_SSG_DR; - SLOT->evc = EG_DST; - SLOT->eve = EG_DED; - SLOT->evs = SLOT->evsd; - }else{ - /* again */ - SLOT->evc = SLOT->SL + (EG_UST - EG_DST); - } - /* hold check */ - if( SLOT->SEG&1) SLOT->evs = 0; - break; -#endif - } - } - /* calcrate envelope */ -#if 0 /* ifdef TL_SAVE_MEM */ - signed int env_out = SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]; /* LFO_out[SLOT->AMS] */ - if(env_out >= (EG_ENT-1) ) return EG_ENT-1; - return env_out; +#define FM_BUSY_CLEAR(ST) ((ST)->BusyExpire = 0) #else - return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]; /* LFO_out[SLOT->AMS] */ +#define FM_STATUS_FLAG(ST) ((ST)->status) +#define FM_BUSY_SET(ST,bclock) {} +#define FM_BUSY_CLEAR(ST) {} #endif -} -/* set algorythm connection */ -static void set_algorythm( FM_CH *CH ) +/* ---------- event handler of Phase Generator ---------- */ + +/* phase of the envelope generator */ +#define EG_ATT 4 +#define EG_DEC 3 +#define EG_SUS 2 +#define EG_REL 1 +#define EG_OFF 0 + + + + +#if 0 +/* This will be removed as soon as SSG support will be added */ +#if FM_SEG_SUPPORT + +/* SEG down side end */ +static void FM_EG_SSG_sr( FM_SLOT *SLOT ) { - signed int *carrier = &outd[CH->PAN]; + if( SLOT->SEG&2){ + /* reverse */ + SLOT->state = FM_EG_SSG_SR; + SLOT->volume = SLOT->SL + (EG_UST - EG_DST); + SLOT->eve = EG_UED; + SLOT->evs = SLOT->delta_sr; + }else{ + /* again */ + SLOT->volume = EG_DST; + } + /* hold */ + if( SLOT->SEG&1) SLOT->evs = 0; +} + +/* SEG upside side end */ +static void FM_EG_SSG_sr( FM_SLOT *SLOT ) +{ + if( SLOT->SEG&2){ + /* reverse */ + SLOT->state = FM_EG_SSG_DR; + SLOT->volume = EG_DST; + SLOT->eve = EG_DED; + SLOT->evs = SLOT->delta_dr; + }else{ + /* again */ + SLOT->volume = SLOT->SL + (EG_UST - EG_DST); + } + /* hold check */ + if( SLOT->SEG&1) SLOT->evs = 0; +} + +/* SEG Attack end */ +static void FM_EG_SSG_ar( FM_SLOT *SLOT ) +{ + if( SLOT->SEG&4){ /* start direction */ + /* next SSG-SR (upside start ) */ + SLOT->state = FM_EG_SSG_SR; + SLOT->volume = SLOT->SL + (EG_UST - EG_DST); + SLOT->eve = EG_UED; + SLOT->evs = SLOT->delta_sr; + }else{ + /* next SSG-DR (downside start ) */ + SLOT->state = FM_EG_SSG_DR; + SLOT->volume = EG_DST; + SLOT->eve = EG_DED; + SLOT->evs = SLOT->delta_dr; + } +} +#endif /* FM_SEG_SUPPORT */ +#endif - /* setup connect algorythm */ - switch( CH->ALGO ){ - case 0: - /* PG---S1---S2---S3---S4---OUT */ - CH->connect1 = &feedback2; - CH->connect2 = &feedback3; - CH->connect3 = &feedback4; - break; - case 1: - /* PG---S1-+-S3---S4---OUT */ - /* PG---S2-+ */ - CH->connect1 = &feedback3; - CH->connect2 = &feedback3; - CH->connect3 = &feedback4; - break; - case 2: - /* PG---S1------+-S4---OUT */ - /* PG---S2---S3-+ */ - CH->connect1 = &feedback4; - CH->connect2 = &feedback3; - CH->connect3 = &feedback4; - break; - case 3: - /* PG---S1---S2-+-S4---OUT */ - /* PG---S3------+ */ - CH->connect1 = &feedback2; - CH->connect2 = &feedback4; - CH->connect3 = &feedback4; - break; - case 4: - /* PG---S1---S2-+--OUT */ - /* PG---S3---S4-+ */ - CH->connect1 = &feedback2; - CH->connect2 = carrier; - CH->connect3 = &feedback4; - break; - case 5: - /* +-S2-+ */ - /* PG---S1-+-S3-+-OUT */ - /* +-S4-+ */ - CH->connect1 = 0; /* special mark */ - CH->connect2 = carrier; - CH->connect3 = carrier; - break; - case 6: - /* PG---S1---S2-+ */ - /* PG--------S3-+-OUT */ - /* PG--------S4-+ */ - CH->connect1 = &feedback2; - CH->connect2 = carrier; - CH->connect3 = carrier; - break; - case 7: - /* PG---S1-+ */ - /* PG---S2-+-OUT */ - /* PG---S3-+ */ - /* PG---S4-+ */ - CH->connect1 = carrier; - CH->connect2 = carrier; - CH->connect3 = carrier; - } - CH->connect4 = carrier; + + +/* ----- key on of SLOT ----- */ +INLINE void FM_KEYON(FM_CH *CH , int s ) +{ + FM_SLOT *SLOT = &CH->SLOT[s]; + if( !SLOT->key ) + { + SLOT->key = 1; + /* restart Phase Generator */ + SLOT->Cnt = 0; +#if FM_SEG_SUPPORT + if( SLOT->SEG&8 ) SLOT->state = FM_EG_SSG_AR; + else +#endif + /* phase -> Attack */ + SLOT->state = EG_ATT; + } +} +/* ----- key off of SLOT ----- */ +INLINE void FM_KEYOFF(FM_CH *CH , int s ) +{ + FM_SLOT *SLOT = &CH->SLOT[s]; + if( SLOT->key ) + { + SLOT->key = 0; + /* phase -> Release */ + if (SLOT->state>EG_REL) + SLOT->state = EG_REL; + } +} + +/* setup Algorithm connection */ +static void setup_connection( FM_CH *CH, int ch ) +{ + INT32 *carrier = &out_fm[ch]; + + switch( CH->ALGO ){ + case 0: + /* PG---S1---S2---S3---S4---OUT */ + CH->connect1 = &pg_in2; + CH->connect2 = &pg_in3; + CH->connect3 = &pg_in4; + break; + case 1: + /* PG---S1-+-S3---S4---OUT */ + /* PG---S2-+ */ + CH->connect1 = &pg_in3; + CH->connect2 = &pg_in3; + CH->connect3 = &pg_in4; + break; + case 2: + /* PG---S1------+-S4---OUT */ + /* PG---S2---S3-+ */ + CH->connect1 = &pg_in4; + CH->connect2 = &pg_in3; + CH->connect3 = &pg_in4; + break; + case 3: + /* PG---S1---S2-+-S4---OUT */ + /* PG---S3------+ */ + CH->connect1 = &pg_in2; + CH->connect2 = &pg_in4; + CH->connect3 = &pg_in4; + break; + case 4: + /* PG---S1---S2-+--OUT */ + /* PG---S3---S4-+ */ + CH->connect1 = &pg_in2; + CH->connect2 = carrier; + CH->connect3 = &pg_in4; + break; + case 5: + /* +-S2-+ */ + /* PG---S1-+-S3-+-OUT */ + /* +-S4-+ */ + CH->connect1 = 0; /* special case */ + CH->connect2 = carrier; + CH->connect3 = carrier; + break; + case 6: + /* PG---S1---S2-+ */ + /* PG--------S3-+-OUT */ + /* PG--------S4-+ */ + CH->connect1 = &pg_in2; + CH->connect2 = carrier; + CH->connect3 = carrier; + break; + case 7: + /* PG---S1-+ */ + /* PG---S2-+-OUT */ + /* PG---S3-+ */ + /* PG---S4-+ */ + CH->connect1 = carrier; + CH->connect2 = carrier; + CH->connect3 = carrier; + } + CH->connect4 = carrier; } /* set detune & multiple */ INLINE void set_det_mul(FM_ST *ST,FM_CH *CH,FM_SLOT *SLOT,int v) { - SLOT->mul = MUL_TABLE[v&0x0f]; - SLOT->DT = ST->DT_TABLE[(v>>4)&7]; - CH->SLOT[SLOT1].Incr=-1; + SLOT->mul = (v&0x0f)? (v&0x0f)*2 : 1; + SLOT->DT = ST->DT_TABLE[(v>>4)&7]; + CH->SLOT[SLOT1].Incr=-1; } /* set total level */ INLINE void set_tl(FM_CH *CH,FM_SLOT *SLOT , int v,int csmflag) { - v &= 0x7f; - v = (v<<7)|v; /* 7bit -> 14bit */ - SLOT->TL = (v*EG_ENT)>>14; - if( !csmflag ) - { /* not CSM latch total level */ - SLOT->TLL = SLOT->TL + KSL[CH->kcode]; - } + SLOT->TL = (v&0x7f)<<(ENV_BITS-7); /*7bit TL*/ + /* if it is not a CSM channel , latch the total level */ + if( !csmflag ) + SLOT->TLL = SLOT->TL; } /* set attack rate & key scale */ -INLINE void set_ar_ksr(FM_CH *CH,FM_SLOT *SLOT,int v,signed int *ar_table) +INLINE void set_ar_ksr(FM_CH *CH,FM_SLOT *SLOT,int v,UINT32 *eg_tab) { - SLOT->KSR = 3-(v>>6); - SLOT->AR = (v&=0x1f) ? &ar_table[v<<1] : RATE_0; - SLOT->evsa = SLOT->AR[SLOT->ksr]; - if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa; - CH->SLOT[SLOT1].Incr=-1; + SLOT->KSR = 3-(v>>6); + SLOT->ARval = (v&0x1f) ? 32 + ((v&0x1f)<<1) : 0; + SLOT->AR = &eg_tab[ SLOT->ARval ]; + + if ((SLOT->ARval + SLOT->ksr) < 32+62) + SLOT->delta_ar = SLOT->AR[SLOT->ksr]; + else + SLOT->delta_ar = MAX_ATT_INDEX+1; + + CH->SLOT[SLOT1].Incr=-1; /* Optimize: only set this, if new SLOT->KSR is different */ } + /* set decay rate */ -INLINE void set_dr(FM_SLOT *SLOT,int v,signed int *dr_table) +INLINE void set_dr(FM_SLOT *SLOT,int v,UINT32 *eg_tab) { - SLOT->DR = (v&=0x1f) ? &dr_table[v<<1] : RATE_0; - SLOT->evsd = SLOT->DR[SLOT->ksr]; - if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd; + SLOT->DR = (v&0x1f) ? &eg_tab[32 + ((v&0x1f)<<1)] : &eg_tab[0]; + SLOT->delta_dr = SLOT->DR[SLOT->ksr]; } + /* set sustain rate */ -INLINE void set_sr(FM_SLOT *SLOT,int v,signed int *dr_table) +INLINE void set_sr(FM_SLOT *SLOT,int v,UINT32 *eg_tab) { - SLOT->SR = (v&=0x1f) ? &dr_table[v<<1] : RATE_0; - SLOT->evss = SLOT->SR[SLOT->ksr]; - if( SLOT->evm == ENV_MOD_SR ) SLOT->evs = SLOT->evss; + SLOT->SR = (v&0x1f) ? &eg_tab[32 + ((v&0x1f)<<1)] : &eg_tab[0]; + SLOT->delta_sr = SLOT->SR[SLOT->ksr]; } + /* set release rate */ -INLINE void set_sl_rr(FM_SLOT *SLOT,int v,signed int *dr_table) +INLINE void set_sl_rr(FM_SLOT *SLOT,int v,UINT32 *eg_tab) { - SLOT->SL = SL_TABLE[(v>>4)]; - SLOT->RR = &dr_table[((v&0x0f)<<2)|2]; - SLOT->evsr = SLOT->RR[SLOT->ksr]; - if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr; + SLOT->sl = SL_TABLE[ v>>4 ]; + SLOT->RR = &eg_tab[34 + ((v&0x0f)<<2)]; + SLOT->delta_rr = SLOT->RR[SLOT->ksr]; } -/* operator output calcrator */ -#define OP_OUT(slot,env,con) SIN_TABLE[((slot.Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env] -/* ---------- calcrate one of channel ---------- */ -INLINE void FM_CALC_CH( FM_CH *CH ) + + +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm) { - int op_out; - int env_out; + UINT32 p; - feedback2 = feedback3 = feedback4 = 0; + p = (env<<3) + sin_tab[ ( ((signed int)((phase & ~FREQ_MASK) + (pm<<15))) >> FREQ_SH ) & SIN_MASK ]; - /* SLOT 1 */ - env_out=FM_CALC_SLOT(&CH->SLOT[SLOT1]); - if( env_out < EG_ENT-1 ) - { - if( CH->FB){ - /* with self feed back */ - op_out = CH->op1_out; - CH->op1_out = OP_OUT(CH->SLOT[SLOT1],env_out,(CH->op1_out>>CH->FB) /* +LFOOut[SLOT->AMS]*/ ); - op_out = (op_out + CH->op1_out)/2; - }else{ - /* without self feed back */ - op_out = OP_OUT(CH->SLOT[SLOT1],env_out,0 /* +LFOOut[SLOT->AMS]*/ ); - } - /* output slot1 */ - if( !CH->connect1 ) - { - /* algorythm 5 */ - feedback2 = feedback3 = feedback4 = op_out; - }else{ - /* other algorythm */ - *CH->connect1 += op_out; - } - } - /* SLOT 2 */ - env_out=FM_CALC_SLOT(&CH->SLOT[SLOT2]); - if( env_out < EG_ENT-1 ) - *CH->connect2 += OP_OUT(CH->SLOT[SLOT2],env_out, feedback2 /* +LFOOut[SLOT->AMS]*/ ); - /* SLOT 3 */ - env_out=FM_CALC_SLOT(&CH->SLOT[SLOT3]); - if( env_out < EG_ENT-1 ) - *CH->connect3 += OP_OUT(CH->SLOT[SLOT3],env_out, feedback3 /* +LFOOut[SLOT->AMS]*/ ); - /* SLOT 4 */ - env_out=FM_CALC_SLOT(&CH->SLOT[SLOT4]); - if( env_out < EG_ENT-1 ) - *CH->connect4 += OP_OUT(CH->SLOT[SLOT4],env_out, feedback4 /* +LFOOut[SLOT->AMS]*/ ); + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; } -/* ---------- frequency counter for operater update ---------- */ -INLINE void CALC_FCSLOT(FM_SLOT *SLOT , int fc , int kc ) + +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm) { - int ksr; + UINT32 p; + INT32 i; - /* frequency step counter */ - SLOT->Incr= (fc+SLOT->DT[kc])*SLOT->mul; - ksr = kc >> SLOT->KSR; - if( SLOT->ksr != ksr ) - { - SLOT->ksr = ksr; - /* attack , decay rate recalcration */ - SLOT->evsa = SLOT->AR[ksr]; - SLOT->evsd = SLOT->DR[ksr]; - SLOT->evss = SLOT->SR[ksr]; - SLOT->evsr = SLOT->RR[ksr]; - } - SLOT->TLL = SLOT->TL + KSL[kc]; + i = (phase & ~FREQ_MASK) + pm; + +/*logerror("i=%08x (i>>16)&511=%8i phase=%i [pm=%08x] ",i, (i>>16)&511, phase>>FREQ_SH, pm);*/ + + p = (env<<3) + sin_tab[ (i>>FREQ_SH) & SIN_MASK]; + +/*logerror("(p&255=%i p>>8=%i) out= %i\n", p&255,p>>8, tl_tab[p&255]>>(p>>8) );*/ + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; } -/* ---------- frequency counter ---------- */ -INLINE void CALC_FCOUNT(FM_CH *CH ) + + +INLINE unsigned int calc_eg(FM_SLOT *SLOT) { - if( CH->SLOT[SLOT1].Incr==-1){ - int fc = CH->fc; - int kc = CH->kcode; - CALC_FCSLOT(&CH->SLOT[SLOT1] , fc , kc ); - CALC_FCSLOT(&CH->SLOT[SLOT2] , fc , kc ); - CALC_FCSLOT(&CH->SLOT[SLOT3] , fc , kc ); - CALC_FCSLOT(&CH->SLOT[SLOT4] , fc , kc ); - } + unsigned int out; + + switch(SLOT->state) + { + case EG_ATT: /* attack phase */ + { + INT32 step = SLOT->volume; + + SLOT->volume -= SLOT->delta_ar; + step = (step>>ENV_SH) - (((UINT32)SLOT->volume)>>ENV_SH); /* number of levels passed since last time */ + if (step > 0) + { + INT32 tmp_volume = SLOT->volume + (step<>4) & ~ENV_MASK); + if (tmp_volume <= MIN_ATT_INDEX) + break; + step--; + }while(step); + SLOT->volume = tmp_volume; + } + + if (SLOT->volume <= MIN_ATT_INDEX) + { + if (SLOT->volume < 0) + SLOT->volume = 0; /* this is not quite correct (checked) */ + SLOT->state = EG_DEC; + } + } + break; + + case EG_DEC: /* decay phase */ + if ( (SLOT->volume += SLOT->delta_dr) >= SLOT->sl ) + { + SLOT->volume = SLOT->sl; /* this is not quite correct (checked) */ + SLOT->state = EG_SUS; + } + break; + + case EG_SUS: /* sustain phase */ + if ( (SLOT->volume += SLOT->delta_sr) > MAX_ATT_INDEX ) + { + SLOT->volume = MAX_ATT_INDEX; + SLOT->state = EG_OFF; + } + break; + + case EG_REL: /* release phase */ + if ( (SLOT->volume += SLOT->delta_rr) > MAX_ATT_INDEX ) + { + SLOT->volume = MAX_ATT_INDEX; + SLOT->state = EG_OFF; + } + break; + } + + out = SLOT->TLL + (((unsigned int)SLOT->volume)>>ENV_SH); + if(SLOT->ams) + out += (SLOT->ams*lfo_amd/LFO_RATE); + return out; } -/* ---------- frequency counter ---------- */ -INLINE void OPM_CALC_FCOUNT(YM2151 *OPM , FM_CH *CH ) + +/* ---------- calculate one of channel ---------- */ +INLINE void FM_CALC_CH( FM_CH *CH ) { - if( CH->SLOT[SLOT1].Incr==-1) - { - int fc = CH->fc; - int kc = CH->kcode; - CALC_FCSLOT(&CH->SLOT[SLOT1] , OPM->KC_TABLE[fc + CH->SLOT[SLOT1].DT2] , kc ); - CALC_FCSLOT(&CH->SLOT[SLOT2] , OPM->KC_TABLE[fc + CH->SLOT[SLOT2].DT2] , kc ); - CALC_FCSLOT(&CH->SLOT[SLOT3] , OPM->KC_TABLE[fc + CH->SLOT[SLOT3].DT2] , kc ); - CALC_FCSLOT(&CH->SLOT[SLOT4] , OPM->KC_TABLE[fc + CH->SLOT[SLOT4].DT2] , kc ); - } + unsigned int eg_out1,eg_out2,eg_out3,eg_out4; /*envelope output*/ + + /* Phase Generator */ + pg_in2 = pg_in3 = pg_in4 = 0; + + /* Envelope Generator */ + eg_out1 = calc_eg(&CH->SLOT[SLOT1]); + eg_out2 = calc_eg(&CH->SLOT[SLOT2]); + eg_out3 = calc_eg(&CH->SLOT[SLOT3]); + eg_out4 = calc_eg(&CH->SLOT[SLOT4]); + + /* Connection */ + { + INT32 out = CH->op1_out[0] + CH->op1_out[1]; + CH->op1_out[0] = CH->op1_out[1]; + + if( !CH->connect1 ){ + /* algorithm 5 */ + pg_in2 = pg_in3 = pg_in4 = CH->op1_out[0]; + }else{ + /* other algorithms */ + *CH->connect1 += CH->op1_out[0]; + } + + CH->op1_out[1] = 0; + if( eg_out1 < ENV_QUIET ) /* SLOT 1 */ + CH->op1_out[1] = op_calc1(CH->SLOT[SLOT1].Cnt, eg_out1, (out<FB) ); + } + + if( eg_out2 < ENV_QUIET ) /* SLOT 2 */ + *CH->connect2 += op_calc(CH->SLOT[SLOT2].Cnt, eg_out2, pg_in2); + + if( eg_out3 < ENV_QUIET ) /* SLOT 3 */ + *CH->connect3 += op_calc(CH->SLOT[SLOT3].Cnt, eg_out3, pg_in3); + + if( eg_out4 < ENV_QUIET ) /* SLOT 4 */ + *CH->connect4 += op_calc(CH->SLOT[SLOT4].Cnt, eg_out4, pg_in4); + + + /* update phase counters AFTER output calculations */ + { + INT32 pms = lfo_pmd * CH->pms / LFO_RATE; + if(pms) + { + CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr + (INT32)(pms * CH->SLOT[SLOT1].Incr) / PMS_RATE; + CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr + (INT32)(pms * CH->SLOT[SLOT2].Incr) / PMS_RATE; + CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr + (INT32)(pms * CH->SLOT[SLOT3].Incr) / PMS_RATE; + CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr + (INT32)(pms * CH->SLOT[SLOT4].Incr) / PMS_RATE; + } + else + { + CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr; + CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr; + CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr; + CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr; + } + } } -/* ----------- initialize time tabls ----------- */ -static void init_timetables( FM_ST *ST , char *DTTABLE , int ARRATE , int DRRATE ) + +/* ---------- update phase increment counter of operator ---------- */ +INLINE void CALC_FCSLOT(FM_SLOT *SLOT , int fc , int kc ) { - int i,d; - double rate; + int ksr; - /* make detune table */ - for (d = 0;d <= 3;d++){ - for (i = 0;i <= 31;i++){ - rate = (double)DTTABLE[d*32 + i] * ST->freqbase / 4096 * FREQ_RATE; - ST->DT_TABLE[d][i] = rate; - ST->DT_TABLE[d+4][i] = -rate; - } - } - /* make attack rate & decay rate tables */ - for (i = 0;i < 4;i++) ST->AR_TABLE[i] = ST->DR_TABLE[i] = 0; - for (i = 4;i < 64;i++){ - rate = (double)ST->freqbase / 4096.0; /* frequency rate */ - if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ - rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */ - rate *= (double)(EG_ENT<AR_TABLE[i] = rate / ARRATE; - ST->DR_TABLE[i] = rate / DRRATE; - } - ST->AR_TABLE[62] = EG_AED-1; - ST->AR_TABLE[63] = EG_AED-1; - for (i = 64;i < 94 ;i++){ /* make for overflow area */ - ST->AR_TABLE[i] = ST->AR_TABLE[63]; - ST->DR_TABLE[i] = ST->DR_TABLE[63]; - } + /* (frequency) phase increment counter */ + SLOT->Incr= ((fc+SLOT->DT[kc])*SLOT->mul) >> 1; + + ksr = kc >> SLOT->KSR; + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + /* calculate envelope generator rates */ + if ((SLOT->ARval + ksr) < 32+62) + SLOT->delta_ar = SLOT->AR[ksr]; + else + SLOT->delta_ar = MAX_ATT_INDEX+1; + SLOT->delta_dr = SLOT->DR[ksr]; + SLOT->delta_sr = SLOT->SR[ksr]; + SLOT->delta_rr = SLOT->RR[ksr]; + } +} + +/* ---------- update phase increments counters ---------- */ +INLINE void OPN_CALC_FCOUNT(FM_CH *CH ) +{ + if( CH->SLOT[SLOT1].Incr==-1){ + int fc = CH->fc; + int kc = CH->kcode; + CALC_FCSLOT(&CH->SLOT[SLOT1] , fc , kc ); + CALC_FCSLOT(&CH->SLOT[SLOT2] , fc , kc ); + CALC_FCSLOT(&CH->SLOT[SLOT3] , fc , kc ); + CALC_FCSLOT(&CH->SLOT[SLOT4] , fc , kc ); + } +} + +/* ----------- initialize time tables ----------- */ +static void init_timetables( FM_ST *ST , UINT8 *DTTABLE ) +{ + int i,d; + double rate; #if 0 - for (i = 0;i < 64 ;i++){ /* make for overflow area */ - Log(LOG_WAR,"rate %2d , ar %f ms , dr %f ms \n",i, - ((double)(EG_ENT<AR_TABLE[i]) * (1000.0 / ST->rate), - ((double)(EG_ENT<DR_TABLE[i]) * (1000.0 / ST->rate) ); - } + 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<DT_TABLE[d][i] = (INT32) rate; + ST->DT_TABLE[d+4][i] = (INT32)-rate; +#if 0 + logerror("FM.C: DT [%2i %2i] = %8x \n", d, i, ST->DT_TABLE[d][i] ); +#endif + } + } + + /* calculate Envelope Generator rate table */ + for (i=0; i<34; i++) + ST->eg_tab[i] = 0; /* infinity */ + + for (i=2; i<64; i++) + { + rate = ST->freqbase; /* frequency rate */ + if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ + rate *= 1<< (i>>2); /* b2-5 : shift bit */ + rate /= 12.0 * 1024.0; + rate *= (double)(1<eg_tab[32+i] = rate; +#if 0 + logerror("FM.C: Rate %2i %1i Decay [real %11.4f ms][emul %11.4f ms][d=%08x]\n",i>>2, i&3, + ( ((double)(ENV_LEN<rate), + ( ((double)(ENV_LEN<eg_tab[32+i] ) * (1000.0 / (double)ST->rate), ST->eg_tab[32+i] ); +#endif + } + + for (i=0; i<32; i++) + { + ST->eg_tab[ 32+64+i ] = ST->eg_tab[32+63]; + } } /* ---------- reset one of channel ---------- */ static void reset_channel( FM_ST *ST , FM_CH *CH , int chan ) { - int c,s; + int c,s; - ST->mode = 0; /* normal mode */ - FM_STATUS_RESET(ST,0xff); - ST->TA = 0; - ST->TAC = 0; - ST->TB = 0; - ST->TBC = 0; - - for( c = 0 ; c < chan ; c++ ) - { - CH[c].fc = 0; - CH[c].PAN = OPN_CENTER; /* or OPM_CENTER */ - for(s = 0 ; s < 4 ; s++ ) - { - CH[c].SLOT[s].SEG = 0; - CH[c].SLOT[s].evm = ENV_MOD_OFF; - CH[c].SLOT[s].evc = EG_OFF; - CH[c].SLOT[s].eve = EG_OFF+1; - CH[c].SLOT[s].evs = 0; - } - } -} + ST->mode = 0; /* normal mode */ + FM_STATUS_RESET(ST,0xff); + ST->TA = 0; + ST->TAC = 0; + ST->TB = 0; + ST->TBC = 0; + + for( c = 0 ; c < chan ; c++ ) + { + CH[c].fc = 0; + for(s = 0 ; s < 4 ; s++ ) + { + CH[c].SLOT[s].SEG = 0; + CH[c].SLOT[s].state= EG_OFF; + CH[c].SLOT[s].volume = MAX_ATT_INDEX; + } + } +} + +/* ---------- initialize generic tables ---------- */ + +static void init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 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; i0.0) + o = 8*log(1.0/m)/log(2); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(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 ] = 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]]);*/ + } -/* ---------- generic table initialize ---------- */ -static int FMInitTable( void ) -{ - int s,t; - double rate; - int i,j; - double pom; - - /* allocate total level table */ - TL_TABLE = malloc(TL_MAX*2*sizeof(int)); - if( TL_TABLE == 0 ) return 0; - /* make total level table */ - for (t = 0;t < EG_ENT-1 ;t++){ - rate = ((1< voltage */ - TL_TABLE[ t] = (int)rate; - TL_TABLE[TL_MAX+t] = -TL_TABLE[t]; -/* Log(LOG_INF,"TotalLevel(%3d) = %x\n",t,TL_TABLE[t]);*/ - } - /* fill volume off area */ - for ( t = EG_ENT-1; t < TL_MAX ;t++){ - TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0; - } + /*logerror("FM.C: ENV_QUIET= %08x\n",ENV_QUIET );*/ - /* make sinwave table (total level offet) */ - /* degree 0 = degree 180 = off */ - SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[EG_ENT-1]; - for (s = 1;s <= SIN_ENT/4;s++){ - pom = sin(2*PI*s/SIN_ENT); /* sin */ - pom = 20*log10(1/pom); /* decibel */ - j = pom / EG_STEP; /* TL_TABLE steps */ - - /* degree 0 - 90 , degree 180 - 90 : plus section */ - SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j]; - /* degree 180 - 270 , degree 360 - 270 : minus section */ - SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j]; -/* Log(LOG_INF,"sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP);*/ - } - /* envelope counter -> envelope output table */ - for (i=0; i= EG_ENT ) pom = EG_ENT-1; */ - ENV_CURVE[i] = (int)pom; - /* DECAY ,RELEASE curve */ - ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i; -#ifdef SEG_SUPPORT - /* DECAY UPSIDE (SSG ENV) */ - ENV_CURVE[(EG_UST>>ENV_BITS)+i]= EG_ENT-1-i; +#ifdef SAVE_SAMPLE + sample[0]=fopen("sampsum.pcm","ab"); #endif - } - /* off */ - ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1; +} - /* decay to reattack envelope converttable */ - j = EG_ENT-1; - for (i=0; i>ENV_BITS] ); */ - } - return 1; +static int FMInitTable( void ) +{ + return 1; } static void FMCloseTable( void ) { - if( TL_TABLE ) free( TL_TABLE ); - return; +#if 0 + if( tl_tab ) free( tl_tab ); + tl_tab = 0; +#endif +#ifdef SAVE_SAMPLE + fclose(sample[0]); +#endif + return; } /* OPN/OPM Mode Register Write */ INLINE void FMSetMode( FM_ST *ST ,int 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+12); - /* External timer handler */ - if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,(double)ST->TBC,ST->TimerBase); - } - }else if (ST->timermodel == FM_TIMER_INTERVAL) - { /* stop interbval timer */ - 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)<<12; - /* External timer handler */ - if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,(double)ST->TAC,ST->TimerBase); - } - }else if (ST->timermodel == FM_TIMER_INTERVAL) - { /* stop interbval timer */ - if( ST->TAC != 0 ) - { - ST->TAC = 0; - if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,0,ST->TimerBase); - } - } + /* 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 ) + { + /* James Ponder 2001-09-30: Timer is not correct, adjusted by 12 */ + ST->TBC = ( 256-ST->TB)<<(4 + 12); + /* External timer handler */ + if (ST->Timer_Handler) (ST->Timer_Handler)(n,1,ST->TBC,ST->TimerBase); + } + }else if (ST->timermodel == FM_TIMER_INTERVAL) + { /* stop interbval timer */ + 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 ) + { + /* James Ponder 2001-09-30: Timer is not correct, adjusted by 12 */ + ST->TAC = (1024-ST->TA) << 12; + /* External timer handler */ + if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,ST->TAC,ST->TimerBase); + } + }else if (ST->timermodel == FM_TIMER_INTERVAL) + { /* stop interbval timer */ + if( ST->TAC != 0 ) + { + ST->TAC = 0; + if (ST->Timer_Handler) (ST->Timer_Handler)(n,0,0,ST->TimerBase); + } + } } /* Timer A Overflow */ INLINE void TimerAOver(FM_ST *ST) { - /* status set if enabled */ - if(ST->mode & 0x04) FM_STATUS_SET(ST,0x01); - /* clear or reload the counter */ - if (ST->timermodel == FM_TIMER_INTERVAL) - { - ST->TAC = (1024-ST->TA)<<12; - if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,0,(double)ST->TAC,ST->TimerBase); - } - else ST->TAC = 0; + /* set status (if enabled) */ + if(ST->mode & 0x04) FM_STATUS_SET(ST,0x01); + /* clear or reload the counter */ + if (ST->timermodel == FM_TIMER_INTERVAL) + { + /* James Ponder 2001-09-30: Timer is not correct, adjusted by 12 */ + ST->TAC = (1024-ST->TA) << 12; + if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,0,ST->TAC,ST->TimerBase); + } + else ST->TAC = 0; } /* Timer B Overflow */ INLINE void TimerBOver(FM_ST *ST) { - /* status set if enabled */ - if(ST->mode & 0x08) FM_STATUS_SET(ST,0x02); - /* clear or reload the counter */ - if (ST->timermodel == FM_TIMER_INTERVAL) - { - ST->TBC = ( 256-ST->TB)<<4; - if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,1,(double)ST->TBC,ST->TimerBase); - } - else ST->TBC = 0; + /* set status (if enabled) */ + if(ST->mode & 0x08) FM_STATUS_SET(ST,0x02); + /* clear or reload the counter */ + if (ST->timermodel == FM_TIMER_INTERVAL) + { + /* James Ponder 2001-09-30: Timer is not correct, adjusted by 12 */ + ST->TBC = ( 256-ST->TB)<< (4 + 12); + if (ST->Timer_Handler) (ST->Timer_Handler)(ST->index,1,ST->TBC,ST->TimerBase); + } + else ST->TBC = 0; } /* CSM Key Controll */ INLINE void CSMKeyControll(FM_CH *CH) { - int ksl = KSL[CH->kcode]; - /* all key off */ - FM_KEYOFF(CH,SLOT1); - FM_KEYOFF(CH,SLOT2); - FM_KEYOFF(CH,SLOT3); - FM_KEYOFF(CH,SLOT4); - /* total level latch */ - CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + ksl; - CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + ksl; - CH->SLOT[SLOT3].TLL = CH->SLOT[SLOT3].TL + ksl; - CH->SLOT[SLOT4].TLL = CH->SLOT[SLOT4].TL + ksl; - /* all key on */ - FM_KEYON(CH,SLOT1); - FM_KEYON(CH,SLOT2); - FM_KEYON(CH,SLOT3); - FM_KEYON(CH,SLOT4); -} - -#ifdef INTERNAL_TIMER -/* ---------- calcrate timer A ---------- */ -INLINE void CALC_TIMER_A( FM_ST *ST , FM_CH *CSM_CH ){ - if( ST->TAC && (ST->Timer_Handler==0) ) - if( (ST->TAC -= ST->freqbase) <= 0 ){ - TimerAOver( ST ); - /* CSM mode key,TL controll */ - if( ST->mode & 0x80 ){ /* CSM mode total level latch and auto key on */ - CSMKeyControll( CSM_CH ); - } - } + /* all key off */ + /* FM_KEYOFF(CH,SLOT1); */ + /* FM_KEYOFF(CH,SLOT2); */ + /* FM_KEYOFF(CH,SLOT3); */ + /* FM_KEYOFF(CH,SLOT4); */ + /* total level latch */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL; + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL; + CH->SLOT[SLOT3].TLL = CH->SLOT[SLOT3].TL; + CH->SLOT[SLOT4].TLL = CH->SLOT[SLOT4].TL; + /* all key on */ + FM_KEYON(CH,SLOT1); + FM_KEYON(CH,SLOT2); + FM_KEYON(CH,SLOT3); + FM_KEYON(CH,SLOT4); } -/* ---------- calcrate timer B ---------- */ -INLINE void CALC_TIMER_B( FM_ST *ST,int step){ - if( ST->TBC && (ST->Timer_Handler==0) ) - if( (ST->TBC -= ST->freqbase*step) <= 0 ){ - TimerBOver( ST ); - } + +#ifdef _STATE_H +#if 0 +static void FM_channel_postload(FM_CH *CH,int num_ch) +{ + int slot , ch; + + for(ch=0;chop1_out , 2); + state_save_register_UINT32(state_name, num, "phasestep" , &CH->fc , 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->Cnt , 1); + state_save_register_UINT8 (state_name, num, "state" , &SLOT->state , 1); + state_save_register_INT32 (state_name, num, "volume" , &SLOT->volume , 1); + state_save_register_UINT32(state_name, num, "totallevel" , &SLOT->TLL , 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 ); } -#endif /* INTERNAL_TIMER */ +#endif /* _STATE_H */ #if BUILD_OPN -/* ---------- priscaler set(and make time tables) ---------- */ -void OPNSetPris(FM_OPN *OPN , int pris , int TimerPris, int SSGpris) +/***********************************************************/ +/* OPN unit */ +/***********************************************************/ + +/* OPN 3slot struct */ +typedef struct opn_3slot { + UINT32 fc[3]; /* fnum3,blk3 :calculated */ + UINT8 fn_h; /* freq3 latch */ + UINT8 kcode[3]; /* key code : */ +}FM_3SLOT; + +/* OPN/A/B common state */ +typedef struct opn_f { + UINT8 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 FN_TABLE[2048]; /* fnumber -> increment counter */ + /* LFO */ + UINT32 LFOCnt; + UINT32 LFOIncr; + UINT32 LFO_FREQ[8]; /* LFO FREQ table */ +} FM_OPN; + +/* 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}; + +//#define LFO_ENT 512 +//#define LFO_SH (32-9) +//#define LFO_RATE 0x10000 +//#define PMS_RATE 0x400 + +static int OPNInitTable(void) { - int fn; + int i; - /* frequency base */ - OPN->ST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock * 4096.0 / OPN->ST.rate) / pris : 0; - /* Timer base time */ - OPN->ST.TimerBase = (OPN->ST.rate) ? 1.0/((double)OPN->ST.clock / (double)TimerPris) : 0; - /* SSG part priscaler set */ - if( SSGpris ) SSGClk( OPN->ST.index, OPN->ST.clock * 2 / SSGpris ); - /* make time tables */ - init_timetables( &OPN->ST , OPN_DTTABLE , OPN_ARRATE , OPN_DRRATE ); - /* make fnumber -> increment counter table */ - for( fn=0 ; fn < 2048 ; fn++ ) - { - /* it is freq table for octave 7 */ - /* opn freq counter = 20bit */ - OPN->FN_TABLE[fn] = (double)fn * OPN->ST.freqbase / 4096 * FREQ_RATE * (1<<7) / 2; - } -/* Log(LOG_INF,"OPN %d set priscaler %d\n",OPN->ST.index,pris);*/ + /* LFO wave table */ + for(i=0; iST.freqbase = (OPN->ST.rate) ? ((double)OPN->ST.clock / OPN->ST.rate) / pres : 0; +#else + OPN->ST.rate = (double)OPN->ST.clock / pres; + OPN->ST.freqbase = 1.0; +#endif + + /* Timer base time */ + OPN->ST.TimerBase = 1.0/((double)OPN->ST.clock / (double)TimerPres); + /* SSG part prescaler set */ + if( SSGpres ) SSGClk( OPN->ST.index, OPN->ST.clock * 2 / SSGpres ); + /* make time tables */ + init_timetables( &OPN->ST , OPN_DTTABLE ); + /* 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 */ +#if 0 + logerror("FM.C: FN_TABLE[%4i] = %08x (dec=%8i)\n", + i, OPN->FN_TABLE[i]>>6,OPN->FN_TABLE[i]>>6 ); +#endif + } + + /* LFO freq. table */ + { + /* 3.98Hz,5.56Hz,6.02Hz,6.37Hz,6.88Hz,9.63Hz,48.1Hz,72.2Hz @ 8MHz */ +#define FM_LF(Hz) ((double)LFO_ENT*(1<LFO_FREQ[i] = (UINT32)(freq_table[i] * OPN->ST.freqbase); + } + } + +/* LOG(LOG_INF,("OPN %d set prescaler %d\n",OPN->ST.index,pres));*/ } /* ---------- write a OPN mode register 0x20-0x2f ---------- */ static void OPNWriteMode(FM_OPN *OPN, int r, int v) { - unsigned char c; - FM_CH *CH; + UINT8 c; + FM_CH *CH; - switch(r){ - case 0x21: /* Test */ - break; - case 0x22: /* LFO FREQ (YM2608/YM2612) */ - /* 3.98Hz,5.56Hz,6.02Hz,6.37Hz,6.88Hz,9.63Hz,48.1Hz,72.2Hz */ - /* FM2608[n].LFOIncr = FM2608[n].LFO_TABLE[v&0x0f]; */ - 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 controll */ - FMSetMode( &(OPN->ST),OPN->ST.index,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]; - /* csm mode */ - if( c == 2 && (OPN->ST.mode & 0x80) ) break; - 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); -/* Log(LOG_INF,"OPN %d:%d : KEY %02X\n",n,c,v&0xf0);*/ - break; - } + switch(r){ + case 0x21: /* Test */ + break; + case 0x22: /* LFO FREQ (YM2608/YM2612) */ + if( OPN->type & TYPE_LFOPAN ) + { + OPN->LFOIncr = (v&0x08) ? OPN->LFO_FREQ[v&7] : 0; + cur_chip = NULL; + } + 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 controll */ + FMSetMode( &(OPN->ST),OPN->ST.index,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]; + /* csm mode */ + /* if( c == 2 && (OPN->ST.mode & 0x80) ) break; */ + 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); +/* LOG(LOG_INF,("OPN %d:%d : KEY %02X\n",n,c,v&0xf0));*/ + break; + } } /* ---------- write a OPN register (0x30-0xff) ---------- */ static void OPNWriteReg(FM_OPN *OPN, int r, int v) { - unsigned char c; - FM_CH *CH; - FM_SLOT *SLOT; - - /* 0x30 - 0xff */ - if( (c = OPN_CHAN(r)) == 3 ) return; /* 0xX3,0xX7,0xXB,0xXF */ - if( (r >= 0x100) /* && (OPN->type & TYPE_6CH) */ ) 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,(c == 2) && (OPN->ST.mode & 0x80) ); - break; - case 0x50: /* KS, AR */ - set_ar_ksr(CH,SLOT,v,OPN->ST.AR_TABLE); - break; - case 0x60: /* DR */ - /* bit7 = AMS ENABLE(YM2612) */ - set_dr(SLOT,v,OPN->ST.DR_TABLE); - break; - case 0x70: /* SR */ - set_sr(SLOT,v,OPN->ST.DR_TABLE); - break; - case 0x80: /* SL, RR */ - set_sl_rr(SLOT,v,OPN->ST.DR_TABLE); - break; - case 0x90: /* SSG-EG */ -#ifndef SEG_SUPPORT - if(v&0x08) Log(LOG_ERR,"OPN %d,%d,%d :SSG-TYPE envelope selected (not supported )\n",OPN->ST.index,c,OPN_SLOT(r)); -#endif - SLOT->SEG = v&0x0f; - break; - case 0xa0: - switch( OPN_SLOT(r) ){ - case 0: /* 0xa0-0xa2 : FNUM1 */ - { - unsigned int fn = (((unsigned int)( (CH->fn_h)&7))<<8) + v; - unsigned char blk = CH->fn_h>>3; - /* make keyscale code */ - CH->kcode = (blk<<2)|OPN_FKTABLE[(fn>>7)]; - /* make basic increment counter 32bit = 1 cycle */ - CH->fc = OPN->FN_TABLE[fn]>>(7-blk); - CH->SLOT[SLOT1].Incr=-1; - } - break; - case 1: /* 0xa4-0xa6 : FNUM2,BLK */ - CH->fn_h = v&0x3f; - break; - case 2: /* 0xa8-0xaa : 3CH FNUM1 */ - if( r < 0x100) - { - unsigned int fn = (((unsigned int)(OPN->SL3.fn_h[c]&7))<<8) + v; - unsigned char blk = OPN->SL3.fn_h[c]>>3; - /* make keyscale code */ - OPN->SL3.kcode[c]= (blk<<2)|OPN_FKTABLE[(fn>>7)]; - /* make basic increment counter 32bit = 1 cycle */ - OPN->SL3.fc[c] = OPN->FN_TABLE[fn]>>(7-blk); - (OPN->P_CH)[2].SLOT[SLOT1].Incr=-1; - } - break; - case 3: /* 0xac-0xae : 3CH FNUM2,BLK */ - if( r < 0x100) - OPN->SL3.fn_h[c] = 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 ? 8 - feedback : 0; - set_algorythm( CH ); - } - break; - case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2608) */ - if( OPN->type & TYPE_LFOPAN) - { - /* b0-2 PMS */ - /* 0,3.4,6.7,10,14,20,40,80(cent) */ - SLOT->pms = (v>>4) & 0x07; - /* b4-5 AMS */ - /* 0,1.4,5.9,11.8(dB) */ - SLOT->ams = v & 0x03; - /* PAN */ - CH->PAN = (v>>6)&0x03; /* PAN : b6 = R , b7 = L */ - set_algorythm( CH ); - /* Log(LOG_INF,"OPN %d,%d : PAN %d\n",n,c,CH->PAN);*/ - } - break; - } - break; - } + UINT8 c; + FM_CH *CH; + FM_SLOT *SLOT; + + /* 0x30 - 0xff */ + if( (c = OPN_CHAN(r)) == 3 ) return; /* 0xX3,0xX7,0xXB,0xXF */ + if( (r >= 0x100) /* && (OPN->type & TYPE_6CH) */ ) 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,(c == 2) && (OPN->ST.mode & 0x80) ); + break; + case 0x50: /* KS, AR */ + set_ar_ksr(CH,SLOT,v,OPN->ST.eg_tab); + break; + case 0x60: /* DR */ + /* bit7 = AMS_ON ENABLE(YM2612) */ + set_dr(SLOT,v,OPN->ST.eg_tab); + if( OPN->type & TYPE_LFOPAN) + { + SLOT->amon = (v&0x80) ? ~0: 0; + SLOT->ams = CH->ams & SLOT->amon; + } + break; + case 0x70: /* SR */ + set_sr(SLOT,v,OPN->ST.eg_tab); + break; + case 0x80: /* SL, RR */ + set_sl_rr(SLOT,v,OPN->ST.eg_tab); + break; + case 0x90: /* SSG-EG */ +#if !FM_SEG_SUPPORT + if(v&0x08) LOG(LOG_ERR,("OPN %d,%d,%d :SSG-TYPE envelope selected (not supported )\n",OPN->ST.index,c,OPN_SLOT(r))); +#endif + SLOT->SEG = v&0x0f; + break; + case 0xa0: + switch( OPN_SLOT(r) ){ + case 0: /* 0xa0-0xa2 : FNUM1 */ + { + UINT32 fn = (((UINT32)( (OPN->ST.fn_h)&7))<<8) + v; + UINT8 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]>>(7-blk); + 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 fn = (((UINT32)(OPN->SL3.fn_h&7))<<8) + v; + UINT8 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]>>(7-blk); + (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( CH, c ); + } + break; + case 1: /* 0xb4-0xb6 : L , R , AMS , PMS (YM2612/YM2610B/YM2610/YM2608) */ + if( OPN->type & TYPE_LFOPAN) + { + + /* b0-2 PMS */ + /* 0,3.4,6.7,10,14,20,40,80(cent) */ + static const double pmd_table[8]={0,3.4,6.7,10,14,20,40,80}; + + /* b4-5 AMS */ + /* 0, 1.4, 5.9, 11.8 (dB) */ + /* 0, 1.40625, 5.90625, 11.90625 (or 11.8125) */ + /* 0, 15, , 63 , 127 (or 126) in internal representation */ + + /* bit0, bit1, bit2, bit3, bit4, bit5, bit6, bit7, bit8, bit9 */ + /* 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 (internal representation value)*/ + /* 0.09375, 0.1875, 0.375, 0.75, 1.5, 3, 6, 12, 24, 48 (dB)*/ + static const int amd_table[4]={ (int)( ((0.0 *4)/3)/ENV_STEP), + (int)( ((1.40625*4)/3)/ENV_STEP), + (int)( ((5.90625*4)/3)/ENV_STEP), + (int)(((11.90625*4)/3)/ENV_STEP) }; + /* amd_table simply becomes = { 0, 15, 63, 127 } */ + + CH->pms = (INT32)( (1.5/1200.0)*pmd_table[v & 7] * PMS_RATE); + + CH->ams = amd_table[(v>>4) & 0x03]; + CH->SLOT[SLOT1].ams = CH->ams & CH->SLOT[SLOT1].amon; + CH->SLOT[SLOT2].ams = CH->ams & CH->SLOT[SLOT2].amon; + CH->SLOT[SLOT3].ams = CH->ams & CH->SLOT[SLOT3].amon; + CH->SLOT[SLOT4].ams = CH->ams & CH->SLOT[SLOT4].amon; + + /* PAN : b7 = L, b6 = R */ + OPN->PAN[ c*2 ] = (v & 0x80) ? ~0 : 0; + OPN->PAN[ c*2+1 ] = (v & 0x40) ? ~0 : 0; + + /* LOG(LOG_INF,("OPN %d,%d : PAN %x %x\n",n,c,OPN->PAN[c*2],OPN->PAN[c*2+1]));*/ + } + 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) + +*/ +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 */ +/* YM2203 local section */ /*******************************************************************************/ -static YM2203 *FM2203=NULL; /* array of YM2203's */ + +/* here's the virtual YM2203(OPN) */ +typedef struct ym2203_f { +#ifdef _STATE_H + UINT8 REGS[256]; /* registers */ +#endif + FM_OPN OPN; /* OPN state */ + FM_CH CH[3]; /* channel state */ +} YM2203; + +static YM2203 *FM2203=NULL; /* array of YM2203's */ +static int YM2203NumChips; /* number of chips */ /* ---------- update one of chip ----------- */ -void YM2203UpdateOne(int num, void *buffer, int length) +void YM2203UpdateOne(int num, INT16 *buffer, int length) { - YM2203 *F2203 = &(FM2203[num]); - FM_OPN *OPN = &(FM2203[num].OPN); - int i,ch; - int data; - FMSAMPLE *buf = (FMSAMPLE *)buffer; - - State = &F2203->OPN.ST; - cch[0] = &F2203->CH[0]; - cch[1] = &F2203->CH[1]; - cch[2] = &F2203->CH[2]; - - /* frequency counter channel A */ - CALC_FCOUNT( cch[0] ); - /* frequency counter channel B */ - CALC_FCOUNT( cch[1] ); - /* frequency counter channel C */ - if( (State->mode & 0xc0) ){ - /* 3SLOT MODE */ - if( cch[2]->SLOT[SLOT1].Incr==-1){ - /* 3 slot mode */ - CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); - } - }else CALC_FCOUNT( cch[2] ); + YM2203 *F2203 = &(FM2203[num]); + FM_OPN *OPN = &(FM2203[num].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]; + + /* LFO */ + lfo_amd = lfo_pmd = 0; + + /* frequency counter channel A */ + OPN_CALC_FCOUNT( cch[0] ); + /* frequency counter channel B */ + OPN_CALC_FCOUNT( cch[1] ); + /* frequency counter channel C */ + if( (State->mode & 0xc0) ){ + /* 3SLOT MODE */ + if( cch[2]->SLOT[SLOT1].Incr==-1){ + /* 3 slot mode */ + CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); + } + }else OPN_CALC_FCOUNT( cch[2] ); for( i=0; i < length ; i++ ) - { - /* channel A channel B channel C */ - outd[OPN_CENTER] = 0; - /* calcrate FM */ - for( ch=0;ch<3;ch++) FM_CALC_CH( cch[ch] ); - /* limit check */ - data = Limit( outd[OPN_CENTER] , OPN_MAXOUT, OPN_MINOUT ); - /* store to sound buffer */ - buf[i] = data >> OPN_OUTSB; -#ifdef INTERNAL_TIMER - /* timer controll */ - CALC_TIMER_A( State , cch[2] ); -#endif - } -#ifdef INTERNAL_TIMER - CALC_TIMER_B( State , length ); -#endif + { + int lt; + + /* channel A channel B channel C */ + /* clear outputs */ + out_fm[0] = 0; + out_fm[1] = 0; + out_fm[2] = 0; + /* calculate FM */ + FM_CALC_CH( cch[0] ); + FM_CALC_CH( cch[1] ); + FM_CALC_CH( cch[2] ); + + lt = out_fm[0] + out_fm[1] + out_fm[2]; + + lt >>= FINAL_SH; + /* check output limit */ + Limit( lt , MAXOUT, MINOUT ); + /* store to sound buffer */ + buf[i] = lt; + /* timer controll */ + INTERNAL_TIMER_A( State , cch[2] ) + } + INTERNAL_TIMER_B(State,length) } /* ---------- reset one of chip ---------- */ void YM2203ResetChip(int num) { - int i; - FM_OPN *OPN = &(FM2203[num].OPN); - - /* Reset Priscaler */ - OPNSetPris( OPN , 6*12 , 6*12 ,4); /* 1/6 , 1/4 */ - /* reset SSG section */ - SSGReset(OPN->ST.index); - /* status clear */ - FM_IRQMASK_SET(&OPN->ST,0x03); - OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ - reset_channel( &OPN->ST , FM2203[num].CH , 3 ); - /* reset OPerator paramater */ - for(i = 0xb6 ; i >= 0xb4 ; i-- ) OPNWriteReg(OPN,i,0xc0); /* PAN RESET */ - for(i = 0xb2 ; i >= 0x30 ; i-- ) OPNWriteReg(OPN,i,0); - for(i = 0x26 ; i >= 0x20 ; i-- ) OPNWriteReg(OPN,i,0); -} -#if 0 -/* ---------- return the buffer ---------- */ -FMSAMPLE *YM2203Buffer(int n) -{ - return FM2203[n].Buf; -} + int i; + FM_OPN *OPN = &(FM2203[num].OPN); -/* ---------- set buffer ---------- */ -int YM2203SetBuffer(int n, FMSAMPLE *buf) -{ - if( buf == 0 ) return -1; - FM2203[n].Buf = buf; - return 0; + /* Reset Prescaler */ + OPNPrescaler_w(OPN, 0 , 1 ); + /* reset SSG section */ + SSGReset(OPN->ST.index); + /* status clear */ + FM_IRQMASK_SET(&OPN->ST,0x03); + FM_BUSY_CLEAR(&OPN->ST); + OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ + reset_channel( &OPN->ST , FM2203[num].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 +static void YM2203_postload(void) +{ + int num , r; + + for(num=0;numST.address = v & 0xff; - /* Write register to SSG emurator */ - if( v < 16 ) SSGWrite(n,0,v); - switch(OPN->ST.address) - { - case 0x2d: /* divider sel */ - OPNSetPris( OPN, 6*12, 6*12 ,4); /* OPN 1/6 , SSG 1/4 */ - break; - case 0x2e: /* divider sel */ - OPNSetPris( OPN, 3*12, 3*12,2); /* OPN 1/3 , SSG 1/2 */ - break; - case 0x2f: /* divider sel */ - OPNSetPris( OPN, 2*12, 2*12,1); /* OPN 1/2 , SSG 1/1 */ - break; - } - } - else - { /* data port */ - int addr = OPN->ST.address; - switch( addr & 0xf0 ) - { - case 0x00: /* 0x00-0x0f : SSG section */ - /* Write data to SSG emurator */ - SSGWrite(n,a,v); - break; - case 0x20: /* 0x20-0x2f : Mode section */ - YM2203UpdateReq(n); - /* write register */ - OPNWriteMode(OPN,addr,v); - break; - default: /* 0x30-0xff : OPN section */ - YM2203UpdateReq(n); - /* write register */ - OPNWriteReg(OPN,addr,v); - } - } - return OPN->ST.irq; + if( !(a&1) ) + { /* address port */ + OPN->ST.address = (v &= 0xff); + /* Write register to SSG emulator */ + if( v < 16 ) SSGWrite(n,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; +#ifdef _STATE_H + FM2203[n].REGS[addr] = v; +#endif + switch( addr & 0xf0 ) + { + case 0x00: /* 0x00-0x0f : SSG section */ + /* Write data to SSG emulator */ + SSGWrite(n,a,v); + break; + case 0x20: /* 0x20-0x2f : Mode section */ + YM2203UpdateReq(n); + /* write register */ + OPNWriteMode(OPN,addr,v); + break; + default: /* 0x30-0xff : OPN section */ + YM2203UpdateReq(n); + /* write register */ + OPNWriteReg(OPN,addr,v); + } + FM_BUSY_SET(&OPN->ST,1); + } + return OPN->ST.irq; +} + +UINT8 YM2203Read(int n,int a) +{ + YM2203 *F2203 = &(FM2203[n]); + int addr = F2203->OPN.ST.address; + int ret = 0; + + if( !(a&1) ) + { /* status port */ + ret = FM_STATUS_FLAG(&F2203->OPN.ST); + } + else + { /* data port (only SSG) */ + if( addr < 16 ) ret = SSGRead(n); + } + return ret; } -unsigned char YM2203Read(int n,int a) +int YM2203TimerOver(int n,int c) { - YM2203 *F2203 = &(FM2203[n]); - int addr = F2203->OPN.ST.address; - int ret = 0; + YM2203 *F2203 = &(FM2203[n]); - if( !(a&1) ) - { /* status port */ - ret = F2203->OPN.ST.status; - } - else - { /* data port (ONLY SSG) */ - if( addr < 16 ) ret = SSGRead(n); - } - return ret; + if( c ) + { /* Timer B */ + TimerBOver( &(F2203->OPN.ST) ); + } + else + { /* Timer A */ + YM2203UpdateReq(n); + /* timer update */ + TimerAOver( &(F2203->OPN.ST) ); + /* CSM mode key,TL control */ + if( F2203->OPN.ST.mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + CSMKeyControll( &(F2203->CH[2]) ); + } + } + return F2203->OPN.ST.irq; } +#endif /* BUILD_YM2203 */ -int YM2203TimerOver(int n,int c) -{ - YM2203 *F2203 = &(FM2203[n]); - if( c ) - { /* Timer B */ - TimerBOver( &(F2203->OPN.ST) ); - } - else - { /* Timer A */ - YM2203UpdateReq(n); - /* timer update */ - TimerAOver( &(F2203->OPN.ST) ); - /* CSM mode key,TL controll */ - if( F2203->OPN.ST.mode & 0x80 ) - { /* CSM mode total level latch and auto key on */ - CSMKeyControll( &(F2203->CH[2]) ); - } - } - return F2203->OPN.ST.irq; -} -#endif /* BUILD_YM2203 */ +#if (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B) +/* adpcm type A struct */ +typedef struct adpcm_state { + UINT8 flag; /* port state */ + UINT8 flagMask; /* arrived flag mask */ + UINT8 now_data; /* current ROM data */ + UINT32 now_addr; /* current ROM address */ + UINT32 now_step; + UINT32 step; + UINT32 start; /* sample data start address*/ + UINT32 end; /* sample data end address */ + UINT8 IL; /* Instrument Level */ + INT32 adpcm_acc; /* accumulator */ + INT32 adpcm_step; /* step */ + INT32 adpcm_out; /* (speedup) hiro-shi!! */ + INT8 vol_mul; /* volume in "0.75dB" steps */ + UINT8 vol_shift; /* volume in "-6dB" steps */ + INT32 *pan; /* &out_adpcm[OPN_xxxx] */ +}ADPCM_CH; -#if (BUILD_FM_ADPCMA || BUILD_FM_ADPCMB) +/* here's the virtual YM2610 */ +typedef struct ym2610_f { +#ifdef _STATE_H + UINT8 REGS[512]; /* registers */ +#endif + FM_OPN OPN; /* OPN state */ + FM_CH CH[6]; /* channel state */ + int address1; /* address register1 */ +/* ADPCM-A unit */ + UINT8 *pcmbuf; /* pcm rom buffer */ + UINT32 pcm_size; /* size of pcm rom */ + UINT8 adpcmTL; /* adpcmA total level */ + ADPCM_CH adpcm[6]; /* adpcm channels */ + UINT32 adpcmreg[0x30]; /* registers */ + UINT8 adpcm_arrivedEndAddress; + YM_DELTAT deltaT; /* Delta-T ADPCM unit */ +} YM2610; -/*#define ADPCMA_DECODE_RANGE 1024 */ -#define ADPCMA_DECODE_RANGE 1024 -#define ADPCMA_DECODE_MIN (-(ADPCMA_DECODE_RANGE*ADPCMA_VOLUME_RATE)) -#define ADPCMA_DECODE_MAX ((ADPCMA_DECODE_RANGE*ADPCMA_VOLUME_RATE)-1) -#define ADPCMA_VOLUME_DIV 1 - -#define ADPCMB_DECODE_RANGE 32768 -#define ADPCMB_DECODE_MIN (-(ADPCMB_DECODE_RANGE)) -#define ADPCMB_DECODE_MAX ((ADPCMB_DECODE_RANGE)-1) - -/* DELTA-T particle adjuster */ -#define ADPCMB_DELTA_MAX (24576) -#define ADPCMB_DELTA_MIN (127) -#define ADPCMB_DELTA_DEF (127) - -/***************************************************************/ -/* ADPCM units are made by Hiromitsu Shioya (MMSND) */ -/***************************************************************/ -static char *pcmbufA, *pcmbufB; -static unsigned int pcmsizeA, pcmsizeB; -static unsigned char adpcm_arrivedEndAddress; -static unsigned char adpcm_statusmask; +/* here is the virtual YM2608 */ +typedef YM2610 YM2608; -/************************************************************/ -/************************************************************/ -/* --------------------- subroutines --------------------- */ -/************************************************************/ -/************************************************************/ -/************************/ -/* ADPCM A tables */ -/************************/ -static int jedi_table[49*16]; -static int decode_tableA1[16] = { - -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16, - -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16 -}; -/* 0.9 , 0.9 , 0.9 , 0.9 , 1.2 , 1.6 , 2.0 , 2.4 */ -/* 8 = -1 , 2 5 8 11 */ -/* 9 = -1 , 2 5 9 13 */ -/* 10= -1 , 2 6 10 14 */ -/* 12= -1 , 2 7 12 17 */ -/* 20= -2 , 4 12 20 32 */ +#endif /* (BUILD_YM2608||BUILD_YM2610||BUILD_YM2610B) */ -#if 1 -static void InitOPNB_ADPCMATable(void){ - int step, nib; - for (step = 0; step <= 48; step++) - { - int stepval = floor (16.0 * pow (11.0 / 10.0, (double)step) * ADPCMA_VOLUME_RATE); - /* loop over all nibbles and compute the difference */ - for (nib = 0; nib < 16; nib++) - { - int value = stepval*((nib&0x07)*2+1)/8; - jedi_table[step*16+nib] = (nib&0x08) ? -value : value; - } - } -} -#else -static int decode_tableA2[49] = { - 0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001c, 0x001f, - 0x0022, 0x0025, 0x0029, 0x002d, 0x0032, 0x0037, 0x003c, 0x0042, - 0x0049, 0x0050, 0x0058, 0x0061, 0x006b, 0x0076, 0x0082, 0x008f, - 0x009d, 0x00ad, 0x00be, 0x00d1, 0x00e6, 0x00fd, 0x0117, 0x0133, - 0x0151, 0x0173, 0x0198, 0x01c1, 0x01ee, 0x0220, 0x0256, 0x0292, - 0x02d4, 0x031c, 0x036c, 0x03c3, 0x0424, 0x048e, 0x0502, 0x0583, - 0x0610 -}; -static void InitOPNB_ADPCMATable(void){ - int ta,tb,tc; - for(ta=0;ta<49;ta++){ - for(tb=0;tb<16;tb++){ - tc=0; - if(tb&0x04){tc+=((decode_tableA2[ta]*ADPCMA_VOLUME_RATE));} - if(tb&0x02){tc+=((decode_tableA2[ta]*ADPCMA_VOLUME_RATE)>>1);} - if(tb&0x01){tc+=((decode_tableA2[ta]*ADPCMA_VOLUME_RATE)>>2);} - tc+=((decode_tableA2[ta]*ADPCMA_VOLUME_RATE)>>3); - if(tb&0x08){tc=(0-tc);} - jedi_table[ta*16+tb]=tc; - } - } -} -#endif +#if BUILD_ADPCMA -/************************/ -/* ADPCM B tables */ -/************************/ -/* Forecast to next Forecast (rate = *8) */ -/* 1/8 , 3/8 , 5/8 , 7/8 , 9/8 , 11/8 , 13/8 , 15/8 */ -static const int decode_tableB1[16] = { - 1, 3, 5, 7, 9, 11, 13, 15, - -1, -3, -5, -7, -9, -11, -13, -15, -}; -/* delta to next delta (rate= *64) */ -/* 0.9 , 0.9 , 0.9 , 0.9 , 1.2 , 1.6 , 2.0 , 2.4 */ -static const int decode_tableB2[16] = { - 57, 57, 57, 57, 77, 102, 128, 153, - 57, 57, 57, 57, 77, 102, 128, 153 -}; +/**** YM2610 ADPCM defines ****/ +#define ADPCM_SHIFT (16) /* frequency step rate */ +#define ADPCMA_ADDRESS_SHIFT 8 /* adpcm A address shift */ -/* Forecast to Measurement (rate = *8) */ -/* n < 1/4 , 1/4 <= n > 1/2 , 1/2 <= n > 3/4 , 3/4 <= n > 1 */ -/* 1 <= n > 5/4 , 5/4 <= n > 3/2 , 3/2 <= n > 7/4 , 7/4 <= n */ -#if 1 -#define decode_tableB3 decode_tableB1 -#else -static const int decode_tableB3[16] = { - 0, 2, 4, 6, 8, 10, 12, 14, - 0,-2, -4, -6, -8, -10,-12,-14 +static UINT8 *pcmbufA; +static UINT32 pcmsizeA; + + +/* Algorithm and tables verified on real YM2610 */ + +/* usual ADPCM table (16 * 1.1^N) */ +static 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 }; -#endif + +/* different from the usual ADPCM table */ +static int step_inc[8] = { -1*16, -1*16, -1*16, -1*16, 2*16, 5*16, 7*16, 9*16 }; + +/* speedup purposes only */ +static int jedi_table[ 49*16 ]; + + +static void InitOPNB_ADPCMATable(void) +{ + 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; + } + } +} /**** ADPCM A (Non control type) ****/ INLINE void OPNB_ADPCM_CALC_CHA( YM2610 *F2610, ADPCM_CH *ch ) { - unsigned int step; - int data; + UINT32 step; + UINT8 data; - ch->now_step += ch->step; - if ( ch->now_step >= (1<now_step >> ADPCM_SHIFT; - ch->now_step &= (1<now_addr+step) > (ch->end<<1) ) { - ch->flag = 0; - F2610->adpcm_arrivedEndAddress |= ch->flagMask & F2610->adpcm_statusmask; - return; - } - do{ + ch->now_step += ch->step; + if ( ch->now_step >= (1<now_step >> ADPCM_SHIFT; + ch->now_step &= (1< 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; + F2610->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 = *(pcmbufA+(ch->now_addr>>1)); - data = (ch->now_data >> 4)&0x0f; - } - ch->now_addr++; - - ch->adpcmx = Limit( ch->adpcmx + (jedi_table[ch->adpcmd+data]), - ADPCMA_DECODE_MAX, ADPCMA_DECODE_MIN ); - ch->adpcmd = Limit( ch->adpcmd + decode_tableA1[data], 48*16, 0*16 ); - /**** calc pcm * volume data ****/ - ch->adpcml = ch->adpcmx * ch->volume; - }while(--step); - } - /* output for work of output channels (outd[OPNxxxx])*/ - *(ch->pan) += ch->adpcml; -} + 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 = *(pcmbufA+(ch->now_addr>>1)); + data = (ch->now_data >> 4)&0x0f; + } + + ch->now_addr++; + + ch->adpcm_acc += jedi_table[ch->adpcm_step + data]; + + /* extend 12-bit signed int */ + if (ch->adpcm_acc & 0x800) + ch->adpcm_acc |= ~0xfff; + else + 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 */ + } -/**** ADPCM B (Delta-T control type) ****/ -INLINE void OPNB_ADPCM_CALC_CHB( YM2610 *F2610, ADPCM_CH *ch ) -{ - unsigned int step; - int data; - - int old_m; - int now_leveling; - int delta_next; - - ch->now_step += ch->step; - if ( ch->now_step >= (1<now_step >> ADPCM_SHIFT; - ch->now_step &= (1<now_addr > (ch->end<<1) ) { - if( F2610->port0state&0x10 ){ - /**** repeat start ****/ - ch->now_addr = ch->start<<1; - /*ch->adpcmm = 0;*/ - ch->adpcmx = 0; - /* ch->adpcml = 0; */ - ch->adpcmd = ADPCMB_DELTA_DEF; - ch->next_leveling = 0; - ch->flag = 1; - }else{ - F2610->adpcm_arrivedEndAddress |= ch->flagMask & F2610->adpcm_statusmask; - ch->flag = 0; - ch->adpcml = 0; - now_leveling = 0; - return; - } - } -#if 0 - if ( ch->now_addr > (pcmsizeB<<1) ) { - Log(LOG_WAR,"YM2610: Attempting to play past Delta T rom size!\n" ); - return; - } -#endif - if( ch->now_addr&1 ) data = ch->now_data & 0x0f; - else - { - ch->now_data = *(pcmbufB+(ch->now_addr>>1)); - data = ch->now_data >> 4; - } - ch->now_addr++; - /* shift Measurement value */ - old_m = ch->adpcmx/*adpcmm*/; - /* ch->adpcmm = Limit( ch->adpcmx + (decode_tableB3[data] * ch->adpcmd / 8) ,ADPCMB_DECODE_MAX, ADPCMB_DECODE_MIN ); */ - /* Forecast to next Forecast */ - ch->adpcmx = Limit( ch->adpcmx+(decode_tableB1[data] * ch->adpcmd / 8) ,ADPCMB_DECODE_MAX, ADPCMB_DECODE_MIN ); - /* delta to next delta */ - ch->adpcmd = Limit( ( ch->adpcmd * decode_tableB2[data] ) / 64, ADPCMB_DELTA_MAX, ADPCMB_DELTA_MIN ); - /* shift leveling value */ - delta_next = ch->adpcmx/*adpcmm*/ - old_m; - now_leveling = ch->next_leveling; - ch->next_leveling = old_m + (delta_next / 2); - }while(--step); -/*#define CUT_RE_SAMPLING */ -#ifdef CUT_RE_SAMPLING - ch->adpcml = ch->next_leveling * ch->volume; - ch->adpcml = ch->adpcmx/*adpcmm*/ * ch->volume; - } -#else - /* delta step of re-sampling */ - ch->sample_step = (ch->next_leveling - now_leveling) * ch->volume_w_step; - /* output of start point */ - ch->adpcml = now_leveling * ch->volume; - /* adjust to now */ - ch->adpcml += (int)((double)ch->sample_step * ((double)ch->now_step/(double)ch->step)); - } - ch->adpcml += ch->sample_step; -#endif - /* output for work of output channels (outd[OPNxxxx])*/ - /**(ch->pan) += ch->adpcml; */ - *(ch->pan) += ch->adpcml; + /* output for work of output channels (out_adpcm[OPNxxxx])*/ + *(ch->pan) += ch->adpcm_out; } -static YM2610 *FM2610=NULL; /* array of YM2610's */ - /* ADPCM type A */ static void FM_ADPCMAWrite(YM2610 *F2610,int r,int v) { - ADPCM_CH *adpcm = F2610->adpcm; - unsigned char c = r&0x07; + ADPCM_CH *adpcm = F2610->adpcm; + UINT8 c = r&0x07; - F2610->adpcmreg[1][r] = v&0xff; /* stock data */ - switch( r ){ - case 0x00: /* DM,--,C5,C4,C3,C2,C1,C0 */ - F2610->port1state = v&0xff; - if( !(v&0x80) ){ - /* KEY ON */ - for( c = 0; c < 6; c++ ){ - if( (1<OPN.ST.freqbase)/4096.0/3.0); - adpcm[c].now_addr = adpcm[c].start<<1; - adpcm[c].now_step = (1<pcmbuf[1]==NULL){ /* Check ROM Mapped */ -#ifdef __RAINE__ - PrintDebug("YM2610: main adpcm rom not mapped\n"); -#else - Log(LOG_WAR,"YM2610: Attempting to play regular adpcm but no rom is mapped\n"); -#endif - adpcm[c].flag = 0; - } else{ - if(adpcm[c].end >= F2610->pcm_size[1]){ /* Check End in Range */ -#ifdef __RAINE__ - PrintDebug("YM2610: main adpcm end out of range: $%08x\n",adpcm[c].end); -#endif - adpcm[c].end = F2610->pcm_size[1]-1; - } - if(adpcm[c].start >= F2610->pcm_size[1]){ /* Check Start in Range */ -#ifdef __RAINE__ - PrintDebug("YM2610: main adpcm start out of range: $%08x\n",adpcm[c].start); -#endif - adpcm[c].flag = 0; - } - } - /*** (1<TL_adpcmb = &(TL_TABLE[((v&0x3f)^0x3f)*(int)(0.75/EG_STEP)]); - for( c = 0; c < 6; c++ ){ - adpcm[c].volume = F2610->TL_adpcmb[adpcm[c].IL*(int)(0.75/EG_STEP)] / ADPCMA_DECODE_RANGE / ADPCMA_VOLUME_DIV; - /**** calc pcm * volume data ****/ - adpcm[c].adpcml = adpcm[c].adpcmx * adpcm[c].volume; - } - break; - default: - c = r&0x07; - if( c >= 0x06 ) return; - switch( r&0x38 ){ - case 0x08: /* B7=L,B6=R,B4-0=IL */ - adpcm[c].IL = (v&0x1f)^0x1f; - adpcm[c].volume = F2610->TL_adpcmb[adpcm[c].IL*(int)(0.75/EG_STEP)] / ADPCMA_DECODE_RANGE / ADPCMA_VOLUME_DIV; - adpcm[c].pan = &outd[(v>>6)&0x03]; - /**** calc pcm * volume data ****/ - adpcm[c].adpcml = adpcm[c].adpcmx * adpcm[c].volume; - break; - case 0x10: - case 0x18: - adpcm[c].start = ( (F2610->adpcmreg[1][0x18 + c]*0x0100 | F2610->adpcmreg[1][0x10 + c]) << F2610->port1shift); - break; - case 0x20: - case 0x28: - adpcm[c].end = ( (F2610->adpcmreg[1][0x28 + c]*0x0100 | F2610->adpcmreg[1][0x20 + c]) << F2610->port1shift); - adpcm[c].end += (1<port1shift) - 1; - break; - } - } + F2610->adpcmreg[r] = v&0xff; /* stock data */ + switch( r ){ + case 0x00: /* DM,--,C5,C4,C3,C2,C1,C0 */ + /* F2610->port1state = v&0xff; */ + if( !(v&0x80) ){ + /* KEY ON */ + for( c = 0; c < 6; c++ ){ + if( (1<OPN.ST.freqbase)/3.0); + 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; + if(F2610->pcmbuf==NULL){ /* Check ROM Mapped */ + LOG(LOG_WAR,("YM2610: ADPCM-A rom not mapped\n")); + adpcm[c].flag = 0; + } else{ + if(adpcm[c].end >= F2610->pcm_size){ /* Check End in Range */ + LOG(LOG_WAR,("YM2610: ADPCM-A end out of range: $%08x\n",adpcm[c].end)); + /*adpcm[c].end = F2610->pcm_size-1;*/ /* JB: DO NOT uncomment this, otherwise you will break the comparison in the ADPCM_CALC_CHA() */ + } + if(adpcm[c].start >= F2610->pcm_size) /* Check Start in Range */ + { + LOG(LOG_WAR,("YM2610: ADPCM-A start out of range: $%08x\n",adpcm[c].start)); + adpcm[c].flag = 0; + } + } + } /*** (1<adpcmTL = (v & 0x3f) ^ 0x3f; + for( c = 0; c < 6; c++ ) + { + int volume = F2610->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 = F2610->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 = &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 = ( (F2610->adpcmreg[0x18 + c]*0x0100 | F2610->adpcmreg[0x10 + c]) << ADPCMA_ADDRESS_SHIFT); + break; + case 0x20: + case 0x28: + adpcm[c].end = ( (F2610->adpcmreg[0x28 + c]*0x0100 | F2610->adpcmreg[0x20 + c]) << ADPCMA_ADDRESS_SHIFT); + adpcm[c].end += (1<flag , 1); + state_save_register_UINT8 (state_name, num, "data" , &adpcm->now_data , 1); + state_save_register_UINT32(state_name, num, "addr" , &adpcm->now_addr , 1); + state_save_register_UINT32(state_name, num, "step" , &adpcm->now_step , 1); + state_save_register_INT32 (state_name, num, "a_acc" , &adpcm->adpcm_acc , 1); + state_save_register_INT32 (state_name, num, "a_step" , &adpcm->adpcm_step, 1); + state_save_register_INT32 (state_name, num, "a_out" , &adpcm->adpcm_out , 1); + } } +#endif /* _STATE_H */ -/* ADPCM type B (DELTA-T) */ -static void FM_ADPCMBWrite(YM2610 *F2610,int r,int v) -{ - ADPCM_CH *adpcm = &(F2610->adpcm[6]); - - F2610->adpcmreg[0][r] = v&0xff; /* stock data */ - switch( r ){ - case 0x00: /* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */ -#if 0 - case 0x60: /* write buffer MEMORY from PCM data port */ - case 0x20: /* read buffer MEMORY to PCM data port */ -#endif - if( v&0x80 ){ - F2610->port0state = v&0x90; /* start req,memory mode,repeat flag copy */ - /**** start ADPCM ****/ - adpcm->volume_w_step = (double)adpcm->volume * adpcm->step / (1<now_addr = (adpcm->start)<<1; - adpcm->now_step = (1<step; - /*adpcm->adpcmm = 0;*/ - adpcm->adpcmx = 0; - adpcm->adpcml = 0; - adpcm->adpcmd = ADPCMB_DELTA_DEF; - adpcm->next_leveling=0; - adpcm->flag = 1; /* start ADPCM */ - if( !adpcm->step ){ - adpcm->flag = 0; - F2610->port0state = 0x00; - } - /**** PCMROM check & limit check ****/ - if(F2610->pcmbuf[0] == NULL){ /* Check ROM Mapped */ -#ifdef __RAINE__ - PrintDebug("YM2610: Delta-T adpcm rom not mapped\n"); -#endif - adpcm->flag = 0; - F2610->port0state = 0x00; - } else{ - if( adpcm->end >= F2610->pcm_size[0] ){ /* Check End in Range */ -#ifdef __RAINE__ - PrintDebug("YM2610: Delta-T adpcm end out of range: $%08x\n",adpcm->end); -#endif - adpcm->end = F2610->pcm_size[0] - 1; - } - if( adpcm->start >= F2610->pcm_size[0] ){ /* Check Start in Range */ -#ifdef __RAINE__ - PrintDebug("YM2610: Delta-T adpcm start out of range: $%08x\n",adpcm->start); -#endif - adpcm->flag = 0; - F2610->port0state = 0x00; - } - } - } else if( v&0x01 ){ - adpcm->flag = 0; - F2610->port0state = 0x00; - } - break; - case 0x01: /* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */ - F2610->port0control = v&0xff; - adpcm->pan = &outd[(v>>6)&0x03]; - break; - case 0x02: /* Start Address L */ - case 0x03: /* Start Address H */ - adpcm->start = (F2610->adpcmreg[0][0x3]*0x0100 | F2610->adpcmreg[0][0x2]) << F2610->port0shift; - break; - case 0x04: /* Stop Address L */ - case 0x05: /* Stop Address H */ - adpcm->end = (F2610->adpcmreg[0][0x5]*0x0100 | F2610->adpcmreg[0][0x4]) << F2610->port0shift; - adpcm->end += (1<port0shift) - 1; - break; - case 0x06: /* Prescale L (PCM and Recoard frq) */ - case 0x07: /* Proscale H */ - case 0x08: /* ADPCM data */ - break; - case 0x09: /* DELTA-N L (ADPCM Playback Prescaler) */ - case 0x0a: /* DELTA-N H */ - adpcm->delta = (F2610->adpcmreg[0][0xa]*0x0100 | F2610->adpcmreg[0][0x9]); - adpcm->step = (unsigned int)((float)(adpcm->delta*(1<<(ADPCM_SHIFT-16)))*((float)F2610->OPN.ST.freqbase)/4096.0); - adpcm->volume_w_step = (double)adpcm->volume * adpcm->step / (1<volume; - adpcm->volume = ((v&0xff)<<(TL_BITS-8)) * ADPCMB_VOLUME_RATE / ADPCMB_DECODE_RANGE; - if( oldvol != 0 ) - { - adpcm->adpcml = (int)((double)adpcm->adpcml / (double)oldvol * (double)adpcm->volume); - adpcm->sample_step = (int)((double)adpcm->sample_step / (double)oldvol * (double)adpcm->volume); - } - adpcm->volume_w_step = (int)((double)adpcm->volume * (double)adpcm->step / (double)(1<ADMode & 0x20 ) - { /* buffer memory */ - /* F2203->OPN.ST.status |= 0x04; */ - return 0; - } - else - { /* from PCM data register */ - FM_STATUS_SET(F2608->OPN.ST,0x08); /* BRDY = 1 */ - return F2608->ADData; - } + YM2608 *F2608 = &(FM2608[n]); + if( F2608->ADMode & 0x20 ) + { /* buffer memory */ + /* F2203->OPN.ST.status |= 0x04; */ + return 0; + } + else + { /* from PCM data register */ + FM_STATUS_SET(F2608->OPN.ST,0x08); /* BRDY = 1 */ + return F2608->ADData; + } } /* Put decoded data */ INLINE void YM2608WriteADPCM(int n,int v) { - YM2608 *F2608 = &(FM2608[n]); - if( F2608->ADMode & 0x20 ) - { /* for buffer */ - return; - } - else - { /* for PCM data port */ - F2608->ADData = v; - FM_STATUS_SET(F2608->OPN.ST,0x08) /* BRDY = 1 */ - } + YM2608 *F2608 = &(FM2608[n]); + if( F2608->ADMode & 0x20 ) + { /* for buffer */ + return; + } + else + { /* for PCM data port */ + F2608->ADData = v; + FM_STATUS_SET(F2608->OPN.ST,0x08) /* BRDY = 1 */ + } } #endif /* ---------- IRQ flag Controll Write 0x110 ---------- */ INLINE void YM2608IRQFlagWrite(FM_ST *ST,int n,int v) { - if( v & 0x80 ) - { /* Reset IRQ flag */ - FM_STATUS_RESET(ST,0xff); - } - else - { /* Set IRQ mask */ - /* !!!!!!!!!! pending !!!!!!!!!! */ - /* F2610->adpcm_statusmask = v & 0x1f; */ - } + if( v & 0x80 ) + { /* Reset IRQ flag */ + FM_STATUS_RESET(ST,0xff); + } + else + { /* Set IRQ mask */ + /* !!!!!!!!!! pending !!!!!!!!!! */ + } +} + +/* ---------- compatible mode & IRQ flag Controll Write 0x29 ---------- */ +void YM2608IRQMaskWrite(FM_OPN *OPN,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; + else OPN->type &= ~TYPE_6CH; + /* IRQ MASK */ + FM_IRQMASK_SET(&OPN->ST,v&0x1f); } #ifdef YM2608_RHYTHM_PCM /**** RYTHM (PCM) ****/ -INLINE void YM2608_RYTHM( YM2610 *F2610, ADPCM_CH *ch ) +INLINE void YM2608_RYTHM( YM2608 *F2608, ADPCM_CH *ch ) { - unsigned int step; - int data; + UINT32 step; - ch->now_step += ch->step; - if ( ch->now_step >= (1<now_step >> ADPCM_SHIFT; - ch->now_step &= (1<now_addr+step) > (ch->end<<1) ) { - ch->flag = 0; - F2610->adpcm_arrivedEndAddress |= ch->flagMask & F2610->adpcm_statusmask; - return; - } - do{ - /* get a next pcm data */ - ch->adpcmx = ((short *)pcmbufA)[ch->now_addr]; - ch->now_addr++; - /**** calc pcm * volume data ****/ - ch->adpcml = ch->adpcmx * ch->volume; - }while(--step); - } - /* output for work of output channels (outd[OPNxxxx])*/ - *(ch->pan) += ch->adpcml; + ch->now_step += ch->step; + if ( ch->now_step >= (1<now_step >> ADPCM_SHIFT; + ch->now_step &= (1<now_addr+step) > (ch->end<<1) ) { /*most likely this comparison is wrong */ + ch->flag = 0; + F2608->adpcm_arrivedEndAddress |= ch->flagMask; + return; + } + do{ + /* get a next pcm data */ + ch->adpcm_acc = ((short *)pcmbufA)[ch->now_addr]; + ch->now_addr++; + }while(--step); + /**** calc pcm * volume data ****/ + ch->adpcm_out = (ch->adpcm_acc * ch->vol_mul ) >> ch->vol_shift; + } + /* output for work of output channels (out_adpcm[OPNxxxx])*/ + *(ch->pan) += ch->adpcm_out; } #endif /* YM2608_RHYTHM_PCM */ /* ---------- update one of chip ----------- */ -void YM2608UpdateOne(int num, void **buffer, int length) +void YM2608UpdateOne(int num, INT16 **buffer, int length) { - YM2608 *F2608 = &(FM2608[num]); - FM_OPN *OPN = &(FM2608[num].OPN); - int dataR,dataL; - int i,j,ch; - - /* set bufer */ - bufL = (FMSAMPLE *)buffer[0]; - bufR = (FMSAMPLE *)buffer[1]; - - if( (void *)F2608 != cur_chip ){ - cur_chip = (void *)F2608; - - State = &OPN->ST; - 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]; - /* setup adpcm rom address */ - pcmbufB = F2608->pcmbuf[0]; - pcmsizeB = F2608->pcm_size[0]; - pcmbufA = F2608->pcmbuf[1]; - pcmsizeA = F2608->pcm_size[1]; - } - /* update frequency counter */ - CALC_FCOUNT( cch[0] ); - CALC_FCOUNT( cch[1] ); - if( (State->mode & 0xc0) ){ - /* 3SLOT MODE */ - if( cch[2]->SLOT[SLOT1].Incr==-1){ - /* 3 slot mode */ - CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); - } - }else CALC_FCOUNT( cch[2] ); - CALC_FCOUNT( cch[3] ); - CALC_FCOUNT( cch[4] ); - CALC_FCOUNT( cch[5] ); - /* buffering */ + YM2608 *F2608 = &(FM2608[num]); + FM_OPN *OPN = &(FM2608[num].OPN); + YM_DELTAT *DELTAT = &(F2608[num].deltaT); + int i,j; + FMSAMPLE *bufL,*bufR; + + /* setup DELTA-T unit */ + YM_DELTAT_DECODE_PRESET(DELTAT); + + /* set bufer */ + bufL = buffer[0]; + bufR = buffer[1]; + + if( (void *)F2608 != cur_chip ){ + cur_chip = (void *)F2608; + + State = &OPN->ST; + 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]; + /* setup adpcm rom address */ + pcmbufA = F2608->pcmbuf; + pcmsizeA = F2608->pcm_size; + + LFOCnt = OPN->LFOCnt; + LFOIncr = OPN->LFOIncr; + if( !LFOIncr ) lfo_amd = lfo_pmd = 0; + } + /* update frequency counter */ + OPN_CALC_FCOUNT( cch[0] ); + OPN_CALC_FCOUNT( cch[1] ); + if( (State->mode & 0xc0) ){ + /* 3SLOT MODE */ + if( cch[2]->SLOT[SLOT1].Incr==-1){ + /* 3 slot mode */ + CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); + } + }else OPN_CALC_FCOUNT( cch[2] ); + OPN_CALC_FCOUNT( cch[3] ); + OPN_CALC_FCOUNT( cch[4] ); + OPN_CALC_FCOUNT( cch[5] ); + /* buffering */ for( i=0; i < length ; i++ ) - { - /* clear output acc. */ - outd[OPN_LEFT] = outd[OPN_RIGHT]= outd[OPN_CENTER] = 0; - /**** deltaT ADPCM ****/ - if( F2608->adpcm[6].flag ) - OPNB_ADPCM_CALC_CHB( F2608, &F2608->adpcm[6]); - /* FM */ - FM_CALC_CH( cch[0] ); - FM_CALC_CH( cch[1] ); - FM_CALC_CH( cch[2] ); - FM_CALC_CH( cch[3] ); - FM_CALC_CH( cch[4] ); - FM_CALC_CH( cch[5] ); - for( j = 0; j < 6; j++ ) - { - /**** ADPCM ****/ - if( F2608->adpcm[j].flag ) + { + /* LFO */ + if( LFOIncr ) + { + lfo_amd = OPN_LFO_wave[(LFOCnt+=LFOIncr)>>LFO_SH]; + lfo_pmd = lfo_amd-(LFO_RATE/2); + } + + /* clear output acc. */ + out_adpcm[OUTD_LEFT] = out_adpcm[OUTD_RIGHT]= out_adpcm[OUTD_CENTER] = 0; + out_delta[OUTD_LEFT] = out_delta[OUTD_RIGHT]= 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 */ + FM_CALC_CH( cch[0] ); + FM_CALC_CH( cch[1] ); + FM_CALC_CH( cch[2] ); + FM_CALC_CH( cch[3] ); + FM_CALC_CH( cch[4] ); + FM_CALC_CH( cch[5] ); + + /**** deltaT ADPCM ****/ + if( DELTAT->portstate ) + YM_DELTAT_ADPCM_CALC(DELTAT); + + for( j = 0; j < 6; j++ ) + { + /**** ADPCM ****/ + if( F2608->adpcm[j].flag ) #ifdef YM2608_RHYTHM_PCM - YM2608_RYTHM(F2608, &F2608->adpcm[j]); -#else - OPNB_ADPCM_CALC_CHA( F2608, &F2608->adpcm[j]); -#endif - } - /* get left & right output with clipping */ - dataL = Limit( outd[OPN_CENTER] + outd[OPN_LEFT], OPNB_MAXOUT, OPNB_MINOUT ); - dataR = Limit( outd[OPN_CENTER] + outd[OPN_RIGHT], OPNB_MAXOUT, OPNB_MINOUT ); - /* buffering */ - /* stereo separate */ -#ifdef FM_STEREO_MIX /* stereo mixing */ - /* stereo mix */ - ((FMSAMPLE_MIX *)bufL)[i] = ((dataL>>OPNB_OUTSB)<>OPNB_OUTSB); + YM2608_RYTHM(F2608, &F2608->adpcm[j]); #else - /* stereo separate */ - bufL[i] = dataL>>OPNB_OUTSB; - bufR[i] = dataR>>OPNB_OUTSB; + OPNB_ADPCM_CALC_CHA( F2608, &F2608->adpcm[j]); #endif + } -#ifdef LFO_SUPPORT - CALC_LOPM_LFO; -#endif -#ifdef INTERNAL_TIMER - /* timer controll */ - CALC_TIMER_A( State , cch[2] ); -#endif - } -#ifdef INTERNAL_TIMER - CALC_TIMER_B( State , length ); -#endif + /* buffering */ + { + int lt,rt; + + lt = out_adpcm[OUTD_LEFT] + out_adpcm[OUTD_CENTER]; + rt = out_adpcm[OUTD_RIGHT] + out_adpcm[OUTD_CENTER]; + lt += (out_delta[OUTD_LEFT] + out_delta[OUTD_CENTER])>>8; + rt += (out_delta[OUTD_RIGHT] + out_delta[OUTD_CENTER])>>8; + + lt += ((out_fm[0]>>0) & OPN->PAN[0]); /* we need to find real level on real chip */ + rt += ((out_fm[0]>>0) & OPN->PAN[1]); + lt += ((out_fm[1]>>0) & OPN->PAN[2]); + rt += ((out_fm[1]>>0) & OPN->PAN[3]); + lt += ((out_fm[2]>>0) & OPN->PAN[4]); + rt += ((out_fm[2]>>0) & OPN->PAN[5]); + lt += ((out_fm[3]>>0) & OPN->PAN[6]); + rt += ((out_fm[3]>>0) & OPN->PAN[7]); + lt += ((out_fm[4]>>0) & OPN->PAN[8]); + rt += ((out_fm[4]>>0) & OPN->PAN[9]); + lt += ((out_fm[5]>>0) & OPN->PAN[10]); + rt += ((out_fm[5]>>0) & OPN->PAN[11]); + + lt >>= FINAL_SH; + rt >>= FINAL_SH; + + Limit( lt, MAXOUT, MINOUT ); + Limit( rt, MAXOUT, MINOUT ); + /* buffering */ + bufL[i] = lt; + bufR[i] = rt; + } + + /* timer A controll */ + INTERNAL_TIMER_A( State , cch[2] ) + } + INTERNAL_TIMER_B(State,length) + /* check IRQ for DELTA-T arrived flag */ + FM_STATUS_SET(State, 0); + + OPN->LFOCnt = LFOCnt; + +} +#ifdef _STATE_H +static void YM2608_postload(void) +{ + int num , r; + + for(num=0;numOPN,1,2); + F2608->deltaT.freqbase = F2608->OPN.ST.freqbase; + /* IRQ mask / mode */ + YM2608IRQMaskWrite(&F2608->OPN,F2608->REGS[0x29]); + /* SSG registers */ + for(r=0;r<16;r++) + { + SSGWrite(num,0,r); + SSGWrite(num,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) */ + FM_ADPCMAWrite(F2608,1,F2608->REGS[0x111]); + for( r=0x08 ; r<0x0c ; r++) + FM_ADPCMAWrite(F2608,r,F2608->REGS[r+0x110]); + /* Delta-T ADPCM unit */ + YM_DELTAT_postload(&F2608->deltaT , &F2608->REGS[0x100] ); + } + cur_chip = NULL; +} + +static void YM2608_save_state(void) +{ + int num; + const char statename[] = "YM2608"; + + for(num=0;numREGS , 512); + FMsave_state_st(statename,num,&FM2608[num].OPN.ST); + FMsave_state_channel(statename,num,FM2608[num].CH,6); + /* 3slots */ + state_save_register_UINT32(statename, num, "slot3fc" , F2608->OPN.SL3.fc , 3); + state_save_register_UINT8 (statename, num, "slot3fh" , &F2608->OPN.SL3.fn_h , 1); + state_save_register_UINT8 (statename, num, "slot3kc" , F2608->OPN.SL3.kcode , 3); + /* address register1 */ + state_save_register_int (statename, num, "address1" , &F2608->address1); + /* rythm(ADPCMA) */ + FMsave_state_adpcma(statename,num,F2608->adpcm); + /* Delta-T ADPCM unit */ + YM_DELTAT_savestate(statename,num,&FM2608[num].deltaT); + } + state_save_register_func_postload(YM2608_postload); } +#endif /* _STATE_H */ /* -------------------------- YM2608(OPNA) ---------------------------------- */ int YM2608Init(int num, int clock, int rate, - void **pcmroma,int *pcmsizea,short *rhythmrom,int *rhythmpos, + void **pcmrom,int *pcmsize,short *rhythmrom,int *rhythmpos, FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler) { - int i,j; + int i,j; - if (FM2608) return (-1); /* duplicate init. */ - cur_chip = NULL; /* hiro-shi!! */ + if (FM2608) return (-1); /* duplicate init. */ + cur_chip = NULL; /* hiro-shi!! */ - FMNumChips = num; + YM2608NumChips = num; - /* allocate extend state space */ - if( (FM2608 = (YM2608 *)malloc(sizeof(YM2608) * FMNumChips))==NULL) - return (-1); - /* clear */ - memset(FM2608,0,sizeof(YM2608) * FMNumChips); - /* allocate total level table (128kb space) */ - if( !FMInitTable() ) - { - free( FM2608 ); - return (-1); - } - - for ( i = 0 ; i < FMNumChips; i++ ) { - FM2608[i].OPN.ST.index = i; - FM2608[i].OPN.type = TYPE_YM2608; - FM2608[i].OPN.P_CH = FM2608[i].CH; - FM2608[i].OPN.ST.clock = clock; - FM2608[i].OPN.ST.rate = rate; - /* FM2608[i].OPN.ST.irq = 0; */ - /* FM2608[i].OPN.ST.status = 0; */ - FM2608[i].OPN.ST.timermodel = FM_TIMER_SINGLE; - /* Extend handler */ - FM2608[i].OPN.ST.Timer_Handler = TimerHandler; - FM2608[i].OPN.ST.IRQ_Handler = IRQHandler; - /* ADPCM */ - FM2608[i].pcmbuf[0] = (char *)(pcmroma[i]); - FM2608[i].pcm_size[0] = pcmsizea[i]; - FM2608[i].pcmbuf[1] = (char *)rhythmrom; + /* allocate extend state space */ + if( (FM2608 = (YM2608 *)malloc(sizeof(YM2608) * YM2608NumChips))==NULL) + return (-1); + /* clear */ + memset(FM2608,0,sizeof(YM2608) * YM2608NumChips); + /* allocate total level table (128kb space) */ + if( !OPNInitTable() ) + { + free( FM2608 ); + return (-1); + } + + for ( i = 0 ; i < YM2608NumChips; i++ ) { + FM2608[i].OPN.ST.index = i; + FM2608[i].OPN.type = TYPE_YM2608; + FM2608[i].OPN.P_CH = FM2608[i].CH; + FM2608[i].OPN.ST.clock = clock; + FM2608[i].OPN.ST.rate = rate; + /* FM2608[i].OPN.ST.irq = 0; */ + /* FM2608[i].OPN.ST.status = 0; */ + FM2608[i].OPN.ST.timermodel = FM_TIMER_INTERVAL; + /* Extend handler */ + FM2608[i].OPN.ST.Timer_Handler = TimerHandler; + FM2608[i].OPN.ST.IRQ_Handler = IRQHandler; + /* DELTA-T */ + FM2608[i].deltaT.memory = (UINT8 *)(pcmrom[i]); + FM2608[i].deltaT.memory_size = pcmsize[i]; + FM2608[i].deltaT.arrivedFlagPtr = &FM2608[i].OPN.ST.status; + FM2608[i].deltaT.flagMask = 0x04; /* status flag.bit3 */ + /* ADPCM(Rythm) */ + FM2608[i].pcmbuf = (UINT8 *)rhythmrom; #ifdef YM2608_RHYTHM_PCM - /* rhythm sound setup (PCM) */ - for(j=0;j<6;j++) - { - /* rhythm sound */ - FM2608[i].adpcm[j].start = rhythmpos[j]; - FM2608[i].adpcm[j].end = rhythmpos[j+1]-1; - } - FM2608[i].pcm_size[1] = rhythmpos[6]; + /* rhythm sound setup (PCM) */ + for(j=0;j<6;j++) + { + /* rhythm sound */ + FM2608[i].adpcm[j].start = rhythmpos[j]; + FM2608[i].adpcm[j].end = rhythmpos[j+1]-1; + } + FM2608[i].pcm_size = rhythmpos[6]; #else - /* rhythm sound setup (ADPCM) */ - FM2608[i].pcm_size[1] = rhythmsize; + /* rhythm sound setup (ADPCM) */ + FM2608[i].pcm_size = rhythmsize; #endif - YM2608ResetChip(i); - } - InitOPNB_ADPCMATable(); - return 0; + YM2608ResetChip(i); + } + InitOPNB_ADPCMATable(); +#ifdef _STATE_H + YM2608_save_state(); +#endif + return 0; } -/* ---------- shut down emurator ----------- */ +/* ---------- shut down emulator ----------- */ void YM2608Shutdown() { if (!FM2608) return; - FMCloseTable(); - free(FM2608); - FM2608 = NULL; + FMCloseTable(); + free(FM2608); + FM2608 = NULL; } -/* ---------- reset one of chip ---------- */ +/* ---------- reset one of chips ---------- */ void YM2608ResetChip(int num) { - int i; - YM2608 *F2608 = &(FM2608[num]); - FM_OPN *OPN = &(FM2608[num].OPN); - - /* Reset Priscaler */ - OPNSetPris( OPN, 6*24, 6*24,4*2); /* OPN 1/6 , SSG 1/4 */ - /* reset SSG section */ - SSGReset(OPN->ST.index); - /* status clear */ - FM_IRQMASK_SET(&OPN->ST,0x1f); - OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ - - /* extend 3ch. disable */ - /*OPN->type &= (~TYPE_6CH); */ - - reset_channel( &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); - /* reset ADPCM unit */ - /**** ADPCM work initial ****/ - for( i = 0; i < 6+1; i++ ){ - F2608->adpcm[i].now_addr = 0; - F2608->adpcm[i].now_step = 0; - F2608->adpcm[i].step = 0; - F2608->adpcm[i].start = 0; - F2608->adpcm[i].end = 0; - /* F2608->adpcm[i].delta = 21866; */ - F2608->adpcm[i].volume = 0; - F2608->adpcm[i].pan = &outd[OPN_CENTER]; /* default center */ - F2608->adpcm[i].flagMask = (i == 6) ? 0x20 : 0; - F2608->adpcm[i].flag = 0; - F2608->adpcm[i].adpcmx = 0; - F2608->adpcm[i].adpcmd = 127; - F2608->adpcm[i].adpcml = 0; - /* DELTA-T */ - /*F2608->adpcm[i].adpcmm = 0;*/ - F2608->adpcm[i].volume_w_step = 0; - F2608->adpcm[i].next_leveling=0; - } - F2608->TL_adpcmb = &(TL_TABLE[0x3f*(int)(0.75/EG_STEP)]); - F2608->port0state = 0; - F2608->port0shift = 8; /* allways 8bits shift */ - /*F2608->port1state = 0; */ - F2608->port1state = -1; - F2608->port1shift = 8; /* allways 8bits shift */ - F2608->adpcm_arrivedEndAddress = 0; /* don't used */ - F2608->adpcm_statusmask = 0xbf; /* don't used */ + int i; + YM2608 *F2608 = &(FM2608[num]); + FM_OPN *OPN = &(FM2608[num].OPN); + YM_DELTAT *DELTAT = &(F2608[num].deltaT); + + /* Reset Prescaler */ + OPNPrescaler_w(OPN , 0 , 2); + F2608->deltaT.freqbase = OPN->ST.freqbase; + /* reset SSG section */ + SSGReset(OPN->ST.index); + /* status clear */ + FM_IRQMASK_SET(&OPN->ST,0x1f); + FM_BUSY_CLEAR(&OPN->ST); + OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ + + /* extend 3ch. disable */ + /*OPN->type &= (~TYPE_6CH);*/ + + reset_channel( &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); + /* reset ADPCM unit */ + /**** ADPCM work initial ****/ + for( i = 0; i < 6; i++ ){ //this was i < 6+1 which must be a bug ??? + F2608->adpcm[i].now_addr = 0; + F2608->adpcm[i].now_step = 0; + F2608->adpcm[i].step = 0; + F2608->adpcm[i].start = 0; + F2608->adpcm[i].end = 0; + /* F2608->adpcm[i].delta = 21866; */ + F2608->adpcm[i].vol_mul = 0; + F2608->adpcm[i].pan = &out_adpcm[OUTD_CENTER]; /* default center */ + F2608->adpcm[i].flagMask = 0; //(i == 6) ? 0x20 : 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->port1state = -1; */ + F2608->adpcm_arrivedEndAddress = 0; /* don't used */ + + /* DELTA-T unit */ + DELTAT->freqbase = OPN->ST.freqbase; + DELTAT->output_pointer = out_delta; + DELTAT->portshift = 5; /* allways 5bits shift */ /* ASG */ + DELTAT->output_range = 1<<23; + YM_DELTAT_ADPCM_Reset(DELTAT,OUTD_CENTER); } /* YM2608 write */ /* n = number */ /* a = address */ /* v = value */ -int YM2608Write(int n, int a,int v) +int YM2608Write(int n, int a,UINT8 v) { - YM2608 *F2608 = &(FM2608[n]); - FM_OPN *OPN = &(FM2608[n].OPN); - int addr; - - switch(a&3){ - case 0: /* address port 0 */ - OPN->ST.address = v & 0xff; - /* Write register to SSG emurator */ - if( v < 16 ) SSGWrite(n,0,v); - switch(OPN->ST.address) - { - case 0x2d: /* divider sel */ - OPNSetPris( OPN, 6*24, 6*24, 4*2); /* OPN 1/6 , SSG 1/4 */ - break; - case 0x2e: /* divider sel */ - OPNSetPris( OPN, 3*24, 3*24,2*2); /* OPN 1/3 , SSG 1/2 */ - break; - case 0x2f: /* divider sel */ - OPNSetPris( OPN, 2*24, 2*24,1*2); /* OPN 1/2 , SSG 1/1 */ - break; - } - break; - case 1: /* data port 0 */ - addr = OPN->ST.address; - switch(addr & 0xf0) - { - case 0x00: /* SSG section */ - /* Write data to SSG emurator */ - SSGWrite(n,a,v); - break; - case 0x10: /* 0x10-0x1f : Rhythm section */ - YM2608UpdateReq(n); - FM_ADPCMAWrite(F2608,addr-0x10,v); - break; - case 0x20: /* Mode Register */ - switch(addr) - { - case 0x29: /* SCH,xirq mask */ - /* SCH,xx,xxx,EN_ZERO,EN_BRDY,EN_EOS,EN_TB,EN_TA */ - /* extend 3ch. enable/disable */ - if(v&0x80) OPN->type |= TYPE_6CH; - else OPN->type &= ~TYPE_6CH; - /* IRQ MASK */ - FM_IRQMASK_SET(&OPN->ST,v&0x1f); - break; - default: - YM2608UpdateReq(n); - OPNWriteMode(OPN,addr,v); - } - break; - default: /* OPN section */ - YM2608UpdateReq(n); - OPNWriteReg(OPN,addr,v); - } - break; - case 2: /* address port 1 */ - F2608->address1 = v & 0xff; - break; - case 3: /* data port 1 */ - addr = F2608->address1; - YM2608UpdateReq(n); - switch( addr & 0xf0 ) - { - case 0x00: /* ADPCM PORT */ - switch( addr ) - { - case 0x0c: /* Limit address L */ - /*F2608->ADLimit = (F2608->ADLimit & 0xff00) | v; */ - /*break; */ - case 0x0d: /* Limit address H */ - /*F2608->ADLimit = (F2608->ADLimit & 0x00ff) | (v<<8); */ - /*break; */ - case 0x0e: /* DAC data */ - /*break; */ - case 0x0f: /* PCM data port */ - /*F2608->ADData = v; */ - /*FM_STATUS_RESET(F2608->OPN.ST,0x08); */ - break; - default: - /* 0x00-0x0b */ - FM_ADPCMBWrite(F2608,addr,v); - } - break; - case 0x10: /* IRQ Flag controll */ - if( addr == 0x10 ) - YM2608IRQFlagWrite(&(OPN->ST),n,v); - break; - default: - OPNWriteReg(OPN,addr|0x100,v); - } - } - return OPN->ST.irq; -} -unsigned char YM2608Read(int n,int a) -{ - YM2608 *F2608 = &(FM2608[n]); - int addr = F2608->OPN.ST.address; - int ret = 0; - - switch( a&3 ){ - case 0: /* status 0 : YM2203 compatible */ - /* BUSY:x:x:x:x:x:FLAGB:FLAGA */ - if(addr==0xff) ret = 0x00; /* ID code */ - else ret = F2608->OPN.ST.status & 0x83; - break; - case 1: /* status 0 */ - if( addr < 16 ) ret = SSGRead(n); - break; - case 2: /* status 1 : + ADPCM status */ - /* BUSY:x:PCMBUSY:ZERO:BRDY:EOS:FLAGB:FLAGA */ - if(addr==0xff) ret = 0x00; /* ID code */ - else ret = F2608->OPN.ST.status | (F2608->adpcm[6].flag ? 0x20 : 0); - break; - case 3: - ret = 0; - break; - } - return ret; + YM2608 *F2608 = &(FM2608[n]); + FM_OPN *OPN = &(FM2608[n].OPN); + int addr; + + switch(a&3){ + case 0: /* address port 0 */ + OPN->ST.address = (v &= 0xff); + /* Write register to SSG emulator */ + if( v < 16 ) SSGWrite(n,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 */ + addr = OPN->ST.address; +#ifdef _STATE_H + F2608->REGS[addr] = v; +#endif + switch(addr & 0xf0) + { + case 0x00: /* SSG section */ + /* Write data to SSG emulator */ + SSGWrite(n,a,v); + break; + case 0x10: /* 0x10-0x1f : Rhythm section */ + YM2608UpdateReq(n); + FM_ADPCMAWrite(F2608,addr-0x10,v); + break; + case 0x20: /* Mode Register */ + switch(addr) + { + case 0x29: /* SCH,xirq mask */ + YM2608IRQMaskWrite(OPN,v); + break; + default: + YM2608UpdateReq(n); + OPNWriteMode(OPN,addr,v); + } + break; + default: /* OPN section */ + YM2608UpdateReq(n); + OPNWriteReg(OPN,addr,v); + } + break; + case 2: /* address port 1 */ + F2608->address1 = v & 0xff; + break; + case 3: /* data port 1 */ + addr = F2608->address1; +#ifdef _STATE_H + F2608->REGS[addr+0x100] = v; +#endif + YM2608UpdateReq(n); + switch( addr & 0xf0 ) + { + case 0x00: /* DELTAT PORT */ + switch( addr ) + { + case 0x0c: /* Limit address L */ + /*F2608->ADLimit = (F2608->ADLimit & 0xff00) | v; */ + /*break;*/ + case 0x0d: /* Limit address H */ + /*F2608->ADLimit = (F2608->ADLimit & 0x00ff) | (v<<8);*/ + /*break;*/ + case 0x0e: /* DAC data */ + /*break;*/ + case 0x0f: /* PCM data port */ + /*F2608->ADData = v;*/ + /*FM_STATUS_RESET(F2608->OPN.ST,0x08);*/ + break; + default: + /* 0x00-0x0b */ + YM_DELTAT_ADPCM_Write(&F2608->deltaT,addr,v); + } + break; + case 0x10: /* IRQ Flag controll */ + if( addr == 0x10 ) + YM2608IRQFlagWrite(&(OPN->ST),n,v); + break; + default: + OPNWriteReg(OPN,addr+0x100,v); + } + } + return OPN->ST.irq; +} +UINT8 YM2608Read(int n,int a) +{ + YM2608 *F2608 = &(FM2608[n]); + int addr = F2608->OPN.ST.address; + int ret = 0; + + switch( a&3 ){ + case 0: /* status 0 : YM2203 compatible */ + /* BUSY:x:x:x:x:x:FLAGB:FLAGA */ + if(addr==0xff) ret = 0x00; /* ID code */ + else ret = FM_STATUS_FLAG(&F2608->OPN.ST)&0x83; + break; + case 1: /* status 0 */ + if( addr < 16 ) ret = SSGRead(n); + break; + case 2: /* status 1 : + ADPCM status */ + /* BUSY:x:PCMBUSY:ZERO:BRDY:EOS:FLAGB:FLAGA */ + if(addr==0xff) ret = 0x00; /* ID code */ + else ret = FM_STATUS_FLAG(&F2608->OPN.ST) | (F2608->adpcm[6].flag ? 0x20 : 0); + break; + case 3: + ret = 0; + break; + } + return ret; } int YM2608TimerOver(int n,int c) { - YM2608 *F2608 = &(FM2608[n]); + YM2608 *F2608 = &(FM2608[n]); - if( c ) - { /* Timer B */ - TimerBOver( &(F2608->OPN.ST) ); - } - else - { /* Timer A */ - YM2608UpdateReq(n); - /* 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->CH[2]) ); - } - } - return FM2608->OPN.ST.irq; + if( c ) + { /* Timer B */ + TimerBOver( &(F2608->OPN.ST) ); + } + else + { /* Timer A */ + YM2608UpdateReq(n); + /* 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->CH[2]) ); + } + } + return FM2608->OPN.ST.irq; } -#if 0 -/* ---------- return the buffer ---------- */ -FMSAMPLE **YM2608Buffer(int n) -{ - return &(FM2608[n].Buf); -} -#endif - -#if 0 -/* ---------- set buffer ---------- */ -int YM2608SetBuffer(int n, FMSAMPLE **buf ) -{ - int i; - for( i = 0 ; i < YM2608_NUMBUF ; i++){ - FM2608[n].Buf[i] = buf[i]; - if( cur_chip == &FM2608[n] ) cur_chip = NULL; - } - return 0; -} -#endif - #endif /* BUILD_YM2608 */ -#if BUILD_YM2610 + +#if BUILD_OPNB /* -------------------------- YM2610(OPNB) ---------------------------------- */ -/*static YM2610 *FM2610=NULL; array of YM2610's */ +static YM2610 *FM2610=NULL; /* array of YM2610's */ +static int YM2610NumChips; /* total chip */ -/* ---------- update one of chip (YM2610B FM6: ADPCM-A6: ADPCM-B:1) ----------- */ -void YM2610UpdateOne(int num, void **buffer, int length) +/* ---------- update one of chip (YM2610 FM4: ADPCM-A6: ADPCM-B1) ----------- */ +void YM2610UpdateOne(int num, INT16 **buffer, int length) { - YM2610 *F2610 = &(FM2610[num]); - FM_OPN *OPN = &(FM2610[num].OPN); - static FMSAMPLE *buf[YM2610_NUMBUF]; - int dataR,dataL; - int i,j; - - /* buffer setup */ - bufL = (FMSAMPLE *)buffer[0]; - bufR = (FMSAMPLE *)buffer[1]; - - if( (void *)F2610 != cur_chip ){ - cur_chip = (void *)F2610; - State = &OPN->ST; - /*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]; - /* setup adpcm rom address */ - pcmbufB = F2610->pcmbuf[0]; - pcmsizeB = F2610->pcm_size[0]; - pcmbufA = F2610->pcmbuf[1]; - pcmsizeA = F2610->pcm_size[1]; - } + YM2610 *F2610 = &(FM2610[num]); + FM_OPN *OPN = &(FM2610[num].OPN); + YM_DELTAT *DELTAT = &(F2610[num].deltaT); + int i,j; + FMSAMPLE *bufL,*bufR; + + /* setup DELTA-T unit */ + YM_DELTAT_DECODE_PRESET(DELTAT); + + /* buffer setup */ + bufL = buffer[0]; + bufR = buffer[1]; + + if( (void *)F2610 != cur_chip ){ + cur_chip = (void *)F2610; + State = &OPN->ST; + cch[0] = &F2610->CH[1]; + cch[1] = &F2610->CH[2]; + cch[2] = &F2610->CH[4]; + cch[3] = &F2610->CH[5]; + /* setup adpcm rom address */ + pcmbufA = F2610->pcmbuf; + pcmsizeA = F2610->pcm_size; + + LFOCnt = OPN->LFOCnt; + LFOIncr = OPN->LFOIncr; + if( !LFOIncr ) lfo_amd = lfo_pmd = 0; + } #ifdef YM2610B_WARNING +#define FM_KEY_IS(SLOT) ((SLOT)->key) #define FM_MSG_YM2610B "YM2610-%d.CH%d is playing,Check whether the type of the chip is YM2610B\n" - /* Check YM2610B worning message */ - if(errorlog) - { - if( F2610->CH[0].SLOT[3].evm > ENV_MOD_OFF ) - Log(LOG_WAR,FM_MSG_YM2610B,num,0); - if( F2610->CH[3].SLOT[3].evm > ENV_MOD_OFF ) - Log(LOG_WAR,FM_MSG_YM2610B,num,3); - } -#endif - /* update frequency counter */ - /*CALC_FCOUNT( cch[0] ); */ - CALC_FCOUNT( cch[1] ); - if( (State->mode & 0xc0) ){ - /* 3SLOT MODE */ - if( cch[2]->SLOT[SLOT1].Incr==-1){ - /* 3 slot mode */ - CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); - } - }else CALC_FCOUNT( cch[2] ); - /*CALC_FCOUNT( cch[3] ); */ - CALC_FCOUNT( cch[4] ); - CALC_FCOUNT( cch[5] ); + /* Check YM2610B warning message */ + if( FM_KEY_IS(&F2610->CH[0].SLOT[3]) ) + LOG(LOG_WAR,(FM_MSG_YM2610B,num,0)); + if( FM_KEY_IS(&F2610->CH[3].SLOT[3]) ) + LOG(LOG_WAR,(FM_MSG_YM2610B,num,3)); +#endif + /* update frequency counter */ + OPN_CALC_FCOUNT( cch[0] ); + if( (State->mode & 0xc0) ){ + /* 3SLOT MODE */ + if( cch[1]->SLOT[SLOT1].Incr==-1){ + /* 3 slot mode */ + CALC_FCSLOT(&cch[1]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); + CALC_FCSLOT(&cch[1]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); + CALC_FCSLOT(&cch[1]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); + CALC_FCSLOT(&cch[1]->SLOT[SLOT4] , cch[1]->fc , cch[1]->kcode ); + } + }else OPN_CALC_FCOUNT( cch[1] ); + OPN_CALC_FCOUNT( cch[2] ); + OPN_CALC_FCOUNT( cch[3] ); - /* buffering */ + /* buffering */ for( i=0; i < length ; i++ ) - { - /* clear output acc. */ - outd[OPN_LEFT] = outd[OPN_RIGHT]= outd[OPN_CENTER] = 0; - /**** deltaT ADPCM ****/ - if( F2610->adpcm[6].flag ) - OPNB_ADPCM_CALC_CHB( F2610, &F2610->adpcm[6]); - /* FM */ - /*FM_CALC_CH( cch[0] ); */ - FM_CALC_CH( cch[1] ); - FM_CALC_CH( cch[2] ); - /*FM_CALC_CH( cch[3] ); */ - FM_CALC_CH( cch[4] ); - FM_CALC_CH( cch[5] ); - for( j = 0; j < 6; j++ ) - { - /**** ADPCM ****/ - if( F2610->adpcm[j].flag ) - OPNB_ADPCM_CALC_CHA( F2610, &F2610->adpcm[j]); - } - /* get left & right output with clipping */ - dataL = Limit( outd[OPN_CENTER] + outd[OPN_LEFT], OPNB_MAXOUT, OPNB_MINOUT ); - dataR = Limit( outd[OPN_CENTER] + outd[OPN_RIGHT], OPNB_MAXOUT, OPNB_MINOUT ); - /* buffering */ -#ifdef FM_STEREO_MIX /* stereo mixing */ - /* stereo mix */ - ((FMSAMPLE_MIX *)bufL)[i] = ((dataL>>OPNB_OUTSB)<>OPNB_OUTSB); -#else - /* stereo separate */ - bufL[i] = dataL>>OPNB_OUTSB; - bufR[i] = dataR>>OPNB_OUTSB; -#endif + { + /* LFO */ + if( LFOIncr ) + { + lfo_amd = OPN_LFO_wave[(LFOCnt+=LFOIncr)>>LFO_SH]; + lfo_pmd = lfo_amd-(LFO_RATE/2); + } + + /* clear output acc. */ + out_adpcm[OUTD_LEFT] = out_adpcm[OUTD_RIGHT]= out_adpcm[OUTD_CENTER] = 0; + out_delta[OUTD_LEFT] = out_delta[OUTD_RIGHT]= out_delta[OUTD_CENTER] = 0; + /* clear outputs */ + out_fm[1] = 0; + out_fm[2] = 0; + out_fm[4] = 0; + out_fm[5] = 0; + + /* calculate FM */ + FM_CALC_CH( cch[0] ); /*remapped to 1*/ + FM_CALC_CH( cch[1] ); /*remapped to 2*/ + FM_CALC_CH( cch[2] ); /*remapped to 4*/ + FM_CALC_CH( cch[3] ); /*remapped to 5*/ + + /**** deltaT ADPCM ****/ + if( DELTAT->portstate ) + YM_DELTAT_ADPCM_CALC(DELTAT); + + for( j = 0; j < 6; j++ ) + { + /* ADPCM */ + if( F2610->adpcm[j].flag ) + OPNB_ADPCM_CALC_CHA( F2610, &F2610->adpcm[j]); + } + + /* buffering */ + { + int lt,rt; + + lt = out_adpcm[OUTD_LEFT] + out_adpcm[OUTD_CENTER]; + rt = out_adpcm[OUTD_RIGHT] + out_adpcm[OUTD_CENTER]; + lt += (out_delta[OUTD_LEFT] + out_delta[OUTD_CENTER])>>9; + rt += (out_delta[OUTD_RIGHT] + 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( State , cch[1] ) + } + INTERNAL_TIMER_B(State,length) -#ifdef LFO_SUPPORT - CALC_LOPM_LFO; -#endif -#ifdef INTERNAL_TIMER - /* timer controll */ - CALC_TIMER_A( State , cch[2] ); -#endif - } -#ifdef INTERNAL_TIMER - CALC_TIMER_B( State , length ); -#endif + OPN->LFOCnt = LFOCnt; } -#endif /* BUILD_YM2610 */ +#endif /* BUILD_OPNB */ #if BUILD_YM2610B -/* ---------- update one of chip (YM2610B FM6: ADPCM-A6: ADPCM-B:1) ----------- */ -void YM2610BUpdateOne(int num, void **buffer, int length) +/* ---------- update one of chip (YM2610B FM6: ADPCM-A6: ADPCM-B1) ----------- */ +void YM2610BUpdateOne(int num, INT16 **buffer, int length) { - YM2610 *F2610 = &(FM2610[num]); - FM_OPN *OPN = &(FM2610[num].OPN); - static FMSAMPLE *buf[YM2610_NUMBUF]; - int dataR,dataL; - int i,j; - - /* buffer setup */ - bufL = (FMSAMPLE *)buffer[0]; - bufR = (FMSAMPLE *)buffer[1]; - - if( (void *)F2610 != cur_chip ){ - cur_chip = (void *)F2610; - State = &OPN->ST; - 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]; - /* setup adpcm rom address */ - pcmbufB = F2610->pcmbuf[0]; - pcmsizeB = F2610->pcm_size[0]; - pcmbufA = F2610->pcmbuf[1]; - pcmsizeA = F2610->pcm_size[1]; - } - - /* update frequency counter */ - CALC_FCOUNT( cch[0] ); - CALC_FCOUNT( cch[1] ); - if( (State->mode & 0xc0) ){ - /* 3SLOT MODE */ - if( cch[2]->SLOT[SLOT1].Incr==-1){ - /* 3 slot mode */ - CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); - } - }else CALC_FCOUNT( cch[2] ); - CALC_FCOUNT( cch[3] ); - CALC_FCOUNT( cch[4] ); - CALC_FCOUNT( cch[5] ); + YM2610 *F2610 = &(FM2610[num]); + FM_OPN *OPN = &(FM2610[num].OPN); + YM_DELTAT *DELTAT = &(FM2610[num].deltaT); + int i,j; + FMSAMPLE *bufL,*bufR; + + /* setup DELTA-T unit */ + YM_DELTAT_DECODE_PRESET(DELTAT); + /* buffer setup */ + bufL = buffer[0]; + bufR = buffer[1]; + + if( (void *)F2610 != cur_chip ){ + cur_chip = (void *)F2610; + State = &OPN->ST; + 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]; + /* setup adpcm rom address */ + pcmbufA = F2610->pcmbuf; + pcmsizeA = F2610->pcm_size; + + LFOCnt = OPN->LFOCnt; + LFOIncr = OPN->LFOIncr; + if( !LFOIncr ) lfo_amd = lfo_pmd = 0; + } + + /* update frequency counter */ + OPN_CALC_FCOUNT( cch[0] ); + OPN_CALC_FCOUNT( cch[1] ); + if( (State->mode & 0xc0) ){ + /* 3SLOT MODE */ + if( cch[2]->SLOT[SLOT1].Incr==-1){ + /* 3 slot mode */ + CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); + } + }else OPN_CALC_FCOUNT( cch[2] ); + OPN_CALC_FCOUNT( cch[3] ); + OPN_CALC_FCOUNT( cch[4] ); + OPN_CALC_FCOUNT( cch[5] ); - /* buffering */ + /* buffering */ for( i=0; i < length ; i++ ) - { - /* clear output acc. */ - outd[OPN_LEFT] = outd[OPN_RIGHT]= outd[OPN_CENTER] = 0; - /**** deltaT ADPCM ****/ - if( F2610->adpcm[6].flag ) - OPNB_ADPCM_CALC_CHB( F2610, &F2610->adpcm[6]); - /* FM */ - FM_CALC_CH( cch[0] ); - FM_CALC_CH( cch[1] ); - FM_CALC_CH( cch[2] ); - FM_CALC_CH( cch[3] ); - FM_CALC_CH( cch[4] ); - FM_CALC_CH( cch[5] ); - for( j = 0; j < 6; j++ ) - { - /**** ADPCM ****/ - if( F2610->adpcm[j].flag ) - OPNB_ADPCM_CALC_CHA( F2610, &F2610->adpcm[j]); - } - /* get left & right output with clipping */ - dataL = Limit( outd[OPN_CENTER] + outd[OPN_LEFT], OPNB_MAXOUT, OPNB_MINOUT ); - dataR = Limit( outd[OPN_CENTER] + outd[OPN_RIGHT], OPNB_MAXOUT, OPNB_MINOUT ); - /* buffering */ - /* stereo separate */ -#ifdef FM_STEREO_MIX /* stereo mixing */ - /* stereo mix */ - ((FMSAMPLE_MIX *)bufL)[i] = ((dataL>>OPNB_OUTSB)<>OPNB_OUTSB); -#else - /* stereo separate */ - bufL[i] = dataL>>OPNB_OUTSB; - bufR[i] = dataR>>OPNB_OUTSB; -#endif + { + /* LFO */ + if( LFOIncr ) + { + lfo_amd = OPN_LFO_wave[(LFOCnt+=LFOIncr)>>LFO_SH]; + lfo_pmd = lfo_amd-(LFO_RATE/2); + } + + /* clear output acc. */ + out_adpcm[OUTD_LEFT] = out_adpcm[OUTD_RIGHT]= out_adpcm[OUTD_CENTER] = 0; + out_delta[OUTD_LEFT] = out_delta[OUTD_RIGHT]= 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 */ + FM_CALC_CH( cch[0] ); + FM_CALC_CH( cch[1] ); + FM_CALC_CH( cch[2] ); + FM_CALC_CH( cch[3] ); + FM_CALC_CH( cch[4] ); + FM_CALC_CH( cch[5] ); + + /**** deltaT ADPCM ****/ + if( DELTAT->portstate ) + YM_DELTAT_ADPCM_CALC(DELTAT); + + for( j = 0; j < 6; j++ ) + { + /**** ADPCM ****/ + if( F2610->adpcm[j].flag ) + OPNB_ADPCM_CALC_CHA( F2610, &F2610->adpcm[j]); + } + + /* buffering */ + { + int lt,rt; + + lt = out_adpcm[OUTD_LEFT] + out_adpcm[OUTD_CENTER]; + rt = out_adpcm[OUTD_RIGHT] + out_adpcm[OUTD_CENTER]; + lt += (out_delta[OUTD_LEFT] + out_delta[OUTD_CENTER])>>9; + rt += (out_delta[OUTD_RIGHT] + 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 controll */ + INTERNAL_TIMER_A( State , cch[2] ) + } + INTERNAL_TIMER_B(State,length) -#ifdef LFO_SUPPORT - CALC_LOPM_LFO; -#endif -#ifdef INTERNAL_TIMER - /* timer controll */ - CALC_TIMER_A( State , cch[2] ); -#endif - } -#ifdef INTERNAL_TIMER - CALC_TIMER_B( State , length ); -#endif + OPN->LFOCnt = LFOCnt; } #endif /* BUILD_YM2610B */ #if BUILD_OPNB + +#ifdef _STATE_H +static void YM2610_postload(void) +{ + int num , r; + + for(num=0;numREGS[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) */ + FM_ADPCMAWrite(F2610,1,F2610->REGS[0x111]); + for( r=0x08 ; r<0x0c ; r++) + FM_ADPCMAWrite(F2610,r,F2610->REGS[r+0x110]); + /* Delta-T ADPCM unit */ + YM_DELTAT_postload(&F2610->deltaT , &F2610->REGS[0x100] ); + } + cur_chip = NULL; +} + +static void YM2610_save_state(void) +{ + int num; + const char statename[] = "YM2610"; + + for(num=0;numREGS , 512); + FMsave_state_st(statename,num,&FM2610[num].OPN.ST); + FMsave_state_channel(statename,num,FM2610[num].CH,6); + /* 3slots */ + state_save_register_UINT32(statename, num, "slot3fc" , F2610->OPN.SL3.fc , 3); + state_save_register_UINT8 (statename, num, "slot3fh" , &F2610->OPN.SL3.fn_h , 1); + state_save_register_UINT8 (statename, num, "slot3kc" , F2610->OPN.SL3.kcode , 3); + /* address register1 */ + state_save_register_int (statename, num, "address1" , &F2610->address1); + state_save_register_UINT8 (statename, num, "arrivedFlag", &F2610->adpcm_arrivedEndAddress , 1); + /* rythm(ADPCMA) */ + FMsave_state_adpcma(statename,num,F2610->adpcm); + /* Delta-T ADPCM unit */ + YM_DELTAT_savestate(statename,num,&FM2610[num].deltaT); + } + state_save_register_func_postload(YM2610_postload); +} +#endif /* _STATE_H */ + int YM2610Init(int num, int clock, int rate, void **pcmroma,int *pcmsizea,void **pcmromb,int *pcmsizeb, FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler) { - int i,j; + int i; - if (FM2610) return (-1); /* duplicate init. */ - cur_chip = NULL; /* hiro-shi!! */ + if (FM2610) return (-1); /* duplicate init. */ + cur_chip = NULL; /* hiro-shi!! */ - FMNumChips = num; + YM2610NumChips = num; - /* allocate extend state space */ - if( (FM2610 = (YM2610 *)malloc(sizeof(YM2610) * FMNumChips))==NULL) - return (-1); - /* clear */ - memset(FM2610,0,sizeof(YM2610) * FMNumChips); - /* allocate total level table (128kb space) */ - if( !FMInitTable() ) - { - free( FM2610 ); - return (-1); - } - - for ( i = 0 ; i < FMNumChips; i++ ) { - /* FM */ - FM2610[i].OPN.ST.index = i; - FM2610[i].OPN.type = TYPE_YM2610; - FM2610[i].OPN.P_CH = FM2610[i].CH; - FM2610[i].OPN.ST.clock = clock; - FM2610[i].OPN.ST.rate = rate; - /* FM2610[i].OPN.ST.irq = 0; */ - /* FM2610[i].OPN.ST.status = 0; */ - FM2610[i].OPN.ST.timermodel = FM_TIMER_INTERVAL; - /* Extend handler */ - FM2610[i].OPN.ST.Timer_Handler = TimerHandler; - FM2610[i].OPN.ST.IRQ_Handler = IRQHandler; - /* ADPCM */ - FM2610[i].pcmbuf[0] = (char *)(pcmroma[i]); - FM2610[i].pcm_size[0] = pcmsizea[i]; - FM2610[i].pcmbuf[1] = (char *)(pcmromb[i]); - FM2610[i].pcm_size[1] = pcmsizeb[i]; - /* */ - YM2610ResetChip(i); - } - InitOPNB_ADPCMATable(); - return 0; + /* allocate extend state space */ + if( (FM2610 = (YM2610 *)malloc(sizeof(YM2610) * YM2610NumChips))==NULL) + return (-1); + /* clear */ + memset(FM2610,0,sizeof(YM2610) * YM2610NumChips); + /* allocate total level table (128kb space) */ + if( !OPNInitTable() ) + { + free( FM2610 ); + return (-1); + } + + for ( i = 0 ; i < YM2610NumChips; i++ ) { + YM2610 *F2610 = &(FM2610[i]); + /* FM */ + F2610->OPN.ST.index = i; + F2610->OPN.type = TYPE_YM2610; + F2610->OPN.P_CH = FM2610[i].CH; + F2610->OPN.ST.clock = clock; + F2610->OPN.ST.rate = rate; + /* FM2610[i].OPN.ST.irq = 0; */ + /* FM2610[i].OPN.ST.status = 0; */ + F2610->OPN.ST.timermodel = FM_TIMER_INTERVAL; + /* Extend handler */ + F2610->OPN.ST.Timer_Handler = TimerHandler; + F2610->OPN.ST.IRQ_Handler = IRQHandler; + /* ADPCM */ + F2610->pcmbuf = (UINT8 *)(pcmroma[i]); + F2610->pcm_size = pcmsizea[i]; + /* DELTA-T */ + F2610->deltaT.memory = (UINT8 *)(pcmromb[i]); + F2610->deltaT.memory_size = pcmsizeb[i]; + F2610->deltaT.arrivedFlagPtr = &F2610->adpcm_arrivedEndAddress; + /* */ + YM2610ResetChip(i); + } + InitOPNB_ADPCMATable(); +#ifdef _STATE_H + YM2610_save_state(); +#endif + return 0; } -/* ---------- shut down emurator ----------- */ +/* ---------- shut down emulator ----------- */ void YM2610Shutdown() { if (!FM2610) return; - FMCloseTable(); - free(FM2610); - FM2610 = NULL; -} - -#if 0 -unsigned int getNowAdpcmAddr( int num ){ - return FM2610[0].adpcm[num].now_addr; -} -unsigned char getNowAdpcmReg( int port, int num ){ - return FM2610[0].adpcmreg[port][num]; + FMCloseTable(); + free(FM2610); + FM2610 = NULL; } -#endif /* ---------- reset one of chip ---------- */ void YM2610ResetChip(int num) { - int i; - YM2610 *F2610 = &(FM2610[num]); - FM_OPN *OPN = &(FM2610[num].OPN); - - /* Reset Priscaler */ - OPNSetPris( OPN, 6*24, 6*24, 4*2); /* OPN 1/6 , SSG 1/4 */ - /* reset SSG section */ - SSGReset(OPN->ST.index); - /* status clear */ - FM_IRQMASK_SET(&OPN->ST,0x03); - OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ - - reset_channel( &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+1; i++ ){ - F2610->adpcm[i].now_addr = 0; - F2610->adpcm[i].now_step = 0; - F2610->adpcm[i].step = 0; - F2610->adpcm[i].start = 0; - F2610->adpcm[i].end = 0; - /* F2610->adpcm[i].delta = 21866; */ - F2610->adpcm[i].volume = 0; - F2610->adpcm[i].pan = &outd[OPN_CENTER]; /* default center */ - F2610->adpcm[i].flagMask = (i == 6) ? 0x80 : (1<adpcm[i].flag = 0; - F2610->adpcm[i].adpcmx = 0; - F2610->adpcm[i].adpcmd = 127; - F2610->adpcm[i].adpcml = 0; - /* DELTA-T */ - /*F2610->adpcm[i].adpcmm = 0;*/ - F2610->adpcm[i].volume_w_step = 0; - F2610->adpcm[i].next_leveling=0; - } - F2610->TL_adpcmb = &(TL_TABLE[0x3f*(int)(0.75/EG_STEP)]); - F2610->port0state = 0; - F2610->port0shift = 8; /* allways 8bits shift */ - /*F2610->port1state = 0; */ - F2610->port1state = -1; - F2610->port1shift = 8; /* allways 8bits shift */ - F2610->adpcm_arrivedEndAddress = 0; - F2610->adpcm_statusmask = 0xbf; + int i; + YM2610 *F2610 = &(FM2610[num]); + FM_OPN *OPN = &(FM2610[num].OPN); + YM_DELTAT *DELTAT = &(FM2610[num].deltaT); + + /* Reset Prescaler */ + OPNSetPres( OPN, 6*24, 6*24, 4*2); /* OPN 1/6 , SSG 1/4 */ + /* reset SSG section */ + SSGReset(OPN->ST.index); + /* status clear */ + FM_IRQMASK_SET(&OPN->ST,0x03); + FM_BUSY_CLEAR(&OPN->ST); + OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ + + reset_channel( &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++ ){ // this was "i < 6+1" which is ... a bug ? + F2610->adpcm[i].now_addr = 0; + F2610->adpcm[i].now_step = 0; + F2610->adpcm[i].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 = &out_adpcm[OUTD_CENTER]; /* default center */ + F2610->adpcm[i].flagMask = 1<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->port1state = -1; */ + F2610->adpcm_arrivedEndAddress = 0; + + /* DELTA-T unit */ + DELTAT->freqbase = OPN->ST.freqbase; + DELTAT->output_pointer = out_delta; + DELTAT->portshift = 8; /* allways 8bits shift */ + DELTAT->output_range = 1<<23; + YM_DELTAT_ADPCM_Reset(DELTAT,OUTD_CENTER); } /* YM2610 write */ /* n = number */ /* a = address */ /* v = value */ -int YM2610Write(int n, int a,int v) -{ - YM2610 *F2610 = &(FM2610[n]); - FM_OPN *OPN = &(FM2610[n].OPN); - int addr; - - switch( a&3 ){ - case 0: /* address port 0 */ - OPN->ST.address = v & 0xff; - /* Write register to SSG emurator */ - if( v < 16 ) SSGWrite(n,0,v); - break; - case 1: /* data port 0 */ - addr = OPN->ST.address; - switch(addr & 0xf0) - { - case 0x00: /* SSG section */ - /* Write data to SSG emurator */ - SSGWrite(n,a,v); - break; - case 0x10: /* DeltaT ADPCM */ - YM2610UpdateReq(n); - switch(addr) - { - case 0x1c: /* FLAG CONTROL : Extend Status Clear/Mask */ - F2610->adpcm_statusmask = ~v; - F2610->adpcm_arrivedEndAddress &= F2610->adpcm_statusmask; - break; - default: - /* 0x10-0x1b */ - FM_ADPCMBWrite(F2610,addr & 0x0f,v); - } - break; - case 0x20: /* Mode Register */ - YM2610UpdateReq(n); - OPNWriteMode(OPN,addr,v); - break; - default: /* OPN section */ - YM2610UpdateReq(n); - /* write register */ - OPNWriteReg(OPN,addr,v); - } - break; - case 2: /* address port 1 */ - F2610->address1 = v & 0xff; - break; - case 3: /* data port 1 */ - YM2610UpdateReq(n); - addr = F2610->address1; - if( addr < 0x30 ) - /* 100-12f : ADPCM A section */ - FM_ADPCMAWrite(F2610,addr,v); - else - OPNWriteReg(OPN,addr|0x100,v); - } - return OPN->ST.irq; -} -unsigned char YM2610Read(int n,int a) +int YM2610Write(int n, int a,UINT8 v) { - YM2610 *F2610 = &(FM2610[n]); - int addr = F2610->OPN.ST.address; - unsigned char ret = 0; - int i = 0; - - switch( a&3){ - case 0: /* status 0 : YM2203 compatible */ - ret = F2610->OPN.ST.status & 0x83; - break; - case 1: /* data 0 */ - if( addr < 16 ) ret = SSGRead(n); - 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 */ -#if 0 - ret = 0; - for( i=0;i<7;i++) - if(!(F2610->adpcm[i].flag)) ret |= F2610->adpcm[i].flagMask; - ret &= F2610->adpcm_statusmask; -#else - ret = F2610->adpcm_arrivedEndAddress; -#endif -#ifdef __RAINE__ - /*PrintDebug( "YM2610Status2 %02x\n", ret ); */ - /*PrintIngame(120,"YM2610Status2 %02x", ret ); */ -#endif - break; - case 3: - ret = 0; - break; - } - return ret; + YM2610 *F2610 = &(FM2610[n]); + FM_OPN *OPN = &(FM2610[n].OPN); + int addr; + int ch; + + + switch( a&3 ){ + case 0: /* address port 0 */ + OPN->ST.address = v & 0xff; + /* Write register to SSG emulator */ + if( v < 16 ) SSGWrite(n,0,v); + break; + case 1: /* data port 0 */ + addr = OPN->ST.address; +#ifdef _STATE_H + F2610->REGS[addr] = v; +#endif + switch(addr & 0xf0) + { + case 0x00: /* SSG section */ + /* Write data to SSG emulator */ + SSGWrite(n,a,v); + break; + case 0x10: /* DeltaT ADPCM */ + YM2610UpdateReq(n); + switch(addr) + { + case 0x1c: /* FLAG CONTROL : Extend Status Clear/Mask */ + { + UINT8 statusmask = ~v; + /* set arrived flag mask */ + for(ch=0;ch<6;ch++) + F2610->adpcm[ch].flagMask = statusmask&(1<deltaT.flagMask = statusmask&0x80; + /* clear arrived flag */ + F2610->adpcm_arrivedEndAddress &= statusmask&0x3f; + } + break; + default: + /* 0x10-0x1b */ + YM_DELTAT_ADPCM_Write(&F2610->deltaT,addr-0x10,v); + } + break; + case 0x20: /* Mode Register */ + YM2610UpdateReq(n); + OPNWriteMode(OPN,addr,v); + break; + default: /* OPN section */ + YM2610UpdateReq(n); + /* write register */ + OPNWriteReg(OPN,addr,v); + } + break; + case 2: /* address port 1 */ + F2610->address1 = v & 0xff; + break; + case 3: /* data port 1 */ + YM2610UpdateReq(n); + addr = F2610->address1; +#ifdef _STATE_H + F2610->REGS[addr|0x100] = v; +#endif + if( addr < 0x30 ) + /* 100-12f : ADPCM A section */ + FM_ADPCMAWrite(F2610,addr,v); + else + OPNWriteReg(OPN,addr|0x100,v); + } + return OPN->ST.irq; +} +UINT8 YM2610Read(int n,int a) +{ + YM2610 *F2610 = &(FM2610[n]); + int addr = F2610->OPN.ST.address; + UINT8 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 = SSGRead(n); + 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 YM2610TimerOver(int n,int c) { - YM2610 *F2610 = &(FM2610[n]); + YM2610 *F2610 = &(FM2610[n]); - if( c ) - { /* Timer B */ - TimerBOver( &(F2610->OPN.ST) ); - } - else - { /* Timer A */ - YM2610UpdateReq(n); - /* 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->CH[2]) ); - } - } - return F2610->OPN.ST.irq; + if( c ) + { /* Timer B */ + TimerBOver( &(F2610->OPN.ST) ); + } + else + { /* Timer A */ + YM2610UpdateReq(n); + /* 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->CH[2]) ); + } + } + return F2610->OPN.ST.irq; } -#if 0 -/* ---------- return the buffer ---------- */ -FMSAMPLE *YM2610Buffer(int n) -{ - return FMOPN[n].Buf[0]; -} -#endif - -#if 0 -/* ---------- set buffer ---------- */ -int YM2610SetBuffer(int n, FMSAMPLE **buf ) -{ - int i; - for( i = 0 ; i < YM2610_NUMBUF ; i++){ - FM2610[n].Buf[i] = buf[i]; - /*if( cur_chip == &FM2610[n] ) cur_chip = NULL;*/ - } - return 0; -} -#endif - -#endif /* BUILD_YM2610 */ +#endif /* BUILD_OPNB */ #if BUILD_YM2612 /*******************************************************************************/ -/* YM2612 local section */ +/* YM2612 local section */ /*******************************************************************************/ -static YM2612 *FM2612=NULL; /* array of YM2612's */ +/* here's the virtual YM2612 */ +typedef struct ym2612_f { +#ifdef _STATE_H + UINT8 REGS[512]; /* registers */ +#endif + FM_OPN OPN; /* OPN state */ + FM_CH CH[6]; /* channel state */ + int address1; /* address register1 */ + /* dac output (YM2612) */ + int dacen; + INT32 dacout; +} YM2612; + +static int YM2612NumChips; /* total chip */ +static YM2612 *FM2612=NULL; /* array of YM2612's */ + +static int dacen; /* ---------- update one of chip ----------- */ -void YM2612UpdateOne(int num, void **buffer, int length) +void YM2612UpdateOne(int num, INT16 **buffer, int length) { - YM2612 *F2612 = &(FM2612[num]); - FM_OPN *OPN = &(FM2612[num].OPN); - int dataR,dataL; - int i,ch; - int dacen = F2612->dacen; - int dacout = F2612->dacout; - - /* set bufer */ - bufL = (FMSAMPLE *)buffer[0]; - bufR = (FMSAMPLE *)buffer[1]; - - if( (void *)F2612 != cur_chip ){ - cur_chip = (void *)F2612; - - State = &OPN->ST; - cch[0] = &F2612->CH[0]; - cch[1] = &F2612->CH[1]; - cch[2] = &F2612->CH[2]; - cch[3] = &F2612->CH[3]; - cch[4] = &F2612->CH[4]; - cch[5] = &F2612->CH[5]; - } - /* update frequency counter */ - CALC_FCOUNT( cch[0] ); - CALC_FCOUNT( cch[1] ); - if( (State->mode & 0xc0) ){ - /* 3SLOT MODE */ - if( cch[2]->SLOT[SLOT1].Incr==-1){ - /* 3 slot mode */ - CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); - CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); - } - }else CALC_FCOUNT( cch[2] ); - CALC_FCOUNT( cch[3] ); - CALC_FCOUNT( cch[4] ); - CALC_FCOUNT( cch[5] ); - /* buffering */ - for( i=0; i < length ; i++ ) - { - /* clear output acc. */ - outd[OPN_LEFT] = outd[OPN_RIGHT]= outd[OPN_CENTER] = 0; - /* calcrate channel output */ - for( ch=0;ch<5;ch++) FM_CALC_CH( cch[ch] ); - if( dacen ) *cch[5]->connect4 += dacout; - else FM_CALC_CH( cch[5] ); - /* get left & right output */ - dataL = Limit( outd[OPN_CENTER] + outd[OPN_LEFT], OPN_MAXOUT, OPN_MINOUT ); - dataR = Limit( outd[OPN_CENTER] + outd[OPN_RIGHT], OPN_MAXOUT, OPN_MINOUT ); - /* buffering */ -#ifdef FM_STEREO_MIX /* stereo mixing */ - /* stereo mix */ - ((FMSAMPLE_MIX *)bufL)[i] = ((dataL>>OPN_OUTSB)<>OPN_OUTSB); -#else - /* stereo separate */ - bufL[i] = dataL>>OPN_OUTSB; - bufR[i] = dataR>>OPN_OUTSB; -#endif + YM2612 *F2612 = &(FM2612[num]); + FM_OPN *OPN = &(FM2612[num].OPN); + int i; + FMSAMPLE *bufL,*bufR; + INT32 dacout = F2612->dacout; + + /* set bufer */ + bufL = buffer[0]; + bufR = buffer[1]; + + if( (void *)F2612 != cur_chip ){ + cur_chip = (void *)F2612; + + State = &OPN->ST; + cch[0] = &F2612->CH[0]; + cch[1] = &F2612->CH[1]; + cch[2] = &F2612->CH[2]; + cch[3] = &F2612->CH[3]; + cch[4] = &F2612->CH[4]; + cch[5] = &F2612->CH[5]; + /* DAC mode */ + dacen = F2612->dacen; + + LFOCnt = OPN->LFOCnt; + LFOIncr = OPN->LFOIncr; + if( !LFOIncr ) lfo_amd = lfo_pmd = 0; + } + /* update frequency counter */ + OPN_CALC_FCOUNT( cch[0] ); + OPN_CALC_FCOUNT( cch[1] ); + if( (State->mode & 0xc0) ){ + /* 3SLOT MODE */ + if( cch[2]->SLOT[SLOT1].Incr==-1){ + /* 3 slot mode */ + CALC_FCSLOT(&cch[2]->SLOT[SLOT1] , OPN->SL3.fc[1] , OPN->SL3.kcode[1] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT2] , OPN->SL3.fc[2] , OPN->SL3.kcode[2] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT3] , OPN->SL3.fc[0] , OPN->SL3.kcode[0] ); + CALC_FCSLOT(&cch[2]->SLOT[SLOT4] , cch[2]->fc , cch[2]->kcode ); + } + }else OPN_CALC_FCOUNT( cch[2] ); + OPN_CALC_FCOUNT( cch[3] ); + OPN_CALC_FCOUNT( cch[4] ); + OPN_CALC_FCOUNT( cch[5] ); -#ifdef LFO_SUPPORT - CALC_LOPM_LFO; -#endif -#ifdef INTERNAL_TIMER - /* timer controll */ - CALC_TIMER_A( State , cch[2] ); -#endif - } -#ifdef INTERNAL_TIMER - CALC_TIMER_B( State , length ); -#endif + /* buffering */ + for( i=0; i < length ; i++ ) + { + /* LFO */ + if( LFOIncr ) + { + lfo_amd = OPN_LFO_wave[(LFOCnt+=LFOIncr)>>LFO_SH]; + lfo_pmd = lfo_amd-(LFO_RATE/2); + } + + /* 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 */ + FM_CALC_CH( cch[0] ); + FM_CALC_CH( cch[1] ); + FM_CALC_CH( cch[2] ); + FM_CALC_CH( cch[3] ); + FM_CALC_CH( cch[4] ); + if( dacen ) + *cch[5]->connect4 += dacout; + else + FM_CALC_CH( cch[5] ); + + + /* buffering */ + { + int lt,rt; + + lt = ((out_fm[0]>>0) & OPN->PAN[0]); + rt = ((out_fm[0]>>0) & OPN->PAN[1]); + lt += ((out_fm[1]>>0) & OPN->PAN[2]); + rt += ((out_fm[1]>>0) & OPN->PAN[3]); + lt += ((out_fm[2]>>0) & OPN->PAN[4]); + rt += ((out_fm[2]>>0) & OPN->PAN[5]); + lt += ((out_fm[3]>>0) & OPN->PAN[6]); + rt += ((out_fm[3]>>0) & OPN->PAN[7]); + lt += ((out_fm[4]>>0) & OPN->PAN[8]); + rt += ((out_fm[4]>>0) & OPN->PAN[9]); + lt += ((out_fm[5]>>0) & OPN->PAN[10]); + rt += ((out_fm[5]>>0) & 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 controll */ + INTERNAL_TIMER_A( State , cch[2] ) + } + INTERNAL_TIMER_B(State,length) + + OPN->LFOCnt = LFOCnt; +} + +#ifdef _STATE_H +static void YM2612_postload(void) +{ + int num , r; + + for(num=0;numST,0x03); - OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ - - reset_channel( &OPN->ST , &F2612->CH[0] , 6 ); - - 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);OPNWriteReg(OPN,i|0x100,0);} - /* DAC mode clear */ - F2612->dacen = 0; + int i; + YM2612 *F2612 = &(FM2612[num]); + FM_OPN *OPN = &(FM2612[num].OPN); + + OPNSetPres( OPN, 6*24, 6*24, 0); + /* status clear */ + FM_IRQMASK_SET(&OPN->ST,0x03); + FM_BUSY_CLEAR(&OPN->ST); + OPNWriteMode(OPN,0x27,0x30); /* mode 0 , timer reset */ + + reset_channel( &OPN->ST , &F2612->CH[0] , 6 ); + 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); + /* DAC mode clear */ + F2612->dacen = 0; } /* YM2612 write */ /* n = number */ /* a = address */ /* v = value */ -int YM2612Write(int n, int a,int v) +int YM2612Write(int n, int a,UINT8 v) { - YM2612 *F2612 = &(FM2612[n]); - int addr; + YM2612 *F2612 = &(FM2612[n]); + int addr; - switch( a&3){ - case 0: /* address port 0 */ - F2612->OPN.ST.address = v & 0xff; - break; - case 1: /* data port 0 */ - addr = F2612->OPN.ST.address; - switch( addr & 0xf0 ) - { - case 0x20: /* 0x20-0x2f Mode */ - switch( addr ) - { - case 0x2a: /* DAC data (YM2612) */ - YM2612UpdateReq(n); - F2612->dacout = v<<(TL_BITS-8); - break; /* jp 3/6/99 */ - case 0x2b: /* DAC Sel (YM2612) */ - /* b7 = dac enable */ - F2612->dacen = v & 0x80; - break; - default: /* OPN section */ - YM2612UpdateReq(n); - /* write register */ - OPNWriteMode(&(F2612->OPN),addr,v); - } - break; - default: /* 0x30-0xff OPN section */ - YM2612UpdateReq(n); - /* write register */ - OPNWriteReg(&(F2612->OPN),addr,v); - } - break; - case 2: /* address port 1 */ - F2612->address1 = v & 0xff; - break; - case 3: /* data port 1 */ - addr = F2612->address1; + switch( a&3){ + case 0: /* address port 0 */ + F2612->OPN.ST.address = v & 0xff; + break; + case 1: /* data port 0 */ + addr = F2612->OPN.ST.address; +#ifdef _STATE_H + F2612->REGS[addr] = v; +#endif + switch( addr & 0xf0 ) + { + case 0x20: /* 0x20-0x2f Mode */ + switch( addr ) + { + case 0x2a: /* DAC data (YM2612) */ YM2612UpdateReq(n); - OPNWriteReg(&(F2612->OPN),addr|0x100,v); - break; - } - return F2612->OPN.ST.irq; -} -unsigned char YM2612Read(int n,int a) -{ - YM2612 *F2612 = &(FM2612[n]); - int addr = F2612->OPN.ST.address; - - switch( a&3){ - case 0: /* status 0 */ - return F2612->OPN.ST.status; - case 1: - case 2: - case 3: - Log(LOG_WAR,"YM2612 #%d:A=%d read unmapped area\n"); - return F2612->OPN.ST.status; - } - return 0; + /* James Ponder 2001-09-30 level setting of 5 found suitable */ + F2612->dacout = ((int)v - 0x80) << 5; /* level unknown */ + break; + case 0x2b: /* DAC Sel (YM2612) */ + /* b7 = dac enable */ + F2612->dacen = v & 0x80; + cur_chip = NULL; + break; + default: /* OPN section */ + YM2612UpdateReq(n); + /* write register */ + OPNWriteMode(&(F2612->OPN),addr,v); + } + break; + default: /* 0x30-0xff OPN section */ + YM2612UpdateReq(n); + /* write register */ + OPNWriteReg(&(F2612->OPN),addr,v); + } + break; + case 2: /* address port 1 */ + F2612->address1 = v & 0xff; + break; + case 3: /* data port 1 */ + addr = F2612->address1 |0x100; +#ifdef _STATE_H + F2612->REGS[addr] = v; +#endif + YM2612UpdateReq(n); + OPNWriteReg(&(F2612->OPN),addr,v); + break; + } + return F2612->OPN.ST.irq; +} +UINT8 YM2612Read(int n,int a) +{ + YM2612 *F2612 = &(FM2612[n]); + + switch( a&3){ + case 0: /* status 0 */ + return FM_STATUS_FLAG(&F2612->OPN.ST); + case 1: + case 2: + case 3: + LOG(LOG_WAR,("YM2612 #%d:A=%d read unmapped area\n")); + return FM_STATUS_FLAG(&F2612->OPN.ST); + } + return 0; } int YM2612TimerOver(int n,int c) { - YM2612 *F2612 = &(FM2612[n]); + YM2612 *F2612 = &(FM2612[n]); - if( c ) - { /* Timer B */ - TimerBOver( &(F2612->OPN.ST) ); - } - else - { /* Timer A */ - YM2612UpdateReq(n); - /* timer update */ - TimerAOver( &(F2612->OPN.ST) ); - /* CSM mode key,TL controll */ - if( F2612->OPN.ST.mode & 0x80 ) - { /* CSM mode total level latch and auto key on */ - CSMKeyControll( &(F2612->CH[2]) ); - } - } - return F2612->OPN.ST.irq; -} - -#if 0 -/* ---------- set buffer ---------- */ -int YM2612SetBuffer(int n, FMSAMPLE **buf ) -{ - int i; - for( i = 0 ; i < YM2612_NUMBUF ; i++){ - FM2612[n].Buf[i] = buf[i]; - if( cur_chip == &FM2612[n] ) cur_chip = NULL; - } - return 0; + if( c ) + { /* Timer B */ + TimerBOver( &(F2612->OPN.ST) ); + } + else + { /* Timer A */ + YM2612UpdateReq(n); + /* timer update */ + TimerAOver( &(F2612->OPN.ST) ); + /* CSM mode key,TL controll */ + if( F2612->OPN.ST.mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + CSMKeyControll( &(F2612->CH[2]) ); + } + } + return F2612->OPN.ST.irq; } -#endif #endif /* BUILD_YM2612 */ - #if BUILD_YM2151 /*******************************************************************************/ -/* YM2151 local section */ +/* YM2151 local section */ /*******************************************************************************/ /* -------------------------- OPM ---------------------------------- */ -#undef SEG_SUPPORT /* OPM has not SEG type envelope */ +#undef FM_SEG_SUPPORT +#define FM_SEG_SUPPORT 0 /* OPM has not SEG type envelope */ + +#define FREQ_BITS 24 /* frequency turn */ + +/* operator output calcrator */ +#define OP_OUTN(PG,EG) NOISE_TABLE[(PG/(0x1000000/SIN_LEN))&(SIN_LEN-1)][EG] + + +/* here's the virtual YM2151(OPM) */ +typedef struct ym2151_f { +#ifdef _STATE_H + UINT8 REGS[256]; +#endif + FM_ST ST; /* general state */ + FM_CH CH[8]; /* channel state */ + UINT8 ct; /* CT0,1 */ + UINT32 NoiseCnt; /* noise generator */ + UINT32 NoiseIncr; /* noise mode enable & step */ + + /* LFO */ + UINT32 LFOCnt; + UINT32 LFOIncr; + UINT8 pmd; /* LFO pmd level */ + UINT8 amd; /* LFO amd level */ + INT32 *wavetype; /* LFO waveform */ + UINT8 testreg; /* test register (LFO reset) */ + UINT32 KC_TABLE[8*12*64+950];/* keycode,keyfunction -> count */ + mem_write_handler PortWrite;/* callback when write CT0/CT1 */ +} YM2151; -static YM2151 *FMOPM=NULL; /* array of YM2151's */ +static YM2151 *FMOPM=NULL; /* array of YM2151's */ +static int YM2151NumChips; /* total chip */ -/* ---------- priscaler set(and make time tables) ---------- */ -void OPMInitTable( int num ) +static INT32 OPM_LFO_waves[LFO_ENT*4]; /* LFO wave tabel */ +static INT32 *OPM_LFO_wave; + +/* current chip state */ +static UINT32 NoiseCnt , NoiseIncr; + +static INT32 *NOISE_TABLE[SIN_LEN]; + +static const int DT2_TABLE[4]={ /* 4 DT2 values */ +/* + * DT2 defines offset in cents from base note + * + * The table below defines offset in deltas table... + * User's Manual page 22 + * Values below were calculated using formula: value = orig.val * 1.5625 + * + * DT2=0 DT2=1 DT2=2 DT2=3 + * 0 600 781 950 + */ + 0, 384, 500, 608 +}; + +static const int KC_TO_SEMITONE[16]={ + /*translate note code KC into more usable number of semitone*/ + 0*64, 1*64, 2*64, 3*64, + 3*64, 4*64, 5*64, 6*64, + 6*64, 7*64, 8*64, 9*64, + 9*64,10*64,11*64,12*64 +}; + +/* ---------- frequency counter ---------- */ +INLINE void OPM_CALC_FCOUNT(YM2151 *OPM , FM_CH *CH ) +{ + if( CH->SLOT[SLOT1].Incr==-1) + { + int fc = CH->fc; + int kc = CH->kcode; + + CALC_FCSLOT(&CH->SLOT[SLOT1] , OPM->KC_TABLE[fc + CH->SLOT[SLOT1].DT2] , kc ); + CALC_FCSLOT(&CH->SLOT[SLOT2] , OPM->KC_TABLE[fc + CH->SLOT[SLOT2].DT2] , kc ); + CALC_FCSLOT(&CH->SLOT[SLOT3] , OPM->KC_TABLE[fc + CH->SLOT[SLOT3].DT2] , kc ); + CALC_FCSLOT(&CH->SLOT[SLOT4] , OPM->KC_TABLE[fc + CH->SLOT[SLOT4].DT2] , kc ); + } +} + +/* ---------- calculate one of channel7 ---------- */ +INLINE void OPM_CALC_CH7( FM_CH *CH ) +{ + UINT32 eg_out1,eg_out2,eg_out3,eg_out4; /*envelope output*/ + + /* Phase Generator */ + INT32 pms = lfo_pmd * CH->pms / LFO_RATE; + if(pms) + { + pg_in1 = (CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr + (INT32)(pms * CH->SLOT[SLOT1].Incr) / PMS_RATE); + pg_in2 = (CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr + (INT32)(pms * CH->SLOT[SLOT2].Incr) / PMS_RATE); + pg_in3 = (CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr + (INT32)(pms * CH->SLOT[SLOT3].Incr) / PMS_RATE); + pg_in4 = (CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr + (INT32)(pms * CH->SLOT[SLOT4].Incr) / PMS_RATE); + } + else + { + pg_in1 = (CH->SLOT[SLOT1].Cnt += CH->SLOT[SLOT1].Incr); + pg_in2 = (CH->SLOT[SLOT2].Cnt += CH->SLOT[SLOT2].Incr); + pg_in3 = (CH->SLOT[SLOT3].Cnt += CH->SLOT[SLOT3].Incr); + pg_in4 = (CH->SLOT[SLOT4].Cnt += CH->SLOT[SLOT4].Incr); + } + /* Envelope Generator */ + FM_CALC_EG(eg_out1,CH->SLOT[SLOT1]); + FM_CALC_EG(eg_out2,CH->SLOT[SLOT2]); + FM_CALC_EG(eg_out3,CH->SLOT[SLOT3]); + FM_CALC_EG(eg_out4,CH->SLOT[SLOT4]); + + /* connection */ + if( eg_out1 < ENV_QUIET ) /* SLOT 1 */ + { + if( CH->FB ){ + /* with self feed back */ + pg_in1 += (CH->op1_out[0]+CH->op1_out[1])>>CH->FB; + CH->op1_out[1] = CH->op1_out[0]; + } + CH->op1_out[0] = OP_OUT(pg_in1,eg_out1); + /* output slot1 */ + if( !CH->connect1 ) + { + /* algorithm 5 */ + pg_in2 += CH->op1_out[0]; + pg_in3 += CH->op1_out[0]; + pg_in4 += CH->op1_out[0]; + }else{ + /* other algorithm */ + *CH->connect1 += CH->op1_out[0]; + } + } + if( eg_out2 < ENV_QUIET ) /* SLOT 2 */ + *CH->connect2 += OP_OUT(pg_in2,eg_out2); + if( eg_out3 < ENV_QUIET ) /* SLOT 3 */ + *CH->connect3 += OP_OUT(pg_in3,eg_out3); + /* SLOT 4 */ + if(NoiseIncr) + { + NoiseCnt += NoiseIncr; + if( eg_out4 < ENV_QUIET ) + *CH->connect4 += OP_OUTN(NoiseCnt,eg_out4); + } + else + { + if( eg_out4 < ENV_QUIET ) + *CH->connect4 += OP_OUT(pg_in4,eg_out4); + } +} + +static int OPMInitTable(void) +{ + int i; + + /* NOISE wave table */ + + for(i=0;iKC_TABLE[i] = (UINT32)(pom * rate); + /*LOG(LOG_WAR,("OPM KC %d = %x\n",i,OPM->KC_TABLE[i]));*/ + } - if (FMOPM[num].ST.rate) - rate = (double)(1<KC_TABLE[i] = (unsigned int)(pom * rate); - /*Log(LOG_WAR,"OPM KC %d = %x\n",i,OPM->KC_TABLE[i]);*/ - } + /* make time tables */ + init_timetables( &OPM->ST , OPM_DTTABLE ); - /* make time tables */ - init_timetables( &OPM->ST , OPM_DTTABLE , OPM_ARRATE , OPM_DRRATE ); +} + +/* ---------- write a register on YM2151 chip number 'n' ---------- */ +static void OPMWriteReg(int n, int r, int v) +{ + UINT8 c; + FM_CH *CH; + FM_SLOT *SLOT; + + YM2151 *OPM = &(FMOPM[n]); + + c = OPM_CHAN(r); + CH = &OPM->CH[c]; + SLOT= &CH->SLOT[OPM_SLOT(r)]; + + switch( r & 0xe0 ){ + case 0x00: /* 0x00-0x1f */ + switch( r ){ + case 0x01: /* test */ + if( (OPM->testreg&(OPM->testreg^v))&0x02 ) /* fall eggge */ + { /* reset LFO counter */ + OPM->LFOCnt = 0; + cur_chip = NULL; + } + OPM->testreg = v; + break; + case 0x08: /* key on / off */ + c = v&7; + /* CSM mode */ + if( OPM->ST.mode & 0x80 ) break; + CH = &OPM->CH[c]; + if(v&0x08) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1); + if(v&0x10) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2); + if(v&0x20) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3); + if(v&0x40) FM_KEYON(CH,SLOT4); else FM_KEYOFF(CH,SLOT4); + break; + case 0x0f: /* Noise freq (ch7.op4) */ + /* b7 = Noise enable */ + /* b0-4 noise freq */ + OPM->NoiseIncr = !(v&0x80) ? 0 : + /* !!!!! unknown noise freqency rate !!!!! */ + (UINT32)((1<ST.freqbase); + cur_chip = NULL; +#if 1 + if( v & 0x80 ){ + LOG(LOG_WAR,("OPM Noise mode selelted\n")); + } +#endif + break; + case 0x10: /* timer A High 8*/ + OPM->ST.TA = (OPM->ST.TA & 0x03)|(((int)v)<<2); + break; + case 0x11: /* timer A Low 2*/ + OPM->ST.TA = (OPM->ST.TA & 0x3fc)|(v&3); + break; + case 0x12: /* timer B */ + OPM->ST.TB = v; + break; + case 0x14: /* mode , timer controll */ + FMSetMode( &(OPM->ST),n,v ); + break; + + case 0x18: /* lfreq */ + /* f = fm * 2^(LFRQ/16) / (4295*10^6) */ + { + static double drate[16]={ + 1.0 ,1.044273782,1.090507733,1.138788635, /*0-3*/ + 1.189207115,1.241857812,1.296839555,1.354255547, /*4-7*/ + 1.414213562,1.476826146,1.542210825,1.610490332, /*8-11*/ + 1.681792831,1.75625216 ,1.834008086,1.915206561}; + double rate = pow(2.0,v/16)*drate[v&0x0f] / 4295000000.0; + OPM->LFOIncr = (UINT32)((double)LFO_ENT*(1<ST.freqbase*64) * rate); + cur_chip = NULL; + } + break; + case 0x19: /* PMD/AMD */ + if( v & 0x80 ) OPM->pmd = v & 0x7f; + else OPM->amd = v & 0x7f; + break; + + case 0x1b: /* CT , W */ + /* b7 = CT1 */ + /* b6 = CT0 */ + /* b0-2 = wave form(LFO) 0=nokogiri,1=houkei,2=sankaku,3=noise */ + /*if(OPM->ct != v)*/ + { + OPM->ct = v>>6; + if( OPM->PortWrite != 0) + OPM->PortWrite(0, OPM->ct ); /* bit0 = CT0,bit1 = CT1 */ + } + + if( OPM->wavetype != &OPM_LFO_waves[(v&3)*LFO_ENT]) + { + OPM->wavetype = &OPM_LFO_waves[(v&3)*LFO_ENT]; + cur_chip = NULL; + } + break; + } + break; + case 0x20: /* 20-3f */ + switch( OPM_SLOT(r) ){ + case 0: /* 0x20-0x27 : RL,FB,CON */ + { + int feedback = (v>>3)&7; + CH->ALGO = v&7; + CH->FB = feedback ? 8+1 - feedback : 0; + /* RL order -> LR order */ + CH->PAN = ((v>>7)&1) | ((v>>5)&2); + setup_connection( CH ); + } + break; + case 1: /* 0x28-0x2f : Keycode */ + { + int blk = (v>>4)&7; + /* make keyscale code */ + CH->kcode = (v>>2)&0x1f; + /* make basic increment counter 22bit = 1 cycle */ + CH->fc = (blk * (12*64)) + KC_TO_SEMITONE[v&0x0f] + (CH->fc&0x3f); + CH->SLOT[SLOT1].Incr=-1; + } + break; + case 2: /* 0x30-0x37 : Keyfunction */ + CH->fc = (CH->fc&~0x3f) + (v>>2); + CH->SLOT[SLOT1].Incr=-1; + break; + case 3: /* 0x38-0x3f : PMS / AMS */ + /* b0-1 AMS */ + /* AMS * 23.90625db @ AMD=127 */ + /*CH->ams = (v & 0x03) * (23.90625/ENV_STEP);*/ + CH->ams = (UINT32)( (23.90625/ENV_STEP) / (1<<(3-(v&3))) ); + CH->SLOT[SLOT1].ams = CH->ams & CH->SLOT[SLOT1].amon; + CH->SLOT[SLOT2].ams = CH->ams & CH->SLOT[SLOT2].amon; + CH->SLOT[SLOT3].ams = CH->ams & CH->SLOT[SLOT3].amon; + CH->SLOT[SLOT4].ams = CH->ams & CH->SLOT[SLOT4].amon; + /* b4-6 PMS */ + /* 0,5,10,20,50,100,400,700 (cent) @ PMD=127 */ + { + /* 1 octabe = 1200cent = +100%/-50% */ + /* 100cent = 1seminote = 6% ?? */ + static const int pmd_table[8] = {0,5,10,20,50,100,400,700}; + CH->pms = (INT32)( (1.5/1200.0)*pmd_table[(v>>4) & 0x07] * PMS_RATE ); + } + break; + } + break; + case 0x40: /* DT1,MUL */ + set_det_mul(&OPM->ST,CH,SLOT,v); + break; + case 0x60: /* TL */ + set_tl(CH,SLOT,v,(OPM->ST.mode & 0x80) ); + break; + case 0x80: /* KS, AR */ + set_ar_ksr(CH,SLOT,v,OPM->ST.AR_TABLE); + break; + case 0xa0: /* AMS EN,D1R */ + set_dr(SLOT,v,OPM->ST.DR_TABLE); + /* bit7 = AMS ENABLE */ + SLOT->amon = (v&0x80) ? ~0: 0; + SLOT->ams = CH->ams & SLOT->amon; + break; + case 0xc0: /* DT2 ,D2R */ + SLOT->DT2 = DT2_TABLE[v>>6]; + CH->SLOT[SLOT1].Incr=-1; + set_sr(SLOT,v,OPM->ST.DR_TABLE); + break; + case 0xe0: /* D1L, RR */ + set_sl_rr(SLOT,v,OPM->ST.DR_TABLE); + break; + } +} + +int YM2151Write(int n,int a,UINT8 v) +{ + YM2151 *F2151 = &(FMOPM[n]); + + if( !(a&1) ) + { /* address port */ + F2151->ST.address = v & 0xff; + } + else + { /* data port */ + int addr = F2151->ST.address; +#ifdef _STATE_H + F2151->REGS[addr] = v; +#endif + YM2151UpdateReq(n); + /* write register */ + OPMWriteReg(n,addr,v); + FM_BUSY_SET(&F2151->ST,1); + } + return F2151->ST.irq; } /* ---------- reset one of chip ---------- */ void OPMResetChip(int num) { - int i; + int i; YM2151 *OPM = &(FMOPM[num]); - OPMInitTable( num ); - reset_channel( &OPM->ST , &OPM->CH[0] , 8 ); - /* status clear */ - FM_IRQMASK_SET(&OPM->ST,0x03); - OPMWriteReg(num,0x1b,0x00); - /* reset OPerator paramater */ - for(i = 0xff ; i >= 0x20 ; i-- ) OPMWriteReg(num,i,0); + OPMResetTable( num ); + reset_channel( &OPM->ST , &OPM->CH[0] , 8 ); + /* status clear */ + FM_IRQMASK_SET(&OPM->ST,0x03); + FM_BUSY_CLEAR(&OPM->ST); + OPMWriteReg(num,0x1b,0x00); + /* reset OPerator paramater */ + for(i = 0xff ; i >= 0x20 ; i-- ) OPMWriteReg(num,i,0); +} + +#ifdef _STATE_H +static void YM2151_postload(void) +{ + int num , r; + + for(num=0;numREGS[0x0f]); /* noise sel */ + OPMWriteReg(num,0x18,F2151->REGS[0x18]); /* lfreq */ + OPMWriteReg(num,0x1b,F2151->REGS[0x1b]); /* CT , W */ + + for(r=0xff;r>=0x20;r--) + OPMWriteReg(num,r,F2151->REGS[r]); + /* channels */ + /*FM_channel_postload(F2151->CH,8);*/ + } + cur_chip = NULL; +} + +static void YM2151_save_state(void) +{ + int num; + const char statename[] = "YM2151"; + + for(num=0;numREGS , 256); + FMsave_state_st(statename,num,&F2151->ST); + FMsave_state_channel(statename,num,F2151->CH,8); + + state_save_register_UINT32 (statename, num, "NoiseCount" , &F2151->NoiseCnt , 1); + state_save_register_UINT32 (statename, num, "NoiseStep" , &F2151->NoiseIncr , 1); + state_save_register_UINT32 (statename, num, "LFOCount" , &F2151->LFOCnt , 1); + state_save_register_UINT32 (statename, num, "LFOStep" , &F2151->LFOIncr , 1); + state_save_register_UINT8 (statename, num, "LFOPMD" , &F2151->pmd , 1); + state_save_register_UINT8 (statename, num, "LFOAMD" , &F2151->amd , 1); + state_save_register_UINT8 (statename, num, "test" , &F2151->testreg , 1); + } + state_save_register_func_postload(YM2151_postload); } +#endif /* _STATE_H */ /* ---------- Initialize YM2151 emulator(s) ---------- */ /* 'num' is the number of virtual YM2151's to allocate */ @@ -3337,323 +4206,172 @@ void OPMResetChip(int num) int OPMInit(int num, int clock, int rate, FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler) { - int i,j; + int i; - if (FMOPM) return (-1); /* duplicate init. */ - cur_chip = NULL; /* hiro-shi!! */ + if (FMOPM) return (-1); /* duplicate init. */ + cur_chip = NULL; /* hiro-shi!! */ - FMNumChips = num; + YM2151NumChips = num; - /* allocate ym2151 state space */ - if( (FMOPM = (YM2151 *)malloc(sizeof(YM2151) * FMNumChips))==NULL) - return (-1); - /* allocate total lebel table (128kb space) */ - if( !FMInitTable() ) - { - free( FMOPM ); - return (-1); - } - for ( i = 0 ; i < FMNumChips; i++ ) { - FMOPM[i].ST.index = i; - FMOPM[i].ST.clock = clock; - FMOPM[i].ST.rate = rate; - /* FMOPM[i].ST.irq = 0; */ - /* FMOPM[i].ST.status = 0; */ - FMOPM[i].ST.timermodel = FM_TIMER_SINGLE; - FMOPM[i].ST.freqbase = rate ? ((double)clock * 4096.0 / rate) / 64 : 0; - FMOPM[i].ST.TimerBase = rate ? 1.0/((double)clock / 64.0) : 0; - /*OPMSetBuffer(i,0,0);*/ - /* Extend handler */ - FMOPM[i].ST.Timer_Handler = TimerHandler; - FMOPM[i].ST.IRQ_Handler = IRQHandler; - /* Reset callback handler of CT0/1 */ - FMOPM[i].PortWrite = 0; - OPMResetChip(i); - } - return(0); + /* allocate ym2151 state space */ + if( (FMOPM = (YM2151 *)malloc(sizeof(YM2151) * YM2151NumChips))==NULL) + return (-1); + + /* clear */ + memset(FMOPM,0,sizeof(YM2151) * YM2151NumChips); + + /* allocate total level table (128kb space) */ + if( !OPMInitTable() ) + { + free( FMOPM ); + return (-1); + } + for ( i = 0 ; i < YM2151NumChips; i++ ) { + FMOPM[i].ST.index = i; + FMOPM[i].ST.clock = clock; + FMOPM[i].ST.rate = rate; + /* FMOPM[i].ST.irq = 0; */ + /* FMOPM[i].ST.status = 0; */ + FMOPM[i].ST.timermodel = FM_TIMER_INTERVAL; + FMOPM[i].ST.freqbase = rate ? ((double)clock / rate) / 64 : 0; + FMOPM[i].ST.TimerBase = 1.0/((double)clock / 64.0); + /* Extend handler */ + FMOPM[i].ST.Timer_Handler = TimerHandler; + FMOPM[i].ST.IRQ_Handler = IRQHandler; + /* Reset callback handler of CT0/1 */ + FMOPM[i].PortWrite = 0; + OPMResetChip(i); + } +#ifdef _STATE_H + YM2151_save_state(); +#endif /* _STATE_H */ + return(0); } -/* ---------- shut down emurator ----------- */ +/* ---------- shut down emulator ----------- */ void OPMShutdown() { if (!FMOPM) return; - FMCloseTable(); - free(FMOPM); - FMOPM = NULL; -} -/* ---------- write a register on YM2151 chip number 'n' ---------- */ -void OPMWriteReg(int n, int r, int v) -{ - unsigned char c; - FM_CH *CH; - FM_SLOT *SLOT; - - YM2151 *OPM = &(FMOPM[n]); - - c = OPM_CHAN(r); - CH = &OPM->CH[c]; - SLOT= &CH->SLOT[OPM_SLOT(r)]; - - switch( r & 0xe0 ){ - case 0x00: /* 0x00-0x1f */ - switch( r ){ - case 0x01: /* test */ - break; - case 0x08: /* key on / off */ - c = v&7; - /* CSM mode */ - if( c == 7 && (OPM->ST.mode & 0x80) ) break; - CH = &OPM->CH[c]; - if(v&0x08) FM_KEYON(CH,SLOT1); else FM_KEYOFF(CH,SLOT1); - if(v&0x10) FM_KEYON(CH,SLOT2); else FM_KEYOFF(CH,SLOT2); - if(v&0x20) FM_KEYON(CH,SLOT3); else FM_KEYOFF(CH,SLOT3); - if(v&0x40) FM_KEYON(CH,SLOT4); else FM_KEYOFF(CH,SLOT4); - break; - case 0x0f: /* Noise freq (ch7.op4) */ - /* b7 = Noise enable */ - /* b0-4 noise freq */ - if( v & 0x80 ){ - /* !!!!! do not supported noise mode !!!!! */ - Log(LOG_WAR,"OPM Noise mode sel ( not supported )\n"); - } - OPM->NReg = v & 0x8f; - break; - case 0x10: /* timer A High 8*/ - OPM->ST.TA = (OPM->ST.TA & 0x03)|(((int)v)<<2); - break; - case 0x11: /* timer A Low 2*/ - OPM->ST.TA = (OPM->ST.TA & 0x3fc)|(v&3); - break; - case 0x12: /* timer B */ - OPM->ST.TB = v; - break; - case 0x14: /* mode , timer controll */ - FMSetMode( &(OPM->ST),n,v ); - break; - case 0x18: /* lfreq */ - /* !!!!! pickup lfo frequency table !!!!! */ - break; - case 0x19: /* PMD/AMD */ - if( v & 0x80 ) OPM->pmd = v & 0x7f; - else OPM->amd = v & 0x7f; - break; - case 0x1b: /* CT , W */ - /* b7 = CT1 */ - /* b6 = CT0 */ - /* b0-3 = wave form(LFO) 0=nokogiri,1=houkei,2=sankaku,3=noise */ - OPM->ctw = v&0xff; - if( OPM->PortWrite != 0) - OPM->PortWrite(0, (OPM->ctw)>>6 ); /* bit0 = CT0,bit1 = CT1 */ - break; - } - break; - case 0x20: /* 20-3f */ - switch( OPM_SLOT(r) ){ - case 0: /* 0x20-0x27 : RL,FB,CON */ - { - int feedback = (v>>3)&7; - CH->ALGO = v&7; - CH->FB = feedback ? 8 - feedback : 0; - CH->PAN = ((v>>6)&0x03); - set_algorythm( CH ); - } - break; - case 1: /* 0x28-0x2f : Keycode */ - { - int blk = (v>>4)&7; - /* make keyscale code */ - CH->kcode = (v>>2)&0x1f; - /* make basic increment counter 22bit = 1 cycle */ - CH->fc = (blk * (12*64)) + KC_TO_SEMITONE[v&0x0f] + CH->fn_h; - CH->SLOT[SLOT1].Incr=-1; - } - break; - case 2: /* 0x30-0x37 : Keyfunction */ - CH->fc -= CH->fn_h; - CH->fn_h = v>>2; - CH->fc += CH->fn_h; - CH->SLOT[SLOT1].Incr=-1; - break; - case 3: /* 0x38-0x3f : PMS / AMS */ - /* b0-1 AMS */ - /* AMS * 23.90625db */ - CH->SLOT[SLOT1].ams = v & 0x03; - CH->SLOT[SLOT2].ams = v & 0x03; - CH->SLOT[SLOT3].ams = v & 0x03; - CH->SLOT[SLOT4].ams = v & 0x03; - /* b4-6 PMS */ - /* 0,5,10,20,50,100,400,700 (cent) */ - CH->SLOT[SLOT1].pms = (v>>4) & 0x07; - CH->SLOT[SLOT2].pms = (v>>4) & 0x07; - CH->SLOT[SLOT3].pms = (v>>4) & 0x07; - CH->SLOT[SLOT4].pms = (v>>4) & 0x07; - break; - } - break; - case 0x40: /* DT1,MUL */ - set_det_mul(&OPM->ST,CH,SLOT,v); - break; - case 0x60: /* TL */ - set_tl(CH,SLOT,v,(c == 7) && (OPM->ST.mode & 0x80) ); - break; - case 0x80: /* KS, AR */ - set_ar_ksr(CH,SLOT,v,OPM->ST.AR_TABLE); - break; - case 0xa0: /* AMS EN,D1R */ - /* bit7 = AMS ENABLE */ - set_dr(SLOT,v,OPM->ST.DR_TABLE); - break; - case 0xc0: /* DT2 ,D2R */ - SLOT->DT2 = DT2_TABLE[v>>6]; - CH->SLOT[SLOT1].Incr=-1; - set_sr(SLOT,v,OPM->ST.DR_TABLE); - break; - case 0xe0: /* D1L, RR */ - set_sl_rr(SLOT,v,OPM->ST.DR_TABLE); - break; - } + FMCloseTable(); + free(FMOPM); + FMOPM = NULL; } -/* ---------- read status port ---------- */ -unsigned char OPMReadStatus(int n) +UINT8 YM2151Read(int n,int a) { - return FMOPM[n].ST.status; -} - -int YM2151Write(int n,int a,int v) -{ - YM2151 *F2151 = &(FMOPM[n]); - - if( !(a&1) ) - { /* address port */ - F2151->ST.address = v & 0xff; - } - else - { /* data port */ - int addr = F2151->ST.address; - YM2151UpdateReq(n); - /* write register */ - OPMWriteReg(n,addr,v); - } - return F2151->ST.irq; -} - -unsigned char YM2151Read(int n,int a) -{ - if( !(a&1) ) return 0; - else return FMOPM[n].ST.status; + if( !(a&1) ) return 0; + else return FM_STATUS_FLAG(&FMOPM[n].ST); } /* ---------- make digital sound data ---------- */ -void OPMUpdateOne(int num, void **buffer, int length) -{ - YM2151 *OPM = &(FMOPM[num]); - int i,ch; - int dataR,dataL; - - /* set bufer */ - bufL = (FMSAMPLE *)buffer[0]; - bufR = (FMSAMPLE *)buffer[1]; - - if( (void *)OPM != cur_chip ){ - cur_chip = (void *)OPM; - - State = &OPM->ST; - /* channel pointer */ - cch[0] = &OPM->CH[0]; - cch[1] = &OPM->CH[1]; - cch[2] = &OPM->CH[2]; - cch[3] = &OPM->CH[3]; - cch[4] = &OPM->CH[4]; - cch[5] = &OPM->CH[5]; - cch[6] = &OPM->CH[6]; - cch[7] = &OPM->CH[7]; - } - OPM_CALC_FCOUNT( OPM , cch[0] ); - OPM_CALC_FCOUNT( OPM , cch[1] ); - OPM_CALC_FCOUNT( OPM , cch[2] ); - OPM_CALC_FCOUNT( OPM , cch[3] ); - OPM_CALC_FCOUNT( OPM , cch[4] ); - OPM_CALC_FCOUNT( OPM , cch[5] ); - OPM_CALC_FCOUNT( OPM , cch[6] ); - /* CSM check */ - OPM_CALC_FCOUNT( OPM , cch[7] ); - - for( i=0; i < length ; i++ ) - { - /* clear output acc. */ - outd[OPM_LEFT] = outd[OPM_RIGHT]= outd[OPM_CENTER] = 0; - /* calcrate channel output */ - for( ch=0;ch<8;ch++) FM_CALC_CH( cch[ch] ); - /* get left & right output */ - dataL = Limit( outd[OPM_CENTER] + outd[OPM_LEFT], OPM_MAXOUT, OPM_MINOUT ); - dataR = Limit( outd[OPM_CENTER] + outd[OPM_RIGHT], OPM_MAXOUT, OPM_MINOUT ); - -#ifdef FM_STEREO_MIX /* stereo mixing */ - /* stereo mix */ - ((FMSAMPLE_MIX *)bufL)[i] = ((dataL>>OPM_OUTSB)<>OPM_OUTSB); -#else - /* stereo separate */ - bufL[i] = dataL>>OPM_OUTSB; - bufR[i] = dataR>>OPM_OUTSB; -#endif -#ifdef LFO_SUPPORT - CALC_LOPM_LFO; -#endif - -#ifdef INTERNAL_TIMER - CALC_TIMER_A( State , cch[7] ); -#endif - } -#ifdef INTERNAL_TIMER - CALC_TIMER_B( State , length ); -#endif -} - -void OPMSetPortHander(int n,void (*PortWrite)(int offset,int CT) ) +void OPMUpdateOne(int num, INT16 **buffer, int length) { - FMOPM[n].PortWrite = PortWrite; + YM2151 *OPM = &(FMOPM[num]); + int i; + int amd,pmd; + FM_CH *ch; + FMSAMPLE *bufL,*bufR; + + /* set bufer */ + bufL = buffer[0]; + bufR = buffer[1]; + + if( (void *)OPM != cur_chip ){ + cur_chip = (void *)OPM; + + State = &OPM->ST; + /* channel pointer */ + cch[0] = &OPM->CH[0]; + cch[1] = &OPM->CH[1]; + cch[2] = &OPM->CH[2]; + cch[3] = &OPM->CH[3]; + cch[4] = &OPM->CH[4]; + cch[5] = &OPM->CH[5]; + cch[6] = &OPM->CH[6]; + cch[7] = &OPM->CH[7]; + /* ch7.op4 noise mode / step */ + NoiseIncr = OPM->NoiseIncr; + NoiseCnt = OPM->NoiseCnt; + /* LFO */ + LFOCnt = OPM->LFOCnt; + /*LFOIncr = OPM->LFOIncr;*/ + if( !LFOIncr ) lfo_amd = lfo_pmd = 0; + OPM_LFO_wave = OPM->wavetype; + } + amd = OPM->amd; + pmd = OPM->pmd; + if(amd==0 && pmd==0) + LFOIncr = 0; + else + LFOIncr = OPM->LFOIncr; + + OPM_CALC_FCOUNT( OPM , cch[0] ); + OPM_CALC_FCOUNT( OPM , cch[1] ); + OPM_CALC_FCOUNT( OPM , cch[2] ); + OPM_CALC_FCOUNT( OPM , cch[3] ); + OPM_CALC_FCOUNT( OPM , cch[4] ); + OPM_CALC_FCOUNT( OPM , cch[5] ); + OPM_CALC_FCOUNT( OPM , cch[6] ); + OPM_CALC_FCOUNT( OPM , cch[7] ); + + for( i=0; i < length ; i++ ) + { + /* LFO */ + if( LFOIncr ) + { + INT32 depth = OPM_LFO_wave[(LFOCnt+=LFOIncr)>>LFO_SH]; + lfo_amd = depth * amd; + lfo_pmd = (depth-(LFO_RATE/127/2)) * pmd; + } + /* clear output acc. */ + out_ch[OUTD_LEFT] = out_ch[OUTD_RIGHT]= out_ch[OUTD_CENTER] = 0; + /* calculate channel output */ + for(ch = cch[0] ; ch <= cch[6] ; ch++) + FM_CALC_CH( ch ); + OPM_CALC_CH7( cch[7] ); + /* buffering */ + FM_BUFFERING_STEREO; + /* timer A controll */ + INTERNAL_TIMER_A( State , cch[7] ) + } + INTERNAL_TIMER_B(State,length) + OPM->NoiseCnt = NoiseCnt; + OPM->LFOCnt = LFOCnt; } -#if 0 -/* ---------- return the buffer ---------- */ -FMSAMPLE *OPMBuffer(int n,int c) +void OPMSetPortHander(int n,mem_write_handler PortWrite) { - return FMOPM[n].Buf[c]; + FMOPM[n].PortWrite = PortWrite; } -/* ---------- set buffer ---------- */ -int OPMSetBuffer(int n, FMSAMPLE **buf ) -{ - int i; - for( i = 0 ; i < YM2151_NUMBUF ; i++){ - FMOPM[n].Buf[i] = buf[i]; - if( cur_chip == &FMOPM[n] ) cur_chip = NULL; - } - return 0; -} -#endif int YM2151TimerOver(int n,int c) { - YM2151 *F2151 = &(FMOPM[n]); + YM2151 *F2151 = &(FMOPM[n]); - if( c ) - { /* Timer B */ - TimerBOver( &(F2151->ST) ); - } - else - { /* Timer A */ - YM2151UpdateReq(n); - /* timer update */ - TimerAOver( &(F2151->ST) ); - /* CSM mode key,TL controll */ - if( F2151->ST.mode & 0x80 ) - { /* CSM mode total level latch and auto key on */ - CSMKeyControll( &(F2151->CH[7]) ); - } - } - return F2151->ST.irq; + if( c ) + { /* Timer B */ + TimerBOver( &(F2151->ST) ); + } + else + { /* Timer A */ + YM2151UpdateReq(n); + /* timer update */ + TimerAOver( &(F2151->ST) ); + /* CSM mode key,TL controll */ + if( F2151->ST.mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + CSMKeyControll( &(F2151->CH[0]) ); + CSMKeyControll( &(F2151->CH[1]) ); + CSMKeyControll( &(F2151->CH[2]) ); + CSMKeyControll( &(F2151->CH[3]) ); + CSMKeyControll( &(F2151->CH[4]) ); + CSMKeyControll( &(F2151->CH[5]) ); + CSMKeyControll( &(F2151->CH[6]) ); + CSMKeyControll( &(F2151->CH[7]) ); + } + } + return F2151->ST.irq; } #endif /* BUILD_YM2151 */