/* Slot key on without reseting the phase */ static void slotOn2(OPLL_SLOT slot) { slot.eg_mode = OPLL_EG_STATE.ATTACK; slot.eg_phase = 0; UPDATE_EG(slot); }
static void UPDATE_EG(OPLL_SLOT S) { (S).eg_dphase = calc_eg_dphase(S); }
static void UPDATE_ALL(OPLL_SLOT S) { UPDATE_PG(S); UPDATE_TLL(S); UPDATE_RKS(S); UPDATE_WF(S); UPDATE_EG(S); /* EG should be updated last. */ }
static void UPDATE_RKS(OPLL_SLOT S) { (S).rks = (uint)rksTable[((S).fnum) >> 8, (S).block, (S).patch.kr]; }
static void UPDATE_WF(OPLL_SLOT S) { (S).sintbl = waveform[(S).patch.wf]; }
static void setSlotVolume(OPLL_SLOT slot, int volume) { slot.volume = volume; }
static void calc_envelope(OPLL_SLOT slot, int lfo) { uint egout; switch (slot.eg_mode) { case OPLL_EG_STATE.ATTACK: egout = (uint)AR_ADJUST_TABLE[HIGHBITS(slot.eg_phase, EG_DP_BITS - EG_BITS)]; slot.eg_phase += slot.eg_dphase; if ((EG_DP_WIDTH & slot.eg_phase) != 0 || (slot.patch.ar == 15)) { egout = 0; slot.eg_phase = 0; slot.eg_mode = OPLL_EG_STATE.DECAY; UPDATE_EG(slot); } break; case OPLL_EG_STATE.DECAY: egout = HIGHBITS(slot.eg_phase, EG_DP_BITS - EG_BITS); slot.eg_phase += slot.eg_dphase; if (slot.eg_phase >= SL[slot.patch.sl]) { if (slot.patch.eg != 0) { slot.eg_phase = SL[slot.patch.sl]; slot.eg_mode = OPLL_EG_STATE.SUSHOLD; UPDATE_EG(slot); } else { slot.eg_phase = SL[slot.patch.sl]; slot.eg_mode = OPLL_EG_STATE.SUSTINE; UPDATE_EG(slot); } } break; case OPLL_EG_STATE.SUSHOLD: egout = HIGHBITS(slot.eg_phase, EG_DP_BITS - EG_BITS); if (slot.patch.eg == 0) { slot.eg_mode = OPLL_EG_STATE.SUSTINE; UPDATE_EG(slot); } break; case OPLL_EG_STATE.SUSTINE: case OPLL_EG_STATE.RELEASE: egout = HIGHBITS(slot.eg_phase, EG_DP_BITS - EG_BITS); slot.eg_phase += slot.eg_dphase; if (egout >= (1 << EG_BITS)) { slot.eg_mode = OPLL_EG_STATE.FINISH; egout = (1 << EG_BITS) - 1; } break; case OPLL_EG_STATE.SETTLE: egout = HIGHBITS(slot.eg_phase, EG_DP_BITS - EG_BITS); slot.eg_phase += slot.eg_dphase; if (egout >= (1 << EG_BITS)) { slot.eg_mode = OPLL_EG_STATE.ATTACK; egout = (1 << EG_BITS) - 1; UPDATE_EG(slot); } break; case OPLL_EG_STATE.FINISH: egout = (1 << EG_BITS) - 1; break; default: egout = (1 << EG_BITS) - 1; break; } if (slot.patch.am != 0) egout = (uint)(EG2DB(egout + slot.tll) + lfo); else egout = EG2DB(egout + slot.tll); if (egout >= DB_MUTE) egout = unchecked((uint)DB_MUTE - 1); slot.egout = egout | 3; }
/* HI-HAT */ static int calc_slot_hat(OPLL_SLOT slot, int pgout_cym, uint noise) { uint dbout; if (slot.egout + 1 >= DB_MUTE) return 0; else if ( /* the same as fmopl.c */ ((BIT(slot.pgout, PG_BITS - 8) ^ BIT(slot.pgout, PG_BITS - 1)) | BIT(slot.pgout, PG_BITS - 7)) ^ /* different from fmopl.c */ (BIT(pgout_cym, PG_BITS - 7) & !BIT(pgout_cym, PG_BITS - 5)) ) { if (noise != 0) dbout = DB_NEG(12.0); else dbout = DB_NEG(24.0); } else { if (noise != 0) dbout = DB_POS(12.0); else dbout = DB_POS(24.0); } return DB2LIN_TABLE[dbout + slot.egout]; }
/************************************************************ Calc Parameters ************************************************************/ static uint calc_eg_dphase(OPLL_SLOT slot) { switch (slot.eg_mode) { case OPLL_EG_STATE.ATTACK: return dphaseARTable[slot.patch.ar, slot.rks]; case OPLL_EG_STATE.DECAY: return dphaseDRTable[slot.patch.dr, slot.rks]; case OPLL_EG_STATE.SUSHOLD: return 0; case OPLL_EG_STATE.SUSTINE: return dphaseDRTable[slot.patch.rr, slot.rks]; case OPLL_EG_STATE.RELEASE: if (slot.sustine != 0) return dphaseDRTable[5, slot.rks]; else if (slot.patch.eg != 0) return dphaseDRTable[slot.patch.rr, slot.rks]; else return dphaseDRTable[7, slot.rks]; case OPLL_EG_STATE.SETTLE: return dphaseDRTable[15, 0]; case OPLL_EG_STATE.FINISH: return 0; default: return 0; } }
/* SNARE */ static int calc_slot_snare(OPLL_SLOT slot, uint noise) { if (slot.egout + 1 >= DB_MUTE) return 0; if (BIT(slot.pgout, 7)) return DB2LIN_TABLE[(noise != 0 ? DB_POS(0.0) : DB_POS(15.0)) + slot.egout]; else return DB2LIN_TABLE[(noise != 0 ? DB_NEG(0.0) : DB_NEG(15.0)) + slot.egout]; }
/* TOP-CYM */ static int calc_slot_cym(OPLL_SLOT slot, uint pgout_hh) { uint dbout; if (slot.egout + 1 >= DB_MUTE) return 0; else if ( /* the same as fmopl.c */ ((BIT(pgout_hh, PG_BITS - 8) ^ BIT(pgout_hh, PG_BITS - 1)) | BIT(pgout_hh, PG_BITS - 7)) ^ /* different from fmopl.c */ (BIT(slot.pgout, PG_BITS - 7) & !BIT(slot.pgout, PG_BITS - 5)) ) dbout = DB_NEG(3.0); else dbout = DB_POS(3.0); return DB2LIN_TABLE[dbout + slot.egout]; }
/* TOM */ static int calc_slot_tom(OPLL_SLOT slot) { if (slot.egout + 1 >= DB_MUTE) return 0; return DB2LIN_TABLE[slot.sintbl[slot.pgout] + slot.egout]; }
/* MODULATOR */ static int calc_slot_mod(OPLL_SLOT slot) { int fm; slot.output[1] = slot.output[0]; if (slot.egout + 1 >= DB_MUTE) { slot.output[0] = 0; } else if (slot.patch.fb != 0) { fm = wave2_4pi(slot.feedback) >> (int)(7 - slot.patch.fb); slot.output[0] = DB2LIN_TABLE[slot.sintbl[(slot.pgout + fm) & (PG_WIDTH - 1)] + slot.egout]; } else { slot.output[0] = DB2LIN_TABLE[slot.sintbl[slot.pgout] + slot.egout]; } slot.feedback = (slot.output[1] + slot.output[0]) >> 1; return slot.feedback; }
/* CARRIOR */ static int calc_slot_car(OPLL_SLOT slot, int fm) { if (slot.egout + 1 >= DB_MUTE) { slot.output[0] = 0; } else { slot.output[0] = DB2LIN_TABLE[slot.sintbl[(slot.pgout + wave2_8pi(fm)) & (PG_WIDTH - 1)] + slot.egout]; } slot.output[1] = (slot.output[1] + slot.output[0]) >> 1; return slot.output[1]; }
/* Slot key off */ static void slotOff(OPLL_SLOT slot) { if (slot.eg_mode == OPLL_EG_STATE.ATTACK) slot.eg_phase = (uint)EXPAND_BITS(AR_ADJUST_TABLE[HIGHBITS(slot.eg_phase, EG_DP_BITS - EG_BITS)], EG_BITS, EG_DP_BITS); slot.eg_mode = OPLL_EG_STATE.RELEASE; UPDATE_EG(slot); }
static void UPDATE_PG(OPLL_SLOT S) { (S).dphase = dphaseTable[(S).fnum, (S).block, (S).patch.ml]; }
/* Change a rhythm voice */ static void setSlotPatch(OPLL_SLOT slot, OPLL_PATCH patch) { slot.patch = patch; }
static void UPDATE_TLL(OPLL_SLOT S) { if (S.type == 0) { (S).tll = tllTable[((S).fnum) >> 5, (S).block, (S).patch.tl, (S).patch.kl]; } else { (S).tll = tllTable[((S).fnum) >> 5, (S).block, (S).volume, (S).patch.kl]; } }
/*********************************************************** Initializing ***********************************************************/ static void OPLL_SLOT_reset(OPLL_SLOT slot, int type) { slot.type = type; slot.sintbl = waveform[0]; slot.phase = 0; slot.dphase = 0; slot.output[0] = 0; slot.output[1] = 0; slot.feedback = 0; slot.eg_mode = OPLL_EG_STATE.FINISH; slot.eg_phase = EG_DP_WIDTH; slot.eg_dphase = 0; slot.rks = 0; slot.tll = 0; slot.sustine = 0; slot.fnum = 0; slot.block = 0; slot.volume = 0; slot.pgout = 0; slot.egout = 0; slot.patch = new OPLL_PATCH(); }
/* PG */ static void calc_phase(OPLL_SLOT slot, int lfo) { if (slot.patch.pm != 0) slot.phase += (uint)((slot.dphase * lfo) >> PM_AMP_BITS); else slot.phase += slot.dphase; slot.phase &= unchecked((uint)(DP_WIDTH - 1)); slot.pgout = HIGHBITS(slot.phase, DP_BASE_BITS); }