/* connect for SLOT 2 */ /* set algorythm connection */ static void set_algorythm(OPL_CH CH) { var carrier = new Func <int,int>(index => outd[index]); CH.connect1 = CH.CON != 0 ? carrier : new Func <int,int>(index => feedback2 + index); CH.connect2 = carrier; }
/* ---------- calcrate one of channel ---------- */ void OPL_CALC_CH(OPL_CH CH) { uint env_out; OPL_SLOT*SLOT; feedback2 = 0; /* SLOT 1 */ SLOT = &CH.SLOT[SLOT1]; env_out = OPL_CALC_SLOT(SLOT); if (env_out < (uint)(EG_ENT - 1)) { /* PG */ if (SLOT.vib) { SLOT.Cnt += (SLOT.Incr * vib) >> VIB_RATE_SHIFT; } else { SLOT.Cnt += SLOT.Incr; } /* connection */ if (CH.FB) { int feedback1 = (CH.op1_out[0] + CH.op1_out[1]) >> CH.FB; CH.op1_out[1] = CH.op1_out[0]; *CH.connect1 += CH.op1_out[0] = OP_OUT(SLOT,env_out,feedback1); } else { *CH.connect1 += OP_OUT(SLOT,env_out,0); } } else { CH.op1_out[1] = CH.op1_out[0]; CH.op1_out[0] = 0; } /* SLOT 2 */ SLOT = &CH.SLOT[SLOT2]; env_out = OPL_CALC_SLOT(SLOT); if (env_out < (uint)(EG_ENT - 1)) { /* PG */ if (SLOT.vib) { SLOT.Cnt += (SLOT.Incr * vib) >> VIB_RATE_SHIFT; } else { SLOT.Cnt += SLOT.Incr; } /* connection */ outd[0] += OP_OUT(SLOT,env_out,feedback2); } }
/* set multi,am,vib,EG-TYP,KSR,mul */ void set_mul(int slot,int v) { OPL_CH CH = P_CH[slot >> 1]; OPL_SLOT SLOT = CH.SLOT[slot & 1]; SLOT.mul = MUL_TABLE[v & 0x0f]; SLOT.KSR = (v & 0x10) != 0 ? (byte)0 : (byte)2; SLOT.eg_typ = (byte)((v & 0x20) >> 5); SLOT.vib = (byte)(v & 0x40); SLOT.ams = (byte)(v & 0x80); CALC_FCSLOT(CH,SLOT); }
/* set ksl & tl */ void set_ksl_tl(int slot,int v) { OPL_CH CH = P_CH[slot >> 1]; OPL_SLOT SLOT = CH.SLOT[slot & 1]; int ksl = v >> 6; /* 0 / 1.5 / 3 / 6 db/OCT */ SLOT.ksl = ksl != 0 ? (byte)(3 - ksl) : (byte)31; SLOT.TL = (int)((v & 0x3f) * (0.75 / EG_STEP())); /* 0.75db step */ if ((mode & 0x80) == 0) { /* not CSM latch total level */ SLOT.TLL = (int)(SLOT.TL + (CH.ksl_base >> SLOT.ksl)); } }
/* ---------- frequency counter for operater update ---------- */ void CALC_FCSLOT(OPL_CH CH,OPL_SLOT SLOT) { int ksr; /* frequency step counter */ SLOT.Incr = CH.fc * SLOT.mul; ksr = CH.kcode >> SLOT.KSR; if (SLOT.ksr != ksr) { SLOT.ksr = (byte)ksr; /* attack , decay rate recalcration */ SLOT.evsa = SLOT.AR(ksr); SLOT.evsd = SLOT.DR(ksr); SLOT.evsr = SLOT.RR(ksr); } SLOT.TLL = (int)(SLOT.TL + (CH.ksl_base >> SLOT.ksl)); }
/* set sustain level & release rate */ void set_sl_rr(int slot,int v) { OPL_CH CH = P_CH[slot >> 1]; OPL_SLOT SLOT = CH.SLOT[slot & 1]; int sl = v >> 4; int rr = v & 0x0f; SLOT.SL = SL_TABLE[sl]; if (SLOT.evm == ENV_MOD_DR) { SLOT.eve = SLOT.SL; } SLOT.RR = new Func <int,int>(index => DR_TABLE[index + rr << 2]); SLOT.evsr = SLOT.RR(SLOT.ksr); if (SLOT.evm == ENV_MOD_RR) { SLOT.evs = SLOT.evsr; } }
/* set attack rate & decay rate */ void set_ar_dr(int slot,int v) { OPL_CH CH = P_CH[slot >> 1]; OPL_SLOT SLOT = CH.SLOT[slot & 1]; int ar = v >> 4; int dr = v & 0x0f; SLOT.AR = ar != 0 ? new Func <int,int>(index => AR_TABLE[index + ar << 2]) : RATE_0; SLOT.evsa = SLOT.AR(SLOT.ksr); if (SLOT.evm == ENV_MOD_AR) { SLOT.evs = SLOT.evsa; } SLOT.DR = dr != 0 ? new Func <int,int>(index => DR_TABLE[index + dr << 2]) : RATE_0; SLOT.evsd = SLOT.DR(SLOT.ksr); if (SLOT.evm == ENV_MOD_DR) { SLOT.evs = SLOT.evsd; } }
/* connect for SLOT 2 */ /* set algorythm connection */ static void set_algorythm(OPL_CH CH) { var carrier = new Func<int,int>(index => outd[index]); CH.connect1 = CH.CON != 0 ? carrier : new Func<int,int>(index => feedback2 + index); CH.connect2 = carrier; }
void OPL_CALC_RH(OPL_CH CH) { uint env_tam, env_sd, env_top, env_hh; // This code used to do int(rnd.getRandomBit() * (WHITE_NOISE_db / EG_STEP)), // but EG_STEP = 96.0/EG_ENT, and WHITE_NOISE_db=6.0. So, that's equivalent to // int(rnd.getRandomBit() * EG_ENT/16). We know that EG_ENT is 4096, or 1024, // or 128, so we can safely avoid any FP ops. int whitenoise = rnd.getRandomBit() * (EG_ENT >> 4); int tone8; OPL_SLOT* SLOT; int env_out; /* BD : same as FM serial mode and output level is large */ feedback2 = 0; /* SLOT 1 */ SLOT = &CH[6].SLOT[SLOT1]; env_out = OPL_CALC_SLOT(SLOT); if (env_out < EG_ENT - 1) { /* PG */ if (SLOT.vib) SLOT.Cnt += (SLOT.Incr * vib) >> VIB_RATE_SHIFT; else SLOT.Cnt += SLOT.Incr; /* connection */ if (CH[6].FB) { int feedback1 = (CH[6].op1_out[0] + CH[6].op1_out[1]) >> CH[6].FB; CH[6].op1_out[1] = CH[6].op1_out[0]; feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT, env_out, feedback1); } else { feedback2 = OP_OUT(SLOT, env_out, 0); } } else { feedback2 = 0; CH[6].op1_out[1] = CH[6].op1_out[0]; CH[6].op1_out[0] = 0; } /* SLOT 2 */ SLOT = &CH[6].SLOT[SLOT2]; env_out = OPL_CALC_SLOT(SLOT); if (env_out < EG_ENT - 1) { /* PG */ if (SLOT.vib) SLOT.Cnt += (SLOT.Incr * vib) >> VIB_RATE_SHIFT; else SLOT.Cnt += SLOT.Incr; /* connection */ outd[0] += OP_OUT(SLOT, env_out, feedback2) * 2; } // SD (17) = mul14[fnum7] + white noise // TAM (15) = mul15[fnum8] // TOP (18) = fnum6(mul18[fnum8]+whitenoise) // HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise env_sd = OPL_CALC_SLOT(SLOT7_2) + whitenoise; env_tam = OPL_CALC_SLOT(SLOT8_1); env_top = OPL_CALC_SLOT(SLOT8_2); env_hh = OPL_CALC_SLOT(SLOT7_1) + whitenoise; /* PG */ if (SLOT7_1.vib) SLOT7_1.Cnt += (SLOT7_1.Incr * vib) >> (VIB_RATE_SHIFT - 1); else SLOT7_1.Cnt += 2 * SLOT7_1.Incr; if (SLOT7_2.vib) SLOT7_2.Cnt += (CH[7].fc * vib) >> (VIB_RATE_SHIFT - 3); else SLOT7_2.Cnt += (CH[7].fc * 8); if (SLOT8_1.vib) SLOT8_1.Cnt += (SLOT8_1.Incr * vib) >> VIB_RATE_SHIFT; else SLOT8_1.Cnt += SLOT8_1.Incr; if (SLOT8_2.vib) SLOT8_2.Cnt += ((CH[8].fc * 3) * vib) >> (VIB_RATE_SHIFT - 4); else SLOT8_2.Cnt += (CH[8].fc * 48); tone8 = OP_OUT(SLOT8_2, whitenoise, 0); /* SD */ if (env_sd < (uint)(EG_ENT - 1)) outd[0] += OP_OUT(SLOT7_1, env_sd, 0) * 8; /* TAM */ if (env_tam < (uint)(EG_ENT - 1)) outd[0] += OP_OUT(SLOT8_1, env_tam, 0) * 2; /* TOP-CY */ if (env_top < (uint)(EG_ENT - 1)) outd[0] += OP_OUT(SLOT7_2, env_top, tone8) * 2; /* HH */ if (env_hh < (uint)(EG_ENT - 1)) outd[0] += OP_OUT(SLOT7_2, env_hh, tone8) * 2; }
/* ---------- calcrate one of channel ---------- */ void OPL_CALC_CH(OPL_CH CH) { uint env_out; OPL_SLOT* SLOT; feedback2 = 0; /* SLOT 1 */ SLOT = &CH.SLOT[SLOT1]; env_out = OPL_CALC_SLOT(SLOT); if (env_out < (uint)(EG_ENT - 1)) { /* PG */ if (SLOT.vib) SLOT.Cnt += (SLOT.Incr * vib) >> VIB_RATE_SHIFT; else SLOT.Cnt += SLOT.Incr; /* connection */ if (CH.FB) { int feedback1 = (CH.op1_out[0] + CH.op1_out[1]) >> CH.FB; CH.op1_out[1] = CH.op1_out[0]; *CH.connect1 += CH.op1_out[0] = OP_OUT(SLOT, env_out, feedback1); } else { *CH.connect1 += OP_OUT(SLOT, env_out, 0); } } else { CH.op1_out[1] = CH.op1_out[0]; CH.op1_out[0] = 0; } /* SLOT 2 */ SLOT = &CH.SLOT[SLOT2]; env_out = OPL_CALC_SLOT(SLOT); if (env_out < (uint)(EG_ENT - 1)) { /* PG */ if (SLOT.vib) SLOT.Cnt += (SLOT.Incr * vib) >> VIB_RATE_SHIFT; else SLOT.Cnt += SLOT.Incr; /* connection */ outd[0] += OP_OUT(SLOT, env_out, feedback2); } }
/* ---------- frequency counter for operater update ---------- */ void CALC_FCSLOT(OPL_CH CH, OPL_SLOT SLOT) { int ksr; /* frequency step counter */ SLOT.Incr = CH.fc * SLOT.mul; ksr = CH.kcode >> SLOT.KSR; if (SLOT.ksr != ksr) { SLOT.ksr = (byte)ksr; /* attack , decay rate recalcration */ SLOT.evsa = SLOT.AR(ksr); SLOT.evsd = SLOT.DR(ksr); SLOT.evsr = SLOT.RR(ksr); } SLOT.TLL = (int)(SLOT.TL + (CH.ksl_base >> SLOT.ksl)); }
void OPL_CALC_RH(OPL_CH CH) { uint env_tam,env_sd,env_top,env_hh; // This code used to do int(rnd.getRandomBit() * (WHITE_NOISE_db / EG_STEP)), // but EG_STEP = 96.0/EG_ENT, and WHITE_NOISE_db=6.0. So, that's equivalent to // int(rnd.getRandomBit() * EG_ENT/16). We know that EG_ENT is 4096, or 1024, // or 128, so we can safely avoid any FP ops. int whitenoise = rnd.getRandomBit() * (EG_ENT >> 4); int tone8; OPL_SLOT*SLOT; int env_out; /* BD : same as FM serial mode and output level is large */ feedback2 = 0; /* SLOT 1 */ SLOT = &CH[6].SLOT[SLOT1]; env_out = OPL_CALC_SLOT(SLOT); if (env_out < EG_ENT - 1) { /* PG */ if (SLOT.vib) { SLOT.Cnt += (SLOT.Incr * vib) >> VIB_RATE_SHIFT; } else { SLOT.Cnt += SLOT.Incr; } /* connection */ if (CH[6].FB) { int feedback1 = (CH[6].op1_out[0] + CH[6].op1_out[1]) >> CH[6].FB; CH[6].op1_out[1] = CH[6].op1_out[0]; feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1); } else { feedback2 = OP_OUT(SLOT,env_out,0); } } else { feedback2 = 0; CH[6].op1_out[1] = CH[6].op1_out[0]; CH[6].op1_out[0] = 0; } /* SLOT 2 */ SLOT = &CH[6].SLOT[SLOT2]; env_out = OPL_CALC_SLOT(SLOT); if (env_out < EG_ENT - 1) { /* PG */ if (SLOT.vib) { SLOT.Cnt += (SLOT.Incr * vib) >> VIB_RATE_SHIFT; } else { SLOT.Cnt += SLOT.Incr; } /* connection */ outd[0] += OP_OUT(SLOT,env_out,feedback2) * 2; } // SD (17) = mul14[fnum7] + white noise // TAM (15) = mul15[fnum8] // TOP (18) = fnum6(mul18[fnum8]+whitenoise) // HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise env_sd = OPL_CALC_SLOT(SLOT7_2) + whitenoise; env_tam = OPL_CALC_SLOT(SLOT8_1); env_top = OPL_CALC_SLOT(SLOT8_2); env_hh = OPL_CALC_SLOT(SLOT7_1) + whitenoise; /* PG */ if (SLOT7_1.vib) { SLOT7_1.Cnt += (SLOT7_1.Incr * vib) >> (VIB_RATE_SHIFT - 1); } else { SLOT7_1.Cnt += 2 * SLOT7_1.Incr; } if (SLOT7_2.vib) { SLOT7_2.Cnt += (CH[7].fc * vib) >> (VIB_RATE_SHIFT - 3); } else { SLOT7_2.Cnt += (CH[7].fc * 8); } if (SLOT8_1.vib) { SLOT8_1.Cnt += (SLOT8_1.Incr * vib) >> VIB_RATE_SHIFT; } else { SLOT8_1.Cnt += SLOT8_1.Incr; } if (SLOT8_2.vib) { SLOT8_2.Cnt += ((CH[8].fc * 3) * vib) >> (VIB_RATE_SHIFT - 4); } else { SLOT8_2.Cnt += (CH[8].fc * 48); } tone8 = OP_OUT(SLOT8_2,whitenoise,0); /* SD */ if (env_sd < (uint)(EG_ENT - 1)) { outd[0] += OP_OUT(SLOT7_1,env_sd,0) * 8; } /* TAM */ if (env_tam < (uint)(EG_ENT - 1)) { outd[0] += OP_OUT(SLOT8_1,env_tam,0) * 2; } /* TOP-CY */ if (env_top < (uint)(EG_ENT - 1)) { outd[0] += OP_OUT(SLOT7_2,env_top,tone8) * 2; } /* HH */ if (env_hh < (uint)(EG_ENT - 1)) { outd[0] += OP_OUT(SLOT7_2,env_hh,tone8) * 2; } }