From 23577f4be8c3cf4cdd9dbf73043bb3702cb77116 Mon Sep 17 00:00:00 2001 From: khokh2001 Date: Sun, 20 Sep 2015 02:11:03 +0900 Subject: [PATCH 1/2] nuked opl emulator update --- src/oplsynth/nukedopl3.cpp | 433 ++++++++++++++++++++----------------- src/oplsynth/nukedopl3.h | 15 +- 2 files changed, 248 insertions(+), 200 deletions(-) diff --git a/src/oplsynth/nukedopl3.cpp b/src/oplsynth/nukedopl3.cpp index 4d143f4a5..0baa67bda 100644 --- a/src/oplsynth/nukedopl3.cpp +++ b/src/oplsynth/nukedopl3.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2013-2014 Nuke.YKT +* Copyright (C) 2013-2014 Nuke.YKT(Alexey Khokholov) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,53 +27,31 @@ OPL2 ROMs. */ -//version 1.5 +//version 1.6 /* Changelog: v1.1: - Vibrato's sign fix + Vibrato's sign fix. v1.2: - Operator key fix - Corrected 4-operator mode - Corrected rhythm mode - Some small fixes - v1.2.1: - Small envelope generator fix - Removed EX_Get function(not used) - v1.3: - Complete rewrite - (Not released) - v1.4: - New envelope and waveform generator + Operator key fix. + Corrected 4-operator mode. + Corrected rhythm mode. + Some small fixes. + v1.2.1: + Small envelope generator fix. + v1.3: + Complete rewrite. + v1.4: + New envelope and waveform generator. Some small fixes. - (Not released) v1.4.1: - Envelope generator rate calculation fix - (Not released) + Envelope generator rate calculation fix. v1.4.2: Version for ZDoom. v1.5: - Optimizations -*/ - - -/* Verified: - Noise generator. - Waveform generator. - Envelope generator increase table. - Tremolo. -*/ - -/* TODO: - Verify: - kslrom[15] value(is it 128?). - Sustain level = 15. - Vibrato, Phase generator. - Rhythm part. - Envelope generator state switching(decay->sustain when egt = 1 and decay->release). - Feedback. - Register write. - 4-operator. + Optimizations. + v1.6: + Improved emulation output. */ #include @@ -216,19 +194,17 @@ envelope_sinfunc envelope_sin[8] = { }; void envelope_gen_off(opl_slot *slott); -void envelope_gen_change(opl_slot *slott); void envelope_gen_attack(opl_slot *slott); void envelope_gen_decay(opl_slot *slott); void envelope_gen_sustain(opl_slot *slott); void envelope_gen_release(opl_slot *slott); -envelope_genfunc envelope_gen[6] = { +envelope_genfunc envelope_gen[5] = { envelope_gen_off, envelope_gen_attack, envelope_gen_decay, envelope_gen_sustain, - envelope_gen_release, - envelope_gen_change + envelope_gen_release }; enum envelope_gen_num { @@ -252,7 +228,7 @@ Bit8u envelope_calc_rate(opl_slot *slot, Bit8u reg_rate) { } void envelope_update_ksl(opl_slot *slot) { - Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 1) - ((slot->channel->block ^ 0x07) << 5) - 0x20; + Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - ((0x08 - slot->channel->block) << 5); if (ksl < 0) { ksl = 0; } @@ -281,28 +257,25 @@ void envelope_gen_off(opl_slot *slot) { slot->eg_rout = 0x1ff; } -void envelope_gen_change(opl_slot *slot) { - slot->eg_gen = slot->eg_gennext; - envelope_update_rate(slot); -} - void envelope_gen_attack(opl_slot *slot) { + if (slot->eg_rout == 0x00) { + slot->eg_gen = envelope_gen_num_decay; + envelope_update_rate(slot); + return; + } slot->eg_rout += ((~slot->eg_rout) *slot->eg_inc) >> 3; if (slot->eg_rout < 0x00) { slot->eg_rout = 0x00; } - if (!slot->eg_rout) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_decay; - } } void envelope_gen_decay(opl_slot *slot) { - slot->eg_rout += slot->eg_inc; if (slot->eg_rout >= slot->reg_sl << 4) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_sustain; + slot->eg_gen = envelope_gen_num_sustain; + envelope_update_rate(slot); + return; } + slot->eg_rout += slot->eg_inc; } void envelope_gen_sustain(opl_slot *slot) { @@ -312,11 +285,13 @@ void envelope_gen_sustain(opl_slot *slot) { } void envelope_gen_release(opl_slot *slot) { - slot->eg_rout += slot->eg_inc; if (slot->eg_rout >= 0x1ff) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_off; + slot->eg_gen = envelope_gen_num_off; + slot->eg_rout = 0x1ff; + envelope_update_rate(slot); + return; } + slot->eg_rout += slot->eg_inc; } void envelope_calc(opl_slot *slot) { @@ -324,10 +299,7 @@ void envelope_calc(opl_slot *slot) { rate_h = slot->eg_rate >> 2; rate_l = slot->eg_rate & 3; Bit8u inc = 0; - if (slot->eg_gen == envelope_gen_num_attack && rate_h == 0x0f) { - inc = 8; - } - else if (eg_incsh[rate_h] > 0) { + if (eg_incsh[rate_h] > 0) { if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) { inc = eg_incstep[eg_incdesc[rate_h]][rate_l][((slot->chip->timer) >> eg_incsh[rate_h]) & 0x07]; } @@ -336,14 +308,19 @@ void envelope_calc(opl_slot *slot) { inc = eg_incstep[eg_incdesc[rate_h]][rate_l][slot->chip->timer & 0x07] << (-eg_incsh[rate_h]); } slot->eg_inc = inc; - envelope_gen[slot->eg_gen](slot); slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; + envelope_gen[slot->eg_gen](slot); } void eg_keyon(opl_slot *slot, Bit8u type) { if (!slot->key) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_attack; + slot->eg_gen = envelope_gen_num_attack; + envelope_update_rate(slot); + if ((slot->eg_rate >> 2) == 0x0f) { + slot->eg_gen = envelope_gen_num_decay; + envelope_update_rate(slot); + slot->eg_rout = 0x00; + } slot->pg_phase = 0x00; } slot->key |= type; @@ -353,8 +330,8 @@ void eg_keyoff(opl_slot *slot, Bit8u type) { if (slot->key) { slot->key &= (~type); if (!slot->key) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_release; + slot->eg_gen = envelope_gen_num_release; + envelope_update_rate(slot); } } } @@ -366,7 +343,7 @@ void eg_keyoff(opl_slot *slot, Bit8u type) { void pg_generate(opl_slot *slot) { Bit16u f_num = slot->channel->f_num; if (slot->reg_vib) { - Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10)&0x07] + (0x01 - slot->chip->dvb)); + Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10) & 0x07] + (0x01 - slot->chip->dvb)); f_num += f_num_high * vibsgn_table[(slot->chip->timer >> 10) & 0x07]; } slot->pg_phase += (((f_num << slot->channel->block) >> 1) * mt[slot->reg_mult]) >> 1; @@ -387,7 +364,7 @@ void n_generate(opl_chip *chip) { // Slot // -void slot_write20(opl_slot *slot,Bit8u data) { +void slot_write20(opl_slot *slot, Bit8u data) { if ((data >> 7) & 0x01) { slot->trem = &slot->chip->tremval; } @@ -434,14 +411,14 @@ void slot_generatephase(opl_slot *slot, Bit16u phase) { } void slot_generate(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9) + (*slot->mod), slot->eg_out); + slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9) + (*slot->mod), slot->eg_out); } void slot_generatezm(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9), slot->eg_out); + slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9), slot->eg_out); } -void slot_calgfb(opl_slot *slot) { +void slot_calcfb(opl_slot *slot) { slot->prout[1] = slot->prout[0]; slot->prout[0] = slot->out; if (slot->channel->fb != 0x00) { @@ -461,57 +438,61 @@ void chan_setupalg(opl_channel *channel); void chan_updaterhythm(opl_chip *chip, Bit8u data) { chip->rhy = data & 0x3f; if (chip->rhy & 0x20) { - chip->channel[6].out[0] = &chip->slot[13].out; - chip->channel[6].out[1] = &chip->slot[13].out; - chip->channel[6].out[2] = &chip->zeromod; - chip->channel[6].out[3] = &chip->zeromod; - chip->channel[7].out[0] = &chip->slot[14].out; - chip->channel[7].out[1] = &chip->slot[14].out; - chip->channel[7].out[2] = &chip->slot[15].out; - chip->channel[7].out[3] = &chip->slot[15].out; - chip->channel[8].out[0] = &chip->slot[16].out; - chip->channel[8].out[1] = &chip->slot[16].out; - chip->channel[8].out[2] = &chip->slot[17].out; - chip->channel[8].out[3] = &chip->slot[17].out; + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *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 (Bit8u chnum = 6; chnum < 9; chnum++) { chip->channel[chnum].chtype = ch_drum; } + chan_setupalg(channel6); //hh if (chip->rhy & 0x01) { - eg_keyon(&chip->slot[14], egk_drum); + eg_keyon(channel7->slots[0], egk_drum); } else { - eg_keyoff(&chip->slot[14], egk_drum); + eg_keyoff(channel7->slots[0], egk_drum); } //tc if (chip->rhy & 0x02) { - eg_keyon(&chip->slot[17], egk_drum); + eg_keyon(channel8->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[17], egk_drum); + eg_keyoff(channel8->slots[1], egk_drum); } //tom if (chip->rhy & 0x04) { - eg_keyon(&chip->slot[16], egk_drum); + eg_keyon(channel8->slots[0], egk_drum); } else { - eg_keyoff(&chip->slot[16], egk_drum); + eg_keyoff(channel8->slots[0], egk_drum); } //sd if (chip->rhy & 0x08) { - eg_keyon(&chip->slot[15], egk_drum); + eg_keyon(channel7->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[15], egk_drum); + eg_keyoff(channel7->slots[1], egk_drum); } //bd if (chip->rhy & 0x10) { - eg_keyon(&chip->slot[12], egk_drum); - eg_keyon(&chip->slot[13], egk_drum); + eg_keyon(channel6->slots[0], egk_drum); + eg_keyon(channel6->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[12], egk_drum); - eg_keyoff(&chip->slot[13], egk_drum); + eg_keyoff(channel6->slots[0], egk_drum); + eg_keyoff(channel6->slots[1], egk_drum); } } else { @@ -566,6 +547,16 @@ void chan_writeb0(opl_channel *channel, Bit8u data) { void chan_setupalg(opl_channel *channel) { if (channel->chtype == ch_drum) { + switch (channel->alg & 0x01) { + case 0x00: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->slots[0]->out; + break; + case 0x01: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->chip->zeromod; + break; + } return; } if (channel->alg & 0x08) { @@ -672,49 +663,39 @@ void chan_writec0(opl_channel *channel, Bit8u data) { } } -void chan_generaterhythm(opl_chip *chip) { - if (chip->rhy & 0x20) { - opl_channel *channel6 = &chip->channel[6]; - opl_channel *channel7 = &chip->channel[7]; - opl_channel *channel8 = &chip->channel[8]; - slot_generate(channel6->slots[0]); - slot_generate(channel6->slots[1]); - Bit16u phase14 = channel7->slots[0]->pg_phase & 0x3ff; - Bit16u phase17 = channel8->slots[1]->pg_phase & 0x3ff; - Bit16u phase = 0x00; - //hh tc phase bit - Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - //hh - phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); - slot_generatephase(channel7->slots[0], phase); - //sd - phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); - slot_generatephase(channel7->slots[1], phase); - //tt - slot_generatezm(channel8->slots[0]); - //tc - phase = 0x100 | (phasebit << 9); - slot_generatephase(channel8->slots[1], phase); - } +void chan_generaterhythm1(opl_chip *chip) { + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *channel8 = &chip->channel[8]; + slot_generate(channel6->slots[0]); + Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + Bit16u phase = 0x00; + //hh tc phase bit + Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //hh + phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); + slot_generatephase(channel7->slots[0], phase); + //tt + slot_generatezm(channel8->slots[0]); } -void chan_generate(opl_channel *channel) { - if (channel->chtype == ch_drum) { - return; - } - if (channel->alg & 0x08) { - return; - } - if (channel->alg & 0x04) { - slot_generate(channel->pair->slots[0]); - slot_generate(channel->pair->slots[1]); - slot_generate(channel->slots[0]); - slot_generate(channel->slots[1]); - } - else { - slot_generate(channel->slots[0]); - slot_generate(channel->slots[1]); - } +void chan_generaterhythm2(opl_chip *chip) { + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *channel8 = &chip->channel[8]; + slot_generate(channel6->slots[1]); + Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + Bit16u phase = 0x00; + //hh tc phase bit + Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //sd + phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); + slot_generatephase(channel7->slots[1], phase); + //tc + phase = 0x100 | (phasebit << 9); + slot_generatephase(channel8->slots[1], phase); } void chan_enable(opl_channel *channel) { @@ -782,21 +763,132 @@ Bit16s limshort(Bit32s a) { return (Bit16s)a; } +void chip_generate(opl_chip *chip, Bit16s *buff) { + buff[1] = limshort(chip->mixbuff[1]); + + for (Bit8u ii = 0; ii < 12; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + for (Bit8u ii = 12; ii < 15; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) { + chan_generaterhythm1(chip); + } + else { + slot_generate(&chip->slot[12]); + slot_generate(&chip->slot[13]); + slot_generate(&chip->slot[14]); + } + + chip->mixbuff[0] = 0; + for (Bit8u ii = 0; ii < 18; ii++) { + Bit16s accm = 0; + for (Bit8u jj = 0; jj < 4; jj++) { + accm += *chip->channel[ii].out[jj]; + } + if (chip->FullPan) { + chip->mixbuff[0] += (Bit16s)(accm * chip->channel[ii].fcha); + } + else { + chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); + } + } + + for (Bit8u ii = 15; ii < 18; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) { + chan_generaterhythm2(chip); + } + else { + slot_generate(&chip->slot[15]); + slot_generate(&chip->slot[16]); + slot_generate(&chip->slot[17]); + } + + buff[0] = limshort(chip->mixbuff[0]); + + for (Bit8u ii = 18; ii < 33; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + chip->mixbuff[1] = 0; + for (Bit8u ii = 0; ii < 18; ii++) { + Bit16s accm = 0; + for (Bit8u jj = 0; jj < 4; jj++) { + accm += *chip->channel[ii].out[jj]; + } + if (chip->FullPan) { + chip->mixbuff[1] += (Bit16s)(accm * chip->channel[ii].fchb); + } + else { + chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); + } + } + + for (Bit8u ii = 33; ii < 36; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + n_generate(chip); + + if ((chip->timer & 0x3f) == 0x3f) { + if (!chip->tremdir) { + if (chip->tremtval == 105) { + chip->tremtval--; + chip->tremdir = 1; + } + else { + chip->tremtval++; + } + } + else { + if (chip->tremtval == 0) { + chip->tremtval++; + chip->tremdir = 0; + } + else { + chip->tremtval--; + } + } + chip->tremval = (chip->tremtval >> 2) >> ((1 - chip->dam) << 1); + } + + chip->timer++; +} + void NukedOPL3::Reset() { memset(&opl3, 0, sizeof(opl_chip)); for (Bit8u slotnum = 0; slotnum < 36; slotnum++) { - opl3.slot[slotnum].channel = &opl3.channel[slotnum / 2]; opl3.slot[slotnum].chip = &opl3; opl3.slot[slotnum].mod = &opl3.zeromod; opl3.slot[slotnum].eg_rout = 0x1ff; opl3.slot[slotnum].eg_out = 0x1ff; opl3.slot[slotnum].eg_gen = envelope_gen_num_off; - opl3.slot[slotnum].eg_gennext = envelope_gen_num_off; opl3.slot[slotnum].trem = (Bit8u*)&opl3.zeromod; } for (Bit8u channum = 0; channum < 18; channum++) { - opl3.channel[channum].slots[0] = &opl3.slot[2 * channum]; - opl3.channel[channum].slots[1] = &opl3.slot[2 * channum + 1]; + opl3.channel[channum].slots[0] = &opl3.slot[ch_slot[channum]]; + opl3.channel[channum].slots[1] = &opl3.slot[ch_slot[channum] + 3]; + opl3.slot[ch_slot[channum]].channel = &opl3.channel[channum]; + opl3.slot[ch_slot[channum] + 3].channel = &opl3.channel[channum]; if ((channum % 9) < 3) { opl3.channel[channum].pair = &opl3.channel[channum + 3]; } @@ -816,6 +908,8 @@ void NukedOPL3::Reset() { chan_setupalg(&opl3.channel[channum]); } opl3.noise = 0x306600; + opl3.timer = 0; + opl3.FullPan = FullPan; } void NukedOPL3::WriteReg(int reg, int v) { @@ -903,58 +997,11 @@ void NukedOPL3::WriteReg(int reg, int v) { } void NukedOPL3::Update(float* sndptr, int numsamples) { - Bit32s outa, outb; + Bit16s buffer[2]; for (Bit32u i = 0; i < (Bit32u)numsamples; i++) { - outa = 0; - outb = 0; - for (Bit8u ii = 0; ii < 36; ii++) { - slot_calgfb(&opl3.slot[ii]); - } - chan_generaterhythm(&opl3); - for (Bit8u ii = 0; ii < 18; ii++) { - chan_generate(&opl3.channel[ii]); - Bit16s accm = 0; - for (Bit8u jj = 0; jj < 4; jj++) { - accm += *opl3.channel[ii].out[jj]; - } - if (FullPan) { - outa += (Bit16s)(accm * opl3.channel[ii].fcha); - outb += (Bit16s)(accm * opl3.channel[ii].fchb); - } - else { - outa += (Bit16s)(accm & opl3.channel[ii].cha); - outb += (Bit16s)(accm & opl3.channel[ii].chb); - } - } - for (Bit8u ii = 0; ii < 36; ii++) { - envelope_calc(&opl3.slot[ii]); - pg_generate(&opl3.slot[ii]); - } - n_generate(&opl3); - opl3.timer++; - if (!(opl3.timer & 0x3f)) { - if (!opl3.tremdir) { - if (opl3.tremtval == 105) { - opl3.tremtval--; - opl3.tremdir = 1; - } - else { - opl3.tremtval++; - } - } - else { - if (opl3.tremtval == 0) { - opl3.tremtval++; - opl3.tremdir = 0; - } - else { - opl3.tremtval--; - } - } - opl3.tremval = (opl3.tremtval >> 2) >> ((1 - opl3.dam) << 1); - } - *sndptr++ += (float)(outa / 10240.0); - *sndptr++ += (float)(outb / 10240.0); + chip_generate(&opl3, buffer); + *sndptr++ += (float)(buffer[0] / 10240.0); + *sndptr++ += (float)(buffer[1] / 10240.0); } } diff --git a/src/oplsynth/nukedopl3.h b/src/oplsynth/nukedopl3.h index ccf37fe14..849646f5f 100644 --- a/src/oplsynth/nukedopl3.h +++ b/src/oplsynth/nukedopl3.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2013-2014 Nuke.YKT +* Copyright (C) 2013-2015 Nuke.YKT(Alexey Khokholov) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,7 +27,7 @@ OPL2 ROMs. */ -//version 1.5 +//version 1.6 #include "opl.h" #include "muslib.h" @@ -116,7 +116,7 @@ static const Bit8u mt[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, // ksl table // -static const Bit8u kslrom[16] = { 0, 64, 80, 90, 96, 102, 106, 110, 112, 116, 118, 120, 122, 124, 126, 127 }; +static const Bit8u kslrom[16] = { 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 }; static const Bit8u kslshift[4] = { 8, 1, 2, 0 }; @@ -133,7 +133,7 @@ static const Bit8s vibsgn_table[8] = { 1, 1, 1, 1, -1, -1, -1, -1 }; static const Bit8u eg_incstep[3][4][8] = { { { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, - { { 0, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 1, 1, 0, 1 }, { 1, 1, 1, 1, 1, 1, 0, 1 } }, + { { 0, 1, 0, 1, 0, 1, 0, 1 }, { 0, 1, 0, 1, 1, 1, 0, 1 }, { 0, 1, 1, 1, 0, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1 } }, { { 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 2, 2, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1 } } }; @@ -149,8 +149,8 @@ static const Bit8s eg_incsh[16] = { // address decoding // -static const Bit8s ad_slot[0x20] = { 0, 2, 4, 1, 3, 5, -1, -1, 6, 8, 10, 7, 9, 11, -1, -1, 12, 14, 16, 13, 15, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - +static const Bit8s ad_slot[0x20] = { 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static const Bit8u ch_slot[18] = { 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 }; struct opl_chip; struct opl_slot; @@ -167,7 +167,6 @@ struct opl_slot { Bit16s eg_out; Bit8u eg_inc; Bit8u eg_gen; - Bit8u eg_gennext; Bit8u eg_rate; Bit8u eg_ksl; Bit8u *trem; @@ -217,6 +216,8 @@ struct opl_chip { Bit8u tremdir; Bit32u noise; Bit16s zeromod; + Bit32s mixbuff[2]; + Bit8u FullPan; }; From b1b17beaf6b027ef061b3da6683dcf8b351d323a Mon Sep 17 00:00:00 2001 From: khokh2001 Date: Sun, 20 Sep 2015 02:11:03 +0900 Subject: [PATCH 2/2] nuked opl emulator update --- src/oplsynth/nukedopl3.cpp | 433 ++++++++++++++++++++----------------- src/oplsynth/nukedopl3.h | 15 +- 2 files changed, 248 insertions(+), 200 deletions(-) diff --git a/src/oplsynth/nukedopl3.cpp b/src/oplsynth/nukedopl3.cpp index 4d143f4a5..c99c5c55b 100644 --- a/src/oplsynth/nukedopl3.cpp +++ b/src/oplsynth/nukedopl3.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2013-2014 Nuke.YKT +* Copyright (C) 2013-2015 Nuke.YKT(Alexey Khokholov) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,53 +27,31 @@ OPL2 ROMs. */ -//version 1.5 +//version 1.6 /* Changelog: v1.1: - Vibrato's sign fix + Vibrato's sign fix. v1.2: - Operator key fix - Corrected 4-operator mode - Corrected rhythm mode - Some small fixes - v1.2.1: - Small envelope generator fix - Removed EX_Get function(not used) - v1.3: - Complete rewrite - (Not released) - v1.4: - New envelope and waveform generator + Operator key fix. + Corrected 4-operator mode. + Corrected rhythm mode. + Some small fixes. + v1.2.1: + Small envelope generator fix. + v1.3: + Complete rewrite. + v1.4: + New envelope and waveform generator. Some small fixes. - (Not released) v1.4.1: - Envelope generator rate calculation fix - (Not released) + Envelope generator rate calculation fix. v1.4.2: Version for ZDoom. v1.5: - Optimizations -*/ - - -/* Verified: - Noise generator. - Waveform generator. - Envelope generator increase table. - Tremolo. -*/ - -/* TODO: - Verify: - kslrom[15] value(is it 128?). - Sustain level = 15. - Vibrato, Phase generator. - Rhythm part. - Envelope generator state switching(decay->sustain when egt = 1 and decay->release). - Feedback. - Register write. - 4-operator. + Optimizations. + v1.6: + Improved emulation output. */ #include @@ -216,19 +194,17 @@ envelope_sinfunc envelope_sin[8] = { }; void envelope_gen_off(opl_slot *slott); -void envelope_gen_change(opl_slot *slott); void envelope_gen_attack(opl_slot *slott); void envelope_gen_decay(opl_slot *slott); void envelope_gen_sustain(opl_slot *slott); void envelope_gen_release(opl_slot *slott); -envelope_genfunc envelope_gen[6] = { +envelope_genfunc envelope_gen[5] = { envelope_gen_off, envelope_gen_attack, envelope_gen_decay, envelope_gen_sustain, - envelope_gen_release, - envelope_gen_change + envelope_gen_release }; enum envelope_gen_num { @@ -252,7 +228,7 @@ Bit8u envelope_calc_rate(opl_slot *slot, Bit8u reg_rate) { } void envelope_update_ksl(opl_slot *slot) { - Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 1) - ((slot->channel->block ^ 0x07) << 5) - 0x20; + Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - ((0x08 - slot->channel->block) << 5); if (ksl < 0) { ksl = 0; } @@ -281,28 +257,25 @@ void envelope_gen_off(opl_slot *slot) { slot->eg_rout = 0x1ff; } -void envelope_gen_change(opl_slot *slot) { - slot->eg_gen = slot->eg_gennext; - envelope_update_rate(slot); -} - void envelope_gen_attack(opl_slot *slot) { + if (slot->eg_rout == 0x00) { + slot->eg_gen = envelope_gen_num_decay; + envelope_update_rate(slot); + return; + } slot->eg_rout += ((~slot->eg_rout) *slot->eg_inc) >> 3; if (slot->eg_rout < 0x00) { slot->eg_rout = 0x00; } - if (!slot->eg_rout) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_decay; - } } void envelope_gen_decay(opl_slot *slot) { - slot->eg_rout += slot->eg_inc; if (slot->eg_rout >= slot->reg_sl << 4) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_sustain; + slot->eg_gen = envelope_gen_num_sustain; + envelope_update_rate(slot); + return; } + slot->eg_rout += slot->eg_inc; } void envelope_gen_sustain(opl_slot *slot) { @@ -312,11 +285,13 @@ void envelope_gen_sustain(opl_slot *slot) { } void envelope_gen_release(opl_slot *slot) { - slot->eg_rout += slot->eg_inc; if (slot->eg_rout >= 0x1ff) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_off; + slot->eg_gen = envelope_gen_num_off; + slot->eg_rout = 0x1ff; + envelope_update_rate(slot); + return; } + slot->eg_rout += slot->eg_inc; } void envelope_calc(opl_slot *slot) { @@ -324,10 +299,7 @@ void envelope_calc(opl_slot *slot) { rate_h = slot->eg_rate >> 2; rate_l = slot->eg_rate & 3; Bit8u inc = 0; - if (slot->eg_gen == envelope_gen_num_attack && rate_h == 0x0f) { - inc = 8; - } - else if (eg_incsh[rate_h] > 0) { + if (eg_incsh[rate_h] > 0) { if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) { inc = eg_incstep[eg_incdesc[rate_h]][rate_l][((slot->chip->timer) >> eg_incsh[rate_h]) & 0x07]; } @@ -336,14 +308,19 @@ void envelope_calc(opl_slot *slot) { inc = eg_incstep[eg_incdesc[rate_h]][rate_l][slot->chip->timer & 0x07] << (-eg_incsh[rate_h]); } slot->eg_inc = inc; - envelope_gen[slot->eg_gen](slot); slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; + envelope_gen[slot->eg_gen](slot); } void eg_keyon(opl_slot *slot, Bit8u type) { if (!slot->key) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_attack; + slot->eg_gen = envelope_gen_num_attack; + envelope_update_rate(slot); + if ((slot->eg_rate >> 2) == 0x0f) { + slot->eg_gen = envelope_gen_num_decay; + envelope_update_rate(slot); + slot->eg_rout = 0x00; + } slot->pg_phase = 0x00; } slot->key |= type; @@ -353,8 +330,8 @@ void eg_keyoff(opl_slot *slot, Bit8u type) { if (slot->key) { slot->key &= (~type); if (!slot->key) { - slot->eg_gen = envelope_gen_num_change; - slot->eg_gennext = envelope_gen_num_release; + slot->eg_gen = envelope_gen_num_release; + envelope_update_rate(slot); } } } @@ -366,7 +343,7 @@ void eg_keyoff(opl_slot *slot, Bit8u type) { void pg_generate(opl_slot *slot) { Bit16u f_num = slot->channel->f_num; if (slot->reg_vib) { - Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10)&0x07] + (0x01 - slot->chip->dvb)); + Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10) & 0x07] + (0x01 - slot->chip->dvb)); f_num += f_num_high * vibsgn_table[(slot->chip->timer >> 10) & 0x07]; } slot->pg_phase += (((f_num << slot->channel->block) >> 1) * mt[slot->reg_mult]) >> 1; @@ -387,7 +364,7 @@ void n_generate(opl_chip *chip) { // Slot // -void slot_write20(opl_slot *slot,Bit8u data) { +void slot_write20(opl_slot *slot, Bit8u data) { if ((data >> 7) & 0x01) { slot->trem = &slot->chip->tremval; } @@ -434,14 +411,14 @@ void slot_generatephase(opl_slot *slot, Bit16u phase) { } void slot_generate(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9) + (*slot->mod), slot->eg_out); + slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9) + (*slot->mod), slot->eg_out); } void slot_generatezm(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((slot->pg_phase >> 9), slot->eg_out); + slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9), slot->eg_out); } -void slot_calgfb(opl_slot *slot) { +void slot_calcfb(opl_slot *slot) { slot->prout[1] = slot->prout[0]; slot->prout[0] = slot->out; if (slot->channel->fb != 0x00) { @@ -461,57 +438,61 @@ void chan_setupalg(opl_channel *channel); void chan_updaterhythm(opl_chip *chip, Bit8u data) { chip->rhy = data & 0x3f; if (chip->rhy & 0x20) { - chip->channel[6].out[0] = &chip->slot[13].out; - chip->channel[6].out[1] = &chip->slot[13].out; - chip->channel[6].out[2] = &chip->zeromod; - chip->channel[6].out[3] = &chip->zeromod; - chip->channel[7].out[0] = &chip->slot[14].out; - chip->channel[7].out[1] = &chip->slot[14].out; - chip->channel[7].out[2] = &chip->slot[15].out; - chip->channel[7].out[3] = &chip->slot[15].out; - chip->channel[8].out[0] = &chip->slot[16].out; - chip->channel[8].out[1] = &chip->slot[16].out; - chip->channel[8].out[2] = &chip->slot[17].out; - chip->channel[8].out[3] = &chip->slot[17].out; + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *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 (Bit8u chnum = 6; chnum < 9; chnum++) { chip->channel[chnum].chtype = ch_drum; } + chan_setupalg(channel6); //hh if (chip->rhy & 0x01) { - eg_keyon(&chip->slot[14], egk_drum); + eg_keyon(channel7->slots[0], egk_drum); } else { - eg_keyoff(&chip->slot[14], egk_drum); + eg_keyoff(channel7->slots[0], egk_drum); } //tc if (chip->rhy & 0x02) { - eg_keyon(&chip->slot[17], egk_drum); + eg_keyon(channel8->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[17], egk_drum); + eg_keyoff(channel8->slots[1], egk_drum); } //tom if (chip->rhy & 0x04) { - eg_keyon(&chip->slot[16], egk_drum); + eg_keyon(channel8->slots[0], egk_drum); } else { - eg_keyoff(&chip->slot[16], egk_drum); + eg_keyoff(channel8->slots[0], egk_drum); } //sd if (chip->rhy & 0x08) { - eg_keyon(&chip->slot[15], egk_drum); + eg_keyon(channel7->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[15], egk_drum); + eg_keyoff(channel7->slots[1], egk_drum); } //bd if (chip->rhy & 0x10) { - eg_keyon(&chip->slot[12], egk_drum); - eg_keyon(&chip->slot[13], egk_drum); + eg_keyon(channel6->slots[0], egk_drum); + eg_keyon(channel6->slots[1], egk_drum); } else { - eg_keyoff(&chip->slot[12], egk_drum); - eg_keyoff(&chip->slot[13], egk_drum); + eg_keyoff(channel6->slots[0], egk_drum); + eg_keyoff(channel6->slots[1], egk_drum); } } else { @@ -566,6 +547,16 @@ void chan_writeb0(opl_channel *channel, Bit8u data) { void chan_setupalg(opl_channel *channel) { if (channel->chtype == ch_drum) { + switch (channel->alg & 0x01) { + case 0x00: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->slots[0]->out; + break; + case 0x01: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->chip->zeromod; + break; + } return; } if (channel->alg & 0x08) { @@ -672,49 +663,39 @@ void chan_writec0(opl_channel *channel, Bit8u data) { } } -void chan_generaterhythm(opl_chip *chip) { - if (chip->rhy & 0x20) { - opl_channel *channel6 = &chip->channel[6]; - opl_channel *channel7 = &chip->channel[7]; - opl_channel *channel8 = &chip->channel[8]; - slot_generate(channel6->slots[0]); - slot_generate(channel6->slots[1]); - Bit16u phase14 = channel7->slots[0]->pg_phase & 0x3ff; - Bit16u phase17 = channel8->slots[1]->pg_phase & 0x3ff; - Bit16u phase = 0x00; - //hh tc phase bit - Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - //hh - phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); - slot_generatephase(channel7->slots[0], phase); - //sd - phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); - slot_generatephase(channel7->slots[1], phase); - //tt - slot_generatezm(channel8->slots[0]); - //tc - phase = 0x100 | (phasebit << 9); - slot_generatephase(channel8->slots[1], phase); - } +void chan_generaterhythm1(opl_chip *chip) { + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *channel8 = &chip->channel[8]; + slot_generate(channel6->slots[0]); + Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + Bit16u phase = 0x00; + //hh tc phase bit + Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //hh + phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); + slot_generatephase(channel7->slots[0], phase); + //tt + slot_generatezm(channel8->slots[0]); } -void chan_generate(opl_channel *channel) { - if (channel->chtype == ch_drum) { - return; - } - if (channel->alg & 0x08) { - return; - } - if (channel->alg & 0x04) { - slot_generate(channel->pair->slots[0]); - slot_generate(channel->pair->slots[1]); - slot_generate(channel->slots[0]); - slot_generate(channel->slots[1]); - } - else { - slot_generate(channel->slots[0]); - slot_generate(channel->slots[1]); - } +void chan_generaterhythm2(opl_chip *chip) { + opl_channel *channel6 = &chip->channel[6]; + opl_channel *channel7 = &chip->channel[7]; + opl_channel *channel8 = &chip->channel[8]; + slot_generate(channel6->slots[1]); + Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + Bit16u phase = 0x00; + //hh tc phase bit + Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //sd + phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); + slot_generatephase(channel7->slots[1], phase); + //tc + phase = 0x100 | (phasebit << 9); + slot_generatephase(channel8->slots[1], phase); } void chan_enable(opl_channel *channel) { @@ -782,21 +763,132 @@ Bit16s limshort(Bit32s a) { return (Bit16s)a; } +void chip_generate(opl_chip *chip, Bit16s *buff) { + buff[1] = limshort(chip->mixbuff[1]); + + for (Bit8u ii = 0; ii < 12; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + for (Bit8u ii = 12; ii < 15; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) { + chan_generaterhythm1(chip); + } + else { + slot_generate(&chip->slot[12]); + slot_generate(&chip->slot[13]); + slot_generate(&chip->slot[14]); + } + + chip->mixbuff[0] = 0; + for (Bit8u ii = 0; ii < 18; ii++) { + Bit16s accm = 0; + for (Bit8u jj = 0; jj < 4; jj++) { + accm += *chip->channel[ii].out[jj]; + } + if (chip->FullPan) { + chip->mixbuff[0] += (Bit16s)(accm * chip->channel[ii].fcha); + } + else { + chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); + } + } + + for (Bit8u ii = 15; ii < 18; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) { + chan_generaterhythm2(chip); + } + else { + slot_generate(&chip->slot[15]); + slot_generate(&chip->slot[16]); + slot_generate(&chip->slot[17]); + } + + buff[0] = limshort(chip->mixbuff[0]); + + for (Bit8u ii = 18; ii < 33; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + chip->mixbuff[1] = 0; + for (Bit8u ii = 0; ii < 18; ii++) { + Bit16s accm = 0; + for (Bit8u jj = 0; jj < 4; jj++) { + accm += *chip->channel[ii].out[jj]; + } + if (chip->FullPan) { + chip->mixbuff[1] += (Bit16s)(accm * chip->channel[ii].fchb); + } + else { + chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); + } + } + + for (Bit8u ii = 33; ii < 36; ii++) { + slot_calcfb(&chip->slot[ii]); + pg_generate(&chip->slot[ii]); + envelope_calc(&chip->slot[ii]); + slot_generate(&chip->slot[ii]); + } + + n_generate(chip); + + if ((chip->timer & 0x3f) == 0x3f) { + if (!chip->tremdir) { + if (chip->tremtval == 105) { + chip->tremtval--; + chip->tremdir = 1; + } + else { + chip->tremtval++; + } + } + else { + if (chip->tremtval == 0) { + chip->tremtval++; + chip->tremdir = 0; + } + else { + chip->tremtval--; + } + } + chip->tremval = (chip->tremtval >> 2) >> ((1 - chip->dam) << 1); + } + + chip->timer++; +} + void NukedOPL3::Reset() { memset(&opl3, 0, sizeof(opl_chip)); for (Bit8u slotnum = 0; slotnum < 36; slotnum++) { - opl3.slot[slotnum].channel = &opl3.channel[slotnum / 2]; opl3.slot[slotnum].chip = &opl3; opl3.slot[slotnum].mod = &opl3.zeromod; opl3.slot[slotnum].eg_rout = 0x1ff; opl3.slot[slotnum].eg_out = 0x1ff; opl3.slot[slotnum].eg_gen = envelope_gen_num_off; - opl3.slot[slotnum].eg_gennext = envelope_gen_num_off; opl3.slot[slotnum].trem = (Bit8u*)&opl3.zeromod; } for (Bit8u channum = 0; channum < 18; channum++) { - opl3.channel[channum].slots[0] = &opl3.slot[2 * channum]; - opl3.channel[channum].slots[1] = &opl3.slot[2 * channum + 1]; + opl3.channel[channum].slots[0] = &opl3.slot[ch_slot[channum]]; + opl3.channel[channum].slots[1] = &opl3.slot[ch_slot[channum] + 3]; + opl3.slot[ch_slot[channum]].channel = &opl3.channel[channum]; + opl3.slot[ch_slot[channum] + 3].channel = &opl3.channel[channum]; if ((channum % 9) < 3) { opl3.channel[channum].pair = &opl3.channel[channum + 3]; } @@ -816,6 +908,8 @@ void NukedOPL3::Reset() { chan_setupalg(&opl3.channel[channum]); } opl3.noise = 0x306600; + opl3.timer = 0; + opl3.FullPan = FullPan; } void NukedOPL3::WriteReg(int reg, int v) { @@ -903,58 +997,11 @@ void NukedOPL3::WriteReg(int reg, int v) { } void NukedOPL3::Update(float* sndptr, int numsamples) { - Bit32s outa, outb; + Bit16s buffer[2]; for (Bit32u i = 0; i < (Bit32u)numsamples; i++) { - outa = 0; - outb = 0; - for (Bit8u ii = 0; ii < 36; ii++) { - slot_calgfb(&opl3.slot[ii]); - } - chan_generaterhythm(&opl3); - for (Bit8u ii = 0; ii < 18; ii++) { - chan_generate(&opl3.channel[ii]); - Bit16s accm = 0; - for (Bit8u jj = 0; jj < 4; jj++) { - accm += *opl3.channel[ii].out[jj]; - } - if (FullPan) { - outa += (Bit16s)(accm * opl3.channel[ii].fcha); - outb += (Bit16s)(accm * opl3.channel[ii].fchb); - } - else { - outa += (Bit16s)(accm & opl3.channel[ii].cha); - outb += (Bit16s)(accm & opl3.channel[ii].chb); - } - } - for (Bit8u ii = 0; ii < 36; ii++) { - envelope_calc(&opl3.slot[ii]); - pg_generate(&opl3.slot[ii]); - } - n_generate(&opl3); - opl3.timer++; - if (!(opl3.timer & 0x3f)) { - if (!opl3.tremdir) { - if (opl3.tremtval == 105) { - opl3.tremtval--; - opl3.tremdir = 1; - } - else { - opl3.tremtval++; - } - } - else { - if (opl3.tremtval == 0) { - opl3.tremtval++; - opl3.tremdir = 0; - } - else { - opl3.tremtval--; - } - } - opl3.tremval = (opl3.tremtval >> 2) >> ((1 - opl3.dam) << 1); - } - *sndptr++ += (float)(outa / 10240.0); - *sndptr++ += (float)(outb / 10240.0); + chip_generate(&opl3, buffer); + *sndptr++ += (float)(buffer[0] / 10240.0); + *sndptr++ += (float)(buffer[1] / 10240.0); } } diff --git a/src/oplsynth/nukedopl3.h b/src/oplsynth/nukedopl3.h index ccf37fe14..849646f5f 100644 --- a/src/oplsynth/nukedopl3.h +++ b/src/oplsynth/nukedopl3.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2013-2014 Nuke.YKT +* Copyright (C) 2013-2015 Nuke.YKT(Alexey Khokholov) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,7 +27,7 @@ OPL2 ROMs. */ -//version 1.5 +//version 1.6 #include "opl.h" #include "muslib.h" @@ -116,7 +116,7 @@ static const Bit8u mt[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, // ksl table // -static const Bit8u kslrom[16] = { 0, 64, 80, 90, 96, 102, 106, 110, 112, 116, 118, 120, 122, 124, 126, 127 }; +static const Bit8u kslrom[16] = { 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 }; static const Bit8u kslshift[4] = { 8, 1, 2, 0 }; @@ -133,7 +133,7 @@ static const Bit8s vibsgn_table[8] = { 1, 1, 1, 1, -1, -1, -1, -1 }; static const Bit8u eg_incstep[3][4][8] = { { { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }, - { { 0, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 0, 1, 0, 1 }, { 1, 1, 0, 1, 1, 1, 0, 1 }, { 1, 1, 1, 1, 1, 1, 0, 1 } }, + { { 0, 1, 0, 1, 0, 1, 0, 1 }, { 0, 1, 0, 1, 1, 1, 0, 1 }, { 0, 1, 1, 1, 0, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1 } }, { { 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 2, 2, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1 } } }; @@ -149,8 +149,8 @@ static const Bit8s eg_incsh[16] = { // address decoding // -static const Bit8s ad_slot[0x20] = { 0, 2, 4, 1, 3, 5, -1, -1, 6, 8, 10, 7, 9, 11, -1, -1, 12, 14, 16, 13, 15, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - +static const Bit8s ad_slot[0x20] = { 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static const Bit8u ch_slot[18] = { 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 }; struct opl_chip; struct opl_slot; @@ -167,7 +167,6 @@ struct opl_slot { Bit16s eg_out; Bit8u eg_inc; Bit8u eg_gen; - Bit8u eg_gennext; Bit8u eg_rate; Bit8u eg_ksl; Bit8u *trem; @@ -217,6 +216,8 @@ struct opl_chip { Bit8u tremdir; Bit32u noise; Bit16s zeromod; + Bit32s mixbuff[2]; + Bit8u FullPan; };