#include <cstdint>
class Opal {
class Channel;
enum {
OPL3SampleRate = 49716,
NumChannels = 18,
NumOperators = 36,
EnvOff = -1,
EnvAtt,
EnvDec,
EnvSus,
EnvRel,
};
class Operator {
public:
Operator();
void SetMaster(Opal *opal) { Master = opal; }
void SetChannel(Channel *chan) { Chan = chan; }
int16_t Output(uint16_t keyscalenum, uint32_t phase_step, int16_t vibrato, int16_t mod = 0, int16_t fbshift = 0);
void SetKeyOn(bool on);
void SetTremoloEnable(bool on);
void SetVibratoEnable(bool on);
void SetSustainMode(bool on);
void SetEnvelopeScaling(bool on);
void SetFrequencyMultiplier(uint16_t scale);
void SetKeyScale(uint16_t scale);
void SetOutputLevel(uint16_t level);
void SetAttackRate(uint16_t rate);
void SetDecayRate(uint16_t rate);
void SetSustainLevel(uint16_t level);
void SetReleaseRate(uint16_t rate);
void SetWaveform(uint16_t wave);
void ComputeRates();
void ComputeKeyScaleLevel();
protected:
Opal * Master; Channel * Chan; uint32_t Phase; uint16_t Waveform; uint16_t FreqMultTimes2; int EnvelopeStage; int16_t EnvelopeLevel; uint16_t OutputLevel; uint16_t AttackRate;
uint16_t DecayRate;
uint16_t SustainLevel;
uint16_t ReleaseRate;
uint16_t AttackShift;
uint16_t AttackMask;
uint16_t AttackAdd;
const uint16_t *AttackTab;
uint16_t DecayShift;
uint16_t DecayMask;
uint16_t DecayAdd;
const uint16_t *DecayTab;
uint16_t ReleaseShift;
uint16_t ReleaseMask;
uint16_t ReleaseAdd;
const uint16_t *ReleaseTab;
uint16_t KeyScaleShift;
uint16_t KeyScaleLevel;
int16_t Out[2];
bool KeyOn;
bool KeyScaleRate; bool SustainMode; bool TremoloEnable;
bool VibratoEnable;
};
class Channel {
public:
Channel();
void SetMaster(Opal *opal) { Master = opal; }
void SetOperators(Operator *a, Operator *b, Operator *c, Operator *d) {
Op[0] = a;
Op[1] = b;
Op[2] = c;
Op[3] = d;
if (a)
a->SetChannel(this);
if (b)
b->SetChannel(this);
if (c)
c->SetChannel(this);
if (d)
d->SetChannel(this);
}
void Output(int16_t &left, int16_t &right);
void SetEnable(bool on) { Enable = on; }
void SetChannelPair(Channel *pair) { ChannelPair = pair; }
void SetFrequencyLow(uint16_t freq);
void SetFrequencyHigh(uint16_t freq);
void SetKeyOn(bool on);
void SetOctave(uint16_t oct);
void SetLeftEnable(bool on);
void SetRightEnable(bool on);
void SetFeedback(uint16_t val);
void SetModulationType(uint16_t type);
uint16_t GetFreq() const { return Freq; }
uint16_t GetOctave() const { return Octave; }
uint16_t GetKeyScaleNumber() const { return KeyScaleNumber; }
uint16_t GetModulationType() const { return ModulationType; }
void ComputeKeyScaleNumber();
protected:
void ComputePhaseStep();
Operator * Op[4];
Opal * Master; uint16_t Freq; uint16_t Octave; uint32_t PhaseStep;
uint16_t KeyScaleNumber;
uint16_t FeedbackShift;
uint16_t ModulationType;
Channel * ChannelPair;
bool Enable;
bool LeftEnable, RightEnable;
};
public:
Opal(int sample_rate);
Opal(const Opal &) = delete;
Opal(Opal &&) = delete;
~Opal();
void SetSampleRate(int sample_rate);
void Port(uint16_t reg_num, uint8_t val);
void Sample(int16_t *left, int16_t *right);
protected:
void Init(int sample_rate);
void Output(int16_t &left, int16_t &right);
int32_t SampleRate;
int32_t SampleAccum;
int16_t LastOutput[2], CurrOutput[2];
Channel Chan[NumChannels];
Operator Op[NumOperators];
uint16_t Clock;
uint16_t TremoloClock;
uint16_t TremoloLevel;
uint16_t VibratoTick;
uint16_t VibratoClock;
bool NoteSel;
bool TremoloDepth;
bool VibratoDepth;
static const uint16_t RateTables[4][8];
static const uint16_t ExpTable[256];
static const uint16_t LogSinTable[256];
};
const uint16_t Opal::RateTables[4][8] = {
{ 1, 0, 1, 0, 1, 0, 1, 0 },
{ 1, 0, 1, 0, 0, 0, 1, 0 },
{ 1, 0, 0, 0, 1, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0 },
};
const uint16_t Opal::ExpTable[0x100] = {
1018, 1013, 1007, 1002, 996, 991, 986, 980, 975, 969, 964, 959, 953, 948, 942, 937,
932, 927, 921, 916, 911, 906, 900, 895, 890, 885, 880, 874, 869, 864, 859, 854,
849, 844, 839, 834, 829, 824, 819, 814, 809, 804, 799, 794, 789, 784, 779, 774,
770, 765, 760, 755, 750, 745, 741, 736, 731, 726, 722, 717, 712, 708, 703, 698,
693, 689, 684, 680, 675, 670, 666, 661, 657, 652, 648, 643, 639, 634, 630, 625,
621, 616, 612, 607, 603, 599, 594, 590, 585, 581, 577, 572, 568, 564, 560, 555,
551, 547, 542, 538, 534, 530, 526, 521, 517, 513, 509, 505, 501, 496, 492, 488,
484, 480, 476, 472, 468, 464, 460, 456, 452, 448, 444, 440, 436, 432, 428, 424,
420, 416, 412, 409, 405, 401, 397, 393, 389, 385, 382, 378, 374, 370, 367, 363,
359, 355, 352, 348, 344, 340, 337, 333, 329, 326, 322, 318, 315, 311, 308, 304,
300, 297, 293, 290, 286, 283, 279, 276, 272, 268, 265, 262, 258, 255, 251, 248,
244, 241, 237, 234, 231, 227, 224, 220, 217, 214, 210, 207, 204, 200, 197, 194,
190, 187, 184, 181, 177, 174, 171, 168, 164, 161, 158, 155, 152, 148, 145, 142,
139, 136, 133, 130, 126, 123, 120, 117, 114, 111, 108, 105, 102, 99, 96, 93,
90, 87, 84, 81, 78, 75, 72, 69, 66, 63, 60, 57, 54, 51, 48, 45,
42, 40, 37, 34, 31, 28, 25, 22, 20, 17, 14, 11, 8, 6, 3, 0,
};
const uint16_t Opal::LogSinTable[0x100] = {
2137, 1731, 1543, 1419, 1326, 1252, 1190, 1137, 1091, 1050, 1013, 979, 949, 920, 894, 869,
846, 825, 804, 785, 767, 749, 732, 717, 701, 687, 672, 659, 646, 633, 621, 609,
598, 587, 576, 566, 556, 546, 536, 527, 518, 509, 501, 492, 484, 476, 468, 461,
453, 446, 439, 432, 425, 418, 411, 405, 399, 392, 386, 380, 375, 369, 363, 358,
352, 347, 341, 336, 331, 326, 321, 316, 311, 307, 302, 297, 293, 289, 284, 280,
276, 271, 267, 263, 259, 255, 251, 248, 244, 240, 236, 233, 229, 226, 222, 219,
215, 212, 209, 205, 202, 199, 196, 193, 190, 187, 184, 181, 178, 175, 172, 169,
167, 164, 161, 159, 156, 153, 151, 148, 146, 143, 141, 138, 136, 134, 131, 129,
127, 125, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96,
94, 92, 91, 89, 87, 85, 83, 82, 80, 78, 77, 75, 74, 72, 70, 69,
67, 66, 64, 63, 62, 60, 59, 57, 56, 55, 53, 52, 51, 49, 48, 47,
46, 45, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30,
29, 28, 27, 26, 25, 24, 23, 23, 22, 21, 20, 20, 19, 18, 17, 17,
16, 15, 15, 14, 13, 13, 12, 12, 11, 10, 10, 9, 9, 8, 8, 7,
7, 7, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
};
#if 0#endif
Opal::Opal(int sample_rate) {
Init(sample_rate);
}
Opal::~Opal() {
}
void Opal::Init(int sample_rate) {
Clock = 0;
TremoloClock = 0;
VibratoTick = 0;
VibratoClock = 0;
NoteSel = false;
TremoloDepth = false;
VibratoDepth = false;
for (int i = 0; i < NumOperators; i++)
Op[i].SetMaster(this);
for (int i = 0; i < NumChannels; i++)
Chan[i].SetMaster(this);
const int chan_ops[] = {
0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32,
};
for (int i = 0; i < NumChannels; i++) {
Channel *chan = &Chan[i];
int op = chan_ops[i];
if (i < 3 || (i >= 9 && i < 12))
chan->SetOperators(&Op[op], &Op[op + 3], &Op[op + 6], &Op[op + 9]);
else
chan->SetOperators(&Op[op], &Op[op + 3], 0, 0);
}
for (int i = 0; i < NumOperators; i++)
Op[i].ComputeRates();
SetSampleRate(sample_rate);
}
void Opal::SetSampleRate(int sample_rate) {
if (sample_rate == 0)
sample_rate = OPL3SampleRate;
SampleRate = sample_rate;
SampleAccum = 0;
LastOutput[0] = LastOutput[1] = 0;
CurrOutput[0] = CurrOutput[1] = 0;
}
void Opal::Port(uint16_t reg_num, uint8_t val) {
static const int8_t op_lookup[] = {
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,
};
uint16_t type = reg_num & 0xE0;
if (reg_num == 0xBD) {
TremoloDepth = (val & 0x80) != 0;
VibratoDepth = (val & 0x40) != 0;
return;
}
if (type == 0x00) {
if (reg_num == 0x104) {
uint8_t mask = 1;
for (int i = 0; i < 6; i++, mask <<= 1) {
uint16_t chan = static_cast<uint16_t>(i < 3 ? i : i + 6);
Channel *primary = &Chan[chan];
Channel *secondary = &Chan[chan + 3];
if (val & mask) {
primary->SetChannelPair(secondary);
secondary->SetEnable(false);
} else {
primary->SetChannelPair(0);
secondary->SetEnable(true);
}
}
} else if (reg_num == 0x08) {
NoteSel = (val & 0x40) != 0;
for (int i = 0; i < NumChannels; i++)
Chan[i].ComputeKeyScaleNumber();
}
} else if (type >= 0xA0 && type <= 0xC0) {
int chan_num = reg_num & 15;
if (chan_num >= 9)
return;
if (reg_num & 0x100)
chan_num += 9;
Channel &chan = Chan[chan_num];
switch (reg_num & 0xF0) {
case 0xA0: {
chan.SetFrequencyLow(val);
break;
}
case 0xB0: {
chan.SetKeyOn((val & 0x20) != 0);
chan.SetOctave(val >> 2 & 7);
chan.SetFrequencyHigh(val & 3);
break;
}
case 0xC0: {
chan.SetRightEnable((val & 0x20) != 0);
chan.SetLeftEnable((val & 0x10) != 0);
chan.SetFeedback(val >> 1 & 7);
chan.SetModulationType(val & 1);
break;
}
}
} else if ((type >= 0x20 && type <= 0x80) || type == 0xE0) {
int op_num = op_lookup[reg_num & 0x1F];
if (op_num < 0)
return;
if (reg_num & 0x100)
op_num += 18;
Operator &op = Op[op_num];
switch (type) {
case 0x20: {
op.SetTremoloEnable((val & 0x80) != 0);
op.SetVibratoEnable((val & 0x40) != 0);
op.SetSustainMode((val & 0x20) != 0);
op.SetEnvelopeScaling((val & 0x10) != 0);
op.SetFrequencyMultiplier(val & 15);
break;
}
case 0x40: {
op.SetKeyScale(val >> 6);
op.SetOutputLevel(val & 0x3F);
break;
}
case 0x60: {
op.SetAttackRate(val >> 4);
op.SetDecayRate(val & 15);
break;
}
case 0x80: {
op.SetSustainLevel(val >> 4);
op.SetReleaseRate(val & 15);
break;
}
case 0xE0: {
op.SetWaveform(val & 7);
break;
}
}
}
}
void Opal::Sample(int16_t *left, int16_t *right) {
while (SampleAccum >= SampleRate) {
LastOutput[0] = CurrOutput[0];
LastOutput[1] = CurrOutput[1];
Output(CurrOutput[0], CurrOutput[1]);
SampleAccum -= SampleRate;
}
int32_t omblend = SampleRate - SampleAccum;
*left = static_cast<uint16_t>((LastOutput[0] * omblend + CurrOutput[0] * SampleAccum) / SampleRate);
*right = static_cast<uint16_t>((LastOutput[1] * omblend + CurrOutput[1] * SampleAccum) / SampleRate);
SampleAccum += OPL3SampleRate;
}
void Opal::Output(int16_t &left, int16_t &right) {
int32_t leftmix = 0, rightmix = 0;
for (int i = 0; i < NumChannels; i++) {
int16_t chanleft, chanright;
Chan[i].Output(chanleft, chanright);
leftmix += chanleft;
rightmix += chanright;
}
if (leftmix < -0x8000)
left = -0x8000;
else if (leftmix > 0x7FFF)
left = 0x7FFF;
else
left = static_cast<uint16_t>(leftmix);
if (rightmix < -0x8000)
right = -0x8000;
else if (rightmix > 0x7FFF)
right = 0x7FFF;
else
right = static_cast<uint16_t>(rightmix);
Clock++;
TremoloClock = (TremoloClock + 1) % 13440;
TremoloLevel = ((TremoloClock < 13440 / 2) ? TremoloClock : 13440 - TremoloClock) / 256;
if (!TremoloDepth)
TremoloLevel >>= 2;
VibratoTick++;
if (VibratoTick >= 1024) {
VibratoTick = 0;
VibratoClock = (VibratoClock + 1) & 7;
}
}
Opal::Channel::Channel() {
Master = 0;
Freq = 0;
Octave = 0;
PhaseStep = 0;
KeyScaleNumber = 0;
FeedbackShift = 0;
ModulationType = 0;
ChannelPair = 0;
Enable = true;
}
void Opal::Channel::Output(int16_t &left, int16_t &right) {
if (!Enable) {
left = right = 0;
return;
}
int16_t vibrato = (Freq >> 7) & 7;
if (!Master->VibratoDepth)
vibrato >>= 1;
uint16_t clk = Master->VibratoClock;
if (!(clk & 3))
vibrato = 0; else {
if (clk & 1)
vibrato >>= 1; if (clk & 4)
vibrato = -vibrato; }
vibrato <<= Octave;
int16_t out, acc;
if (ChannelPair) {
if (ChannelPair->GetModulationType() == 0) {
if (ModulationType == 0) {
out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift);
out = Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato, out, 0);
out = Op[2]->Output(KeyScaleNumber, PhaseStep, vibrato, out, 0);
out = Op[3]->Output(KeyScaleNumber, PhaseStep, vibrato, out, 0);
} else {
out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift);
acc = Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, 0);
acc = Op[2]->Output(KeyScaleNumber, PhaseStep, vibrato, acc, 0);
out += Op[3]->Output(KeyScaleNumber, PhaseStep, vibrato, acc, 0);
}
} else {
if (ModulationType == 0) {
out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift);
out = Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato, out, 0);
acc = Op[2]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, 0);
out += Op[3]->Output(KeyScaleNumber, PhaseStep, vibrato, acc, 0);
} else {
out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift);
acc = Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, 0);
out += Op[2]->Output(KeyScaleNumber, PhaseStep, vibrato, acc, 0);
out += Op[3]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, 0);
}
}
} else {
if (ModulationType == 0) {
out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift);
out = Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato, out, 0);
} else {
out = Op[0]->Output(KeyScaleNumber, PhaseStep, vibrato, 0, FeedbackShift);
out += Op[1]->Output(KeyScaleNumber, PhaseStep, vibrato);
}
}
left = LeftEnable ? out : 0;
right = RightEnable ? out : 0;
}
void Opal::Channel::SetFrequencyLow(uint16_t freq) {
Freq = (Freq & 0x300) | (freq & 0xFF);
ComputePhaseStep();
}
void Opal::Channel::SetFrequencyHigh(uint16_t freq) {
Freq = (Freq & 0xFF) | ((freq & 3) << 8);
ComputePhaseStep();
ComputeKeyScaleNumber();
}
void Opal::Channel::SetOctave(uint16_t oct) {
Octave = oct & 7;
ComputePhaseStep();
ComputeKeyScaleNumber();
}
void Opal::Channel::SetKeyOn(bool on) {
Op[0]->SetKeyOn(on);
Op[1]->SetKeyOn(on);
}
void Opal::Channel::SetLeftEnable(bool on) {
LeftEnable = on;
}
void Opal::Channel::SetRightEnable(bool on) {
RightEnable = on;
}
void Opal::Channel::SetFeedback(uint16_t val) {
FeedbackShift = val ? 9 - val : 0;
}
void Opal::Channel::SetModulationType(uint16_t type) {
ModulationType = type;
}
void Opal::Channel::ComputePhaseStep() {
PhaseStep = uint32_t(Freq) << Octave;
}
void Opal::Channel::ComputeKeyScaleNumber() {
uint16_t lsb = Master->NoteSel ? Freq >> 9 : (Freq >> 8) & 1;
KeyScaleNumber = Octave << 1 | lsb;
for (int i = 0; i < 4; i++) {
if (!Op[i])
continue;
Op[i]->ComputeRates();
Op[i]->ComputeKeyScaleLevel();
}
}
Opal::Operator::Operator() {
Master = 0;
Chan = 0;
Phase = 0;
Waveform = 0;
FreqMultTimes2 = 1;
EnvelopeStage = EnvOff;
EnvelopeLevel = 0x1FF;
AttackRate = 0;
DecayRate = 0;
SustainLevel = 0;
ReleaseRate = 0;
KeyScaleShift = 0;
KeyScaleLevel = 0;
Out[0] = Out[1] = 0;
KeyOn = false;
KeyScaleRate = false;
SustainMode = false;
TremoloEnable = false;
VibratoEnable = false;
}
int16_t Opal::Operator::Output(uint16_t , uint32_t phase_step, int16_t vibrato, int16_t mod, int16_t fbshift) {
if (VibratoEnable)
phase_step += vibrato;
Phase += (phase_step * FreqMultTimes2) / 2;
uint16_t level = (EnvelopeLevel + OutputLevel + KeyScaleLevel + (TremoloEnable ? Master->TremoloLevel : 0)) << 3;
switch (EnvelopeStage) {
case EnvAtt: {
if (AttackRate == 0)
break;
if (AttackMask && (Master->Clock & AttackMask))
break;
uint16_t add = ((AttackAdd >> AttackTab[Master->Clock >> AttackShift & 7]) * ~EnvelopeLevel) >> 3;
EnvelopeLevel += add;
if (EnvelopeLevel <= 0) {
EnvelopeLevel = 0;
EnvelopeStage = EnvDec;
}
break;
}
case EnvDec: {
if (DecayMask && (Master->Clock & DecayMask))
break;
if (DecayRate != 0) {
uint16_t add = DecayAdd >> DecayTab[Master->Clock >> DecayShift & 7];
EnvelopeLevel += add;
}
if (EnvelopeLevel >= SustainLevel) {
EnvelopeLevel = SustainLevel;
EnvelopeStage = EnvSus;
}
break;
}
case EnvSus: {
if (SustainMode)
break;
MPT_FALLTHROUGH;
}
case EnvRel: {
if (ReleaseRate == 0)
break;
if (ReleaseMask && (Master->Clock & ReleaseMask))
break;
uint16_t add = ReleaseAdd >> ReleaseTab[Master->Clock >> ReleaseShift & 7];
EnvelopeLevel += add;
if (EnvelopeLevel >= 0x1FF) {
EnvelopeLevel = 0x1FF;
EnvelopeStage = EnvOff;
Out[0] = Out[1] = 0;
return 0;
}
break;
}
default:
Out[0] = Out[1] = 0;
return 0;
}
if (fbshift)
mod += (Out[0] + Out[1]) >> fbshift;
uint16_t phase = static_cast<uint16_t>(Phase >> 10) + mod;
uint16_t offset = phase & 0xFF;
uint16_t logsin;
bool negate = false;
switch (Waveform) {
case 0:
if (phase & 0x100)
offset ^= 0xFF;
logsin = Master->LogSinTable[offset];
negate = (phase & 0x200) != 0;
break;
case 1:
if (phase & 0x200)
offset = 0;
else if (phase & 0x100)
offset ^= 0xFF;
logsin = Master->LogSinTable[offset];
break;
case 2:
if (phase & 0x100)
offset ^= 0xFF;
logsin = Master->LogSinTable[offset];
break;
case 3:
if (phase & 0x100)
offset = 0;
logsin = Master->LogSinTable[offset];
break;
case 4:
if (phase & 0x200)
offset = 0;
else {
if (phase & 0x80)
offset ^= 0xFF;
offset = (offset + offset) & 0xFF;
negate = (phase & 0x100) != 0;
}
logsin = Master->LogSinTable[offset];
break;
case 5:
if (phase & 0x200)
offset = 0;
else {
offset = (offset + offset) & 0xFF;
if (phase & 0x80)
offset ^= 0xFF;
}
logsin = Master->LogSinTable[offset];
break;
case 6:
logsin = 0;
negate = (phase & 0x200) != 0;
break;
default:
logsin = phase & 0x1FF;
if (phase & 0x200) {
logsin ^= 0x1FF;
negate = true;
}
logsin <<= 3;
break;
}
uint16_t mix = logsin + level;
if (mix > 0x1FFF)
mix = 0x1FFF;
int16_t v = (Master->ExpTable[mix & 0xFF] + 1024u) >> (mix >> 8u);
v += v;
if (negate)
v = ~v;
Out[1] = Out[0];
Out[0] = v;
return v;
}
void Opal::Operator::SetKeyOn(bool on) {
if (KeyOn == on)
return;
KeyOn = on;
if (on) {
if (AttackRate == 15) {
EnvelopeStage = EnvDec;
EnvelopeLevel = 0;
} else
EnvelopeStage = EnvAtt;
Phase = 0;
} else {
if (EnvelopeStage != EnvOff && EnvelopeStage != EnvRel)
EnvelopeStage = EnvRel;
}
}
void Opal::Operator::SetTremoloEnable(bool on) {
TremoloEnable = on;
}
void Opal::Operator::SetVibratoEnable(bool on) {
VibratoEnable = on;
}
void Opal::Operator::SetSustainMode(bool on) {
SustainMode = on;
}
void Opal::Operator::SetEnvelopeScaling(bool on) {
KeyScaleRate = on;
ComputeRates();
}
void Opal::Operator::SetFrequencyMultiplier(uint16_t scale) {
const uint16_t mul_times_2[] = {
1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30,
};
FreqMultTimes2 = mul_times_2[scale & 15];
}
void Opal::Operator::SetKeyScale(uint16_t scale) {
static const uint8_t kslShift[4] = { 15, 1, 2, 0 };
KeyScaleShift = kslShift[scale];
ComputeKeyScaleLevel();
}
void Opal::Operator::SetOutputLevel(uint16_t level) {
OutputLevel = level * 4;
}
void Opal::Operator::SetAttackRate(uint16_t rate) {
AttackRate = rate;
ComputeRates();
}
void Opal::Operator::SetDecayRate(uint16_t rate) {
DecayRate = rate;
ComputeRates();
}
void Opal::Operator::SetSustainLevel(uint16_t level) {
SustainLevel = level < 15 ? level : 31;
SustainLevel *= 16;
}
void Opal::Operator::SetReleaseRate(uint16_t rate) {
ReleaseRate = rate;
ComputeRates();
}
void Opal::Operator::SetWaveform(uint16_t wave) {
Waveform = wave & 7;
}
void Opal::Operator::ComputeRates() {
int combined_rate = AttackRate * 4 + (Chan->GetKeyScaleNumber() >> (KeyScaleRate ? 0 : 2));
int rate_high = combined_rate >> 2;
int rate_low = combined_rate & 3;
AttackShift = static_cast<uint16_t>(rate_high < 12 ? 12 - rate_high : 0);
AttackMask = (1 << AttackShift) - 1;
AttackAdd = (rate_high < 12) ? 1 : 1 << (rate_high - 12);
AttackTab = Master->RateTables[rate_low];
if (AttackRate == 15)
AttackAdd = 0xFFF;
combined_rate = DecayRate * 4 + (Chan->GetKeyScaleNumber() >> (KeyScaleRate ? 0 : 2));
rate_high = combined_rate >> 2;
rate_low = combined_rate & 3;
DecayShift = static_cast<uint16_t>(rate_high < 12 ? 12 - rate_high : 0);
DecayMask = (1 << DecayShift) - 1;
DecayAdd = (rate_high < 12) ? 1 : 1 << (rate_high - 12);
DecayTab = Master->RateTables[rate_low];
combined_rate = ReleaseRate * 4 + (Chan->GetKeyScaleNumber() >> (KeyScaleRate ? 0 : 2));
rate_high = combined_rate >> 2;
rate_low = combined_rate & 3;
ReleaseShift = static_cast<uint16_t>(rate_high < 12 ? 12 - rate_high : 0);
ReleaseMask = (1 << ReleaseShift) - 1;
ReleaseAdd = (rate_high < 12) ? 1 : 1 << (rate_high - 12);
ReleaseTab = Master->RateTables[rate_low];
}
void Opal::Operator::ComputeKeyScaleLevel() {
static const uint8_t levtab[] = {
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, 8, 12, 16, 20, 24, 28, 32,
0, 0, 0, 0, 0, 12, 20, 28, 32, 40, 44, 48, 52, 56, 60, 64,
0, 0, 0, 20, 32, 44, 52, 60, 64, 72, 76, 80, 84, 88, 92, 96,
0, 0, 32, 52, 64, 76, 84, 92, 96, 104, 108, 112, 116, 120, 124, 128,
0, 32, 64, 84, 96, 108, 116, 124, 128, 136, 140, 144, 148, 152, 156, 160,
0, 64, 96, 116, 128, 140, 148, 156, 160, 168, 172, 176, 180, 184, 188, 192,
0, 96, 128, 148, 160, 172, 180, 188, 192, 200, 204, 208, 212, 216, 220, 224,
};
uint16_t i = (Chan->GetOctave() << 4) | (Chan->GetFreq() >> 6);
KeyScaleLevel = levtab[i] >> KeyScaleShift;
}