public static void OPL3_WriteRegBuffered(ref opl3_chip chip, ushort reg, byte v) { ulong time1, time2; if ((chip.writebuf[chip.writebuf_last].reg & 0x200) != 0) { OPL3_WriteReg(ref chip, (ushort)(chip.writebuf[chip.writebuf_last].reg & 0x1ff), chip.writebuf[chip.writebuf_last].data); chip.writebuf_cur = (uint)((chip.writebuf_last + 1) % OPL_WRITEBUF_SIZE); chip.writebuf_samplecnt = chip.writebuf[chip.writebuf_last].time; } chip.writebuf[chip.writebuf_last].reg = (ushort)(reg | 0x200); chip.writebuf[chip.writebuf_last].data = v; time1 = chip.writebuf_lasttime + (ulong)OPL_WRITEBUF_DELAY; time2 = chip.writebuf_samplecnt; if (time1 < time2) { time1 = time2; } chip.writebuf[chip.writebuf_last].time = time1; chip.writebuf_lasttime = time1; chip.writebuf_last = (chip.writebuf_last + 1) % (uint)OPL_WRITEBUF_SIZE; }
public static void OPL3_Reset(ref opl3_chip chip, int samplerate) { byte slotnum; byte channum; chip = new opl3_chip(); for (slotnum = 0; slotnum < 36; slotnum++) { chip.slot[slotnum] = new opl3_slot(); chip.slot[slotnum].chip = chip; unsafe { fixed(short *p = &chip.zeromod) { chip.slot[slotnum].mod = p; } } chip.slot[slotnum].eg_rout = 0x1ff; chip.slot[slotnum].eg_out = 0x1ff; chip.slot[slotnum].eg_gen = envelope_gen_num.release; //chip.slot[slotnum].trem = (byte)chip.zeromod; chip.slot[slotnum].tremZero = true; chip.slot[slotnum].slot_num = slotnum; } for (channum = 0; channum < 18; channum++) { chip.channel[channum] = new opl3_channel(); chip.channel[channum].slots[0] = chip.slot[ch_slot[channum]]; chip.channel[channum].slots[1] = chip.slot[ch_slot[channum] + 3]; chip.slot[ch_slot[channum]].channel = chip.channel[channum]; chip.slot[ch_slot[channum] + 3].channel = chip.channel[channum]; if ((channum % 9) < 3) { chip.channel[channum].pair = chip.channel[channum + 3]; } else if ((channum % 9) < 6) { chip.channel[channum].pair = chip.channel[channum - 3]; } chip.channel[channum].chip = chip; chip.channel[channum]._out[0] = chip.zeromod; chip.channel[channum]._out[1] = chip.zeromod; chip.channel[channum]._out[2] = chip.zeromod; chip.channel[channum]._out[3] = chip.zeromod; chip.channel[channum].chtype = ChannelType.ch_2op; chip.channel[channum].cha = 0xffff; chip.channel[channum].chb = 0xffff; chip.channel[channum].ch_num = channum; OPL3_ChannelSetupAlg(ref chip.channel[channum]); } chip.noise = 1; chip.rateratio = (int)((samplerate << RSM_FRAC) / 49716); chip.tremoloshift = 4; chip.vibshift = 1; }
public static void OPL3_GenerateStream(ref opl3_chip chip, short[] sndptr, uint numsamples, int pos) { int x = 0; for (int i = 0; i < numsamples / 2; i++) { OPL3_GenerateResampled(ref chip, sndptr, x); x += 2; //sndptr += 2; } }
public static void OPL3_GenerateResampled(ref opl3_chip chip, short[] buf, int pos) { while (chip.samplecnt >= chip.rateratio) { chip.oldsamples[0] = chip.samples[0]; chip.oldsamples[1] = chip.samples[1]; Nuked.OPL3_Generate(ref chip, chip.samples); chip.samplecnt -= chip.rateratio; } buf[pos] = (short)((chip.oldsamples[0] * (chip.rateratio - chip.samplecnt) + chip.samples[0] * chip.samplecnt) / chip.rateratio); buf[pos + 1] = (short)((chip.oldsamples[1] * (chip.rateratio - chip.samplecnt) + chip.samples[1] * chip.samplecnt) / chip.rateratio); chip.samplecnt += 1 << RSM_FRAC; }
public static void OPL3_ChannelSet4Op(ref opl3_chip chip, byte data) { byte bit; byte chnum; for (bit = 0; bit < 6; bit++) { chnum = bit; if (bit >= 3) { chnum += 9 - 3; } if (((data >> bit) & 0x01) != 0) { chip.channel[chnum].chtype = ChannelType.ch_4op; chip.channel[chnum + 3].chtype = ChannelType.ch_4op2; } else { chip.channel[chnum].chtype = ChannelType.ch_2op; chip.channel[chnum + 3].chtype = ChannelType.ch_2op; } } }
public static void OPL3_Generate(ref opl3_chip chip, short[] buf) { byte ii; byte jj; short accm; byte shift = 0; buf[1] = OPL3_ClipSample(chip.mixbuff[1]); for (ii = 0; ii < 15; ii++) { OPL3_SlotCalcFB(ref chip.slot[ii]); OPL3_EnvelopeCalc(ref chip.slot[ii]); OPL3_PhaseGenerate(ref chip.slot[ii]); OPL3_SlotGenerate(ref chip.slot[ii]); } chip.mixbuff[0] = 0; for (ii = 0; ii < 18; ii++) { accm = 0; for (jj = 0; jj < 4; jj++) { accm += chip.channel[ii]._out[jj]; } chip.mixbuff[0] += (short)(accm & chip.channel[ii].cha); } for (ii = 15; ii < 18; ii++) { OPL3_SlotCalcFB(ref chip.slot[ii]); OPL3_EnvelopeCalc(ref chip.slot[ii]); OPL3_PhaseGenerate(ref chip.slot[ii]); OPL3_SlotGenerate(ref chip.slot[ii]); } buf[0] = OPL3_ClipSample(chip.mixbuff[0]); for (ii = 18; ii < 33; ii++) { OPL3_SlotCalcFB(ref chip.slot[ii]); OPL3_EnvelopeCalc(ref chip.slot[ii]); OPL3_PhaseGenerate(ref chip.slot[ii]); OPL3_SlotGenerate(ref chip.slot[ii]); } chip.mixbuff[1] = 0; for (ii = 0; ii < 18; ii++) { accm = 0; for (jj = 0; jj < 4; jj++) { accm += chip.channel[ii]._out[jj]; } chip.mixbuff[1] += (short)(accm & chip.channel[ii].chb); } for (ii = 33; ii < 36; ii++) { OPL3_SlotCalcFB(ref chip.slot[ii]); OPL3_EnvelopeCalc(ref chip.slot[ii]); OPL3_PhaseGenerate(ref chip.slot[ii]); OPL3_SlotGenerate(ref chip.slot[ii]); } if ((chip.timer & 0x3f) == 0x3f) { chip.tremolopos = (byte)((chip.tremolopos + 1) % 210); } if (chip.tremolopos < 105) { chip.tremolo = (byte)(chip.tremolopos >> chip.tremoloshift); } else { chip.tremolo = (byte)((210 - chip.tremolopos) >> chip.tremoloshift); } if ((chip.timer & 0x3ff) == 0x3ff) { chip.vibpos = (byte)((chip.vibpos + 1) & 7); } chip.timer++; chip.eg_add = 0; if (chip.eg_timer != 0) { while (shift < 36 && ((chip.eg_timer >> shift) & 1) == 0) { shift++; } if (shift > 12) { chip.eg_add = 0; } else { chip.eg_add = (byte)(shift + 1); } } if (chip.eg_timerrem != 0 || chip.eg_state != 0) { if (chip.eg_timer == 0xfffffffff) { chip.eg_timer = 0; chip.eg_timerrem = 1; } else { chip.eg_timer++; chip.eg_timerrem = 0; } } chip.eg_state ^= 1; while (chip.writebuf[chip.writebuf_cur].time <= chip.writebuf_samplecnt) { if ((chip.writebuf[chip.writebuf_cur].reg & 0x200) == 0) { break; } chip.writebuf[chip.writebuf_cur].reg &= 0x1ff; OPL3_WriteReg(ref chip, chip.writebuf[chip.writebuf_cur].reg, chip.writebuf[chip.writebuf_cur].data); chip.writebuf_cur = (uint)((chip.writebuf_cur + 1) % OPL_WRITEBUF_SIZE); } chip.writebuf_samplecnt++; }
// // Channel // public static void OPL3_ChannelUpdateRhythm(ref opl3_chip chip, byte data) { opl3_channel channel6; opl3_channel channel7; opl3_channel channel8; byte chnum; chip.rhy = (byte)(data & 0x3f); if ((chip.rhy & 0x20) != 0) { channel6 = chip.channel[6]; channel7 = chip.channel[7]; channel8 = chip.channel[8]; channel6._out[0] = channel6.slots[1]._out; channel6._out[1] = channel6.slots[1]._out; channel6._out[2] = chip.zeromod; channel6._out[3] = chip.zeromod; channel7._out[0] = channel7.slots[0]._out; channel7._out[1] = channel7.slots[0]._out; channel7._out[2] = channel7.slots[1]._out; channel7._out[3] = channel7.slots[1]._out; channel8._out[0] = channel8.slots[0]._out; channel8._out[1] = channel8.slots[0]._out; channel8._out[2] = channel8.slots[1]._out; channel8._out[3] = channel8.slots[1]._out; for (chnum = 6; chnum < 9; chnum++) { chip.channel[chnum].chtype = ChannelType.ch_drum; } OPL3_ChannelSetupAlg(ref channel6); OPL3_ChannelSetupAlg(ref channel7); OPL3_ChannelSetupAlg(ref channel8); //hh if ((chip.rhy & 0x01) != 0) { OPL3_EnvelopeKeyOn(ref channel7.slots[0], EnvelopeKeyType.drum); } else { OPL3_EnvelopeKeyOff(ref channel7.slots[0], EnvelopeKeyType.drum); } //tc if ((chip.rhy & 0x02) != 0) { OPL3_EnvelopeKeyOn(ref channel8.slots[1], EnvelopeKeyType.drum); } else { OPL3_EnvelopeKeyOff(ref channel8.slots[1], EnvelopeKeyType.drum); } //tom if ((chip.rhy & 0x04) != 0) { OPL3_EnvelopeKeyOn(ref channel8.slots[0], EnvelopeKeyType.drum); } else { OPL3_EnvelopeKeyOff(ref channel8.slots[0], EnvelopeKeyType.drum); } //sd if ((chip.rhy & 0x08) != 0) { OPL3_EnvelopeKeyOn(ref channel7.slots[1], EnvelopeKeyType.drum); } else { OPL3_EnvelopeKeyOff(ref channel7.slots[1], EnvelopeKeyType.drum); } //bd if ((chip.rhy & 0x10) != 0) { OPL3_EnvelopeKeyOn(ref channel6.slots[0], EnvelopeKeyType.drum); OPL3_EnvelopeKeyOn(ref channel6.slots[1], EnvelopeKeyType.drum); } else { OPL3_EnvelopeKeyOff(ref channel6.slots[0], EnvelopeKeyType.drum); OPL3_EnvelopeKeyOff(ref channel6.slots[1], EnvelopeKeyType.drum); } } else { for (chnum = 6; chnum < 9; chnum++) { chip.channel[chnum].chtype = ChannelType.ch_2op; OPL3_ChannelSetupAlg(ref chip.channel[chnum]); OPL3_EnvelopeKeyOff(ref chip.channel[chnum].slots[0], EnvelopeKeyType.drum); OPL3_EnvelopeKeyOff(ref chip.channel[chnum].slots[1], EnvelopeKeyType.drum); } } }
public static void OPL3_WriteReg(ref opl3_chip chip, ushort reg, byte v) { byte high = (byte)((reg >> 8) & 0x01); byte regm = (byte)(reg & 0xff); switch (regm & 0xf0) { case 0x00: if (high != 0) { switch (regm & 0x0f) { case 0x04: OPL3_ChannelSet4Op(ref chip, v); break; case 0x05: chip.newm = (byte)(v & 0x01); break; } } else { switch (regm & 0x0f) { case 0x08: chip.nts = (byte)((v >> 6) & 0x01); break; } } break; case 0x20: case 0x30: if (ad_slot[regm & 0x1f] >= 0) { OPL3_SlotWrite20(ref chip.slot[18 * high + ad_slot[regm & 0x1f]], v); } break; case 0x40: case 0x50: if (ad_slot[regm & 0x1f] >= 0) { OPL3_SlotWrite40(ref chip.slot[18 * high + ad_slot[regm & 0x1f]], v); } break; case 0x60: case 0x70: if (ad_slot[regm & 0x1f] >= 0) { OPL3_SlotWrite60(ref chip.slot[18 * high + ad_slot[regm & 0x1f]], v); } break; case 0x80: case 0x90: if (ad_slot[regm & 0x1f] >= 0) { OPL3_SlotWrite80(ref chip.slot[18 * high + ad_slot[regm & 0x1f]], v); } break; case 0xe0: case 0xf0: if (ad_slot[regm & 0x1f] >= 0) { OPL3_SlotWriteE0(ref chip.slot[18 * high + ad_slot[regm & 0x1f]], v); } break; case 0xa0: if ((regm & 0x0f) < 9) { OPL3_ChannelWriteA0(ref chip.channel[(int)(9 * high + (regm & 0x0f))], v); } break; case 0xb0: if (regm == 0xbd && high == 0) { chip.tremoloshift = (byte)((((v >> 7) ^ 1) << 1) + 2); chip.vibshift = (byte)(((v >> 6) & 0x01) ^ 1); OPL3_ChannelUpdateRhythm(ref chip, v); } else if ((regm & 0x0f) < 9) { OPL3_ChannelWriteB0(ref chip.channel[9 * high + (regm & 0x0f)], v); if ((v & 0x20) != 0) { OPL3_ChannelKeyOn(ref chip.channel[9 * high + (regm & 0x0f)]); } else { OPL3_ChannelKeyOff(ref chip.channel[9 * high + (regm & 0x0f)]); } } break; case 0xc0: if ((regm & 0x0f) < 9) { OPL3_ChannelWriteC0(ref chip.channel[9 * high + (regm & 0x0f)], v); } break; } }