/* STEREO MODE (OPT) */ void OPLL_set_pan(OPLL opll, uint ch, uint pan) { opll.pan[ch & 15] = pan & 3; }
void OPLL_copyPatch(OPLL opll, int num, OPLL_PATCH patch) { opll.patch[num] = (OPLL_PATCH)patch.Clone(); }
/* Reset patch datas by system default. */ void OPLL_reset_patch(OPLL opll, int type) { int i; for (i = 0; i < 19 * 2; i++) OPLL_copyPatch(opll, i, default_patch[type % OPLL_TONE_NUM, i]); }
/* Set F-Number ( fnum : 9bit ) */ static void setFnumber(OPLL opll, int c, int fnum) { CAR(opll, c).fnum = fnum; MOD(opll, c).fnum = fnum; }
/* Change Rhythm Mode */ static void update_rhythm_mode(OPLL opll) { if ((opll.patch_number[6] & 0x10) != 0) { if ((opll.slot_on_flag[SLOT_BD2] | (opll.reg[0x0e] & 32)) == 0) { opll.slot[SLOT_BD1].eg_mode = OPLL_EG_STATE.FINISH; opll.slot[SLOT_BD2].eg_mode = OPLL_EG_STATE.FINISH; setPatch(opll, 6, opll.reg[0x36] >> 4); } } else if ((opll.reg[0x0e] & 32) != 0) { opll.patch_number[6] = 16; opll.slot[SLOT_BD1].eg_mode = OPLL_EG_STATE.FINISH; opll.slot[SLOT_BD2].eg_mode = OPLL_EG_STATE.FINISH; setSlotPatch(opll.slot[SLOT_BD1], opll.patch[16 * 2 + 0]); setSlotPatch(opll.slot[SLOT_BD2], opll.patch[16 * 2 + 1]); } if ((opll.patch_number[7] & 0x10) != 0) { if (!((opll.slot_on_flag[SLOT_HH] != 0 && opll.slot_on_flag[SLOT_SD] != 0) | ((opll.reg[0x0e] & 32) != 0))) { opll.slot[SLOT_HH].type = 0; opll.slot[SLOT_HH].eg_mode = OPLL_EG_STATE.FINISH; opll.slot[SLOT_SD].eg_mode = OPLL_EG_STATE.FINISH; setPatch(opll, 7, opll.reg[0x37] >> 4); } } else if ((opll.reg[0x0e] & 32) != 0) { opll.patch_number[7] = 17; opll.slot[SLOT_HH].type = 1; opll.slot[SLOT_HH].eg_mode = OPLL_EG_STATE.FINISH; opll.slot[SLOT_SD].eg_mode = OPLL_EG_STATE.FINISH; setSlotPatch(opll.slot[SLOT_HH], opll.patch[17 * 2 + 0]); setSlotPatch(opll.slot[SLOT_SD], opll.patch[17 * 2 + 1]); } if ((opll.patch_number[8] & 0x10) != 0) { if (!((opll.slot_on_flag[SLOT_CYM] != 0 && opll.slot_on_flag[SLOT_TOM] != 0) | ((opll.reg[0x0e] & 32) != 0))) { opll.slot[SLOT_TOM].type = 0; opll.slot[SLOT_TOM].eg_mode = OPLL_EG_STATE.FINISH; opll.slot[SLOT_CYM].eg_mode = OPLL_EG_STATE.FINISH; setPatch(opll, 8, opll.reg[0x38] >> 4); } } else if ((opll.reg[0x0e] & 32) != 0) { opll.patch_number[8] = 18; opll.slot[SLOT_TOM].type = 1; opll.slot[SLOT_TOM].eg_mode = OPLL_EG_STATE.FINISH; opll.slot[SLOT_CYM].eg_mode = OPLL_EG_STATE.FINISH; setSlotPatch(opll.slot[SLOT_TOM], opll.patch[18 * 2 + 0]); setSlotPatch(opll.slot[SLOT_CYM], opll.patch[18 * 2 + 1]); } }
static void keyOff_CYM(OPLL opll) { if (opll.slot_on_flag[SLOT_CYM] != 0) slotOff(CAR(opll, 8)); }
/* Set sustine parameter */ static void setSustine(OPLL opll, int c, int sustine) { CAR(opll, c).sustine = sustine; if (MOD(opll, c).type != 0) MOD(opll, c).sustine = sustine; }
public YM2413(ChipType type) { MaxVolume = short.MaxValue; opll = OPLL_new(3579545, 44100, (int)type); }
/* Channel key on */ static void keyOn(OPLL opll, int i) { if (opll.slot_on_flag[i * 2] == 0) slotOn(MOD(opll, i)); if (opll.slot_on_flag[i * 2 + 1] == 0) slotOn(CAR(opll, i)); opll.key_status[i] = 1; }
static uint RATE_ADJUST(double x) { return (rate == 49716 ? (uint)x : (uint)((double)(x) * clk / 72 / rate + 0.5)); } /* added 0.5 to round the value*/ static OPLL_SLOT MOD(OPLL o, int x) { return ((o).slot[(x) << 1]); }
static OPLL_SLOT CAR(OPLL o, int x) { return ((o).slot[((x) << 1) | 1]); }
public YM2413() { MaxVolume = short.MaxValue; opll = OPLL_new(3579545, 44100, 0); }
void OPLL_calc_stereo(OPLL opll, int[] output) { if (!opll.quality) { calc_stereo(opll, output); return; } while (opll.realstep > opll.oplltime) { opll.oplltime += opll.opllstep; opll.sprev[0] = opll.snext[0]; opll.sprev[1] = opll.snext[1]; calc_stereo(opll, opll.snext); } opll.oplltime -= opll.realstep; output[0] = (short)(((double)opll.snext[0] * (opll.opllstep - opll.oplltime) + (double)opll.sprev[0] * opll.oplltime) / opll.opllstep); output[1] = (short)(((double)opll.snext[1] * (opll.opllstep - opll.oplltime) + (double)opll.sprev[1] * opll.oplltime) / opll.opllstep); }
static void calc_stereo(OPLL opll, int[] output) { int[] b = new[] { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ int[] r = new[] { 0, 0, 0, 0 }; /* Ignore, Right, Left, Center */ int i; update_ampm(opll); update_noise(opll); for (i = 0; i < 18; i++) { calc_phase(opll.slot[i], opll.lfo_pm); calc_envelope(opll.slot[i], opll.lfo_am); } for (i = 0; i < 6; i++) if ((opll.mask & OPLL_MASK_CH(i)) == 0 && (CAR(opll, i).eg_mode != OPLL_EG_STATE.FINISH)) b[opll.pan[i]] += calc_slot_car(CAR(opll, i), calc_slot_mod(MOD(opll, i))); if (opll.patch_number[6] <= 15) { if ((opll.mask & OPLL_MASK_CH(6)) == 0 && (CAR(opll, 6).eg_mode != OPLL_EG_STATE.FINISH)) b[opll.pan[6]] += calc_slot_car(CAR(opll, 6), calc_slot_mod(MOD(opll, 6))); } else { if ((opll.mask & OPLL_MASK_BD) == 0 && (CAR(opll, 6).eg_mode != OPLL_EG_STATE.FINISH)) r[opll.pan[9]] += calc_slot_car(CAR(opll, 6), calc_slot_mod(MOD(opll, 6))); } if (opll.patch_number[7] <= 15) { if ((opll.mask & OPLL_MASK_CH(7)) == 0 && (CAR(opll, 7).eg_mode != OPLL_EG_STATE.FINISH)) b[opll.pan[7]] += calc_slot_car(CAR(opll, 7), calc_slot_mod(MOD(opll, 7))); } else { if ((opll.mask & OPLL_MASK_HH) == 0 && (MOD(opll, 7).eg_mode != OPLL_EG_STATE.FINISH)) r[opll.pan[10]] += calc_slot_hat(MOD(opll, 7), (int)CAR(opll, 8).pgout, opll.noise_seed & 1); if ((opll.mask & OPLL_MASK_SD) == 0 && (CAR(opll, 7).eg_mode != OPLL_EG_STATE.FINISH)) r[opll.pan[11]] -= calc_slot_snare(CAR(opll, 7), opll.noise_seed & 1); } if (opll.patch_number[8] <= 15) { if ((opll.mask & OPLL_MASK_CH(8)) == 0 && (CAR(opll, 8).eg_mode != OPLL_EG_STATE.FINISH)) b[opll.pan[8]] += calc_slot_car(CAR(opll, 8), calc_slot_mod(MOD(opll, 8))); } else { if ((opll.mask & OPLL_MASK_TOM) == 0 && (MOD(opll, 8).eg_mode != OPLL_EG_STATE.FINISH)) r[opll.pan[12]] += calc_slot_tom(MOD(opll, 8)); if ((opll.mask & OPLL_MASK_CYM) == 0 && (CAR(opll, 8).eg_mode != OPLL_EG_STATE.FINISH)) r[opll.pan[13]] -= calc_slot_cym(CAR(opll, 8), MOD(opll, 7).pgout); } output[1] = (b[1] + b[3] + ((r[1] + r[3]) << 1)) << 3; output[0] = (b[2] + b[3] + ((r[2] + r[3]) << 1)) << 3; }
static void keyOff_TOM(OPLL opll) { if (opll.slot_on_flag[SLOT_TOM] != 0) slotOff(MOD(opll, 8)); }
/* Channel key off */ static void keyOff(OPLL opll, int i) { if (opll.slot_on_flag[i * 2 + 1] != 0) slotOff(CAR(opll, i)); opll.key_status[i] = 0; }
static void keyOff_HH(OPLL opll) { if (opll.slot_on_flag[SLOT_HH] != 0) slotOff(MOD(opll, 7)); }
static void keyOn_BD(OPLL opll) { keyOn(opll, 6); }
/* Change a voice */ static void setPatch(OPLL opll, int i, int num) { opll.patch_number[i] = num; MOD(opll, i).patch = opll.patch[num * 2 + 0]; CAR(opll, i).patch = opll.patch[num * 2 + 1]; }
static void keyOn_TOM(OPLL opll) { if (opll.slot_on_flag[SLOT_TOM] == 0) slotOn(MOD(opll, 8)); }
/* Volume : 6bit ( Volume register << 2 ) */ static void setVolume(OPLL opll, int c, int volume) { CAR(opll, c).volume = volume; }
static void keyOn_HH(OPLL opll) { if (opll.slot_on_flag[SLOT_HH] == 0) slotOn2(MOD(opll, 7)); }
/* Set Block data (block : 3bit ) */ static void setBlock(OPLL opll, int c, int block) { CAR(opll, c).block = block; MOD(opll, c).block = block; }
static void keyOn_CYM(OPLL opll) { if (opll.slot_on_flag[SLOT_CYM] == 0) slotOn2(CAR(opll, 8)); }
static void update_key_status(OPLL opll) { int ch; for (ch = 0; ch < 9; ch++) opll.slot_on_flag[ch * 2] = opll.slot_on_flag[ch * 2 + 1] = (opll.reg[0x20 + ch]) & 0x10; if ((opll.reg[0x0e] & 32) != 0) { opll.slot_on_flag[SLOT_BD1] |= (opll.reg[0x0e] & 0x10); opll.slot_on_flag[SLOT_BD2] |= (opll.reg[0x0e] & 0x10); opll.slot_on_flag[SLOT_SD] |= (opll.reg[0x0e] & 0x08); opll.slot_on_flag[SLOT_HH] |= (opll.reg[0x0e] & 0x01); opll.slot_on_flag[SLOT_TOM] |= (opll.reg[0x0e] & 0x04); opll.slot_on_flag[SLOT_CYM] |= (opll.reg[0x0e] & 0x02); } }
/* Drum key off */ static void keyOff_BD(OPLL opll) { keyOff(opll, 6); }
OPLL OPLL_new(uint clk, uint rate, int type) { OPLL opll = new OPLL(); int i; maketables(clk, rate); for (i = 0; i < 19 * 2; i++) opll.patch[i] = new OPLL_PATCH(); opll.mask = 0; OPLL_reset(opll); OPLL_reset_patch(opll, type); return opll; }
static void keyOff_SD(OPLL opll) { if (opll.slot_on_flag[SLOT_SD] == 0) slotOff(CAR(opll, 7)); }
/* Reset whole of OPLL except patch datas. */ void OPLL_reset(OPLL opll) { int i; opll.adr = 0; opll.output = 0; opll.pm_phase = 0; opll.am_phase = 0; opll.noise_seed = 0xffff; opll.mask = 0; for (i = 0; i < 18; i++) OPLL_SLOT_reset(opll.slot[i], i % 2); for (i = 0; i < 9; i++) { opll.key_status[i] = 0; setPatch(opll, i, 0); } for (i = 0; i < 0x40; i++) OPLL_writeReg(opll, (uint)i, 0); opll.realstep = (uint)((1 << 31) / rate); opll.opllstep = (uint)((1 << 31) / (clk / 72)); opll.oplltime = 0; for (i = 0; i < 14; i++) opll.pan[i] = 3; opll.sprev[0] = opll.sprev[1] = 0; opll.snext[0] = opll.snext[1] = 0; }
void OPLL_writeIO(OPLL opll, uint adr, uint val) { if ((adr & 1) != 0) OPLL_writeReg(opll, opll.adr, val); else opll.adr = val; }