fmopl.cc

Go to the documentation of this file.
00001 /* 
00002  * Copyright (C) 1999/2000 Tatsuyuki Satoh
00003  * Copyright (C) 2001/2002 The ScummVM project
00004  * Copyright (C) 2002 The Exult Team
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010 
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015 
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019  *
00020  * $Header: /cvsroot/exult/exult/audio/midi_drivers/fmopl.cc,v 1.3 2004/05/21 16:57:13 colourles Exp $
00021  *
00022  * LGPL licensed version of MAMEs fmopl (V0.37a modified) by
00023  * Tatsuyuki Satoh. Included from LGPL'ed AdPlug.
00024  */
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #  include <config.h>
00028 #endif
00029 
00030 #ifdef USE_FMOPL_MIDI
00031 
00032 #include "common_types.h"
00033 #include <cstdio>
00034 #include <cstdlib>
00035 #include <cstring>
00036 #include <cstdarg>
00037 #include <cmath>
00038 #include <iostream>
00039 #include "fmopl.h"
00040 
00041 #ifndef UNDER_CE
00042 using std::malloc;
00043 using std::free;
00044 #endif
00045 
00046 #ifndef PI
00047 #define PI 3.14159265358979323846
00048 #endif
00049 
00050 /* -------------------- preliminary define section --------------------- */
00051 /* attack/decay rate time rate */
00052 #define OPL_ARRATE     141280  /* RATE 4 =  2826.24ms @ 3.6MHz */
00053 #define OPL_DRRATE    1956000  /* RATE 4 = 39280.64ms @ 3.6MHz */
00054 
00055 #define FREQ_BITS 24      /* frequency turn          */
00056 
00057 /* counter bits = 20 , octerve 7 */
00058 #define FREQ_RATE   (1<<(FREQ_BITS-20))
00059 #define TL_BITS    (FREQ_BITS+2)
00060 
00061 /* final output shift , limit minimum and maximum */
00062 #define OPL_OUTSB   (TL_BITS+3-16)    /* OPL output final shift 16bit */
00063 #define OPL_MAXOUT (0x7fff<<OPL_OUTSB)
00064 #define OPL_MINOUT (-0x8000<<OPL_OUTSB)
00065 
00066 /* -------------------- quality selection --------------------- */
00067 
00068 /* sinwave entries */
00069 /* used static memory = SIN_ENT * 4 (byte) */
00070 #define SIN_ENT 2048
00071 
00072 /* output level entries (envelope,sinwave) */
00073 /* envelope counter lower bits */
00074 #define ENV_BITS 16
00075 /* envelope output entries */
00076 #define EG_ENT   4096
00077 /* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */
00078 /* used static  memory = EG_ENT*4 (byte)                     */
00079 
00080 #define EG_OFF   ((2*EG_ENT)<<ENV_BITS)  /* OFF          */
00081 #define EG_DED   EG_OFF
00082 #define EG_DST   (EG_ENT<<ENV_BITS)      /* DECAY  START */
00083 #define EG_AED   EG_DST
00084 #define EG_AST   0                       /* ATTACK START */
00085 
00086 #define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step  */
00087 
00088 /* LFO table entries */
00089 #define VIB_ENT 512
00090 #define VIB_SHIFT (32-9)
00091 #define AMS_ENT 512
00092 #define AMS_SHIFT (32-9)
00093 
00094 #define VIB_RATE 256
00095 
00096 /* -------------------- local defines , macros --------------------- */
00097 
00098 /* register number to channel number , slot offset */
00099 #define SLOT1 0
00100 #define SLOT2 1
00101 
00102 /* envelope phase */
00103 #define ENV_MOD_RR  0x00
00104 #define ENV_MOD_DR  0x01
00105 #define ENV_MOD_AR  0x02
00106 
00107 /* -------------------- tables --------------------- */
00108 static const int slot_array[32]=
00109 {
00110    0, 2, 4, 1, 3, 5,-1,-1,
00111    6, 8,10, 7, 9,11,-1,-1,
00112   12,14,16,13,15,17,-1,-1,
00113   -1,-1,-1,-1,-1,-1,-1,-1
00114 };
00115 
00116 #define SC(mydb) ((uint32) (mydb / (EG_STEP/2)))
00117 
00118 static const uint32 KSL_TABLE[8 * 16] = {
00119   /* OCT 0 */
00120   SC(0.000), SC(0.000), SC(0.000), SC(0.000),
00121   SC(0.000), SC(0.000), SC(0.000), SC(0.000),
00122   SC(0.000), SC(0.000), SC(0.000), SC(0.000),
00123   SC(0.000), SC(0.000), SC(0.000), SC(0.000),
00124   /* OCT 1 */
00125   SC(0.000), SC(0.000), SC(0.000), SC(0.000),
00126   SC(0.000), SC(0.000), SC(0.000), SC(0.000),
00127   SC(0.000), SC(0.750), SC(1.125), SC(1.500),
00128   SC(1.875), SC(2.250), SC(2.625), SC(3.000),
00129   /* OCT 2 */
00130   SC(0.000), SC(0.000), SC(0.000), SC(0.000),
00131   SC(0.000), SC(1.125), SC(1.875), SC(2.625),
00132   SC(3.000), SC(3.750), SC(4.125), SC(4.500),
00133   SC(4.875), SC(5.250), SC(5.625), SC(6.000),
00134   /* OCT 3 */
00135   SC(0.000), SC(0.000), SC(0.000), SC(1.875),
00136   SC(3.000), SC(4.125), SC(4.875), SC(5.625),
00137   SC(6.000), SC(6.750), SC(7.125), SC(7.500),
00138   SC(7.875), SC(8.250), SC(8.625), SC(9.000),
00139   /* OCT 4 */
00140   SC(0.000), SC(0.000), SC(3.000), SC(4.875),
00141   SC(6.000), SC(7.125), SC(7.875), SC(8.625),
00142   SC(9.000), SC(9.750), SC(10.125), SC(10.500),
00143   SC(10.875), SC(11.250), SC(11.625), SC(12.000),
00144   /* OCT 5 */
00145   SC(0.000), SC(3.000), SC(6.000), SC(7.875),
00146   SC(9.000), SC(10.125), SC(10.875), SC(11.625),
00147   SC(12.000), SC(12.750), SC(13.125), SC(13.500),
00148   SC(13.875), SC(14.250), SC(14.625), SC(15.000),
00149   /* OCT 6 */
00150   SC(0.000), SC(6.000), SC(9.000), SC(10.875),
00151   SC(12.000), SC(13.125), SC(13.875), SC(14.625),
00152   SC(15.000), SC(15.750), SC(16.125), SC(16.500),
00153   SC(16.875), SC(17.250), SC(17.625), SC(18.000),
00154   /* OCT 7 */
00155   SC(0.000), SC(9.000), SC(12.000), SC(13.875),
00156   SC(15.000), SC(16.125), SC(16.875), SC(17.625),
00157   SC(18.000), SC(18.750), SC(19.125), SC(19.500),
00158   SC(19.875), SC(20.250), SC(20.625), SC(21.000)
00159 };
00160 #undef SC
00161 
00162 
00163 /* sustain lebel table (3db per step) */
00164 /* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
00165 #define SC(db) (int)(db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST
00166 static const int SL_TABLE[16]={
00167  SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
00168  SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
00169 };
00170 #undef SC
00171 
00172 #define TL_MAX (EG_ENT*2) /* limit(tl + ksr + envelope) + sinwave */
00173 /* TotalLevel : 48 24 12  6  3 1.5 0.75 (dB) */
00174 /* TL_TABLE[ 0      to TL_MAX          ] : plus  section */
00175 /* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
00176 static int *TL_TABLE;
00177 
00178 /* pointers to TL_TABLE with sinwave output offset */
00179 static int **SIN_TABLE;
00180 
00181 /* LFO table */
00182 static int *AMS_TABLE;
00183 static int *VIB_TABLE;
00184 
00185 /* envelope output curve table */
00186 /* attack + decay + OFF */
00187 static int ENV_CURVE[2*EG_ENT+1];
00188 
00189 /* multiple table */
00190 #define ML(a) (int)(a*2)
00191 static const uint32 MUL_TABLE[16]= {
00192 /* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
00193    ML(0.50), ML(1.00), ML(2.00),  ML(3.00), ML(4.00), ML(5.00), ML(6.00), ML(7.00),
00194    ML(8.00), ML(9.00), ML(10.00), ML(10.00),ML(12.00),ML(12.00),ML(15.00),ML(15.00)
00195 };
00196 #undef ML
00197 
00198 /* dummy attack / decay rate ( when rate == 0 ) */
00199 static int RATE_0[16]=
00200 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
00201 
00202 /* -------------------- static state --------------------- */
00203 
00204 /* lock level of common table */
00205 static int num_lock = 0;
00206 
00207 /* work table */
00208 static void *cur_chip = NULL; /* current chip point */
00209 /* currenct chip state */
00210 /* static OPLSAMPLE  *bufL,*bufR; */
00211 static OPL_CH *S_CH;
00212 static OPL_CH *E_CH;
00213 OPL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2;
00214 
00215 static int outd[1];
00216 static int ams;
00217 static int vib;
00218 int  *ams_table;
00219 int  *vib_table;
00220 static int amsIncr;
00221 static int vibIncr;
00222 static int feedback2;   /* connect for SLOT 2 */
00223 
00224 /* --------------------- subroutines  --------------------- */
00225 
00226 inline int Limit( int val, int max, int min ) {
00227   if ( val > max )
00228     val = max;
00229   else if ( val < min )
00230     val = min;
00231 
00232   return val;
00233 }
00234 
00235 /* status set and IRQ handling */
00236 inline void OPL_STATUS_SET(FM_OPL *OPL,int flag)
00237 {
00238   /* set status flag */
00239   OPL->status |= flag;
00240   if(!(OPL->status & 0x80))
00241   {
00242     if(OPL->status & OPL->statusmask)
00243     { /* IRQ on */
00244       OPL->status |= 0x80;
00245       /* callback user interrupt handler (IRQ is OFF to ON) */
00246       if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1);
00247     }
00248   }
00249 }
00250 
00251 /* status reset and IRQ handling */
00252 inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
00253 {
00254   /* reset status flag */
00255   OPL->status &=~flag;
00256   if((OPL->status & 0x80))
00257   {
00258     if (!(OPL->status & OPL->statusmask) )
00259     {
00260       OPL->status &= 0x7f;
00261       /* callback user interrupt handler (IRQ is ON to OFF) */
00262       if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
00263     }
00264   }
00265 }
00266 
00267 /* IRQ mask set */
00268 inline void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
00269 {
00270   OPL->statusmask = flag;
00271   /* IRQ handling check */
00272   OPL_STATUS_SET(OPL,0);
00273   OPL_STATUS_RESET(OPL,0);
00274 }
00275 
00276 /* ----- key on  ----- */
00277 inline void OPL_KEYON(OPL_SLOT *SLOT)
00278 {
00279   /* sin wave restart */
00280   SLOT->Cnt = 0;
00281   /* set attack */
00282   SLOT->evm = ENV_MOD_AR;
00283   SLOT->evs = SLOT->evsa;
00284   SLOT->evc = EG_AST;
00285   SLOT->eve = EG_AED;
00286 }
00287 /* ----- key off ----- */
00288 inline void OPL_KEYOFF(OPL_SLOT *SLOT)
00289 {
00290   if( SLOT->evm > ENV_MOD_RR)
00291   {
00292     /* set envelope counter from envleope output */
00293     SLOT->evm = ENV_MOD_RR;
00294     if( !(SLOT->evc&EG_DST) )
00295       //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST;
00296       SLOT->evc = EG_DST;
00297     SLOT->eve = EG_DED;
00298     SLOT->evs = SLOT->evsr;
00299   }
00300 }
00301 
00302 /* ---------- calcrate Envelope Generator & Phase Generator ---------- */
00303 /* return : envelope output */
00304 inline uint32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
00305 {
00306   /* calcrate envelope generator */
00307   if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
00308   {
00309     switch( SLOT->evm ){
00310     case ENV_MOD_AR: /* ATTACK -> DECAY1 */
00311       /* next DR */
00312       SLOT->evm = ENV_MOD_DR;
00313       SLOT->evc = EG_DST;
00314       SLOT->eve = SLOT->SL;
00315       SLOT->evs = SLOT->evsd;
00316       break;
00317     case ENV_MOD_DR: /* DECAY -> SL or RR */
00318       SLOT->evc = SLOT->SL;
00319       SLOT->eve = EG_DED;
00320       if(SLOT->eg_typ)
00321       {
00322         SLOT->evs = 0;
00323       }
00324       else
00325       {
00326         SLOT->evm = ENV_MOD_RR;
00327         SLOT->evs = SLOT->evsr;
00328       }
00329       break;
00330     case ENV_MOD_RR: /* RR -> OFF */
00331       SLOT->evc = EG_OFF;
00332       SLOT->eve = EG_OFF+1;
00333       SLOT->evs = 0;
00334       break;
00335     }
00336   }
00337   /* calcrate envelope */
00338   return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0);
00339 }
00340 
00341 /* set algorythm connection */
00342 static void set_algorythm( OPL_CH *CH)
00343 {
00344   int *carrier = &outd[0];
00345   CH->connect1 = CH->CON ? carrier : &feedback2;
00346   CH->connect2 = carrier;
00347 }
00348 
00349 /* ---------- frequency counter for operater update ---------- */
00350 inline void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
00351 {
00352   int ksr;
00353 
00354   /* frequency step counter */
00355   SLOT->Incr = CH->fc * SLOT->mul;
00356   ksr = CH->kcode >> SLOT->KSR;
00357 
00358   if( SLOT->ksr != ksr )
00359   {
00360     SLOT->ksr = ksr;
00361     /* attack , decay rate recalcration */
00362     SLOT->evsa = SLOT->AR[ksr];
00363     SLOT->evsd = SLOT->DR[ksr];
00364     SLOT->evsr = SLOT->RR[ksr];
00365   }
00366   SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
00367 }
00368 
00369 /* set multi,am,vib,EG-TYP,KSR,mul */
00370 inline void set_mul(FM_OPL *OPL,int slot,int v)
00371 {
00372   OPL_CH   *CH   = &OPL->P_CH[slot/2];
00373   OPL_SLOT *SLOT = &CH->SLOT[slot&1];
00374 
00375   SLOT->mul    = MUL_TABLE[v&0x0f];
00376   SLOT->KSR    = (v&0x10) ? 0 : 2;
00377   SLOT->eg_typ = (v&0x20)>>5;
00378   SLOT->vib    = (v&0x40);
00379   SLOT->ams    = (v&0x80);
00380   CALC_FCSLOT(CH,SLOT);
00381 }
00382 
00383 /* set ksl & tl */
00384 inline void set_ksl_tl(FM_OPL *OPL,int slot,int v)
00385 {
00386   OPL_CH   *CH   = &OPL->P_CH[slot/2];
00387   OPL_SLOT *SLOT = &CH->SLOT[slot&1];
00388   int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */
00389 
00390   SLOT->ksl = ksl ? 3-ksl : 31;
00391   SLOT->TL  = (int)((v&0x3f)*(0.75/EG_STEP)); /* 0.75db step */
00392 
00393   if( !(OPL->mode&0x80) )
00394   { /* not CSM latch total level */
00395     SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
00396   }
00397 }
00398 
00399 /* set attack rate & decay rate  */
00400 inline void set_ar_dr(FM_OPL *OPL,int slot,int v)
00401 {
00402   OPL_CH   *CH   = &OPL->P_CH[slot/2];
00403   OPL_SLOT *SLOT = &CH->SLOT[slot&1];
00404   int ar = v>>4;
00405   int dr = v&0x0f;
00406 
00407   SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0;
00408   SLOT->evsa = SLOT->AR[SLOT->ksr];
00409   if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa;
00410 
00411   SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0;
00412   SLOT->evsd = SLOT->DR[SLOT->ksr];
00413   if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd;
00414 }
00415 
00416 /* set sustain level & release rate */
00417 inline void set_sl_rr(FM_OPL *OPL,int slot,int v)
00418 {
00419   OPL_CH   *CH   = &OPL->P_CH[slot/2];
00420   OPL_SLOT *SLOT = &CH->SLOT[slot&1];
00421   int sl = v>>4;
00422   int rr = v & 0x0f;
00423 
00424   SLOT->SL = SL_TABLE[sl];
00425   if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL;
00426   SLOT->RR = &OPL->DR_TABLE[rr<<2];
00427   SLOT->evsr = SLOT->RR[SLOT->ksr];
00428   if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr;
00429 }
00430 
00431 /* operator output calcrator */
00432 #define OP_OUT(slot,env,con)   slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env]
00433 /* ---------- calcrate one of channel ---------- */
00434 inline void OPL_CALC_CH( OPL_CH *CH )
00435 {
00436   uint32 env_out;
00437   OPL_SLOT *SLOT;
00438 
00439   feedback2 = 0;
00440   /* SLOT 1 */
00441   SLOT = &CH->SLOT[SLOT1];
00442   env_out=OPL_CALC_SLOT(SLOT);
00443   if( env_out < EG_ENT-1 )
00444   {
00445     /* PG */
00446     if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
00447     else          SLOT->Cnt += SLOT->Incr;
00448     /* connectoion */
00449     if(CH->FB)
00450     {
00451       int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB;
00452       CH->op1_out[1] = CH->op1_out[0];
00453       *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
00454     }
00455     else
00456     {
00457       *CH->connect1 += OP_OUT(SLOT,env_out,0);
00458     }
00459   }else
00460   {
00461     CH->op1_out[1] = CH->op1_out[0];
00462     CH->op1_out[0] = 0;
00463   }
00464   /* SLOT 2 */
00465   SLOT = &CH->SLOT[SLOT2];
00466   env_out=OPL_CALC_SLOT(SLOT);
00467   if( env_out < EG_ENT-1 )
00468   {
00469     /* PG */
00470     if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
00471     else          SLOT->Cnt += SLOT->Incr;
00472     /* connectoion */
00473     outd[0] += OP_OUT(SLOT,env_out, feedback2);
00474   }
00475 }
00476 
00477 /* ---------- calcrate rythm block ---------- */
00478 #define WHITE_NOISE_db 6.0
00479 inline void OPL_CALC_RH( OPL_CH *CH )
00480 {
00481   uint32 env_tam,env_sd,env_top,env_hh;
00482   int whitenoise = int((std::rand()&1)*(WHITE_NOISE_db/EG_STEP));
00483   int tone8;
00484 
00485   OPL_SLOT *SLOT;
00486   int env_out;
00487 
00488   /* BD : same as FM serial mode and output level is large */
00489   feedback2 = 0;
00490   /* SLOT 1 */
00491   SLOT = &CH[6].SLOT[SLOT1];
00492   env_out=OPL_CALC_SLOT(SLOT);
00493   if( env_out < EG_ENT-1 )
00494   {
00495     /* PG */
00496     if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
00497     else          SLOT->Cnt += SLOT->Incr;
00498     /* connectoion */
00499     if(CH[6].FB)
00500     {
00501       int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB;
00502       CH[6].op1_out[1] = CH[6].op1_out[0];
00503       feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
00504     }
00505     else
00506     {
00507       feedback2 = OP_OUT(SLOT,env_out,0);
00508     }
00509   }else
00510   {
00511     feedback2 = 0;
00512     CH[6].op1_out[1] = CH[6].op1_out[0];
00513     CH[6].op1_out[0] = 0;
00514   }
00515   /* SLOT 2 */
00516   SLOT = &CH[6].SLOT[SLOT2];
00517   env_out=OPL_CALC_SLOT(SLOT);
00518   if( env_out < EG_ENT-1 )
00519   {
00520     /* PG */
00521     if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
00522     else          SLOT->Cnt += SLOT->Incr;
00523     /* connectoion */
00524     outd[0] += OP_OUT(SLOT,env_out, feedback2)*2;
00525   }
00526 
00527   // SD  (17) = mul14[fnum7] + white noise
00528   // TAM (15) = mul15[fnum8]
00529   // TOP (18) = fnum6(mul18[fnum8]+whitenoise)
00530   // HH  (14) = fnum7(mul18[fnum8]+whitenoise) + white noise
00531   env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise;
00532   env_tam=OPL_CALC_SLOT(SLOT8_1);
00533   env_top=OPL_CALC_SLOT(SLOT8_2);
00534   env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise;
00535 
00536   /* PG */
00537   if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE);
00538   else             SLOT7_1->Cnt += 2*SLOT7_1->Incr;
00539   if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE);
00540   else             SLOT7_2->Cnt += (CH[7].fc*8);
00541   if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE);
00542   else             SLOT8_1->Cnt += SLOT8_1->Incr;
00543   if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE);
00544   else             SLOT8_2->Cnt += (CH[8].fc*48);
00545 
00546   tone8 = OP_OUT(SLOT8_2,whitenoise,0 );
00547 
00548   /* SD */
00549   if( env_sd < EG_ENT-1 )
00550     outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8;
00551   /* TAM */
00552   if( env_tam < EG_ENT-1 )
00553     outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2;
00554   /* TOP-CY */
00555   if( env_top < EG_ENT-1 )
00556     outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2;
00557   /* HH */
00558   if( env_hh  < EG_ENT-1 )
00559     outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2;
00560 }
00561 
00562 /* ----------- initialize time tabls ----------- */
00563 static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE )
00564 {
00565   int i;
00566   double rate;
00567 
00568   /* make attack rate & decay rate tables */
00569   for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0;
00570   for (i = 4;i <= 60;i++){
00571     rate  = OPL->freqbase;            /* frequency rate */
00572     if( i < 60 ) rate *= 1.0+(i&3)*0.25;    /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */
00573     rate *= 1<<((i>>2)-1);            /* b2-5 : shift bit */
00574     rate *= (double)(EG_ENT<<ENV_BITS);
00575     OPL->AR_TABLE[i] = (int)(rate / ARRATE);
00576     OPL->DR_TABLE[i] = (int)(rate / DRRATE);
00577   }
00578   for (i = 60;i < 76;i++)
00579   {
00580     OPL->AR_TABLE[i] = EG_AED-1;
00581     OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
00582   }
00583 }
00584 
00585 /* ---------- generic table initialize ---------- */
00586 static int OPLOpenTable( void )
00587 {
00588   int s,t;
00589   double rate;
00590   int i,j;
00591   double pom;
00592 
00593   /* allocate dynamic tables */
00594   if( (TL_TABLE = (int *)malloc(TL_MAX*2*sizeof(int))) == NULL)
00595     return 0;
00596   if( (SIN_TABLE = (int **)malloc(SIN_ENT*4 *sizeof(int *))) == NULL)
00597   {
00598     free(TL_TABLE);
00599     return 0;
00600   }
00601   if( (AMS_TABLE = (int *)malloc(AMS_ENT*2 *sizeof(int))) == NULL)
00602   {
00603     free(TL_TABLE);
00604     free(SIN_TABLE);
00605     return 0;
00606   }
00607   if( (VIB_TABLE = (int *)malloc(VIB_ENT*2 *sizeof(int))) == NULL)
00608   {
00609     free(TL_TABLE);
00610     free(SIN_TABLE);
00611     free(AMS_TABLE);
00612     return 0;
00613   }
00614   /* make total level table */
00615   for (t = 0;t < EG_ENT-1 ;t++){
00616     rate = ((1<<TL_BITS)-1)/std::pow(10,EG_STEP*t/20);  /* dB -> voltage */
00617     TL_TABLE[       t] =  (int)rate;
00618     TL_TABLE[TL_MAX+t] = -TL_TABLE[t];
00619   }
00620   /* fill volume off area */
00621   for ( t = EG_ENT-1; t < TL_MAX ;t++){
00622     TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0;
00623   }
00624 
00625   /* make sinwave table (total level offet) */
00626   /* degree 0 = degree 180                   = off */
00627   SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2]         = &TL_TABLE[EG_ENT-1];
00628   for (s = 1;s <= SIN_ENT/4;s++){
00629     pom = std::sin(2*PI*s/SIN_ENT); /* sin     */
00630     pom = 20*std::log10(1/pom);    /* decibel */
00631     j = int(pom / EG_STEP);         /* TL_TABLE steps */
00632 
00633         /* degree 0   -  90    , degree 180 -  90 : plus section */
00634     SIN_TABLE[          s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j];
00635         /* degree 180 - 270    , degree 360 - 270 : minus section */
00636     SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT  -s] = &TL_TABLE[TL_MAX+j];
00637   }
00638   for (s = 0;s < SIN_ENT;s++)
00639   {
00640     SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT];
00641     SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)];
00642     SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s];
00643   }
00644 
00645   /* envelope counter -> envelope output table */
00646   for (i=0; i<EG_ENT; i++)
00647   {
00648     /* ATTACK curve */
00649     pom = std::pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT;
00650     /* if( pom >= EG_ENT ) pom = EG_ENT-1; */
00651     ENV_CURVE[i] = (int)pom;
00652     /* DECAY ,RELEASE curve */
00653     ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i;
00654   }
00655   /* off */
00656   ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
00657   /* make LFO ams table */
00658   for (i=0; i<AMS_ENT; i++)
00659   {
00660     pom = (1.0+std::sin(2*PI*i/AMS_ENT))/2; /* sin */
00661     AMS_TABLE[i]         = (int)((1.0/EG_STEP)*pom); /* 1dB   */
00662     AMS_TABLE[AMS_ENT+i] = (int)((4.8/EG_STEP)*pom); /* 4.8dB */
00663   }
00664   /* make LFO vibrate table */
00665   for (i=0; i<VIB_ENT; i++)
00666   {
00667     /* 100cent = 1seminote = 6% ?? */
00668     pom = (double)VIB_RATE*0.06*std::sin(2*PI*i/VIB_ENT); /* +-100sect step */
00669     VIB_TABLE[i]         = (int)(VIB_RATE + (pom*0.07)); /* +- 7cent */
00670     VIB_TABLE[VIB_ENT+i] = (int)(VIB_RATE + (pom*0.14)); /* +-14cent */
00671   }
00672   return 1;
00673 }
00674 
00675 
00676 static void OPLCloseTable( void )
00677 {
00678   free(TL_TABLE);
00679   free(SIN_TABLE);
00680   free(AMS_TABLE);
00681   free(VIB_TABLE);
00682 }
00683 
00684 /* CSM Key Controll */
00685 inline void CSMKeyControll(OPL_CH *CH)
00686 {
00687   OPL_SLOT *slot1 = &CH->SLOT[SLOT1];
00688   OPL_SLOT *slot2 = &CH->SLOT[SLOT2];
00689   /* all key off */
00690   OPL_KEYOFF(slot1);
00691   OPL_KEYOFF(slot2);
00692   /* total level latch */
00693   slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
00694   slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
00695   /* key on */
00696   CH->op1_out[0] = CH->op1_out[1] = 0;
00697   OPL_KEYON(slot1);
00698   OPL_KEYON(slot2);
00699 }
00700 
00701 /* ---------- opl initialize ---------- */
00702 static void OPL_initalize(FM_OPL *OPL)
00703 {
00704   int fn;
00705 
00706   /* frequency base */
00707   OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72  : 0;
00708   /* Timer base time */
00709   OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 );
00710   /* make time tables */
00711   init_timetables( OPL , OPL_ARRATE , OPL_DRRATE );
00712   /* make fnumber -> increment counter table */
00713   for( fn=0 ; fn < 1024 ; fn++ )
00714   {
00715     OPL->FN_TABLE[fn] = (uint32)(OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2);
00716   }
00717   /* LFO freq.table */
00718   OPL->amsIncr = (int)(OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0);
00719   OPL->vibIncr = (int)(OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0);
00720 }
00721 
00722 /* ---------- write a OPL registers ---------- */
00723 void OPLWriteReg(FM_OPL *OPL, int r, int v)
00724 {
00725   OPL_CH *CH;
00726   int slot;
00727   uint32 block_fnum;
00728 
00729   switch(r&0xe0)
00730   {
00731   case 0x00: /* 00-1f:controll */
00732     switch(r&0x1f)
00733     {
00734     case 0x01:
00735       /* wave selector enable */
00736       if(OPL->type&OPL_TYPE_WAVESEL)
00737       {
00738         OPL->wavesel = v&0x20;
00739         if(!OPL->wavesel)
00740         {
00741           /* preset compatible mode */
00742           int c;
00743           for(c=0;c<OPL->max_ch;c++)
00744           {
00745             OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
00746             OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
00747           }
00748         }
00749       }
00750       return;
00751     case 0x02:  /* Timer 1 */
00752       OPL->T[0] = (256-v)*4;
00753       break;
00754     case 0x03:  /* Timer 2 */
00755       OPL->T[1] = (256-v)*16;
00756       return;
00757     case 0x04:  /* IRQ clear / mask and Timer enable */
00758       if(v&0x80)
00759       { /* IRQ flag clear */
00760         OPL_STATUS_RESET(OPL,0x7f);
00761       }
00762       else
00763       { /* set IRQ mask ,timer enable*/
00764         uint8 st1 = v&1;
00765         uint8 st2 = (v>>1)&1;
00766         /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
00767         OPL_STATUS_RESET(OPL,v&0x78);
00768         OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01);
00769         /* timer 2 */
00770         if(OPL->st[1] != st2)
00771         {
00772           double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0;
00773           OPL->st[1] = st2;
00774           if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval);
00775         }
00776         /* timer 1 */
00777         if(OPL->st[0] != st1)
00778         {
00779           double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0;
00780           OPL->st[0] = st1;
00781           if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval);
00782         }
00783       }
00784       return;
00785     }
00786     break;
00787   case 0x20:  /* am,vib,ksr,eg type,mul */
00788     slot = slot_array[r&0x1f];
00789     if(slot == -1) return;
00790     set_mul(OPL,slot,v);
00791     return;
00792   case 0x40:
00793     slot = slot_array[r&0x1f];
00794     if(slot == -1) return;
00795     set_ksl_tl(OPL,slot,v);
00796     return;
00797   case 0x60:
00798     slot = slot_array[r&0x1f];
00799     if(slot == -1) return;
00800     set_ar_dr(OPL,slot,v);
00801     return;
00802   case 0x80:
00803     slot = slot_array[r&0x1f];
00804     if(slot == -1) return;
00805     set_sl_rr(OPL,slot,v);
00806     return;
00807   case 0xa0:
00808     switch(r)
00809     {
00810     case 0xbd:
00811       /* amsep,vibdep,r,bd,sd,tom,tc,hh */
00812       {
00813       uint8 rkey = OPL->rythm^v;
00814       OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
00815       OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
00816       OPL->rythm  = v&0x3f;
00817       if(OPL->rythm&0x20)
00818       {
00819         /* BD key on/off */
00820         if(rkey&0x10)
00821         {
00822           if(v&0x10)
00823           {
00824             OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0;
00825             OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]);
00826             OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]);
00827           }
00828           else
00829           {
00830             OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]);
00831             OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]);
00832           }
00833         }
00834         /* SD key on/off */
00835         if(rkey&0x08)
00836         {
00837           if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]);
00838           else       OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]);
00839         }/* TAM key on/off */
00840         if(rkey&0x04)
00841         {
00842           if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]);
00843           else       OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]);
00844         }
00845         /* TOP-CY key on/off */
00846         if(rkey&0x02)
00847         {
00848           if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]);
00849           else       OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]);
00850         }
00851         /* HH key on/off */
00852         if(rkey&0x01)
00853         {
00854           if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]);
00855           else       OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]);
00856         }
00857       }
00858       }
00859       return;
00860     }
00861     /* keyon,block,fnum */
00862     if( (r&0x0f) > 8) return;
00863     CH = &OPL->P_CH[r&0x0f];
00864     if(!(r&0x10))
00865     { /* a0-a8 */
00866       block_fnum  = (CH->block_fnum&0x1f00) | v;
00867     }
00868     else
00869     { /* b0-b8 */
00870       int keyon = (v>>5)&1;
00871       block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);
00872       if(CH->keyon != keyon)
00873       {
00874         if( (CH->keyon=keyon) )
00875         {
00876           CH->op1_out[0] = CH->op1_out[1] = 0;
00877           OPL_KEYON(&CH->SLOT[SLOT1]);
00878           OPL_KEYON(&CH->SLOT[SLOT2]);
00879         }
00880         else
00881         {
00882           OPL_KEYOFF(&CH->SLOT[SLOT1]);
00883           OPL_KEYOFF(&CH->SLOT[SLOT2]);
00884         }
00885       }
00886     }
00887     /* update */
00888     if(CH->block_fnum != block_fnum)
00889     {
00890       int blockRv = 7-(block_fnum>>10);
00891       int fnum   = block_fnum&0x3ff;
00892       CH->block_fnum = block_fnum;
00893 
00894       CH->ksl_base = KSL_TABLE[block_fnum>>6];
00895       CH->fc = OPL->FN_TABLE[fnum]>>blockRv;
00896       CH->kcode = CH->block_fnum>>9;
00897       if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1;
00898       CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
00899       CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
00900     }
00901     return;
00902   case 0xc0:
00903     /* FB,C */
00904     if( (r&0x0f) > 8) return;
00905     CH = &OPL->P_CH[r&0x0f];
00906     {
00907     int feedback = (v>>1)&7;
00908     CH->FB   = feedback ? (8+1) - feedback : 0;
00909     CH->CON = v&1;
00910     set_algorythm(CH);
00911     }
00912     return;
00913   case 0xe0: /* wave type */
00914     slot = slot_array[r&0x1f];
00915     if(slot == -1) return;
00916     CH = &OPL->P_CH[slot/2];
00917     if(OPL->wavesel)
00918     {
00919       CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT];
00920     }
00921     return;
00922   }
00923 }
00924 
00925 /* lock/unlock for common table */
00926 static int OPL_LockTable(void)
00927 {
00928   num_lock++;
00929   if(num_lock>1) return 0;
00930   /* first time */
00931   cur_chip = NULL;
00932   /* allocate total level table (128kb space) */
00933   if( !OPLOpenTable() )
00934   {
00935     num_lock--;
00936     return -1;
00937   }
00938   return 0;
00939 }
00940 
00941 static void OPL_UnLockTable(void)
00942 {
00943   if(num_lock) num_lock--;
00944   if(num_lock) return;
00945   /* last time */
00946   cur_chip = NULL;
00947   OPLCloseTable();
00948 }
00949 
00950 /*******************************************************************************/
00951 /*    YM3812 local section                                                   */
00952 /*******************************************************************************/
00953 
00954 /* ---------- update one of chip ----------- */
00955 void YM3812UpdateOne(FM_OPL *OPL, sint16 *buffer, int length)
00956 {
00957     int i;
00958   int data;
00959   sint16 *buf = buffer;
00960   uint32 amsCnt  = OPL->amsCnt;
00961   uint32 vibCnt  = OPL->vibCnt;
00962   uint8 rythm = OPL->rythm&0x20;
00963   OPL_CH *CH,*R_CH;
00964 
00965   if( (void *)OPL != cur_chip ){
00966     cur_chip = (void *)OPL;
00967     /* channel pointers */
00968     S_CH = OPL->P_CH;
00969     E_CH = &S_CH[9];
00970     /* rythm slot */
00971     SLOT7_1 = &S_CH[7].SLOT[SLOT1];
00972     SLOT7_2 = &S_CH[7].SLOT[SLOT2];
00973     SLOT8_1 = &S_CH[8].SLOT[SLOT1];
00974     SLOT8_2 = &S_CH[8].SLOT[SLOT2];
00975     /* LFO state */
00976     amsIncr = OPL->amsIncr;
00977     vibIncr = OPL->vibIncr;
00978     ams_table = OPL->ams_table;
00979     vib_table = OPL->vib_table;
00980   }
00981   R_CH = rythm ? &S_CH[6] : E_CH;
00982     for( i=0; i < length ; i++ )
00983   {
00984     /*            channel A         channel B         channel C      */
00985     /* LFO */
00986     ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
00987     vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
00988     outd[0] = 0;
00989     /* FM part */
00990     for(CH=S_CH ; CH < R_CH ; CH++)
00991       OPL_CALC_CH(CH);
00992     /* Rythn part */
00993     if(rythm)
00994       OPL_CALC_RH(S_CH);
00995     /* limit check */
00996     data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
00997     /* store to sound buffer */
00998     buf[i] = data >> OPL_OUTSB;
00999   }
01000 
01001   OPL->amsCnt = amsCnt;
01002   OPL->vibCnt = vibCnt;
01003 }
01004 
01005 /* ---------- reset a chip ---------- */
01006 void OPLResetChip(FM_OPL *OPL)
01007 {
01008   int c,s;
01009   int i;
01010 
01011   /* reset chip */
01012   OPL->mode   = 0;  /* normal mode */
01013   OPL_STATUS_RESET(OPL,0x7f);
01014   /* reset with register write */
01015   OPLWriteReg(OPL,0x01,0); /* wabesel disable */
01016   OPLWriteReg(OPL,0x02,0); /* Timer1 */
01017   OPLWriteReg(OPL,0x03,0); /* Timer2 */
01018   OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */
01019   for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0);
01020   /* reset OPerator paramater */
01021   for( c = 0 ; c < OPL->max_ch ; c++ )
01022   {
01023     OPL_CH *CH = &OPL->P_CH[c];
01024     /* OPL->P_CH[c].PAN = OPN_CENTER; */
01025     for(s = 0 ; s < 2 ; s++ )
01026     {
01027       /* wave table */
01028       CH->SLOT[s].wavetable = &SIN_TABLE[0];
01029       /* CH->SLOT[s].evm = ENV_MOD_RR; */
01030       CH->SLOT[s].evc = EG_OFF;
01031       CH->SLOT[s].eve = EG_OFF+1;
01032       CH->SLOT[s].evs = 0;
01033     }
01034   }
01035 }
01036 
01037 /* ----------  Create a virtual YM3812 ----------       */
01038 /* 'rate'  is sampling rate and 'bufsiz' is the size of the  */
01039 FM_OPL *OPLCreate(int type, int clock, int rate)
01040 {
01041   char *ptr;
01042   FM_OPL *OPL;
01043   int state_size;
01044   int max_ch = 9; /* normaly 9 channels */
01045 
01046   if( OPL_LockTable() ==-1) return NULL;
01047   /* allocate OPL state space */
01048   state_size  = sizeof(FM_OPL);
01049   state_size += sizeof(OPL_CH)*max_ch;
01050 
01051   /* allocate memory block */
01052   ptr = (char *)malloc(state_size);
01053   if(ptr==NULL) return NULL;
01054 
01055   /* clear */
01056   memset(ptr,0,state_size);
01057   OPL        = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
01058   OPL->P_CH  = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
01059 
01060   /* set channel state pointer */
01061   OPL->type  = type;
01062   OPL->clock = clock;
01063   OPL->rate  = rate;
01064   OPL->max_ch = max_ch;
01065 
01066   /* init grobal tables */
01067   OPL_initalize(OPL);
01068 
01069   /* reset chip */
01070   OPLResetChip(OPL);
01071   return OPL;
01072 }
01073 
01074 /* ----------  Destroy one of vietual YM3812 ----------       */
01075 void OPLDestroy(FM_OPL *OPL)
01076 {
01077   OPL_UnLockTable();
01078   free(OPL);
01079 }
01080 
01081 /* ----------  Option handlers ----------       */
01082 
01083 void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset)
01084 {
01085   OPL->TimerHandler   = TimerHandler;
01086   OPL->TimerParam = channelOffset;
01087 }
01088 void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param)
01089 {
01090   OPL->IRQHandler     = IRQHandler;
01091   OPL->IRQParam = param;
01092 }
01093 void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param)
01094 {
01095   OPL->UpdateHandler = UpdateHandler;
01096   OPL->UpdateParam = param;
01097 }
01098 
01099 /* ---------- YM3812 I/O interface ---------- */
01100 int OPLWrite(FM_OPL *OPL,int a,int v)
01101 {
01102   if( !(a&1) )
01103   { /* address port */
01104     OPL->address = v & 0xff;
01105   }
01106   else
01107   { /* data port */
01108     if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
01109     OPLWriteReg(OPL,OPL->address,v);
01110   }
01111   return OPL->status>>7;
01112 }
01113 
01114 unsigned char OPLRead(FM_OPL *OPL,int a)
01115 {
01116   if( !(a&1) )
01117   { /* status port */
01118     return OPL->status & (OPL->statusmask|0x80);
01119   }
01120   /* data port */
01121   switch(OPL->address)
01122   {
01123   case 0x05: /* KeyBoard IN */
01124     CERR(("OPL:read unmapped KEYBOARD port\n"));
01125     return 0;
01126   case 0x19: /* I/O DATA    */
01127     CERR(("OPL:read unmapped I/O port\n"));
01128     return 0;
01129   case 0x1a: /* PCM-DATA    */
01130     return 0;
01131   }
01132   return 0;
01133 }
01134 
01135 int OPLTimerOver(FM_OPL *OPL,int c)
01136 {
01137   if( c )
01138   { /* Timer B */
01139     OPL_STATUS_SET(OPL,0x20);
01140   }
01141   else
01142   { /* Timer A */
01143     OPL_STATUS_SET(OPL,0x40);
01144     /* CSM mode key,TL controll */
01145     if( OPL->mode & 0x80 )
01146     { /* CSM mode total level latch and auto key on */
01147       int ch;
01148       if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
01149       for(ch=0;ch<9;ch++)
01150         CSMKeyControll( &OPL->P_CH[ch] );
01151     }
01152   }
01153   /* reload timer */
01154   if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase);
01155   return OPL->status>>7;
01156 }
01157 
01158 #endif //USE_FMOPL_MIDI

Generated on Mon Jul 9 14:42:40 2007 for ExultEngine by  doxygen 1.5.1