static void reset_channel(FM_ST ST, FM_CH[] CH, int chan) { int c, s; ST.mode = 0; /* normal mode */ FM_STATUS_RESET(ST, 0xff); ST.TA = 0; ST.TAC = 0; ST.TB = 0; ST.TBC = 0; for (c = 0; c < chan; c++) { CH[c] = new FM_CH(); CH[c].fc = 0; CH[c].PAN = OUTD_CENTER; for (s = 0; s < 4; s++) { CH[c].SLOT[s].SEG = 0; CH[c].SLOT[s].eg_next = FM_EG_Release; CH[c].SLOT[s].evc = EG_OFF; CH[c].SLOT[s].eve = EG_OFF + 1; CH[c].SLOT[s].evs = 0; } } }
/* CSM Key Controll */ static void CSMKeyControll(FM_CH CH) { /* int ksl = KSL[CH.kcode]; */ /* all key off */ FM_KEYOFF(CH, SLOT1); FM_KEYOFF(CH, SLOT2); FM_KEYOFF(CH, SLOT3); FM_KEYOFF(CH, SLOT4); /* total level latch */ CH.SLOT[SLOT1].TLL = CH.SLOT[SLOT1].TL /*+ ksl*/; CH.SLOT[SLOT2].TLL = CH.SLOT[SLOT2].TL /*+ ksl*/; CH.SLOT[SLOT3].TLL = CH.SLOT[SLOT3].TL /*+ ksl*/; CH.SLOT[SLOT4].TLL = CH.SLOT[SLOT4].TL /*+ ksl*/; /* all key on */ FM_KEYON(CH, SLOT1); FM_KEYON(CH, SLOT2); FM_KEYON(CH, SLOT3); FM_KEYON(CH, SLOT4); }
/* set total level */ static void set_tl(FM_CH CH, FM_SLOT SLOT, int v, int csmflag) { v &= 0x7f; v = (v << 7) | v; /* 7bit . 14bit */ SLOT.TL = (v * EG_ENT) >> 14; if (csmflag == 0) { /* not CSM latch total level */ SLOT.TLL = SLOT.TL /* + KSL[CH.kcode] */; } }
/* set attack rate & key scale */ static void set_ar_ksr(FM_CH CH, FM_SLOT SLOT, int v, IntSubArray ar_table) { SLOT.KSR = (byte)(3 - (v >> 6)); SLOT.AR = (v &= 0x1f) != 0 ? new IntSubArray(ar_table, v << 1) : new IntSubArray(RATE_0); SLOT.evsa = SLOT.AR[SLOT.ksr]; if (SLOT.eg_next == FM_EG_AR) SLOT.evs = SLOT.evsa; CH.SLOT[SLOT1].Incr = unchecked((uint)-1); }
static void setup_connection(FM_CH CH) { IntSubArray carrier = new IntSubArray(out_ch,CH.PAN); /* NONE,LEFT,RIGHT or CENTER */ switch (CH.ALGO) { case 0: /* PG---S1---S2---S3---S4---OUT */ CH.connect1 = new IntSubArray(pg_in2); CH.connect2 = new IntSubArray(pg_in3); CH.connect3 = new IntSubArray(pg_in4); break; case 1: /* PG---S1-+-S3---S4---OUT */ /* PG---S2-+ */ CH.connect1 = new IntSubArray(pg_in3); CH.connect2 = new IntSubArray(pg_in3); CH.connect3 = new IntSubArray(pg_in4); break; case 2: /* PG---S1------+-S4---OUT */ /* PG---S2---S3-+ */ CH.connect1 = new IntSubArray(pg_in4); CH.connect2 = new IntSubArray(pg_in3); CH.connect3 = new IntSubArray(pg_in4); break; case 3: /* PG---S1---S2-+-S4---OUT */ /* PG---S3------+ */ CH.connect1 = new IntSubArray(pg_in2); CH.connect2 = new IntSubArray(pg_in4); CH.connect3 = new IntSubArray(pg_in4); break; case 4: /* PG---S1---S2-+--OUT */ /* PG---S3---S4-+ */ CH.connect1 = new IntSubArray(pg_in2); CH.connect2 = new IntSubArray(carrier); CH.connect3 = new IntSubArray(pg_in4); break; case 5: /* +-S2-+ */ /* PG---S1-+-S3-+-OUT */ /* +-S4-+ */ CH.connect1 = null; /* special case */ CH.connect2 = new IntSubArray(carrier); CH.connect3 = new IntSubArray(carrier); break; case 6: /* PG---S1---S2-+ */ /* PG--------S3-+-OUT */ /* PG--------S4-+ */ CH.connect1 = new IntSubArray(pg_in2); CH.connect2 = new IntSubArray(carrier); CH.connect3 = new IntSubArray(carrier); break; case 7: /* PG---S1-+ */ /* PG---S2-+-OUT */ /* PG---S3-+ */ /* PG---S4-+ */ CH.connect1 = new IntSubArray(carrier); CH.connect2 = new IntSubArray(carrier); CH.connect3 = new IntSubArray(carrier); break; } CH.connect4 = carrier; }
/* set detune & multiple */ static void set_det_mul(FM_ST ST, FM_CH CH, FM_SLOT SLOT, int v) { SLOT.mul = (uint)MUL_TABLE[v & 0x0f]; SLOT.DT = ST.DT_TABLE[(v >> 4) & 7]; CH.SLOT[SLOT1].Incr = unchecked((uint)-1); }
static void FM_KEYON(FM_CH CH, int s) { FM_SLOT SLOT = CH.SLOT[s]; if (!FM_KEY_IS(SLOT)) { /* restart Phage Generator */ SLOT.Cnt = 0; /* phase . Attack */ #if FM_SEG_SUPPORT if( SLOT.SEG&8 ) SLOT.eg_next = FM_EG_SSG_AR; else #endif SLOT.eg_next = FM_EG_AR; SLOT.evs = SLOT.evsa; #if false /* convert decay count to attack count */ /* --- This caused the problem by credit sound of paper boy. --- */ SLOT.evc = EG_AST + DRAR_TABLE[ENV_CURVE[SLOT.evc>>ENV_BITS]];/* + SLOT.evs;*/ #else /* reset attack counter */ SLOT.evc = EG_AST; #endif SLOT.eve = EG_AED; } }
/* ----- key off of SLOT ----- */ static void FM_KEYOFF(FM_CH CH, int s) { FM_SLOT SLOT = CH.SLOT[s]; if (FM_KEY_IS(SLOT)) { /* if Attack phase then adjust envelope counter */ if (SLOT.evc < EG_DST) SLOT.evc = (ENV_CURVE[SLOT.evc >> ENV_BITS] << ENV_BITS) + EG_DST; /* phase . Release */ SLOT.eg_next = FM_EG_Release; SLOT.eve = EG_DED; SLOT.evs = SLOT.evsr; } }
static void CALC_FCOUNT(FM_CH CH) { if (CH.SLOT[SLOT1].Incr == unchecked((uint)-1)) { int fc = (int)CH.fc; int kc = CH.kcode; CALC_FCSLOT(CH.SLOT[SLOT1], fc, kc); CALC_FCSLOT(CH.SLOT[SLOT2], fc, kc); CALC_FCSLOT(CH.SLOT[SLOT3], fc, kc); CALC_FCSLOT(CH.SLOT[SLOT4], fc, kc); } }
public YM2203() { for (int i = 0; i < 3; i++) CH[i] = new FM_CH(); }
/* external timer mode */ static void INTERNAL_TIMER_A(FM_ST ST, FM_CH CSM_CH) { }
static void FM_CALC_CH(FM_CH CH) { uint eg_out1 = 0, eg_out2 = 0, eg_out3 = 0, eg_out4 = 0; //envelope output /* Phase Generator */ #if FM_LFO_SUPPORT int pms = lfo_pmd * CH.pms / LFO_RATE; if (pms != 0) { pg_in1[0] = (int)((CH.SLOT[SLOT1].Cnt += (uint)(CH.SLOT[SLOT1].Incr + (int)(pms * CH.SLOT[SLOT1].Incr) / PMS_RATE))); pg_in2[0] = (int)((CH.SLOT[SLOT2].Cnt += (uint)(CH.SLOT[SLOT2].Incr + (int)(pms * CH.SLOT[SLOT2].Incr) / PMS_RATE))); pg_in3[0] = (int)((CH.SLOT[SLOT3].Cnt += (uint)(CH.SLOT[SLOT3].Incr + (int)(pms * CH.SLOT[SLOT3].Incr) / PMS_RATE))); pg_in4[0] = (int)((CH.SLOT[SLOT4].Cnt += (uint)(CH.SLOT[SLOT4].Incr + (int)(pms * CH.SLOT[SLOT4].Incr) / PMS_RATE))); } else #endif { pg_in1[0] = (int)((CH.SLOT[SLOT1].Cnt += CH.SLOT[SLOT1].Incr)); pg_in2[0] = (int)((CH.SLOT[SLOT2].Cnt += CH.SLOT[SLOT2].Incr)); pg_in3[0] = (int)((CH.SLOT[SLOT3].Cnt += CH.SLOT[SLOT3].Incr)); pg_in4[0] = (int)((CH.SLOT[SLOT4].Cnt += CH.SLOT[SLOT4].Incr)); } /* Envelope Generator */ FM_CALC_EG(ref eg_out1, CH.SLOT[SLOT1]); FM_CALC_EG(ref eg_out2, CH.SLOT[SLOT2]); FM_CALC_EG(ref eg_out3, CH.SLOT[SLOT3]); FM_CALC_EG(ref eg_out4, CH.SLOT[SLOT4]); /* Connection */ if (eg_out1 < EG_CUT_OFF) /* SLOT 1 */ { if (CH.FB != 0) { /* with self feed back */ pg_in1[0] += (CH.op1_out[0] + CH.op1_out[1]) >> CH.FB; CH.op1_out[1] = CH.op1_out[0]; } CH.op1_out[0] = OP_OUT(pg_in1[0], eg_out1); /* output slot1 */ if (CH.connect1 == null) { /* algorythm 5 */ pg_in2[0] += CH.op1_out[0]; pg_in3[0] += CH.op1_out[0]; pg_in4[0] += CH.op1_out[0]; } else { /* other algorythm */ CH.connect1[0] += CH.op1_out[0]; } } if (eg_out2 < EG_CUT_OFF) /* SLOT 2 */ CH.connect2[0] += OP_OUT(pg_in2[0], eg_out2); if (eg_out3 < EG_CUT_OFF) /* SLOT 3 */ CH.connect3[0] += OP_OUT(pg_in3[0], eg_out3); if (eg_out4 < EG_CUT_OFF) /* SLOT 4 */ CH.connect4[0] += OP_OUT(pg_in4[0], eg_out4); }
static void OPM_CALC_FCOUNT(YM2151 OPM, FM_CH CH) { if (CH.SLOT[SLOT1].Incr == unchecked((uint)-1)) { int fc = (int)CH.fc; int kc = CH.kcode; CALC_FCSLOT(CH.SLOT[SLOT1], (int)(OPM.KC_TABLE[fc + CH.SLOT[SLOT1].DT2]), kc); CALC_FCSLOT(CH.SLOT[SLOT2], (int)(OPM.KC_TABLE[fc + CH.SLOT[SLOT2].DT2]), kc); CALC_FCSLOT(CH.SLOT[SLOT3], (int)(OPM.KC_TABLE[fc + CH.SLOT[SLOT3].DT2]), kc); CALC_FCSLOT(CH.SLOT[SLOT4], (int)(OPM.KC_TABLE[fc + CH.SLOT[SLOT4].DT2]), kc); } }