#include "headers.h"
#include "misc.h"
#include "fmgen.h"
#include "fmgeninl.h"
#define LOGNAME "fmgen"
#define FM_EG_BOTTOM 955
namespace FM
{
const uint8 Operator::notetable[128] =
{
0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11,
12, 12, 12, 12, 12, 12, 12, 13, 14, 15, 15, 15, 15, 15, 15, 15,
16, 16, 16, 16, 16, 16, 16, 17, 18, 19, 19, 19, 19, 19, 19, 19,
20, 20, 20, 20, 20, 20, 20, 21, 22, 23, 23, 23, 23, 23, 23, 23,
24, 24, 24, 24, 24, 24, 24, 25, 26, 27, 27, 27, 27, 27, 27, 27,
28, 28, 28, 28, 28, 28, 28, 29, 30, 31, 31, 31, 31, 31, 31, 31,
};
const int8 Operator::dttable[256] =
{
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, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4,
4, 6, 6, 6, 8, 8, 8, 10, 10, 12, 12, 14, 16, 16, 16, 16,
2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 8, 8, 8, 10,
10, 12, 12, 14, 16, 16, 18, 20, 22, 24, 26, 28, 32, 32, 32, 32,
4, 4, 4, 4, 4, 6, 6, 6, 8, 8, 8, 10, 10, 12, 12, 14,
16, 16, 18, 20, 22, 24, 26, 28, 32, 34, 38, 40, 44, 44, 44, 44,
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, 0, 0, 0, -2, -2, -2, -2, -2, -2, -2, -2, -4, -4, -4, -4,
-4, -6, -6, -6, -8, -8, -8,-10,-10,-12,-12,-14,-16,-16,-16,-16,
-2, -2, -2, -2, -4, -4, -4, -4, -4, -6, -6, -6, -8, -8, -8,-10,
-10,-12,-12,-14,-16,-16,-18,-20,-22,-24,-26,-28,-32,-32,-32,-32,
-4, -4, -4, -4, -4, -6, -6, -6, -8, -8, -8,-10,-10,-12,-12,-14,
-16,-16,-18,-20,-22,-24,-26,-28,-32,-34,-38,-40,-44,-44,-44,-44,
};
const int8 Operator::decaytable1[64][8] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0,
1, 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, 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, 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, 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, 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, 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, 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, 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, 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, 1, 1, 0, 1, 0, 1, 0,
1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1,
2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1,
2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 4, 2, 2, 2,
4, 2, 4, 2, 4, 2, 4, 2, 4, 4, 4, 2, 4, 4, 4, 2,
4, 4, 4, 4, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 4, 4,
8, 4, 8, 4, 8, 4, 8, 4, 8, 8, 8, 4, 8, 8, 8, 4,
16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,
};
const int Operator::decaytable2[16] =
{
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2047, 2047, 2047, 2047, 2047
};
const int8 Operator::attacktable[64][8] =
{
-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4,-1,
4,-1, 4,-1, 4,-1, 4,-1, 4, 4, 4,-1, 4,-1, 4,-1,
4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4, 4, 4, 4, 4,-1,
4,-1, 4,-1, 4,-1, 4,-1, 4, 4, 4,-1, 4,-1, 4,-1,
4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4, 4, 4, 4, 4,-1,
4,-1, 4,-1, 4,-1, 4,-1, 4, 4, 4,-1, 4,-1, 4,-1,
4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4, 4, 4, 4, 4,-1,
4,-1, 4,-1, 4,-1, 4,-1, 4, 4, 4,-1, 4,-1, 4,-1,
4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4, 4, 4, 4, 4,-1,
4,-1, 4,-1, 4,-1, 4,-1, 4, 4, 4,-1, 4,-1, 4,-1,
4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4, 4, 4, 4, 4,-1,
4,-1, 4,-1, 4,-1, 4,-1, 4, 4, 4,-1, 4,-1, 4,-1,
4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4, 4, 4, 4, 4,-1,
4,-1, 4,-1, 4,-1, 4,-1, 4, 4, 4,-1, 4,-1, 4,-1,
4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4, 4, 4, 4, 4,-1,
4,-1, 4,-1, 4,-1, 4,-1, 4, 4, 4,-1, 4,-1, 4,-1,
4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4, 4, 4, 4, 4,-1,
4,-1, 4,-1, 4,-1, 4,-1, 4, 4, 4,-1, 4,-1, 4,-1,
4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4, 4, 4, 4, 4,-1,
4,-1, 4,-1, 4,-1, 4,-1, 4, 4, 4,-1, 4,-1, 4,-1,
4, 4, 4,-1, 4, 4, 4,-1, 4, 4, 4, 4, 4, 4, 4,-1,
4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4,
3, 4, 3, 4, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 4,
3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3,
2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2,
1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2,
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,
};
const int Operator::ssgenvtable[8][2][3][2] =
{
1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 2, 0, 2, 0, 0, 1, 2, 0, 2, 0, 1,-1, 0, 1, 1,-1, 0, 1, 1,-1, 0, 1, 1,-1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2,-1, 2,-1, 2,-1, 1,-1, 2,-1, 2,-1, 1,-1, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 0, 1, 1,-1, 0, 1, 1,-1, 0, 1, 1,-1, 0, 1, 2, 0, 2, 0, 1,-1, 2, 0, 2, 0, };
int pmtable[2][8][FM_LFOENTS];
uint amtable[2][4][FM_LFOENTS];
static bool tablemade = false;
}
namespace FM
{
void MakeLFOTable()
{
if (tablemade)
return;
tablemade = true;
int i;
static const double pms[2][8] =
{
{ 0, 1/360., 2/360., 3/360., 4/360., 6/360., 12/360., 24/360., }, { 0, 1/480., 2/480., 4/480., 10/480., 20/480., 80/480., 140/480., }, };
static const uint8 amt[2][4] =
{
{ 31, 6, 4, 3 }, { 31, 2, 1, 0 }, };
for (int type = 0; type < 2; type++)
{
for (i=0; i<8; i++)
{
double pmb = pms[type][i];
for (int j=0; j<FM_LFOENTS; j++)
{
double v = pow(2.0, pmb * (2 * j - FM_LFOENTS+1) / (FM_LFOENTS-1));
double w = 0.6 * pmb * sin(2 * j * 3.14159265358979323846 / FM_LFOENTS) + 1;
pmtable[type][i][j] = int(0x10000 * (w - 1));
}
}
for (i=0; i<4; i++)
{
for (int j=0; j<FM_LFOENTS; j++)
{
amtable[type][i][j] = (((j * 4) >> amt[type][i]) * 2) << 2;
}
}
}
}
Chip::Chip()
: ratio_(0), aml_(0), pml_(0), pmv_(0), optype_(typeN)
{
}
void Chip::SetRatio(uint ratio)
{
if (ratio_ != ratio)
{
ratio_ = ratio;
MakeTable();
}
}
void Chip::MakeTable()
{
int h, l;
static const float dt2lv[4] = { 1.f, 1.414f, 1.581f, 1.732f };
for (h=0; h<4; h++)
{
assert(2 + FM_RATIOBITS - FM_PGBITS >= 0);
double rr = dt2lv[h] * double(ratio_) / (1 << (2 + FM_RATIOBITS - FM_PGBITS));
for (l=0; l<16; l++)
{
int mul = l ? l * 2 : 1;
multable_[h][l] = uint(mul * rr);
}
}
}
bool FM::Operator::tablehasmade = false;
uint FM::Operator::sinetable[1024];
int32 FM::Operator::cltable[FM_CLENTS];
FM::Operator::Operator()
: chip_(0)
{
if (!tablehasmade)
MakeTable();
ar_ = dr_ = sr_ = rr_ = key_scale_rate_ = 0;
ams_ = amtable[0][0];
mute_ = false;
keyon_ = false;
tl_out_ = false;
ssg_type_ = 0;
multiple_ = 0;
detune_ = 0;
detune2_ = 0;
ms_ = 0;
}
void FM::Operator::Reset()
{
tl_ = tl_latch_ = 127;
ShiftPhase(off);
eg_count_ = 0;
eg_curve_count_ = 0;
ssg_phase_ = 0;
pg_count_ = 0;
out_ = out2_ = 0;
param_changed_ = true;
PARAMCHANGE(0);
}
void Operator::MakeTable()
{
assert(FM_CLENTS >= 256);
int* p = cltable;
int i;
for (i=0; i<256; i++)
{
int v = int(floor(pow(2., 13. - i / 256.)));
v = (v + 2) & ~3;
*p++ = v;
*p++ = -v;
}
while (p < cltable + FM_CLENTS)
{
*p++ = p[-512] / 2;
}
double log2 = log(2.);
for (i=0; i<FM_OPSINENTS/2; i++)
{
double r = (i * 2 + 1) * FM_PI / FM_OPSINENTS;
double q = -256 * log(sin(r)) / log2;
uint s = (int) (floor(q + 0.5)) + 1;
sinetable[i] = s * 2 ;
sinetable[FM_OPSINENTS / 2 + i] = s * 2 + 1;
}
::FM::MakeLFOTable();
tablehasmade = true;
}
inline void FM::Operator::SetDPBN(uint dp, uint bn)
{
dp_ = dp, bn_ = bn; param_changed_ = true;
PARAMCHANGE(1);
}
void Operator::Prepare()
{
if (param_changed_)
{
param_changed_ = false;
pg_diff_ = (dp_ + dttable[detune_ + bn_]) * chip_->GetMulValue(detune2_, multiple_);
pg_diff_lfo_ = pg_diff_ >> 11;
key_scale_rate_ = bn_ >> (3-ks_);
tl_out_ = mute_ ? 0x3ff : tl_ * 8;
switch (eg_phase_)
{
case attack:
SetEGRate(ar_ ? Min(63, ar_ + key_scale_rate_) : 0);
break;
case decay:
SetEGRate(dr_ ? Min(63, dr_ + key_scale_rate_) : 0);
eg_level_on_next_phase_ = sl_ * 8;
break;
case sustain:
SetEGRate(sr_ ? Min(63, sr_ + key_scale_rate_) : 0);
break;
case release:
SetEGRate(Min(63, rr_ + key_scale_rate_));
break;
}
if (ssg_type_ && (eg_phase_ != release))
{
int m = ar_ >= ((ssg_type_ == 8 || ssg_type_ == 12) ? 56 : 60);
assert(0 <= ssg_phase_ && ssg_phase_ <= 2);
const int* table = ssgenvtable[ssg_type_ & 7][m][ssg_phase_];
ssg_offset_ = table[0] * 0x200;
ssg_vector_ = table[1];
}
ams_ = amtable[type_][amon_ ? (ms_ >> 4) & 3 : 0];
EGUpdate();
dbgopout_ = 0;
}
}
void Operator::ShiftPhase(EGPhase nextphase)
{
switch (nextphase)
{
case attack: tl_ = tl_latch_;
if (ssg_type_)
{
ssg_phase_ = ssg_phase_ + 1;
if (ssg_phase_ > 2)
ssg_phase_ = 1;
int m = ar_ >= ((ssg_type_ == 8 || ssg_type_ == 12) ? 56 : 60);
assert(0 <= ssg_phase_ && ssg_phase_ <= 2);
const int* table = ssgenvtable[ssg_type_ & 7][m][ssg_phase_];
ssg_offset_ = table[0] * 0x200;
ssg_vector_ = table[1];
}
if ((ar_ + key_scale_rate_) < 62)
{
SetEGRate(ar_ ? Min(63, ar_ + key_scale_rate_) : 0);
eg_phase_ = attack;
break;
}
case decay: if (sl_)
{
eg_level_ = 0;
eg_level_on_next_phase_ = ssg_type_ ? Min(sl_ * 8, 0x200) : sl_ * 8;
SetEGRate(dr_ ? Min(63, dr_ + key_scale_rate_) : 0);
eg_phase_ = decay;
break;
}
case sustain: eg_level_ = sl_ * 8;
eg_level_on_next_phase_ = ssg_type_ ? 0x200 : 0x400;
SetEGRate(sr_ ? Min(63, sr_ + key_scale_rate_) : 0);
eg_phase_ = sustain;
break;
case release: if (ssg_type_)
{
eg_level_ = eg_level_ * ssg_vector_ + ssg_offset_;
ssg_vector_ = 1;
ssg_offset_ = 0;
}
if (eg_phase_ == attack || (eg_level_ < FM_EG_BOTTOM)) {
eg_level_on_next_phase_ = 0x400;
SetEGRate(Min(63, rr_ + key_scale_rate_));
eg_phase_ = release;
break;
}
case off: default:
eg_level_ = FM_EG_BOTTOM;
eg_level_on_next_phase_ = FM_EG_BOTTOM;
EGUpdate();
SetEGRate(0);
eg_phase_ = off;
break;
}
}
void Operator::SetFNum(uint f)
{
dp_ = (f & 2047) << ((f >> 11) & 7);
bn_ = notetable[(f >> 7) & 127];
param_changed_ = true;
PARAMCHANGE(2);
}
#define IS2EC_SHIFT ((20 + FM_PGBITS) - 13)
#define Sine(s) sinetable[((s) >> (20+FM_PGBITS-FM_OPSINBITS))&(FM_OPSINENTS-1)]
#define SINE(s) sinetable[(s) & (FM_OPSINENTS-1)]
inline FM::ISample Operator::LogToLin(uint a)
{
#if 1 return (a < FM_CLENTS) ? cltable[a] : 0;
#else#endif
}
inline void Operator::EGUpdate()
{
if (!ssg_type_)
{
eg_out_ = Min(tl_out_ + eg_level_, 0x3ff) << (1 + 2);
}
else
{
eg_out_ = Min(tl_out_ + eg_level_ * ssg_vector_ + ssg_offset_, 0x3ff) << (1 + 2);
}
}
inline void Operator::SetEGRate(uint rate)
{
eg_rate_ = rate;
eg_count_diff_ = decaytable2[rate / 4] * chip_->GetRatio();
}
void FM::Operator::EGCalc()
{
eg_count_ = (2047 * 3) << FM_RATIOBITS;
if (eg_phase_ == attack)
{
int c = attacktable[eg_rate_][eg_curve_count_ & 7];
if (c >= 0)
{
eg_level_ -= 1 + (eg_level_ >> c);
if (eg_level_ <= 0)
ShiftPhase(decay);
}
EGUpdate();
}
else
{
if (!ssg_type_)
{
eg_level_ += decaytable1[eg_rate_][eg_curve_count_ & 7];
if (eg_level_ >= eg_level_on_next_phase_)
ShiftPhase(EGPhase(eg_phase_+1));
EGUpdate();
}
else
{
eg_level_ += 4 * decaytable1[eg_rate_][eg_curve_count_ & 7];
if (eg_level_ >= eg_level_on_next_phase_)
{
EGUpdate();
switch (eg_phase_)
{
case decay:
ShiftPhase(sustain);
break;
case sustain:
ShiftPhase(attack);
break;
case release:
ShiftPhase(off);
break;
}
}
}
}
eg_curve_count_++;
}
inline void FM::Operator::EGStep()
{
eg_count_ -= eg_count_diff_;
if (eg_count_ <= 0)
EGCalc();
}
inline uint32 FM::Operator::PGCalc()
{
uint32 ret = pg_count_;
pg_count_ += pg_diff_;
dbgpgout_ = ret;
return ret;
}
inline uint32 FM::Operator::PGCalcL()
{
uint32 ret = pg_count_;
pg_count_ += pg_diff_ + ((pg_diff_lfo_ * chip_->GetPMV()) >> 5); dbgpgout_ = ret;
return ret ;
}
inline FM::ISample FM::Operator::Calc(ISample in)
{
EGStep();
out2_ = out_;
int pgin = PGCalc() >> (20+FM_PGBITS-FM_OPSINBITS);
pgin += in >> (20+FM_PGBITS-FM_OPSINBITS-(2+IS2EC_SHIFT));
out_ = LogToLin(eg_out_ + SINE(pgin));
dbgopout_ = out_;
return out_;
}
inline FM::ISample FM::Operator::CalcL(ISample in)
{
EGStep();
int pgin = PGCalcL() >> (20+FM_PGBITS-FM_OPSINBITS);
pgin += in >> (20+FM_PGBITS-FM_OPSINBITS-(2+IS2EC_SHIFT));
out_ = LogToLin(eg_out_ + SINE(pgin) + ams_[chip_->GetAML()]);
dbgopout_ = out_;
return out_;
}
inline FM::ISample FM::Operator::CalcN(uint noise)
{
EGStep();
int lv = Max(0, 0x3ff - (tl_out_ + eg_level_)) << 1;
noise = (noise & 1) - 1;
out_ = (lv + noise) ^ noise;
dbgopout_ = out_;
return out_;
}
inline FM::ISample FM::Operator::CalcFB(uint fb)
{
EGStep();
ISample in = out_ + out2_;
out2_ = out_;
int pgin = PGCalc() >> (20+FM_PGBITS-FM_OPSINBITS);
if (fb < 31)
{
pgin += ((in << (1 + IS2EC_SHIFT)) >> fb) >> (20+FM_PGBITS-FM_OPSINBITS);
}
out_ = LogToLin(eg_out_ + SINE(pgin));
dbgopout_ = out2_;
return out2_;
}
inline FM::ISample FM::Operator::CalcFBL(uint fb)
{
EGStep();
ISample in = out_ + out2_;
out2_ = out_;
int pgin = PGCalcL() >> (20+FM_PGBITS-FM_OPSINBITS);
if (fb < 31)
{
pgin += ((in << (1 + IS2EC_SHIFT)) >> fb) >> (20+FM_PGBITS-FM_OPSINBITS);
}
out_ = LogToLin(eg_out_ + SINE(pgin) + ams_[chip_->GetAML()]);
dbgopout_ = out_;
return out_;
}
#undef Sine
const uint8 Channel4::fbtable[8] = { 31, 7, 6, 5, 4, 3, 2, 1 };
int Channel4::kftable[64];
bool Channel4::tablehasmade = false;
Channel4::Channel4()
{
if (!tablehasmade)
MakeTable();
SetAlgorithm(0);
pms = pmtable[0][0];
}
void Channel4::MakeTable()
{
for (int i=0; i<64; i++)
{
kftable[i] = int(0x10000 * pow(2., i / 768.) );
}
}
void Channel4::Reset()
{
op[0].Reset();
op[1].Reset();
op[2].Reset();
op[3].Reset();
}
int Channel4::Prepare()
{
op[0].Prepare();
op[1].Prepare();
op[2].Prepare();
op[3].Prepare();
pms = pmtable[op[0].type_][op[0].ms_ & 7];
int key = (op[0].IsOn() | op[1].IsOn() | op[2].IsOn() | op[3].IsOn()) ? 1 : 0;
int lfo = op[0].ms_ & (op[0].amon_ | op[1].amon_ | op[2].amon_ | op[3].amon_ ? 0x37 : 7) ? 2 : 0;
return key | lfo;
}
void Channel4::SetFNum(uint f)
{
for (int i=0; i<4; i++)
op[i].SetFNum(f);
}
void Channel4::SetKCKF(uint kc, uint kf)
{
const static uint kctable[16] =
{
5197, 5506, 5833, 6180, 6180, 6547, 6937, 7349,
7349, 7786, 8249, 8740, 8740, 9259, 9810, 10394,
};
int oct = 19 - ((kc >> 4) & 7);
uint kcv = kctable[kc & 0x0f];
kcv = (kcv + 2) / 4 * 4;
uint dp = kcv * kftable[kf & 0x3f];
dp >>= 16 + 3;
dp <<= 16 + 3;
dp >>= oct;
uint bn = (kc >> 2) & 31;
op[0].SetDPBN(dp, bn);
op[1].SetDPBN(dp, bn);
op[2].SetDPBN(dp, bn);
op[3].SetDPBN(dp, bn);
}
void Channel4::KeyControl(uint key)
{
if (key & 0x1) op[0].KeyOn(); else op[0].KeyOff();
if (key & 0x2) op[1].KeyOn(); else op[1].KeyOff();
if (key & 0x4) op[2].KeyOn(); else op[2].KeyOff();
if (key & 0x8) op[3].KeyOn(); else op[3].KeyOff();
}
void Channel4::SetAlgorithm(uint algo)
{
static const uint8 table1[8][6] =
{
{ 0, 1, 1, 2, 2, 3 }, { 1, 0, 0, 1, 1, 2 },
{ 1, 1, 1, 0, 0, 2 }, { 0, 1, 2, 1, 1, 2 },
{ 0, 1, 2, 2, 2, 1 }, { 0, 1, 0, 1, 0, 1 },
{ 0, 1, 2, 1, 2, 1 }, { 1, 0, 1, 0, 1, 0 },
};
in [0] = &buf[table1[algo][0]];
out[0] = &buf[table1[algo][1]];
in [1] = &buf[table1[algo][2]];
out[1] = &buf[table1[algo][3]];
in [2] = &buf[table1[algo][4]];
out[2] = &buf[table1[algo][5]];
op[0].ResetFB();
algo_ = algo;
}
ISample Channel4::Calc()
{
int r;
switch (algo_)
{
case 0:
op[2].Calc(op[1].Out());
op[1].Calc(op[0].Out());
r = op[3].Calc(op[2].Out());
op[0].CalcFB(fb);
break;
case 1:
op[2].Calc(op[0].Out() + op[1].Out());
op[1].Calc(0);
r = op[3].Calc(op[2].Out());
op[0].CalcFB(fb);
break;
case 2:
op[2].Calc(op[1].Out());
op[1].Calc(0);
r = op[3].Calc(op[0].Out() + op[2].Out());
op[0].CalcFB(fb);
break;
case 3:
op[2].Calc(0);
op[1].Calc(op[0].Out());
r = op[3].Calc(op[1].Out() + op[2].Out());
op[0].CalcFB(fb);
break;
case 4:
op[2].Calc(0);
r = op[1].Calc(op[0].Out());
r += op[3].Calc(op[2].Out());
op[0].CalcFB(fb);
break;
case 5:
r = op[2].Calc(op[0].Out());
r += op[1].Calc(op[0].Out());
r += op[3].Calc(op[0].Out());
op[0].CalcFB(fb);
break;
case 6:
r = op[2].Calc(0);
r += op[1].Calc(op[0].Out());
r += op[3].Calc(0);
op[0].CalcFB(fb);
break;
case 7:
r = op[2].Calc(0);
r += op[1].Calc(0);
r += op[3].Calc(0);
r += op[0].CalcFB(fb);
break;
}
return r;
}
ISample Channel4::CalcL()
{
chip_->SetPMV(pms[chip_->GetPML()]);
int r;
switch (algo_)
{
case 0:
op[2].CalcL(op[1].Out());
op[1].CalcL(op[0].Out());
r = op[3].CalcL(op[2].Out());
op[0].CalcFBL(fb);
break;
case 1:
op[2].CalcL(op[0].Out() + op[1].Out());
op[1].CalcL(0);
r = op[3].CalcL(op[2].Out());
op[0].CalcFBL(fb);
break;
case 2:
op[2].CalcL(op[1].Out());
op[1].CalcL(0);
r = op[3].CalcL(op[0].Out() + op[2].Out());
op[0].CalcFBL(fb);
break;
case 3:
op[2].CalcL(0);
op[1].CalcL(op[0].Out());
r = op[3].CalcL(op[1].Out() + op[2].Out());
op[0].CalcFBL(fb);
break;
case 4:
op[2].CalcL(0);
r = op[1].CalcL(op[0].Out());
r += op[3].CalcL(op[2].Out());
op[0].CalcFBL(fb);
break;
case 5:
r = op[2].CalcL(op[0].Out());
r += op[1].CalcL(op[0].Out());
r += op[3].CalcL(op[0].Out());
op[0].CalcFBL(fb);
break;
case 6:
r = op[2].CalcL(0);
r += op[1].CalcL(op[0].Out());
r += op[3].CalcL(0);
op[0].CalcFBL(fb);
break;
case 7:
r = op[2].CalcL(0);
r += op[1].CalcL(0);
r += op[3].CalcL(0);
r += op[0].CalcFBL(fb);
break;
}
return r;
}
ISample Channel4::CalcN(uint noise)
{
buf[1] = buf[2] = buf[3] = 0;
buf[0] = op[0].out_; op[0].CalcFB(fb);
*out[0] += op[1].Calc(*in[0]);
*out[1] += op[2].Calc(*in[1]);
int o = op[3].out_;
op[3].CalcN(noise);
return *out[2] + o;
}
ISample Channel4::CalcLN(uint noise)
{
chip_->SetPMV(pms[chip_->GetPML()]);
buf[1] = buf[2] = buf[3] = 0;
buf[0] = op[0].out_; op[0].CalcFBL(fb);
*out[0] += op[1].CalcL(*in[0]);
*out[1] += op[2].CalcL(*in[1]);
int o = op[3].out_;
op[3].CalcN(noise);
return *out[2] + o;
}
}