ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

mame.cpp

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


Generated on Sat Mar 23 2019 05:01:49 for ResidualVM by doxygen 1.7.1
curved edge   curved edge