// Envelope generator short OPL3_EnvelopeCalcExp(uint level) { if (level > 0x1fff) { level = 0x1fff; } return (exprom[level & 0xff] << 1) >> (level >> 8); } short OPL3_EnvelopeCalcSin0(ushort phase, ushort envelope) { ushort out = 0; ushort neg = 0; phase &= 0x3ff; if (phase & 0x200) { neg = 0xffff; } if (phase & 0x100) { out = logsinrom[(phase & 0xff) ^ 0xff]; } else { out = logsinrom[phase & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; } short OPL3_EnvelopeCalcSin1(ushort phase, ushort envelope) { ushort out = 0; phase &= 0x3ff; if (phase & 0x200) { out = 0x1000; } else if (phase & 0x100) { out = logsinrom[(phase & 0xff) ^ 0xff]; } else { out = logsinrom[phase & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)); } short OPL3_EnvelopeCalcSin2(ushort phase, ushort envelope) { ushort out = 0; phase &= 0x3ff; if (phase & 0x100) { out = logsinrom[(phase & 0xff) ^ 0xff]; } else { out = logsinrom[phase & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)); } short OPL3_EnvelopeCalcSin3(ushort phase, ushort envelope) { ushort out = 0; phase &= 0x3ff; if (phase & 0x100) { out = 0x1000; } else { out = logsinrom[phase & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)); } short OPL3_EnvelopeCalcSin4(ushort phase, ushort envelope) { ushort out = 0; ushort neg = 0; phase &= 0x3ff; if ((phase & 0x300) == 0x100) { neg = 0xffff; } if (phase & 0x200) { out = 0x1000; } else if (phase & 0x80) { out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; } else { out = logsinrom[(phase << 1) & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; } short OPL3_EnvelopeCalcSin5(ushort phase, ushort envelope) { ushort out = 0; phase &= 0x3ff; if (phase & 0x200) { out = 0x1000; } else if (phase & 0x80) { out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; } else { out = logsinrom[(phase << 1) & 0xff]; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)); } short OPL3_EnvelopeCalcSin6(ushort phase, ushort envelope) { ushort neg = 0; phase &= 0x3ff; if (phase & 0x200) { neg = 0xffff; } return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg; } short OPL3_EnvelopeCalcSin7(ushort phase, ushort envelope) { ushort out = 0; ushort neg = 0; phase &= 0x3ff; if (phase & 0x200) { neg = 0xffff; phase = (phase & 0x1ff) ^ 0x1ff; } out = phase << 3; return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; } short OPL3_EnvelopeCalcTri(ushort phase, ushort envelope) { ushort out = 0; ushort neg = 0; phase &= 0x3ff; if (phase & 0x200) { neg = 0xffff; } if (phase & 0x100) { out = (phase & 0xff) << 3; } else { out = ~(phase & 0xff) << 3; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; } short OPL3_EnvelopeCalcSqr25(ushort phase, ushort envelope) { ushort neg = 0; phase &= 0x3ff; if (phase & 0x300) { neg = 0xffff; } return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg; } short OPL3_EnvelopeCalcSqr12(ushort phase, ushort envelope) { ushort neg = 0; phase &= 0x3ff; if (phase & 0x380) { neg = 0xffff; } return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg; } short OPL3_EnvelopeCalcSaw(ushort phase, ushort envelope) { ushort out = 0; ushort neg = 0; phase &= 0x3ff; if (phase & 0x200) { neg = 0xffff; out = ~(phase & 0x1ff) << 2; } else { out = (phase & 0x1ff) << 2; } return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; } short OPL3_EnvelopeCalcNoise(ushort phase, ushort envelope) { ushort out = 0; ushort neg = 0; phase &= 0x3ff; if ((phase ^ rng_table[~phase & 0xff]) & 1) { neg = 0xffff; } out = rng_table[phase & 0xff] << 2; return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; } static const envelope_sinfunc envelope_sin[16] = { OPL3_EnvelopeCalcSin0, OPL3_EnvelopeCalcSin1, OPL3_EnvelopeCalcSin2, OPL3_EnvelopeCalcSin3, OPL3_EnvelopeCalcSin4, OPL3_EnvelopeCalcSin5, OPL3_EnvelopeCalcSin6, OPL3_EnvelopeCalcSin7, OPL3_EnvelopeCalcTri, OPL3_EnvelopeCalcSqr25, OPL3_EnvelopeCalcSqr12, OPL3_EnvelopeCalcSaw, OPL3_EnvelopeCalcNoise, OPL3_EnvelopeCalcNoise, OPL3_EnvelopeCalcNoise, OPL3_EnvelopeCalcNoise, }; void OPL3_EnvelopeCalc(opl3_slot *slot) { byte nonzero; byte rate; byte rate_hi; byte rate_lo; byte reg_rate = 0; byte ks; byte eg_shift, shift; ushort eg_rout; short eg_inc; byte eg_off; byte reset = 0; if(slot->retrigger) { slot->eg_rout = 0x1ff; } slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; if (slot->key && slot->eg_gen == envelope_gen_num_release) { reset = 1; reg_rate = slot->reg_ar; } else { switch (slot->eg_gen) { case envelope_gen_num_attack: reg_rate = slot->reg_ar; break; case envelope_gen_num_decay: reg_rate = slot->reg_dr; break; case envelope_gen_num_sustain: if (!slot->reg_type) { reg_rate = slot->reg_rr; } break; case envelope_gen_num_release: reg_rate = slot->reg_rr; break; } } slot->pg_reset = reset; ks = slot->channel->ksv >> ((slot->reg_ksr ^ 1) << 1); nonzero = (reg_rate != 0); rate = ks + (reg_rate << 2); rate_hi = rate >> 2; rate_lo = rate & 0x03; if (rate_hi & 0x10) { rate_hi = 0x0f; } eg_shift = rate_hi + slot->chip->eg_add; shift = 0; if (nonzero) { if (rate_hi < 12) { if (slot->chip->eg_state) { switch (eg_shift) { case 12: shift = 1; break; case 13: shift = (rate_lo >> 1) & 0x01; break; case 14: shift = rate_lo & 0x01; break; default: break; } } } else { shift = (rate_hi & 0x03) + eg_incstep[rate_lo][slot->chip->timer & 0x03]; if (shift & 0x04) { shift = 0x03; } if (!shift) { shift = slot->chip->eg_state; } } } eg_rout = slot->eg_rout; eg_inc = 0; eg_off = 0; /* Instant attack */ if (reset && rate_hi == 0x0f) { eg_rout = 0x00; } /* Envelope off */ if ((slot->eg_rout & 0x1f8) == 0x1f8) { eg_off = 1; } if (slot->eg_gen != envelope_gen_num_attack && !reset && eg_off) { eg_rout = 0x1ff; } switch (slot->eg_gen) { case envelope_gen_num_attack: if (!(slot->eg_rout)) { slot->eg_gen = envelope_gen_num_decay; } else if (slot->key && shift > 0 && rate_hi != 0x0f) { eg_inc = ~slot->eg_rout >> (4 - shift); } break; case envelope_gen_num_decay: if ((slot->eg_rout >> 4) == slot->reg_sl) { slot->eg_gen = envelope_gen_num_sustain; } else if (!eg_off && !reset && shift > 0) { eg_inc = 1 << (shift - 1); } break; case envelope_gen_num_sustain: case envelope_gen_num_release: if (!eg_off && !reset && shift > 0) { eg_inc = 1 << (shift - 1); } break; } slot->eg_rout = (eg_rout + eg_inc) & 0x1ff; /* Key off */ if (reset) { slot->eg_gen = envelope_gen_num_attack; } if (!(slot->key)) { slot->eg_gen = envelope_gen_num_release; } slot->detrigger = 0; slot->retrigger = 0; } void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) { short ksl = (kslrom[slot->channel->f_num >> 6] << 2) - ((0x08 - slot->channel->block) << 5); if (ksl < 0) { ksl = 0; } slot->eg_ksl = (byte)ksl; } void OPL3_EnvelopeKeyOn(opl3_slot *slot) { slot->key = 0x01; if(slot->detrigger) { slot->eg_gen = envelope_gen_num_release; // slot->eg_rout = 0x1ff; // slot->eg_out = slot->eg_rout = 0x1ff; slot->detrigger = 0; } slot->retrigger = 1; } void OPL3_EnvelopeKeyOff(opl3_slot *slot) { slot->key = 0x00; slot->detrigger = 1; slot->retrigger = 0; } void OPL3_PhaseGenerate(opl3_slot *slot) { opl3_chip *chip; ushort f_num; uint basefreq; ushort phase; chip = slot->chip; f_num = slot->channel->f_num; if (slot->reg_vib) { char range; byte vibpos; range = (f_num >> 7) & 7; vibpos = slot->chip->vibpos; if (!(vibpos & 3)) { range = 0; } else if (vibpos & 1) { range >>= 1; } range >>= slot->chip->vibshift; if (vibpos & 4) { range = -range; } f_num += range; } basefreq = (f_num << slot->channel->block) >> 1; phase = (ushort)(slot->pg_phase >> 9); if (slot->pg_reset) { slot->pg_phase = 0; } slot->pg_phase += (basefreq * op_mt[slot->reg_mult]) >> 1; slot->pg_phase_out = phase; } void OPL3_SlotGenerate(opl3_slot *slot) { slot->out = envelope_sin[slot->reg_wf](slot->pg_phase_out + *slot->mod, slot->eg_out); } void OPL3_SlotCalcFB(opl3_slot *slot) { if (slot->channel->fb != 0x00) { slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->channel->fb); } else { slot->fbmod = 0; } slot->prout = slot->out; } void OPL3_ProcessSlot(opl3_slot *slot) { OPL3_SlotCalcFB(slot); OPL3_EnvelopeCalc(slot); OPL3_PhaseGenerate(slot); OPL3_SlotGenerate(slot); } short OPL3_ClipSampleOld(int sample) { if (sample > 32767) { sample = 32767; } else if (sample < -32768) { sample = -32768; } return (short)sample; } short OPL3_ClipSample(int sample) { int sign = (sample < 0) ? -1 : 1; sample = (sample < 0) ? -sample : sample; sample *= 5; sample /= 8; sample = sample > 32767 ? 32767 : sample; sample *= sign; return (short)sample; } void OPL3_Generate(opl3_chip *chip, short *buf) { opl3_channel *channel; short **out; int mix[2]; byte ii; short accm; byte shift = 0; buf[0] = OPL3_ClipSample(chip->mixbuff[0]); buf[1] = OPL3_ClipSample(chip->mixbuff[1]); for (ii = 0; ii < (chip->n_voices * 2); ii++) { OPL3_ProcessSlot(&chip->slot[ii]); } mix[0] = mix[1] = 0; for (ii = 0; ii < chip->n_voices; ii++) { channel = &chip->channel[ii]; out = channel->out; accm = *out[0] + *out[1] + *out[2] + *out[3]; mix[0] += (short)((accm * channel->level[0]) >> 16); mix[1] += (short)((accm * channel->level[1]) >> 16); } chip->mixbuff[0] = mix[0]; chip->mixbuff[1] = mix[1]; if ((chip->timer & 0x3f) == 0x3f) { chip->tremolopos = (chip->tremolopos + 1) % 210; } if (chip->tremolopos < 105) { chip->tremolo = chip->tremolopos >> chip->tremoloshift; } else { chip->tremolo = (210 - chip->tremolopos) >> chip->tremoloshift; } if ((chip->timer & 0x3ff) == 0x3ff) { chip->vibpos = (chip->vibpos + 1) & 7; } chip->timer++; chip->eg_add = 0; if (chip->eg_timer) { while (shift < 36 && ((chip->eg_timer >> shift) & 1) == 0) { shift++; } if (shift > 12) { chip->eg_add = 0; } else { chip->eg_add = shift + 1; } } if (chip->eg_timerrem || chip->eg_state) { 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; } void OPL3_GenerateResampled(opl3_chip *chip, short *buf) { while (chip->samplecnt >= chip->rateratio) { chip->oldsamples[0] = chip->samples[0]; chip->oldsamples[1] = chip->samples[1]; OPL3_Generate(chip, chip->samples); chip->samplecnt -= chip->rateratio; } buf[0] = (short)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) + chip->samples[0] * chip->samplecnt) / chip->rateratio); buf[1] = (short)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) + chip->samples[1] * chip->samplecnt) / chip->rateratio); chip->samplecnt += 1 << RSM_FRAC; } // Operator void OPL3_SlotFlags(opl3_slot *slot, byte tremolo, byte vibrato, byte sustaining, byte ksr) { if (tremolo) { slot->trem = &slot->chip->tremolo; } else { slot->trem = (byte*)&slot->chip->zeromod; } slot->reg_vib = vibrato & 0x01; slot->reg_type = sustaining & 0x01; slot->reg_ksr = ksr & 0x01; } void OPL3_SlotMult(opl3_slot *slot, byte mult) { slot->reg_mult = mult & 0x0f; } void OPL3_SlotKSL(opl3_slot *slot, byte ksl) { slot->reg_ksl = ksl & 0x03; OPL3_EnvelopeUpdateKSL(slot); } void OPL3_SlotLevel(opl3_slot *slot, byte level) { slot->reg_tl = level & 0x3f; } void OPL3_SlotADSR(opl3_slot *slot, byte attack, byte decay, byte sustain, byte release) { slot->reg_ar = attack & 0x0f; slot->reg_dr = decay & 0x0f; slot->reg_sl = sustain & 0x0f; if (slot->reg_sl == 0x0f) { slot->reg_sl = 0x1f; } slot->reg_rr = release & 0x0f; if (slot->reg_rr == 0x00) { slot->reg_rr = 0x01; } } void OPL3_SlotWaveform(opl3_slot *slot, byte waveform) { slot->reg_wf = waveform & 0x07; } void OPL3_SlotWaveformNew(opl3_slot *slot, byte waveform) { slot->reg_wf = waveform & 0x0f; } // Channel void OPL3_ChannelSetupAlg(opl3_channel *channel) { if (channel->alg & 0x08) { return; } if (channel->alg & 0x04) { channel->pair->out[0] = &channel->chip->zeromod; channel->pair->out[1] = &channel->chip->zeromod; channel->pair->out[2] = &channel->chip->zeromod; channel->pair->out[3] = &channel->chip->zeromod; switch (channel->alg & 0x03) { case 0x00: channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; channel->slots[0]->mod = &channel->pair->slots[1]->out; channel->slots[1]->mod = &channel->slots[0]->out; channel->out[0] = &channel->slots[1]->out; channel->out[1] = &channel->chip->zeromod; channel->out[2] = &channel->chip->zeromod; channel->out[3] = &channel->chip->zeromod; break; case 0x01: channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; channel->slots[0]->mod = &channel->chip->zeromod; channel->slots[1]->mod = &channel->slots[0]->out; channel->out[0] = &channel->pair->slots[1]->out; channel->out[1] = &channel->slots[1]->out; channel->out[2] = &channel->chip->zeromod; channel->out[3] = &channel->chip->zeromod; break; case 0x02: channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; channel->pair->slots[1]->mod = &channel->chip->zeromod; channel->slots[0]->mod = &channel->pair->slots[1]->out; channel->slots[1]->mod = &channel->slots[0]->out; channel->out[0] = &channel->pair->slots[0]->out; channel->out[1] = &channel->slots[1]->out; channel->out[2] = &channel->chip->zeromod; channel->out[3] = &channel->chip->zeromod; break; case 0x03: channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; channel->pair->slots[1]->mod = &channel->chip->zeromod; channel->slots[0]->mod = &channel->pair->slots[1]->out; channel->slots[1]->mod = &channel->chip->zeromod; channel->out[0] = &channel->pair->slots[0]->out; channel->out[1] = &channel->slots[0]->out; channel->out[2] = &channel->slots[1]->out; channel->out[3] = &channel->chip->zeromod; break; } } else { switch (channel->alg & 0x01) { case 0x00: channel->slots[0]->mod = &channel->slots[0]->fbmod; channel->slots[1]->mod = &channel->slots[0]->out; channel->out[0] = &channel->slots[1]->out; channel->out[1] = &channel->chip->zeromod; channel->out[2] = &channel->chip->zeromod; channel->out[3] = &channel->chip->zeromod; break; case 0x01: channel->slots[0]->mod = &channel->slots[0]->fbmod; channel->slots[1]->mod = &channel->chip->zeromod; channel->out[0] = &channel->slots[0]->out; channel->out[1] = &channel->slots[1]->out; channel->out[2] = &channel->chip->zeromod; channel->out[3] = &channel->chip->zeromod; break; } } } void OPL3_ChannelUpdateAlg(opl3_channel *channel) { channel->alg = channel->con; if (channel->chtype == ch_4op) { channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); channel->alg = 0x08; OPL3_ChannelSetupAlg(channel->pair); } else if (channel->chtype == ch_4op2) { channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); channel->pair->alg = 0x08; OPL3_ChannelSetupAlg(channel); } else { OPL3_ChannelSetupAlg(channel); } } void OPL3_ChannelFreq(opl3_channel *channel, byte block, ushort f_num) { if (channel->chtype == ch_4op2) { return; } channel->f_num = f_num & 0x3ff; channel->block = block & 0x07; channel->ksv = (channel->block << 1) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); OPL3_EnvelopeUpdateKSL(channel->slots[0]); OPL3_EnvelopeUpdateKSL(channel->slots[1]); if (channel->chtype == ch_4op) { channel->pair->f_num = channel->f_num; channel->pair->block = channel->block; channel->pair->ksv = channel->ksv; OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); } } void OPL3_ChannelOutput(opl3_channel *channel, byte output, uint level) { channel->level[output & 1] = level; } void OPL3_Channel4Op(opl3_channel *channel, byte op4) { if (op4) { channel->chtype = ch_4op; channel->pair->chtype = ch_4op2; OPL3_ChannelUpdateAlg(channel); } else { channel->chtype = ch_2op; channel->pair->chtype = ch_2op; OPL3_ChannelUpdateAlg(channel); OPL3_ChannelUpdateAlg(channel->pair); } } void OPL3_ChannelFeedback(opl3_channel *channel, byte feedback) { channel->fb = feedback & 0x07; } void OPL3_ChannelAM(opl3_channel *channel, byte am) { channel->con = am & 0x01; OPL3_ChannelUpdateAlg(channel); } void OPL3_ChannelKeyOn(opl3_channel *channel) { if (channel->chtype == ch_4op) { OPL3_EnvelopeKeyOn(channel->slots[0]); OPL3_EnvelopeKeyOn(channel->slots[1]); OPL3_EnvelopeKeyOn(channel->pair->slots[0]); OPL3_EnvelopeKeyOn(channel->pair->slots[1]); } else if (channel->chtype == ch_2op) { OPL3_EnvelopeKeyOn(channel->slots[0]); OPL3_EnvelopeKeyOn(channel->slots[1]); } } void OPL3_ChannelKeyOff(opl3_channel *channel) { if (channel->chtype == ch_4op) { OPL3_EnvelopeKeyOff(channel->slots[0]); OPL3_EnvelopeKeyOff(channel->slots[1]); OPL3_EnvelopeKeyOff(channel->pair->slots[0]); OPL3_EnvelopeKeyOff(channel->pair->slots[1]); } else if (channel->chtype == ch_2op) { OPL3_EnvelopeKeyOff(channel->slots[0]); OPL3_EnvelopeKeyOff(channel->slots[1]); } } void OPL3_Reset(opl3_chip *chip) { byte slotnum; byte channum; int rateratio = chip->rateratio; byte n_voices = chip->n_voices; opl3_slot *slot = chip->slot; opl3_channel *channel = chip->channel; memset(chip, 0, sizeof(opl3_chip) + (n_voices * (sizeof(opl3_slot) * 2 + sizeof(opl3_channel)))); chip->rateratio = rateratio; chip->n_voices = n_voices; chip->slot = slot; chip->channel = channel; for (slotnum = 0; slotnum < (chip->n_voices * 2); slotnum++) { slot = &chip->slot[slotnum]; slot->chip = chip; slot->mod = &chip->zeromod; slot->eg_rout = 0x1ff; slot->eg_out = 0x1ff; slot->eg_gen = envelope_gen_num_release; slot->trem = (byte*)&chip->zeromod; slot->slot_num = slotnum; } for (channum = 0; channum < chip->n_voices; channum++) { channel = &chip->channel[channum]; channel->slots[0] = &chip->slot[channum * 2]; channel->slots[1] = &chip->slot[channum * 2 + 1]; chip->slot[channum * 2].channel = channel; chip->slot[channum * 2 + 1].channel = channel; channel->pair = &chip->channel[(channum & 1) ? (channum - 1) : (channum + 1)]; channel->chip = chip; channel->out[0] = &chip->zeromod; channel->out[1] = &chip->zeromod; channel->out[2] = &chip->zeromod; channel->out[3] = &chip->zeromod; channel->chtype = ch_2op; channel->level[0] = 0x10000; channel->level[1] = 0x10000; channel->ch_num = channum; OPL3_ChannelSetupAlg(channel); } chip->tremoloshift = 4; chip->vibshift = 1; } void OPL3_Rate(opl3_chip *chip, uint samplerate) { chip->rateratio = (samplerate << RSM_FRAC) / 49716; } void OPL3_ChipFlags(opl3_chip *chip, byte nts, byte vibrato, byte deeptremolo, byte deepvibrato) { chip->nts = nts; chip->tremoloshift = ((deeptremolo ^ 1) << 1) + 2; chip->vibshift = deepvibrato ^ 1; } opl3_chip *OPL3_Alloc(uint samplerate, byte voices) { opl3_chip *chip = malloc(sizeof(opl3_chip) + (voices * (sizeof(opl3_slot) * 2 + sizeof(opl3_channel)))); chip->channel = (opl3_channel*)(((byte*)chip) + sizeof(opl3_chip)); chip->slot = (opl3_slot*)(((byte*)chip->channel) + (voices * sizeof(opl3_channel))); chip->n_voices = voices; OPL3_Rate(chip, samplerate); OPL3_Reset(chip); return chip; } byte OPL3_Playing(opl3_chip *chip) { opl3_slot *slot; for(int z = 0; z < (chip->n_voices * 2); z++) { slot = &chip->slot[z]; if(slot->eg_out <= 0x100) { return 1; } } return 0; }