34namespace YM2413Burczynski {
37static constexpr int ENV_BITS = 10;
38static constexpr double ENV_STEP = 128.0 / (1 << ENV_BITS);
40static constexpr int MAX_ATT_INDEX = (1 << (ENV_BITS - 2)) - 1;
41static constexpr int MIN_ATT_INDEX = 0;
43static constexpr int TL_RES_LEN = 256;
49static constexpr int DV(
double x) {
return narrow_cast<int>(x / 0.1875); }
50static constexpr std::array<int, 8 * 16> ksl_tab =
53 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
54 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
55 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
56 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
58 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
59 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
60 DV( 0.000),DV( 0.750),DV( 1.125),DV( 1.500),
61 DV( 1.875),DV( 2.250),DV( 2.625),DV( 3.000),
63 DV( 0.000),DV( 0.000),DV( 0.000),DV( 0.000),
64 DV( 0.000),DV( 1.125),DV( 1.875),DV( 2.625),
65 DV( 3.000),DV( 3.750),DV( 4.125),DV( 4.500),
66 DV( 4.875),DV( 5.250),DV( 5.625),DV( 6.000),
68 DV( 0.000),DV( 0.000),DV( 0.000),DV( 1.875),
69 DV( 3.000),DV( 4.125),DV( 4.875),DV( 5.625),
70 DV( 6.000),DV( 6.750),DV( 7.125),DV( 7.500),
71 DV( 7.875),DV( 8.250),DV( 8.625),DV( 9.000),
73 DV( 0.000),DV( 0.000),DV( 3.000),DV( 4.875),
74 DV( 6.000),DV( 7.125),DV( 7.875),DV( 8.625),
75 DV( 9.000),DV( 9.750),DV(10.125),DV(10.500),
76 DV(10.875),DV(11.250),DV(11.625),DV(12.000),
78 DV( 0.000),DV( 3.000),DV( 6.000),DV( 7.875),
79 DV( 9.000),DV(10.125),DV(10.875),DV(11.625),
80 DV(12.000),DV(12.750),DV(13.125),DV(13.500),
81 DV(13.875),DV(14.250),DV(14.625),DV(15.000),
83 DV( 0.000),DV( 6.000),DV( 9.000),DV(10.875),
84 DV(12.000),DV(13.125),DV(13.875),DV(14.625),
85 DV(15.000),DV(15.750),DV(16.125),DV(16.500),
86 DV(16.875),DV(17.250),DV(17.625),DV(18.000),
88 DV( 0.000),DV( 9.000),DV(12.000),DV(13.875),
89 DV(15.000),DV(16.125),DV(16.875),DV(17.625),
90 DV(18.000),DV(18.750),DV(19.125),DV(19.500),
91 DV(19.875),DV(20.250),DV(20.625),DV(21.000)
96static constexpr int SC(
int db) {
return int(
double(db) / ENV_STEP); }
97static constexpr std::array<int, 16> sl_tab = {
98 SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
99 SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(15)
102static constexpr std::array eg_inc =
105 std::array<uint8_t, 8>{ 0,1, 0,1, 0,1, 0,1, },
106 std::array<uint8_t, 8>{ 0,1, 0,1, 1,1, 0,1, },
107 std::array<uint8_t, 8>{ 0,1, 1,1, 0,1, 1,1, },
108 std::array<uint8_t, 8>{ 0,1, 1,1, 1,1, 1,1, },
110 std::array<uint8_t, 8>{ 1,1, 1,1, 1,1, 1,1, },
111 std::array<uint8_t, 8>{ 1,1, 1,2, 1,1, 1,2, },
112 std::array<uint8_t, 8>{ 1,2, 1,2, 1,2, 1,2, },
113 std::array<uint8_t, 8>{ 1,2, 2,2, 1,2, 2,2, },
115 std::array<uint8_t, 8>{ 2,2, 2,2, 2,2, 2,2, },
116 std::array<uint8_t, 8>{ 2,2, 2,4, 2,2, 2,4, },
117 std::array<uint8_t, 8>{ 2,4, 2,4, 2,4, 2,4, },
118 std::array<uint8_t, 8>{ 2,4, 4,4, 2,4, 4,4, },
120 std::array<uint8_t, 8>{ 4,4, 4,4, 4,4, 4,4, },
121 std::array<uint8_t, 8>{ 8,8, 8,8, 8,8, 8,8, },
122 std::array<uint8_t, 8>{ 0,0, 0,0, 0,0, 0,0, },
126static constexpr std::array<uint8_t, 16 + 64 + 16> eg_rate_select =
130 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
157 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
164static constexpr std::array<uint8_t, 16 + 64 + 16> eg_rate_shift =
168 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
195 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
199static constexpr uint8_t ML(
double x) {
return uint8_t(2 * x); }
200static constexpr std::array<uint8_t, 16> mul_tab =
202 ML( 0.50), ML( 1.00), ML( 2.00), ML( 3.00),
203 ML( 4.00), ML( 5.00), ML( 6.00), ML( 7.00),
204 ML( 8.00), ML( 9.00), ML(10.00), ML(10.00),
205 ML(12.00), ML(12.00), ML(15.00), ML(15.00),
212static constexpr int TL_TAB_LEN = 11 * 2 * TL_RES_LEN;
213static constexpr auto tlTab = [] {
214 std::array<int, TL_TAB_LEN> result = {};
215 for (
auto x :
xrange(TL_RES_LEN)) {
216 double m = (1 << 16) / cstd::exp2<6>((x + 1) * (ENV_STEP / 4.0) / 8.0);
222 n = (n >> 1) + (n & 1);
224 for (
auto i :
xrange(11)) {
225 result[x * 2 + 0 + i * 2 * TL_RES_LEN] = n >> i;
226 result[x * 2 + 1 + i * 2 * TL_RES_LEN] = -(n >> i);
234static constexpr auto sinTab = [] {
235 std::array<std::array<unsigned, SIN_LEN>, 2> result = {};
236 for (
auto i :
xrange(SIN_LEN / 4)) {
239 double m = cstd::sin<2>(narrow_cast<double>((i * 2) + 1) *
Math::pi / SIN_LEN);
240 int n = int(
cstd::round(cstd::log2<8, 3>(m) * -256.0));
241 result[0][i] = 2 * n;
243 for (
auto i :
xrange(SIN_LEN / 4)) {
244 result[0][SIN_LEN / 4 + i] = result[0][SIN_LEN / 4 - 1 - i];
246 for (
auto i :
xrange(SIN_LEN / 2)) {
247 result[0][SIN_LEN / 2 + i] = result[0][i] | 1;
249 for (
auto i :
xrange(SIN_LEN / 2)) {
250 result[1][i] = result[0][i];
252 for (
auto i :
xrange(SIN_LEN / 2)) {
253 result[1][i + SIN_LEN / 2] = TL_TAB_LEN;
270static constexpr int LFO_AM_TAB_ELEMENTS = 210;
271static constexpr std::array<uint8_t, LFO_AM_TAB_ELEMENTS> lfo_am_table =
328static constexpr std::array lfo_pm_table =
331 std::array<int8_t, 8>{ 0, 0, 0, 0, 0, 0, 0, 0, },
334 std::array<int8_t, 8>{ 1, 0, 0, 0,-1, 0, 0, 0, },
337 std::array<int8_t, 8>{ 2, 1, 0,-1,-2,-1, 0, 1, },
340 std::array<int8_t, 8>{ 3, 1, 0,-1,-3,-1, 0, 1, },
343 std::array<int8_t, 8>{ 4, 2, 0,-2,-4,-2, 0, 2, },
346 std::array<int8_t, 8>{ 5, 2, 0,-2,-5,-2, 0, 2, },
349 std::array<int8_t, 8>{ 6, 3, 0,-3,-6,-3, 0, 3, },
352 std::array<int8_t, 8>{ 7, 3, 0,-3,-7,-3, 0, 3, },
360static constexpr std::array table = {
363 std::array<uint8_t, 8>{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
364 std::array<uint8_t, 8>{ 0x61, 0x61, 0x1e, 0x17, 0xf0, 0x7f, 0x00, 0x17 },
365 std::array<uint8_t, 8>{ 0x13, 0x41, 0x16, 0x0e, 0xfd, 0xf4, 0x23, 0x23 },
366 std::array<uint8_t, 8>{ 0x03, 0x01, 0x9a, 0x04, 0xf3, 0xf3, 0x13, 0xf3 },
367 std::array<uint8_t, 8>{ 0x11, 0x61, 0x0e, 0x07, 0xfa, 0x64, 0x70, 0x17 },
368 std::array<uint8_t, 8>{ 0x22, 0x21, 0x1e, 0x06, 0xf0, 0x76, 0x00, 0x28 },
369 std::array<uint8_t, 8>{ 0x21, 0x22, 0x16, 0x05, 0xf0, 0x71, 0x00, 0x18 },
370 std::array<uint8_t, 8>{ 0x21, 0x61, 0x1d, 0x07, 0x82, 0x80, 0x17, 0x17 },
371 std::array<uint8_t, 8>{ 0x23, 0x21, 0x2d, 0x16, 0x90, 0x90, 0x00, 0x07 },
372 std::array<uint8_t, 8>{ 0x21, 0x21, 0x1b, 0x06, 0x64, 0x65, 0x10, 0x17 },
373 std::array<uint8_t, 8>{ 0x21, 0x21, 0x0b, 0x1a, 0x85, 0xa0, 0x70, 0x07 },
374 std::array<uint8_t, 8>{ 0x23, 0x01, 0x83, 0x10, 0xff, 0xb4, 0x10, 0xf4 },
375 std::array<uint8_t, 8>{ 0x97, 0xc1, 0x20, 0x07, 0xff, 0xf4, 0x22, 0x22 },
376 std::array<uint8_t, 8>{ 0x61, 0x00, 0x0c, 0x05, 0xc2, 0xf6, 0x40, 0x44 },
377 std::array<uint8_t, 8>{ 0x01, 0x01, 0x56, 0x03, 0x94, 0xc2, 0x03, 0x12 },
378 std::array<uint8_t, 8>{ 0x21, 0x01, 0x89, 0x03, 0xf1, 0xe4, 0xf0, 0x23 },
385 std::array<uint8_t, 8>{ 0x01, 0x01, 0x16, 0x00, 0xfd, 0xf8, 0x2f, 0x6d },
386 std::array<uint8_t, 8>{ 0x01, 0x01, 0x00, 0x00, 0xd8, 0xd8, 0xf9, 0xf8 },
387 std::array<uint8_t, 8>{ 0x05, 0x01, 0x00, 0x00, 0xf8, 0xba, 0x49, 0x55 },
390static constexpr FreqIndex fnumToIncrement(
int block_fnum)
394 const int block = (block_fnum & 0x1C00) >> 10;
395 return FreqIndex(block_fnum & 0x03FF) >> (11 - block);
406 if (!(eg_cnt & eg_mask_dp)) {
407 egOut += eg_sel_dp[(eg_cnt >> eg_sh_dp) & 7];
408 if (egOut >= MAX_ATT_INDEX) {
409 egOut = MAX_ATT_INDEX;
417 if (!(eg_cnt & eg_mask_ar)) {
419 (~egOut * eg_sel_ar[(eg_cnt >> eg_sh_ar) & 7]) >> 2;
420 if (egOut <= MIN_ATT_INDEX) {
421 egOut = MIN_ATT_INDEX;
428 if (!(eg_cnt & eg_mask_dr)) {
429 egOut += eg_sel_dr[(eg_cnt >> eg_sh_dr) & 7];
448 if (!(eg_cnt & eg_mask_rr)) {
449 egOut += eg_sel_rr[(eg_cnt >> eg_sh_rr) & 7];
450 if (egOut >= MAX_ATT_INDEX) {
451 egOut = MAX_ATT_INDEX;
462 const bool sustain = !eg_sustain || channel.
isSustained();
463 const unsigned mask = sustain ? eg_mask_rs : eg_mask_rr;
464 if (!(eg_cnt & mask)) {
465 const uint8_t shift = sustain ? eg_sh_rs : eg_sh_rr;
466 std::span<const uint8_t, 8> sel = sustain ? eg_sel_rs : eg_sel_rr;
467 egOut += sel[(eg_cnt >> shift) & 7];
468 if (egOut >= MAX_ATT_INDEX) {
469 egOut = MAX_ATT_INDEX;
485 auto lfo_fn_table_index_offset = narrow<int>(lfo_pm_table
487 phase += fnumToIncrement(
494 return phase.
toInt();
497inline void Slot::updateTotalLevel(
Channel& channel)
502inline void Slot::updateAttackRate(
int kcodeScaled)
504 if ((ar + kcodeScaled) < (16 + 62)) {
505 eg_sh_ar = eg_rate_shift[ar + kcodeScaled];
506 eg_sel_ar = eg_inc[eg_rate_select[ar + kcodeScaled]];
509 eg_sel_ar = eg_inc[13];
511 eg_mask_ar = (1 << eg_sh_ar) - 1;
514inline void Slot::updateDecayRate(
int kcodeScaled)
516 eg_sh_dr = eg_rate_shift[dr + kcodeScaled];
517 eg_sel_dr = eg_inc[eg_rate_select[dr + kcodeScaled]];
518 eg_mask_dr = (1 << eg_sh_dr) - 1;
521inline void Slot::updateReleaseRate(
int kcodeScaled)
523 eg_sh_rr = eg_rate_shift[rr + kcodeScaled];
524 eg_sel_rr = eg_inc[eg_rate_select[rr + kcodeScaled]];
525 eg_mask_rr = (1 << eg_sh_rr) - 1;
529 unsigned lfo_am,
int phase2)
532 auto env = narrow<unsigned>((TLL + egOut2 + (lfo_am & AMmask)) << 5);
533 unsigned p = env + waveTable[phase2 & SIN_MASK];
534 return p < TL_TAB_LEN ? tlTab[p] : 0;
538 unsigned lfo_pm,
unsigned lfo_am)
543 phase2 += (op1_out[0] + op1_out[1]) >> fb_shift;
546 op1_out[0] = op1_out[1];
548 op1_out[1] =
calcOutput(channel, eg_cnt, carrier, lfo_am, phase2);
549 return op1_out[0] << 1;
597static constexpr int genPhaseHighHat(
int phaseM7,
int phaseC8,
int noise_rng)
602 if (phaseC8 & 0x28) {
607 const bool bit7 = (phaseM7 & 0x80) != 0;
608 const bool bit3 = (phaseM7 & 0x08) != 0;
609 const bool bit2 = (phaseM7 & 0x04) != 0;
610 return bool((bit2 ^ bit7) | bit3);
614 return hi ? (0x200 | 0xD0) : (0xD0 >> 2);
616 return hi ? (0x200 | (0xD0 >> 2)) : 0xD0;
620static constexpr int genPhaseSnare(
int phaseM7,
int noise_rng)
624 return ((phaseM7 & 0x100) + 0x100)
625 ^ ((noise_rng & 1) << 8);
628static constexpr int genPhaseCymbal(
int phaseM7,
int phaseC8)
631 if (phaseC8 & 0x28) {
636 const bool bit7 = (phaseM7 & 0x80) != 0;
637 const bool bit3 = (phaseM7 & 0x08) != 0;
638 const bool bit2 = (phaseM7 & 0x04) != 0;
639 return ((bit2 != bit7) || bit3) ? 0x300 : 0x100;
645 : waveTable(sinTab[0])
646 , eg_sel_dp(eg_inc[0]), eg_sel_ar(eg_inc[0]), eg_sel_dr(eg_inc[0])
647 , eg_sel_rr(eg_inc[0]), eg_sel_rs(eg_inc[0])
694 mul = mul_tab[value];
714 AMmask = value ? ~0 : 0;
719 TL = value << (ENV_BITS - 2 - 7);
720 updateTotalLevel(channel);
725 ksl = value ? (3 - value) : 31;
726 updateTotalLevel(channel);
731 waveTable = sinTab[value];
736 fb_shift = value ? 8 - value : 0;
741 int kcodeScaled = channel.
getKeyCode() >> KSR;
742 ar = value ? narrow<uint8_t>(16 + (value << 2)) : 0;
743 updateAttackRate(kcodeScaled);
748 int kcodeScaled = channel.
getKeyCode() >> KSR;
749 dr = value ? narrow<uint8_t>(16 + (value << 2)) : 0;
750 updateDecayRate(kcodeScaled);
755 int kcodeScaled = channel.
getKeyCode() >> KSR;
756 rr = value ? narrow<uint8_t>(16 + (value << 2)) : 0;
757 updateReleaseRate(kcodeScaled);
767 updateTotalLevel(channel);
773 waveTable = sinTab[0];
775 egOut = MAX_ATT_INDEX;
784 const int kcodeScaled = channel.
getKeyCode() >> KSR;
785 updateAttackRate(kcodeScaled);
786 updateDecayRate(kcodeScaled);
787 updateReleaseRate(kcodeScaled);
789 const int rs = channel.
isSustained() ? 16 + (5 << 2) : 16 + (7 << 2);
790 eg_sh_rs = eg_rate_shift[rs + kcodeScaled];
791 eg_sel_rs = eg_inc[eg_rate_select[rs + kcodeScaled]];
793 const int dp = 16 + (13 << 2);
794 eg_sh_dp = eg_rate_shift[dp + kcodeScaled];
795 eg_sel_dp = eg_inc[eg_rate_select[dp + kcodeScaled]];
797 eg_mask_rs = (1 << eg_sh_rs) - 1;
798 eg_mask_dp = (1 << eg_sh_dp) - 1;
803 if (block_fnum == block_fnum_)
return;
804 block_fnum = block_fnum_;
806 ksl_base = ksl_tab[block_fnum >> 5];
807 fc = fnumToIncrement(block_fnum * 2);
842 return (block_fnum & 0x0F00) >> 8;
905 for (
auto part :
xrange(8)) {
911 : lfo_am_cnt(0), lfo_pm_cnt(0)
914 for (
const auto&
e : tlTab) std::cout <<
e <<
'\n';
916 for (
const auto& s : sinTab) {
917 for (
const auto&
e : s) std::cout <<
e <<
'\n';
928void YM2413::updateCustomInstrument(
int part, uint8_t value)
931 inst_tab[0][part] = value;
934 for (
auto ch :
xrange(isRhythm() ? 6 : 9)) {
935 Channel& channel = channels[ch];
936 if ((reg[0x30 + ch] & 0xF0) == 0) {
942void YM2413::setRhythmFlags(uint8_t old)
944 Channel& ch6 = channels[6];
945 Channel& ch7 = channels[7];
946 Channel& ch8 = channels[8];
949 uint8_t flags = reg[0x0E];
950 if ((flags ^ old) & 0x20) {
953 ch6.updateInstrument(inst_tab[16]);
955 ch7.updateInstrument(inst_tab[17]);
956 ch7.mod.setTotalLevel(ch7, uint8_t((reg[0x37] >> 4) << 2));
958 ch8.updateInstrument(inst_tab[18]);
959 ch8.mod.setTotalLevel(ch8, uint8_t((reg[0x38] >> 4) << 2));
961 ch6.updateInstrument(inst_tab[reg[0x36] >> 4]);
962 ch7.updateInstrument(inst_tab[reg[0x37] >> 4]);
963 ch8.updateInstrument(inst_tab[reg[0x38] >> 4]);
1003 for (uint8_t i = 0x3F; i >= 0x10; --i) {
1011void YM2413::resetOperators()
1013 for (
auto& ch : channels) {
1014 ch.mod.resetOperators();
1015 ch.car.resetOperators();
1019bool YM2413::isRhythm()
const
1021 return (reg[0x0E] & 0x20) != 0;
1024Channel& YM2413::getChannelForReg(uint8_t r)
1026 uint8_t chan = (r & 0x0F) % 9;
1027 return channels[chan];
1032 return 1.0f / 2048.0f;
1042 unsigned channelActiveBits = 0;
1044 for (
auto ch :
xrange(isRhythm() ? 6 : 9)) {
1045 if (channels[ch].car.isActive()) {
1046 channelActiveBits |= 1 << ch;
1053 for (
auto ch :
xrange(6, 9)) {
1054 if (channels[ch].car.isActive()) {
1055 channelActiveBits |= 1 << ch;
1057 bufs[ch + 3] =
nullptr;
1060 if (channels[7].mod.isActive()) {
1061 channelActiveBits |= 1 << (7 + 9);
1065 if (channels[8].mod.isActive()) {
1066 channelActiveBits |= 1 << (8 + 9);
1074 if (channelActiveBits) {
1089 for (
auto i :
xrange(num)) {
1094 if (lfo_am_cnt ==
LFOAMIndex(LFO_AM_TAB_ELEMENTS)) {
1098 unsigned lfo_am = lfo_am_table[lfo_am_cnt.
toInt()] >> 1;
1099 unsigned lfo_pm = lfo_pm_cnt.
toInt() & 7;
1101 for (
auto ch :
xrange(isRhythm() ? 6 : 9)) {
1102 Channel& channel = channels[ch];
1103 int fm = channel.
mod.
calc_slot_mod(channel, eg_cnt,
false, lfo_pm, lfo_am);
1104 if ((channelActiveBits >> ch) & 1) {
1105 bufs[ch][i] += narrow_cast<float>(channel.
calcOutput(eg_cnt, lfo_pm, lfo_am, fm));
1116 Channel& channel6 = channels[6];
1117 int fm = channel6.
mod.
calc_slot_mod(channels[6], eg_cnt,
true, lfo_pm, lfo_am);
1118 if (channelActiveBits & (1 << 6)) {
1119 bufs[ 9][i] += narrow_cast<float>(2 * channel6.
calcOutput(eg_cnt, lfo_pm, lfo_am, fm));
1126 (void)channels[7].car.calc_phase(channels[7], lfo_pm);
1127 int phaseM7 = channels[7].mod.calc_phase(channels[7], lfo_pm);
1128 int phaseC8 = channels[8].car.calc_phase(channels[8], lfo_pm);
1129 int phaseM8 = channels[8].mod.calc_phase(channels[8], lfo_pm);
1132 if (channelActiveBits & (1 << 7)) {
1133 Slot& SLOT7_2 = channels[7].car;
1134 bufs[10][i] += narrow_cast<float>(2 * SLOT7_2.
calcOutput(channels[7], eg_cnt,
true, lfo_am, genPhaseSnare(phaseM7, noise_rng)));
1138 if (channelActiveBits & (1 << 8)) {
1139 Slot& SLOT8_2 = channels[8].car;
1140 bufs[11][i] += narrow_cast<float>(2 * SLOT8_2.
calcOutput(channels[8], eg_cnt,
true, lfo_am, genPhaseCymbal(phaseM7, phaseC8)));
1144 if (channelActiveBits & (1 << (7 + 9))) {
1145 Slot& SLOT7_1 = channels[7].mod;
1146 bufs[12][i] += narrow_cast<float>(2 * SLOT7_1.
calcOutput(channels[7], eg_cnt,
true, lfo_am, genPhaseHighHat(phaseM7, phaseC8, noise_rng)));
1150 if (channelActiveBits & (1 << (8 + 9))) {
1151 Slot& SLOT8_1 = channels[8].mod;
1152 bufs[13][i] += narrow_cast<float>(2 * SLOT8_1.
calcOutput(channels[8], eg_cnt,
true, lfo_am, phaseM8));
1181 if (noise_rng & 1) {
1182 noise_rng ^= 0x800302;
1191 registerLatch = value;
1193 writeReg(registerLatch & 0x3f, value);
1202void YM2413::writeReg(uint8_t r, uint8_t v)
1204 uint8_t old = reg[r];
1219 updateCustomInstrument(r, v);
1222 setRhythmFlags(old);
1229 Channel& ch = getChannelForReg(r);
1230 ch.setFrequencyLow(v);
1235 Channel& ch = getChannelForReg(r);
1238 ch.setSustain((v & 0x20) != 0);
1242 ch.setFrequencyHigh(v & 0x0F);
1246 Channel& ch = getChannelForReg(r);
1247 ch.car.setTotalLevel(ch, uint8_t((v & 0x0F) << 2));
1252 uint8_t chan = (r & 0x0F) % 9;
1253 if (isRhythm() && (chan >= 6)) {
1257 ch.mod.setTotalLevel(ch, uint8_t((v >> 4) << 2));
1260 if ((old & 0xF0) != (v & 0xF0)) {
1261 ch.updateInstrument(inst_tab[v >> 4]);
1278static constexpr std::initializer_list<enum_string<YM2413Burczynski::Slot::EnvelopeState>> envelopeStateInfo = {
1288namespace YM2413Burczynski {
1294template<
typename Archive>
1299 uint8_t waveform = (waveTable.data() == sinTab[0].data()) ? 0 : 1;
1300 a.serialize(
"waveform", waveform);
1301 if constexpr (Archive::IS_LOADER) {
1305 a.serialize(
"phase", phase,
1311 "eg_sustain", eg_sustain,
1312 "fb_shift", fb_shift,
1333template<
typename Archive>
1337 std::array<Slot, 2> slots = {
mod,
car};
1339 if constexpr (Archive::IS_LOADER) {
1346 "ksl_base", ksl_base,
1349 if constexpr (Archive::IS_LOADER) {
1359template<
typename Archive>
1362 if (a.versionBelow(version, 2)) a.beginTag(
"YM2413Core");
1363 a.serialize(
"registers", reg);
1364 if (a.versionBelow(version, 2)) a.endTag(
"YM2413Core");
1367 a.serialize_blob(
"user_instrument", inst_tab[0]);
1368 a.serialize(
"channels", channels,
1370 "noise_rng", noise_rng,
1371 "lfo_am_cnt", lfo_am_cnt,
1372 "lfo_pm_cnt", lfo_pm_cnt);
1373 if (a.versionAtLeast(version, 4)) {
1374 a.serialize(
"registerLatch", registerLatch);
constexpr int toInt() const
Returns the integer part (rounded down) of this fixed point number.
constexpr void addQuantum()
Increase this value with the smallest possible amount.
void setSustain(bool sustained)
void updateInstrument(std::span< const uint8_t, 8 > inst)
Sets all synthesis parameters as specified by the instrument.
FreqIndex getFrequencyIncrement() const
void updateInstrumentPart(int part, uint8_t value)
Sets some synthesis parameters as specified by the instrument.
void setFrequencyLow(uint8_t value)
Changes the lower 8 bits of the frequency for this channel.
void serialize(Archive &ar, unsigned version)
uint8_t getKeyCode() const
int getKeyScaleLevelBase() const
void setFrequency(int block_fnum)
Sets the frequency for this channel.
void setFrequencyHigh(uint8_t value)
Changes the higher 4 bits of the frequency for this channel.
int calcOutput(unsigned eg_cnt, unsigned lfo_pm, unsigned lfo_am, int fm)
Calculate the value of the current sample produced by this channel.
void setSustainLevel(uint8_t value)
Sets the sustain level [0..15].
EnvelopeState
Envelope Generator phases Note: These are ordered: phase constants are compared in the code.
void updateFrequency(Channel &channel)
Called by Channel when block_fnum changes.
void setEnvelopeSustained(bool value)
Sets the envelope type of the current instrument.
void setKeyOff(KeyPart part)
void setKeyOnOff(KeyPart part, bool enabled)
void setAttackRate(const Channel &channel, uint8_t value)
Sets the attack rate [0..15].
int calcOutput(Channel &channel, unsigned eg_cnt, bool carrier, unsigned lfo_am, int phase)
void setTotalLevel(Channel &channel, uint8_t value)
Sets the total level: [0..63].
void setFrequencyMultiplier(uint8_t value)
Sets the frequency multiplier [0..15].
void setReleaseRate(const Channel &channel, uint8_t value)
Sets the release rate [0..15].
void setWaveform(uint8_t value)
Sets the waveform: 0 = sinus, 1 = half sinus, half silence.
int calc_envelope(Channel &channel, unsigned eg_cnt, bool carrier)
void serialize(Archive &ar, unsigned version)
void setVibrato(bool value)
Enables (true) or disables (false) vibrato.
int calc_phase(Channel &channel, unsigned lfo_pm)
void setAmplitudeModulation(bool value)
Enables (true) or disables (false) amplitude modulation.
void setKeyOn(KeyPart part)
void setDecayRate(const Channel &channel, uint8_t value)
Sets the decay rate [0..15].
void setKeyScaleLevel(Channel &channel, uint8_t value)
Sets the key scale level: 0->0 / 1->1.5 / 2->3.0 / 3->6.0 dB/OCT.
void setFeedbackShift(uint8_t value)
Sets the amount of feedback [0..7].
bool isActive() const
Does this slot currently produce an output signal?
int calc_slot_mod(Channel &channel, unsigned eg_cnt, bool carrier, unsigned lfo_pm, unsigned lfo_am)
void setKeyScaleRate(bool value)
Sets the key scale rate: true->0, false->2.
void updateGenerators(Channel &channel)
Update phase increment counter of operator.
void generateChannels(std::span< float *, 9+5 > bufs, unsigned num) override
Generate the sound output.
void writePort(bool port, uint8_t value, int offset) override
Write to the YM2413 register/data port.
void serialize(Archive &ar, unsigned version)
void reset() override
Reset this YM2413 core.
void pokeReg(uint8_t reg, uint8_t value) override
Write to a YM2413 register (for debug).
float getAmplificationFactor() const override
Returns normalization factor.
uint8_t peekReg(uint8_t reg) const override
Read from a YM2413 register (for debug).
Abstract interface for the YM2413 core.
static constexpr int CLOCK_FREQ
Input clock frequency.
constexpr double round(double x)
FixedPoint< 16 > FreqIndex
16.16 fixed point type for frequency calculations.
This file implemented 3 utility functions:
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
constexpr void fill(ForwardRange &&range, const T &value)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)