Archived
1
0
Fork 0
This repository has been archived on 2025-09-02. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
skcblitz/opl3.h
2025-09-02 14:43:36 +02:00

932 lines
23 KiB
C

// 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;
}