933 lines
23 KiB
C
933 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;
|
||
|
}
|