DOSBox-X
|
00001 #include "np2glue.h" 00002 //#include "compiler.h" 00003 #include <math.h> 00004 //#include "pccore.h" 00005 //#include "iocore.h" 00006 #include "sound.h" 00007 #include "fmboard.h" 00008 //#include "keydisp.h" 00009 00010 00011 #define OPM_ARRATE 399128L 00012 #define OPM_DRRATE 5514396L 00013 00014 #define EG_STEP (96.0 / EVC_ENT) // dB step 00015 #define SC(db) (SINT32)((db) * ((3.0 / EG_STEP) * (1 << ENV_BITS))) + EC_DECAY 00016 #define D2(v) (((double)(6 << KF_BITS) * log((double)(v)) / log(2.0)) + 0.5) 00017 #define FMASMSHIFT (32 - 6 - (OPM_OUTSB + 1 + FMDIV_BITS) + FMVOL_SFTBIT) 00018 #define FREQBASE4096 ((double)OPNA_CLOCK / calcrate / 64) 00019 00020 00021 OPNCFG opncfg; 00022 #ifdef OPNGENX86 00023 char envshift[EVC_ENT]; 00024 char sinshift[SIN_ENT]; 00025 #endif 00026 00027 00028 static SINT32 detunetable[8][32]; 00029 static SINT32 attacktable[94]; 00030 static SINT32 decaytable[94]; 00031 00032 static const SINT32 decayleveltable[16] = { 00033 SC( 0),SC( 1),SC( 2),SC( 3),SC( 4),SC( 5),SC( 6),SC( 7), 00034 SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)}; 00035 static const UINT8 multipletable[] = { 00036 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30}; 00037 static const SINT32 nulltable[] = { 00038 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 00039 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 00040 static const UINT8 kftable[16] = {0,0,0,0,0,0,0,1,2,3,3,3,3,3,3,3}; 00041 static const UINT8 dttable[] = { 00042 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00043 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00044 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 00045 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8, 00046 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 00047 5, 6, 6, 7, 8, 8, 9,10,11,12,13,14,16,16,16,16, 00048 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 00049 8, 8, 9,10,11,12,13,14,16,17,19,20,22,22,22,22}; 00050 static const int extendslot[4] = {2, 3, 1, 0}; 00051 static const int fmslot[4] = {0, 2, 1, 3}; 00052 00053 00054 void opngen_initialize(UINT rate) { 00055 00056 UINT ratebit; 00057 int i; 00058 char sft; 00059 int j; 00060 double pom; 00061 long detune; 00062 UINT32 calcrate; 00063 00064 if (rate == 44100) { 00065 ratebit = 0; 00066 } 00067 else if (rate == 22050) { 00068 ratebit = 1; 00069 } 00070 else { 00071 ratebit = 2; 00072 } 00073 calcrate = (OPNA_CLOCK / 72) >> ratebit; 00074 opncfg.calc1024 = FMDIV_ENT * 44100 / (OPNA_CLOCK / 72); 00075 00076 for (i=0; i<EVC_ENT; i++) { 00077 #ifdef OPNGENX86 00078 sft = ENVTBL_BIT; 00079 while(sft < (ENVTBL_BIT + 8)) { 00080 pom = (double)(1 << sft) / pow(10.0, EG_STEP*(EVC_ENT-i)/20.0); 00081 opncfg.envtable[i] = (long)pom; 00082 envshift[i] = sft - TL_BITS; 00083 if (opncfg.envtable[i] >= (1 << (ENVTBL_BIT - 1))) { 00084 break; 00085 } 00086 sft++; 00087 } 00088 #else 00089 pom = (double)(1 << ENVTBL_BIT) / pow(10.0, EG_STEP*(EVC_ENT-i)/20.0); 00090 opncfg.envtable[i] = (long)pom; 00091 #endif 00092 } 00093 for (i=0; i<SIN_ENT; i++) { 00094 #ifdef OPNGENX86 00095 char sft; 00096 sft = SINTBL_BIT; 00097 while(sft < (SINTBL_BIT + 8)) { 00098 pom = (double)(1 << sft) * sin(2*PI*i/SIN_ENT); 00099 opncfg.sintable[i] = (long)pom; 00100 sinshift[i] = sft; 00101 if (opncfg.sintable[i] >= (1 << (SINTBL_BIT - 1))) { 00102 break; 00103 } 00104 if (opncfg.sintable[i] <= -1 * (1 << (SINTBL_BIT - 1))) { 00105 break; 00106 } 00107 sft++; 00108 } 00109 #else 00110 pom = (double)((1 << SINTBL_BIT) - 1) * sin(2*PI*i/SIN_ENT); 00111 opncfg.sintable[i] = (long)pom; 00112 #endif 00113 } 00114 for (i=0; i<EVC_ENT; i++) { 00115 pom = pow(((double)(EVC_ENT-1-i)/EVC_ENT), 8) * EVC_ENT; 00116 opncfg.envcurve[i] = (long)pom; 00117 opncfg.envcurve[EVC_ENT + i] = i; 00118 } 00119 opncfg.envcurve[EVC_ENT*2] = EVC_ENT; 00120 00121 // opmbaserate = (1L << FREQ_BITS) / (rate * x / 44100) * 55466; 00122 // でも今は x == 55466だから… 00123 00124 // ここで FREQ_BITS >= 16が条件 00125 if (rate == 44100) { 00126 opncfg.ratebit = 0 + (FREQ_BITS - 16); 00127 } 00128 else if (rate == 22050) { 00129 opncfg.ratebit = 1 + (FREQ_BITS - 16); 00130 } 00131 else { 00132 opncfg.ratebit = 2 + (FREQ_BITS - 16); 00133 } 00134 00135 for (i=0; i<4; i++) { 00136 for (j=0; j<32; j++) { 00137 detune = dttable[i*32 + j]; 00138 sft = ratebit + (FREQ_BITS - 21); 00139 if (sft >= 0) { 00140 detune <<= sft; 00141 } 00142 else { 00143 detune >>= (0 - sft); 00144 } 00145 00146 detunetable[i][j] = detune; 00147 detunetable[i+4][j] = -detune; 00148 } 00149 } 00150 for (i=0; i<4; i++) { 00151 attacktable[i] = decaytable[i] = 0; 00152 } 00153 for (i=4; i<64; i++) { 00154 double freq = (double)(EVC_ENT << ENV_BITS) * FREQBASE4096; 00155 if (i < 8) { // 忘れてます。 00156 freq *= 1.0 + (i & 2) * 0.25; 00157 } 00158 else if (i < 60) { 00159 freq *= 1.0 + (i & 3) * 0.25; 00160 } 00161 freq *= (double)(1 << ((i >> 2) - 1)); 00162 #if 0 00163 attacktable[i] = (long)((freq + OPM_ARRATE - 1) / OPM_ARRATE); 00164 decaytable[i] = (long)((freq + OPM_DRRATE - 1) / OPM_DRRATE); 00165 #else 00166 attacktable[i] = (long)(freq / OPM_ARRATE); 00167 decaytable[i] = (long)(freq / OPM_DRRATE); 00168 #endif 00169 if (attacktable[i] >= EC_DECAY) { 00170 TRACEOUT(("attacktable %d %d %ld", i, attacktable[i], EC_DECAY)); 00171 } 00172 if (decaytable[i] >= EC_DECAY) { 00173 TRACEOUT(("decaytable %d %d %ld", i, decaytable[i], EC_DECAY)); 00174 } 00175 } 00176 attacktable[62] = EC_DECAY - 1; 00177 attacktable[63] = EC_DECAY - 1; 00178 for (i=64; i<94; i++) { 00179 attacktable[i] = attacktable[63]; 00180 decaytable[i] = decaytable[63]; 00181 } 00182 } 00183 00184 void opngen_setvol(UINT vol) { 00185 00186 opncfg.fmvol = vol * 5 / 4; 00187 #if defined(OPNGENX86) 00188 opncfg.fmvol <<= FMASMSHIFT; 00189 #endif 00190 } 00191 00192 void opngen_setVR(REG8 channel, REG8 value) { 00193 00194 if ((channel & 3) && (value)) { 00195 opncfg.vr_en = TRUE; 00196 opncfg.vr_l = (channel & 1)?value:0; 00197 opncfg.vr_r = (channel & 2)?value:0; 00198 } 00199 else { 00200 opncfg.vr_en = FALSE; 00201 } 00202 } 00203 00204 00205 // ---- 00206 00207 static void set_algorithm(OPNCH *ch) { 00208 00209 SINT32 *outd; 00210 UINT8 outslot; 00211 00212 outd = &opngen.outdc; 00213 if (ch->stereo) { 00214 switch(ch->pan & 0xc0) { 00215 case 0x80: 00216 outd = &opngen.outdl; 00217 break; 00218 00219 case 0x40: 00220 outd = &opngen.outdr; 00221 break; 00222 } 00223 } 00224 switch(ch->algorithm) { 00225 case 0: 00226 ch->connect1 = &opngen.feedback2; 00227 ch->connect2 = &opngen.feedback3; 00228 ch->connect3 = &opngen.feedback4; 00229 outslot = 0x08; 00230 break; 00231 00232 case 1: 00233 ch->connect1 = &opngen.feedback3; 00234 ch->connect2 = &opngen.feedback3; 00235 ch->connect3 = &opngen.feedback4; 00236 outslot = 0x08; 00237 break; 00238 00239 case 2: 00240 ch->connect1 = &opngen.feedback4; 00241 ch->connect2 = &opngen.feedback3; 00242 ch->connect3 = &opngen.feedback4; 00243 outslot = 0x08; 00244 break; 00245 00246 case 3: 00247 ch->connect1 = &opngen.feedback2; 00248 ch->connect2 = &opngen.feedback4; 00249 ch->connect3 = &opngen.feedback4; 00250 outslot = 0x08; 00251 break; 00252 00253 case 4: 00254 ch->connect1 = &opngen.feedback2; 00255 ch->connect2 = outd; 00256 ch->connect3 = &opngen.feedback4; 00257 outslot = 0x0a; 00258 break; 00259 00260 case 5: 00261 ch->connect1 = 0; 00262 ch->connect2 = outd; 00263 ch->connect3 = outd; 00264 outslot = 0x0e; 00265 break; 00266 00267 case 6: 00268 ch->connect1 = &opngen.feedback2; 00269 ch->connect2 = outd; 00270 ch->connect3 = outd; 00271 outslot = 0x0e; 00272 break; 00273 00274 case 7: 00275 default: 00276 ch->connect1 = outd; 00277 ch->connect2 = outd; 00278 ch->connect3 = outd; 00279 outslot = 0x0f; 00280 } 00281 ch->connect4 = outd; 00282 ch->outslot = outslot; 00283 } 00284 00285 static void set_dt1_mul(OPNSLOT *slot, REG8 value) { 00286 00287 slot->multiple = (SINT32)multipletable[value & 0x0f]; 00288 slot->detune1 = detunetable[(value >> 4) & 7]; 00289 } 00290 00291 static void set_tl(OPNSLOT *slot, REG8 value) { 00292 00293 #if (EVC_BITS >= 7) 00294 slot->totallevel = ((~value) & 0x007f) << (EVC_BITS - 7); 00295 #else 00296 slot->totallevel = ((~value) & 0x007f) >> (7 - EVC_BITS); 00297 #endif 00298 } 00299 00300 static void set_ks_ar(OPNSLOT *slot, REG8 value) { 00301 00302 slot->keyscale = ((~value) >> 6) & 3; 00303 value &= 0x1f; 00304 slot->attack = (value)?(attacktable + (value << 1)):nulltable; 00305 slot->env_inc_attack = slot->attack[slot->envratio]; 00306 if (slot->env_mode == EM_ATTACK) { 00307 slot->env_inc = slot->env_inc_attack; 00308 } 00309 } 00310 00311 static void set_d1r(OPNSLOT *slot, REG8 value) { 00312 00313 value &= 0x1f; 00314 slot->decay1 = (value)?(decaytable + (value << 1)):nulltable; 00315 slot->env_inc_decay1 = slot->decay1[slot->envratio]; 00316 if (slot->env_mode == EM_DECAY1) { 00317 slot->env_inc = slot->env_inc_decay1; 00318 } 00319 } 00320 00321 static void set_dt2_d2r(OPNSLOT *slot, REG8 value) { 00322 00323 value &= 0x1f; 00324 slot->decay2 = (value)?(decaytable + (value << 1)):nulltable; 00325 if (slot->ssgeg1) { 00326 slot->env_inc_decay2 = 0; 00327 } 00328 else { 00329 slot->env_inc_decay2 = slot->decay2[slot->envratio]; 00330 } 00331 if (slot->env_mode == EM_DECAY2) { 00332 slot->env_inc = slot->env_inc_decay2; 00333 } 00334 } 00335 00336 static void set_d1l_rr(OPNSLOT *slot, REG8 value) { 00337 00338 slot->decaylevel = decayleveltable[value >> 4]; 00339 slot->release = decaytable + ((value & 0x0f) << 2) + 2; 00340 slot->env_inc_release = slot->release[slot->envratio]; 00341 if (slot->env_mode == EM_RELEASE) { 00342 slot->env_inc = slot->env_inc_release; 00343 if (value == 0xff) { 00344 slot->env_mode = EM_OFF; 00345 slot->env_cnt = EC_OFF; 00346 slot->env_end = EC_OFF + 1; 00347 slot->env_inc = 0; 00348 } 00349 } 00350 } 00351 00352 static void set_ssgeg(OPNSLOT *slot, REG8 value) { 00353 00354 value &= 0xf; 00355 if ((value == 0xb) || (value == 0xd)) { 00356 slot->ssgeg1 = 1; 00357 slot->env_inc_decay2 = 0; 00358 } 00359 else { 00360 slot->ssgeg1 = 0; 00361 slot->env_inc_decay2 = slot->decay2[slot->envratio]; 00362 } 00363 if (slot->env_mode == EM_DECAY2) { 00364 slot->env_inc = slot->env_inc_decay2; 00365 } 00366 } 00367 00368 static void channleupdate(OPNCH *ch) { 00369 00370 int i; 00371 UINT32 fc = ch->keynote[0]; // ver0.27 00372 UINT8 kc = ch->kcode[0]; 00373 UINT evr; 00374 OPNSLOT *slot; 00375 00376 slot = ch->slot; 00377 if (!(ch->extop)) { 00378 for (i=0; i<4; i++, slot++) { 00379 slot->freq_inc = (fc + slot->detune1[kc]) * slot->multiple; 00380 evr = kc >> slot->keyscale; 00381 if (slot->envratio != evr) { 00382 slot->envratio = evr; 00383 slot->env_inc_attack = slot->attack[evr]; 00384 slot->env_inc_decay1 = slot->decay1[evr]; 00385 slot->env_inc_decay2 = slot->decay2[evr]; 00386 slot->env_inc_release = slot->release[evr]; 00387 } 00388 } 00389 } 00390 else { 00391 for (i=0; i<4; i++, slot++) { 00392 int s = extendslot[i]; 00393 slot->freq_inc = (ch->keynote[s] + slot->detune1[ch->kcode[s]]) 00394 * slot->multiple; 00395 evr = ch->kcode[s] >> slot->keyscale; 00396 if (slot->envratio != evr) { 00397 slot->envratio = evr; 00398 slot->env_inc_attack = slot->attack[evr]; 00399 slot->env_inc_decay1 = slot->decay1[evr]; 00400 slot->env_inc_decay2 = slot->decay2[evr]; 00401 slot->env_inc_release = slot->release[evr]; 00402 } 00403 } 00404 } 00405 } 00406 00407 00408 // ---- 00409 00410 void opngen_reset(void) { 00411 00412 OPNCH *ch; 00413 UINT i; 00414 UINT j; 00415 00416 ZeroMemory(&opngen, sizeof(opngen)); 00417 ZeroMemory(opnch, sizeof(opnch)); 00418 opngen.playchannels = 3; 00419 00420 ch = opnch; 00421 for (i=0; i<OPNCH_MAX; i++) { 00422 ch->keynote[0] = 0; 00423 OPNSLOT *slot = ch->slot; 00424 for (j=0; j<4; j++) { 00425 slot->env_mode = EM_OFF; 00426 slot->env_cnt = EC_OFF; 00427 slot->env_end = EC_OFF + 1; 00428 slot->env_inc = 0; 00429 slot->detune1 = detunetable[0]; 00430 slot->attack = nulltable; 00431 slot->decay1 = nulltable; 00432 slot->decay2 = nulltable; 00433 slot->release = decaytable; 00434 slot++; 00435 } 00436 ch++; 00437 } 00438 for (i=0x30; i<0xc0; i++) { 00439 opngen_setreg(0, i, 0xff); 00440 opngen_setreg(3, i, 0xff); 00441 opngen_setreg(6, i, 0xff); 00442 opngen_setreg(9, i, 0xff); 00443 } 00444 } 00445 00446 void opngen_setcfg(REG8 maxch, UINT32 flag) { 00447 00448 OPNCH *ch; 00449 UINT i; 00450 00451 opngen.playchannels = maxch; 00452 ch = opnch; 00453 if ((flag & OPN_CHMASK) == OPN_STEREO) { 00454 for (i=0; i<OPNCH_MAX; i++) { 00455 if (flag & (1 << i)) { 00456 ch->stereo = TRUE; 00457 set_algorithm(ch); 00458 } 00459 ch++; 00460 } 00461 } 00462 else { 00463 for (i=0; i<OPNCH_MAX; i++) { 00464 if (flag & (1 << i)) { 00465 ch->stereo = FALSE; 00466 set_algorithm(ch); 00467 } 00468 ch++; 00469 } 00470 } 00471 } 00472 00473 void opngen_setextch(UINT chnum, REG8 data) { 00474 00475 OPNCH *ch; 00476 00477 ch = opnch; 00478 ch[chnum].extop = data; 00479 } 00480 00481 void opngen_setreg(REG8 chbase, UINT reg, REG8 value) { 00482 00483 UINT chpos; 00484 OPNCH *ch; 00485 00486 chpos = reg & 3; 00487 if (chpos == 3) { 00488 return; 00489 } 00490 sound_sync(); 00491 ch = opnch + chbase + chpos; 00492 if (reg < 0xa0) { 00493 OPNSLOT *slot = ch->slot + fmslot[(reg >> 2) & 3]; 00494 switch(reg & 0xf0) { 00495 case 0x30: // DT1 MUL 00496 set_dt1_mul(slot, value); 00497 channleupdate(ch); 00498 break; 00499 00500 case 0x40: // TL 00501 set_tl(slot, value); 00502 break; 00503 00504 case 0x50: // KS AR 00505 set_ks_ar(slot, value); 00506 channleupdate(ch); 00507 break; 00508 00509 case 0x60: // D1R 00510 set_d1r(slot, value); 00511 break; 00512 00513 case 0x70: // DT2 D2R 00514 set_dt2_d2r(slot, value); 00515 channleupdate(ch); 00516 break; 00517 00518 case 0x80: // D1L RR 00519 set_d1l_rr(slot, value); 00520 break; 00521 00522 case 0x90: 00523 set_ssgeg(slot, value); 00524 channleupdate(ch); 00525 break; 00526 } 00527 } 00528 else { 00529 UINT fn; 00530 UINT8 blk; 00531 switch(reg & 0xfc) { 00532 case 0xa0: 00533 blk = ch->keyfunc[0] >> 3; 00534 fn = ((ch->keyfunc[0] & 7) << 8) + value; 00535 ch->kcode[0] = (blk << 2) | kftable[fn >> 7]; 00536 // ch->keynote[0] = fn * opmbaserate / (1L << (22-blk)); 00537 ch->keynote[0] = (fn << (opncfg.ratebit + blk)) >> 6; 00538 channleupdate(ch); 00539 break; 00540 00541 case 0xa4: 00542 ch->keyfunc[0] = value & 0x3f; 00543 break; 00544 00545 case 0xa8: 00546 ch = opnch + chbase + 2; 00547 blk = ch->keyfunc[chpos+1] >> 3; 00548 fn = ((ch->keyfunc[chpos+1] & 7) << 8) + value; 00549 ch->kcode[chpos+1] = (blk << 2) | kftable[fn >> 7]; 00550 // ch->keynote[chpos+1] = fn * opmbaserate / (1L << (22-blk)); 00551 ch->keynote[chpos+1] = (fn << (opncfg.ratebit + blk)) >> 6; 00552 channleupdate(ch); 00553 break; 00554 00555 case 0xac: 00556 ch = opnch + chbase + 2; 00557 ch->keyfunc[chpos+1] = value & 0x3f; 00558 break; 00559 00560 case 0xb0: 00561 ch->algorithm = (UINT8)(value & 7); 00562 value = (value >> 3) & 7; 00563 if (value) { 00564 ch->feedback = 8 - value; 00565 } 00566 else { 00567 ch->feedback = 0; 00568 } 00569 set_algorithm(ch); 00570 break; 00571 00572 case 0xb4: 00573 ch->pan = (UINT8)(value & 0xc0); 00574 set_algorithm(ch); 00575 break; 00576 } 00577 } 00578 } 00579 00580 void opngen_keyon(UINT chnum, REG8 value) { 00581 00582 OPNCH *ch; 00583 OPNSLOT *slot; 00584 REG8 bit; 00585 UINT i; 00586 00587 sound_sync(); 00588 opngen.keyreg[chnum] = value; 00589 opngen.playing++; 00590 ch = opnch + chnum; 00591 ch->playing |= value >> 4; 00592 slot = ch->slot; 00593 bit = 0x10; 00594 for (i=0; i<4; i++) { 00595 if (value & bit) { // keyon 00596 if (slot->env_mode <= EM_RELEASE) { 00597 slot->freq_cnt = 0; 00598 if (i == OPNSLOT1) { 00599 ch->op1fb = 0; 00600 } 00601 slot->env_mode = EM_ATTACK; 00602 slot->env_inc = slot->env_inc_attack; 00603 slot->env_cnt = EC_ATTACK; 00604 slot->env_end = EC_DECAY; 00605 } 00606 } 00607 else { // keyoff 00608 if (slot->env_mode > EM_RELEASE) { 00609 slot->env_mode = EM_RELEASE; 00610 if (!(slot->env_cnt & EC_DECAY)) { 00611 slot->env_cnt = (opncfg.envcurve[slot->env_cnt 00612 >> ENV_BITS] << ENV_BITS) + EC_DECAY; 00613 } 00614 slot->env_end = EC_OFF; 00615 slot->env_inc = slot->env_inc_release; 00616 } 00617 } 00618 slot++; 00619 bit <<= 1; 00620 } 00621 // keydisp_fmkeyon((UINT8)chnum, value); 00622 } 00623